mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
clientv3: add Err() to WatchResponse
Checking for number of events as a failure condition was a kludge.
This commit is contained in:
parent
dc7f9a89b0
commit
1e16758029
@ -139,7 +139,7 @@ func (e *Election) observe(ctx context.Context, ch chan<- v3.GetResponse) {
|
|||||||
|
|
||||||
for kv == nil {
|
for kv == nil {
|
||||||
wr, ok := <-wch
|
wr, ok := <-wch
|
||||||
if !ok || len(wr.Events) == 0 {
|
if !ok || wr.Err() != nil {
|
||||||
cancel()
|
cancel()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
|
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
||||||
v3 "github.com/coreos/etcd/clientv3"
|
v3 "github.com/coreos/etcd/clientv3"
|
||||||
"github.com/coreos/etcd/etcdserver/api/v3rpc"
|
|
||||||
"github.com/coreos/etcd/storage/storagepb"
|
"github.com/coreos/etcd/storage/storagepb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -52,10 +51,7 @@ func waitUpdate(ctx context.Context, client *v3.Client, key string, opts ...v3.O
|
|||||||
if !ok {
|
if !ok {
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
}
|
}
|
||||||
if len(wresp.Events) == 0 {
|
return wresp.Err()
|
||||||
return v3rpc.ErrCompacted
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitDelete(ctx context.Context, client *v3.Client, key string, rev int64) error {
|
func waitDelete(ctx context.Context, client *v3.Client, key string, rev int64) error {
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
|
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
||||||
"github.com/coreos/etcd/clientv3"
|
"github.com/coreos/etcd/clientv3"
|
||||||
|
"github.com/coreos/etcd/etcdserver/api/v3rpc"
|
||||||
"github.com/coreos/etcd/integration"
|
"github.com/coreos/etcd/integration"
|
||||||
"github.com/coreos/etcd/pkg/testutil"
|
"github.com/coreos/etcd/pkg/testutil"
|
||||||
storagepb "github.com/coreos/etcd/storage/storagepb"
|
storagepb "github.com/coreos/etcd/storage/storagepb"
|
||||||
@ -347,8 +348,8 @@ func TestWatchInvalidFutureRevision(t *testing.T) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("expected wresp 'open'(ok true), but got ok %v", ok)
|
t.Fatalf("expected wresp 'open'(ok true), but got ok %v", ok)
|
||||||
}
|
}
|
||||||
if !wresp.Canceled {
|
if wresp.Err() != v3rpc.ErrFutureRev {
|
||||||
t.Fatalf("wresp.Canceled expected 'true', but got %v", wresp.Canceled)
|
t.Fatalf("wresp.Err() expected ErrFutureRev, but got %v", wresp.Err())
|
||||||
}
|
}
|
||||||
|
|
||||||
_, ok = <-rch // ensure the channel is closed
|
_, ok = <-rch // ensure the channel is closed
|
||||||
@ -356,3 +357,42 @@ func TestWatchInvalidFutureRevision(t *testing.T) {
|
|||||||
t.Fatalf("expected wresp 'closed'(ok false), but got ok %v", ok)
|
t.Fatalf("expected wresp 'closed'(ok false), but got ok %v", ok)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestWatchCompactRevision ensures the CompactRevision error is given on a
|
||||||
|
// compaction event ahead of a watcher.
|
||||||
|
func TestWatchCompactRevision(t *testing.T) {
|
||||||
|
defer testutil.AfterTest(t)
|
||||||
|
|
||||||
|
clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
|
||||||
|
defer clus.Terminate(t)
|
||||||
|
|
||||||
|
// set some keys
|
||||||
|
kv := clientv3.NewKV(clus.RandClient())
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
if _, err := kv.Put(context.TODO(), "foo", "bar"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w := clientv3.NewWatcher(clus.RandClient())
|
||||||
|
defer w.Close()
|
||||||
|
|
||||||
|
if err := kv.Compact(context.TODO(), 4); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
wch := w.Watch(context.Background(), "foo", clientv3.WithRev(2))
|
||||||
|
|
||||||
|
// get compacted error message
|
||||||
|
wresp, ok := <-wch
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("expected wresp, but got closed channel")
|
||||||
|
}
|
||||||
|
if wresp.Err() != v3rpc.ErrCompacted {
|
||||||
|
t.Fatalf("wresp.Err() expected ErrCompacteed, but got %v", wresp.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure the channel is closed
|
||||||
|
if wresp, ok = <-wch; ok {
|
||||||
|
t.Fatalf("expected closed channel, but got %v", wresp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
|
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
||||||
"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
|
"github.com/coreos/etcd/Godeps/_workspace/src/google.golang.org/grpc"
|
||||||
|
"github.com/coreos/etcd/etcdserver/api/v3rpc"
|
||||||
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
||||||
storagepb "github.com/coreos/etcd/storage/storagepb"
|
storagepb "github.com/coreos/etcd/storage/storagepb"
|
||||||
)
|
)
|
||||||
@ -41,14 +42,25 @@ type Watcher interface {
|
|||||||
type WatchResponse struct {
|
type WatchResponse struct {
|
||||||
Header pb.ResponseHeader
|
Header pb.ResponseHeader
|
||||||
Events []*storagepb.Event
|
Events []*storagepb.Event
|
||||||
// CompactRevision is set to the compaction revision that
|
|
||||||
// caused the watcher to cancel.
|
// CompactRevision is the minimum revision the watcher may receive.
|
||||||
CompactRevision int64
|
CompactRevision int64
|
||||||
|
|
||||||
// Canceled is 'true' when it has received wrong watch start revision.
|
// Canceled is set to indicate the channel is about to close.
|
||||||
Canceled bool
|
Canceled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Err is the error value if this WatchResponse holds an error.
|
||||||
|
func (wr *WatchResponse) Err() error {
|
||||||
|
if wr.CompactRevision != 0 {
|
||||||
|
return v3rpc.ErrCompacted
|
||||||
|
}
|
||||||
|
if wr.Canceled {
|
||||||
|
return v3rpc.ErrFutureRev
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// watcher implements the Watcher interface
|
// watcher implements the Watcher interface
|
||||||
type watcher struct {
|
type watcher struct {
|
||||||
c *Client
|
c *Client
|
||||||
@ -179,12 +191,13 @@ func (w *watcher) addStream(resp *pb.WatchResponse, pendingReq *watchRequest) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if resp.Canceled || resp.CompactRevision != 0 {
|
if resp.Canceled || resp.CompactRevision != 0 {
|
||||||
// compaction after start revision
|
// a cancel at id creation time means the start revision has
|
||||||
|
// been compacted out of the store
|
||||||
ret := make(chan WatchResponse, 1)
|
ret := make(chan WatchResponse, 1)
|
||||||
ret <- WatchResponse{
|
ret <- WatchResponse{
|
||||||
Header: *resp.Header,
|
Header: *resp.Header,
|
||||||
CompactRevision: resp.CompactRevision,
|
CompactRevision: resp.CompactRevision,
|
||||||
Canceled: resp.Canceled}
|
Canceled: true}
|
||||||
close(ret)
|
close(ret)
|
||||||
pendingReq.retc <- ret
|
pendingReq.retc <- ret
|
||||||
return
|
return
|
||||||
@ -375,8 +388,7 @@ func (w *watcher) serveStream(ws *watcherStream) {
|
|||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case outc <- *curWr:
|
case outc <- *curWr:
|
||||||
if len(wrs[0].Events) == 0 {
|
if wrs[0].Err() != nil {
|
||||||
// compaction message
|
|
||||||
closing = true
|
closing = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ func snapshotCommandFunc(cmd *cobra.Command, args []string) {
|
|||||||
func snapshotToStdout(c *clientv3.Client) {
|
func snapshotToStdout(c *clientv3.Client) {
|
||||||
// must explicitly fetch first revision since no retry on stdout
|
// must explicitly fetch first revision since no retry on stdout
|
||||||
wr := <-c.Watch(context.TODO(), "", clientv3.WithPrefix(), clientv3.WithRev(1))
|
wr := <-c.Watch(context.TODO(), "", clientv3.WithPrefix(), clientv3.WithRev(1))
|
||||||
if len(wr.Events) > 0 {
|
if wr.Err() == nil {
|
||||||
wr.CompactRevision = 1
|
wr.CompactRevision = 1
|
||||||
}
|
}
|
||||||
if rev := snapshot(os.Stdout, c, wr.CompactRevision+1); rev != 0 {
|
if rev := snapshot(os.Stdout, c, wr.CompactRevision+1); rev != 0 {
|
||||||
@ -111,7 +111,7 @@ func snapshot(w io.Writer, c *clientv3.Client, rev int64) int64 {
|
|||||||
wc := s.SyncUpdates(context.TODO())
|
wc := s.SyncUpdates(context.TODO())
|
||||||
|
|
||||||
for wr := range wc {
|
for wr := range wc {
|
||||||
if len(wr.Events) == 0 {
|
if wr.Err() != nil {
|
||||||
return wr.CompactRevision
|
return wr.CompactRevision
|
||||||
}
|
}
|
||||||
for _, ev := range wr.Events {
|
for _, ev := range wr.Events {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user