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

feat(ARCO-283): remove freecache, combine methods with cache implementation #643

Merged
merged 26 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
137a106
feat(ARCO-283): remove freecache, combine methods with cache implemen…
pawellewandowski98 Nov 13, 2024
71ab858
fix(ARCO-283): fix linter error
pawellewandowski98 Nov 13, 2024
d80f8fb
refactor(ARCO-283): use struct instead of plain map
pawellewandowski98 Nov 13, 2024
ccc9822
feat(ARCO-283): clear cache after update
pawellewandowski98 Nov 13, 2024
eb6b402
feat(ARCO-283): add in memory cache
pawellewandowski98 Nov 13, 2024
9a3056e
fix(ARCO-283): fix linter errors
pawellewandowski98 Nov 13, 2024
9c85066
fix(ARCO-283): fix PR comments
pawellewandowski98 Nov 13, 2024
485328c
refactor(ARCO-283): use sync map in memory cache
pawellewandowski98 Nov 14, 2024
f49c7ab
test(ARCO-283): fix unit tests
pawellewandowski98 Nov 14, 2024
c3f74ba
feat(ARCO-283): save separate transactions in cache
pawellewandowski98 Nov 14, 2024
b157306
fix(ARCO-283): fix build and linter errors
pawellewandowski98 Nov 14, 2024
b37d5ee
feat(ARCO-283): add option to store data in cache for one hash
pawellewandowski98 Nov 15, 2024
44f425f
chore(ARCO-283): remove unused code
pawellewandowski98 Nov 15, 2024
6019cef
chore(ARCO-283): remove log
pawellewandowski98 Nov 15, 2024
6996f76
feat(ARCO-283): add transaction for redis operations
pawellewandowski98 Nov 19, 2024
00495df
chore(ARCO-283): check if key exists when counting records
pawellewandowski98 Nov 19, 2024
73fdadc
chore(ARCO-283): remove clear cache
pawellewandowski98 Nov 19, 2024
1988ea3
feat(ARCO-283): split cache methods
pawellewandowski98 Nov 20, 2024
b94b62c
refactor(ARCO-283): refactor in-memory cache method
pawellewandowski98 Nov 20, 2024
15b03a7
fix(ARCO-283): fix PR comments
pawellewandowski98 Nov 21, 2024
81a6db1
test(ARCO-283): add Redis integration tests
pawellewandowski98 Nov 21, 2024
3f95b2b
fix(ARCO-283): fix linter error
pawellewandowski98 Nov 21, 2024
f633e42
test(ARCO-283): fix Redis test
pawellewandowski98 Nov 21, 2024
7158db0
fix(ARCO-283): update status in cache only when bigger
pawellewandowski98 Nov 22, 2024
fc19ee8
fix(ARCO-283): fix PR comments
pawellewandowski98 Nov 22, 2024
4fcc557
fix(ARCO-283): fix linter error
pawellewandowski98 Nov 22, 2024
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
6 changes: 2 additions & 4 deletions cmd/arc/services/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"github.com/bitcoin-sv/arc/internal/cache"

"github.com/bitcoin-sv/arc/config"
"github.com/coocood/freecache"
"github.com/go-redis/redis/v8"
)

