Skip to content

Commit

Permalink
Merge pull request #252 from semihbkgr/accept-hz-map
Browse files Browse the repository at this point in the history
Create Hazelcast store from map instance
  • Loading branch information
eko authored Jun 14, 2024
2 parents 6d59150 + e5f543b commit 78b7afe
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 68 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,12 @@ if err != nil {
log.Fatalf("Failed to start client: %v", err)
}

hzMapName:= "gocache"
hzMap, err := hzClient.GetMap(ctx, "gocache")
if err != nil {
b.Fatalf("Failed to get map: %v", err)
}

hazelcastStore := hazelcast_store.NewHazelcast(hzClient, hzMapName)
hazelcastStore := hazelcast_store.NewHazelcast(hzMap)

cacheManager := cache.New[string](hazelcastStore)
err := cacheManager.Set(ctx, "my-key", "my-value", store.WithExpiration(15*time.Second))
Expand Down
65 changes: 13 additions & 52 deletions store/hazelcast/hazelcast.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"time"

lib_store "github.com/eko/gocache/lib/v4/store"
"github.com/hazelcast/hazelcast-go-client"
"github.com/hazelcast/hazelcast-go-client/types"
"golang.org/x/sync/errgroup"
)
Expand All @@ -22,8 +21,6 @@ type HazelcastMapInterface interface {
Clear(ctx context.Context) error
}

type HazelcastMapInterfaceProvider func(ctx context.Context) (HazelcastMapInterface, error)

