diff --git a/etcdserver/server.go b/etcdserver/server.go index 27dac2641..2370736b4 100644 --- a/etcdserver/server.go +++ b/etcdserver/server.go @@ -64,6 +64,8 @@ var ( ErrIDRemoved = errors.New("etcdserver: ID removed") ErrIDExists = errors.New("etcdserver: ID exists") ErrIDNotFound = errors.New("etcdserver: ID not found") + ErrCanceled = errors.New("etcdserver: request cancelled") + ErrTimeout = errors.New("etcdserver: request timed out") storeMembersPrefix = path.Join(StoreAdminPrefix, "members") storeRemovedMembersPrefix = path.Join(StoreAdminPrefix, "removed_members") @@ -383,7 +385,7 @@ func (s *EtcdServer) Do(ctx context.Context, r pb.Request) (Response, error) { return resp, resp.err case <-ctx.Done(): s.w.Trigger(r.ID, nil) // GC wait - return Response{}, ctx.Err() + return Response{}, parseCtxErr(ctx.Err()) case <-s.done: return Response{}, ErrStopped } @@ -477,7 +479,7 @@ func (s *EtcdServer) configure(ctx context.Context, cc raftpb.ConfChange) error return nil case <-ctx.Done(): s.w.Trigger(cc.ID, nil) // GC wait - return ctx.Err() + return parseCtxErr(ctx.Err()) case <-s.done: return ErrStopped } @@ -752,6 +754,17 @@ func GenID() (n uint64) { return } +func parseCtxErr(err error) error { + switch err { + case context.Canceled: + return ErrCanceled + case context.DeadlineExceeded: + return ErrTimeout + default: + return err + } +} + func getBool(v *bool) (vv bool, set bool) { if v == nil { return false, false diff --git a/etcdserver/server_test.go b/etcdserver/server_test.go index 110e6028e..6efa9467e 100644 --- a/etcdserver/server_test.go +++ b/etcdserver/server_test.go @@ -614,8 +614,8 @@ func TestDoProposalCancelled(t *testing.T) { if len(gaction) != 0 { t.Errorf("len(action) = %v, want 0", len(gaction)) } - if err != context.Canceled { - t.Fatalf("err = %v, want %v", err, context.Canceled) + if err != ErrCanceled { + t.Fatalf("err = %v, want %v", err, ErrCanceled) } w := []action{action{name: "Register1"}, action{name: "Trigger1"}} if !reflect.DeepEqual(wait.action, w) { @@ -623,6 +623,18 @@ func TestDoProposalCancelled(t *testing.T) { } } +func TestDoProposalTimeout(t *testing.T) { + ctx, _ := context.WithTimeout(context.Background(), 0) + srv := &EtcdServer{ + node: &nodeRecorder{}, + w: &waitRecorder{}, + } + _, err := srv.Do(ctx, pb.Request{Method: "PUT", ID: 1}) + if err != ErrTimeout { + t.Fatalf("err = %v, want %v", err, ErrTimeout) + } +} + func TestDoProposalStopped(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel()