Files
upstream-centrifugo/internal/config/cache.go
upstream-mirror b352a9a30d
Some checks failed
test / Lint (push) Failing after 3s
test / Test with Go 1.26.8 (push) Failing after 2s
snapshot of https://github.com/centrifugal/centrifugo.git (master, 2026-09-16; blobs > 131072B omitted)
2026-09-16 01:17:21 +05:00

74 lines
1.8 KiB
Go

package config
import (
"hash/fnv"
"sync/atomic"
"time"
)
type cacheItem struct {
channel string
value channelOptionsResult
expires int64
}
type cacheShard struct {
// index is unsigned on purpose: it only ever grows, and unsigned overflow
// wraps to zero cleanly. With a signed counter the wrap goes negative and
// the modulo below yields a negative buffer index, panicking the server
// after 2^31 Set calls land on the same shard.
index atomic.Uint32
size uint32
buffer []atomic.Value
}
type rollingCache struct {
shards []*cacheShard
}
func newRollingCache(shardSize int, shardCount int) *rollingCache {
rc := &rollingCache{
shards: make([]*cacheShard, shardCount),
}
for i := range rc.shards {
shard := &cacheShard{
size: uint32(shardSize),
buffer: make([]atomic.Value, shardSize),
}
for j := 0; j < shardSize; j++ {
shard.buffer[j].Store(&cacheItem{}) // Initialize with zero value.
}
rc.shards[i] = shard
}
return rc
}
func (c *rollingCache) shardForKey(key string) *cacheShard {
h := fnv.New64a()
_, _ = h.Write([]byte(key))
shardIndex := h.Sum64() % uint64(len(c.shards))
return c.shards[shardIndex]
}
func (c *rollingCache) Get(channel string) (channelOptionsResult, bool) {
shard := c.shardForKey(channel)
for i := 0; i < int(shard.size); i++ {
item := shard.buffer[i].Load().(*cacheItem)
if item.channel == channel && time.Now().UnixNano() < item.expires {
return item.value, true
}
}
return channelOptionsResult{}, false
}
func (c *rollingCache) Set(channel string, value channelOptionsResult, ttl time.Duration) {
shard := c.shardForKey(channel)
index := int(shard.index.Add(1) % shard.size)
item := &cacheItem{
channel: channel,
value: value,
expires: time.Now().Add(ttl).UnixNano(),
}
shard.buffer[index].Store(item)
}