const (
// HazelcastType represents the storage type as a string value
HazelcastType = "hazelcast"
Expand All @@ -35,37 +32,21 @@ const (

// HazelcastStore is a store for Hazelcast
type HazelcastStore struct {
mapProvider HazelcastMapInterfaceProvider
options *lib_store.Options
hzMap HazelcastMapInterface
options *lib_store.Options
}

// NewHazelcast creates a new store to Hazelcast instance(s)
func NewHazelcast(hzClient *hazelcast.Client, mapName string, options ...lib_store.Option) *HazelcastStore {
return &HazelcastStore{
mapProvider: func(ctx context.Context) (HazelcastMapInterface, error) {
return hzClient.GetMap(ctx, mapName)
},
options: lib_store.ApplyOptions(options...),
}
}

// newHazelcast creates a new store with given HazelcastMapInterface for test purpose
func newHazelcast(hzMap HazelcastMapInterface, options ...lib_store.Option) *HazelcastStore {
func NewHazelcast(hzMap HazelcastMapInterface, options ...lib_store.Option) *HazelcastStore {
return &HazelcastStore{
mapProvider: func(ctx context.Context) (HazelcastMapInterface, error) {
return hzMap, nil
},
hzMap: hzMap,
options: lib_store.ApplyOptions(options...),
}
}

// Get returns data stored from a given key
func (s *HazelcastStore) Get(ctx context.Context, key any) (any, error) {
hzMap, err := s.mapProvider(ctx)
if err != nil {
return nil, err
}
value, err := hzMap.Get(ctx, key)
value, err := s.hzMap.Get(ctx, key)
if err != nil {
return nil, err
}
Expand All @@ -77,11 +58,7 @@ func (s *HazelcastStore) Get(ctx context.Context, key any) (any, error) {

// GetWithTTL returns data stored from a given key and its corresponding TTL
func (s *HazelcastStore) GetWithTTL(ctx context.Context, key any) (any, time.Duration, error) {
hzMap, err := s.mapProvider(ctx)
if err != nil {
return nil, 0, err
}
entryView, err := hzMap.GetEntryView(ctx, key)
entryView, err := s.hzMap.GetEntryView(ctx, key)
if err != nil {
return nil, 0, err
}
Expand All @@ -94,16 +71,12 @@ func (s *HazelcastStore) GetWithTTL(ctx context.Context, key any) (any, time.Dur
// Set defines data in Hazelcast for given key identifier
func (s *HazelcastStore) Set(ctx context.Context, key any, value any, options ...lib_store.Option) error {
opts := lib_store.ApplyOptionsWithDefault(s.options, options...)
hzMap, err := s.mapProvider(ctx)
if err != nil {
return err
}
err = hzMap.SetWithTTL(ctx, key, value, opts.Expiration)
err := s.hzMap.SetWithTTL(ctx, key, value, opts.Expiration)
if err != nil {
return err
}
if tags := opts.Tags; len(tags) > 0 {
s.setTags(ctx, hzMap, key, tags)
s.setTags(ctx, s.hzMap, key, tags)
}
return nil
}
Expand Down Expand Up @@ -137,45 +110,33 @@ func (s *HazelcastStore) setTags(ctx context.Context, hzMap HazelcastMapInterfac

// Delete removes data from Hazelcast for given key identifier
func (s *HazelcastStore) Delete(ctx context.Context, key any) error {
hzMap, err := s.mapProvider(ctx)
if err != nil {
return err
}
_, err = hzMap.Remove(ctx, key)
_, err := s.hzMap.Remove(ctx, key)
return err
}

// Invalidate invalidates some cache data in Hazelcast for given options
func (s *HazelcastStore) Invalidate(ctx context.Context, options ...lib_store.InvalidateOption) error {
opts := lib_store.ApplyInvalidateOptions(options...)
if tags := opts.Tags; len(tags) > 0 {
hzMap, err := s.mapProvider(ctx)
if err != nil {
return err
}
for _, tag := range tags {
tagKey := fmt.Sprintf(HazelcastTagPattern, tag)
tagValue, err := hzMap.Get(ctx, tagKey)
tagValue, err := s.hzMap.Get(ctx, tagKey)
if err != nil || tagValue == nil {
continue
}
cacheKeys := strings.Split(tagValue.(string), ",")
for _, cacheKey := range cacheKeys {
hzMap.Remove(ctx, cacheKey)
s.hzMap.Remove(ctx, cacheKey)
}
hzMap.Remove(ctx, tagKey)
s.hzMap.Remove(ctx, tagKey)
}
}
return nil
}

// Clear resets all data in the store
func (s *HazelcastStore) Clear(ctx context.Context) error {
hzMap, err := s.mapProvider(ctx)
if err != nil {
return err
}
return hzMap.Clear(ctx)
return s.hzMap.Clear(ctx)
}

// GetType returns the store type
Expand Down
14 changes: 12 additions & 2 deletions store/hazelcast/hazelcast_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ func BenchmarkHazelcastSet(b *testing.B) {
b.Fatalf("Failed to start client: %v", err)
}

store := NewHazelcast(hzClient, "gocache")
hzMap, err := hzClient.GetMap(ctx, "gocache")
if err != nil {
b.Fatalf("Failed to get map: %v", err)
}

store := NewHazelcast(hzMap)

for k := 0.; k <= 10; k++ {
n := int(math.Pow(2, k))
Expand All @@ -40,7 +45,12 @@ func BenchmarkHazelcastGet(b *testing.B) {
b.Fatalf("Failed to start client: %v", err)
}

store := NewHazelcast(hzClient, "gocache")
hzMap, err := hzClient.GetMap(ctx, "gocache")
if err != nil {
b.Fatalf("Failed to get map: %v", err)
}

store := NewHazelcast(hzMap)

key := "test"
value := []byte("value")
Expand Down
26 changes: 14 additions & 12 deletions store/hazelcast/hazelcast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ import (

func TestNewHazelcast(t *testing.T) {
// Given
mapName := "gocache"
ctrl := gomock.NewController(t)

hzMap := NewMockHazelcastMapInterface(ctrl)

// When
store := NewHazelcast(nil, mapName, lib_store.WithExpiration(6*time.Second))
store := NewHazelcast(hzMap, lib_store.WithExpiration(6*time.Second))

// Then
assert.IsType(t, new(HazelcastStore), store)
assert.NotNil(t, store.mapProvider)
assert.Equal(t, hzMap, store.hzMap)
assert.Equal(t, &lib_store.Options{Expiration: 6 * time.Second}, store.options)
}

Expand All @@ -33,7 +35,7 @@ func TestHazelcastGet(t *testing.T) {
hzMap := NewMockHazelcastMapInterface(ctrl)
hzMap.EXPECT().Get(ctx, "my-key").Return("my-value", nil)

store := newHazelcast(hzMap)
store := NewHazelcast(hzMap)

// When
value, err := store.Get(ctx, "my-key")
Expand All @@ -55,7 +57,7 @@ func TestHazelcastSet(t *testing.T) {
hzMap := NewMockHazelcastMapInterface(ctrl)
hzMap.EXPECT().SetWithTTL(ctx, cacheKey, cacheValue, 5*time.Second).Return(nil)

store := newHazelcast(hzMap, lib_store.WithExpiration(6*time.Second))
store := NewHazelcast(hzMap, lib_store.WithExpiration(6*time.Second))

// When
err := store.Set(ctx, cacheKey, cacheValue, lib_store.WithExpiration(5*time.Second))
Expand All @@ -76,7 +78,7 @@ func TestHazelcastSetWhenNoOptionsGiven(t *testing.T) {
hzMap := NewMockHazelcastMapInterface(ctrl)
hzMap.EXPECT().SetWithTTL(ctx, cacheKey, cacheValue, 6*time.Second).Return(nil)

store := newHazelcast(hzMap, lib_store.WithExpiration(6*time.Second))
store := NewHazelcast(hzMap, lib_store.WithExpiration(6*time.Second))

// When
err := store.Set(ctx, cacheKey, cacheValue)
Expand All @@ -99,7 +101,7 @@ func TestHazelcastSetWithTags(t *testing.T) {
hzMap.EXPECT().SetWithTTL(gomock.Any(), "gocache_tag_tag1", cacheKey, TagKeyExpiry).Return(nil)
hzMap.EXPECT().Get(gomock.Any(), "gocache_tag_tag1").Return(nil, nil)

store := newHazelcast(hzMap)
store := NewHazelcast(hzMap)

// When
err := store.Set(ctx, cacheKey, cacheValue, lib_store.WithTags([]string{"tag1"}))
Expand All @@ -119,7 +121,7 @@ func TestHazelcastDelete(t *testing.T) {
hzMap := NewMockHazelcastMapInterface(ctrl)
hzMap.EXPECT().Remove(ctx, "my-key").Return(0, nil)

store := newHazelcast(hzMap)
store := NewHazelcast(hzMap)

// When
err := store.Delete(ctx, cacheKey)
Expand All @@ -137,7 +139,7 @@ func TestHazelcastInvalidate(t *testing.T) {
hzMap := NewMockHazelcastMapInterface(ctrl)
hzMap.EXPECT().Get(ctx, "gocache_tag_tag1").Return(nil, nil)

store := newHazelcast(hzMap)
store := NewHazelcast(hzMap)

// When
err := store.Invalidate(ctx, lib_store.WithInvalidateTags([]string{"tag1"}))
Expand All @@ -161,7 +163,7 @@ func TestHazelcastInvalidateWhenCacheKeysExist(t *testing.T) {
hzMap.EXPECT().Remove(ctx, "my-key2").Return("my-value2", nil)
hzMap.EXPECT().Remove(ctx, "gocache_tag_tag1").Return(cacheKeys, nil)

store := newHazelcast(hzMap)
store := NewHazelcast(hzMap)

// When
err := store.Invalidate(ctx, lib_store.WithInvalidateTags([]string{"tag1"}))
Expand All @@ -179,7 +181,7 @@ func TestHazelcastClear(t *testing.T) {
hzMap := NewMockHazelcastMapInterface(ctrl)
hzMap.EXPECT().Clear(ctx).Return(nil)

store := newHazelcast(hzMap, lib_store.WithExpiration(6*time.Second))
store := NewHazelcast(hzMap, lib_store.WithExpiration(6*time.Second))

// When
err := store.Clear(ctx)
Expand All @@ -194,7 +196,7 @@ func TestHazelcastType(t *testing.T) {

hzMap := NewMockHazelcastMapInterface(ctrl)

store := newHazelcast(hzMap)
store := NewHazelcast(hzMap)

// When - Then
assert.Equal(t, HazelcastType, store.GetType())
Expand Down

0 comments on commit 78b7afe

Please sign in to comment.