Skip to content

Commit 510ab4b

Browse files
authored
Merge pull request #374 from ydb-platform/close-session-by-nodeid
marked truncated result as retryable error + added closing sessions i…
2 parents e0268b8 + 9926384 commit 510ab4b

File tree

15 files changed

+147
-107
lines changed

15 files changed

+147
-107
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
* Marked the truncated result as retryable error
2+
* Added closing sessions if node removed from discovery results
3+
* Moved session status type from `table/options` package to `table`
4+
* Changed session status source type from `uint32` to `string` alias
5+
16
## v3.37.6
27
* Added to balancer notifying mechanism for listening in table client event about removing some nodes and closing sessions on them
38
* Removed from public client interfaces `closer.Closer` (for exclude undefined behaviour on client-side)

internal/balancer/balancer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ type Balancer struct {
4141
onDiscovery []func(ctx context.Context, endpoints []endpoint.Info)
4242
}
4343

44-
func (b *Balancer) OnDiscovery(onDiscovery func(ctx context.Context, endpoints []endpoint.Info)) {
44+
func (b *Balancer) OnUpdate(onDiscovery func(ctx context.Context, endpoints []endpoint.Info)) {
4545
b.mu.WithLock(func() {
4646
b.onDiscovery = append(b.onDiscovery, onDiscovery)
4747
})

internal/endpoint/endpoint.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ func withLastUpdated(ts time.Time) Option {
150150
}
151151
}
152152

153-
func New(address string, opts ...Option) Endpoint {
153+
func New(address string, opts ...Option) *endpoint {
154154
e := &endpoint{
155155
address: address,
156156
lastUpdated: time.Now(),

internal/table/client.go

Lines changed: 87 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import (
1919
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsync"
2020
"github.com/ydb-platform/ydb-go-sdk/v3/retry"
2121
"github.com/ydb-platform/ydb-go-sdk/v3/table"
22-
"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
2322
"github.com/ydb-platform/ydb-go-sdk/v3/testutil/timeutil"
2423
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
2524
)
@@ -32,7 +31,7 @@ type sessionBuilder func(ctx context.Context, opts ...sessionBuilderOption) (*se
3231
type balancerNotifier interface {
3332
grpc.ClientConnInterface
3433

35-
OnDiscovery(onDiscovery func(ctx context.Context, endpoints []endpoint.Info))
34+
OnUpdate(onDiscovery func(ctx context.Context, endpoints []endpoint.Info))
3635
}
3736

3837
func New(balancer balancerNotifier, config config.Config) *Client {
@@ -55,6 +54,7 @@ func newClient(
5554
cc: balancer,
5655
build: builder,
5756
index: make(map[*session]sessionInfo),
57+
nodes: make(map[uint32]map[*session]struct{}),
5858
idle: list.New(),
5959
waitq: list.New(),
6060
limit: config.SizeLimit(),
@@ -67,7 +67,7 @@ func newClient(
6767
done: make(chan struct{}),
6868
}
6969
if balancer != nil {
70-
balancer.OnDiscovery(c.onDiscovery)
70+
balancer.OnUpdate(c.updateNodes)
7171
}
7272
if idleThreshold := config.IdleThreshold(); idleThreshold > 0 {
7373
c.spawnedGoroutines.Add(1)
@@ -88,6 +88,7 @@ type Client struct {
8888
// read-write fields
8989
mu xsync.Mutex
9090
index map[*session]sessionInfo
91+
nodes map[uint32]map[*session]struct{}
9192
createInProgress int // KIKIMR-9163: in-create-process counter
9293
limit int // Upper bound for Client size.
9394
idle *list.List // list<*session>
@@ -118,7 +119,7 @@ func withCreateSessionOnClose(onClose func(s *session)) createSessionOption {
118119
}
119120
}
120121

121-
func (c *Client) onDiscovery(ctx context.Context, endpoints []endpoint.Info) {
122+
func (c *Client) updateNodes(ctx context.Context, endpoints []endpoint.Info) {
122123
nodeIDs := make([]uint32, len(endpoints))
123124
for i, e := range endpoints {
124125
nodeIDs[i] = e.NodeID()
@@ -127,26 +128,17 @@ func (c *Client) onDiscovery(ctx context.Context, endpoints []endpoint.Info) {
127128
return nodeIDs[i] < nodeIDs[j]
128129
})
129130
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()
131+
for nodeID := range c.nodes {
134132
if sort.Search(len(nodeIDs), func(i int) bool {
135133
return nodeIDs[i] >= nodeID
136134
}) == 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)
135+
for s := range c.nodes[nodeID] {
136+
if info, has := c.index[s]; has && info.idle != nil {
137+
c.internalPoolAsyncCloseSession(ctx, s)
138+
} else {
139+
s.SetStatus(table.SessionClosing)
140+
}
141+
}
150142
}
151143
}
152144
})
@@ -256,13 +248,51 @@ func (c *Client) createSession(ctx context.Context, opts ...createSessionOption)
256248
}
257249
}
258250

251+
func (c *Client) appendSessionToNodes(s *session) {
252+
c.mu.WithLock(func() {
253+
nodeID := s.NodeID()
254+
sessions, has := c.nodes[nodeID]
255+
if !has {
256+
sessions = make(map[*session]struct{})
257+
}
258+
sessions[s] = struct{}{}
259+
c.nodes[nodeID] = sessions
260+
})
261+
}
262+
263+
func (c *Client) removeSessionFromNodes(s *session) {
264+
c.mu.WithLock(func() {
265+
nodeID := s.NodeID()
266+
sessions, has := c.nodes[nodeID]
267+
if !has {
268+
sessions = make(map[*session]struct{})
269+
}
270+
delete(sessions, s)
271+
if len(sessions) == 0 {
272+
delete(c.nodes, nodeID)
273+
} else {
274+
c.nodes[nodeID] = sessions
275+
}
276+
})
277+
}
278+
259279
func (c *Client) CreateSession(ctx context.Context, opts ...table.Option) (_ table.ClosableSession, err error) {
260280
if c == nil {
261281
return nil, xerrors.WithStackTrace(errNilClient)
262282
}
263283
var s *session
284+
createSession := func(ctx context.Context) (*session, error) {
285+
s, err = c.createSession(ctx,
286+
withCreateSessionOnCreate(c.appendSessionToNodes),
287+
withCreateSessionOnClose(c.removeSessionFromNodes),
288+
)
289+
if err != nil {
290+
return nil, xerrors.WithStackTrace(err)
291+
}
292+
return s, nil
293+
}
264294
if !c.config.AutoRetry() {
265-
s, err = c.createSession(ctx)
295+
s, err = createSession(ctx)
266296
if err != nil {
267297
return nil, xerrors.WithStackTrace(err)
268298
}
@@ -272,7 +302,7 @@ func (c *Client) CreateSession(ctx context.Context, opts ...table.Option) (_ tab
272302
err = retry.Retry(
273303
ctx,
274304
func(ctx context.Context) (err error) {
275-
s, err = c.createSession(ctx)
305+
s, err = createSession(ctx)
276306
if err != nil {
277307
return xerrors.WithStackTrace(err)
278308
}
@@ -328,40 +358,45 @@ func (c *Client) internalPoolCreateSession(ctx context.Context) (s *session, err
328358
})
329359
}()
330360

331-
s, err = c.createSession(meta.WithAllowFeatures(ctx,
332-
meta.HintSessionBalancer,
333-
), withCreateSessionOnCreate(func(s *session) {
334-
c.mu.WithLock(func() {
335-
c.index[s] = sessionInfo{
336-
touched: timeutil.Now(),
337-
}
338-
trace.TableOnPoolSessionAdd(c.config.Trace(), s)
339-
trace.TableOnPoolStateChange(c.config.Trace(), len(c.index), "append")
340-
})
341-
}), withCreateSessionOnClose(func(s *session) {
342-
c.mu.WithLock(func() {
343-
info, has := c.index[s]
344-
if !has {
345-
panic("session not found in pool")
346-
}
361+
s, err = c.createSession(
362+
meta.WithAllowFeatures(ctx,
363+
meta.HintSessionBalancer,
364+
),
365+
withCreateSessionOnCreate(c.appendSessionToNodes),
366+
withCreateSessionOnClose(c.removeSessionFromNodes),
367+
withCreateSessionOnCreate(func(s *session) {
368+
c.mu.WithLock(func() {
369+
c.index[s] = sessionInfo{
370+
touched: timeutil.Now(),
371+
}
372+
trace.TableOnPoolSessionAdd(c.config.Trace(), s)
373+
trace.TableOnPoolStateChange(c.config.Trace(), len(c.index), "append")
374+
})
375+
}), withCreateSessionOnClose(func(s *session) {
376+
c.mu.WithLock(func() {
377+
info, has := c.index[s]
378+
if !has {
379+
panic("session not found in pool")
380+
}
347381

348-
delete(c.index, s)
382+
delete(c.index, s)
349383

350-
trace.TableOnPoolSessionRemove(c.config.Trace(), s)
351-
trace.TableOnPoolStateChange(c.config.Trace(), len(c.index), "remove")
384+
trace.TableOnPoolSessionRemove(c.config.Trace(), s)
385+
trace.TableOnPoolStateChange(c.config.Trace(), len(c.index), "remove")
352386

353-
if !c.isClosed() {
354-
c.internalPoolNotify(nil)
355-
}
387+
if !c.isClosed() {
388+
c.internalPoolNotify(nil)
389+
}
356390

357-
if info.idle != nil {
358-
c.idle.Remove(info.idle)
359-
}
360-
})
361-
}))
391+
if info.idle != nil {
392+
c.idle.Remove(info.idle)
393+
}
394+
})
395+
}))
362396
if err != nil {
363397
return nil, xerrors.WithStackTrace(err)
364398
}
399+
365400
return s, nil
366401
}
367402

@@ -596,7 +631,7 @@ func (c *Client) Close(ctx context.Context) (err error) {
596631
for e := c.idle.Front(); e != nil; e = e.Next() {
597632
wg.Add(1)
598633
s := e.Value.(*session)
599-
s.SetStatus(options.SessionClosing)
634+
s.SetStatus(table.SessionClosing)
600635
go func() {
601636
defer wg.Done()
602637
c.internalPoolSyncCloseSession(ctx, s)
@@ -770,7 +805,7 @@ func (c *Client) internalPoolNotify(s *session) (notified bool) {
770805
}
771806

772807
func (c *Client) internalPoolAsyncCloseSession(ctx context.Context, s *session) {
773-
s.SetStatus(options.SessionClosing)
808+
s.SetStatus(table.SessionClosing)
774809
c.spawnedGoroutines.Add(1)
775810
go func() {
776811
defer c.spawnedGoroutines.Done()

internal/table/retry_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xrand"
1616
"github.com/ydb-platform/ydb-go-sdk/v3/retry"
1717
"github.com/ydb-platform/ydb-go-sdk/v3/table"
18-
"github.com/ydb-platform/ydb-go-sdk/v3/table/options"
1918
"github.com/ydb-platform/ydb-go-sdk/v3/testutil"
2019
)
2120

@@ -154,7 +153,7 @@ func TestRetryerSessionClosing(t *testing.T) {
154153
config.New(),
155154
func(ctx context.Context, s table.Session) error {
156155
sessions = append(sessions, s)
157-
s.(*session).SetStatus(options.SessionClosing)
156+
s.(*session).SetStatus(table.SessionClosing)
158157
return nil
159158
},
160159
table.Options{},

internal/table/scanner/scanner.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
"github.com/ydb-platform/ydb-go-sdk/v3/table/types"
2424
)
2525

26-
var errTruncated = xerrors.Wrap(errors.New("truncated result"))
26+
var errTruncated = xerrors.Retryable(errors.New("truncated result"))
2727

2828
type scanner struct {
2929
set *Ydb.ResultSet

internal/table/session.go

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,9 @@ type session struct {
4646
tableService Ydb_Table_V1.TableServiceClient
4747
config config.Config
4848

49-
status options.SessionStatus
50-
nodeID uint32
49+
status table.SessionStatus
50+
statusMtx sync.RWMutex
51+
nodeID uint32
5152

5253
onClose []func(s *session)
5354
closeOnce sync.Once
@@ -72,23 +73,27 @@ func (s *session) NodeID() uint32 {
7273
return uint32(nodeID)
7374
}
7475

75-
func (s *session) Status() string {
76+
func (s *session) Status() table.SessionStatus {
7677
if s == nil {
77-
return ""
78+
return table.SessionStatusUnknown
7879
}
79-
return options.SessionStatus(atomic.LoadUint32((*uint32)(&s.status))).String()
80+
s.statusMtx.RLock()
81+
defer s.statusMtx.RUnlock()
82+
return s.status
8083
}
8184

82-
func (s *session) SetStatus(status options.SessionStatus) {
83-
atomic.StoreUint32((*uint32)(&s.status), uint32(status))
85+
func (s *session) SetStatus(status table.SessionStatus) {
86+
s.statusMtx.Lock()
87+
defer s.statusMtx.Unlock()
88+
s.status = status
8489
}
8590

8691
func (s *session) isClosed() bool {
87-
return options.SessionStatus(atomic.LoadUint32((*uint32)(&s.status))) == options.SessionClosed
92+
return s.Status() == table.SessionClosed
8893
}
8994

9095
func (s *session) isClosing() bool {
91-
return options.SessionStatus(atomic.LoadUint32((*uint32)(&s.status))) == options.SessionClosing
96+
return s.Status() == table.SessionClosing
9297
}
9398

9499
func newSession(ctx context.Context, cc grpc.ClientConnInterface, config config.Config, opts ...sessionBuilderOption) (
@@ -129,6 +134,7 @@ func newSession(ctx context.Context, cc grpc.ClientConnInterface, config config.
129134
id: result.GetSessionId(),
130135
tableService: c,
131136
config: config,
137+
status: table.SessionReady,
132138
}
133139

134140
for _, o := range opts {
@@ -159,7 +165,7 @@ func (s *session) Close(ctx context.Context) (err error) {
159165

160166
s.closeOnce.Do(func() {
161167
defer func() {
162-
s.SetStatus(options.SessionClosed)
168+
s.SetStatus(table.SessionClosed)
163169
}()
164170

165171
onDone := trace.TableOnSessionDelete(s.config.Trace(), &ctx, s)
@@ -231,9 +237,9 @@ func (s *session) KeepAlive(ctx context.Context) (err error) {
231237
}
232238
switch result.SessionStatus {
233239
case Ydb_Table.KeepAliveResult_SESSION_STATUS_READY:
234-
s.SetStatus(options.SessionReady)
240+
s.SetStatus(table.SessionReady)
235241
case Ydb_Table.KeepAliveResult_SESSION_STATUS_BUSY:
236-
s.SetStatus(options.SessionBusy)
242+
s.SetStatus(table.SessionBusy)
237243
}
238244
return nil
239245
}
@@ -446,7 +452,7 @@ func (s *session) checkError(err error) {
446452
return
447453
}
448454
if m := retry.Check(err); m.MustDeleteSession() {
449-
s.SetStatus(options.SessionClosing)
455+
s.SetStatus(table.SessionClosing)
450456
}
451457
}
452458

internal/table/session_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,17 @@ func TestSessionKeepAlive(t *testing.T) {
6565
if err != nil {
6666
t.Fatal(err)
6767
}
68-
if s.Status() != options.SessionReady.String() {
69-
t.Fatalf("Result %v differ from, expectd %v", s.Status(), options.SessionReady.String())
68+
if s.Status() != table.SessionReady {
69+
t.Fatalf("Result %v differ from, expectd %v", s.Status(), table.SessionReady)
7070
}
7171

7272
status, e = Ydb_Table.KeepAliveResult_SESSION_STATUS_BUSY, nil
7373
err = s.KeepAlive(ctx)
7474
if err != nil {
7575
t.Fatal(err)
7676
}
77-
if s.Status() != options.SessionBusy.String() {
78-
t.Fatalf("Result %v differ from, expectd %v", s.Status(), options.SessionBusy.String())
77+
if s.Status() != table.SessionBusy {
78+
t.Fatalf("Result %v differ from, expectd %v", s.Status(), table.SessionBusy)
7979
}
8080
}
8181

0 commit comments

Comments
 (0)