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 }