44 "context"
55 "database/sql/driver"
66 "io"
7+ "sync"
8+ "time"
79
810 metaHeaders "github.com/ydb-platform/ydb-go-sdk/v3/internal/meta"
911 "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
@@ -58,10 +60,18 @@ func WithDisableServerBalancer() ConnectorOption {
5860 }
5961}
6062
63+ func WithIdleThreshold (idleThreshold time.Duration ) ConnectorOption {
64+ return func (c * Connector ) error {
65+ c .idleThreshold = idleThreshold
66+ return nil
67+ }
68+ }
69+
6170func Open (d Driver , connection connection , opts ... ConnectorOption ) (_ * Connector , err error ) {
6271 c := & Connector {
6372 driver : d ,
6473 connection : connection ,
74+ conns : make (map [* conn ]struct {}),
6575 defaultTxControl : table .DefaultTxControl (),
6676 defaultQueryMode : DefaultQueryMode ,
6777 }
@@ -70,6 +80,9 @@ func Open(d Driver, connection connection, opts ...ConnectorOption) (_ *Connecto
7080 return nil , err
7181 }
7282 }
83+ if c .idleThreshold > 0 {
84+ c .idleStopper = c .idleCloser ()
85+ }
7386 d .Attach (c )
7487 return c , nil
7588}
@@ -97,11 +110,17 @@ type Connector struct {
97110 driver Driver
98111 connection connection
99112
113+ conns map [* conn ]struct {}
114+ connsMtx sync.RWMutex
115+
116+ idleStopper func ()
117+
100118 defaultTxControl * table.TransactionControl
101119 defaultQueryMode QueryMode
102120 defaultDataQueryOpts []options.ExecuteDataQueryOption
103121 defaultScanQueryOpts []options.ExecuteScanQueryOption
104122 disableServerBalancer bool
123+ idleThreshold time.Duration
105124
106125 trace trace.DatabaseSQL
107126}
@@ -111,15 +130,56 @@ var (
111130 _ io.Closer = & Connector {}
112131)
113132
133+ func (c * Connector ) idleCloser () (idleStopper func ()) {
134+ var ctx context.Context
135+ ctx , idleStopper = context .WithCancel (context .Background ())
136+ go func () {
137+ for {
138+ select {
139+ case <- ctx .Done ():
140+ return
141+ case <- time .After (c .idleThreshold ):
142+ c .connsMtx .RLock ()
143+ conns := make ([]* conn , 0 , len (c .conns ))
144+ for cc := range c .conns {
145+ conns = append (conns , cc )
146+ }
147+ c .connsMtx .RUnlock ()
148+ for _ , cc := range conns {
149+ if cc .sinceLastUsage () > c .idleThreshold {
150+ cc .session .Close (context .Background ())
151+ }
152+ }
153+ }
154+ }
155+ }()
156+ return idleStopper
157+ }
158+
114159func (c * Connector ) Close () (err error ) {
115160 defer c .driver .Detach (c )
161+ if c .idleStopper != nil {
162+ c .idleStopper ()
163+ }
116164 return nil
117165}
118166
119167func (c * Connector ) Connection () connection {
120168 return c .connection
121169}
122170
171+ func (c * Connector ) attach (cc * conn ) {
172+ c .connsMtx .Lock ()
173+ defer c .connsMtx .Unlock ()
174+ c .conns [cc ] = struct {}{}
175+ }
176+
177+ func (c * Connector ) detach (cc * conn ) {
178+ c .connsMtx .Lock ()
179+ defer c .connsMtx .Unlock ()
180+ delete (c .conns , cc )
181+ }
182+
123183func (c * Connector ) Connect (ctx context.Context ) (_ driver.Conn , err error ) {
124184 onDone := trace .DatabaseSQLOnConnectorConnect (c .trace , & ctx )
125185 defer func () {
0 commit comments