mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-30 21:30:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			241 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Go
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			241 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Go
		
	
	
		
			Executable File
		
	
	
	
	
| /*
 | |
| Copyright 2014 The Kubernetes Authors.
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|     http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| package cache
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"strings"
 | |
| 
 | |
| 	"k8s.io/kubernetes/pkg/api/meta"
 | |
| )
 | |
| 
 | |
| // Store is a generic object storage interface. Reflector knows how to watch a server
 | |
| // and update a store. A generic store is provided, which allows Reflector to be used
 | |
| // as a local caching system, and an LRU store, which allows Reflector to work like a
 | |
| // queue of items yet to be processed.
 | |
| //
 | |
| // Store makes no assumptions about stored object identity; it is the responsibility
 | |
| // of a Store implementation to provide a mechanism to correctly key objects and to
 | |
| // define the contract for obtaining objects by some arbitrary key type.
 | |
| type Store interface {
 | |
| 	Add(obj interface{}) error
 | |
| 	Update(obj interface{}) error
 | |
| 	Delete(obj interface{}) error
 | |
| 	List() []interface{}
 | |
| 	ListKeys() []string
 | |
| 	Get(obj interface{}) (item interface{}, exists bool, err error)
 | |
| 	GetByKey(key string) (item interface{}, exists bool, err error)
 | |
| 
 | |
| 	// Replace will delete the contents of the store, using instead the
 | |
| 	// given list. Store takes ownership of the list, you should not reference
 | |
| 	// it after calling this function.
 | |
| 	Replace([]interface{}, string) error
 | |
| 	Resync() error
 | |
| }
 | |
| 
 | |
| // KeyFunc knows how to make a key from an object. Implementations should be deterministic.
 | |
| type KeyFunc func(obj interface{}) (string, error)
 | |
| 
 | |
| // KeyError will be returned any time a KeyFunc gives an error; it includes the object
 | |
| // at fault.
 | |
| type KeyError struct {
 | |
| 	Obj interface{}
 | |
| 	Err error
 | |
| }
 | |
| 
 | |
| // Error gives a human-readable description of the error.
 | |
| func (k KeyError) Error() string {
 | |
| 	return fmt.Sprintf("couldn't create key for object %+v: %v", k.Obj, k.Err)
 | |
| }
 | |
| 
 | |
| // ExplicitKey can be passed to MetaNamespaceKeyFunc if you have the key for
 | |
| // the object but not the object itself.
 | |
| type ExplicitKey string
 | |
| 
 | |
| // MetaNamespaceKeyFunc is a convenient default KeyFunc which knows how to make
 | |
| // keys for API objects which implement meta.Interface.
 | |
| // The key uses the format <namespace>/<name> unless <namespace> is empty, then
 | |
| // it's just <name>.
 | |
| //
 | |
| // TODO: replace key-as-string with a key-as-struct so that this
 | |
| // packing/unpacking won't be necessary.
 | |
| func MetaNamespaceKeyFunc(obj interface{}) (string, error) {
 | |
| 	if key, ok := obj.(ExplicitKey); ok {
 | |
| 		return string(key), nil
 | |
| 	}
 | |
| 	meta, err := meta.Accessor(obj)
 | |
| 	if err != nil {
 | |
| 		return "", fmt.Errorf("object has no meta: %v", err)
 | |
| 	}
 | |
| 	if len(meta.GetNamespace()) > 0 {
 | |
| 		return meta.GetNamespace() + "/" + meta.GetName(), nil
 | |
| 	}
 | |
| 	return meta.GetName(), nil
 | |
| }
 | |
| 
 | |
| // SplitMetaNamespaceKey returns the namespace and name that
 | |
| // MetaNamespaceKeyFunc encoded into key.
 | |
| //
 | |
| // TODO: replace key-as-string with a key-as-struct so that this
 | |
| // packing/unpacking won't be necessary.
 | |
| func SplitMetaNamespaceKey(key string) (namespace, name string, err error) {
 | |
| 	parts := strings.Split(key, "/")
 | |
| 	switch len(parts) {
 | |
| 	case 1:
 | |
| 		// name only, no namespace
 | |
| 		return "", parts[0], nil
 | |
| 	case 2:
 | |
| 		// namespace and name
 | |
| 		return parts[0], parts[1], nil
 | |
| 	}
 | |
| 
 | |
| 	return "", "", fmt.Errorf("unexpected key format: %q", key)
 | |
| }
 | |
| 
 | |
| // cache responsibilities are limited to:
 | |
| //	1. Computing keys for objects via keyFunc
 | |
| //  2. Invoking methods of a ThreadSafeStorage interface
 | |
| type cache struct {
 | |
| 	// cacheStorage bears the burden of thread safety for the cache
 | |
| 	cacheStorage ThreadSafeStore
 | |
| 	// keyFunc is used to make the key for objects stored in and retrieved from items, and
 | |
| 	// should be deterministic.
 | |
| 	keyFunc KeyFunc
 | |
| }
 | |
| 
 | |
| var _ Store = &cache{}
 | |
| 
 | |
| // Add inserts an item into the cache.
 | |
| func (c *cache) Add(obj interface{}) error {
 | |
| 	key, err := c.keyFunc(obj)
 | |
| 	if err != nil {
 | |
| 		return KeyError{obj, err}
 | |
| 	}
 | |
| 	c.cacheStorage.Add(key, obj)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Update sets an item in the cache to its updated state.
 | |
| func (c *cache) Update(obj interface{}) error {
 | |
| 	key, err := c.keyFunc(obj)
 | |
| 	if err != nil {
 | |
| 		return KeyError{obj, err}
 | |
| 	}
 | |
| 	c.cacheStorage.Update(key, obj)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Delete removes an item from the cache.
 | |
| func (c *cache) Delete(obj interface{}) error {
 | |
| 	key, err := c.keyFunc(obj)
 | |
| 	if err != nil {
 | |
| 		return KeyError{obj, err}
 | |
| 	}
 | |
| 	c.cacheStorage.Delete(key)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // List returns a list of all the items.
 | |
| // List is completely threadsafe as long as you treat all items as immutable.
 | |
| func (c *cache) List() []interface{} {
 | |
| 	return c.cacheStorage.List()
 | |
| }
 | |
| 
 | |
| // ListKeys returns a list of all the keys of the objects currently
 | |
| // in the cache.
 | |
| func (c *cache) ListKeys() []string {
 | |
| 	return c.cacheStorage.ListKeys()
 | |
| }
 | |
| 
 | |
| // GetIndexers returns the indexers of cache
 | |
| func (c *cache) GetIndexers() Indexers {
 | |
| 	return c.cacheStorage.GetIndexers()
 | |
| }
 | |
| 
 | |
| // Index returns a list of items that match on the index function
 | |
| // Index is thread-safe so long as you treat all items as immutable
 | |
| func (c *cache) Index(indexName string, obj interface{}) ([]interface{}, error) {
 | |
| 	return c.cacheStorage.Index(indexName, obj)
 | |
| }
 | |
| 
 | |
| // ListIndexFuncValues returns the list of generated values of an Index func
 | |
| func (c *cache) ListIndexFuncValues(indexName string) []string {
 | |
| 	return c.cacheStorage.ListIndexFuncValues(indexName)
 | |
| }
 | |
| 
 | |
| func (c *cache) ByIndex(indexName, indexKey string) ([]interface{}, error) {
 | |
| 	return c.cacheStorage.ByIndex(indexName, indexKey)
 | |
| }
 | |
| 
 | |
| func (c *cache) AddIndexers(newIndexers Indexers) error {
 | |
| 	return c.cacheStorage.AddIndexers(newIndexers)
 | |
| }
 | |
| 
 | |
| // Get returns the requested item, or sets exists=false.
 | |
| // Get is completely threadsafe as long as you treat all items as immutable.
 | |
| func (c *cache) Get(obj interface{}) (item interface{}, exists bool, err error) {
 | |
| 	key, err := c.keyFunc(obj)
 | |
| 	if err != nil {
 | |
| 		return nil, false, KeyError{obj, err}
 | |
| 	}
 | |
| 	return c.GetByKey(key)
 | |
| }
 | |
| 
 | |
| // GetByKey returns the request item, or exists=false.
 | |
| // GetByKey is completely threadsafe as long as you treat all items as immutable.
 | |
| func (c *cache) GetByKey(key string) (item interface{}, exists bool, err error) {
 | |
| 	item, exists = c.cacheStorage.Get(key)
 | |
| 	return item, exists, nil
 | |
| }
 | |
| 
 | |
| // Replace will delete the contents of 'c', using instead the given list.
 | |
| // 'c' takes ownership of the list, you should not reference the list again
 | |
| // after calling this function.
 | |
| func (c *cache) Replace(list []interface{}, resourceVersion string) error {
 | |
| 	items := map[string]interface{}{}
 | |
| 	for _, item := range list {
 | |
| 		key, err := c.keyFunc(item)
 | |
| 		if err != nil {
 | |
| 			return KeyError{item, err}
 | |
| 		}
 | |
| 		items[key] = item
 | |
| 	}
 | |
| 	c.cacheStorage.Replace(items, resourceVersion)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Resync touches all items in the store to force processing
 | |
| func (c *cache) Resync() error {
 | |
| 	return c.cacheStorage.Resync()
 | |
| }
 | |
| 
 | |
| // NewStore returns a Store implemented simply with a map and a lock.
 | |
| func NewStore(keyFunc KeyFunc) Store {
 | |
| 	return &cache{
 | |
| 		cacheStorage: NewThreadSafeStore(Indexers{}, Indices{}),
 | |
| 		keyFunc:      keyFunc,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // NewIndexer returns an Indexer implemented simply with a map and a lock.
 | |
| func NewIndexer(keyFunc KeyFunc, indexers Indexers) Indexer {
 | |
| 	return &cache{
 | |
| 		cacheStorage: NewThreadSafeStore(indexers, Indices{}),
 | |
| 		keyFunc:      keyFunc,
 | |
| 	}
 | |
| }
 |