github.com/alpe/etcd@v0.1.2-0.20130915230056-09f31af88aeb/store/watcher.go (about) 1 package store 2 3 import ( 4 "path" 5 "strconv" 6 "strings" 7 ) 8 9 //------------------------------------------------------------------------------ 10 // 11 // Typedefs 12 // 13 //------------------------------------------------------------------------------ 14 15 // WatcherHub is where the client register its watcher 16 type WatcherHub struct { 17 watchers map[string][]*Watcher 18 } 19 20 // Currently watcher only contains a response channel 21 type Watcher struct { 22 C chan *Response 23 } 24 25 // Create a new watcherHub 26 func newWatcherHub() *WatcherHub { 27 w := new(WatcherHub) 28 w.watchers = make(map[string][]*Watcher) 29 return w 30 } 31 32 // Create a new watcher 33 func NewWatcher() *Watcher { 34 return &Watcher{C: make(chan *Response, 1)} 35 } 36 37 // Add a watcher to the watcherHub 38 func (w *WatcherHub) addWatcher(prefix string, watcher *Watcher, sinceIndex uint64, 39 responseStartIndex uint64, currentIndex uint64, resMap map[string]*Response) error { 40 41 prefix = path.Clean("/" + prefix) 42 43 if sinceIndex != 0 && sinceIndex >= responseStartIndex { 44 for i := sinceIndex; i <= currentIndex; i++ { 45 if checkResponse(prefix, i, resMap) { 46 watcher.C <- resMap[strconv.FormatUint(i, 10)] 47 return nil 48 } 49 } 50 } 51 52 _, ok := w.watchers[prefix] 53 54 if !ok { 55 w.watchers[prefix] = make([]*Watcher, 0) 56 } 57 58 w.watchers[prefix] = append(w.watchers[prefix], watcher) 59 60 return nil 61 } 62 63 // Check if the response has what we are watching 64 func checkResponse(prefix string, index uint64, resMap map[string]*Response) bool { 65 66 resp, ok := resMap[strconv.FormatUint(index, 10)] 67 68 if !ok { 69 // not storage system command 70 return false 71 } else { 72 path := resp.Key 73 if strings.HasPrefix(path, prefix) { 74 prefixLen := len(prefix) 75 if len(path) == prefixLen || path[prefixLen] == '/' { 76 return true 77 } 78 79 } 80 } 81 82 return false 83 } 84 85 // Notify the watcher a action happened 86 func (w *WatcherHub) notify(resp Response) error { 87 resp.Key = path.Clean(resp.Key) 88 89 segments := strings.Split(resp.Key, "/") 90 currPath := "/" 91 92 // walk through all the pathes 93 for _, segment := range segments { 94 currPath = path.Join(currPath, segment) 95 96 watchers, ok := w.watchers[currPath] 97 98 if ok { 99 100 newWatchers := make([]*Watcher, 0) 101 // notify all the watchers 102 for _, watcher := range watchers { 103 watcher.C <- &resp 104 } 105 106 if len(newWatchers) == 0 { 107 // we have notified all the watchers at this path 108 // delete the map 109 delete(w.watchers, currPath) 110 } else { 111 w.watchers[currPath] = newWatchers 112 } 113 } 114 115 } 116 117 return nil 118 } 119 120 // stopWatchers stops all the watchers 121 // This function is used when the etcd recovery from a snapshot at runtime 122 func (w *WatcherHub) stopWatchers() { 123 for _, subWatchers := range w.watchers { 124 for _, watcher := range subWatchers { 125 watcher.C <- nil 126 } 127 } 128 w.watchers = nil 129 }