Add more docs and example
This commit is contained in:
@@ -13,6 +13,36 @@ Puddle is a tiny generic resource pool library for Go that uses the standard con
|
|||||||
* High performance
|
* High performance
|
||||||
* 100% test coverage
|
* 100% test coverage
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
constructor := func(context.Context) (interface{}, error) {
|
||||||
|
return net.Dial("tcp", "127.0.0.1:8080")
|
||||||
|
}
|
||||||
|
destructor := func(value interface{}) {
|
||||||
|
value.(net.Conn).Close()
|
||||||
|
}
|
||||||
|
maxPoolSize := 10
|
||||||
|
|
||||||
|
pool := puddle.NewPool(constructor, destructor, maxPoolSize)
|
||||||
|
|
||||||
|
// Acquire resource from the pool.
|
||||||
|
res, err := pool.Acquire(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use resource.
|
||||||
|
_, err = res.Value().(net.Conn).Write([]byte{1})
|
||||||
|
if err != nil {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release when done.
|
||||||
|
res.Release()
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// Package puddle is a generic resource pool.
|
||||||
|
/*
|
||||||
|
|
||||||
|
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 concerrency 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.
|
||||||
|
*/
|
||||||
|
package puddle
|
||||||
@@ -4,7 +4,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -589,6 +591,84 @@ func TestStress(t *testing.T) {
|
|||||||
pool.Close()
|
pool.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func exampleDummyServer(laddr string, acceptCount int, recvCountChan chan int) {
|
||||||
|
ln, err := net.Listen("tcp", laddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Listen:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < acceptCount; i++ {
|
||||||
|
conn, err := ln.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Accept:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
recvCount := 0
|
||||||
|
for {
|
||||||
|
buf := make([]byte, 1)
|
||||||
|
_, err := conn.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
recvCountChan <- recvCount
|
||||||
|
return
|
||||||
|
}
|
||||||
|
recvCount += 1
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Example_Pool() {
|
||||||
|
// Dummy server
|
||||||
|
maxPoolSize := 4
|
||||||
|
serverRecvCountChan := make(chan int)
|
||||||
|
laddr := "127.0.0.1:8080"
|
||||||
|
|
||||||
|
// exampleDummyServer only listens maxPoolSize times so if the pool tried to
|
||||||
|
// connect more than that the pool would receive an error.
|
||||||
|
go exampleDummyServer(laddr, maxPoolSize, serverRecvCountChan)
|
||||||
|
|
||||||
|
// Pool usage
|
||||||
|
pool := puddle.NewPool(
|
||||||
|
func(context.Context) (interface{}, error) { return net.Dial("tcp", laddr) },
|
||||||
|
func(value interface{}) { value.(net.Conn).Close() },
|
||||||
|
maxPoolSize,
|
||||||
|
)
|
||||||
|
|
||||||
|
clientCount := 32
|
||||||
|
opPerClientCount := 100
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
|
||||||
|
for i := 0; i < clientCount; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < opPerClientCount; i++ {
|
||||||
|
res, err := pool.Acquire(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Acquire", err)
|
||||||
|
}
|
||||||
|
_, err = res.Value().(net.Conn).Write([]byte{1})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Write", err)
|
||||||
|
}
|
||||||
|
res.Release()
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
pool.Close()
|
||||||
|
totalRecv := <-serverRecvCountChan
|
||||||
|
totalRecv += <-serverRecvCountChan
|
||||||
|
totalRecv += <-serverRecvCountChan
|
||||||
|
totalRecv += <-serverRecvCountChan
|
||||||
|
|
||||||
|
fmt.Println("Ops:", totalRecv)
|
||||||
|
// Output:
|
||||||
|
// Ops: 3200
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkPoolAcquireAndRelease(b *testing.B) {
|
func BenchmarkPoolAcquireAndRelease(b *testing.B) {
|
||||||
benchmarks := []struct {
|
benchmarks := []struct {
|
||||||
poolSize int
|
poolSize int
|
||||||
|
|||||||
Reference in New Issue
Block a user