Skip to content

Commit

Permalink
[BREAKING] support generic API (#321)
Browse files Browse the repository at this point in the history
  • Loading branch information
aryehlev authored Sep 6, 2023
1 parent 1854617 commit e2027d3
Show file tree
Hide file tree
Showing 10 changed files with 299 additions and 292 deletions.
157 changes: 81 additions & 76 deletions cache.go

Large diffs are not rendered by default.

158 changes: 79 additions & 79 deletions cache_test.go

Large diffs are not rendered by default.

44 changes: 22 additions & 22 deletions policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ const (
// policy is the interface encapsulating eviction/admission behavior.
// TODO: remove this interface and just rename defaultPolicy to policy, as we
// are probably only going to use/implement/maintain one policy.
type policy interface {
type policy[V any] interface {
ringConsumer
// Add attempts to Add the key-cost pair to the Policy. It returns a slice
// of evicted keys and a bool denoting whether or not the key-cost pair
// was added. If it returns true, the key should be stored in cache.
Add(uint64, int64) ([]*Item, bool)
Add(uint64, int64) ([]*Item[V], bool)
// Has returns true if the key exists in the Policy.
Has(uint64) bool
// Del deletes the key from the Policy.
Expand All @@ -61,11 +61,11 @@ type policy interface {
UpdateMaxCost(int64)
}

func newPolicy(numCounters, maxCost int64) policy {
return newDefaultPolicy(numCounters, maxCost)
func newPolicy[V any](numCounters, maxCost int64) policy[V] {
return newDefaultPolicy[V](numCounters, maxCost)
}

type defaultPolicy struct {
type defaultPolicy[V any] struct {
sync.Mutex
admit *tinyLFU
evict *sampledLFU
Expand All @@ -75,8 +75,8 @@ type defaultPolicy struct {
metrics *Metrics
}

func newDefaultPolicy(numCounters, maxCost int64) *defaultPolicy {
p := &defaultPolicy{
func newDefaultPolicy[V any](numCounters, maxCost int64) *defaultPolicy[V] {
p := &defaultPolicy[V]{
admit: newTinyLFU(numCounters),
evict: newSampledLFU(maxCost),
itemsCh: make(chan []uint64, 3),
Expand All @@ -86,7 +86,7 @@ func newDefaultPolicy(numCounters, maxCost int64) *defaultPolicy {
return p
}

func (p *defaultPolicy) CollectMetrics(metrics *Metrics) {
func (p *defaultPolicy[V]) CollectMetrics(metrics *Metrics) {
p.metrics = metrics
p.evict.metrics = metrics
}
Expand All @@ -96,7 +96,7 @@ type policyPair struct {
cost int64
}

func (p *defaultPolicy) processItems() {
func (p *defaultPolicy[V]) processItems() {
for {
select {
case items := <-p.itemsCh:
Expand All @@ -109,7 +109,7 @@ func (p *defaultPolicy) processItems() {
}
}

func (p *defaultPolicy) Push(keys []uint64) bool {
func (p *defaultPolicy[V]) Push(keys []uint64) bool {
if p.isClosed {
return false
}
Expand All @@ -131,7 +131,7 @@ func (p *defaultPolicy) Push(keys []uint64) bool {
// Add decides whether the item with the given key and cost should be accepted by
// the policy. It returns the list of victims that have been evicted and a boolean
// indicating whether the incoming item should be accepted.
func (p *defaultPolicy) Add(key uint64, cost int64) ([]*Item, bool) {
func (p *defaultPolicy[V]) Add(key uint64, cost int64) ([]*Item[V], bool) {
p.Lock()
defer p.Unlock()

Expand Down Expand Up @@ -165,7 +165,7 @@ func (p *defaultPolicy) Add(key uint64, cost int64) ([]*Item, bool) {
// O(lg N).
sample := make([]*policyPair, 0, lfuSample)
// As items are evicted they will be appended to victims.
victims := make([]*Item, 0)
victims := make([]*Item[V], 0)

// Delete victims until there's enough space or a minKey is found that has
// more hits than incoming item.
Expand Down Expand Up @@ -195,7 +195,7 @@ func (p *defaultPolicy) Add(key uint64, cost int64) ([]*Item, bool) {
sample[minId] = sample[len(sample)-1]
sample = sample[:len(sample)-1]
// Store victim in evicted victims slice.
victims = append(victims, &Item{
victims = append(victims, &Item[V]{
Key: minKey,
Conflict: 0,
Cost: minCost,
Expand All @@ -207,33 +207,33 @@ func (p *defaultPolicy) Add(key uint64, cost int64) ([]*Item, bool) {
return victims, true
}

func (p *defaultPolicy) Has(key uint64) bool {
func (p *defaultPolicy[V]) Has(key uint64) bool {
p.Lock()
_, exists := p.evict.keyCosts[key]
p.Unlock()
return exists
}

func (p *defaultPolicy) Del(key uint64) {
func (p *defaultPolicy[V]) Del(key uint64) {
p.Lock()
p.evict.del(key)
p.Unlock()
}

func (p *defaultPolicy) Cap() int64 {
func (p *defaultPolicy[V]) Cap() int64 {
p.Lock()
capacity := p.evict.getMaxCost() - p.evict.used
p.Unlock()
return capacity
}

func (p *defaultPolicy) Update(key uint64, cost int64) {
func (p *defaultPolicy[V]) Update(key uint64, cost int64) {
p.Lock()
p.evict.updateIfHas(key, cost)
p.Unlock()
}

func (p *defaultPolicy) Cost(key uint64) int64 {
func (p *defaultPolicy[V]) Cost(key uint64) int64 {
p.Lock()
if cost, found := p.evict.keyCosts[key]; found {
p.Unlock()
Expand All @@ -243,14 +243,14 @@ func (p *defaultPolicy) Cost(key uint64) int64 {
return -1
}

func (p *defaultPolicy) Clear() {
func (p *defaultPolicy[V]) Clear() {
p.Lock()
p.admit.clear()
p.evict.clear()
p.Unlock()
}

func (p *defaultPolicy) Close() {
func (p *defaultPolicy[V]) Close() {
if p.isClosed {
return
}
Expand All @@ -262,14 +262,14 @@ func (p *defaultPolicy) Close() {
p.isClosed = true
}

func (p *defaultPolicy) MaxCost() int64 {
func (p *defaultPolicy[V]) MaxCost() int64 {
if p == nil || p.evict == nil {
return 0
}
return p.evict.getMaxCost()
}

func (p *defaultPolicy) UpdateMaxCost(maxCost int64) {
func (p *defaultPolicy[V]) UpdateMaxCost(maxCost int64) {
if p == nil || p.evict == nil {
return
}
Expand Down
28 changes: 14 additions & 14 deletions policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@ func TestPolicy(t *testing.T) {
defer func() {
require.Nil(t, recover())
}()
newPolicy(100, 10)
newPolicy[int](100, 10)
}

func TestPolicyMetrics(t *testing.T) {
p := newDefaultPolicy(100, 10)
p := newDefaultPolicy[int](100, 10)
p.CollectMetrics(newMetrics())
require.NotNil(t, p.metrics)
require.NotNil(t, p.evict.metrics)
}

func TestPolicyProcessItems(t *testing.T) {
p := newDefaultPolicy(100, 10)
p := newDefaultPolicy[int](100, 10)
p.itemsCh <- []uint64{1, 2, 2}
time.Sleep(wait)
p.Lock()
Expand All @@ -39,7 +39,7 @@ func TestPolicyProcessItems(t *testing.T) {
}

func TestPolicyPush(t *testing.T) {
p := newDefaultPolicy(100, 10)
p := newDefaultPolicy[int](100, 10)
require.True(t, p.Push([]uint64{}))

keepCount := 0
Expand All @@ -52,7 +52,7 @@ func TestPolicyPush(t *testing.T) {
}

func TestPolicyAdd(t *testing.T) {
p := newDefaultPolicy(1000, 100)
p := newDefaultPolicy[int](1000, 100)
if victims, added := p.Add(1, 101); victims != nil || added {
t.Fatal("can't add an item bigger than entire cache")
}
Expand Down Expand Up @@ -81,14 +81,14 @@ func TestPolicyAdd(t *testing.T) {
}

func TestPolicyHas(t *testing.T) {
p := newDefaultPolicy(100, 10)
p := newDefaultPolicy[int](100, 10)
p.Add(1, 1)
require.True(t, p.Has(1))
require.False(t, p.Has(2))
}

func TestPolicyDel(t *testing.T) {
p := newDefaultPolicy(100, 10)
p := newDefaultPolicy[int](100, 10)
p.Add(1, 1)
p.Del(1)
p.Del(2)
Expand All @@ -97,13 +97,13 @@ func TestPolicyDel(t *testing.T) {
}

func TestPolicyCap(t *testing.T) {
p := newDefaultPolicy(100, 10)
p := newDefaultPolicy[int](100, 10)
p.Add(1, 1)
require.Equal(t, int64(9), p.Cap())
}

func TestPolicyUpdate(t *testing.T) {
p := newDefaultPolicy(100, 10)
p := newDefaultPolicy[int](100, 10)
p.Add(1, 1)
p.Update(1, 2)
p.Lock()
Expand All @@ -112,14 +112,14 @@ func TestPolicyUpdate(t *testing.T) {
}

func TestPolicyCost(t *testing.T) {
p := newDefaultPolicy(100, 10)
p := newDefaultPolicy[int](100, 10)
p.Add(1, 2)
require.Equal(t, int64(2), p.Cost(1))
require.Equal(t, int64(-1), p.Cost(2))
}

func TestPolicyClear(t *testing.T) {
p := newDefaultPolicy(100, 10)
p := newDefaultPolicy[int](100, 10)
p.Add(1, 1)
p.Add(2, 2)
p.Add(3, 3)
Expand All @@ -135,20 +135,20 @@ func TestPolicyClose(t *testing.T) {
require.NotNil(t, recover())
}()

p := newDefaultPolicy(100, 10)
p := newDefaultPolicy[int](100, 10)
p.Add(1, 1)
p.Close()
p.itemsCh <- []uint64{1}
}

func TestPushAfterClose(t *testing.T) {
p := newDefaultPolicy(100, 10)
p := newDefaultPolicy[int](100, 10)
p.Close()
require.False(t, p.Push([]uint64{1, 2}))
}

func TestAddAfterClose(t *testing.T) {
p := newDefaultPolicy(100, 10)
p := newDefaultPolicy[int](100, 10)
p.Close()
p.Add(1, 1)
}
Expand Down
Loading

0 comments on commit e2027d3

Please sign in to comment.