Track acquire and slow acquire count
This commit is contained in:
@@ -64,7 +64,8 @@ type Pool struct {
|
|||||||
destructor Destructor
|
destructor Destructor
|
||||||
maxSize int
|
maxSize int
|
||||||
|
|
||||||
acquireCount uint64
|
acquireCount int64
|
||||||
|
slowAcquireCount int64
|
||||||
|
|
||||||
closed bool
|
closed bool
|
||||||
}
|
}
|
||||||
@@ -103,6 +104,8 @@ type Stat struct {
|
|||||||
acquiredResources int
|
acquiredResources int
|
||||||
idleResources int
|
idleResources int
|
||||||
maxResources int
|
maxResources int
|
||||||
|
acquireCount int64
|
||||||
|
slowAcquireCount int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalResource returns the total number of resources in the pool.
|
// TotalResource returns the total number of resources in the pool.
|
||||||
@@ -131,11 +134,24 @@ func (s *Stat) MaxResources() int {
|
|||||||
return s.maxResources
|
return s.maxResources
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AcquireCount returns the number of successful acquires from the pool.
|
||||||
|
func (s *Stat) AcquireCount() int64 {
|
||||||
|
return s.acquireCount
|
||||||
|
}
|
||||||
|
|
||||||
|
// SlowAcquireCount returns the number of successful acquires from the pool
|
||||||
|
// that waited for a resource to be released or constructed.
|
||||||
|
func (s *Stat) SlowAcquireCount() int64 {
|
||||||
|
return s.slowAcquireCount
|
||||||
|
}
|
||||||
|
|
||||||
// Stat returns the current pool statistics.
|
// Stat returns the current pool statistics.
|
||||||
func (p *Pool) Stat() *Stat {
|
func (p *Pool) Stat() *Stat {
|
||||||
p.cond.L.Lock()
|
p.cond.L.Lock()
|
||||||
s := &Stat{
|
s := &Stat{
|
||||||
maxResources: p.maxSize,
|
maxResources: p.maxSize,
|
||||||
|
acquireCount: p.acquireCount,
|
||||||
|
slowAcquireCount: p.slowAcquireCount,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, res := range p.allResources {
|
for _, res := range p.allResources {
|
||||||
@@ -166,6 +182,7 @@ func (p *Pool) Acquire(ctx context.Context) (*Resource, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slowAcquire := false
|
||||||
p.cond.L.Lock()
|
p.cond.L.Lock()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@@ -176,11 +193,19 @@ func (p *Pool) Acquire(ctx context.Context) (*Resource, error) {
|
|||||||
|
|
||||||
// If a resource is available now
|
// If a resource is available now
|
||||||
if len(p.idleResources) > 0 {
|
if len(p.idleResources) > 0 {
|
||||||
rw := p.lockedIdleAcquire()
|
res := p.idleResources[len(p.idleResources)-1]
|
||||||
|
p.idleResources = p.idleResources[:len(p.idleResources)-1]
|
||||||
|
res.status = resourceStatusAcquired
|
||||||
|
p.acquireCount += 1
|
||||||
|
if slowAcquire {
|
||||||
|
p.slowAcquireCount += 1
|
||||||
|
}
|
||||||
p.cond.L.Unlock()
|
p.cond.L.Unlock()
|
||||||
return rw, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slowAcquire = true
|
||||||
|
|
||||||
// If there is room to create a resource do so
|
// If there is room to create a resource do so
|
||||||
if len(p.allResources) < p.maxSize {
|
if len(p.allResources) < p.maxSize {
|
||||||
res := &Resource{pool: p, status: resourceStatusConstructing}
|
res := &Resource{pool: p, status: resourceStatusConstructing}
|
||||||
@@ -199,6 +224,8 @@ func (p *Pool) Acquire(ctx context.Context) (*Resource, error) {
|
|||||||
|
|
||||||
res.value = value
|
res.value = value
|
||||||
res.status = resourceStatusAcquired
|
res.status = resourceStatusAcquired
|
||||||
|
p.acquireCount += 1
|
||||||
|
p.slowAcquireCount += 1
|
||||||
p.cond.L.Unlock()
|
p.cond.L.Unlock()
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
@@ -230,18 +257,6 @@ func (p *Pool) Acquire(ctx context.Context) (*Resource, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// lockedIdleAcquire gets the top resource from p.idleResources. p.cond.L
|
|
||||||
// must already be locked. len(p.idleResources) must be > 0.
|
|
||||||
func (p *Pool) lockedIdleAcquire() *Resource {
|
|
||||||
rw := p.idleResources[len(p.idleResources)-1]
|
|
||||||
p.idleResources = p.idleResources[:len(p.idleResources)-1]
|
|
||||||
if rw.status != resourceStatusIdle {
|
|
||||||
panic("BUG: non-idle resource gotten from idleResources")
|
|
||||||
}
|
|
||||||
rw.status = resourceStatusAcquired
|
|
||||||
return rw
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) {
|
||||||
p.cond.L.Lock()
|
p.cond.L.Lock()
|
||||||
|
|||||||
+41
-1
@@ -261,7 +261,7 @@ func TestPoolCloseBlocksUntilAllResourcesReleasedAndClosed(t *testing.T) {
|
|||||||
assert.Equal(t, len(resources), closeCalls.Value())
|
assert.Equal(t, len(resources), closeCalls.Value())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPoolStat(t *testing.T) {
|
func TestPoolStatResources(t *testing.T) {
|
||||||
startWaitChan := make(chan struct{})
|
startWaitChan := make(chan struct{})
|
||||||
waitingChan := make(chan struct{})
|
waitingChan := make(chan struct{})
|
||||||
endWaitChan := make(chan struct{})
|
endWaitChan := make(chan struct{})
|
||||||
@@ -310,6 +310,46 @@ func TestPoolStat(t *testing.T) {
|
|||||||
close(endWaitChan)
|
close(endWaitChan)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPoolStatCounters(t *testing.T) {
|
||||||
|
createFunc, _ := createCreateResourceFunc()
|
||||||
|
pool := puddle.NewPool(createFunc, stubCloseRes, 1)
|
||||||
|
defer pool.Close()
|
||||||
|
|
||||||
|
res, err := pool.Acquire(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
res.Release()
|
||||||
|
|
||||||
|
stat := pool.Stat()
|
||||||
|
assert.Equal(t, int64(1), stat.AcquireCount())
|
||||||
|
assert.Equal(t, int64(1), stat.SlowAcquireCount())
|
||||||
|
|
||||||
|
res, err = pool.Acquire(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
res.Release()
|
||||||
|
|
||||||
|
stat = pool.Stat()
|
||||||
|
assert.Equal(t, int64(2), stat.AcquireCount())
|
||||||
|
assert.Equal(t, int64(1), stat.SlowAcquireCount())
|
||||||
|
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
res, err = pool.Acquire(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
res.Release()
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
stat = pool.Stat()
|
||||||
|
assert.Equal(t, int64(4), stat.AcquireCount())
|
||||||
|
assert.Equal(t, int64(2), stat.SlowAcquireCount())
|
||||||
|
}
|
||||||
|
|
||||||
func TestResourceDestroyRemovesResourceFromPool(t *testing.T) {
|
func TestResourceDestroyRemovesResourceFromPool(t *testing.T) {
|
||||||
createFunc, _ := createCreateResourceFunc()
|
createFunc, _ := createCreateResourceFunc()
|
||||||
var closeCalls Counter
|
var closeCalls Counter
|
||||||
|
|||||||
Reference in New Issue
Block a user