Involved Source Filescontext.go Package puddle is a generic resource pool with type-parametrized api.
Puddle is a tiny generic resource pool library for Go that uses the standard
context library to signal cancellation of acquires. It is designed to contain
the minimum functionality a resource pool needs that cannot be implemented
without concurrency concerns. For example, a database connection pool may use
puddle internally and implement health checks and keep-alive behavior without
needing to implement any concurrent code of its own.log.gonanotime.gopool.goresource_list.go
Package-Level Type Names (total 9, in which 6 are exported)
Type Parameters:
T: any Constructor is a function called by the pool to construct a resource.
Type Parameters:
T: any Destructor is a function called by the pool to destroy a resource.
Type Parameters:
T: any Pool is a concurrency-safe resource pool.acquireCountint64acquireDurationtime.Duration acquireSem provides an allowance to acquire a resource.
Releases are allowed only when caller holds mux. Acquires have to
happen before mux is locked (doesn't apply to semaphore.TryAcquire in
AcquireAllIdle).allResourcesresList[T]baseAcquireCtxcontext.ContextcancelBaseAcquireCtxcontext.CancelFunccanceledAcquireCountatomic.Int64closedboolconstructorConstructor[T]destructWGsync.WaitGroupdestructorDestructor[T]emptyAcquireCountint64emptyAcquireWaitTimetime.DurationidleResources*genstack.GenStack[*Resource[T]]maxSizeint32 mux is the pool internal lock. Any modification of shared state of
the pool (but Acquires of acquireSem) must be performed only by
holder of the lock. Long running operations are not allowed when mux
is held.resetCountint Acquire gets a resource from the pool. If no resources are available and the pool is not at maximum capacity it will
create a new resource. If the pool is at maximum capacity it will block until a resource is available. ctx can be
used to cancel the Acquire.
If Acquire creates a new resource the resource constructor function will receive a context that delegates Value() to
ctx. Canceling ctx will cause Acquire to return immediately but it will not cancel the resource creation. This avoids
the problem of it being impossible to create resources when the time to create a resource is greater than any one
caller of Acquire is willing to wait. AcquireAllIdle acquires all currently idle resources. Its intended use is for
health check and keep-alive functionality. It does not update pool
statistics. Close destroys all resources in the pool and rejects future Acquire calls.
Blocks until all resources are returned to pool and destroyed. CreateResource constructs a new resource without acquiring it. It goes straight in the IdlePool. If the pool is full
it returns an error. It can be useful to maintain warm resources under little load. Reset destroys all resources, but leaves the pool open. It is intended for use when an error is detected that would
disrupt all resources (such as a network interruption or a server state change).
It is safe to reset a pool while resources are checked out. Those resources will be destroyed when they are returned
to the pool. Stat returns the current pool statistics. TryAcquire gets a resource from the pool if one is immediately available. If not, it returns ErrNotAvailable. If no
resources are available but the pool has room to grow, a resource will be created in the background. ctx is only
used to cancel the background creation. acquire is a continuation of Acquire function that doesn't check context
validity.
This function exists solely only for benchmarking purposes. createNewResource creates a new resource and inserts it into list of pool
resources.
WARNING: Caller of this method must hold the pool mutex! Remove removes res from the pool and closes it. If res is not part of the
pool Remove will panic.(*Pool[T]) destructResourceValue(value T)(*Pool[T]) hijackAcquiredResource(res *Resource[T])(*Pool[T]) initResourceValue(ctx context.Context, res *Resource[T]) (*Resource[T], error) releaseAcquiredResource returns res to the the pool. tryAcquireIdleResource checks if there is any idle resource. If there is
some, this method removes it from idle list and returns it. If the idle pool
is empty, this method returns nil and doesn't modify the idleResources slice.
WARNING: Caller of this method must hold the pool mutex!
func NewPool[T](config *Config[T]) (*Pool[T], error)
Type Parameters:
T: any Resource is the resource handle returned by acquiring from the pool.creationTimetime.TimelastUsedNanoint64pool*Pool[T]poolResetCountintstatusbytevalueT CreationTime returns when the resource was created by the pool. Destroy returns the resource to the pool for destruction. res must not be
subsequently used. Hijack assumes ownership of the resource from the pool. Caller is responsible
for cleanup of resource value. IdleDuration returns the duration since Release was last called on the resource. This is equivalent to subtracting
LastUsedNanotime to the current nanotime. LastUsedNanotime returns when Release was last called on the resource measured in nanoseconds from an arbitrary time
(a monotonic time). Returns creation time if Release has never been called. This is only useful to compare with
other calls to LastUsedNanotime. In almost all cases, IdleDuration should be used instead. Release returns the resource to the pool. res must not be subsequently used. ReleaseUnused returns the resource to the pool without updating when it was last used used. i.e. LastUsedNanotime
will not change. res must not be subsequently used. Value returns the resource value.
func (*Pool)[T].Acquire(ctx context.Context) (_ *Resource[T], err error)
func (*Pool)[T].AcquireAllIdle() []*Resource[T]
func (*Pool)[T].TryAcquire(ctx context.Context) (*Resource[T], error)
func (*Pool)[T].acquire(ctx context.Context) (*Resource[T], error)
func (*Pool)[T].createNewResource() *Resource[T]
func (*Pool)[T].initResourceValue(ctx context.Context, res *Resource[T]) (*Resource[T], error)
func (*Pool)[T].tryAcquireIdleResource() *Resource[T]
func (*Pool)[T].destroyAcquiredResource(res *Resource[T])
func (*Pool)[T].hijackAcquiredResource(res *Resource[T])
func (*Pool)[T].initResourceValue(ctx context.Context, res *Resource[T]) (*Resource[T], error)
func (*Pool)[T].releaseAcquiredResource(res *Resource[T], lastUsedNano int64)
func github.com/jackc/pgx/v5/pgxpool.(*Pool).isExpired(res *Resource[*pgxpool.connResource]) bool
Stat is a snapshot of Pool statistics.acquireCountint64acquireDurationtime.DurationacquiredResourcesint32canceledAcquireCountint64constructingResourcesint32emptyAcquireCountint64emptyAcquireWaitTimetime.DurationidleResourcesint32maxResourcesint32 AcquireCount returns the cumulative count of successful acquires from the pool. AcquireDuration returns the total duration of all successful acquires from
the pool. AcquiredResources returns the number of currently acquired resources in the pool. CanceledAcquireCount returns the cumulative count of acquires from the pool
that were canceled by a context. ConstructingResources returns the number of resources with construction in progress in
the pool. EmptyAcquireCount returns the cumulative count of successful acquires from the pool
that waited for a resource to be released or constructed because the pool was
empty. EmptyAcquireWaitTime returns the cumulative time waited for successful acquires
from the pool for a resource to be released or constructed because the pool was
empty. IdleResources returns the number of currently idle resources in the pool. MaxResources returns the maximum size of the pool. TotalResources returns the total number of resources currently in the pool.
The value is the sum of ConstructingResources, AcquiredResources, and
IdleResources.
func (*Pool)[T].Stat() *Stat
Package-Level Functions (total 6, in which 1 is exported)
Type Parameters:
T: any NewPool creates a new pool. Returns an error iff MaxSize is less than 1.
acquireSemAll tries to acquire num free tokens from sem. This function is
guaranteed to acquire at least the lowest number of tokens that has been
available in the semaphore during runtime of this function.
For the time being, semaphore doesn't allow to acquire all tokens atomically
(see https://github.com/golang/sync/pull/19). We simulate this by trying all
powers of 2 that are less or equal to num.
For example, let's immagine we have 19 free tokens in the semaphore which in
total has 24 tokens (i.e. the maxSize of the pool is 24 resources). Then if
num is 24, the log2Uint(24) is 4 and we try to acquire 16, 8, 4, 2 and 1
tokens. Out of those, the acquire of 16, 2 and 1 tokens will succeed.
Naturally, Acquires and Releases of the semaphore might take place
concurrently. For this reason, it's not guaranteed that absolutely all free
tokens in the semaphore will be acquired. But it's guaranteed that at least
the minimal number of tokens that has been present over the whole process
will be acquired. This is sufficient for the use-case we have in this
package.
TODO: Replace this with acquireSem.TryAcquireAll() if it gets to
upstream. https://github.com/golang/sync/pull/19
Type Parameters:
T: ints log2Int returns log2 of an integer. This function panics if val < 0. For val
== 0, returns 0.
nanotime returns the time in nanoseconds since process start.
This approach, described at
https://github.com/golang/go/issues/61765#issuecomment-1672090302,
is fast, monotonic, and portable, and avoids the previous
dependence on runtime.nanotime using the (unsafe) linkname hack.
In particular, time.Since does less work than time.Now.