Skip to content

Commit ca570b1

Browse files
authored
Merge pull request #1720 from ydb-platform/session-limit
* Improved the `ydb.WithSessionPoolSessionUsageLimit` option for allow `time.Duration` as argument type for limit max session time to live since create time
2 parents c653ee4 + 0f525dd commit ca570b1

File tree

8 files changed

+109
-19
lines changed

8 files changed

+109
-19
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
* Improved the `ydb.WithSessionPoolSessionUsageLimit` option for allow `time.Duration` as argument type for limit max session time to live since create time
2+
13
## v3.105.1
24
* Changed the gRPC DNS balancer policy to `round_robin` for internal `discovery/ListEndpoints` call (reverted v3.90.2 changes)
35

internal/pool/pool.go

+62-4
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@ type (
4242
closeItemFunc func(ctx context.Context, item PT)
4343
idleTimeToLive time.Duration
4444
itemUsageLimit uint64
45+
itemUsageTTL time.Duration
4546
}
4647
itemInfo[PT ItemConstraint[T], T any] struct {
4748
idle *xlist.Element[PT]
49+
created time.Time
4850
lastUsage time.Time
4951
useCounter *uint64
5052
}
@@ -113,6 +115,12 @@ func WithItemUsageLimit[PT ItemConstraint[T], T any](itemUsageLimit uint64) Opti
113115
}
114116
}
115117

