Skip to content

Commit 62cd8cc

Browse files
authored
Merge pull request #85 from rfyiamcool/feat/add_setnx
feat: add setnx (if not exists, set kv)
2 parents 0f85751 + b26c342 commit 62cd8cc

File tree

4 files changed

+58
-0
lines changed

4 files changed

+58
-0
lines changed

bucket.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,30 @@ func (b *bucket[T]) get(key string) *Item[T] {
3535
return b.lookup[key]
3636
}
3737

38+
func (b *bucket[T]) setnx(key string, value T, duration time.Duration, track bool) *Item[T] {
39+
b.RLock()
40+
item := b.lookup[key]
41+
b.RUnlock()
42+
if item != nil {
43+
return item
44+
}
45+
46+
expires := time.Now().Add(duration).UnixNano()
47+
newItem := newItem(key, value, expires, track)
48+
49+
b.Lock()
50+
defer b.Unlock()
51+
52+
// check again under write lock
53+
item = b.lookup[key]
54+
if item != nil {
55+
return item
56+
}
57+
58+
b.lookup[key] = newItem
59+
return newItem
60+
}
61+
3862
func (b *bucket[T]) set(key string, value T, duration time.Duration, track bool) (*Item[T], *Item[T]) {
3963
expires := time.Now().Add(duration).UnixNano()
4064
item := newItem(key, value, expires, track)

cache.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,11 @@ func (c *Cache[T]) Set(key string, value T, duration time.Duration) {
146146
c.set(key, value, duration, false)
147147
}
148148

149+
// Setnx set the value in the cache for the specified duration if not exists
150+
func (c *Cache[T]) Setnx(key string, value T, duration time.Duration) {
151+
c.bucket(key).setnx(key, value, duration, false)
152+
}
153+
149154
// Replace the value if it exists, does not set if it doesn't.
150155
// Returns true if the item existed an was replaced, false otherwise.
151156
// Replace does not reset item's TTL

cache_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,27 @@ import (
1212
"github.com/karlseguin/ccache/v3/assert"
1313
)
1414

15+
func Test_Setnx(t *testing.T) {
16+
cache := New(Configure[string]())
17+
defer cache.Stop()
18+
assert.Equal(t, cache.ItemCount(), 0)
19+
20+
cache.Set("spice", "flow", time.Minute)
21+
assert.Equal(t, cache.ItemCount(), 1)
22+
23+
// set if exists
24+
cache.Setnx("spice", "worm", time.Minute)
25+
assert.Equal(t, cache.ItemCount(), 1)
26+
assert.Equal(t, cache.Get("spice").Value(), "flow")
27+
28+
// set if not exists
29+
cache.Delete("spice")
30+
cache.Setnx("spice", "worm", time.Minute)
31+
assert.Equal(t, cache.Get("spice").Value(), "worm")
32+
33+
assert.Equal(t, cache.ItemCount(), 1)
34+
}
35+
1536
func Test_CacheDeletesAValue(t *testing.T) {
1637
cache := New(Configure[string]())
1738
defer cache.Stop()

readme.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,14 @@ cache.Replace("user:4", user)
122122

123123
`Replace` returns true if the item existed (and thus was replaced). In the case where the key was not in the cache, the value *is not* inserted and false is returned.
124124

125+
### Setnx
126+
127+
Set the value if not exists. setnx will first check whether kv exists. If it does not exist, set kv in cache. this operation is atomic.
128+
129+
```go
130+
cache.Set("user:4", user, time.Minute * 10)
131+
```
132+
125133
### GetDropped
126134
You can get the number of keys evicted due to memory pressure by calling `GetDropped`:
127135

0 commit comments

Comments
 (0)