Skip to content

Commit

Permalink
add silding get to cache
Browse files Browse the repository at this point in the history
  • Loading branch information
phuslu committed Jan 3, 2024
1 parent 97ba4eb commit 45cb3ad
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 0 deletions.
6 changes: 6 additions & 0 deletions cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ func (c *Cache[K, V]) Get(key K) (value V, ok bool) {
return c.shards[hash&c.mask].Get(hash, key)
}

// SlidingGet returns value for key and reset the expires with TTL(aka, Sliding Cache).
func (c *Cache[K, V]) SlidingGet(key K) (value V, ok bool) {
hash := uint32(c.hasher.Hash(key))
return c.shards[hash&c.mask].SlidingGet(hash, key)
}

// Peek returns value for key, but does not modify its recency.
func (c *Cache[K, V]) Peek(key K) (value V, ok bool) {
hash := uint32(c.hasher.Hash(key))
Expand Down
16 changes: 16 additions & 0 deletions cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,22 @@ func TestCacheEviction(t *testing.T) {
}
}

func TestCacheSlidingGet(t *testing.T) {
l := newWithShards[string, int](1, 256)

l.SetWithTTL("foobar", 42, 400*time.Millisecond)

time.Sleep(200 * time.Millisecond)
if v, ok := l.SlidingGet("foobar"); !ok || v != 42 {
t.Errorf("foobar should be set to 42: %v,", v)
}

time.Sleep(300 * time.Millisecond)
if v, ok := l.Get("foobar"); !ok || v != 42 {
t.Errorf("foobar should be still set to 42: %v,", v)
}
}

func TestCachePeek(t *testing.T) {
l := New[int, int](64)

Expand Down
1 change: 1 addition & 0 deletions list.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ type node[K comparable, V any] struct {
key K
value V
expires int64
ttl int64
next uint32
prev uint32
}
Expand Down
27 changes: 27 additions & 0 deletions shard.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,31 @@ func (s *shard[K, V]) Get(hash uint32, key K) (value V, ok bool) {
return
}

func (s *shard[K, V]) SlidingGet(hash uint32, key K) (value V, ok bool) {
s.mu.Lock()

if index, exists := s.table.Get(hash, key); exists {
if expires := s.list.nodes[index].expires; expires == 0 {
s.list.MoveToFront(index)
value = s.list.nodes[index].value
ok = true
} else if now := atomic.LoadInt64(&clock); now < expires {
s.list.MoveToFront(index)
s.list.nodes[index].expires = atomic.LoadInt64(&clock) + s.list.nodes[index].ttl
value = s.list.nodes[index].value
ok = true
} else {
s.list.MoveToBack(index)
s.list.nodes[index].value = value
s.table.Delete(hash, key)
}
}

s.mu.Unlock()

return
}

func (s *shard[K, V]) Peek(hash uint32, key K) (value V, ok bool) {
s.mu.Lock()

Expand All @@ -61,6 +86,7 @@ func (s *shard[K, V]) Set(hash uint32, hashfun func(K) uint64, key K, value V, t
s.list.MoveToFront(index)
node.value = value
if ttl > 0 {
node.ttl = int64(ttl)
node.expires = atomic.LoadInt64(&clock) + int64(ttl)
}
prev = previousValue
Expand All @@ -76,6 +102,7 @@ func (s *shard[K, V]) Set(hash uint32, hashfun func(K) uint64, key K, value V, t
node.key = key
node.value = value
if ttl > 0 {
node.ttl = int64(ttl)
node.expires = atomic.LoadInt64(&clock) + int64(ttl)
}
s.table.Set(hash, key, index)
Expand Down

0 comments on commit 45cb3ad

Please sign in to comment.