mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			224 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			224 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2014 The Kubernetes Authors All rights reserved.
 | 
						|
 | 
						|
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
 | 
						|
}
 | 
						|
 | 
						|
// 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.Namespace()) > 0 {
 | 
						|
		return meta.Namespace() + "/" + meta.Name(), nil
 | 
						|
	}
 | 
						|
	return meta.Name(), 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:
 | 
						|
		// name and namespace
 | 
						|
		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
 | 
						|
}
 | 
						|
 | 
						|
// 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()
 | 
						|
}
 | 
						|
 | 
						|
// 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)
 | 
						|
}
 | 
						|
 | 
						|
// 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
 | 
						|
}
 | 
						|
 | 
						|
// 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,
 | 
						|
	}
 | 
						|
}
 |