2
0

maintain lastIUsedTime so clients can use it as a factor in idle and health check logic

This commit is contained in:
Patrick Ellul
2020-01-25 21:41:34 +11:00
parent 11cab39313
commit 6a68341f62
2 changed files with 40 additions and 11 deletions
+24 -2
View File
@@ -29,6 +29,7 @@ type Resource struct {
value interface{}
pool *Pool
creationTime time.Time
lastUsedTime time.Time
status byte
}
@@ -45,7 +46,16 @@ func (res *Resource) Release() {
if res.status != resourceStatusAcquired {
panic("tried to release resource that is not acquired")
}
res.pool.releaseAcquiredResource(res)
res.pool.releaseAcquiredResource(res, true)
}
// Release returns the resource to the pool after it was acquired via AcquireAllIdle.
// It does not updates lastUsedTime. res must not be subsequently used.
func (res *Resource) ReleaseIdle() {
if res.status != resourceStatusAcquired {
panic("tried to release resource that is not acquired")
}
res.pool.releaseAcquiredResource(res, false)
}
// Destroy returns the resource to the pool for destruction. res must not be
@@ -74,6 +84,15 @@ func (res *Resource) CreationTime() time.Time {
return res.creationTime
}
// LastUsedTime returns when the resource was last used, specifically when
// it was released from a normal Acquire (not from an AcquireAllIdle)
func (res *Resource) LastUsedTime() time.Time {
if !(res.status == resourceStatusAcquired || res.status == resourceStatusHijacked) {
panic("tried to access resource that is not acquired or hijacked")
}
return res.lastUsedTime
}
// Pool is a concurrency-safe resource pool.
type Pool struct {
cond *sync.Cond
@@ -340,10 +359,13 @@ func (p *Pool) AcquireAllIdle() []*Resource {
}
// releaseAcquiredResource returns res to the the pool.
func (p *Pool) releaseAcquiredResource(res *Resource) {
func (p *Pool) releaseAcquiredResource(res *Resource, updateLastUsed bool) {
p.cond.L.Lock()
if !p.closed {
if updateLastUsed {
res.lastUsedTime = time.Now()
}
res.status = resourceStatusIdle
p.idleResources = append(p.idleResources, res)
} else {
+16 -9
View File
@@ -217,6 +217,8 @@ func TestPoolAcquireAllIdle(t *testing.T) {
resources[0], err = pool.Acquire(context.Background())
require.NoError(t, err)
assert.True(t, resources[0].LastUsedTime().IsZero(), "lastUsedTime should start as Zero")
resources[1], err = pool.Acquire(context.Background())
require.NoError(t, err)
resources[2], err = pool.Acquire(context.Background())
@@ -225,23 +227,25 @@ func TestPoolAcquireAllIdle(t *testing.T) {
require.NoError(t, err)
assert.Len(t, pool.AcquireAllIdle(), 0)
resources[0].Release()
resources[3].Release()
assert.ElementsMatch(t, []*puddle.Resource{resources[0], resources[3]}, pool.AcquireAllIdle())
r0LastUsedTime := resources[0].LastUsedTime()
assert.WithinDuration(t, time.Now(), r0LastUsedTime, time.Second, "should have updated lastUsedTime")
time.Sleep(1 * time.Millisecond) // sleep before releasing
resources[0].ReleaseIdle()
resources[3].ReleaseIdle()
resources[0].Release()
resources[3].Release()
resources[1].Release()
resources[2].Release()
assert.ElementsMatch(t, resources, pool.AcquireAllIdle())
resources[0].Release()
resources[1].Release()
resources[2].Release()
resources[3].Release()
assert.Equal(t, r0LastUsedTime, resources[0].LastUsedTime(), "should not have updated lastUsedTime")
resources[0].ReleaseIdle()
resources[1].ReleaseIdle()
resources[2].ReleaseIdle()
resources[3].ReleaseIdle()
}
func TestPoolCloseClosesAllIdleResources(t *testing.T) {
@@ -464,9 +468,10 @@ func TestResourceDestroyRemovesResourceFromPool(t *testing.T) {
assert.EqualValues(t, 0, pool.Stat().TotalResources())
assert.EqualValues(t, 0, destructorCalls.Value())
// Can still call Value and CreationTime
// Can still call Value, CreationTime and LastUsedTime
res.Value()
res.CreationTime()
res.LastUsedTime()
}
func TestResourceHijackRemovesResourceFromPoolButDoesNotDestroy(t *testing.T) {
@@ -491,10 +496,12 @@ func TestResourcePanicsOnUsageWhenNotAcquired(t *testing.T) {
res.Release()
assert.PanicsWithValue(t, "tried to release resource that is not acquired", res.Release)
assert.PanicsWithValue(t, "tried to release resource that is not acquired", res.ReleaseIdle)
assert.PanicsWithValue(t, "tried to destroy resource that is not acquired", res.Destroy)
assert.PanicsWithValue(t, "tried to hijack resource that is not acquired", res.Hijack)
assert.PanicsWithValue(t, "tried to access resource that is not acquired or hijacked", func() { res.Value() })
assert.PanicsWithValue(t, "tried to access resource that is not acquired or hijacked", func() { res.CreationTime() })
assert.PanicsWithValue(t, "tried to access resource that is not acquired or hijacked", func() { res.LastUsedTime() })
}
func TestPoolAcquireReturnsErrorWhenPoolIsClosed(t *testing.T) {