puddle

package module
v2.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 15, 2024 License: MIT Imports: 8 Imported by: 1

README

Build Status

Puddle

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 required for a resource pool. It can be used directly or it can be used as the base for a domain specific resource pool. 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.

Features

  • Acquire cancellation via context standard library
  • Statistics API for monitoring pool pressure
  • No dependencies outside of standard library and golang.org/x/sync
  • High performance
  • 100% test coverage of reachable code

Example Usage

package main

import (
	"context"
	"log"
	"net"

	"github.com/andoma-go/puddle/v2"
)

func main() {
	constructor := func(context.Context) (net.Conn, error) {
		return net.Dial("tcp", "127.0.0.1:8080")
	}
	destructor := func(value net.Conn) {
		value.Close()
	}
	maxPoolSize := int32(10)

	pool, err := puddle.NewPool(&puddle.Config[net.Conn]{Constructor: constructor, Destructor: destructor, MaxSize: maxPoolSize})
	if err != nil {
		log.Fatal(err)
	}

	// Acquire resource from the pool.
	res, err := pool.Acquire(context.Background())
	if err != nil {
		log.Fatal(err)
	}

	// Use resource.
	_, err = res.Value().Write([]byte{1})
	if err != nil {
		log.Fatal(err)
	}

	// Release when done.
	res.Release()
}

Status

Puddle is stable and feature complete.

  • Bug reports and fixes are welcome.
  • New features will usually not be accepted if they can be feasibly implemented in a wrapper.
  • Performance optimizations will usually not be accepted unless the performance issue rises to the level of a bug.

Supported Go Versions

puddle supports the same versions of Go that are supported by the Go project. For Go that is the two most recent major releases. This means puddle supports Go 1.19 and higher.

License

MIT

Documentation

Overview

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.

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrClosedPool = errors.New("closed pool")

ErrClosedPool occurs on an attempt to acquire a connection from a closed pool or a pool that is closed while the acquire is waiting.

View Source
var ErrNotAvailable = errors.New("resource not available")

ErrNotAvailable occurs on an attempt to acquire a resource from a pool that is at maximum capacity and has no available resources.

Functions

This section is empty.

Types

type Config

type Config[T any] struct {
	Constructor Constructor[T]
	Destructor  Destructor[T]
	MaxSize     int32
}

type Constructor

type Constructor[T any] func(ctx context.Context) (res T, err error)

Constructor is a function called by the pool to construct a resource.

type Destructor

type Destructor[T any] func(res T)

Destructor is a function called by the pool to destroy a resource.

type Pool

type Pool[T any] struct {
	// contains filtered or unexported fields
}

Pool is a concurrency-safe resource pool.

Example
// Dummy server
laddr := "127.0.0.1:8080"
startAcceptOnceDummyServer(laddr)

// Pool creation
constructor := func(context.Context) (any, error) {
	return net.Dial("tcp", laddr)
}
destructor := func(value any) {
	value.(net.Conn).Close()
}
maxPoolSize := int32(10)

pool, err := puddle.NewPool(&puddle.Config[any]{Constructor: constructor, Destructor: destructor, MaxSize: int32(maxPoolSize)})
if err != nil {
	log.Fatalln("NewPool", err)
}

// Use pool multiple times
for i := 0; i < 10; i++ {
	// Acquire resource
	res, err := pool.Acquire(context.Background())
	if err != nil {
		log.Fatalln("Acquire", err)
	}

	// Type-assert value and use
	_, err = res.Value().(net.Conn).Write([]byte{1})
	if err != nil {
		log.Fatalln("Write", err)
	}

	// Release when done.
	res.Release()
}

stats := pool.Stat()
pool.Close()

fmt.Println("Connections:", stats.TotalResources())
fmt.Println("Acquires:", stats.AcquireCount())
Output:

Connections: 1
Acquires: 10

func NewPool

func NewPool[T any](config *Config[T]) (*Pool[T], error)

