watcher.go 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. /*
  2. Copyright 2014 CoreOS, Inc.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package store
  14. type Watcher interface {
  15. EventChan() chan *Event
  16. StartIndex() uint64 // The EtcdIndex at which the Watcher was created
  17. Remove()
  18. }
  19. type watcher struct {
  20. eventChan chan *Event
  21. stream bool
  22. recursive bool
  23. sinceIndex uint64
  24. startIndex uint64
  25. hub *watcherHub
  26. removed bool
  27. remove func()
  28. }
  29. func (w *watcher) EventChan() chan *Event {
  30. return w.eventChan
  31. }
  32. func (w *watcher) StartIndex() uint64 {
  33. return w.startIndex
  34. }
  35. // notify function notifies the watcher. If the watcher interests in the given path,
  36. // the function will return true.
  37. func (w *watcher) notify(e *Event, originalPath bool, deleted bool) bool {
  38. // watcher is interested the path in three cases and under one condition
  39. // the condition is that the event happens after the watcher's sinceIndex
  40. // 1. the path at which the event happens is the path the watcher is watching at.
  41. // For example if the watcher is watching at "/foo" and the event happens at "/foo",
  42. // the watcher must be interested in that event.
  43. // 2. the watcher is a recursive watcher, it interests in the event happens after
  44. // its watching path. For example if watcher A watches at "/foo" and it is a recursive
  45. // one, it will interest in the event happens at "/foo/bar".
  46. // 3. when we delete a directory, we need to force notify all the watchers who watches
  47. // at the file we need to delete.
  48. // For example a watcher is watching at "/foo/bar". And we deletes "/foo". The watcher
  49. // should get notified even if "/foo" is not the path it is watching.
  50. if (w.recursive || originalPath || deleted) && e.Index() >= w.sinceIndex {
  51. // We cannot block here if the eventChan capacity is full, otherwise
  52. // etcd will hang. eventChan capacity is full when the rate of
  53. // notifications are higher than our send rate.
  54. // If this happens, we close the channel.
  55. select {
  56. case w.eventChan <- e:
  57. default:
  58. // We have missed a notification. Remove the watcher.
  59. // Removing the watcher also closes the eventChan.
  60. w.remove()
  61. }
  62. return true
  63. }
  64. return false
  65. }
  66. // Remove removes the watcher from watcherHub
  67. // The actual remove function is guaranteed to only be executed once
  68. func (w *watcher) Remove() {
  69. w.hub.mutex.Lock()
  70. defer w.hub.mutex.Unlock()
  71. close(w.eventChan)
  72. if w.remove != nil {
  73. w.remove()
  74. }
  75. }