blob: 4958987f0e73e34a2aab6ee231e3ca31a1408c74 [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001/*
2Copyright 2014 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package cache
18
19import (
20 "fmt"
21 "strings"
22
23 "k8s.io/apimachinery/pkg/api/meta"
24)
25
26// Store is a generic object storage interface. Reflector knows how to watch a server
27// and update a store. A generic store is provided, which allows Reflector to be used
28// as a local caching system, and an LRU store, which allows Reflector to work like a
29// queue of items yet to be processed.
30//
31// Store makes no assumptions about stored object identity; it is the responsibility
32// of a Store implementation to provide a mechanism to correctly key objects and to
33// define the contract for obtaining objects by some arbitrary key type.
34type Store interface {
35 Add(obj interface{}) error
36 Update(obj interface{}) error
37 Delete(obj interface{}) error
38 List() []interface{}
39 ListKeys() []string
40 Get(obj interface{}) (item interface{}, exists bool, err error)
41 GetByKey(key string) (item interface{}, exists bool, err error)
42
43 // Replace will delete the contents of the store, using instead the
44 // given list. Store takes ownership of the list, you should not reference
45 // it after calling this function.
46 Replace([]interface{}, string) error
47 Resync() error
48}
49
50// KeyFunc knows how to make a key from an object. Implementations should be deterministic.
51type KeyFunc func(obj interface{}) (string, error)
52
53// KeyError will be returned any time a KeyFunc gives an error; it includes the object
54// at fault.
55type KeyError struct {
56 Obj interface{}
57 Err error
58}
59
60// Error gives a human-readable description of the error.
61func (k KeyError) Error() string {
62 return fmt.Sprintf("couldn't create key for object %+v: %v", k.Obj, k.Err)
63}
64
65// ExplicitKey can be passed to MetaNamespaceKeyFunc if you have the key for
66// the object but not the object itself.
67type ExplicitKey string
68
69// MetaNamespaceKeyFunc is a convenient default KeyFunc which knows how to make
70// keys for API objects which implement meta.Interface.
71// The key uses the format <namespace>/<name> unless <namespace> is empty, then
72// it's just <name>.
73//
74// TODO: replace key-as-string with a key-as-struct so that this
75// packing/unpacking won't be necessary.
76func MetaNamespaceKeyFunc(obj interface{}) (string, error) {
77 if key, ok := obj.(ExplicitKey); ok {
78 return string(key), nil
79 }
80 meta, err := meta.Accessor(obj)
81 if err != nil {
82 return "", fmt.Errorf("object has no meta: %v", err)
83 }
84 if len(meta.GetNamespace()) > 0 {
85 return meta.GetNamespace() + "/" + meta.GetName(), nil
86 }
87 return meta.GetName(), nil
88}
89
90// SplitMetaNamespaceKey returns the namespace and name that
91// MetaNamespaceKeyFunc encoded into key.
92//
93// TODO: replace key-as-string with a key-as-struct so that this
94// packing/unpacking won't be necessary.
95func SplitMetaNamespaceKey(key string) (namespace, name string, err error) {
96 parts := strings.Split(key, "/")
97 switch len(parts) {
98 case 1:
99 // name only, no namespace
100 return "", parts[0], nil
101 case 2:
102 // namespace and name
103 return parts[0], parts[1], nil
104 }
105
106 return "", "", fmt.Errorf("unexpected key format: %q", key)
107}
108
109// cache responsibilities are limited to:
110// 1. Computing keys for objects via keyFunc
111// 2. Invoking methods of a ThreadSafeStorage interface
112type cache struct {
113 // cacheStorage bears the burden of thread safety for the cache
114 cacheStorage ThreadSafeStore
115 // keyFunc is used to make the key for objects stored in and retrieved from items, and
116 // should be deterministic.
117 keyFunc KeyFunc
118}
119
120var _ Store = &cache{}
121
122// Add inserts an item into the cache.
123func (c *cache) Add(obj interface{}) error {
124 key, err := c.keyFunc(obj)
125 if err != nil {
126 return KeyError{obj, err}
127 }
128 c.cacheStorage.Add(key, obj)
129 return nil
130}
131
132// Update sets an item in the cache to its updated state.
133func (c *cache) Update(obj interface{}) error {
134 key, err := c.keyFunc(obj)
135 if err != nil {
136 return KeyError{obj, err}
137 }
138 c.cacheStorage.Update(key, obj)
139 return nil
140}
141
142// Delete removes an item from the cache.
143func (c *cache) Delete(obj interface{}) error {
144 key, err := c.keyFunc(obj)
145 if err != nil {
146 return KeyError{obj, err}
147 }
148 c.cacheStorage.Delete(key)
149 return nil
150}
151
152// List returns a list of all the items.
153// List is completely threadsafe as long as you treat all items as immutable.
154func (c *cache) List() []interface{} {
155 return c.cacheStorage.List()
156}
157
158// ListKeys returns a list of all the keys of the objects currently
159// in the cache.
160func (c *cache) ListKeys() []string {
161 return c.cacheStorage.ListKeys()
162}
163
164// GetIndexers returns the indexers of cache
165func (c *cache) GetIndexers() Indexers {
166 return c.cacheStorage.GetIndexers()
167}
168
169// Index returns a list of items that match on the index function
170// Index is thread-safe so long as you treat all items as immutable
171func (c *cache) Index(indexName string, obj interface{}) ([]interface{}, error) {
172 return c.cacheStorage.Index(indexName, obj)
173}
174
175func (c *cache) IndexKeys(indexName, indexKey string) ([]string, error) {
176 return c.cacheStorage.IndexKeys(indexName, indexKey)
177}
178
179// ListIndexFuncValues returns the list of generated values of an Index func
180func (c *cache) ListIndexFuncValues(indexName string) []string {
181 return c.cacheStorage.ListIndexFuncValues(indexName)
182}
183
184func (c *cache) ByIndex(indexName, indexKey string) ([]interface{}, error) {
185 return c.cacheStorage.ByIndex(indexName, indexKey)
186}
187
188func (c *cache) AddIndexers(newIndexers Indexers) error {
189 return c.cacheStorage.AddIndexers(newIndexers)
190}
191
192// Get returns the requested item, or sets exists=false.
193// Get is completely threadsafe as long as you treat all items as immutable.
194func (c *cache) Get(obj interface{}) (item interface{}, exists bool, err error) {
195 key, err := c.keyFunc(obj)
196 if err != nil {
197 return nil, false, KeyError{obj, err}
198 }
199 return c.GetByKey(key)
200}
201
202// GetByKey returns the request item, or exists=false.
203// GetByKey is completely threadsafe as long as you treat all items as immutable.
204func (c *cache) GetByKey(key string) (item interface{}, exists bool, err error) {
205 item, exists = c.cacheStorage.Get(key)
206 return item, exists, nil
207}
208
209// Replace will delete the contents of 'c', using instead the given list.
210// 'c' takes ownership of the list, you should not reference the list again
211// after calling this function.
212func (c *cache) Replace(list []interface{}, resourceVersion string) error {
213 items := map[string]interface{}{}
214 for _, item := range list {
215 key, err := c.keyFunc(item)
216 if err != nil {
217 return KeyError{item, err}
218 }
219 items[key] = item
220 }
221 c.cacheStorage.Replace(items, resourceVersion)
222 return nil
223}
224
225// Resync touches all items in the store to force processing
226func (c *cache) Resync() error {
227 return c.cacheStorage.Resync()
228}
229
230// NewStore returns a Store implemented simply with a map and a lock.
231func NewStore(keyFunc KeyFunc) Store {
232 return &cache{
233 cacheStorage: NewThreadSafeStore(Indexers{}, Indices{}),
234 keyFunc: keyFunc,
235 }
236}
237
238// NewIndexer returns an Indexer implemented simply with a map and a lock.
239func NewIndexer(keyFunc KeyFunc, indexers Indexers) Indexer {
240 return &cache{
241 cacheStorage: NewThreadSafeStore(indexers, Indices{}),
242 keyFunc: keyFunc,
243 }
244}