Skip to content

Commit

Permalink
fix: deprecate RegisterOn* and add notify
Browse files Browse the repository at this point in the history
  • Loading branch information
shaj13 committed Jun 26, 2022
1 parent a0b499e commit 5a3451b
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 107 deletions.
26 changes: 7 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,26 +166,14 @@ import (

func main() {
cache := libcache.LRU.New(10)
cache.RegisterOnEvicted(func(key, value interface{}) {
fmt.Printf("Cache Key %v Evicted\n", key)
})

cache.RegisterOnExpired(func(key, value interface{}) {
fmt.Printf("Cache Key %v Expired, Removing it from cache\n", key)
// use delete directly when your application
// guarantee no other goroutine can store items with the same key.
// Peek also invoke lazy expiry.
//
// Note this should done only with safe cache.
cache.Peek(key)
})

for i:= 0 ; i < 10 ; i++ {
cache.StoreWithTTL(i, i, time.Microsecond)
fn := func(e libcache.Event) {
fmt.Printf("Operation %s on Key %v \n", e.Op, e.Key)
}

time.Sleep(time.Second)
fmt.Println(cache.Len())
cache.Notify(fn, libcache.Read, libcache.Write, libcache.Remove)
cache.Load(1)
cache.Store(1)
cache.Peek(1)
cache.Delete(1)
}
```

Expand Down
5 changes: 5 additions & 0 deletions arc/arc.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@ func (a *arc) RegisterOnExpired(f func(key, value interface{})) {
a.t2.RegisterOnExpired(f)
}

func (a *arc) Notify(fn func(libcache.Event), ops ...libcache.Op) {
a.t1.Notify(fn, ops...)
a.t2.Notify(fn, ops...)
}

func min(x, y int) int {
if x < y {
return x
Expand Down
63 changes: 42 additions & 21 deletions cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,23 @@ package libcache
import (
"sync"
"time"

"github.com/shaj13/libcache/internal"
)

// These are the generalized cache operations that can trigger a event.
const (
Read = internal.Read
Write = internal.Write
Remove = internal.Remove
)

// Op describes a set of cache operations.
type Op = internal.Op

// Event represents a single cache entry change.
type Event = internal.Event

// Cache stores data so that future requests for that data can be served faster.
type Cache interface {
// Load returns key value.
Expand Down Expand Up @@ -39,24 +54,24 @@ type Cache interface {
// SetTTL sets entries default TTL.
SetTTL(time.Duration)
// RegisterOnEvicted registers a function,
// to call in its own goroutine when an entry is purged from the cache.
// to call it when an entry is purged from the cache.
//
// Deprecated: use Notify instead.
RegisterOnEvicted(f func(key, value interface{}))
// RegisterOnExpired registers a function,
// to call in its own goroutine when an entry TTL elapsed.
// invocation of f, does not mean the entry is purged from the cache,
// if need be, it must coordinate with the cache explicitly.
// to call it when an entry TTL elapsed.
//
// var cache cache.Cache
// onExpired := func(key, value interface{}) {
// _, _, _ = cache.Peek(key)
// }
//
// This should not be done unless the cache thread-safe.
// Deprecated: use Notify instead.
RegisterOnExpired(f func(key, value interface{}))

// Notify causes cahce to relay events to fn.
// If no operations are provided, all incoming operations will be relayed to fn.
// Otherwise, just the provided operations will.
Notify(fn func(Event), ops ...Op)
}

type cache struct {
mu sync.RWMutex
mu sync.Mutex
unsafe Cache
}

Expand Down Expand Up @@ -97,8 +112,8 @@ func (c *cache) Delete(key interface{}) {
}

func (c *cache) Keys() []interface{} {
c.mu.RLock()
defer c.mu.RUnlock()
c.mu.Lock()
defer c.mu.Unlock()
return c.unsafe.Keys()
}

Expand All @@ -121,20 +136,20 @@ func (c *cache) Resize(s int) int {
}

func (c *cache) Len() int {
c.mu.RLock()
defer c.mu.RUnlock()
c.mu.Lock()
defer c.mu.Unlock()
return c.unsafe.Len()
}

func (c *cache) Cap() int {
c.mu.RLock()
defer c.mu.RUnlock()
c.mu.Lock()
defer c.mu.Unlock()
return c.unsafe.Cap()
}

func (c *cache) TTL() time.Duration {
c.mu.RLock()
defer c.mu.RUnlock()
c.mu.Lock()
defer c.mu.Unlock()
return c.unsafe.TTL()
}

Expand All @@ -156,8 +171,14 @@ func (c *cache) RegisterOnExpired(f func(key, value interface{})) {
c.unsafe.RegisterOnExpired(f)
}

func (c *cache) Notify(fn func(Event), ops ...Op) {
c.mu.Lock()
defer c.mu.Unlock()
c.unsafe.Notify(fn, ops...)
}

func (c *cache) Expiry(key interface{}) (time.Time, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
c.mu.Lock()
defer c.mu.Unlock()
return c.unsafe.Expiry(key)
}
49 changes: 30 additions & 19 deletions cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,34 +249,18 @@ func TestOnEvicted(t *testing.T) {
func TestOnExpired(t *testing.T) {
for _, tt := range cacheTests {
t.Run("Test"+tt.cont.String()+"CacheOnExpired", func(t *testing.T) {
send := make(chan interface{})
done := make(chan bool)
expiredKeys := make([]interface{}, 0, 2)
cache := tt.cont.New(0)
cache.RegisterOnExpired(func(key, _ interface{}) {
send <- key
expiredKeys = append(expiredKeys, key)
})
cache.SetTTL(time.Millisecond)

go func() {
for {
key := <-send
expiredKeys = append(expiredKeys, key)
if len(expiredKeys) >= 2 {
done <- true
return
}
}
}()

cache.Store(1, 1234)
cache.Store(2, 1234)

select {
case <-done:
case <-time.After(time.Second * 2):
t.Fatal("TestOnExpired timeout exceeded, expected to receive expired keys")
}
time.Sleep(time.Millisecond * 2)
cache.Peek(1)

assert.ElementsMatch(t, []interface{}{1, 2}, expiredKeys)
})
Expand Down Expand Up @@ -350,3 +334,30 @@ func BenchmarkCache(b *testing.B) {
})
}
}

func TestNotify(t *testing.T) {
for _, tt := range cacheTests {
t.Run("Test"+tt.cont.String()+"CacheNotify", func(t *testing.T) {
got := 0
cache := tt.cont.New(0)
fn := func(e libcache.Event) {
t.Logf("Operation %s on Key %v \n", e.Op, e.Key)
got += e.Key.(int)
}

cache.Notify(fn, libcache.Read, libcache.Write, libcache.Remove)

cache.Load(1)
cache.StoreWithTTL(1, 0, time.Second)
cache.Peek(1)
cache.Delete(1)

if tt.cont == libcache.ARC {
assert.Equal(t, 7, got)
} else {
assert.Equal(t, 4, got)
}
})
}

}
1 change: 1 addition & 0 deletions idle/idle.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ func (idle) Purge() {}
func (idle) SetTTL(ttl time.Duration) {}
func (idle) RegisterOnExpired(f func(key, value interface{})) {}
func (idle) RegisterOnEvicted(f func(key, value interface{})) {}
func (idle) Notify(fn func(libcache.Event), op ...libcache.Op) {}
Loading

0 comments on commit 5a3451b

Please sign in to comment.