@@ -4,12 +4,14 @@ import (
44 "container/list"
55 "context"
66 "fmt"
7+ "sort"
78 "sync"
89 "sync/atomic"
910 "time"
1011
1112 "google.golang.org/grpc"
1213
14+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/endpoint"
1315 "github.com/ydb-platform/ydb-go-sdk/v3/internal/meta"
1416 "github.com/ydb-platform/ydb-go-sdk/v3/internal/table/config"
1517 "github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
@@ -27,14 +29,20 @@ type sessionBuilderOption func(s *session)
2729// sessionBuilder is the interface that holds logic of creating sessions.
2830type sessionBuilder func (ctx context.Context , opts ... sessionBuilderOption ) (* session , error )
2931
30- func New (cc grpc.ClientConnInterface , config config.Config ) * Client {
31- return newClient (cc , func (ctx context.Context , opts ... sessionBuilderOption ) (s * session , err error ) {
32- return newSession (ctx , cc , config , opts ... )
32+ type balancerNotifier interface {
33+ grpc.ClientConnInterface
34+
35+ OnDiscovery (onDiscovery func (ctx context.Context , endpoints []endpoint.Info ))
36+ }
37+
38+ func New (balancer balancerNotifier , config config.Config ) * Client {
39+ return newClient (balancer , func (ctx context.Context , opts ... sessionBuilderOption ) (s * session , err error ) {
40+ return newSession (ctx , balancer , config , opts ... )
3341 }, config )
3442}
3543
3644func newClient (
37- cc grpc. ClientConnInterface ,
45+ balancer balancerNotifier ,
3846 builder sessionBuilder ,
3947 config config.Config ,
4048) * Client {
@@ -44,7 +52,7 @@ func newClient(
4452 )
4553 c := & Client {
4654 config : config ,
47- cc : cc ,
55+ cc : balancer ,
4856 build : builder ,
4957 index : make (map [* session ]sessionInfo ),
5058 idle : list .New (),
@@ -58,6 +66,9 @@ func newClient(
5866 },
5967 done : make (chan struct {}),
6068 }
69+ if balancer != nil {
70+ balancer .OnDiscovery (c .onDiscovery )
71+ }
6172 if idleThreshold := config .IdleThreshold (); idleThreshold > 0 {
6273 c .spawnedGoroutines .Add (1 )
6374 go c .internalPoolGC (ctx , idleThreshold )
@@ -107,6 +118,40 @@ func withCreateSessionOnClose(onClose func(s *session)) createSessionOption {
107118 }
108119}
109120
121+ func (c * Client ) onDiscovery (ctx context.Context , endpoints []endpoint.Info ) {
122+ nodeIDs := make ([]uint32 , len (endpoints ))
123+ for i , e := range endpoints {
124+ nodeIDs [i ] = e .NodeID ()
125+ }
126+ sort .Slice (nodeIDs , func (i , j int ) bool {
127+ return nodeIDs [i ] < nodeIDs [j ]
128+ })
129+ c .mu .WithLock (func () {
130+ touched := make (map [* session ]struct {}, len (c .index ))
131+ for e := c .idle .Front (); e != nil ; e = e .Next () {
132+ s := e .Value .(* session )
133+ nodeID := s .NodeID ()
134+ if sort .Search (len (nodeIDs ), func (i int ) bool {
135+ return nodeIDs [i ] >= nodeID
136+ }) == len (nodeIDs ) {
137+ c .internalPoolAsyncCloseSession (ctx , s )
138+ }
139+ touched [s ] = struct {}{}
140+ }
141+ for s := range c .index {
142+ if _ , has := touched [s ]; has {
143+ continue
144+ }
145+ nodeID := s .NodeID ()
146+ if sort .Search (len (nodeIDs ), func (i int ) bool {
147+ return nodeIDs [i ] >= nodeID
148+ }) == len (nodeIDs ) {
149+ s .SetStatus (options .SessionClosing )
150+ }
151+ }
152+ })
153+ }
154+
110155func (c * Client ) createSession (ctx context.Context , opts ... createSessionOption ) (s * session , err error ) {
111156 if c .isClosed () {
112157 return nil , errClosedClient
0 commit comments