Expand All @@ -15,9 +14,8 @@ var ErrCacheUnknownType = errors.New("unknown cache type")
// NewCacheStore creates a new CacheStore based on the provided configuration.
func NewCacheStore(cacheConfig *config.CacheConfig) (cache.Store, error) {
switch cacheConfig.Engine {
case config.FreeCache:
cacheSize := freecache.NewCache(cacheConfig.Freecache.Size)
return cache.NewFreecacheStore(cacheSize), nil
case config.InMemory:
return cache.NewMemoryStore(), nil
case config.Redis:
c := redis.NewClient(&redis.Options{
Addr: cacheConfig.Redis.Addr,
Expand Down
9 changes: 4 additions & 5 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (
)

const (
FreeCache = "freecache"
Redis = "redis"
InMemory = "in-memory"
Redis = "redis"
)

type ArcConfig struct {
Expand Down Expand Up @@ -137,9 +137,8 @@ type PostgresConfig struct {
}

type CacheConfig struct {
Engine string `mapstructure:"engine"`
Freecache *FreeCacheConfig `mapstructure:"freecache"`
Redis *RedisConfig `mapstructure:"redis"`
Engine string `mapstructure:"engine"`
Redis *RedisConfig `mapstructure:"redis"`
}

type FreeCacheConfig struct {
Expand Down
7 changes: 2 additions & 5 deletions config/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,8 @@ func getCallbackerConfig() *CallbackerConfig {

func getCacheConfig() *CacheConfig {
return &CacheConfig{
Engine: FreeCache,
Freecache: &FreeCacheConfig{
Size: 10 * 1024 * 1024, // Default size 10MB.
},
Redis: &RedisConfig{
Engine: InMemory, // use in memory cache
Redis: &RedisConfig{ // example of Redis config
Addr: "localhost:6379",
Password: "",
DB: 0,
Expand Down
6 changes: 2 additions & 4 deletions config/example_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,8 @@ broadcasting: # settings for connection to nodes
p2p: 18335

cache:
engine: freecache # cache engine - one of freecache | redis
freecache: # freecache configuration
size: 10000000 # size of cache
redis:
engine: redis # cache engine - in-memory/redis
redis: # redis cache configuration in case that engine: redis
addr: "localhost:6379"
password: ""
db: 1
Expand Down
20 changes: 15 additions & 5 deletions internal/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,24 @@ import (
)

var (
ErrCacheNotFound = errors.New("key not found in cache")
ErrCacheFailedToSet = errors.New("failed to set value in cache")
ErrCacheFailedToDel = errors.New("failed to delete value from cache")
ErrCacheFailedToGet = errors.New("failed to get value from cache")
ErrCacheNotFound = errors.New("key not found in cache")
ErrCacheFailedToSet = errors.New("failed to set value in cache")
ErrCacheFailedToDel = errors.New("failed to delete value from cache")
ErrCacheFailedToGet = errors.New("failed to get value from cache")
ErrCacheFailedToScan = errors.New("failed to scan cache")
ErrCacheFailedToGetCount = errors.New("failed to get count from cache")
ErrCacheFailedToExecuteTx = errors.New("failed to execute transaction")
)

type Store interface {
Get(key string) ([]byte, error)
Set(key string, value []byte, ttl time.Duration) error
Del(key string) error
Del(keys ...string) error

MapGet(hashsetKey string, field string) ([]byte, error)
MapGetAll(hashsetKey string) (map[string][]byte, error)
MapSet(hashsetKey string, field string, value []byte) error
MapDel(hashsetKey string, fields ...string) error
MapLen(hashsetKey string) (int64, error)
MapExtractAll(hashsetKey string) (map[string][]byte, error)
}
50 changes: 0 additions & 50 deletions internal/cache/freecache.go

This file was deleted.

142 changes: 142 additions & 0 deletions internal/cache/in_memory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package cache

import (
"errors"
"sync"
"time"
)

type MemoryStore struct {
data sync.Map
}

func NewMemoryStore() *MemoryStore {
return &MemoryStore{}
}

// Get retrieves a value by key.
func (s *MemoryStore) Get(key string) ([]byte, error) {
value, found := s.data.Load(key)
if !found {
return nil, ErrCacheNotFound
}

bytes, ok := value.([]byte)
if !ok {
return nil, ErrCacheFailedToGet
}

return bytes, nil
}

// Set stores a key-value pair, ignoring the ttl parameter.
func (s *MemoryStore) Set(key string, value []byte, _ time.Duration) error {
s.data.Store(key, value)
return nil
}

// Del removes a key from the store.
func (s *MemoryStore) Del(keys ...string) error {
for _, k := range keys {
s.data.Delete(k)
}
return nil
}

// MapGet retrieves a value by key and hashsetKey. Return err if hashsetKey or key not found.
func (s *MemoryStore) MapGet(hashsetKey string, key string) ([]byte, error) {
hashValue, found := s.data.Load(hashsetKey)
if !found {
return nil, ErrCacheNotFound
}

hashMap, ok := hashValue.(map[string][]byte)
if !ok {
return nil, ErrCacheFailedToGet
}

fieldValue, exists := hashMap[key]
if !exists {
return nil, ErrCacheNotFound
}

return fieldValue, nil
}

// MapSet stores a key-value pair for specific hashsetKey.
func (s *MemoryStore) MapSet(hashsetKey string, key string, value []byte) error {
raw, _ := s.data.LoadOrStore(hashsetKey, make(map[string][]byte))

hashMap, ok := raw.(map[string][]byte)
if !ok {
return ErrCacheFailedToSet
}

hashMap[key] = value

s.data.Store(hashsetKey, hashMap)
return nil
}

// MapDel removes a value by key in specific hashsetKey.
func (s *MemoryStore) MapDel(hashsetKey string, keys ...string) error {
hashValue, found := s.data.Load(hashsetKey)
if !found {
return ErrCacheNotFound
}

hashMap, ok := hashValue.(map[string][]byte)
if !ok {
return errors.Join(ErrCacheFailedToDel, ErrCacheFailedToGet)
}

for _, k := range keys {
delete(hashMap, k)
}

s.data.Store(hashsetKey, hashMap)
return nil
}

// MapGetAll retrieves all key-value pairs for a specific hashsetKey. Return err if hashsetKey not found.
func (s *MemoryStore) MapGetAll(hashsetKey string) (map[string][]byte, error) {
hashValue, found := s.data.Load(hashsetKey)
if !found {
return nil, ErrCacheNotFound
}

hashMap, ok := hashValue.(map[string][]byte)
if !ok {
return nil, ErrCacheFailedToGet
}

return hashMap, nil
}

// MapExtractAll retrieves all key-value pairs for a specific hashsetKey and deletes the hashsetKey. Return err if hashsetKey not found.
func (s *MemoryStore) MapExtractAll(hashsetKey string) (map[string][]byte, error) {
hashValue, found := s.data.LoadAndDelete(hashsetKey)
if !found {
return nil, ErrCacheNotFound
}

hashMap, ok := hashValue.(map[string][]byte)
if !ok {
return nil, ErrCacheFailedToGet
}

return hashMap, nil
}

// MapLen returns the number of elements in a hashsetKey in memory.
func (s *MemoryStore) MapLen(hashsetKey string) (int64, error) {
hashMap, err := s.MapGetAll(hashsetKey)
if err != nil {
if errors.Is(err, ErrCacheNotFound) {
return 0, nil
}
return 0, err
}

return int64(len(hashMap)), nil
}
Loading