From 2372da942a05200195e85fe23952d8ccd2bd630b Mon Sep 17 00:00:00 2001 From: Overlord Date: Mon, 1 Dec 2025 21:12:46 +0100 Subject: [PATCH] updated cache --- util/cache/cache.go | 99 ++++++++++++++++++++++++++----------------- util/cache/structs.go | 14 +++--- 2 files changed, 67 insertions(+), 46 deletions(-) diff --git a/util/cache/cache.go b/util/cache/cache.go index 9af7ca3..57d682c 100644 --- a/util/cache/cache.go +++ b/util/cache/cache.go @@ -1,70 +1,91 @@ package cache -import "sync" - -type Cache struct { - mu sync.RWMutex - s2c map[string]string - c2s map[string]string -} - func NewCache() *Cache { - return &Cache{ + c := &Cache{} + c.state.Store(&mappings{ s2c: make(map[string]string), c2s: make(map[string]string), - } + }) + + return c } -// Set creates or overwrites the pair a -> b and b -> a. -// It ensures any previous mappings involving a or b are removed first. func (c *Cache) Set(serverId, channelId string) { c.mu.Lock() defer c.mu.Unlock() - if old, ok := c.s2c[serverId]; ok && old != channelId { - delete(c.c2s, old) + current := c.state.Load() + next := current.clone() + + if oldCh, ok := next.s2c[serverId]; ok && oldCh != channelId { + delete(next.c2s, oldCh) + } + if oldSrv, ok := next.c2s[channelId]; ok && oldSrv != serverId { + delete(next.s2c, oldSrv) } - if old, ok := c.c2s[channelId]; ok && old != serverId { - delete(c.s2c, old) - } + next.s2c[serverId] = channelId + next.c2s[channelId] = serverId - c.s2c[serverId] = channelId - c.c2s[channelId] = serverId + c.state.Store(next) } func (c *Cache) GetByServerId(serverId string) (string, bool) { - c.mu.RLock() - defer c.mu.RUnlock() - - cId, ok := c.s2c[serverId] - return cId, ok + m := c.state.Load() + val, ok := m.s2c[serverId] + return val, ok } func (c *Cache) GetByChannelId(channelId string) (string, bool) { - c.mu.RLock() - defer c.mu.RUnlock() - - sId, ok := c.c2s[channelId] - return sId, ok + m := c.state.Load() + val, ok := m.c2s[channelId] + return val, ok } func (c *Cache) RemoveByServerId(serverId string) { - c.mu.RLock() - defer c.mu.RUnlock() + c.mu.Lock() + defer c.mu.Unlock() - if channelId, ok := c.s2c[serverId]; ok { - delete(c.s2c, serverId) - delete(c.c2s, channelId) + current := c.state.Load() + if _, ok := current.s2c[serverId]; !ok { + return } + + next := current.clone() + if channelId, ok := next.s2c[serverId]; ok { + delete(next.s2c, serverId) + delete(next.c2s, channelId) + } + c.state.Store(next) } func (c *Cache) RemoveByChannelId(channelId string) { - c.mu.RLock() - defer c.mu.RUnlock() + c.mu.Lock() + defer c.mu.Unlock() - if serverId, ok := c.s2c[channelId]; ok { - delete(c.c2s, channelId) - delete(c.s2c, serverId) + current := c.state.Load() + if _, ok := current.c2s[channelId]; !ok { + return } + + next := current.clone() + if serverId, ok := next.c2s[channelId]; ok { + delete(next.c2s, channelId) + delete(next.s2c, serverId) + } + c.state.Store(next) +} + +func (m *mappings) clone() *mappings { + newM := &mappings{ + s2c: make(map[string]string, len(m.s2c)), + c2s: make(map[string]string, len(m.c2s)), + } + for k, v := range m.s2c { + newM.s2c[k] = v + } + for k, v := range m.c2s { + newM.c2s[k] = v + } + return newM } diff --git a/util/cache/structs.go b/util/cache/structs.go index b5ce12f..e484c32 100644 --- a/util/cache/structs.go +++ b/util/cache/structs.go @@ -2,15 +2,15 @@ package cache import ( "sync" + "sync/atomic" ) -type ShardedCache struct { - shards []*shard - shardMask uint32 +type Cache struct { + mu sync.Mutex + state atomic.Pointer[mappings] } -type shard struct { - mu sync.RWMutex - s2c map[string]string // serverId -> channelId - c2s map[string]string // channelId -> serverId +type mappings struct { + s2c map[string]string + c2s map[string]string }