go.etcd.io/etcd@v3.3.27+incompatible/etcdserver/api/v2v3/watcher.go (about) 1 // Copyright 2017 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 v2v3 16 17 import ( 18 "context" 19 "strings" 20 21 "github.com/coreos/etcd/clientv3" 22 etcdErr "github.com/coreos/etcd/error" 23 "github.com/coreos/etcd/store" 24 ) 25 26 func (s *v2v3Store) Watch(prefix string, recursive, stream bool, sinceIndex uint64) (store.Watcher, error) { 27 ctx, cancel := context.WithCancel(s.ctx) 28 wch := s.c.Watch( 29 ctx, 30 // TODO: very pricey; use a single store-wide watch in future 31 s.pfx, 32 clientv3.WithPrefix(), 33 clientv3.WithRev(int64(sinceIndex)), 34 clientv3.WithCreatedNotify(), 35 clientv3.WithPrevKV()) 36 resp, ok := <-wch 37 if err := resp.Err(); err != nil || !ok { 38 cancel() 39 return nil, etcdErr.NewError(etcdErr.EcodeRaftInternal, prefix, 0) 40 } 41 42 evc, donec := make(chan *store.Event), make(chan struct{}) 43 go func() { 44 defer func() { 45 close(evc) 46 close(donec) 47 }() 48 for resp := range wch { 49 for _, ev := range s.mkV2Events(resp) { 50 k := ev.Node.Key 51 if recursive { 52 if !strings.HasPrefix(k, prefix) { 53 continue 54 } 55 // accept events on hidden keys given in prefix 56 k = strings.Replace(k, prefix, "/", 1) 57 // ignore hidden keys deeper than prefix 58 if strings.Contains(k, "/_") { 59 continue 60 } 61 } 62 if !recursive && k != prefix { 63 continue 64 } 65 select { 66 case evc <- ev: 67 case <-ctx.Done(): 68 return 69 } 70 if !stream { 71 return 72 } 73 } 74 } 75 }() 76 77 return &v2v3Watcher{ 78 startRev: resp.Header.Revision, 79 evc: evc, 80 donec: donec, 81 cancel: cancel, 82 }, nil 83 } 84 85 func (s *v2v3Store) mkV2Events(wr clientv3.WatchResponse) (evs []*store.Event) { 86 ak := s.mkActionKey() 87 for _, rev := range mkRevs(wr) { 88 var act, key *clientv3.Event 89 for _, ev := range rev { 90 if string(ev.Kv.Key) == ak { 91 act = ev 92 } else if key != nil && len(key.Kv.Key) < len(ev.Kv.Key) { 93 // use longest key to ignore intermediate new 94 // directories from Create. 95 key = ev 96 } else if key == nil { 97 key = ev 98 } 99 } 100 v2ev := &store.Event{ 101 Action: string(act.Kv.Value), 102 Node: s.mkV2Node(key.Kv), 103 PrevNode: s.mkV2Node(key.PrevKv), 104 EtcdIndex: mkV2Rev(wr.Header.Revision), 105 } 106 evs = append(evs, v2ev) 107 } 108 return evs 109 } 110 111 func mkRevs(wr clientv3.WatchResponse) (revs [][]*clientv3.Event) { 112 var curRev []*clientv3.Event 113 for _, ev := range wr.Events { 114 if curRev != nil && ev.Kv.ModRevision != curRev[0].Kv.ModRevision { 115 revs = append(revs, curRev) 116 curRev = nil 117 } 118 curRev = append(curRev, ev) 119 } 120 if curRev != nil { 121 revs = append(revs, curRev) 122 } 123 return revs 124 } 125 126 type v2v3Watcher struct { 127 startRev int64 128 evc chan *store.Event 129 donec chan struct{} 130 cancel context.CancelFunc 131 } 132 133 func (w *v2v3Watcher) StartIndex() uint64 { return mkV2Rev(w.startRev) } 134 135 func (w *v2v3Watcher) Remove() { 136 w.cancel() 137 <-w.donec 138 } 139 140 func (w *v2v3Watcher) EventChan() chan *store.Event { return w.evc }