etcd/proxy/grpcproxy/watcher.go

130 lines
3.0 KiB
Go
Raw Normal View History

2016-06-29 07:16:52 +03:00
// Copyright 2016 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package grpcproxy
import (
2016-09-03 17:48:59 +03:00
"time"
"go.etcd.io/etcd/clientv3"
pb "go.etcd.io/etcd/etcdserver/etcdserverpb"
"go.etcd.io/etcd/mvcc"
"go.etcd.io/etcd/mvcc/mvccpb"
2016-06-29 07:16:52 +03:00
)
type watchRange struct {
key, end string
}
2016-11-10 23:24:51 +03:00
func (wr *watchRange) valid() bool {
return len(wr.end) == 0 || wr.end > wr.key || (wr.end[0] == 0 && len(wr.end) == 1)
}
2016-06-29 07:16:52 +03:00
type watcher struct {
// user configuration
2016-07-17 07:14:30 +03:00
wr watchRange
2016-07-17 07:14:30 +03:00
filters []mvcc.FilterFunc
2016-06-29 07:16:52 +03:00
progress bool
prevKV bool
// id is the id returned to the client on its watch stream.
id int64
// nextrev is the minimum expected next event revision.
nextrev int64
// lastHeader has the last header sent over the stream.
lastHeader pb.ResponseHeader
// wps is the parent.
wps *watchProxyStream
2016-06-29 07:16:52 +03:00
}
// send filters out repeated events by discarding revisions older
// than the last one sent over the watch channel.
2016-06-29 07:16:52 +03:00
func (w *watcher) send(wr clientv3.WatchResponse) {
if wr.IsProgressNotify() && !w.progress {
return
}
if w.nextrev > wr.Header.Revision && len(wr.Events) > 0 {
return
}
if w.nextrev == 0 {
// current watch; expect updates following this revision
w.nextrev = wr.Header.Revision + 1
}
2016-06-29 07:16:52 +03:00
2016-07-17 07:14:30 +03:00
events := make([]*mvccpb.Event, 0, len(wr.Events))
var lastRev int64
2016-07-17 07:14:30 +03:00
for i := range wr.Events {
ev := (*mvccpb.Event)(wr.Events[i])
if ev.Kv.ModRevision < w.nextrev {
continue
} else {
// We cannot update w.rev here.
// txn can have multiple events with the same rev.
// If w.nextrev updates here, it would skip events in the same txn.
lastRev = ev.Kv.ModRevision
}
2016-07-17 07:14:30 +03:00
filtered := false
for _, filter := range w.filters {
if filter(*ev) {
filtered = true
break
2016-07-17 07:14:30 +03:00
}
}
if filtered {
continue
}
2016-07-17 07:14:30 +03:00
if !w.prevKV {
evCopy := *ev
evCopy.PrevKv = nil
ev = &evCopy
2016-07-17 07:14:30 +03:00
}
events = append(events, ev)
2016-06-29 07:16:52 +03:00
}
2016-07-17 07:14:30 +03:00
if lastRev >= w.nextrev {
w.nextrev = lastRev + 1
}
2016-07-17 07:14:30 +03:00
// all events are filtered out?
if !wr.IsProgressNotify() && !wr.Created && len(events) == 0 && wr.CompactRevision == 0 {
2016-07-17 07:14:30 +03:00
return
}
w.lastHeader = wr.Header
w.post(&pb.WatchResponse{
Header: &wr.Header,
Created: wr.Created,
CompactRevision: wr.CompactRevision,
Canceled: wr.Canceled,
WatchId: w.id,
Events: events,
})
}
// post puts a watch response on the watcher's proxy stream channel
func (w *watcher) post(wr *pb.WatchResponse) bool {
2016-06-29 07:16:52 +03:00
select {
case w.wps.watchCh <- wr:
2016-09-03 17:48:59 +03:00
case <-time.After(50 * time.Millisecond):
w.wps.cancel()
return false
2016-06-29 07:16:52 +03:00
}
return true
2016-06-29 07:16:52 +03:00
}