2019-08-22 05:12:46 +00:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"sync"
|
|
|
|
"sync/atomic"
|
|
|
|
|
|
|
|
"github.com/sirupsen/logrus"
|
2019-12-12 01:27:03 +00:00
|
|
|
"go.etcd.io/etcd/etcdserver/etcdserverpb"
|
|
|
|
"go.etcd.io/etcd/mvcc/mvccpb"
|
2019-08-22 05:12:46 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
watchID int64
|
|
|
|
)
|
|
|
|
|
|
|
|
func (s *KVServerBridge) Watch(ws etcdserverpb.Watch_WatchServer) error {
|
|
|
|
w := watcher{
|
|
|
|
server: ws,
|
|
|
|
backend: s.limited.backend,
|
|
|
|
watches: map[int64]func(){},
|
|
|
|
}
|
|
|
|
defer w.Close()
|
|
|
|
|
|
|
|
for {
|
|
|
|
msg, err := ws.Recv()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if msg.GetCreateRequest() != nil {
|
2020-01-20 22:43:58 +00:00
|
|
|
w.Start(ws.Context(), msg.GetCreateRequest())
|
2019-08-22 05:12:46 +00:00
|
|
|
} else if msg.GetCancelRequest() != nil {
|
2020-10-15 17:34:24 +00:00
|
|
|
logrus.Tracef("WATCH CANCEL REQ id=%d", msg.GetCancelRequest().GetWatchId())
|
2020-01-20 22:43:58 +00:00
|
|
|
w.Cancel(msg.GetCancelRequest().WatchId, nil)
|
2019-08-22 05:12:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type watcher struct {
|
|
|
|
sync.Mutex
|
|
|
|
|
|
|
|
wg sync.WaitGroup
|
|
|
|
backend Backend
|
|
|
|
server etcdserverpb.Watch_WatchServer
|
|
|
|
watches map[int64]func()
|
|
|
|
}
|
|
|
|
|
2020-01-20 22:43:58 +00:00
|
|
|
func (w *watcher) Start(ctx context.Context, r *etcdserverpb.WatchCreateRequest) {
|
2019-08-22 05:12:46 +00:00
|
|
|
w.Lock()
|
|
|
|
defer w.Unlock()
|
|
|
|
|
2020-01-20 22:43:58 +00:00
|
|
|
ctx, cancel := context.WithCancel(ctx)
|
2019-08-22 05:12:46 +00:00
|
|
|
|
|
|
|
id := atomic.AddInt64(&watchID, 1)
|
|
|
|
w.watches[id] = cancel
|
|
|
|
w.wg.Add(1)
|
|
|
|
|
|
|
|
key := string(r.Key)
|
|
|
|
|
2020-10-15 17:34:24 +00:00
|
|
|
logrus.Tracef("WATCH START id=%d, count=%d, key=%s, revision=%d", id, len(w.watches), key, r.StartRevision)
|
2019-08-22 05:12:46 +00:00
|
|
|
|
|
|
|
go func() {
|
|
|
|
defer w.wg.Done()
|
|
|
|
if err := w.server.Send(&etcdserverpb.WatchResponse{
|
|
|
|
Header: &etcdserverpb.ResponseHeader{},
|
|
|
|
Created: true,
|
|
|
|
WatchId: id,
|
|
|
|
}); err != nil {
|
2020-01-20 22:43:58 +00:00
|
|
|
w.Cancel(id, err)
|
2019-08-22 05:12:46 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for events := range w.backend.Watch(ctx, key, r.StartRevision) {
|
|
|
|
if len(events) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if logrus.IsLevelEnabled(logrus.DebugLevel) {
|
|
|
|
for _, event := range events {
|
2020-10-15 17:34:24 +00:00
|
|
|
logrus.Tracef("WATCH READ id=%d, key=%s, revision=%d", id, event.KV.Key, event.KV.ModRevision)
|
2019-08-22 05:12:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := w.server.Send(&etcdserverpb.WatchResponse{
|
|
|
|
Header: txnHeader(events[len(events)-1].KV.ModRevision),
|
|
|
|
WatchId: id,
|
|
|
|
Events: toEvents(events...),
|
|
|
|
}); err != nil {
|
2020-01-20 22:43:58 +00:00
|
|
|
w.Cancel(id, err)
|
2019-11-02 00:05:00 +00:00
|
|
|
continue
|
2019-08-22 05:12:46 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-20 22:43:58 +00:00
|
|
|
w.Cancel(id, nil)
|
2020-10-15 17:34:24 +00:00
|
|
|
logrus.Tracef("WATCH CLOSE id=%d, key=%s", id, key)
|
2019-08-22 05:12:46 +00:00
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
func toEvents(events ...*Event) []*mvccpb.Event {
|
|
|
|
ret := make([]*mvccpb.Event, 0, len(events))
|
|
|
|
for _, e := range events {
|
|
|
|
ret = append(ret, toEvent(e))
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
func toEvent(event *Event) *mvccpb.Event {
|
|
|
|
e := &mvccpb.Event{
|
|
|
|
Kv: toKV(event.KV),
|
|
|
|
PrevKv: toKV(event.PrevKV),
|
|
|
|
}
|
|
|
|
if event.Delete {
|
|
|
|
e.Type = mvccpb.DELETE
|
|
|
|
} else {
|
|
|
|
e.Type = mvccpb.PUT
|
|
|
|
}
|
|
|
|
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
2020-01-20 22:43:58 +00:00
|
|
|
func (w *watcher) Cancel(watchID int64, err error) {
|
2019-08-22 05:12:46 +00:00
|
|
|
w.Lock()
|
|
|
|
if cancel, ok := w.watches[watchID]; ok {
|
|
|
|
cancel()
|
|
|
|
delete(w.watches, watchID)
|
|
|
|
}
|
2020-01-20 22:43:58 +00:00
|
|
|
w.Unlock()
|
|
|
|
|
|
|
|
reason := ""
|
|
|
|
if err != nil {
|
|
|
|
reason = err.Error()
|
|
|
|
}
|
2020-10-15 17:34:24 +00:00
|
|
|
logrus.Tracef("WATCH CANCEL id=%d reason=%s", watchID, reason)
|
2020-01-21 23:57:50 +00:00
|
|
|
serr := w.server.Send(&etcdserverpb.WatchResponse{
|
2020-01-20 22:43:58 +00:00
|
|
|
Header: &etcdserverpb.ResponseHeader{},
|
|
|
|
Canceled: true,
|
|
|
|
CancelReason: "watch closed",
|
|
|
|
WatchId: watchID,
|
2019-08-22 05:12:46 +00:00
|
|
|
})
|
2020-01-21 23:57:50 +00:00
|
|
|
if serr != nil && err != nil {
|
|
|
|
logrus.Errorf("WATCH Failed to send cancel response for watchID %d: %v", watchID, serr)
|
2019-08-22 05:12:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *watcher) Close() {
|
|
|
|
w.Lock()
|
|
|
|
for _, v := range w.watches {
|
|
|
|
v()
|
|
|
|
}
|
2020-01-20 22:43:58 +00:00
|
|
|
w.Unlock()
|
2019-08-22 05:12:46 +00:00
|
|
|
w.wg.Wait()
|
|
|
|
}
|