clientv3: add send created notification

This commit is contained in:
Xiang Li 2016-08-02 14:56:58 -07:00
parent a60387bab2
commit 33c3583b50
3 changed files with 59 additions and 8 deletions

View File

@ -709,3 +709,21 @@ func TestWatchWithFilter(t *testing.T) {
case <-time.After(100 * time.Millisecond): case <-time.After(100 * time.Millisecond):
} }
} }
// TestWatchWithCreatedNotification checks that createdNotification works.
func TestWatchWithCreatedNotification(t *testing.T) {
cluster := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
defer cluster.Terminate(t)
client := cluster.RandClient()
ctx := context.Background()
createC := client.Watch(ctx, "a", clientv3.WithCreatedNotify())
resp := <-createC
if !resp.Created {
t.Fatalf("expected created event, got %v", resp)
}
}

View File

@ -50,6 +50,8 @@ type Op struct {
// progressNotify is for progress updates. // progressNotify is for progress updates.
progressNotify bool progressNotify bool
// createdNotify is for created event
createdNotify bool
// filters for watchers // filters for watchers
filterPut bool filterPut bool
filterDelete bool filterDelete bool
@ -116,6 +118,8 @@ func OpDelete(key string, opts ...OpOption) Op {
panic("unexpected countOnly in delete") panic("unexpected countOnly in delete")
case ret.filterDelete, ret.filterPut: case ret.filterDelete, ret.filterPut:
panic("unexpected filter in delete") panic("unexpected filter in delete")
case ret.createdNotify:
panic("unexpected createdNotify in delete")
} }
return ret return ret
} }
@ -138,6 +142,8 @@ func OpPut(key, val string, opts ...OpOption) Op {
panic("unexpected countOnly in put") panic("unexpected countOnly in put")
case ret.filterDelete, ret.filterPut: case ret.filterDelete, ret.filterPut:
panic("unexpected filter in put") panic("unexpected filter in put")
case ret.createdNotify:
panic("unexpected createdNotify in put")
} }
return ret return ret
} }
@ -281,6 +287,13 @@ func WithProgressNotify() OpOption {
} }
} }
// WithCreatedNotify makes watch server sends the created event.
func WithCreatedNotify() OpOption {
return func(op *Op) {
op.createdNotify = true
}
}
// WithFilterPut discards PUT events from the watcher. // WithFilterPut discards PUT events from the watcher.
func WithFilterPut() OpOption { func WithFilterPut() OpOption {
return func(op *Op) { op.filterPut = true } return func(op *Op) { op.filterPut = true }

View File

@ -61,6 +61,9 @@ type WatchResponse struct {
// the channel sends a final response that has Canceled set to true with a non-nil Err(). // the channel sends a final response that has Canceled set to true with a non-nil Err().
Canceled bool Canceled bool
// Created is used to indicate the creation of the watcher.
Created bool
closeErr error closeErr error
} }
@ -98,6 +101,7 @@ type watcher struct {
// mu protects the grpc streams map // mu protects the grpc streams map
mu sync.RWMutex mu sync.RWMutex
// streams holds all the active grpc streams keyed by ctx value. // streams holds all the active grpc streams keyed by ctx value.
streams map[string]*watchGrpcStream streams map[string]*watchGrpcStream
} }
@ -138,6 +142,8 @@ type watchRequest struct {
key string key string
end string end string
rev int64 rev int64
// send created notification event if this field is true
createdNotify bool
// progressNotify is for progress updates // progressNotify is for progress updates
progressNotify bool progressNotify bool
// filters is the list of events to filter out // filters is the list of events to filter out
@ -223,6 +229,7 @@ func (w *watcher) Watch(ctx context.Context, key string, opts ...OpOption) Watch
wr := &watchRequest{ wr := &watchRequest{
ctx: ctx, ctx: ctx,
createdNotify: ow.createdNotify,
key: string(ow.key), key: string(ow.key),
end: string(ow.end), end: string(ow.end),
rev: ow.rev, rev: ow.rev,
@ -418,6 +425,7 @@ func (w *watchGrpcStream) run() {
w.addStream(pbresp, pendingReq) w.addStream(pbresp, pendingReq)
pendingReq = nil pendingReq = nil
curReqC = w.reqc curReqC = w.reqc
w.dispatchEvent(pbresp)
case pbresp.Canceled: case pbresp.Canceled:
delete(cancelSet, pbresp.WatchId) delete(cancelSet, pbresp.WatchId)
// shutdown serveStream, if any // shutdown serveStream, if any
@ -489,19 +497,23 @@ func (w *watchGrpcStream) dispatchEvent(pbresp *pb.WatchResponse) bool {
w.mu.RLock() w.mu.RLock()
defer w.mu.RUnlock() defer w.mu.RUnlock()
ws, ok := w.streams[pbresp.WatchId] ws, ok := w.streams[pbresp.WatchId]
if !ok {
return false
}
events := make([]*Event, len(pbresp.Events)) events := make([]*Event, len(pbresp.Events))
for i, ev := range pbresp.Events { for i, ev := range pbresp.Events {
events[i] = (*Event)(ev) events[i] = (*Event)(ev)
} }
if ok { wr := &WatchResponse{
wr := &WatchResponse{ Header: *pbresp.Header,
Header: *pbresp.Header, Events: events,
Events: events, CompactRevision: pbresp.CompactRevision,
CompactRevision: pbresp.CompactRevision, Created: pbresp.Created,
Canceled: pbresp.Canceled} Canceled: pbresp.Canceled,
ws.recvc <- wr
} }
return ok ws.recvc <- wr
return true
} }
// serveWatchClient forwards messages from the grpc stream to run() // serveWatchClient forwards messages from the grpc stream to run()
@ -533,6 +545,14 @@ func (w *watchGrpcStream) serveStream(ws *watcherStream) {
for !closing { for !closing {
curWr := emptyWr curWr := emptyWr
outc := ws.outc outc := ws.outc
// ignore created event if create notify is not requested or
// we already sent the initial created event (when we are on the resume path).
if len(wrs) > 0 && wrs[0].Created &&
(!ws.initReq.createdNotify || ws.lastRev != 0) {
wrs = wrs[1:]
}
if len(wrs) > 0 { if len(wrs) > 0 {
curWr = wrs[0] curWr = wrs[0]
} else { } else {