NewPool creates a new pool. Panics if maxSize is less than 1.

func (*Pool[T]) Acquire

func (p *Pool[T]) Acquire(ctx context.Context) (_ *Resource[T], err error)

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.

func (*Pool[T]) AcquireAllIdle

func (p *Pool[T]) AcquireAllIdle() []*Resource[T]

AcquireAllIdle acquires all currently idle resources. Its intended use is for health check and keep-alive functionality. It does not update pool statistics.

func (*Pool[T]) Close

func (p *Pool[T]) Close()

Close destroys all resources in the pool and rejects future Acquire calls. Blocks until all resources are returned to pool and destroyed.

func (*Pool[T]) CreateResource

func (p *Pool[T]) CreateResource(ctx context.Context) error

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.

func (*Pool[T]) Reset

func (p *Pool[T]) Reset()

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.

func (*Pool[T]) Stat

func (p *Pool[T]) Stat() *Stat

Stat returns the current pool statistics.

func (*Pool[T]) TryAcquire

func (p *Pool[T]) TryAcquire(ctx context.Context) (*Resource[T], error)

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.

type Resource

type Resource[T any] struct {
	// contains filtered or unexported fields
}

Resource is the resource handle returned by acquiring from the pool.

func (*Resource[T]) CreationTime

func (res *Resource[T]) CreationTime() time.Time

CreationTime returns when the resource was created by the pool.

func (*Resource[T]) Destroy

func (res *Resource[T]) Destroy()

Destroy returns the resource to the pool for destruction. res must not be subsequently used.

func (*Resource[T]) Hijack

func (res *Resource[T]) Hijack()

Hijack assumes ownership of the resource from the pool. Caller is responsible for cleanup of resource value.

func (*Resource[T]) IdleDuration

func (res *Resource[T]) IdleDuration() time.Duration

IdleDuration returns the duration since Release was last called on the resource. This is equivalent to subtracting LastUsedNanotime to the current nanotime.

func (*Resource[T]) LastUsedNanotime

func (res *Resource[T]) LastUsedNanotime() int64

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.

func (*Resource[T]) Release

func (res *Resource[T]) Release()

Release returns the resource to the pool. res must not be subsequently used.

func (*Resource[T]) ReleaseUnused

func (res *Resource[T]) ReleaseUnused()

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.

func (*Resource[T]) Value

func (res *Resource[T]) Value() T

Value returns the resource value.

type Stat

type Stat struct {
	// contains filtered or unexported fields
}

Stat is a snapshot of Pool statistics.

func (*Stat) AcquireCount

func (s *Stat) AcquireCount() int64

AcquireCount returns the cumulative count of successful acquires from the pool.

func (*Stat) AcquireDuration

func (s *Stat) AcquireDuration() time.Duration

AcquireDuration returns the total duration of all successful acquires from the pool.

func (*Stat) AcquiredResources

func (s *Stat) AcquiredResources() int32

AcquiredResources returns the number of currently acquired resources in the pool.

func (*Stat) CanceledAcquireCount

func (s *Stat) CanceledAcquireCount() int64

CanceledAcquireCount returns the cumulative count of acquires from the pool that were canceled by a context.

func (*Stat) ConstructingResources

func (s *Stat) ConstructingResources() int32

ConstructingResources returns the number of resources with construction in progress in the pool.

func (*Stat) EmptyAcquireCount

func (s *Stat) EmptyAcquireCount() int64

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.

func (*Stat) IdleResources

func (s *Stat) IdleResources() int32

IdleResources returns the number of currently idle resources in the pool.

func (*Stat) MaxResources

func (s *Stat) MaxResources() int32

MaxResources returns the maximum size of the pool.

func (*Stat) TotalResources

func (s *Stat) TotalResources() int32

TotalResources returns the total number of resources currently in the pool. The value is the sum of ConstructingResources, AcquiredResources, and IdleResources.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL