Skip to content

Commit 171f843

Browse files
authored
Convert Session Moved Error and Closing Error to Connection Error (#6)
* Convert Session Moved Error and Closing Error to Connection Error * Remove clientWatchEvent
1 parent 7317a0b commit 171f843

File tree

4 files changed

+93
-42
lines changed

4 files changed

+93
-42
lines changed

client.go

+14-32
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ type Client struct {
9191
conn NetworkConn
9292

9393
creds []authCreds
94-
watchers map[watchPathType][]func(ev clientWatchEvent)
94+
watchers map[watchPathType][]func(ev Event)
9595
// =================================
9696

9797
wg sync.WaitGroup
@@ -176,15 +176,9 @@ type handleEvent struct {
176176
req clientRequest
177177
}
178178

179-
type clientWatchEvent struct {
180-
Type EventType
181-
State State
182-
Path string // For non-session events, the path of the watched node.
183-
}
184-
185179
type clientWatchRequest struct {
186180
pathType watchPathType
187-
callback func(ev clientWatchEvent)
181+
callback func(ev Event)
188182
}
189183

190184
// NetworkConn for connections when connecting to zookeeper.
@@ -233,7 +227,7 @@ func newClientInternal(servers []string, sessionTimeout time.Duration, options .
233227

234228
recvMap: map[int32]clientRequest{},
235229

236-
watchers: map[watchPathType][]func(ev clientWatchEvent){},
230+
watchers: map[watchPathType][]func(ev Event){},
237231

238232
pingSignalChan: make(chan struct{}, 10),
239233
pingCloseChan: make(chan struct{}),
@@ -596,7 +590,7 @@ func (c *Client) authenticate(conn NetworkConn) error {
596590
c.appendHandleQueueGlobalEvent(c.sessExpiredCallback)
597591
}
598592

599-
c.watchers = map[watchPathType][]func(ev clientWatchEvent){}
593+
c.watchers = map[watchPathType][]func(ev Event){}
600594

601595
c.mut.Unlock()
602596

@@ -1009,7 +1003,7 @@ func (c *Client) handleNormalResponse(res responseHeader, buf []byte, blen int)
10091003
}
10101004

10111005
output := connNormal()
1012-
if res.Err == errSessionExpired {
1006+
if res.Err == errSessionExpired || res.Err == errSessionMoved || res.Err == errClosing {
10131007
err = ErrConnectionClosed
10141008
output = connError(err)
10151009
}
@@ -1027,7 +1021,7 @@ func (c *Client) handleWatchEvent(buf []byte, blen int, res responseHeader) conn
10271021
log.Panicf("Unable to decode watch event, err: %v", err)
10281022
}
10291023

1030-
ev := clientWatchEvent{
1024+
ev := Event{
10311025
Type: watchResp.Type,
10321026
State: watchResp.State,
10331027
Path: watchResp.Path,
@@ -1037,7 +1031,7 @@ func (c *Client) handleWatchEvent(buf []byte, blen int, res responseHeader) conn
10371031
defer c.mut.Unlock()
10381032

10391033
watchTypes := computeWatchTypes(watchResp.Type)
1040-
var callbacks []func(ev clientWatchEvent)
1034+
var callbacks []func(ev Event)
10411035
for _, wType := range watchTypes {
10421036
wpt := watchPathType{path: ev.Path, wType: wType}
10431037
callbacks = append(callbacks, c.watchers[wpt]...)
@@ -1049,7 +1043,7 @@ func (c *Client) handleWatchEvent(buf []byte, blen int, res responseHeader) conn
10491043
opcode: opWatcherEvent,
10501044
response: &ev,
10511045
callback: func(res any, zxid int64, err error) {
1052-
ev := res.(*clientWatchEvent)
1046+
ev := res.(*Event)
10531047
for _, cb := range callbacks {
10541048
cb(*ev)
10551049
}
@@ -1184,12 +1178,8 @@ func (c *Client) Children(
11841178
path: path,
11851179
wType: watchTypeChild,
11861180
},
1187-
callback: func(ev clientWatchEvent) {
1188-
opts.watchCallback(Event{
1189-
Type: ev.Type,
1190-
State: ev.State,
1191-
Path: ev.Path,
1192-
})
1181+
callback: func(ev Event) {
1182+
opts.watchCallback(ev)
11931183
},
11941184
}
11951185
}
@@ -1273,12 +1263,8 @@ func (c *Client) Get(
12731263
path: path,
12741264
wType: watchTypeData,
12751265
},
1276-
callback: func(ev clientWatchEvent) {
1277-
opts.watchCallback(Event{
1278-
Type: ev.Type,
1279-
State: ev.State,
1280-
Path: ev.Path,
1281-
})
1266+
callback: func(ev Event) {
1267+
opts.watchCallback(ev)
12821268
},
12831269
}
12841270
}
@@ -1396,12 +1382,8 @@ func (c *Client) Exists(
13961382
path: path,
13971383
wType: watchTypeExist,
13981384
},
1399-
callback: func(ev clientWatchEvent) {
1400-
opts.watchCallback(Event{
1401-
Type: ev.Type,
1402-
State: ev.State,
1403-
Path: ev.Path,
1404-
})
1385+
callback: func(ev Event) {
1386+
opts.watchCallback(ev)
14051387
},
14061388
}
14071389
}

client_test.go

+70-2
Original file line numberDiff line numberDiff line change
@@ -803,7 +803,7 @@ func TestClient_RecvData(t *testing.T) {
803803
path: "/workers-resp",
804804
wType: watchTypeData,
805805
},
806-
callback: func(ev clientWatchEvent) {},
806+
callback: func(ev Event) {},
807807
},
808808
)
809809

@@ -820,7 +820,7 @@ func TestClient_RecvData(t *testing.T) {
820820
req: clientRequest{
821821
xid: -1,
822822
opcode: opWatcherEvent,
823-
response: &clientWatchEvent{
823+
response: &Event{
824824
Type: EventNodeDataChanged,
825825
State: StateHasSession,
826826
Path: "/workers-resp",
@@ -866,6 +866,74 @@ func TestClient_RecvData(t *testing.T) {
866866
assert.Equal(t, ErrConnectionClosed, queue[0].err)
867867
})
868868

869+
t.Run("receive session moved error", func(t *testing.T) {
870+
c := newClientTest(t)
871+
c.doAuthenticate()
872+
873+
c.client.enqueueRequest(
874+
opGetData, &getDataRequest{}, &getDataResponse{},
875+
nil,
876+
)
877+
c.client.getFromSendQueue()
878+
879+
buf := make([]byte, 2048)
880+
n1, _ := encodePacket(buf[4:], &responseHeader{
881+
Xid: 1,
882+
Zxid: 73,
883+
Err: errSessionMoved,
884+
})
885+
binary.BigEndian.PutUint32(buf[:4], uint32(n1))
886+
887+
c.conn.readBuf.Write(buf[:4+n1])
888+
889+
output := c.client.readSingleData(c.conn)
890+
assert.Equal(t, connIOOutput{
891+
closed: false,
892+
broken: true,
893+
err: ErrConnectionClosed,
894+
}, output)
895+
896+
// Check Handle Queue
897+
queue := c.client.handleQueue
898+
899+
assert.Equal(t, 1, len(queue))
900+
assert.Equal(t, ErrConnectionClosed, queue[0].err)
901+
})
902+
903+
t.Run("receive zookeeper is closing error", func(t *testing.T) {
904+
c := newClientTest(t)
905+
c.doAuthenticate()
906+
907+
c.client.enqueueRequest(
908+
opGetData, &getDataRequest{}, &getDataResponse{},
909+
nil,
910+
)
911+
c.client.getFromSendQueue()
912+
913+
buf := make([]byte, 2048)
914+
n1, _ := encodePacket(buf[4:], &responseHeader{
915+
Xid: 1,
916+
Zxid: 73,
917+
Err: errClosing,
918+
})
919+
binary.BigEndian.PutUint32(buf[:4], uint32(n1))
920+
921+
c.conn.readBuf.Write(buf[:4+n1])
922+
923+
output := c.client.readSingleData(c.conn)
924+
assert.Equal(t, connIOOutput{
925+
closed: false,
926+
broken: true,
927+
err: ErrConnectionClosed,
928+
}, output)
929+
930+
// Check Handle Queue
931+
queue := c.client.handleQueue
932+
933+
assert.Equal(t, 1, len(queue))
934+
assert.Equal(t, ErrConnectionClosed, queue[0].err)
935+
})
936+
869937
t.Run("read header len error", func(t *testing.T) {
870938
c := newClientTest(t)
871939

constants.go

+9-6
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import (
55
"fmt"
66
)
77

8-
//revive:disable:exported
9-
108
const (
119
protocolVersion = 0
1210
// DefaultPort is the default port listened by server.
@@ -40,10 +38,13 @@ const (
4038
)
4139

4240
const (
43-
// EventNodeCreated represents a node is created.
44-
EventNodeCreated EventType = 1
45-
EventNodeDeleted EventType = 2
46-
EventNodeDataChanged EventType = 3
41+
// EventNodeCreated represents a znode is created.
42+
EventNodeCreated EventType = 1
43+
// EventNodeDeleted represents a znode is deleted
44+
EventNodeDeleted EventType = 2
45+
// EventNodeDataChanged represents a znode data is changed by Set
46+
EventNodeDataChanged EventType = 3
47+
// EventNodeChildrenChanged when the children of a znode created or deleted
4748
EventNodeChildrenChanged EventType = 4
4849
)
4950

@@ -56,6 +57,8 @@ var (
5657
}
5758
)
5859

60+
//revive:disable:exported
61+
5962
const (
6063
// StateUnknown means the session state is unknown.
6164
StateUnknown State = -1

todolist

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
*) Add Lint
2-
*) Convert errSessionMoved to Connection Error
31
*) Batching Read & Write to TCP (Need to do or not?)
42
*) Stress Tests with Race Detector
53
*) Add Multi-Ops Transactions

0 commit comments

Comments
 (0)