2727package cache
2828
2929import (
30+ "fmt"
3031 "hash/fnv"
3132 "sort"
3233 "strconv"
@@ -65,6 +66,8 @@ const (
6566 namespaceCacheInitialSize = 10 * 1024
6667 namespaceCacheMaxSize = 64 * 1024
6768 namespaceCacheTTL = 0 // 0 means infinity
69+ // NamespaceCacheMinRefreshInterval is a minimun namespace cache refresh interval.
70+ NamespaceCacheMinRefreshInterval = 2 * time .Second
6871 // NamespaceCacheRefreshInterval namespace cache refresh interval
6972 NamespaceCacheRefreshInterval = 10 * time .Second
7073 // NamespaceCacheRefreshFailureRetryInterval is the wait time
@@ -116,7 +119,10 @@ type (
116119
117120 // refresh lock is used to guarantee at most one
118121 // coroutine is doing namespace refreshment
119- refreshLock sync.Mutex
122+ refreshLock sync.Mutex
123+ lastRefreshTime atomic.Value
124+ checkLock sync.Mutex
125+ lastCheckTime time.Time
120126
121127 callbackLock sync.Mutex
122128 prepareCallbacks map [int32 ]PrepareCallbackFn
@@ -165,6 +171,7 @@ func NewNamespaceCache(
165171 }
166172 cache .cacheNameToID .Store (newNamespaceCache ())
167173 cache .cacheByID .Store (newNamespaceCache ())
174+ cache .lastRefreshTime .Store (time.Time {})
168175
169176 return cache
170177}
@@ -316,8 +323,8 @@ func (c *namespaceCache) RegisterNamespaceChangeCallback(
316323 // with namespace change version.
317324 sort .Sort (namespaces )
318325
319- prevEntries := []* NamespaceCacheEntry {}
320- nextEntries := []* NamespaceCacheEntry {}
326+ var prevEntries []* NamespaceCacheEntry
327+ var nextEntries []* NamespaceCacheEntry
321328 for _ , namespace := range namespaces {
322329 if namespace .notificationVersion >= initialNotificationVersion {
323330 prevEntries = append (prevEntries , nil )
@@ -420,6 +427,8 @@ func (c *namespaceCache) refreshNamespaces() error {
420427// this function only refresh the namespaces in the v2 table
421428// the namespaces in the v1 table will be refreshed if cache is stale
422429func (c * namespaceCache ) refreshNamespacesLocked () error {
430+ now := c .timeSource .Now ()
431+
423432 // first load the metadata record, then load namespaces
424433 // this can guarantee that namespaces in the cache are not updated more than metadata record
425434 metadata , err := c .metadataMgr .GetMetadata ()
@@ -451,8 +460,8 @@ func (c *namespaceCache) refreshNamespacesLocked() error {
451460 // with namespace change version.
452461 sort .Sort (namespaces )
453462
454- prevEntries := []* NamespaceCacheEntry {}
455- nextEntries := []* NamespaceCacheEntry {}
463+ var prevEntries []* NamespaceCacheEntry
464+ var nextEntries []* NamespaceCacheEntry
456465
457466 // make a copy of the existing namespace cache, so we can calculate diff and do compare and swap
458467 newCacheNameToID := newNamespaceCache ()
@@ -492,16 +501,35 @@ UpdateLoop:
492501 c .cacheByID .Store (newCacheByID )
493502 c .cacheNameToID .Store (newCacheNameToID )
494503 c .triggerNamespaceChangeCallbackLocked (prevEntries , nextEntries )
504+
505+ // only update last refresh time when refresh succeeded
506+ c .lastRefreshTime .Store (now )
495507 return nil
496508}
497509
498- func (c * namespaceCache ) checkNamespaceExists (
510+ func (c * namespaceCache ) checkAndContinue (
499511 name string ,
500512 id string ,
501- ) error {
513+ ) (bool , error ) {
514+ now := c .timeSource .Now ()
515+ if now .Sub (c .lastRefreshTime .Load ().(time.Time )) < NamespaceCacheMinRefreshInterval {
516+ return false , nil
517+ }
518+
519+ c .checkLock .Lock ()
520+ defer c .checkLock .Unlock ()
502521
522+ now = c .timeSource .Now ()
523+ if now .Sub (c .lastCheckTime ) < NamespaceCacheMinRefreshInterval {
524+ return true , nil
525+ }
526+
527+ c .lastCheckTime = now
503528 _ , err := c .metadataMgr .GetNamespace (& persistence.GetNamespaceRequest {Name : name , ID : id })
504- return err
529+ if err != nil {
530+ return false , err
531+ }
532+ return true , nil
505533}
506534
507535func (c * namespaceCache ) updateNameToIDCache (
@@ -563,9 +591,13 @@ func (c *namespaceCache) getNamespace(
563591 return c .getNamespaceByID (id , true )
564592 }
565593
566- if err := c .checkNamespaceExists (name , "" ); err != nil {
594+ doContinue , err := c .checkAndContinue (name , "" )
595+ if err != nil {
567596 return nil , err
568597 }
598+ if ! doContinue {
599+ return nil , serviceerror .NewNotFound (fmt .Sprintf ("namespace: %v not found" , name ))
600+ }
569601
570602 c .refreshLock .Lock ()
571603 defer c .refreshLock .Unlock ()
@@ -581,7 +613,7 @@ func (c *namespaceCache) getNamespace(
581613 return c .getNamespaceByID (id , true )
582614 }
583615 // impossible case
584- return nil , serviceerror .NewInternal ( "namespaceCache encounter case where namespace exists but cannot be loaded" )
616+ return nil , serviceerror .NewNotFound ( fmt . Sprintf ( " namespace: %v not found" , name ) )
585617}
586618
587619// getNamespaceByID retrieves the information from the cache if it exists, otherwise retrieves the information from metadata
@@ -603,9 +635,13 @@ func (c *namespaceCache) getNamespaceByID(
603635 return result , nil
604636 }
605637
606- if err := c .checkNamespaceExists ("" , id ); err != nil {
638+ doContinue , err := c .checkAndContinue ("" , id )
639+ if err != nil {
607640 return nil , err
608641 }
642+ if ! doContinue {
643+ return nil , serviceerror .NewNotFound (fmt .Sprintf ("namespace ID: %v not found" , id ))
644+ }
609645
610646 c .refreshLock .Lock ()
611647 defer c .refreshLock .Unlock ()
@@ -632,8 +668,7 @@ func (c *namespaceCache) getNamespaceByID(
632668 entry .RUnlock ()
633669 return result , nil
634670 }
635- // impossible case
636- return nil , serviceerror .NewInternal ("namespaceCache encounter case where namespace exists but cannot be loaded" )
671+ return nil , serviceerror .NewNotFound (fmt .Sprintf ("namespace ID: %v not found" , id ))
637672}
638673
639674func (c * namespaceCache ) triggerNamespaceChangePrepareCallbackLocked () {
0 commit comments