diff --git a/Gopkg.lock b/Gopkg.lock index 43db98ab..719b0b71 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -966,7 +966,7 @@ [[projects]] branch = "master" - digest = "1:0dad40d47b86a73d04830e077504d31f508d6e13b802ca53521a5d5d0e4fa4ed" + digest = "1:518e5e7cb6aa149f3ea33bbfdfd367e4ab413d3405e33d85e09ac1f9b7a74c1f" name = "knative.dev/pkg" packages = [ "apis", @@ -986,7 +986,7 @@ "reconciler", ] pruneopts = "T" - revision = "9d7c06b6ab647bcb2e414e90d740b26915917cbf" + revision = "9320e44d1bf75c228b98b30cedcb98bb6e1424ee" [[projects]] branch = "master" @@ -997,7 +997,7 @@ "tools/dep-collector", ] pruneopts = "UT" - revision = "2f62d241ccc085436d060ad5f6764333a50ccf49" + revision = "000a646b850e6f86e3360e7d376edd9c545d31c1" [[projects]] digest = "1:8730e0150dfb2b7e173890c8b9868e7a273082ef8e39f4940e3506a481cf895c" diff --git a/vendor/knative.dev/pkg/apis/duck/cached.go b/vendor/knative.dev/pkg/apis/duck/cached.go index 6696bd0b..67aebc6d 100644 --- a/vendor/knative.dev/pkg/apis/duck/cached.go +++ b/vendor/knative.dev/pkg/apis/duck/cached.go @@ -29,7 +29,7 @@ type CachedInformerFactory struct { Delegate InformerFactory m sync.Mutex - cache map[schema.GroupVersionResource]*result + cache map[schema.GroupVersionResource]*informerCache } // Check that CachedInformerFactory implements InformerFactory. @@ -38,27 +38,41 @@ var _ InformerFactory = (*CachedInformerFactory)(nil) // Get implements InformerFactory. func (cif *CachedInformerFactory) Get(gvr schema.GroupVersionResource) (cache.SharedIndexInformer, cache.GenericLister, error) { cif.m.Lock() + if cif.cache == nil { - cif.cache = make(map[schema.GroupVersionResource]*result) + cif.cache = make(map[schema.GroupVersionResource]*informerCache) } - elt, ok := cif.cache[gvr] + + ic, ok := cif.cache[gvr] if !ok { - elt = &result{} - elt.init = func() { - elt.inf, elt.lister, elt.err = cif.Delegate.Get(gvr) + ic = &informerCache{} + ic.init = func() { + ic.Lock() + defer ic.Unlock() + + // double-checked lock to ensure we call the Delegate + // only once even if multiple goroutines end up inside + // init() simultaneously + if ic.hasInformer() { + return + } + + ic.inf, ic.lister, ic.err = cif.Delegate.Get(gvr) } - cif.cache[gvr] = elt + cif.cache[gvr] = ic } + // If this were done via "defer", then TestDifferentGVRs will fail. cif.m.Unlock() // The call to the delegate could be slow because it syncs informers, so do // this outside of the main lock. - return elt.Get() + return ic.Get() } -type result struct { - sync.Once +type informerCache struct { + sync.RWMutex + init func() inf cache.SharedIndexInformer @@ -66,7 +80,21 @@ type result struct { err error } -func (t *result) Get() (cache.SharedIndexInformer, cache.GenericLister, error) { - t.Do(t.init) - return t.inf, t.lister, t.err +// Get returns the cached informer. If it does not yet exist, we first try to +// acquire one by executing the cache's init function. +func (ic *informerCache) Get() (cache.SharedIndexInformer, cache.GenericLister, error) { + if !ic.initialized() { + ic.init() + } + return ic.inf, ic.lister, ic.err +} + +func (ic *informerCache) initialized() bool { + ic.RLock() + defer ic.RUnlock() + return ic.hasInformer() +} + +func (ic *informerCache) hasInformer() bool { + return ic.inf != nil && ic.lister != nil }