maintain lastIUsedTime so clients can use it as a factor in idle and health check logic
This commit is contained in:
@@ -29,6 +29,7 @@ type Resource struct {
|
|||||||
value interface{}
|
value interface{}
|
||||||
pool *Pool
|
pool *Pool
|
||||||
creationTime time.Time
|
creationTime time.Time
|
||||||
|
lastUsedTime time.Time
|
||||||
status byte
|
status byte
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +46,16 @@ func (res *Resource) Release() {
|
|||||||
if res.status != resourceStatusAcquired {
|
if res.status != resourceStatusAcquired {
|
||||||
panic("tried to release resource that is not acquired")
|
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
|
// 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
|
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.
|
// Pool is a concurrency-safe resource pool.
|
||||||
type Pool struct {
|
type Pool struct {
|
||||||
cond *sync.Cond
|
cond *sync.Cond
|
||||||
@@ -340,10 +359,13 @@ func (p *Pool) AcquireAllIdle() []*Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// releaseAcquiredResource returns res to the the pool.
|
// 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()
|
p.cond.L.Lock()
|
||||||
|
|
||||||
if !p.closed {
|
if !p.closed {
|
||||||
|
if updateLastUsed {
|
||||||
|
res.lastUsedTime = time.Now()
|
||||||
|
}
|
||||||
res.status = resourceStatusIdle
|
res.status = resourceStatusIdle
|
||||||
p.idleResources = append(p.idleResources, res)
|
p.idleResources = append(p.idleResources, res)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+16
-9
@@ -217,6 +217,8 @@ func TestPoolAcquireAllIdle(t *testing.T) {
|
|||||||
|
|
||||||
resources[0], err = pool.Acquire(context.Background())
|
resources[0], err = pool.Acquire(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
assert.True(t, resources[0].LastUsedTime().IsZero(), "lastUsedTime should start as Zero")
|
||||||
|
|
||||||
resources[1], err = pool.Acquire(context.Background())
|
resources[1], err = pool.Acquire(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
resources[2], err = pool.Acquire(context.Background())
|
resources[2], err = pool.Acquire(context.Background())
|
||||||
@@ -225,23 +227,25 @@ func TestPoolAcquireAllIdle(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, pool.AcquireAllIdle(), 0)
|
assert.Len(t, pool.AcquireAllIdle(), 0)
|
||||||
|
|
||||||
resources[0].Release()
|
resources[0].Release()
|
||||||
resources[3].Release()
|
resources[3].Release()
|
||||||
|
|
||||||
assert.ElementsMatch(t, []*puddle.Resource{resources[0], resources[3]}, pool.AcquireAllIdle())
|
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[1].Release()
|
||||||
resources[2].Release()
|
resources[2].Release()
|
||||||
|
|
||||||
assert.ElementsMatch(t, resources, pool.AcquireAllIdle())
|
assert.ElementsMatch(t, resources, pool.AcquireAllIdle())
|
||||||
|
assert.Equal(t, r0LastUsedTime, resources[0].LastUsedTime(), "should not have updated lastUsedTime")
|
||||||
resources[0].Release()
|
resources[0].ReleaseIdle()
|
||||||
resources[1].Release()
|
resources[1].ReleaseIdle()
|
||||||
resources[2].Release()
|
resources[2].ReleaseIdle()
|
||||||
resources[3].Release()
|
resources[3].ReleaseIdle()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPoolCloseClosesAllIdleResources(t *testing.T) {
|
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, pool.Stat().TotalResources())
|
||||||
assert.EqualValues(t, 0, destructorCalls.Value())
|
assert.EqualValues(t, 0, destructorCalls.Value())
|
||||||
|
|
||||||
// Can still call Value and CreationTime
|
// Can still call Value, CreationTime and LastUsedTime
|
||||||
res.Value()
|
res.Value()
|
||||||
res.CreationTime()
|
res.CreationTime()
|
||||||
|
res.LastUsedTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResourceHijackRemovesResourceFromPoolButDoesNotDestroy(t *testing.T) {
|
func TestResourceHijackRemovesResourceFromPoolButDoesNotDestroy(t *testing.T) {
|
||||||
@@ -491,10 +496,12 @@ func TestResourcePanicsOnUsageWhenNotAcquired(t *testing.T) {
|
|||||||
res.Release()
|
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.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 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 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.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.CreationTime() })
|
||||||
|
assert.PanicsWithValue(t, "tried to access resource that is not acquired or hijacked", func() { res.LastUsedTime() })
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPoolAcquireReturnsErrorWhenPoolIsClosed(t *testing.T) {
|
func TestPoolAcquireReturnsErrorWhenPoolIsClosed(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user