Skip to content

Commit 201ab80

Browse files
create a cluser scoped cache separately
Signed-off-by: varshaprasad96 <[email protected]>
1 parent 50bfd90 commit 201ab80

File tree

2 files changed

+73
-14
lines changed

2 files changed

+73
-14
lines changed

pkg/cache/multi_namespace_cache.go

Lines changed: 66 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const globalCache = "_cluster-scope"
4141
// MultiNamespacedCacheBuilder - Builder function to create a new multi-namespaced cache.
4242
// This will scope the cache to a list of namespaces. Listing for all namespaces
4343
// will list for all the namespaces that this knows about. By default this will create
44-
// a global cache for cluster scoped resource (having empty namespace). Note that this is not intended
44+
// a global cache for cluster scoped resource. Note that this is not intended
4545
// to be used for excluding namespaces, this is better done via a Predicate. Also note that
4646
// you may face performance issues when using this with a high number of namespaces.
4747
func MultiNamespacedCacheBuilder(namespaces []string) NewCacheFunc {
@@ -59,9 +59,6 @@ func MultiNamespacedCacheBuilder(namespaces []string) NewCacheFunc {
5959
return nil, fmt.Errorf("error creating global cache %v", err)
6060
}
6161

62-
// add global cache to the cacheMap
63-
caches[globalCache] = gCache
64-
6562
for _, ns := range namespaces {
6663
opts.Namespace = ns
6764
c, err := New(config, opts)
@@ -70,7 +67,7 @@ func MultiNamespacedCacheBuilder(namespaces []string) NewCacheFunc {
7067
}
7168
caches[ns] = c
7269
}
73-
return &multiNamespaceCache{namespaceToCache: caches, Scheme: opts.Scheme, RESTMapper: opts.Mapper}, nil
70+
return &multiNamespaceCache{namespaceToCache: caches, Scheme: opts.Scheme, RESTMapper: opts.Mapper, clusterCache: gCache}, nil
7471
}
7572
}
7673

@@ -82,36 +79,82 @@ type multiNamespaceCache struct {
8279
namespaceToCache map[string]Cache
8380
Scheme *runtime.Scheme
8481
RESTMapper meta.RESTMapper
82+
clusterCache Cache
8583
}
8684

8785
var _ Cache = &multiNamespaceCache{}
8886

8987
// Methods for multiNamespaceCache to conform to the Informers interface
9088
func (c *multiNamespaceCache) GetInformer(ctx context.Context, obj client.Object) (Informer, error) {
9189
informers := map[string]Informer{}
90+
91+
// If the object is clusterscoped, get the informer from clusterCache,
92+
// if not use the namespaced caches.
93+
isNamespaced, err := objectutil.IsAPINamespaced(obj, c.Scheme, c.RESTMapper)
94+
if err != nil {
95+
return nil, err
96+
}
97+
if !isNamespaced {
98+
clusterCacheInf, err := c.clusterCache.GetInformer(ctx, obj)
99+
if err != nil {
100+
return nil, err
101+
}
102+
informers[globalCache] = clusterCacheInf
103+
104+
return &multiNamespaceInformer{namespaceToInformer: informers}, nil
105+
}
106+
92107
for ns, cache := range c.namespaceToCache {
93108
informer, err := cache.GetInformer(ctx, obj)
94109
if err != nil {
95110
return nil, err
96111
}
97112
informers[ns] = informer
98113
}
114+
99115
return &multiNamespaceInformer{namespaceToInformer: informers}, nil
100116
}
101117

102118
func (c *multiNamespaceCache) GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind) (Informer, error) {
103119
informers := map[string]Informer{}
120+
121+
// If the object is clusterscoped, get the informer from clusterCache,
122+
// if not use the namespaced caches.
123+
isNamespaced, err := objectutil.IsAPINamespacedWithGVK(gvk, c.Scheme, c.RESTMapper)
124+
if err != nil {
125+
return nil, err
126+
}
127+
if !isNamespaced {
128+
clusterCacheInf, err := c.clusterCache.GetInformerForKind(ctx, gvk)
129+
if err != nil {
130+
return nil, err
131+
}
132+
informers[globalCache] = clusterCacheInf
133+
134+
return &multiNamespaceInformer{namespaceToInformer: informers}, nil
135+
}
136+
104137
for ns, cache := range c.namespaceToCache {
105138
informer, err := cache.GetInformerForKind(ctx, gvk)
106139
if err != nil {
107140
return nil, err
108141
}
109142
informers[ns] = informer
110143
}
144+
111145
return &multiNamespaceInformer{namespaceToInformer: informers}, nil
112146
}
113147

