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

[Ristretto Store] Add configurable synchronous write option #231

Merged
merged 1 commit into from Dec 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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