Skip to content

Commit 4c5f351

Browse files
authored
Merge pull request #1408 from ydb-platform/fix-session-pool
Do not create new items if index is full
2 parents b6be3a9 + 8831525 commit 4c5f351

File tree

3 files changed

+66
-36
lines changed

3 files changed

+66
-36
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
* Fixed out of index item creation in `internal/pool.Pool`
12
* Fixed tracing of `(*grpcClientStream).finish` event
23

34
## v3.76.4

internal/pool/pool.go

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -294,48 +294,51 @@ func (p *Pool[PT, T]) getItem(ctx context.Context) (_ PT, finalErr error) {
294294
return nil, xerrors.WithStackTrace(err)
295295
}
296296

297-
select {
298-
case <-p.done:
299-
return nil, xerrors.WithStackTrace(errClosedPool)
300-
case <-ctx.Done():
301-
return nil, xerrors.WithStackTrace(ctx.Err())
302-
default:
303-
var item PT
304-
p.mu.WithLock(func() {
305-
if len(p.idle) > 0 {
306-
item, p.idle = p.idle[0], p.idle[1:]
307-
p.stats.Idle().Dec()
308-
}
309-
})
297+
for {
298+
select {
299+
case <-p.done:
300+
return nil, xerrors.WithStackTrace(errClosedPool)
301+
case <-ctx.Done():
302+
return nil, xerrors.WithStackTrace(ctx.Err())
303+
default:
304+
var item PT
305+
p.mu.WithLock(func() {
306+
if len(p.idle) > 0 {
307+
item, p.idle = p.idle[0], p.idle[1:]
308+
p.stats.Idle().Dec()
309+
}
310+
})
310311

311-
if item != nil {
312-
if item.IsAlive() {
313-
return item, nil
312+
if item != nil {
313+
if item.IsAlive() {
314+
return item, nil
315+
}
316+
_ = p.closeItem(ctx, item)
317+
p.mu.WithLock(func() {
318+
delete(p.index, item)
319+
})
320+
p.stats.Index().Dec()
314321
}
315-
_ = p.closeItem(ctx, item)
322+
var err error
323+
var newItem PT
316324
p.mu.WithLock(func() {
317-
delete(p.index, item)
325+
if len(p.index) >= p.limit {
326+
return
327+
}
328+
newItem, err = p.createItem(ctx)
329+
if err != nil {
330+
return
331+
}
332+
p.index[newItem] = struct{}{}
333+
p.stats.Index().Inc()
318334
})
319-
p.stats.Index().Dec()
320-
}
321-
322-
item, err := p.createItem(ctx)
323-
if err != nil {
324-
return nil, xerrors.WithStackTrace(err)
325-
}
326-
327-
addedToIndex := false
328-
p.mu.WithLock(func() {
329-
if len(p.index) < p.limit {
330-
p.index[item] = struct{}{}
331-
addedToIndex = true
335+
if err != nil {
336+
return nil, xerrors.WithStackTrace(err)
337+
}
338+
if newItem != nil {
339+
return newItem, nil
332340
}
333-
})
334-
if addedToIndex {
335-
p.stats.Index().Inc()
336341
}
337-
338-
return item, nil
339342
}
340343
}
341344

internal/pool/pool_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,32 @@ func TestPool(t *testing.T) {
289289
wg.Wait()
290290
}, xtest.StopAfter(42*time.Second))
291291
})
292+
t.Run("ParallelCreation", func(t *testing.T) {
293+
xtest.TestManyTimes(t, func(t testing.TB) {
294+
p := New[*testItem, testItem](rootCtx)
295+
var wg sync.WaitGroup
296+
for range make([]struct{}, DefaultLimit*10) {
297+
wg.Add(1)
298+
go func() {
299+
defer wg.Done()
300+
err := p.With(rootCtx, func(ctx context.Context, testItem *testItem) error {
301+
return nil
302+
})
303+
if err != nil && !xerrors.Is(err, errClosedPool, context.Canceled) {
304+
t.Failed()
305+
}
306+
stats := p.Stats()
307+
require.LessOrEqual(t, stats.Idle+stats.InUse, DefaultLimit)
308+
}()
309+
}
310+
311+
wg.Wait()
312+
stats := p.Stats()
313+
require.Equal(t, DefaultLimit, stats.Limit)
314+
require.Equal(t, 0, stats.InUse)
315+
require.LessOrEqual(t, stats.Idle, DefaultLimit)
316+
}, xtest.StopAfter(30*time.Second))
317+
})
292318
}
293319

294320
func TestSafeStatsRace(t *testing.T) {

0 commit comments

Comments
 (0)