k8s.io/client-go@v0.22.2/tools/cache/store.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  	"fmt"
    21  	"strings"
    22  
    23  	"k8s.io/apimachinery/pkg/api/meta"
    24  )
    25  
    26  // Store is a generic object storage and processing interface.  A
    27  // Store holds a map from string keys to accumulators, and has
    28  // operations to add, update, and delete a given object to/from the
    29  // accumulator currently associated with a given key.  A Store also
    30  // knows how to extract the key from a given object, so many operations
    31  // are given only the object.
    32  //
    33  // In the simplest Store implementations each accumulator is simply
    34  // the last given object, or empty after Delete, and thus the Store's
    35  // behavior is simple storage.
    36  //
    37  // Reflector knows how to watch a server and update a Store.  This
    38  // package provides a variety of implementations of Store.
    39  type Store interface {
    40  
    41  	// Add adds the given object to the accumulator associated with the given object's key
    42  	Add(obj interface{}) error
    43  
    44  	// Update updates the given object in the accumulator associated with the given object's key
    45  	Update(obj interface{}) error
    46  
    47  	// Delete deletes the given object from the accumulator associated with the given object's key
    48  	Delete(obj interface{}) error
    49  
    50  	// List returns a list of all the currently non-empty accumulators
    51  	List() []interface{}
    52  
    53  	// ListKeys returns a list of all the keys currently associated with non-empty accumulators
    54  	ListKeys() []string
    55  
    56  	// Get returns the accumulator associated with the given object's key
    57  	Get(obj interface{}) (item interface{}, exists bool, err error)
    58  
    59  	// GetByKey returns the accumulator associated with the given key
    60  	GetByKey(key string) (item interface{}, exists bool, err error)
    61  
    62  	// Replace will delete the contents of the store, using instead the
    63  	// given list. Store takes ownership of the list, you should not reference
    64  	// it after calling this function.
    65  	Replace([]interface{}, string) error
    66  
    67  	// Resync is meaningless in the terms appearing here but has
    68  	// meaning in some implementations that have non-trivial
    69  	// additional behavior (e.g., DeltaFIFO).
    70  	Resync() error
    71  }
    72  
    73  // KeyFunc knows how to make a key from an object. Implementations should be deterministic.
    74  type KeyFunc func(obj interface{}) (string, error)
    75  
    76  // KeyError will be returned any time a KeyFunc gives an error; it includes the object
    77  // at fault.
    78  type KeyError struct {
    79  	Obj interface{}
    80  	Err error
    81  }
    82  
    83  // Error gives a human-readable description of the error.
    84  func (k KeyError) Error() string {
    85  	return fmt.Sprintf("couldn't create key for object %+v: %v", k.Obj, k.Err)
    86  }
    87  
    88  // Unwrap implements errors.Unwrap
    89  func (k KeyError) Unwrap() error {
    90  	return k.Err
    91  }
    92  
    93  // ExplicitKey can be passed to MetaNamespaceKeyFunc if you have the key for
    94  // the object but not the object itself.
    95  type ExplicitKey string
    96  
    97  // MetaNamespaceKeyFunc is a convenient default KeyFunc which knows how to make
    98  // keys for API objects which implement meta.Interface.
    99  // The key uses the format <namespace>/<name> unless <namespace> is empty, then
   100  // it's just <name>.
   101  //
   102  // TODO: replace key-as-string with a key-as-struct so that this
   103  // packing/unpacking won't be necessary.
   104  func MetaNamespaceKeyFunc(obj interface{}) (string, error) {
   105  	if key, ok := obj.(ExplicitKey); ok {
   106  		return string(key), nil
   107  	}
   108  	meta, err := meta.Accessor(obj)
   109  	if err != nil {
   110  		return "", fmt.Errorf("object has no meta: %v", err)
   111  	}
   112  	if len(meta.GetNamespace()) > 0 {
   113  		return meta.GetNamespace() + "/" + meta.GetName(), nil
   114  	}
   115  	return meta.GetName(), nil
   116  }
   117  
   118  // SplitMetaNamespaceKey returns the namespace and name that
   119  // MetaNamespaceKeyFunc encoded into key.
   120  //
   121  // TODO: replace key-as-string with a key-as-struct so that this
   122  // packing/unpacking won't be necessary.
   123  func SplitMetaNamespaceKey(key string) (namespace, name string, err error) {
   124  	parts := strings.Split(key, "/")
   125  	switch len(parts) {
   126  	case 1:
   127  		// name only, no namespace
   128  		return "", parts[0], nil
   129  	case 2:
   130  		// namespace and name
   131  		return parts[0], parts[1], nil
   132  	}
   133  
   134  	return "", "", fmt.Errorf("unexpected key format: %q", key)
   135  }
   136  
   137  // `*cache` implements Indexer in terms of a ThreadSafeStore and an
   138  // associated KeyFunc.
   139  type cache struct {
   140  	// cacheStorage bears the burden of thread safety for the cache
   141  	cacheStorage ThreadSafeStore
   142  	// keyFunc is used to make the key for objects stored in and retrieved from items, and
   143  	// should be deterministic.
   144  	keyFunc KeyFunc
   145  }
   146  
   147  var _ Store = &cache{}
   148  
   149  // Add inserts an item into the cache.
   150  func (c *cache) Add(obj interface{}) error {
   151  	key, err := c.keyFunc(obj)
   152  	if err != nil {
   153  		return KeyError{obj, err}
   154  	}
   155  	c.cacheStorage.Add(key, obj)
   156  	return nil
   157  }
   158  
   159  // Update sets an item in the cache to its updated state.
   160  func (c *cache) Update(obj interface{}) error {
   161  	key, err := c.keyFunc(obj)
   162  	if err != nil {
   163  		return KeyError{obj, err}
   164  	}
   165  	c.cacheStorage.Update(key, obj)
   166  	return nil
   167  }
   168  
   169  // Delete removes an item from the cache.
   170  func (c *cache) Delete(obj interface{}) error {
   171  	key, err := c.keyFunc(obj)
   172  	if err != nil {
   173  		return KeyError{obj, err}
   174  	}
   175  	c.cacheStorage.Delete(key)
   176  	return nil
   177  }
   178  
   179  // List returns a list of all the items.
   180  // List is completely threadsafe as long as you treat all items as immutable.
   181  func (c *cache) List() []interface{} {
   182  	return c.cacheStorage.List()
   183  }
   184  
   185  // ListKeys returns a list of all the keys of the objects currently
   186  // in the cache.
   187  func (c *cache) ListKeys() []string {
   188  	return c.cacheStorage.ListKeys()
   189  }
   190  
   191  // GetIndexers returns the indexers of cache
   192  func (c *cache) GetIndexers() Indexers {
   193  	return c.cacheStorage.GetIndexers()
   194  }
   195  
   196  // Index returns a list of items that match on the index function
   197  // Index is thread-safe so long as you treat all items as immutable
   198  func (c *cache) Index(indexName string, obj interface{}) ([]interface{}, error) {
   199  	return c.cacheStorage.Index(indexName, obj)
   200  }
   201  
   202  func (c *cache) IndexKeys(indexName, indexKey string) ([]string, error) {
   203  	return c.cacheStorage.IndexKeys(indexName, indexKey)
   204  }
   205  
   206  // ListIndexFuncValues returns the list of generated values of an Index func
   207  func (c *cache) ListIndexFuncValues(indexName string) []string {
   208  	return c.cacheStorage.ListIndexFuncValues(indexName)
   209  }
   210  
   211  func (c *cache) ByIndex(indexName, indexKey string) ([]interface{}, error) {
   212  	return c.cacheStorage.ByIndex(indexName, indexKey)
   213  }
   214  
   215  func (c *cache) AddIndexers(newIndexers Indexers) error {
   216  	return c.cacheStorage.AddIndexers(newIndexers)
   217  }
   218  
   219  // Get returns the requested item, or sets exists=false.
   220  // Get is completely threadsafe as long as you treat all items as immutable.
   221  func (c *cache) Get(obj interface{}) (item interface{}, exists bool, err error) {
   222  	key, err := c.keyFunc(obj)
   223  	if err != nil {
   224  		return nil, false, KeyError{obj, err}
   225  	}
   226  	return c.GetByKey(key)
   227  }
   228  
   229  // GetByKey returns the request item, or exists=false.
   230  // GetByKey is completely threadsafe as long as you treat all items as immutable.
   231  func (c *cache) GetByKey(key string) (item interface{}, exists bool, err error) {
   232  	item, exists = c.cacheStorage.Get(key)
   233  	return item, exists, nil
   234  }
   235  
   236  // Replace will delete the contents of 'c', using instead the given list.
   237  // 'c' takes ownership of the list, you should not reference the list again
   238  // after calling this function.
   239  func (c *cache) Replace(list []interface{}, resourceVersion string) error {
   240  	items := make(map[string]interface{}, len(list))
   241  	for _, item := range list {
   242  		key, err := c.keyFunc(item)
   243  		if err != nil {
   244  			return KeyError{item, err}
   245  		}
   246  		items[key] = item
   247  	}
   248  	c.cacheStorage.Replace(items, resourceVersion)
   249  	return nil
   250  }
   251  
   252  // Resync is meaningless for one of these
   253  func (c *cache) Resync() error {
   254  	return nil
   255  }
   256  
   257  // NewStore returns a Store implemented simply with a map and a lock.
   258  func NewStore(keyFunc KeyFunc) Store {
   259  	return &cache{
   260  		cacheStorage: NewThreadSafeStore(Indexers{}, Indices{}),
   261  		keyFunc:      keyFunc,
   262  	}
   263  }
   264  
   265  // NewIndexer returns an Indexer implemented simply with a map and a lock.
   266  func NewIndexer(keyFunc KeyFunc, indexers Indexers) Indexer {
   267  	return &cache{
   268  		cacheStorage: NewThreadSafeStore(indexers, Indices{}),
   269  		keyFunc:      keyFunc,
   270  	}
   271  }