Skip to content

Commit 014329c

Browse files
committed
dragonboat: fixed #260
1 parent 2da3403 commit 014329c

File tree

4 files changed

+77
-20
lines changed

4 files changed

+77
-20
lines changed

nodehost.go

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -478,14 +478,14 @@ func (nh *NodeHost) Stop() {
478478
// cluster.
479479
//
480480
// As a summary, when -
481-
// - starting a brand new Raft cluster, set join to false and specify all initial
482-
// member node details in the initialMembers map.
483-
// - joining a new node to an existing Raft cluster, set join to true and leave
484-
// the initialMembers map empty. This requires the joining node to have already
485-
// been added as a member node of the Raft cluster.
486-
// - restarting an crashed or stopped node, set join to false and leave the
487-
// initialMembers map to be empty. This applies to both initial member nodes
488-
// and those joined later.
481+
// - starting a brand new Raft cluster, set join to false and specify all initial
482+
// member node details in the initialMembers map.
483+
// - joining a new node to an existing Raft cluster, set join to true and leave
484+
// the initialMembers map empty. This requires the joining node to have already
485+
// been added as a member node of the Raft cluster.
486+
// - restarting an crashed or stopped node, set join to false and leave the
487+
// initialMembers map to be empty. This applies to both initial member nodes
488+
// and those joined later.
489489
func (nh *NodeHost) StartCluster(initialMembers map[uint64]Target,
490490
join bool, create sm.CreateStateMachineFunc, cfg config.Config) error {
491491
cf := func(clusterID uint64, nodeID uint64,
@@ -1520,17 +1520,17 @@ func (nh *NodeHost) getClusterSetIndex() uint64 {
15201520

15211521
// there are three major reasons to bootstrap the cluster
15221522
//
1523-
// 1. when possible, we check whether user incorrectly specified parameters
1524-
// for the startCluster method, e.g. call startCluster with join=true first,
1525-
// then restart the NodeHost instance and call startCluster again with
1526-
// join=false and len(nodes) > 0
1527-
// 2. when restarting a node which is a part of the initial cluster members,
1528-
// for user convenience, we allow the caller not to provide the details of
1529-
// initial members. when the initial cluster member info is required, however
1530-
// we still need to get the initial member info from somewhere. bootstrap is
1531-
// the procedure that records such info.
1532-
// 3. the bootstrap record is used as a marker record in our default LogDB
1533-
// implementation to indicate that a certain node exists here
1523+
// 1. when possible, we check whether user incorrectly specified parameters
1524+
// for the startCluster method, e.g. call startCluster with join=true first,
1525+
// then restart the NodeHost instance and call startCluster again with
1526+
// join=false and len(nodes) > 0
1527+
// 2. when restarting a node which is a part of the initial cluster members,
1528+
// for user convenience, we allow the caller not to provide the details of
1529+
// initial members. when the initial cluster member info is required, however
1530+
// we still need to get the initial member info from somewhere. bootstrap is
1531+
// the procedure that records such info.
1532+
// 3. the bootstrap record is used as a marker record in our default LogDB
1533+
// implementation to indicate that a certain node exists here
15341534
func (nh *NodeHost) bootstrapCluster(initialMembers map[uint64]Target,
15351535
join bool, cfg config.Config,
15361536
smType pb.StateMachineType) (map[uint64]string, bool, error) {
@@ -1999,6 +1999,8 @@ func getRequestState(ctx context.Context, rs *RequestState) (sm.Result, error) {
19991999
return sm.Result{}, ErrClusterClosed
20002000
} else if r.Dropped() {
20012001
return sm.Result{}, ErrClusterNotReady
2002+
} else if r.Aborted() {
2003+
return sm.Result{}, ErrAborted
20022004
}
20032005
plog.Panicf("unknown v code %v", r)
20042006
case <-ctx.Done():

nodehost_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,6 +1537,56 @@ func TestRecoverFromSnapshotCanBeStopped(t *testing.T) {
15371537
runNodeHostTest(t, to, fs)
15381538
}
15391539

1540+
func TestGetRequestState(t *testing.T) {
1541+
tests := []struct {
1542+
code RequestResultCode
1543+
err error
1544+
}{
1545+
{requestCompleted, nil},
1546+
{requestRejected, ErrRejected},
1547+
{requestTimeout, ErrTimeout},
1548+
{requestTerminated, ErrClusterClosed},
1549+
{requestDropped, ErrClusterNotReady},
1550+
{requestAborted, ErrAborted},
1551+
}
1552+
1553+
for _, tt := range tests {
1554+
rs := &RequestState{
1555+
CompletedC: make(chan RequestResult, 1),
1556+
}
1557+
result := RequestResult{code: tt.code}
1558+
rs.notify(result)
1559+
if _, err := getRequestState(context.TODO(), rs); !errors.Is(err, tt.err) {
1560+
t.Errorf("expect error %v, got %v", tt.err, err)
1561+
}
1562+
}
1563+
}
1564+
1565+
func TestGetRequestStateTimeoutAndCancel(t *testing.T) {
1566+
func() {
1567+
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond)
1568+
defer cancel()
1569+
time.Sleep(2 * time.Millisecond)
1570+
rs := &RequestState{
1571+
CompletedC: make(chan RequestResult, 1),
1572+
}
1573+
if _, err := getRequestState(ctx, rs); !errors.Is(err, ErrTimeout) {
1574+
t.Errorf("got %v", err)
1575+
}
1576+
}()
1577+
1578+
func() {
1579+
ctx, cancel := context.WithTimeout(context.Background(), time.Hour)
1580+
cancel()
1581+
rs := &RequestState{
1582+
CompletedC: make(chan RequestResult, 1),
1583+
}
1584+
if _, err := getRequestState(ctx, rs); !errors.Is(err, ErrCanceled) {
1585+
t.Errorf("got %v", err)
1586+
}
1587+
}()
1588+
}
1589+
15401590
func TestNodeHostIDIsStatic(t *testing.T) {
15411591
fs := vfs.GetTestFS()
15421592
id := ""

request.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ var (
7575
ErrCanceled = errors.New("request canceled")
7676
// ErrRejected indicates that the request has been rejected.
7777
ErrRejected = errors.New("request rejected")
78+
// ErrAborted indicates that the request has been aborted, usually by user
79+
// defined behaviours.
80+
ErrAborted = errors.New("request aborted")
7881
// ErrClusterNotReady indicates that the request has been dropped as the
7982
// specified raft cluster is not ready to handle the request. Unknown leader
8083
// is the most common cause of this error, trying to use a cluster not fully
@@ -115,7 +118,8 @@ func IsTempError(err error) bool {
115118
err == ErrClusterNotInitialized ||
116119
err == ErrClusterNotReady ||
117120
err == ErrTimeout ||
118-
err == ErrClosed
121+
err == ErrClosed ||
122+
err == ErrAborted
119123
}
120124

121125
// RequestResultCode is the result code returned to the client to indicate the

request_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ func TestIsTempError(t *testing.T) {
4545
{ErrTimeout, true},
4646
{ErrCanceled, false},
4747
{ErrRejected, false},
48+
{ErrAborted, true},
4849
{ErrClusterNotReady, true},
4950
{ErrInvalidTarget, false},
5051
{ErrInvalidNodeHostID, false},

0 commit comments

Comments
 (0)