Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BREAKING] support generic API #321

Merged
merged 29 commits into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
fe3efab
add generics.
aryehlev Nov 25, 2022
4e36ce4
change module name.
aryehlev Nov 25, 2022
bd7c08e
ecxport key type
aryehlev Nov 25, 2022
f92fd57
changeName
aryehlev Nov 25, 2022
40b7ca8
fix nils and make key type comparable.
aryehlev Nov 25, 2022
f1fb7b7
change nils
aryehlev Nov 25, 2022
8ec1534
try cahnge 1
aryehlev Nov 25, 2022
d388a7e
replace names and fix tests to work with generics.
aryehlev Dec 11, 2022
e3ec3dc
Merge remote-tracking branch 'origin/main'
aryehlev Mar 21, 2023
25500b8
fix comments on PR and also fix KeyToHash to be able to deal with nils .
aryehlev Mar 21, 2023
fc1ddb8
remove random change and make version go 1.19 fo performance.
aryehlev Mar 21, 2023
fd222a1
set the keyToHash function.
aryehlev Mar 25, 2023
23c117a
change keyToHash function to take K type
aryehlev Aug 31, 2023
7c98d35
merge cache.go
aryehlev Aug 31, 2023
cf986a0
merge policy.go
aryehlev Aug 31, 2023
4ef9df4
merge ttl.go
aryehlev Aug 31, 2023
6a17a19
Merge remote-tracking branch 'originFar/main'
aryehlev Aug 31, 2023
a8fffe8
resolve merge changes.
aryehlev Aug 31, 2023
e656080
merge cache_test.go.
aryehlev Aug 31, 2023
0d4debf
fix lint ci.
aryehlev Aug 31, 2023
2af8be1
align tests.
aryehlev Aug 31, 2023
ad223b0
Merge remote-tracking branch 'originFar/main'
aryehlev Sep 1, 2023
d59bbcf
put back regular config.KeyToHash.
aryehlev Sep 1, 2023
0a3c1dc
if key to hash isnt working return error instead of fatal.
aryehlev Sep 1, 2023
a052959
Merge remote-tracking branch 'originFar/main'
aryehlev Sep 1, 2023
91a06d8
merge with main.
aryehlev Sep 1, 2023
d2fba36
fix comment spacing.
aryehlev Sep 4, 2023
f7faa68
put keyToHash without function getter.
aryehlev Sep 4, 2023
e5e54ea
fix typo.
aryehlev Sep 4, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 90 additions & 78 deletions cache.go

Large diffs are not rendered by default.

253 changes: 127 additions & 126 deletions cache_test.go

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion contrib/demo/node_allocator.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build jemalloc && allocator
// +build jemalloc,allocator

package main
Expand All @@ -10,7 +11,7 @@ import (

// Defined in node.go.
func init() {
alloc = z.NewAllocator(10 << 20, "demo")
alloc = z.NewAllocator(10<<20, "demo")
}

func newNode(val int) *node {
Expand Down
1 change: 1 addition & 0 deletions contrib/demo/node_jemalloc.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build jemalloc && !allocator
// +build jemalloc,!allocator

package main
Expand Down
3 changes: 2 additions & 1 deletion contrib/memtest/withjemalloc.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//+build jemalloc
//go:build jemalloc
// +build jemalloc

package main

Expand Down
9 changes: 7 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
module github.com/dgraph-io/ristretto

go 1.12
go 1.19

require (
github.com/cespare/xxhash/v2 v2.1.1
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2
github.com/dustin/go-humanize v1.0.0
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.4.0
golang.org/x/sys v0.0.0-20221010170243-090e33056c14
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v2 v2.2.2 // indirect
)
47 changes: 24 additions & 23 deletions policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,14 @@ 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 {
//
// are probably only going to use/implement/maintain one policy.
mangalaman93 marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -62,11 +63,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 @@ -76,8 +77,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 @@ -87,7 +88,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 @@ -97,7 +98,7 @@ type policyPair struct {
cost int64
}

func (p *defaultPolicy) processItems() {
func (p *defaultPolicy[V]) processItems() {
for {
select {
case items := <-p.itemsCh:
Expand All @@ -110,7 +111,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 @@ -132,7 +133,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 @@ -166,7 +167,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 @@ -196,7 +197,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 @@ -208,33 +209,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 := int64(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 @@ -244,14 +245,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 @@ -263,14 +264,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
2 changes: 1 addition & 1 deletion sketch.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func (r cmRow) reset() {
}

func (r cmRow) clear() {
// Zero each counter.
// zero each counter.
for i := range r {
r[i] = 0
}
Expand Down
Loading