From 4014e4825a5e9f561c2e7b610be4d2a623fbb791 Mon Sep 17 00:00:00 2001 From: Patrick Ellul Date: Mon, 3 Feb 2020 11:14:49 +1100 Subject: [PATCH] CreateResource constructs a new resource without acquiring it. --- pool.go | 26 ++++++++++++++++++++++++++ pool_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/pool.go b/pool.go index 54acf30..1a3fb30 100644 --- a/pool.go +++ b/pool.go @@ -373,6 +373,32 @@ func (p *Pool) AcquireAllIdle() []*Resource { return resources } +// CreateResource constructs a new resource without acquiring it. +// It goes straight in the IdlePool. It does not check against maxSize. +// It can be useful to maintain warm resources under little load. +func (p *Pool) CreateResource(ctx context.Context) error { + + value, err := p.constructResourceValue(ctx) + if err != nil { + return err + } + + res := &Resource{ + pool: p, + creationTime: time.Now(), + status: resourceStatusIdle, + value: value, + } + + p.cond.L.Lock() + p.allResources = append(p.allResources, res) + p.idleResources = append(p.idleResources, res) + p.destructWG.Add(1) + p.cond.L.Unlock() + + return nil +} + // releaseAcquiredResource returns res to the the pool. func (p *Pool) releaseAcquiredResource(res *Resource, lastUsedNano int64) { p.cond.L.Lock() diff --git a/pool_test.go b/pool_test.go index c822a67..1df1486 100644 --- a/pool_test.go +++ b/pool_test.go @@ -245,6 +245,44 @@ func TestPoolAcquireAllIdle(t *testing.T) { resources[3].Release() } +func TestPoolCreateResource(t *testing.T) { + constructor, counter := createConstructor() + pool := puddle.NewPool(constructor, stubDestructor, 10) + defer pool.Close() + + var err error + + err = pool.CreateResource(context.Background()) + require.NoError(t, err) + + allIdle := pool.AcquireAllIdle() + assert.Equal(t, counter.Value(), allIdle[0].Value()) + allIdle[0].ReleaseUnused() + + stats := pool.Stat() + assert.EqualValues(t, 1, stats.IdleResources()) + + res, err := pool.Acquire(context.Background()) + require.NoError(t, err) + assert.Equal(t, 1, res.Value()) + assert.WithinDuration(t, time.Now(), res.CreationTime(), time.Second) + res.Release() + + stats = pool.Stat() + assert.EqualValues(t, 0, stats.EmptyAcquireCount()) +} + +func TestPoolCreateResourceReturnsErrorFromFailedResourceCreate(t *testing.T) { + errCreateFailed := errors.New("create failed") + constructor := func(ctx context.Context) (interface{}, error) { + return nil, errCreateFailed + } + pool := puddle.NewPool(constructor, stubDestructor, 10) + + err := pool.CreateResource(context.Background()) + assert.Equal(t, errCreateFailed, err) +} + func TestPoolCloseClosesAllIdleResources(t *testing.T) { constructor, _ := createConstructor()