Skip to content

Commit 6ce4bde

Browse files
committed
fix go test race conditation
1 parent deef65f commit 6ce4bde

File tree

2 files changed

+68
-41
lines changed

2 files changed

+68
-41
lines changed

pkg/pool/pool.go

+32-17
Original file line numberDiff line numberDiff line change
@@ -173,25 +173,37 @@ func (p *simpleObjectPool) dispose(res types.NetworkResource) {
173173
}
174174
}
175175

176-
func (p *simpleObjectPool) tooManyIdle() bool {
177-
return p.idle.Size() > p.maxIdle || (p.idle.Size() > 0 && p.size() > p.capacity)
176+
func (p *simpleObjectPool) tooManyIdleLocked() bool {
177+
return p.idle.Size() > p.maxIdle || (p.idle.Size() > 0 && p.sizeLocked() > p.capacity)
178+
}
179+
180+
func (p *simpleObjectPool) peekOverfullIdle() *poolItem {
181+
p.lock.Lock()
182+
defer p.lock.Unlock()
183+
184+
if !p.tooManyIdleLocked() {
185+
return nil
186+
}
187+
188+
item := p.idle.Peek()
189+
if item == nil {
190+
return nil
191+
}
192+
193+
if item.reverse.After(time.Now()) {
194+
return nil
195+
}
196+
return p.idle.Pop()
178197
}
179198

180199
//found resources that can be disposed, put them into dispose channel
181-
//must in lock
182200
func (p *simpleObjectPool) checkIdle() {
183-
for p.tooManyIdle() {
184-
p.lock.Lock()
185-
item := p.idle.Peek()
201+
for {
202+
item := p.peekOverfullIdle()
186203
if item == nil {
187-
//impossible
188-
break
189-
}
190-
if item.reverse.After(time.Now()) {
191204
break
192205
}
193-
item = p.idle.Pop()
194-
p.lock.Unlock()
206+
195207
res := item.res
196208
log.Infof("try dispose res %+v", res)
197209
err := p.factory.Dispose(res)
@@ -201,36 +213,39 @@ func (p *simpleObjectPool) checkIdle() {
201213
log.Warnf("error dispose res: %+v", err)
202214
p.AddIdle(res)
203215
}
216+
204217
}
205218
}
206219

207220
func (p *simpleObjectPool) preload() error {
221+
p.lock.Lock()
222+
defer p.lock.Unlock()
208223
for {
209224
// init resource sequential to avoid huge creating request on startup
210225
if p.idle.Size() >= p.minIdle {
211226
break
212227
}
213228

214-
if p.size() >= p.capacity {
229+
if p.sizeLocked() >= p.capacity {
215230
break
216231
}
217232

218233
res, err := p.factory.Create()
219234
if err != nil {
220235
return err
221236
}
222-
p.AddIdle(res)
237+
p.idle.Push(&poolItem{res: res, reverse: time.Now()})
223238
}
224239

225-
tokenCount := p.capacity - p.size()
240+
tokenCount := p.capacity - p.sizeLocked()
226241
for i := 0; i < tokenCount; i++ {
227242
p.tokenCh <- struct{}{}
228243
}
229244

230245
return nil
231246
}
232247

233-
func (p *simpleObjectPool) size() int {
248+
func (p *simpleObjectPool) sizeLocked() int {
234249
return p.idle.Size() + len(p.inuse)
235250
}
236251

@@ -254,7 +269,7 @@ func (p *simpleObjectPool) Acquire(ctx context.Context, resID string) (types.Net
254269
log.Infof("acquire (expect %s): return idle %s", resID, res.GetResourceID())
255270
return res, nil
256271
}
257-
size := p.size()
272+
size := p.sizeLocked()
258273
if size >= p.capacity {
259274
p.lock.Unlock()
260275
log.Infof("acquire (expect %s), size %d, capacity %d: return err %v", resID, size, p.capacity, ErrNoAvailableResource)

pkg/pool/pool_test.go

+36-24
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ import (
1111
)
1212

1313
type mockObjectFactory struct {
14-
createDelay time.Duration
15-
disposeDeplay time.Duration
16-
err error
17-
totalCreated int
18-
totalDisplosed int
19-
idGenerator int
20-
lock sync.Mutex
14+
createDelay time.Duration
15+
disposeDeplay time.Duration
16+
err error
17+
totalCreated int
18+
totalDisposed int
19+
idGenerator int
20+
lock sync.Mutex
2121
}
2222

2323
type mockNetworkResource struct {
@@ -55,24 +55,36 @@ func (f *mockObjectFactory) Dispose(types.NetworkResource) error {
5555
time.Sleep(f.disposeDeplay)
5656
f.lock.Lock()
5757
defer f.lock.Unlock()
58-
f.totalDisplosed++
58+
f.totalDisposed++
5959
return f.err
6060
}
6161

62+
func (f *mockObjectFactory) getTotalDisposed() int {
63+
f.lock.Lock()
64+
defer f.lock.Unlock()
65+
return f.totalDisposed
66+
}
67+
68+
func (f *mockObjectFactory) getTotalCreated() int {
69+
f.lock.Lock()
70+
defer f.lock.Unlock()
71+
return f.totalCreated
72+
}
73+
6274
func TestInitializerWithoutAutoCreate(t *testing.T) {
6375
factory := &mockObjectFactory{}
6476
createPool(factory, 3, 0)
6577
time.Sleep(time.Second)
66-
assert.Equal(t, 0, factory.totalCreated)
67-
assert.Equal(t, 0, factory.totalDisplosed)
78+
assert.Equal(t, 0, factory.getTotalCreated())
79+
assert.Equal(t, 0, factory.getTotalDisposed())
6880
}
6981

7082
func TestInitializerWithAutoCreate(t *testing.T) {
7183
factory := &mockObjectFactory{}
7284
createPool(factory, 0, 0)
7385
time.Sleep(time.Second)
74-
assert.Equal(t, 3, factory.totalCreated)
75-
assert.Equal(t, 0, factory.totalDisplosed)
86+
assert.Equal(t, 3, factory.getTotalCreated())
87+
assert.Equal(t, 0, factory.getTotalDisposed())
7688
}
7789

7890
func createPool(factory ObjectFactory, initIdle, initInuse int) ObjectPool {
@@ -105,39 +117,39 @@ func TestInitializerExceedMaxIdle(t *testing.T) {
105117
factory := &mockObjectFactory{}
106118
createPool(factory, 6, 0)
107119
time.Sleep(1 * time.Second)
108-
assert.Equal(t, 0, factory.totalCreated)
109-
assert.Equal(t, 1, factory.totalDisplosed)
120+
assert.Equal(t, 0, factory.getTotalCreated())
121+
assert.Equal(t, 1, factory.getTotalDisposed())
110122
}
111123

112124
func TestInitializerExceedCapacity(t *testing.T) {
113125
factory := &mockObjectFactory{}
114126
createPool(factory, 1, 10)
115127
time.Sleep(time.Second)
116-
assert.Equal(t, 0, factory.totalCreated)
117-
assert.Equal(t, 1, factory.totalDisplosed)
128+
assert.Equal(t, 0, factory.getTotalCreated())
129+
assert.Equal(t, 1, factory.getTotalDisposed())
118130
}
119131

120132
func TestAcquireIdle(t *testing.T) {
121133
factory := &mockObjectFactory{}
122134
pool := createPool(factory, 3, 0)
123135
_, err := pool.Acquire(context.Background(), "")
124136
assert.Nil(t, err)
125-
assert.Equal(t, 0, factory.totalCreated)
137+
assert.Equal(t, 0, factory.getTotalCreated())
126138
}
127139
func TestAcquireNonExists(t *testing.T) {
128140
factory := &mockObjectFactory{}
129141
pool := createPool(factory, 3, 0)
130142
_, err := pool.Acquire(context.Background(), "1000")
131143
assert.Nil(t, err)
132-
assert.Equal(t, 0, factory.totalCreated)
144+
assert.Equal(t, 0, factory.getTotalCreated())
133145
}
134146

135147
func TestAcquireExists(t *testing.T) {
136148
factory := &mockObjectFactory{}
137149
pool := createPool(factory, 3, 0)
138150
res, err := pool.Acquire(context.Background(), "2")
139151
assert.Nil(t, err)
140-
assert.Equal(t, 0, factory.totalCreated)
152+
assert.Equal(t, 0, factory.getTotalCreated())
141153
assert.Equal(t, "2", res.GetResourceID())
142154
}
143155

@@ -176,7 +188,7 @@ func TestConcurrencyAcquireMoreThanCapacity(t *testing.T) {
176188
}()
177189
}
178190
wg.Wait()
179-
assert.Equal(t, 7, factory.totalCreated)
191+
assert.Equal(t, 7, factory.getTotalCreated())
180192
}
181193

182194
func TestRelease(t *testing.T) {
@@ -190,19 +202,19 @@ func TestRelease(t *testing.T) {
190202
n4, _ := pool.Acquire(context.Background(), "")
191203
n5, _ := pool.Acquire(context.Background(), "")
192204
n6, _ := pool.Acquire(context.Background(), "")
193-
assert.Equal(t, 3, factory.totalCreated)
205+
assert.Equal(t, 3, factory.getTotalCreated())
194206
pool.Release(n1.GetResourceID())
195207
pool.Release(n2.GetResourceID())
196208
pool.Release(n3.GetResourceID())
197209
time.Sleep(1 * time.Second)
198-
assert.Equal(t, 0, factory.totalDisplosed)
210+
assert.Equal(t, 0, factory.getTotalDisposed())
199211
pool.Release(n4.GetResourceID())
200212
pool.Release(n5.GetResourceID())
201213
time.Sleep(1 * time.Second)
202-
assert.Equal(t, 0, factory.totalDisplosed)
214+
assert.Equal(t, 0, factory.getTotalDisposed())
203215
pool.Release(n6.GetResourceID())
204216
time.Sleep(1 * time.Second)
205-
assert.Equal(t, 1, factory.totalDisplosed)
217+
assert.Equal(t, 1, factory.getTotalDisposed())
206218
}
207219

208220
func TestReleaseInvalid(t *testing.T) {

0 commit comments

Comments
 (0)