From df478cfa8f42c459da7fd3e357815a95c0e8670c Mon Sep 17 00:00:00 2001 From: zouliehao Date: Sat, 23 Jul 2022 16:42:25 +0800 Subject: [PATCH] Feature get the value but not update the expiration time (#57) --- cache_test.go | 43 +++++++++++++++++++++++++++++++++++++++++++ cacheitem.go | 7 +++++++ cachetable.go | 27 +++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/cache_test.go b/cache_test.go index e195e93..1c7234a 100644 --- a/cache_test.go +++ b/cache_test.go @@ -168,6 +168,49 @@ func TestCacheKeepAlive(t *testing.T) { } } +func TestPeek(t *testing.T) { + // add an expiring item + table := Cache("TestPeek") + _ = table.Add(k, 250*time.Millisecond, v) + _ = table.Add(k+"_", 250*time.Millisecond, v) + + // test peek item + time.Sleep(150 * time.Millisecond) + p, _ := table.Peek(k) + if p.Data() != v { + t.Error("Error peek item") + } + + // test k is expired + time.Sleep(150 * time.Millisecond) + if table.Exists(k) { + t.Error("Error peek but expired time updated") + } + + // test peek nil + _, err := table.Peek(k) + if err != ErrKeyNotFound { + t.Error("Error peek nil value but not return ErrKeyNotFound") + } + + // test DataLoader + table.SetDataLoader(func(key interface{}, args ...interface{}) *CacheItem { + if key == k { + return NewCacheItem(key, 150*time.Millisecond, "new value") + } + return nil + }) + p, _ = table.Peek(k) + if p.Data() != "new value" { + t.Error("Error peek DataLoader callback did not take effect") + } + + _, err = table.Peek(k + "_") + if err != ErrKeyNotFoundOrLoadable { + t.Error("Error peek DataLoader err") + } +} + func TestDelete(t *testing.T) { // add an item to the cache table := Cache("testDelete") diff --git a/cacheitem.go b/cacheitem.go index 4046be2..4e1ef32 100644 --- a/cacheitem.go +++ b/cacheitem.go @@ -61,6 +61,13 @@ func (item *CacheItem) KeepAlive() { item.accessCount++ } +// AddAccessCount only add one access count. +func (item *CacheItem) AddAccessCount() { + item.Lock() + defer item.Unlock() + item.accessCount++ +} + // LifeSpan returns this item's expiration duration. func (item *CacheItem) LifeSpan() time.Duration { // immutable diff --git a/cachetable.go b/cachetable.go index 1fa75ad..05433d4 100644 --- a/cachetable.go +++ b/cachetable.go @@ -303,6 +303,33 @@ func (table *CacheTable) Value(key interface{}, args ...interface{}) (*CacheItem return nil, ErrKeyNotFound } +// Peek returns an item from the cache, but does not mark its active status, i.e. does not update the active time. +// You can also pass additional arguments to your DataLoader callback function. +func (table *CacheTable) Peek(key interface{}, args ...interface{}) (*CacheItem, error) { + table.RLock() + r, ok := table.items[key] + loadData := table.loadData + table.RUnlock() + + if ok { + r.AddAccessCount() + return r, nil + } + + // Item doesn't exist in cache. Try and fetch it with a data-loader. + if loadData != nil { + item := loadData(key, args...) + if item != nil { + table.Add(key, item.lifeSpan, item.data) + return item, nil + } + + return nil, ErrKeyNotFoundOrLoadable + } + + return nil, ErrKeyNotFound +} + // Flush deletes all items from this cache table. func (table *CacheTable) Flush() { table.Lock()