Store labels and fields with object

This commit is contained in:
Wojciech Tyczynski 2018-02-14 15:39:51 +01:00
parent 69324f90e6
commit 87a65b6c93
2 changed files with 38 additions and 55 deletions

View File

@ -130,7 +130,7 @@ func (i *indexedWatchers) terminateAll(objectType reflect.Type) {
} }
} }
type watchFilterFunc func(key string, l labels.Set, f fields.Set, uninitialized bool) bool type filterWithAttrsFunc func(key string, l labels.Set, f fields.Set, uninitialized bool) bool
// Cacher is responsible for serving WATCH and LIST requests for a given // Cacher is responsible for serving WATCH and LIST requests for a given
// resource from its internal cache and updating its cache in the background // resource from its internal cache and updating its cache in the background
@ -337,7 +337,7 @@ func (c *Cacher) Watch(ctx context.Context, key string, resourceVersion string,
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
forget := forgetWatcher(c, c.watcherIdx, triggerValue, triggerSupported) forget := forgetWatcher(c, c.watcherIdx, triggerValue, triggerSupported)
watcher := newCacheWatcher(watchRV, chanSize, initEvents, watchFilterFunction(key, pred), forget, c.versioner) watcher := newCacheWatcher(watchRV, chanSize, initEvents, filterWithAttrsFunction(key, pred), forget, c.versioner)
c.watchers.addWatcher(watcher, c.watcherIdx, triggerValue, triggerSupported) c.watchers.addWatcher(watcher, c.watcherIdx, triggerValue, triggerSupported)
c.watcherIdx++ c.watcherIdx++
@ -439,7 +439,7 @@ func (c *Cacher) GetToList(ctx context.Context, key string, resourceVersion stri
if err != nil || listVal.Kind() != reflect.Slice { if err != nil || listVal.Kind() != reflect.Slice {
return fmt.Errorf("need a pointer to slice, got %v", listVal.Kind()) return fmt.Errorf("need a pointer to slice, got %v", listVal.Kind())
} }
filter := filterFunction(key, pred) filter := filterWithAttrsFunction(key, pred)
obj, exists, readResourceVersion, err := c.watchCache.WaitUntilFreshAndGet(listRV, key, trace) obj, exists, readResourceVersion, err := c.watchCache.WaitUntilFreshAndGet(listRV, key, trace)
if err != nil { if err != nil {
@ -452,7 +452,7 @@ func (c *Cacher) GetToList(ctx context.Context, key string, resourceVersion stri
if !ok { if !ok {
return fmt.Errorf("non *storeElement returned from storage: %v", obj) return fmt.Errorf("non *storeElement returned from storage: %v", obj)
} }
if filter(elem.Key, elem.Object) { if filter(elem.Key, elem.Labels, elem.Fields, elem.Uninitialized) {
listVal.Set(reflect.Append(listVal, reflect.ValueOf(elem.Object).Elem())) listVal.Set(reflect.Append(listVal, reflect.ValueOf(elem.Object).Elem()))
} }
} }
@ -508,7 +508,7 @@ func (c *Cacher) List(ctx context.Context, key string, resourceVersion string, p
if err != nil || listVal.Kind() != reflect.Slice { if err != nil || listVal.Kind() != reflect.Slice {
return fmt.Errorf("need a pointer to slice, got %v", listVal.Kind()) return fmt.Errorf("need a pointer to slice, got %v", listVal.Kind())
} }
filter := filterFunction(key, pred) filter := filterWithAttrsFunction(key, pred)
objs, readResourceVersion, err := c.watchCache.WaitUntilFreshAndList(listRV, trace) objs, readResourceVersion, err := c.watchCache.WaitUntilFreshAndList(listRV, trace)
if err != nil { if err != nil {
@ -526,7 +526,7 @@ func (c *Cacher) List(ctx context.Context, key string, resourceVersion string, p
if !ok { if !ok {
return fmt.Errorf("non *storeElement returned from storage: %v", obj) return fmt.Errorf("non *storeElement returned from storage: %v", obj)
} }
if filter(elem.Key, elem.Object) { if filter(elem.Key, elem.Labels, elem.Fields, elem.Uninitialized) {
listVal.Set(reflect.Append(listVal, reflect.ValueOf(elem.Object).Elem())) listVal.Set(reflect.Append(listVal, reflect.ValueOf(elem.Object).Elem()))
} }
} }
@ -680,22 +680,7 @@ func forgetWatcher(c *Cacher, index int, triggerValue string, triggerSupported b
} }
} }
func filterFunction(key string, p SelectionPredicate) func(string, runtime.Object) bool { func filterWithAttrsFunction(key string, p SelectionPredicate) filterWithAttrsFunc {
filterFunc := func(objKey string, obj runtime.Object) bool {
if !hasPathPrefix(objKey, key) {
return false
}
matches, err := p.Matches(obj)
if err != nil {
glog.Errorf("invalid object for matching. Obj: %v. Err: %v", obj, err)
return false
}
return matches
}
return filterFunc
}
func watchFilterFunction(key string, p SelectionPredicate) watchFilterFunc {
filterFunc := func(objKey string, label labels.Set, field fields.Set, uninitialized bool) bool { filterFunc := func(objKey string, label labels.Set, field fields.Set, uninitialized bool) bool {
if !hasPathPrefix(objKey, key) { if !hasPathPrefix(objKey, key) {
return false return false
@ -788,13 +773,13 @@ type cacheWatcher struct {
input chan *watchCacheEvent input chan *watchCacheEvent
result chan watch.Event result chan watch.Event
done chan struct{} done chan struct{}
filter watchFilterFunc filter filterWithAttrsFunc
stopped bool stopped bool
forget func(bool) forget func(bool)
versioner Versioner versioner Versioner
} }
func newCacheWatcher(resourceVersion uint64, chanSize int, initEvents []*watchCacheEvent, filter watchFilterFunc, forget func(bool), versioner Versioner) *cacheWatcher { func newCacheWatcher(resourceVersion uint64, chanSize int, initEvents []*watchCacheEvent, filter filterWithAttrsFunc, forget func(bool), versioner Versioner) *cacheWatcher {
watcher := &cacheWatcher{ watcher := &cacheWatcher{
input: make(chan *watchCacheEvent, chanSize), input: make(chan *watchCacheEvent, chanSize),
result: make(chan watch.Event, chanSize), result: make(chan watch.Event, chanSize),

View File

@ -61,12 +61,16 @@ type watchCacheEvent struct {
} }
// Computing a key of an object is generally non-trivial (it performs // Computing a key of an object is generally non-trivial (it performs
// e.g. validation underneath). To avoid computing it multiple times // e.g. validation underneath). Similarly computing object fields and
// (to serve the event in different List/Watch requests), in the // labels. To avoid computing them multiple times (to serve the event
// underlying store we are keeping pair (key, object). // in different List/Watch requests), in the underlying store we are
// keeping structs (key, object, labels, fields, uninitialized).
type storeElement struct { type storeElement struct {
Key string Key string
Object runtime.Object Object runtime.Object
Labels labels.Set
Fields fields.Set
Uninitialized bool
} }
func storeElementKey(obj interface{}) (string, error) { func storeElementKey(obj interface{}) (string, error) {
@ -220,6 +224,20 @@ func (w *watchCache) processEvent(event watch.Event, resourceVersion uint64, upd
return fmt.Errorf("couldn't compute key: %v", err) return fmt.Errorf("couldn't compute key: %v", err)
} }
elem := &storeElement{Key: key, Object: event.Object} elem := &storeElement{Key: key, Object: event.Object}
elem.Labels, elem.Fields, elem.Uninitialized, err = w.getAttrsFunc(event.Object)
if err != nil {
return err
}
watchCacheEvent := &watchCacheEvent{
Type: event.Type,
Object: elem.Object,
ObjLabels: elem.Labels,
ObjFields: elem.Fields,
ObjUninitialized: elem.Uninitialized,
Key: key,
ResourceVersion: resourceVersion,
}
// TODO: We should consider moving this lock below after the watchCacheEvent // TODO: We should consider moving this lock below after the watchCacheEvent
// is created. In such situation, the only problematic scenario is Replace( // is created. In such situation, the only problematic scenario is Replace(
@ -231,34 +249,14 @@ func (w *watchCache) processEvent(event watch.Event, resourceVersion uint64, upd
if err != nil { if err != nil {
return err return err
} }
objLabels, objFields, objUninitialized, err := w.getAttrsFunc(event.Object)
if err != nil {
return err
}
var prevObject runtime.Object
var prevObjLabels labels.Set
var prevObjFields fields.Set
var prevObjUninitialized bool
if exists { if exists {
prevObject = previous.(*storeElement).Object previousElem := previous.(*storeElement)
prevObjLabels, prevObjFields, prevObjUninitialized, err = w.getAttrsFunc(prevObject) watchCacheEvent.PrevObject = previousElem.Object
if err != nil { watchCacheEvent.PrevObjLabels = previousElem.Labels
return err watchCacheEvent.PrevObjFields = previousElem.Fields
} watchCacheEvent.PrevObjUninitialized = previousElem.Uninitialized
}
watchCacheEvent := &watchCacheEvent{
Type: event.Type,
Object: event.Object,
ObjLabels: objLabels,
ObjFields: objFields,
ObjUninitialized: objUninitialized,
PrevObject: prevObject,
PrevObjLabels: prevObjLabels,
PrevObjFields: prevObjFields,
PrevObjUninitialized: prevObjUninitialized,
Key: key,
ResourceVersion: resourceVersion,
} }
if w.onEvent != nil { if w.onEvent != nil {
w.onEvent(watchCacheEvent) w.onEvent(watchCacheEvent)
} }