k8s.io/client-go@v0.31.1/tools/cache/delta_fifo.go (about)

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package cache
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"sync"
    23  	"time"
    24  
    25  	"k8s.io/apimachinery/pkg/util/sets"
    26  
    27  	"k8s.io/klog/v2"
    28  	utiltrace "k8s.io/utils/trace"
    29  )
    30  
    31  // DeltaFIFOOptions is the configuration parameters for DeltaFIFO. All are
    32  // optional.
    33  type DeltaFIFOOptions struct {
    34  
    35  	// KeyFunction is used to figure out what key an object should have. (It's
    36  	// exposed in the returned DeltaFIFO's KeyOf() method, with additional
    37  	// handling around deleted objects and queue state).
    38  	// Optional, the default is MetaNamespaceKeyFunc.
    39  	KeyFunction KeyFunc
    40  
    41  	// KnownObjects is expected to return a list of keys that the consumer of
    42  	// this queue "knows about". It is used to decide which items are missing
    43  	// when Replace() is called; 'Deleted' deltas are produced for the missing items.
    44  	// KnownObjects may be nil if you can tolerate missing deletions on Replace().
    45  	KnownObjects KeyListerGetter
    46  
    47  	// EmitDeltaTypeReplaced indicates that the queue consumer
    48  	// understands the Replaced DeltaType. Before the `Replaced` event type was
    49  	// added, calls to Replace() were handled the same as Sync(). For
    50  	// backwards-compatibility purposes, this is false by default.
    51  	// When true, `Replaced` events will be sent for items passed to a Replace() call.
    52  	// When false, `Sync` events will be sent instead.
    53  	EmitDeltaTypeReplaced bool
    54  
    55  	// If set, will be called for objects before enqueueing them. Please
    56  	// see the comment on TransformFunc for details.
    57  	Transformer TransformFunc
    58  }
    59  
    60  // DeltaFIFO is like FIFO, but differs in two ways.  One is that the
    61  // accumulator associated with a given object's key is not that object
    62  // but rather a Deltas, which is a slice of Delta values for that
    63  // object.  Applying an object to a Deltas means to append a Delta
    64  // except when the potentially appended Delta is a Deleted and the
    65  // Deltas already ends with a Deleted.  In that case the Deltas does
    66  // not grow, although the terminal Deleted will be replaced by the new
    67  // Deleted if the older Deleted's object is a
    68  // DeletedFinalStateUnknown.
    69  //
    70  // The other difference is that DeltaFIFO has two additional ways that
    71  // an object can be applied to an accumulator: Replaced and Sync.
    72  // If EmitDeltaTypeReplaced is not set to true, Sync will be used in
    73  // replace events for backwards compatibility.  Sync is used for periodic
    74  // resync events.
    75  //
    76  // DeltaFIFO is a producer-consumer queue, where a Reflector is
    77  // intended to be the producer, and the consumer is whatever calls
    78  // the Pop() method.
    79  //
    80  // DeltaFIFO solves this use case:
    81  //   - You want to process every object change (delta) at most once.
    82  //   - When you process an object, you want to see everything
    83  //     that's happened to it since you last processed it.
    84  //   - You want to process the deletion of some of the objects.
    85  //   - You might want to periodically reprocess objects.
    86  //
    87  // DeltaFIFO's Pop(), Get(), and GetByKey() methods return
    88  // interface{} to satisfy the Store/Queue interfaces, but they
    89  // will always return an object of type Deltas. List() returns
    90  // the newest object from each accumulator in the FIFO.
    91  //
    92  // A DeltaFIFO's knownObjects KeyListerGetter provides the abilities
    93  // to list Store keys and to get objects by Store key.  The objects in
    94  // question are called "known objects" and this set of objects
    95  // modifies the behavior of the Delete, Replace, and Resync methods
    96  // (each in a different way).
    97  //
    98  // A note on threading: If you call Pop() in parallel from multiple
    99  // threads, you could end up with multiple threads processing slightly
   100  // different versions of the same object.
   101  type DeltaFIFO struct {
   102  	// lock/cond protects access to 'items' and 'queue'.
   103  	lock sync.RWMutex
   104  	cond sync.Cond
   105  
   106  	// `items` maps a key to a Deltas.
   107  	// Each such Deltas has at least one Delta.
   108  	items map[string]Deltas
   109  
   110  	// `queue` maintains FIFO order of keys for consumption in Pop().
   111  	// There are no duplicates in `queue`.
   112  	// A key is in `queue` if and only if it is in `items`.
   113  	queue []string
   114  
   115  	// populated is true if the first batch of items inserted by Replace() has been populated
   116  	// or Delete/Add/Update/AddIfNotPresent was called first.
   117  	populated bool
   118  	// initialPopulationCount is the number of items inserted by the first call of Replace()
   119  	initialPopulationCount int
   120  
   121  	// keyFunc is used to make the key used for queued item
   122  	// insertion and retrieval, and should be deterministic.
   123  	keyFunc KeyFunc
   124  
   125  	// knownObjects list keys that are "known" --- affecting Delete(),
   126  	// Replace(), and Resync()
   127  	knownObjects KeyListerGetter
   128  
   129  	// Used to indicate a queue is closed so a control loop can exit when a queue is empty.
   130  	// Currently, not used to gate any of CRUD operations.
   131  	closed bool
   132  
   133  	// emitDeltaTypeReplaced is whether to emit the Replaced or Sync
   134  	// DeltaType when Replace() is called (to preserve backwards compat).
   135  	emitDeltaTypeReplaced bool
   136  
   137  	// Called with every object if non-nil.
   138  	transformer TransformFunc
   139  }
   140  
   141  // TransformFunc allows for transforming an object before it will be processed.
   142  //
   143  // The most common usage pattern is to clean-up some parts of the object to
   144  // reduce component memory usage if a given component doesn't care about them.
   145  //
   146  // New in v1.27: TransformFunc sees the object before any other actor, and it
   147  // is now safe to mutate the object in place instead of making a copy.
   148  //
   149  // It's recommended for the TransformFunc to be idempotent.
   150  // It MUST be idempotent if objects already present in the cache are passed to
   151  // the Replace() to avoid re-mutating them. Default informers do not pass
   152  // existing objects to Replace though.
   153  //
   154  // Note that TransformFunc is called while inserting objects into the
   155  // notification queue and is therefore extremely performance sensitive; please
   156  // do not do anything that will take a long time.
   157  type TransformFunc func(interface{}) (interface{}, error)
   158  
   159  // DeltaType is the type of a change (addition, deletion, etc)
   160  type DeltaType string
   161  
   162  // Change type definition
   163  const (
   164  	Added   DeltaType = "Added"
   165  	Updated DeltaType = "Updated"
   166  	Deleted DeltaType = "Deleted"
   167  	// Replaced is emitted when we encountered watch errors and had to do a
   168  	// relist. We don't know if the replaced object has changed.
   169  	//
   170  	// NOTE: Previous versions of DeltaFIFO would use Sync for Replace events
   171  	// as well. Hence, Replaced is only emitted when the option
   172  	// EmitDeltaTypeReplaced is true.
   173  	Replaced DeltaType = "Replaced"
   174  	// Sync is for synthetic events during a periodic resync.
   175  	Sync DeltaType = "Sync"
   176  )
   177  
   178  // Delta is a member of Deltas (a list of Delta objects) which
   179  // in its turn is the type stored by a DeltaFIFO. It tells you what
   180  // change happened, and the object's state after* that change.
   181  //
   182  // [*] Unless the change is a deletion, and then you'll get the final
   183  // state of the object before it was deleted.
   184  type Delta struct {
   185  	Type   DeltaType
   186  	Object interface{}
   187  }
   188  
   189  // Deltas is a list of one or more 'Delta's to an individual object.
   190  // The oldest delta is at index 0, the newest delta is the last one.
   191  type Deltas []Delta
   192  
   193  // NewDeltaFIFO returns a Queue which can be used to process changes to items.
   194  //
   195  // keyFunc is used to figure out what key an object should have. (It is
   196  // exposed in the returned DeltaFIFO's KeyOf() method, with additional handling
   197  // around deleted objects and queue state).
   198  //
   199  // 'knownObjects' may be supplied to modify the behavior of Delete,
   200  // Replace, and Resync.  It may be nil if you do not need those
   201  // modifications.
   202  //
   203  // TODO: consider merging keyLister with this object, tracking a list of
   204  // "known" keys when Pop() is called. Have to think about how that
   205  // affects error retrying.
   206  //
   207  //	NOTE: It is possible to misuse this and cause a race when using an
   208  //	external known object source.
   209  //	Whether there is a potential race depends on how the consumer
   210  //	modifies knownObjects. In Pop(), process function is called under
   211  //	lock, so it is safe to update data structures in it that need to be
   212  //	in sync with the queue (e.g. knownObjects).
   213  //
   214  //	Example:
   215  //	In case of sharedIndexInformer being a consumer
   216  //	(https://github.com/kubernetes/kubernetes/blob/0cdd940f/staging/src/k8s.io/client-go/tools/cache/shared_informer.go#L192),
   217  //	there is no race as knownObjects (s.indexer) is modified safely
   218  //	under DeltaFIFO's lock. The only exceptions are GetStore() and
   219  //	GetIndexer() methods, which expose ways to modify the underlying
   220  //	storage. Currently these two methods are used for creating Lister
   221  //	and internal tests.
   222  //
   223  // Also see the comment on DeltaFIFO.
   224  //
   225  // Warning: This constructs a DeltaFIFO that does not differentiate between
   226  // events caused by a call to Replace (e.g., from a relist, which may
   227  // contain object updates), and synthetic events caused by a periodic resync
   228  // (which just emit the existing object). See https://issue.k8s.io/86015 for details.
   229  //
   230  // Use `NewDeltaFIFOWithOptions(DeltaFIFOOptions{..., EmitDeltaTypeReplaced: true})`
   231  // instead to receive a `Replaced` event depending on the type.
   232  //
   233  // Deprecated: Equivalent to NewDeltaFIFOWithOptions(DeltaFIFOOptions{KeyFunction: keyFunc, KnownObjects: knownObjects})
   234  func NewDeltaFIFO(keyFunc KeyFunc, knownObjects KeyListerGetter) *DeltaFIFO {
   235  	return NewDeltaFIFOWithOptions(DeltaFIFOOptions{
   236  		KeyFunction:  keyFunc,
   237  		KnownObjects: knownObjects,
   238  	})
   239  }
   240  
   241  // NewDeltaFIFOWithOptions returns a Queue which can be used to process changes to
   242  // items. See also the comment on DeltaFIFO.
   243  func NewDeltaFIFOWithOptions(opts DeltaFIFOOptions) *DeltaFIFO {
   244  	if opts.KeyFunction == nil {
   245  		opts.KeyFunction = MetaNamespaceKeyFunc
   246  	}
   247  
   248  	f := &DeltaFIFO{
   249  		items:        map[string]Deltas{},
   250  		queue:        []string{},
   251  		keyFunc:      opts.KeyFunction,
   252  		knownObjects: opts.KnownObjects,
   253  
   254  		emitDeltaTypeReplaced: opts.EmitDeltaTypeReplaced,
   255  		transformer:           opts.Transformer,
   256  	}
   257  	f.cond.L = &f.lock
   258  	return f
   259  }
   260  
   261  var (
   262  	_ = Queue(&DeltaFIFO{}) // DeltaFIFO is a Queue
   263  )
   264  
   265  var (
   266  	// ErrZeroLengthDeltasObject is returned in a KeyError if a Deltas
   267  	// object with zero length is encountered (should be impossible,
   268  	// but included for completeness).
   269  	ErrZeroLengthDeltasObject = errors.New("0 length Deltas object; can't get key")
   270  )
   271  
   272  // Close the queue.
   273  func (f *DeltaFIFO) Close() {
   274  	f.lock.Lock()
   275  	defer f.lock.Unlock()
   276  	f.closed = true
   277  	f.cond.Broadcast()
   278  }
   279  
   280  // KeyOf exposes f's keyFunc, but also detects the key of a Deltas object or
   281  // DeletedFinalStateUnknown objects.
   282  func (f *DeltaFIFO) KeyOf(obj interface{}) (string, error) {
   283  	if d, ok := obj.(Deltas); ok {
   284  		if len(d) == 0 {
   285  			return "", KeyError{obj, ErrZeroLengthDeltasObject}
   286  		}
   287  		obj = d.Newest().Object
   288  	}
   289  	if d, ok := obj.(DeletedFinalStateUnknown); ok {
   290  		return d.Key, nil
   291  	}
   292  	return f.keyFunc(obj)
   293  }
   294  
   295  // HasSynced returns true if an Add/Update/Delete/AddIfNotPresent are called first,
   296  // or the first batch of items inserted by Replace() has been popped.
   297  func (f *DeltaFIFO) HasSynced() bool {
   298  	f.lock.Lock()
   299  	defer f.lock.Unlock()
   300  	return f.hasSynced_locked()
   301  }
   302  
   303  func (f *DeltaFIFO) hasSynced_locked() bool {
   304  	return f.populated && f.initialPopulationCount == 0
   305  }
   306  
   307  // Add inserts an item, and puts it in the queue. The item is only enqueued
   308  // if it doesn't already exist in the set.
   309  func (f *DeltaFIFO) Add(obj interface{}) error {
   310  	f.lock.Lock()
   311  	defer f.lock.Unlock()
   312  	f.populated = true
   313  	return f.queueActionLocked(Added, obj)
   314  }
   315  
   316  // Update is just like Add, but makes an Updated Delta.
   317  func (f *DeltaFIFO) Update(obj interface{}) error {
   318  	f.lock.Lock()
   319  	defer f.lock.Unlock()
   320  	f.populated = true
   321  	return f.queueActionLocked(Updated, obj)
   322  }
   323  
   324  // Delete is just like Add, but makes a Deleted Delta. If the given
   325  // object does not already exist, it will be ignored. (It may have
   326  // already been deleted by a Replace (re-list), for example.)  In this
   327  // method `f.knownObjects`, if not nil, provides (via GetByKey)
   328  // _additional_ objects that are considered to already exist.
   329  func (f *DeltaFIFO) Delete(obj interface{}) error {
   330  	id, err := f.KeyOf(obj)
   331  	if err != nil {
   332  		return KeyError{obj, err}
   333  	}
   334  	f.lock.Lock()
   335  	defer f.lock.Unlock()
   336  	f.populated = true
   337  	if f.knownObjects == nil {
   338  		if _, exists := f.items[id]; !exists {
   339  			// Presumably, this was deleted when a relist happened.
   340  			// Don't provide a second report of the same deletion.
   341  			return nil
   342  		}
   343  	} else {
   344  		// We only want to skip the "deletion" action if the object doesn't
   345  		// exist in knownObjects and it doesn't have corresponding item in items.
   346  		// Note that even if there is a "deletion" action in items, we can ignore it,
   347  		// because it will be deduped automatically in "queueActionLocked"
   348  		_, exists, err := f.knownObjects.GetByKey(id)
   349  		_, itemsExist := f.items[id]
   350  		if err == nil && !exists && !itemsExist {
   351  			// Presumably, this was deleted when a relist happened.
   352  			// Don't provide a second report of the same deletion.
   353  			return nil
   354  		}
   355  	}
   356  
   357  	// exist in items and/or KnownObjects
   358  	return f.queueActionLocked(Deleted, obj)
   359  }
   360  
   361  // AddIfNotPresent inserts an item, and puts it in the queue. If the item is already
   362  // present in the set, it is neither enqueued nor added to the set.
   363  //
   364  // This is useful in a single producer/consumer scenario so that the consumer can
   365  // safely retry items without contending with the producer and potentially enqueueing
   366  // stale items.
   367  //
   368  // Important: obj must be a Deltas (the output of the Pop() function). Yes, this is
   369  // different from the Add/Update/Delete functions.
   370  func (f *DeltaFIFO) AddIfNotPresent(obj interface{}) error {
   371  	deltas, ok := obj.(Deltas)
   372  	if !ok {
   373  		return fmt.Errorf("object must be of type deltas, but got: %#v", obj)
   374  	}
   375  	id, err := f.KeyOf(deltas)
   376  	if err != nil {
   377  		return KeyError{obj, err}
   378  	}
   379  	f.lock.Lock()
   380  	defer f.lock.Unlock()
   381  	f.addIfNotPresent(id, deltas)
   382  	return nil
   383  }
   384  
   385  // addIfNotPresent inserts deltas under id if it does not exist, and assumes the caller
   386  // already holds the fifo lock.
   387  func (f *DeltaFIFO) addIfNotPresent(id string, deltas Deltas) {
   388  	f.populated = true
   389  	if _, exists := f.items[id]; exists {
   390  		return
   391  	}
   392  
   393  	f.queue = append(f.queue, id)
   394  	f.items[id] = deltas
   395  	f.cond.Broadcast()
   396  }
   397  
   398  // re-listing and watching can deliver the same update multiple times in any
   399  // order. This will combine the most recent two deltas if they are the same.
   400  func dedupDeltas(deltas Deltas) Deltas {
   401  	n := len(deltas)
   402  	if n < 2 {
   403  		return deltas
   404  	}
   405  	a := &deltas[n-1]
   406  	b := &deltas[n-2]
   407  	if out := isDup(a, b); out != nil {
   408  		deltas[n-2] = *out
   409  		return deltas[:n-1]
   410  	}
   411  	return deltas
   412  }
   413  
   414  // If a & b represent the same event, returns the delta that ought to be kept.
   415  // Otherwise, returns nil.
   416  // TODO: is there anything other than deletions that need deduping?
   417  func isDup(a, b *Delta) *Delta {
   418  	if out := isDeletionDup(a, b); out != nil {
   419  		return out
   420  	}
   421  	// TODO: Detect other duplicate situations? Are there any?
   422  	return nil
   423  }
   424  
   425  // keep the one with the most information if both are deletions.
   426  func isDeletionDup(a, b *Delta) *Delta {
   427  	if b.Type != Deleted || a.Type != Deleted {
   428  		return nil
   429  	}
   430  	// Do more sophisticated checks, or is this sufficient?
   431  	if _, ok := b.Object.(DeletedFinalStateUnknown); ok {
   432  		return a
   433  	}
   434  	return b
   435  }
   436  
   437  // queueActionLocked appends to the delta list for the object.
   438  // Caller must lock first.
   439  func (f *DeltaFIFO) queueActionLocked(actionType DeltaType, obj interface{}) error {
   440  	return f.queueActionInternalLocked(actionType, actionType, obj)
   441  }
   442  
   443  // queueActionInternalLocked appends to the delta list for the object.
   444  // The actionType is emitted and must honor emitDeltaTypeReplaced.
   445  // The internalActionType is only used within this function and must
   446  // ignore emitDeltaTypeReplaced.
   447  // Caller must lock first.
   448  func (f *DeltaFIFO) queueActionInternalLocked(actionType, internalActionType DeltaType, obj interface{}) error {
   449  	id, err := f.KeyOf(obj)
   450  	if err != nil {
   451  		return KeyError{obj, err}
   452  	}
   453  
   454  	// Every object comes through this code path once, so this is a good
   455  	// place to call the transform func.
   456  	//
   457  	// If obj is a DeletedFinalStateUnknown tombstone or the action is a Sync,
   458  	// then the object have already gone through the transformer.
   459  	//
   460  	// If the objects already present in the cache are passed to Replace(),
   461  	// the transformer must be idempotent to avoid re-mutating them,
   462  	// or coordinate with all readers from the cache to avoid data races.
   463  	// Default informers do not pass existing objects to Replace.
   464  	if f.transformer != nil {
   465  		_, isTombstone := obj.(DeletedFinalStateUnknown)
   466  		if !isTombstone && internalActionType != Sync {
   467  			var err error
   468  			obj, err = f.transformer(obj)
   469  			if err != nil {
   470  				return err
   471  			}
   472  		}
   473  	}
   474  
   475  	oldDeltas := f.items[id]
   476  	newDeltas := append(oldDeltas, Delta{actionType, obj})
   477  	newDeltas = dedupDeltas(newDeltas)
   478  
   479  	if len(newDeltas) > 0 {
   480  		if _, exists := f.items[id]; !exists {
   481  			f.queue = append(f.queue, id)
   482  		}
   483  		f.items[id] = newDeltas
   484  		f.cond.Broadcast()
   485  	} else {
   486  		// This never happens, because dedupDeltas never returns an empty list
   487  		// when given a non-empty list (as it is here).
   488  		// If somehow it happens anyway, deal with it but complain.
   489  		if oldDeltas == nil {
   490  			klog.Errorf("Impossible dedupDeltas for id=%q: oldDeltas=%#+v, obj=%#+v; ignoring", id, oldDeltas, obj)
   491  			return nil
   492  		}
   493  		klog.Errorf("Impossible dedupDeltas for id=%q: oldDeltas=%#+v, obj=%#+v; breaking invariant by storing empty Deltas", id, oldDeltas, obj)
   494  		f.items[id] = newDeltas
   495  		return fmt.Errorf("Impossible dedupDeltas for id=%q: oldDeltas=%#+v, obj=%#+v; broke DeltaFIFO invariant by storing empty Deltas", id, oldDeltas, obj)
   496  	}
   497  	return nil
   498  }
   499  
   500  // List returns a list of all the items; it returns the object
   501  // from the most recent Delta.
   502  // You should treat the items returned inside the deltas as immutable.
   503  func (f *DeltaFIFO) List() []interface{} {
   504  	f.lock.RLock()
   505  	defer f.lock.RUnlock()
   506  	return f.listLocked()
   507  }
   508  
   509  func (f *DeltaFIFO) listLocked() []interface{} {
   510  	list := make([]interface{}, 0, len(f.items))
   511  	for _, item := range f.items {
   512  		list = append(list, item.Newest().Object)
   513  	}
   514  	return list
   515  }
   516  
   517  // ListKeys returns a list of all the keys of the objects currently
   518  // in the FIFO.
   519  func (f *DeltaFIFO) ListKeys() []string {
   520  	f.lock.RLock()
   521  	defer f.lock.RUnlock()
   522  	list := make([]string, 0, len(f.queue))
   523  	for _, key := range f.queue {
   524  		list = append(list, key)
   525  	}
   526  	return list
   527  }
   528  
   529  // Get returns the complete list of deltas for the requested item,
   530  // or sets exists=false.
   531  // You should treat the items returned inside the deltas as immutable.
   532  func (f *DeltaFIFO) Get(obj interface{}) (item interface{}, exists bool, err error) {
   533  	key, err := f.KeyOf(obj)
   534  	if err != nil {
   535  		return nil, false, KeyError{obj, err}
   536  	}
   537  	return f.GetByKey(key)
   538  }
   539  
   540  // GetByKey returns the complete list of deltas for the requested item,
   541  // setting exists=false if that list is empty.
   542  // You should treat the items returned inside the deltas as immutable.
   543  func (f *DeltaFIFO) GetByKey(key string) (item interface{}, exists bool, err error) {
   544  	f.lock.RLock()
   545  	defer f.lock.RUnlock()
   546  	d, exists := f.items[key]
   547  	if exists {
   548  		// Copy item's slice so operations on this slice
   549  		// won't interfere with the object we return.
   550  		d = copyDeltas(d)
   551  	}
   552  	return d, exists, nil
   553  }
   554  
   555  // IsClosed checks if the queue is closed
   556  func (f *DeltaFIFO) IsClosed() bool {
   557  	f.lock.Lock()
   558  	defer f.lock.Unlock()
   559  	return f.closed
   560  }
   561  
   562  // Pop blocks until the queue has some items, and then returns one.  If
   563  // multiple items are ready, they are returned in the order in which they were
   564  // added/updated. The item is removed from the queue (and the store) before it
   565  // is returned, so if you don't successfully process it, you need to add it back
   566  // with AddIfNotPresent().
   567  // process function is called under lock, so it is safe to update data structures
   568  // in it that need to be in sync with the queue (e.g. knownKeys). The PopProcessFunc
   569  // may return an instance of ErrRequeue with a nested error to indicate the current
   570  // item should be requeued (equivalent to calling AddIfNotPresent under the lock).
   571  // process should avoid expensive I/O operation so that other queue operations, i.e.
   572  // Add() and Get(), won't be blocked for too long.
   573  //
   574  // Pop returns a 'Deltas', which has a complete list of all the things
   575  // that happened to the object (deltas) while it was sitting in the queue.
   576  func (f *DeltaFIFO) Pop(process PopProcessFunc) (interface{}, error) {
   577  	f.lock.Lock()
   578  	defer f.lock.Unlock()
   579  	for {
   580  		for len(f.queue) == 0 {
   581  			// When the queue is empty, invocation of Pop() is blocked until new item is enqueued.
   582  			// When Close() is called, the f.closed is set and the condition is broadcasted.
   583  			// Which causes this loop to continue and return from the Pop().
   584  			if f.closed {
   585  				return nil, ErrFIFOClosed
   586  			}
   587  
   588  			f.cond.Wait()
   589  		}
   590  		isInInitialList := !f.hasSynced_locked()
   591  		id := f.queue[0]
   592  		f.queue = f.queue[1:]
   593  		depth := len(f.queue)
   594  		if f.initialPopulationCount > 0 {
   595  			f.initialPopulationCount--
   596  		}
   597  		item, ok := f.items[id]
   598  		if !ok {
   599  			// This should never happen
   600  			klog.Errorf("Inconceivable! %q was in f.queue but not f.items; ignoring.", id)
   601  			continue
   602  		}
   603  		delete(f.items, id)
   604  		// Only log traces if the queue depth is greater than 10 and it takes more than
   605  		// 100 milliseconds to process one item from the queue.
   606  		// Queue depth never goes high because processing an item is locking the queue,
   607  		// and new items can't be added until processing finish.
   608  		// https://github.com/kubernetes/kubernetes/issues/103789
   609  		if depth > 10 {
   610  			trace := utiltrace.New("DeltaFIFO Pop Process",
   611  				utiltrace.Field{Key: "ID", Value: id},
   612  				utiltrace.Field{Key: "Depth", Value: depth},
   613  				utiltrace.Field{Key: "Reason", Value: "slow event handlers blocking the queue"})
   614  			defer trace.LogIfLong(100 * time.Millisecond)
   615  		}
   616  		err := process(item, isInInitialList)
   617  		if e, ok := err.(ErrRequeue); ok {
   618  			f.addIfNotPresent(id, item)
   619  			err = e.Err
   620  		}
   621  		// Don't need to copyDeltas here, because we're transferring
   622  		// ownership to the caller.
   623  		return item, err
   624  	}
   625  }
   626  
   627  // Replace atomically does two things: (1) it adds the given objects
   628  // using the Sync or Replace DeltaType and then (2) it does some deletions.
   629  // In particular: for every pre-existing key K that is not the key of
   630  // an object in `list` there is the effect of
   631  // `Delete(DeletedFinalStateUnknown{K, O})` where O is the latest known
   632  // object of K. The pre-existing keys are those in the union set of the keys in
   633  // `f.items` and `f.knownObjects` (if not nil). The last known object for key K is
   634  // the one present in the last delta in `f.items`. If there is no delta for K
   635  // in `f.items`, it is the object in `f.knownObjects`
   636  func (f *DeltaFIFO) Replace(list []interface{}, _ string) error {
   637  	f.lock.Lock()
   638  	defer f.lock.Unlock()
   639  	keys := make(sets.String, len(list))
   640  
   641  	// keep backwards compat for old clients
   642  	action := Sync
   643  	if f.emitDeltaTypeReplaced {
   644  		action = Replaced
   645  	}
   646  
   647  	// Add Sync/Replaced action for each new item.
   648  	for _, item := range list {
   649  		key, err := f.KeyOf(item)
   650  		if err != nil {
   651  			return KeyError{item, err}
   652  		}
   653  		keys.Insert(key)
   654  		if err := f.queueActionInternalLocked(action, Replaced, item); err != nil {
   655  			return fmt.Errorf("couldn't enqueue object: %v", err)
   656  		}
   657  	}
   658  
   659  	// Do deletion detection against objects in the queue
   660  	queuedDeletions := 0
   661  	for k, oldItem := range f.items {
   662  		if keys.Has(k) {
   663  			continue
   664  		}
   665  		// Delete pre-existing items not in the new list.
   666  		// This could happen if watch deletion event was missed while
   667  		// disconnected from apiserver.
   668  		var deletedObj interface{}
   669  		if n := oldItem.Newest(); n != nil {
   670  			deletedObj = n.Object
   671  
   672  			// if the previous object is a DeletedFinalStateUnknown, we have to extract the actual Object
   673  			if d, ok := deletedObj.(DeletedFinalStateUnknown); ok {
   674  				deletedObj = d.Obj
   675  			}
   676  		}
   677  		queuedDeletions++
   678  		if err := f.queueActionLocked(Deleted, DeletedFinalStateUnknown{k, deletedObj}); err != nil {
   679  			return err
   680  		}
   681  	}
   682  
   683  	if f.knownObjects != nil {
   684  		// Detect deletions for objects not present in the queue, but present in KnownObjects
   685  		knownKeys := f.knownObjects.ListKeys()
   686  		for _, k := range knownKeys {
   687  			if keys.Has(k) {
   688  				continue
   689  			}
   690  			if len(f.items[k]) > 0 {
   691  				continue
   692  			}
   693  
   694  			deletedObj, exists, err := f.knownObjects.GetByKey(k)
   695  			if err != nil {
   696  				deletedObj = nil
   697  				klog.Errorf("Unexpected error %v during lookup of key %v, placing DeleteFinalStateUnknown marker without object", err, k)
   698  			} else if !exists {
   699  				deletedObj = nil
   700  				klog.Infof("Key %v does not exist in known objects store, placing DeleteFinalStateUnknown marker without object", k)
   701  			}
   702  			queuedDeletions++
   703  			if err := f.queueActionLocked(Deleted, DeletedFinalStateUnknown{k, deletedObj}); err != nil {
   704  				return err
   705  			}
   706  		}
   707  	}
   708  
   709  	if !f.populated {
   710  		f.populated = true
   711  		f.initialPopulationCount = keys.Len() + queuedDeletions
   712  	}
   713  
   714  	return nil
   715  }
   716  
   717  // Resync adds, with a Sync type of Delta, every object listed by
   718  // `f.knownObjects` whose key is not already queued for processing.
   719  // If `f.knownObjects` is `nil` then Resync does nothing.
   720  func (f *DeltaFIFO) Resync() error {
   721  	f.lock.Lock()
   722  	defer f.lock.Unlock()
   723  
   724  	if f.knownObjects == nil {
   725  		return nil
   726  	}
   727  
   728  	keys := f.knownObjects.ListKeys()
   729  	for _, k := range keys {
   730  		if err := f.syncKeyLocked(k); err != nil {
   731  			return err
   732  		}
   733  	}
   734  	return nil
   735  }
   736  
   737  func (f *DeltaFIFO) syncKeyLocked(key string) error {
   738  	obj, exists, err := f.knownObjects.GetByKey(key)
   739  	if err != nil {
   740  		klog.Errorf("Unexpected error %v during lookup of key %v, unable to queue object for sync", err, key)
   741  		return nil
   742  	} else if !exists {
   743  		klog.Infof("Key %v does not exist in known objects store, unable to queue object for sync", key)
   744  		return nil
   745  	}
   746  
   747  	// If we are doing Resync() and there is already an event queued for that object,
   748  	// we ignore the Resync for it. This is to avoid the race, in which the resync
   749  	// comes with the previous value of object (since queueing an event for the object
   750  	// doesn't trigger changing the underlying store <knownObjects>.
   751  	id, err := f.KeyOf(obj)
   752  	if err != nil {
   753  		return KeyError{obj, err}
   754  	}
   755  	if len(f.items[id]) > 0 {
   756  		return nil
   757  	}
   758  
   759  	if err := f.queueActionLocked(Sync, obj); err != nil {
   760  		return fmt.Errorf("couldn't queue object: %v", err)
   761  	}
   762  	return nil
   763  }
   764  
   765  // A KeyListerGetter is anything that knows how to list its keys and look up by key.
   766  type KeyListerGetter interface {
   767  	KeyLister
   768  	KeyGetter
   769  }
   770  
   771  // A KeyLister is anything that knows how to list its keys.
   772  type KeyLister interface {
   773  	ListKeys() []string
   774  }
   775  
   776  // A KeyGetter is anything that knows how to get the value stored under a given key.
   777  type KeyGetter interface {
   778  	// GetByKey returns the value associated with the key, or sets exists=false.
   779  	GetByKey(key string) (value interface{}, exists bool, err error)
   780  }
   781  
   782  // Oldest is a convenience function that returns the oldest delta, or
   783  // nil if there are no deltas.
   784  func (d Deltas) Oldest() *Delta {
   785  	if len(d) > 0 {
   786  		return &d[0]
   787  	}
   788  	return nil
   789  }
   790  
   791  // Newest is a convenience function that returns the newest delta, or
   792  // nil if there are no deltas.
   793  func (d Deltas) Newest() *Delta {
   794  	if n := len(d); n > 0 {
   795  		return &d[n-1]
   796  	}
   797  	return nil
   798  }
   799  
   800  // copyDeltas returns a shallow copy of d; that is, it copies the slice but not
   801  // the objects in the slice. This allows Get/List to return an object that we
   802  // know won't be clobbered by a subsequent modifications.
   803  func copyDeltas(d Deltas) Deltas {
   804  	d2 := make(Deltas, len(d))
   805  	copy(d2, d)
   806  	return d2
   807  }
   808  
   809  // DeletedFinalStateUnknown is placed into a DeltaFIFO in the case where an object
   810  // was deleted but the watch deletion event was missed while disconnected from
   811  // apiserver. In this case we don't know the final "resting" state of the object, so
   812  // there's a chance the included `Obj` is stale.
   813  type DeletedFinalStateUnknown struct {
   814  	Key string
   815  	Obj interface{}
   816  }