114148
func (c *multiNamespaceCache) Start(ctx context.Context) error {
149+
// start global cache
150+
go func() {
151+
err := c.clusterCache.Start(ctx)
152+
if err != nil {
153+
log.Error(err, "cluster scoped cache failed to start")
154+
}
155+
}()
156+
157+
// start namespaced caches
115158
for ns, cache := range c.namespaceToCache {
116159
go func(ns string, cache Cache) {
117160
err := cache.Start(ctx)
@@ -120,6 +163,7 @@ func (c *multiNamespaceCache) Start(ctx context.Context) error {
120163
}
121164
}(ns, cache)
122165
}
166+
123167
<-ctx.Done()
124168
return nil
125169
}
@@ -131,10 +175,24 @@ func (c *multiNamespaceCache) WaitForCacheSync(ctx context.Context) bool {
131175
synced = s
132176
}
133177
}
178+
179+
// check if cluster scoped cache has synced
180+
if !c.clusterCache.WaitForCacheSync(ctx) {
181+
synced = false
182+
}
134183
return synced
135184
}
136185

137186
func (c *multiNamespaceCache) IndexField(ctx context.Context, obj client.Object, field string, extractValue client.IndexerFunc) error {
187+
isNamespaced, err := objectutil.IsAPINamespaced(obj, c.Scheme, c.RESTMapper)
188+
if err != nil {
189+
return nil
190+
}
191+
192+
if !isNamespaced {
193+
return c.clusterCache.IndexField(ctx, obj, field, extractValue)
194+
}
195+
138196
for _, cache := range c.namespaceToCache {
139197
if err := cache.IndexField(ctx, obj, field, extractValue); err != nil {
140198
return err
@@ -151,8 +209,7 @@ func (c *multiNamespaceCache) Get(ctx context.Context, key client.ObjectKey, obj
151209

152210
if !isNamespaced {
153211
// Look into the global cache to fetch the object
154-
cache := c.namespaceToCache[globalCache]
155-
return cache.Get(ctx, key, obj)
212+
return c.clusterCache.Get(ctx, key, obj)
156213
}
157214

158215
cache, ok := c.namespaceToCache[key.Namespace]
@@ -174,8 +231,7 @@ func (c *multiNamespaceCache) List(ctx context.Context, list client.ObjectList,
174231

175232
if !isNamespaced {
176233
// Look at the global cache to get the objects with the specified GVK
177-
cache := c.namespaceToCache[globalCache]
178-
return cache.List(ctx, list, opts...)
234+
return c.clusterCache.List(ctx, list, opts...)
179235
}
180236

181237
if listOpts.Namespace != corev1.NamespaceAll {
@@ -199,10 +255,7 @@ func (c *multiNamespaceCache) List(ctx context.Context, list client.ObjectList,
199255
limitSet := listOpts.Limit > 0
200256

201257
var resourceVersion string
202-
for ns, cache := range c.namespaceToCache {
203-
if ns == globalCache {
204-
continue
205-
}
258+
for _, cache := range c.namespaceToCache {
206259
listObj := list.DeepCopyObject().(client.ObjectList)
207260
err = cache.List(ctx, listObj, &listOpts)
208261
if err != nil {

pkg/internal/objectutil/objectutil.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,13 @@ func IsAPINamespaced(obj runtime.Object, scheme *runtime.Scheme, restmapper apim
5555
return false, err
5656
}
5757

58-
restmapping, err := restmapper.RESTMapping(schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind})
58+
return IsAPINamespacedWithGVK(gvk, scheme, restmapper)
59+
}
60+
61+
// IsAPINamespacedWithGVK returns true if the object having the provided
62+
// GVK is namespace scoped.
63+
func IsAPINamespacedWithGVK(gk schema.GroupVersionKind, scheme *runtime.Scheme, restmapper apimeta.RESTMapper) (bool, error) {
64+
restmapping, err := restmapper.RESTMapping(schema.GroupKind{Group: gk.Group, Kind: gk.Kind})
5965
if err != nil {
6066
return false, fmt.Errorf("failed to get restmapping: %w", err)
6167
}

0 commit comments

Comments
 (0)