118+
func WithItemUsageTTL[PT ItemConstraint[T], T any](ttl time.Duration) Option[PT, T] {
119+
return func(c *Config[PT, T]) {
120+
c.itemUsageTTL = ttl
121+
}
122+
}
123+
116124
func WithTrace[PT ItemConstraint[T], T any](t *Trace) Option[PT, T] {
117125
return func(c *Config[PT, T]) {
118126
c.trace = t
@@ -235,9 +243,13 @@ func makeAsyncCreateItemFunc[PT ItemConstraint[T], T any]( //nolint:funlen
235243
newItem, err := p.config.createItemFunc(createCtx)
236244
if newItem != nil {
237245
p.mu.WithLock(func() {
238-
var useCounter uint64
246+
var (
247+
useCounter uint64
248+
now = p.config.clock.Now()
249+
)
239250
p.index[newItem] = itemInfo[PT, T]{
240-
lastUsage: p.config.clock.Now(),
251+
created: now,
252+
lastUsage: now,
241253
useCounter: &useCounter,
242254
}
243255
})
@@ -695,6 +707,53 @@ func (p *Pool[PT, T]) pushIdle(item PT, now time.Time) {
695707

696708
const maxAttempts = 100
697709

710+
func needCloseItemByMaxUsage[PT ItemConstraint[T], T any](c *Config[PT, T], info itemInfo[PT, T]) bool {
711+
if c.itemUsageLimit <= 0 {
712+
return false
713+
}
714+
if *info.useCounter < c.itemUsageLimit {
715+
return false
716+
}
717+
718+
return true
719+
}
720+
721+
func needCloseItemByTTL[PT ItemConstraint[T], T any](c *Config[PT, T], info itemInfo[PT, T]) bool {
722+
if c.itemUsageTTL <= 0 {
723+
return false
724+
}
725+
if c.clock.Since(info.created) < c.itemUsageTTL {
726+
return false
727+
}
728+
729+
return true
730+
}
731+
732+
func needCloseItemByIdleTTL[PT ItemConstraint[T], T any](c *Config[PT, T], info itemInfo[PT, T]) bool {
733+
if c.idleTimeToLive <= 0 {
734+
return false
735+
}
736+
if c.clock.Since(info.lastUsage) < c.idleTimeToLive {
737+
return false
738+
}
739+
740+
return true
741+
}
742+
743+
func needCloseItem[PT ItemConstraint[T], T any](c *Config[PT, T], info itemInfo[PT, T]) bool {
744+
if needCloseItemByMaxUsage(c, info) {
745+
return true
746+
}
747+
if needCloseItemByTTL(c, info) {
748+
return true
749+
}
750+
if needCloseItemByIdleTTL(c, info) {
751+
return true
752+
}
753+
754+
return false
755+
}
756+
698757
func (p *Pool[PT, T]) getItem(ctx context.Context) (item PT, finalErr error) { //nolint:funlen
699758
var (
700759
start = p.config.clock.Now()
@@ -749,8 +808,7 @@ func (p *Pool[PT, T]) getItem(ctx context.Context) (item PT, finalErr error) { /
749808
return info
750809
})
751810

752-
if (p.config.itemUsageLimit > 0 && *info.useCounter > p.config.itemUsageLimit) ||
753-
(p.config.idleTimeToLive > 0 && p.config.clock.Since(info.lastUsage) > p.config.idleTimeToLive) {
811+
if needCloseItem(&p.config, info) {
754812
p.closeItem(ctx, item,
755813
closeItemWithLock(),
756814
closeItemNotifyStats(),

internal/query/client.go

+1
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,7 @@ func New(ctx context.Context, cc grpc.ClientConnInterface, cfg *config.Config) *
575575
pool: pool.New(ctx,
576576
pool.WithLimit[*Session, Session](cfg.PoolLimit()),
577577
pool.WithItemUsageLimit[*Session, Session](cfg.PoolSessionUsageLimit()),
578+
pool.WithItemUsageTTL[*Session, Session](cfg.PoolSessionUsageTTL()),
578579
pool.WithTrace[*Session, Session](poolTrace(cfg.Trace())),
579580
pool.WithCreateItemTimeout[*Session, Session](cfg.SessionCreateTimeout()),
580581
pool.WithCloseItemTimeout[*Session, Session](cfg.SessionDeleteTimeout()),

internal/query/config/config.go

+5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type Config struct {
1919

2020
poolLimit int
2121
poolSessionUsageLimit uint64
22+
poolSessionUsageTTL time.Duration
2223

2324
sessionCreateTimeout time.Duration
2425
sessionDeleteTimeout time.Duration
@@ -65,6 +66,10 @@ func (c *Config) PoolSessionUsageLimit() uint64 {
6566
return c.poolSessionUsageLimit
6667
}
6768

69+
func (c *Config) PoolSessionUsageTTL() time.Duration {
70+
return c.poolSessionUsageTTL
71+
}
72+
6873
// SessionCreateTimeout limits maximum time spent on Create session request
6974
func (c *Config) SessionCreateTimeout() time.Duration {
7075
return c.sessionCreateTimeout

internal/query/config/options.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,17 @@ func WithPoolLimit(size int) Option {
3434
}
3535
}
3636

37-
func WithPoolSessionUsageLimit(sessionUsageLimit uint64) Option {
37+
// WithSessionPoolSessionUsageLimit set pool session max usage:
38+
// - if argument type is uint64 - WithSessionPoolSessionUsageLimit limits max usage count of pool session
39+
// - if argument type is time.Duration - WithSessionPoolSessionUsageLimit limits max time to live of pool session
40+
func WithSessionPoolSessionUsageLimit[T interface{ uint64 | time.Duration }](limit T) Option {
3841
return func(c *Config) {
39-
c.poolSessionUsageLimit = sessionUsageLimit
42+
switch v := any(limit).(type) {
43+
case uint64:
44+
c.poolSessionUsageLimit = v
45+
case time.Duration:
46+
c.poolSessionUsageTTL = v
47+
}
4048
}
4149
}
4250

internal/table/client.go

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ func New(ctx context.Context, cc grpc.ClientConnInterface, config *config.Config
4242
pool: pool.New[*Session, Session](ctx,
4343
pool.WithLimit[*Session, Session](config.SizeLimit()),
4444
pool.WithItemUsageLimit[*Session, Session](config.SessionUsageLimit()),
45+
pool.WithItemUsageTTL[*Session, Session](config.SessionUsageTTL()),
4546
pool.WithIdleTimeToLive[*Session, Session](config.IdleThreshold()),
4647
pool.WithCreateItemTimeout[*Session, Session](config.CreateSessionTimeout()),
4748
pool.WithCloseItemTimeout[*Session, Session](config.DeleteTimeout()),

internal/table/config/config.go

+22-9
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,27 @@ func With(config config.Common) Option {
5252
}
5353

5454
// WithSizeLimit defines upper bound of pooled sessions.
55-
// If sizeLimit is less than or equal to zero then the
55+
// If poolLimit is less than or equal to zero then the
5656
// DefaultSessionPoolSizeLimit variable is used as a limit.
5757
func WithSizeLimit(sizeLimit int) Option {
5858
return func(c *Config) {
5959
if sizeLimit > 0 {
60-
c.sizeLimit = sizeLimit
60+
c.poolLimit = sizeLimit
6161
}
6262
}
6363
}
6464

65-
func WithPoolSessionUsageLimit(sessionUsageLimit uint64) Option {
65+
// WithSessionPoolSessionUsageLimit set pool session max usage:
66+
// - if argument type is uint64 - WithSessionPoolSessionUsageLimit limits max usage count of pool session
67+
// - if argument type is time.Duration - WithSessionPoolSessionUsageLimit limits max time to live of pool session
68+
func WithSessionPoolSessionUsageLimit[T interface{ uint64 | time.Duration }](limit T) Option {
6669
return func(c *Config) {
67-
c.sessionUsageLimit = sessionUsageLimit
70+
switch v := any(limit).(type) {
71+
case uint64:
72+
c.poolSessionUsageLimit = v
73+
case time.Duration:
74+
c.poolSessionUsageTTL = v
75+
}
6876
}
6977
}
7078

@@ -182,8 +190,9 @@ func WithClock(clock clockwork.Clock) Option {
182190
type Config struct {
183191
config.Common
184192

185-
sizeLimit int
186-
sessionUsageLimit uint64
193+
poolLimit int
194+
poolSessionUsageLimit uint64
195+
poolSessionUsageTTL time.Duration
187196

188197
createSessionTimeout time.Duration
189198
deleteTimeout time.Duration
@@ -212,11 +221,15 @@ func (c *Config) Clock() clockwork.Clock {
212221
// If SizeLimit is less than or equal to zero then the
213222
// DefaultSessionPoolSizeLimit variable is used as a limit.
214223
func (c *Config) SizeLimit() int {
215-
return c.sizeLimit
224+
return c.poolLimit
216225
}
217226

218227
func (c *Config) SessionUsageLimit() uint64 {
219-
return c.sessionUsageLimit
228+
return c.poolSessionUsageLimit
229+
}
230+
231+
func (c *Config) SessionUsageTTL() time.Duration {
232+
return c.poolSessionUsageTTL
220233
}
221234

222235
// KeepAliveMinSize is a lower bound for sessions in the pool. If there are more sessions open, then
@@ -293,7 +306,7 @@ func (c *Config) DeleteTimeout() time.Duration {
293306

294307
func defaults() *Config {
295308
return &Config{
296-
sizeLimit: DefaultSessionPoolSizeLimit,
309+
poolLimit: DefaultSessionPoolSizeLimit,
297310
createSessionTimeout: DefaultSessionPoolCreateSessionTimeout,
298311
deleteTimeout: DefaultSessionPoolDeleteTimeout,
299312
idleThreshold: DefaultSessionPoolIdleThreshold,

options.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -531,11 +531,13 @@ func WithSessionPoolSizeLimit(sizeLimit int) Option {
531531
}
532532
}
533533

534-
// WithSessionPoolSessionUsageLimit set max count for use session
535-
func WithSessionPoolSessionUsageLimit(sessionUsageLimit uint64) Option {
534+
// WithSessionPoolSessionUsageLimit set pool session max usage:
535+
// - if argument type is uint64 - WithSessionPoolSessionUsageLimit limits max usage count of pool session
536+
// - if argument type is time.Duration - WithSessionPoolSessionUsageLimit limits max time to live of pool session
537+
func WithSessionPoolSessionUsageLimit[T interface{ uint64 | time.Duration }](limit T) Option {
536538
return func(ctx context.Context, d *Driver) error {
537-
d.tableOptions = append(d.tableOptions, tableConfig.WithPoolSessionUsageLimit(sessionUsageLimit))
538-
d.queryOptions = append(d.queryOptions, queryConfig.WithPoolSessionUsageLimit(sessionUsageLimit))
539+
d.tableOptions = append(d.tableOptions, tableConfig.WithSessionPoolSessionUsageLimit(limit))
540+
d.queryOptions = append(d.queryOptions, queryConfig.WithSessionPoolSessionUsageLimit(limit))
539541

540542
return nil
541543
}

0 commit comments

Comments
 (0)