func (r *registry) getNamespace(name string) (*Namespace, error) {
	r.cacheLock.RLock()
	defer r.cacheLock.RUnlock()
	if id, ok := r.cacheNameToID.Get(name).(string); ok {
		return r.getNamespaceByIDLocked(id)
	}
	return nil, serviceerror.NewNotFound(
		fmt.Sprintf("Namespace name %q not found", name))
}
getNamespace retrieves the information from the cache if it exists
package namespace
import (
	"context"
	"fmt"
	"sort"
	"sync"
	"sync/atomic"
	"time"
	"go.temporal.io/api/serviceerror"
	"go.temporal.io/server/common"
	"go.temporal.io/server/common/cache"
	"go.temporal.io/server/common/clock"
	"go.temporal.io/server/common/log"
	"go.temporal.io/server/common/log/tag"
	"go.temporal.io/server/common/metrics"
	"go.temporal.io/server/common/persistence"
	"go.temporal.io/server/internal/goro"
)
type ReplicationPolicy int
const (
	ReplicationPolicyOneCluster ReplicationPolicy = 0
	ReplicationPolicyMultiCluster ReplicationPolicy = 1
)
const (
	cacheInitialSize = 10 * 1024
	cacheMaxSize     = 64 * 1024
	cacheTTL         = 0  
	CacheRefreshInterval = 10 * time.Second
	CacheRefreshFailureRetryInterval = 1 * time.Second
	CacheRefreshPageSize             = 200
	cacheInitialized int32 = 0
	cacheStarted     int32 = 1
	cacheStopped     int32 = 2
)
const (
	stopped int32 = iota
	starting
	running
	stopping
)
var (
	cacheOpts = cache.Options{
		InitialCapacity: cacheInitialSize,
		TTL:             cacheTTL,
	}
)
type (
	Clock interface {
		Now() time.Time
	}
	Persistence interface {
		GetNamespace(
			request *persistence.GetNamespaceRequest,
		) (*persistence.GetNamespaceResponse, error)
		ListNamespaces(
			*persistence.ListNamespacesRequest,
		) (*persistence.ListNamespacesResponse, error)
		GetMetadata() (*persistence.GetMetadataResponse, error)
	}
	PrepareCallbackFn func()
	CallbackFn func(oldNamespaces []*Namespace, newNamespaces []*Namespace)
	Registry interface {
		common.Daemon
		RegisterNamespaceChangeCallback(shard int32, initialNotificationVersion int64, prepareCallback PrepareCallbackFn, callback CallbackFn)
		UnregisterNamespaceChangeCallback(shard int32)
		GetNamespace(name string) (*Namespace, error)
		GetNamespaceByID(id string) (*Namespace, error)
		GetNamespaceID(name string) (string, error)
		GetNamespaceName(id string) (string, error)
		GetCacheSize() (sizeOfCacheByName int64, sizeOfCacheByID int64)
		Refresh()
	}
	registry struct {
		status                  int32
		refresher               *goro.Handle
		triggerRefreshCh        chan chan struct{}
		persistence             Persistence
		globalNamespacesEnabled bool
		clock                   Clock
		metricsClient           metrics.Client
		logger                  log.Logger
		lastRefreshTime         atomic.Value
		cacheLock     sync.RWMutex
		cacheNameToID cache.Cache
		cacheByID     cache.Cache
		callbackLock     sync.Mutex
		prepareCallbacks map[int32]PrepareCallbackFn
		callbacks        map[int32]CallbackFn
	}
)
func NewRegistry(
	persistence Persistence,
	enableGlobalNamespaces bool,
	metricsClient metrics.Client,
	logger log.Logger,
) Registry {
	reg := &registry{
		triggerRefreshCh:        make(chan chan struct{}, 1),
		persistence:             persistence,
		globalNamespacesEnabled: enableGlobalNamespaces,
		clock:                   clock.NewRealTimeSource(),
		metricsClient:           metricsClient,
		logger:                  logger,
		cacheNameToID:           cache.New(cacheMaxSize, &cacheOpts),
		cacheByID:               cache.New(cacheMaxSize, &cacheOpts),
		prepareCallbacks:        make(map[int32]PrepareCallbackFn),
		callbacks:               make(map[int32]CallbackFn),
	}
	reg.lastRefreshTime.Store(time.Time{})
	return reg
}
func (r *registry) GetCacheSize() (sizeOfCacheByName int64, sizeOfCacheByID int64) {
	r.cacheLock.RLock()
	defer r.cacheLock.RUnlock()
	return int64(r.cacheByID.Size()), int64(r.cacheNameToID.Size())
}
func (r *registry) Start() {
	if !atomic.CompareAndSwapInt32(&r.status, stopped, starting) {
		return
	}
	defer atomic.StoreInt32(&r.status, running)
	err := r.refreshNamespaces(context.Background())
	if err != nil {
		r.logger.Fatal("Unable to initialize namespace cache", tag.Error(err))
	}
	r.refresher = goro.Go(context.Background(), r.refreshLoop)
}
func (r *registry) Stop() {
	if !atomic.CompareAndSwapInt32(&r.status, running, stopping) {
		return
	}
	defer atomic.StoreInt32(&r.status, stopped)
	r.refresher.Cancel()
	<-r.refresher.Done()
}
func (r *registry) getAllNamespace() map[string]*Namespace {
	result := make(map[string]*Namespace)
	r.cacheLock.RLock()
	defer r.cacheLock.RUnlock()
	ite := r.cacheByID.Iterator()
	defer ite.Close()
	for ite.HasNext() {
		entry := ite.Next()
		id := entry.Key().(string)
		result[id] = entry.Value().(*Namespace)
	}
	return result
}
func (r *registry) RegisterNamespaceChangeCallback(
	shard int32,
	initialNotificationVersion int64,
	prepareCallback PrepareCallbackFn,
	callback CallbackFn,
) {
	r.callbackLock.Lock()
	r.prepareCallbacks[shard] = prepareCallback
	r.callbacks[shard] = callback
	r.callbackLock.Unlock()
	namespaces := Namespaces{}
	for _, namespace := range r.getAllNamespace() {
		namespaces = append(namespaces, namespace)
	}
	sort.Sort(namespaces)
	var oldEntries []*Namespace
	var newEntries []*Namespace
	for _, namespace := range namespaces {
		if namespace.notificationVersion >= initialNotificationVersion {
			oldEntries = append(oldEntries, nil)
			newEntries = append(newEntries, namespace)
		}
	}
	if len(oldEntries) > 0 {
		prepareCallback()
		callback(oldEntries, newEntries)
	}
}
func (r *registry) UnregisterNamespaceChangeCallback(
	shard int32,
) {
	r.callbackLock.Lock()
	defer r.callbackLock.Unlock()
	delete(r.prepareCallbacks, shard)
	delete(r.callbacks, shard)
}
func (r *registry) GetNamespace(name string) (*Namespace, error) {
	if name == "" {
		return nil, serviceerror.NewInvalidArgument("Namespace is empty.")
	}
	return r.getNamespace(name)
}
func (r *registry) GetNamespaceByID(id string) (*Namespace, error) {
	if id == "" {
		return nil, serviceerror.NewInvalidArgument("NamespaceID is empty.")
	}
	return r.getNamespaceByID(id)
}
func (r *registry) GetNamespaceID(
	name string,
) (string, error) {
	ns, err := r.GetNamespace(name)
	if err != nil {
		return "", err
	}
	return ns.ID(), nil
}
func (r *registry) GetNamespaceName(
	id string,
) (string, error) {
	ns, err := r.getNamespaceByID(id)
	if err != nil {
		return "", err
	}
	return ns.Name(), nil
}
func (r *registry) Refresh() {
	replyCh := make(chan struct{})
	r.triggerRefreshCh <- replyCh
	<-replyCh
}
func (r *registry) refreshLoop(ctx context.Context) error {
	timer := time.NewTicker(CacheRefreshInterval)
	defer timer.Stop()
	go func() {
		for range timer.C {
			select {
			case r.triggerRefreshCh <- nil:
			default:
			}
		}
	}()
	for {
		select {
		case <-ctx.Done():
			return nil
		case replyCh := <-r.triggerRefreshCh:
			for err := r.refreshNamespaces(ctx); err != nil; err = r.refreshNamespaces(ctx) {
				select {
				case <-ctx.Done():
					return nil
				default:
					r.logger.Error("Error refreshing namespace cache", tag.Error(err))
					select {
					case <-time.After(CacheRefreshFailureRetryInterval):
					case <-ctx.Done():
						return nil
					}
				}
			}
			if replyCh != nil {
				replyCh <- struct{}{}
			}
		}
	}
}
func (r *registry) refreshNamespaces(ctx context.Context) error {
	metadata, err := r.persistence.GetMetadata()
	if err != nil {
		return err
	}
	namespaceNotificationVersion := metadata.NotificationVersion
	var token []byte
	request := &persistence.ListNamespacesRequest{PageSize: CacheRefreshPageSize}
	var namespaces Namespaces
	continuePage := true
	for continuePage {
		request.NextPageToken = token
		response, err := r.persistence.ListNamespaces(request)
		if err != nil {
			return err
		}
		token = response.NextPageToken
		for _, namespace := range response.Namespaces {
			namespaces = append(namespaces, FromPersistentState(namespace))
		}
		continuePage = len(token) != 0
	}
	sort.Sort(namespaces)
	var oldEntries []*Namespace
	var newEntries []*Namespace
	newCacheNameToID := cache.New(cacheMaxSize, &cacheOpts)
	newCacheByID := cache.New(cacheMaxSize, &cacheOpts)
	for _, namespace := range r.getAllNamespace() {
		newCacheNameToID.Put(namespace.info.Name, namespace.info.Id)
		newCacheByID.Put(namespace.info.Id, namespace)
	}
UpdateLoop:
	for _, namespace := range namespaces {
		if namespace.notificationVersion >= namespaceNotificationVersion {
			break UpdateLoop
		}
		oldNS := r.updateIDToNamespaceCache(newCacheByID, namespace.ID(), namespace)
		r.updateNameToIDCache(newCacheNameToID, namespace.Name(), namespace.ID())
		if oldNS != nil {
			oldEntries = append(oldEntries, oldNS)
			newEntries = append(newEntries, namespace)
		}
	}
	r.publishCacheUpdate(func() (Namespaces, Namespaces) {
		r.cacheLock.Lock()
		defer r.cacheLock.Unlock()
		r.cacheByID = newCacheByID
		r.cacheNameToID = newCacheNameToID
		return oldEntries, newEntries
	})
	return nil
}
func (r *registry) updateNameToIDCache(c cache.Cache, name string, id string) {
	c.Put(name, id)
}
func (r *registry) updateIDToNamespaceCache(
	cacheByID cache.Cache,
	id string,
	newNS *Namespace,
) *Namespace {
	oldCacheRec := cacheByID.Put(id, newNS)
	if oldNS, ok := oldCacheRec.(*Namespace); ok &&
		newNS.notificationVersion > oldNS.notificationVersion &&
		r.globalNamespacesEnabled {
		return oldNS
	}
	return nil
}