func (r *registry) GetNamespaceByID(id string) (*Namespace, error) {
	if id == "" {
		return nil, serviceerror.NewInvalidArgument("NamespaceID is empty.")
	}
	return r.getNamespaceByID(id)
}
GetNamespaceByID retrieves the information from the cache if it exists, otherwise retrieves the information from metadata
store and writes it to the cache with an expiry before returning back
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)
}