Skip to content

Commit

Permalink
feat(ristretto): add configurable synchronous write option
Browse files Browse the repository at this point in the history
Signed-off-by: Andika Ahmad Ramadhan <andikahmadr@gmail.com>
  • Loading branch information
kmdrn7 committed Nov 23, 2023
1 parent fb1459c commit 0fcb134
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 3 deletions.
9 changes: 9 additions & 0 deletions lib/store/options.go
Expand Up @@ -8,6 +8,7 @@ import (
type Option func(o *Options)

type Options struct {
SynchronousSet bool
Cost int64
Expiration time.Duration
Tags []string
Expand Down Expand Up @@ -47,6 +48,14 @@ func WithCost(cost int64) Option {
}
}

// WithSynchronousSet allows setting the behavior when setting a value, whether to wait until all buffered writes have been applied or not.
// Currently to be used by Ristretto library only.
func WithSynchronousSet() Option {
return func(o *Options) {
o.SynchronousSet = true
}
}

// WithExpiration allows to specify an expiration time when setting a value.
func WithExpiration(expiration time.Duration) Option {
return func(o *Options) {
Expand Down
5 changes: 5 additions & 0 deletions store/ristretto/ristretto.go
Expand Up @@ -23,6 +23,7 @@ type RistrettoClientInterface interface {
SetWithTTL(key, value any, cost int64, ttl time.Duration) bool
Del(key any)
Clear()
Wait()
}

// RistrettoStore is a store for Ristretto (memory) library
Expand Down Expand Up @@ -71,6 +72,10 @@ func (s *RistrettoStore) Set(ctx context.Context, key any, value any, options ..
return err
}

if opts.SynchronousSet {
s.client.Wait()
}

if tags := opts.Tags; len(tags) > 0 {
s.setTags(ctx, key, tags)
}
Expand Down
32 changes: 29 additions & 3 deletions store/ristretto/ristretto_bench_test.go
Expand Up @@ -21,7 +21,33 @@ func BenchmarkRistrettoSet(b *testing.B) {
if err != nil {
panic(err)
}
store := NewRistretto(client, nil)
store := NewRistretto(client)

for k := 0.; k <= 10; k++ {
n := int(math.Pow(2, k))
b.Run(fmt.Sprintf("%d", n), func(b *testing.B) {
for i := 0; i < b.N*n; i++ {
key := fmt.Sprintf("test-%d", n)
value := []byte(fmt.Sprintf("value-%d", n))

store.Set(ctx, key, value, lib_store.WithTags([]string{fmt.Sprintf("tag-%d", n)}))
}
})
}
}

func BenchmarkRistrettoSetWithSynchronousSet(b *testing.B) {
ctx := context.Background()

client, err := ristretto.NewCache(&ristretto.Config{
NumCounters: 1000,
MaxCost: 100,
BufferItems: 64,
})
if err != nil {
panic(err)
}
store := NewRistretto(client, lib_store.WithSynchronousSet())

for k := 0.; k <= 10; k++ {
n := int(math.Pow(2, k))
Expand All @@ -47,12 +73,12 @@ func BenchmarkRistrettoGet(b *testing.B) {
if err != nil {
panic(err)
}
store := NewRistretto(client, nil)
store := NewRistretto(client)

key := "test"
value := []byte("value")

store.Set(ctx, key, value, nil)
store.Set(ctx, key, value)

for k := 0.; k <= 10; k++ {
n := int(math.Pow(2, k))
Expand Down
12 changes: 12 additions & 0 deletions store/ristretto/ristretto_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions store/ristretto/ristretto_test.go
Expand Up @@ -177,6 +177,28 @@ func TestRistrettoSetWhenError(t *testing.T) {
assert.Equal(t, fmt.Errorf("An error has occurred while setting value '%v' on key '%v'", cacheValue, cacheKey), err)
}

func TestRistrettoSetWithSynchronousSet(t *testing.T) {
// Given
ctrl := gomock.NewController(t)

ctx := context.Background()

cacheKey := "my-key"
cacheValue := []byte("my-cache-value")

client := NewMockRistrettoClientInterface(ctrl)
client.EXPECT().SetWithTTL(cacheKey, cacheValue, int64(7), 0*time.Second).Return(true)
client.EXPECT().Wait()

store := NewRistretto(client, lib_store.WithCost(7), lib_store.WithSynchronousSet())

// When
err := store.Set(ctx, cacheKey, cacheValue, lib_store.WithSynchronousSet())

// Then
assert.Nil(t, err)
}

func TestRistrettoSetWithTags(t *testing.T) {
// Given
ctrl := gomock.NewController(t)
Expand Down

0 comments on commit 0fcb134

Please sign in to comment.