From 732ffc7739fb487cd8e6d4ad558f1622c8163a1f Mon Sep 17 00:00:00 2001 From: debspencer Date: Tue, 10 Aug 2021 22:33:43 -0400 Subject: [PATCH] Add a SetAndGet method to return previous value when setting a new one (#101) --- cache.go | 19 +++++++++++++++++++ cache_test.go | 20 ++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/cache.go b/cache.go index df76d50..8fdd55b 100644 --- a/cache.go +++ b/cache.go @@ -117,6 +117,25 @@ func (cache *Cache) GetOrSet(key, value []byte, expireSeconds int) (retValue []b return } +// SetAndGet sets a key, value and expiration for a cache entry and stores it in the cache. +// If the key is larger than 65535 or value is larger than 1/1024 of the cache size, +// the entry will not be written to the cache. expireSeconds <= 0 means no expire, +// but it can be evicted when cache is full. Returns existing value if record exists +// with a bool value to indicate whether an existing record was found +func (cache *Cache) SetAndGet(key, value []byte, expireSeconds int) (retValue []byte, found bool, err error) { + hashVal := hashFunc(key) + segID := hashVal & segmentAndOpVal + cache.locks[segID].Lock() + defer cache.locks[segID].Unlock() + + retValue, _, err = cache.segments[segID].get(key, nil, hashVal, false) + if err == nil { + found = true + } + err = cache.segments[segID].set(key, value, hashVal, expireSeconds) + return +} + // Peek returns the value or not found error, without updating access time or counters. func (cache *Cache) Peek(key []byte) (value []byte, err error) { hashVal := hashFunc(key) diff --git a/cache_test.go b/cache_test.go index c12eebf..161f0a4 100644 --- a/cache_test.go +++ b/cache_test.go @@ -824,3 +824,23 @@ func TestConcurrentGetTTL(t *testing.T) { t.Fatalf("Failed to get the TTL with an error: %+v", err) } } + +func TestSetAndGet(t *testing.T) { + cache := NewCache(1024) + key := []byte("abcd") + val1 := []byte("efgh") + + _, found, _ := cache.SetAndGet(key, val1, 0) + if found == true { + t.Fatalf("SetAndGet unexpected found data") + } + + val2 := []byte("ijkl") + rval, found, _ := cache.SetAndGet(key, val2, 0) + if found == false { + t.Fatalf("SetAndGet expected found data") + } + if string(val1) != string(rval) { + t.Fatalf("SetAndGet expected SetAndGet %s: got %s", string(val1), string(rval)) + } +}