|
|
@@ -19,7 +19,8 @@ type watcherHub struct {
|
|
|
watchers map[string]*list.List
|
|
|
count int64 // current number of watchers.
|
|
|
EventHistory *EventHistory
|
|
|
- pendingWatchers *list.List
|
|
|
+ pendingWatchers map[*list.Element]*list.List
|
|
|
+ pendingList map[*list.List]string
|
|
|
}
|
|
|
|
|
|
// newWatchHub creates a watchHub. The capacity determines how many events we will
|
|
|
@@ -30,7 +31,8 @@ func newWatchHub(capacity int) *watcherHub {
|
|
|
return &watcherHub{
|
|
|
watchers: make(map[string]*list.List),
|
|
|
EventHistory: newEventHistory(capacity),
|
|
|
- pendingWatchers: list.New(),
|
|
|
+ pendingWatchers: make(map[*list.Element]*list.List),
|
|
|
+ pendingList: make(map[*list.List]string),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -39,23 +41,30 @@ func newWatchHub(capacity int) *watcherHub {
|
|
|
// If recursive is false, the first change after index at prefix will be sent to the event channel.
|
|
|
// If index is zero, watch will start from the current index + 1.
|
|
|
func (wh *watcherHub) watch(prefix string, recursive bool, index uint64) (<-chan *Event, *etcdErr.Error) {
|
|
|
- eventChan := make(chan *Event, 1)
|
|
|
-
|
|
|
- e, err := wh.EventHistory.scan(prefix, index)
|
|
|
+ events, err := wh.EventHistory.scan(prefix, index)
|
|
|
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
- if e != nil {
|
|
|
- eventChan <- e
|
|
|
+ eventChan := make(chan *Event, len(events)+5) // use a buffered channel
|
|
|
+
|
|
|
+ if events != nil {
|
|
|
+ for _, e := range events {
|
|
|
+ eventChan <- e
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(events) > 1 {
|
|
|
+ eventChan <- nil
|
|
|
+ }
|
|
|
+
|
|
|
return eventChan, nil
|
|
|
}
|
|
|
|
|
|
w := &watcher{
|
|
|
eventChan: eventChan,
|
|
|
recursive: recursive,
|
|
|
- sinceIndex: index - 1, // to catch Expire()
|
|
|
+ sinceIndex: index,
|
|
|
}
|
|
|
|
|
|
l, ok := wh.watchers[prefix]
|
|
|
@@ -95,19 +104,16 @@ func (wh *watcherHub) notify(e *Event) {
|
|
|
|
|
|
func (wh *watcherHub) notifyWatchers(e *Event, path string, deleted bool) {
|
|
|
l, ok := wh.watchers[path]
|
|
|
-
|
|
|
if ok {
|
|
|
curr := l.Front()
|
|
|
- notifiedAll := true
|
|
|
|
|
|
for {
|
|
|
if curr == nil { // we have reached the end of the list
|
|
|
- if notifiedAll {
|
|
|
+ if l.Len() == 0 {
|
|
|
// if we have notified all watcher in the list
|
|
|
// we can delete the list
|
|
|
delete(wh.watchers, path)
|
|
|
}
|
|
|
-
|
|
|
break
|
|
|
}
|
|
|
|
|
|
@@ -116,20 +122,18 @@ func (wh *watcherHub) notifyWatchers(e *Event, path string, deleted bool) {
|
|
|
w, _ := curr.Value.(*watcher)
|
|
|
|
|
|
if w.notify(e, e.Key == path, deleted) {
|
|
|
- // if we successfully notify a watcher
|
|
|
- // we need to remove the watcher from the list
|
|
|
- // and decrease the counter
|
|
|
- l.Remove(curr)
|
|
|
- atomic.AddInt64(&wh.count, -1)
|
|
|
|
|
|
if e.Action == Expire {
|
|
|
- wh.pendingWatchers.PushBack(w)
|
|
|
+ wh.pendingWatchers[curr] = l
|
|
|
+ wh.pendingList[l] = path
|
|
|
+ } else {
|
|
|
+ // if we successfully notify a watcher
|
|
|
+ // we need to remove the watcher from the list
|
|
|
+ // and decrease the counter
|
|
|
+ l.Remove(curr)
|
|
|
+ atomic.AddInt64(&wh.count, -1)
|
|
|
}
|
|
|
|
|
|
- } else {
|
|
|
- // once there is a watcher in the list is not interested
|
|
|
- // in the event, we should keep the list in the map
|
|
|
- notifiedAll = false
|
|
|
}
|
|
|
|
|
|
curr = next // update current to the next
|
|
|
@@ -138,11 +142,24 @@ func (wh *watcherHub) notifyWatchers(e *Event, path string, deleted bool) {
|
|
|
}
|
|
|
|
|
|
func (wh *watcherHub) clearPendingWatchers() {
|
|
|
- for e := wh.pendingWatchers.Front(); e != nil; e = e.Next() {
|
|
|
+ if len(wh.pendingWatchers) == 0 { // avoid making new maps
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ for e, l := range wh.pendingWatchers {
|
|
|
+ l.Remove(e)
|
|
|
+
|
|
|
+ if l.Len() == 0 {
|
|
|
+ path := wh.pendingList[l]
|
|
|
+ delete(wh.watchers, path)
|
|
|
+ }
|
|
|
+
|
|
|
w, _ := e.Value.(*watcher)
|
|
|
w.eventChan <- nil
|
|
|
}
|
|
|
- wh.pendingWatchers = list.New()
|
|
|
+
|
|
|
+ wh.pendingWatchers = make(map[*list.Element]*list.List)
|
|
|
+ wh.pendingList = make(map[*list.List]string)
|
|
|
}
|
|
|
|
|
|
// clone function clones the watcherHub and return the cloned one.
|