Skip to content

Commit a3ee6a5

Browse files
authored
Merge pull request #151 from ydb-platform/cluster-empty
v3.13.1: improve error messages
2 parents 710f840 + 5cbdd4f commit a3ee6a5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+720
-487
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
## 3.13.1
2+
* Improved error messages
3+
* Defended `cluster.balancer` with `sync.RWMutex` on `cluster.Insert`, `cluster.Update`, `cluster.Remove` and `cluster.Get`
4+
* Excluded `Close` and `Park` methods from `conn.Conn` interface
5+
* Fixed bug with `Multi` balancer `Create()`
6+
* Improved `errors.IsTransportError` (check a few transport error codes instead check single transport error code)
7+
* Improved `errors.Is` (check a few errors instead check single error)
8+
* Refactored YDB errors checking API on client-side
9+
* Implemented of scripting traces
10+
111
## 3.13.0
212
* Refactored `Connection` interface
313
* Removed `CustomOption` and taking client with custom options

errors.go

Lines changed: 27 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -28,29 +28,24 @@ func IsTimeoutError(err error) bool {
2828
return errors.IsTimeoutError(err)
2929
}
3030

31-
func IsTransportError(err error) bool {
32-
return TransportErrorDescription(err) != nil
33-
}
34-
35-
func IsTransportErrorCode(err error, codes ...int32) bool {
36-
d := TransportErrorDescription(err)
37-
if d == nil {
38-
return false
39-
}
40-
for _, code := range codes {
41-
if d.Code() == code {
42-
return true
43-
}
44-
}
45-
return false
31+
func IsTransportError(err error, codes ...int32) bool {
32+
return errors.IsTransportError(
33+
err,
34+
func() (cc []errors.TransportErrorCode) {
35+
for _, code := range codes {
36+
cc = append(cc, errors.TransportErrorCode(code))
37+
}
38+
return cc
39+
}()...,
40+
)
4641
}
4742

4843
func IsTransportErrorCancelled(err error) bool {
49-
return IsTransportErrorCode(err, int32(errors.TransportErrorCanceled))
44+
return IsTransportError(err, int32(errors.TransportErrorCanceled))
5045
}
5146

5247
func IsTransportErrorResourceExhausted(err error) bool {
53-
return IsTransportErrorCode(err, int32(errors.TransportErrorResourceExhausted))
48+
return IsTransportError(err, int32(errors.TransportErrorResourceExhausted))
5449
}
5550

5651
type Error interface {
@@ -72,21 +67,16 @@ func IsYdbError(err error) bool {
7267
return IsTransportError(err) || IsOperationError(err)
7368
}
7469

75-
func IsOperationError(err error) bool {
76-
return OperationErrorDescription(err) != nil
77-
}
78-
79-
func IsOperationErrorCode(err error, codes ...int32) bool {
80-
d := OperationErrorDescription(err)
81-
if d == nil {
82-
return false
83-
}
84-
for _, code := range codes {
85-
if d.Code() == code {
86-
return true
87-
}
88-
}
89-
return false
70+
func IsOperationError(err error, codes ...int32) bool {
71+
return errors.IsOpError(
72+
err,
73+
func() (cc []errors.StatusCode) {
74+
for _, code := range codes {
75+
cc = append(cc, errors.StatusCode(code))
76+
}
77+
return cc
78+
}()...,
79+
)
9080
}
9181

9282
func OperationErrorDescription(err error) Error {
@@ -98,23 +88,23 @@ func OperationErrorDescription(err error) Error {
9888
}
9989

10090
func IsOperationErrorOverloaded(err error) bool {
101-
return IsOperationErrorCode(err, int32(errors.StatusOverloaded))
91+
return IsOperationError(err, int32(errors.StatusOverloaded))
10292
}
10393

10494
func IsOperationErrorUnavailable(err error) bool {
105-
return IsOperationErrorCode(err, int32(errors.StatusUnavailable))
95+
return IsOperationError(err, int32(errors.StatusUnavailable))
10696
}
10797

10898
func IsOperationErrorAlreadyExistsError(err error) bool {
109-
return IsOperationErrorCode(err, int32(errors.StatusAlreadyExists))
99+
return IsOperationError(err, int32(errors.StatusAlreadyExists))
110100
}
111101

112102
func IsOperationErrorNotFoundError(err error) bool {
113-
return IsOperationErrorCode(err, int32(errors.StatusNotFound))
103+
return IsOperationError(err, int32(errors.StatusNotFound))
114104
}
115105

116106
func IsOperationErrorSchemeError(err error) bool {
117-
return IsOperationErrorCode(err, int32(errors.StatusSchemeError))
107+
return IsOperationError(err, int32(errors.StatusSchemeError))
118108
}
119109

120110
func IsRatelimiterAcquireError(err error) bool {

internal/balancer/multi/multi.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ type multi struct {
2424
}
2525

2626
func (m *multi) Create() balancer.Balancer {
27-
bb := m.balancer
28-
for i := range bb {
29-
bb[i] = bb[i].(balancer.Creator).Create()
27+
bb := make([]balancer.Balancer, len(m.balancer))
28+
for i, b := range m.balancer {
29+
bb[i] = b.(balancer.Creator).Create()
3030
}
3131
return &multi{
3232
balancer: bb,

internal/cluster/cluster.go

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cluster
22

33
import (
44
"context"
5+
"fmt"
56
"sort"
67
"strings"
78
"sync"
@@ -26,29 +27,20 @@ const (
2627

2728
var (
2829
// ErrClusterClosed returned when requested on a closed cluster.
29-
ErrClusterClosed = errors.New("cluster closed")
30+
ErrClusterClosed = fmt.Errorf("cluster closed")
3031

3132
// ErrClusterEmpty returned when no connections left in cluster.
32-
ErrClusterEmpty = errors.New("cluster empty")
33-
34-
// ErrUnknownEndpoint returned when no connections left in cluster.
35-
ErrUnknownEndpoint = errors.New("unknown endpoint")
36-
37-
// ErrNilBalancerElement returned when requested on a nil Balancer element.
38-
ErrNilBalancerElement = errors.New("nil balancer element")
39-
40-
// ErrUnknownBalancerElement returned when requested on a unknown Balancer element.
41-
ErrUnknownBalancerElement = errors.New("unknown balancer element")
42-
43-
// ErrUnknownTypeOfBalancerElement returned when requested on a unknown types of Balancer element.
44-
ErrUnknownTypeOfBalancerElement = errors.New("unknown types of balancer element")
33+
ErrClusterEmpty = fmt.Errorf("cluster empty")
4534
)
4635

4736
type cluster struct {
48-
config config.Config
49-
pool conn.Pool
50-
dial func(context.Context, string) (*grpc.ClientConn, error)
51-
balancer balancer.Balancer
37+
config config.Config
38+
pool conn.Pool
39+
dial func(context.Context, string) (*grpc.ClientConn, error)
40+
41+
balancerMtx sync.RWMutex
42+
balancer balancer.Balancer
43+
5244
explorer repeater.Repeater
5345

5446
index map[string]entry.Entry
@@ -77,6 +69,9 @@ func (c *cluster) Pessimize(ctx context.Context, cc conn.Conn, cause error) {
7769
return
7870
}
7971

72+
c.balancerMtx.Lock()
73+
defer c.balancerMtx.Unlock()
74+
8075
if !c.balancer.Contains(entry.Handle) {
8176
return
8277
}
@@ -235,7 +230,7 @@ func (c *cluster) Get(ctx context.Context, opts ...crudOption) (cc conn.Conn, er
235230
defer c.mu.RUnlock()
236231

237232
if c.closed {
238-
return nil, ErrClusterClosed
233+
return nil, errors.Error(ErrClusterClosed)
239234
}
240235

241236
onDone := trace.DriverOnClusterGet(c.config.Trace(), &ctx)
@@ -258,9 +253,12 @@ func (c *cluster) Get(ctx context.Context, opts ...crudOption) (cc conn.Conn, er
258253
}
259254
}
260255

256+
c.balancerMtx.RLock()
257+
defer c.balancerMtx.RUnlock()
258+
261259
cc = c.balancer.Next()
262260
if cc == nil {
263-
return nil, ErrClusterEmpty
261+
return nil, errors.Error(ErrClusterEmpty)
264262
}
265263

266264
return cc, nil
@@ -297,7 +295,7 @@ func (c *cluster) Insert(ctx context.Context, e endpoint.Endpoint, opts ...crudO
297295

298296
entry := entry.Entry{Conn: cc}
299297

300-
inserted = entry.InsertInto(c.balancer)
298+
inserted = entry.InsertInto(c.balancer, &c.balancerMtx)
301299

302300
c.index[e.Address()] = entry
303301

@@ -346,10 +344,10 @@ func (c *cluster) Update(ctx context.Context, e endpoint.Endpoint, opts ...crudO
346344
c.endpoints[e.NodeID()] = entry.Conn
347345
}
348346

349-
if entry.Handle != nil {
350-
// entry.Handle may be nil when connection is being tracked.
351-
c.balancer.Update(entry.Handle, e.Info())
352-
}
347+
c.balancerMtx.Lock()
348+
defer c.balancerMtx.Unlock()
349+
350+
c.balancer.Update(entry.Handle, e.Info())
353351

354352
return entry.Conn
355353
}
@@ -379,16 +377,11 @@ func (c *cluster) Remove(ctx context.Context, e endpoint.Endpoint, opts ...crudO
379377
panic("ydb: can't remove not-existing endpoint")
380378
}
381379

382-
removed = entry.RemoveFrom(c.balancer)
380+
removed = entry.RemoveFrom(c.balancer, &c.balancerMtx)
383381

384382
delete(c.index, e.Address())
385383
delete(c.endpoints, e.NodeID())
386384

387-
if entry.Conn != nil {
388-
// entry.Conn may be nil when connection is being tracked after unsuccessful dial().
389-
_ = entry.Conn.Close(ctx)
390-
}
391-
392385
return entry.Conn
393386
}
394387

internal/cluster/cluster_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ func TestClusterFastRedial(t *testing.T) {
4646
done := make(chan struct{})
4747
go func() {
4848
for i := 0; i < size*10; i++ {
49-
c, err := c.Get(context.Background())
49+
cc, err := c.Get(context.Background())
5050
// enforce close bad connects to track them
51-
if err == nil && c != nil && c.Endpoint().Address() == "bad:0" {
52-
_ = c.Close(ctx)
51+
if err == nil && c != nil && cc.Endpoint().Address() == "bad:0" {
52+
_ = c.Remove(ctx, cc.Endpoint())
5353
}
5454
}
5555
close(done)
@@ -214,7 +214,7 @@ func (ln *stubListener) Accept() (net.Conn, error) {
214214
select {
215215
case ln.C <- c:
216216
case <-ln.exit:
217-
return nil, errors.Errorf(0, "closed")
217+
return nil, errors.Errorf("closed")
218218
}
219219
select {
220220
case ln.S <- s:
@@ -239,7 +239,7 @@ func (ln *stubListener) Dial(ctx context.Context) (*grpc.ClientConn, error) {
239239
grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) {
240240
select {
241241
case <-ln.exit:
242-
return nil, errors.Errorf(0, "refused")
242+
return nil, errors.Errorf("refused")
243243
case c := <-ln.C:
244244
return c, nil
245245
case <-ctx.Done():

internal/cluster/entry/entry.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package entry
22

33
import (
4+
"sync"
5+
46
"github.com/ydb-platform/ydb-go-sdk/v3/internal/balancer"
57
"github.com/ydb-platform/ydb-go-sdk/v3/internal/conn"
68
)
@@ -11,22 +13,26 @@ type Entry struct {
1113
Handle balancer.Element
1214
}
1315

14-
func (c *Entry) InsertInto(b balancer.Balancer) bool {
16+
func (c *Entry) InsertInto(b balancer.Balancer, mtx *sync.RWMutex) bool {
1517
if c.Handle != nil {
1618
panic("ydb: Handle already exists")
1719
}
1820
if c.Conn == nil {
1921
panic("ydb: can't insert nil Conn into balancer")
2022
}
23+
mtx.Lock()
2124
c.Handle = b.Insert(c.Conn)
25+
mtx.Unlock()
2226
return c.Handle != nil
2327
}
2428

25-
func (c *Entry) RemoveFrom(b balancer.Balancer) bool {
29+
func (c *Entry) RemoveFrom(b balancer.Balancer, mtx *sync.RWMutex) bool {
2630
if c.Handle == nil {
2731
return false
2832
}
33+
mtx.Lock()
2934
b.Remove(c.Handle)
35+
mtx.Unlock()
3036
c.Handle = nil
3137
return true
3238
}

0 commit comments

Comments
 (0)