go.etcd.io/etcd@v3.3.27+incompatible/mvcc/watcher.go (about) 1 // Copyright 2015 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package mvcc 16 17 import ( 18 "bytes" 19 "errors" 20 "sync" 21 22 "github.com/coreos/etcd/mvcc/mvccpb" 23 ) 24 25 var ( 26 ErrWatcherNotExist = errors.New("mvcc: watcher does not exist") 27 ) 28 29 type WatchID int64 30 31 // FilterFunc returns true if the given event should be filtered out. 32 type FilterFunc func(e mvccpb.Event) bool 33 34 type WatchStream interface { 35 // Watch creates a watcher. The watcher watches the events happening or 36 // happened on the given key or range [key, end) from the given startRev. 37 // 38 // The whole event history can be watched unless compacted. 39 // If `startRev` <=0, watch observes events after currentRev. 40 // 41 // The returned `id` is the ID of this watcher. It appears as WatchID 42 // in events that are sent to the created watcher through stream channel. 43 // 44 Watch(key, end []byte, startRev int64, fcs ...FilterFunc) WatchID 45 46 // Chan returns a chan. All watch response will be sent to the returned chan. 47 Chan() <-chan WatchResponse 48 49 // RequestProgress requests the progress of the watcher with given ID. The response 50 // will only be sent if the watcher is currently synced. 51 // The responses will be sent through the WatchRespone Chan attached 52 // with this stream to ensure correct ordering. 53 // The responses contains no events. The revision in the response is the progress 54 // of the watchers since the watcher is currently synced. 55 RequestProgress(id WatchID) 56 57 // Cancel cancels a watcher by giving its ID. If watcher does not exist, an error will be 58 // returned. 59 Cancel(id WatchID) error 60 61 // Close closes Chan and release all related resources. 62 Close() 63 64 // Rev returns the current revision of the KV the stream watches on. 65 Rev() int64 66 } 67 68 type WatchResponse struct { 69 // WatchID is the WatchID of the watcher this response sent to. 70 WatchID WatchID 71 72 // Events contains all the events that needs to send. 73 Events []mvccpb.Event 74 75 // Revision is the revision of the KV when the watchResponse is created. 76 // For a normal response, the revision should be the same as the last 77 // modified revision inside Events. For a delayed response to a unsynced 78 // watcher, the revision is greater than the last modified revision 79 // inside Events. 80 Revision int64 81 82 // CompactRevision is set when the watcher is cancelled due to compaction. 83 CompactRevision int64 84 } 85 86 // watchStream contains a collection of watchers that share 87 // one streaming chan to send out watched events and other control events. 88 type watchStream struct { 89 watchable watchable 90 ch chan WatchResponse 91 92 mu sync.Mutex // guards fields below it 93 // nextID is the ID pre-allocated for next new watcher in this stream 94 nextID WatchID 95 closed bool 96 cancels map[WatchID]cancelFunc 97 watchers map[WatchID]*watcher 98 } 99 100 // Watch creates a new watcher in the stream and returns its WatchID. 101 // TODO: return error if ws is closed? 102 func (ws *watchStream) Watch(key, end []byte, startRev int64, fcs ...FilterFunc) WatchID { 103 // prevent wrong range where key >= end lexicographically 104 // watch request with 'WithFromKey' has empty-byte range end 105 if len(end) != 0 && bytes.Compare(key, end) != -1 { 106 return -1 107 } 108 109 ws.mu.Lock() 110 defer ws.mu.Unlock() 111 if ws.closed { 112 return -1 113 } 114 115 id := ws.nextID 116 ws.nextID++ 117 118 w, c := ws.watchable.watch(key, end, startRev, id, ws.ch, fcs...) 119 120 ws.cancels[id] = c 121 ws.watchers[id] = w 122 return id 123 } 124 125 func (ws *watchStream) Chan() <-chan WatchResponse { 126 return ws.ch 127 } 128 129 func (ws *watchStream) Cancel(id WatchID) error { 130 ws.mu.Lock() 131 cancel, ok := ws.cancels[id] 132 w := ws.watchers[id] 133 ok = ok && !ws.closed 134 ws.mu.Unlock() 135 136 if !ok { 137 return ErrWatcherNotExist 138 } 139 cancel() 140 141 ws.mu.Lock() 142 // The watch isn't removed until cancel so that if Close() is called, 143 // it will wait for the cancel. Otherwise, Close() could close the 144 // watch channel while the store is still posting events. 145 if ww := ws.watchers[id]; ww == w { 146 delete(ws.cancels, id) 147 delete(ws.watchers, id) 148 } 149 ws.mu.Unlock() 150 151 return nil 152 } 153 154 func (ws *watchStream) Close() { 155 ws.mu.Lock() 156 defer ws.mu.Unlock() 157 158 for _, cancel := range ws.cancels { 159 cancel() 160 } 161 ws.closed = true 162 close(ws.ch) 163 watchStreamGauge.Dec() 164 } 165 166 func (ws *watchStream) Rev() int64 { 167 ws.mu.Lock() 168 defer ws.mu.Unlock() 169 return ws.watchable.rev() 170 } 171 172 func (ws *watchStream) RequestProgress(id WatchID) { 173 ws.mu.Lock() 174 w, ok := ws.watchers[id] 175 ws.mu.Unlock() 176 if !ok { 177 return 178 } 179 ws.watchable.progress(w) 180 }