Skip to content

Commit

Permalink
Add Version() method
Browse files Browse the repository at this point in the history
  • Loading branch information
gozeloglu committed May 27, 2023
1 parent 17d45be commit 7b99ae7
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 18 deletions.
2 changes: 1 addition & 1 deletion cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func (c *Cache[K, V]) set(key K, value V, ttl time.Duration) *Item[K, V] {
}

// create a new item
item := newItem(key, value, ttl)
item := newItem(key, value, ttl, c.options.enableVersionTrack)
elem = c.items.lru.PushFront(item)
c.items.values[key] = elem
c.updateExpirations(true, elem)
Expand Down
1 change: 1 addition & 0 deletions cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1152,6 +1152,7 @@ func addToCache(c *Cache[string, string], ttl time.Duration, keys ...string) {
key,
fmt.Sprint("value of", key),
ttl+time.Duration(i)*time.Minute,
false,
)
elem := c.items.lru.PushFront(item)
c.items.values[key] = elem
Expand Down
40 changes: 30 additions & 10 deletions item.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,26 @@ type Item[K comparable, V any] struct {
// well, so locking this mutex would be redundant.
// In other words, this mutex is only useful when these fields
// are being read from the outside (e.g. in event functions).
mu sync.RWMutex
key K
value V
ttl time.Duration
expiresAt time.Time
queueIndex int
mu sync.RWMutex
key K
value V
ttl time.Duration
expiresAt time.Time
queueIndex int
version int64
enableVersionTrack bool
}

// newItem creates a new cache item.
func newItem[K comparable, V any](key K, value V, ttl time.Duration) *Item[K, V] {
func newItem[K comparable, V any](key K, value V, ttl time.Duration, enableVersionTrack bool) *Item[K, V] {
item := &Item[K, V]{
key: key,
value: value,
ttl: ttl,
key: key,
value: value,
ttl: ttl,
enableVersionTrack: enableVersionTrack,
}
if !enableVersionTrack {
item.version = -1
}
item.touch()

Expand All @@ -58,6 +64,11 @@ func (item *Item[K, V]) update(value V, ttl time.Duration) {
// 0 or below
item.expiresAt = time.Time{}
item.touchUnsafe()

// update version if it is enabled.
if item.enableVersionTrack {
item.version++
}
}

// touch updates the item's expiration timestamp.
Expand Down Expand Up @@ -128,3 +139,12 @@ func (item *Item[K, V]) ExpiresAt() time.Time {

return item.expiresAt
}

// Version returns the version of the item. Version shows the total number of
// changes made to the item.
func (item *Item[K, V]) Version() int64 {
item.mu.RLock()
defer item.mu.RUnlock()

return item.version
}
18 changes: 15 additions & 3 deletions item_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,45 @@ import (
)

func Test_newItem(t *testing.T) {
item := newItem("key", 123, time.Hour)
item := newItem("key", 123, time.Hour, false)
require.NotNil(t, item)
assert.Equal(t, "key", item.key)
assert.Equal(t, 123, item.value)
assert.Equal(t, time.Hour, item.ttl)
assert.Equal(t, false, item.enableVersionTrack)
assert.Equal(t, int64(-1), item.version)
assert.WithinDuration(t, time.Now().Add(time.Hour), item.expiresAt, time.Minute)
}

func Test_Item_update(t *testing.T) {
item := Item[string, string]{
expiresAt: time.Now().Add(-time.Hour),
value: "hello",
expiresAt: time.Now().Add(-time.Hour),
value: "hello",
enableVersionTrack: true,
}

item.update("test", time.Hour)
assert.Equal(t, "test", item.value)
assert.Equal(t, time.Hour, item.ttl)
assert.Equal(t, int64(1), item.version)
assert.WithinDuration(t, time.Now().Add(time.Hour), item.expiresAt, time.Minute)

item.update("hi", NoTTL)
assert.Equal(t, "hi", item.value)
assert.Equal(t, NoTTL, item.ttl)
assert.Equal(t, int64(2), item.version)
assert.Zero(t, item.expiresAt)
}

func Test_Item_touch(t *testing.T) {
var item Item[string, string]
item.touch()
assert.Equal(t, int64(0), item.version)
assert.Zero(t, item.expiresAt)

item.ttl = time.Hour
item.touch()
assert.Equal(t, int64(0), item.version)
assert.WithinDuration(t, time.Now().Add(time.Hour), item.expiresAt, time.Minute)
}

Expand Down Expand Up @@ -93,3 +100,8 @@ func Test_Item_ExpiresAt(t *testing.T) {

assert.Equal(t, now, item.ExpiresAt())
}

func Test_Item_Version(t *testing.T) {
item := Item[string, string]{version: 5}
assert.Equal(t, int64(5), item.Version())
}
18 changes: 14 additions & 4 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ func (fn optionFunc[K, V]) apply(opts *options[K, V]) {

// options holds all available cache configuration options.
type options[K comparable, V any] struct {
capacity uint64
ttl time.Duration
loader Loader[K, V]
disableTouchOnHit bool
capacity uint64
ttl time.Duration
loader Loader[K, V]
disableTouchOnHit bool
enableVersionTrack bool
}

// applyOptions applies the provided option values to the option struct.
Expand All @@ -46,6 +47,15 @@ func WithTTL[K comparable, V any](ttl time.Duration) Option[K, V] {
})
}

// WithVersion sets the tracking information of the version field in Item.
// If you disable it by passing false, the version will always be -1.
func WithVersion[K comparable, V any](enable bool) Option[K, V] {
return optionFunc[K, V](func(opts *options[K, V]) {
opts.enableVersionTrack = enable
})

}

// WithLoader sets the loader of the cache.
// When passing into Get(), it sets an epheral loader that
// is used instead of the cache's default one.
Expand Down
10 changes: 10 additions & 0 deletions options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ func Test_WithTTL(t *testing.T) {
assert.Equal(t, time.Hour, opts.ttl)
}

func Test_WithVersion(t *testing.T) {
var opts options[string, string]

WithVersion[string, string](true).apply(&opts)
assert.Equal(t, true, opts.enableVersionTrack)

WithVersion[string, string](false).apply(&opts)
assert.Equal(t, false, opts.enableVersionTrack)
}

func Test_WithLoader(t *testing.T) {
var opts options[string, string]

Expand Down

0 comments on commit 7b99ae7

Please sign in to comment.