go.etcd.io/etcd@v3.3.27+incompatible/store/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 store
    16  
    17  type Watcher interface {
    18  	EventChan() chan *Event
    19  	StartIndex() uint64 // The EtcdIndex at which the Watcher was created
    20  	Remove()
    21  }
    22  
    23  type watcher struct {
    24  	eventChan  chan *Event
    25  	stream     bool
    26  	recursive  bool
    27  	sinceIndex uint64
    28  	startIndex uint64
    29  	hub        *watcherHub
    30  	removed    bool
    31  	remove     func()
    32  }
    33  
    34  func (w *watcher) EventChan() chan *Event {
    35  	return w.eventChan
    36  }
    37  
    38  func (w *watcher) StartIndex() uint64 {
    39  	return w.startIndex
    40  }
    41  
    42  // notify function notifies the watcher. If the watcher interests in the given path,
    43  // the function will return true.
    44  func (w *watcher) notify(e *Event, originalPath bool, deleted bool) bool {
    45  	// watcher is interested the path in three cases and under one condition
    46  	// the condition is that the event happens after the watcher's sinceIndex
    47  
    48  	// 1. the path at which the event happens is the path the watcher is watching at.
    49  	// For example if the watcher is watching at "/foo" and the event happens at "/foo",
    50  	// the watcher must be interested in that event.
    51  
    52  	// 2. the watcher is a recursive watcher, it interests in the event happens after
    53  	// its watching path. For example if watcher A watches at "/foo" and it is a recursive
    54  	// one, it will interest in the event happens at "/foo/bar".
    55  
    56  	// 3. when we delete a directory, we need to force notify all the watchers who watches
    57  	// at the file we need to delete.
    58  	// For example a watcher is watching at "/foo/bar". And we deletes "/foo". The watcher
    59  	// should get notified even if "/foo" is not the path it is watching.
    60  	if (w.recursive || originalPath || deleted) && e.Index() >= w.sinceIndex {
    61  		// We cannot block here if the eventChan capacity is full, otherwise
    62  		// etcd will hang. eventChan capacity is full when the rate of
    63  		// notifications are higher than our send rate.
    64  		// If this happens, we close the channel.
    65  		select {
    66  		case w.eventChan <- e:
    67  		default:
    68  			// We have missed a notification. Remove the watcher.
    69  			// Removing the watcher also closes the eventChan.
    70  			w.remove()
    71  		}
    72  		return true
    73  	}
    74  	return false
    75  }
    76  
    77  // Remove removes the watcher from watcherHub
    78  // The actual remove function is guaranteed to only be executed once
    79  func (w *watcher) Remove() {
    80  	w.hub.mutex.Lock()
    81  	defer w.hub.mutex.Unlock()
    82  
    83  	close(w.eventChan)
    84  	if w.remove != nil {
    85  		w.remove()
    86  	}
    87  }
    88  
    89  // nopWatcher is a watcher that receives nothing, always blocking.
    90  type nopWatcher struct{}
    91  
    92  func NewNopWatcher() Watcher                 { return &nopWatcher{} }
    93  func (w *nopWatcher) EventChan() chan *Event { return nil }
    94  func (w *nopWatcher) StartIndex() uint64     { return 0 }
    95  func (w *nopWatcher) Remove()                {}