From f43cf5a4a65131e27c1513903a63ce7f25137bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Lewandowski?= Date: Wed, 20 Nov 2024 10:06:51 +0100 Subject: [PATCH] feat(ARCO-283): split cache methods --- internal/cache/cache.go | 16 ++-- internal/cache/in_memory.go | 121 ++++++++++++------------ internal/cache/redis.go | 84 +++++++++------- internal/metamorph/processor_helpers.go | 8 +- 4 files changed, 127 insertions(+), 102 deletions(-) diff --git a/internal/cache/cache.go b/internal/cache/cache.go index 5c8ab9034..f3b09ef3e 100644 --- a/internal/cache/cache.go +++ b/internal/cache/cache.go @@ -16,10 +16,14 @@ var ( ) type Store interface { - Get(hash *string, key string) ([]byte, error) - GetAllForHash(hash string) (map[string][]byte, error) - GetAllForHashAndDelete(hash string) (map[string][]byte, error) - Set(hash *string, key string, value []byte, ttl time.Duration) error - Del(hash *string, keys ...string) error - CountElementsForHash(hash string) (int64, error) + Get(key string) ([]byte, error) + Set(key string, value []byte, ttl time.Duration) error + Del(keys ...string) error + + MapGet(hash string, key string) ([]byte, error) + MapGetAll(hash string) (map[string][]byte, error) + MapSet(hash string, key string, value []byte) error + MapDel(hash string, keys ...string) error + MapLen(hash string) (int64, error) + MapExtractAll(hash string) (map[string][]byte, error) } diff --git a/internal/cache/in_memory.go b/internal/cache/in_memory.go index 8f6b11113..71b15b6fb 100644 --- a/internal/cache/in_memory.go +++ b/internal/cache/in_memory.go @@ -14,27 +14,8 @@ func NewMemoryStore() *MemoryStore { return &MemoryStore{} } -// Get retrieves a value by key and hash (if given) -func (s *MemoryStore) Get(hash *string, key string) ([]byte, error) { - if hash != nil { - hashValue, found := s.data.Load(hash) - 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 - } - +// 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 @@ -49,54 +30,76 @@ func (s *MemoryStore) Get(hash *string, key string) ([]byte, error) { } // Set stores a key-value pair, ignoring the ttl parameter. -func (s *MemoryStore) Set(hash *string, key string, value []byte, _ time.Duration) error { - if hash != nil { - raw, _ := s.data.LoadOrStore(*hash, make(map[string][]byte)) +func (s *MemoryStore) Set(key string, value []byte, _ time.Duration) error { + s.data.Store(key, value) + return nil +} - hashMap, ok := raw.(map[string][]byte) - if !ok { - return ErrCacheFailedToSet - } +// Del removes a key from the store. +func (s *MemoryStore) Del(keys ...string) error { + for _, k := range keys { + s.data.Delete(k) + } + return nil +} - hashMap[key] = value +// MapGet retrieves a value by key and hash. +func (s *MemoryStore) MapGet(hash string, key string) ([]byte, error) { + hashValue, found := s.data.Load(hash) + if !found { + return nil, ErrCacheNotFound + } - s.data.Store(*hash, hashMap) - return nil + hashMap, ok := hashValue.(map[string][]byte) + if !ok { + return nil, ErrCacheFailedToGet } - s.data.Store(key, value) - return nil + fieldValue, exists := hashMap[key] + if !exists { + return nil, ErrCacheNotFound + } + + return fieldValue, nil } -// Del removes a key from the store. -func (s *MemoryStore) Del(hash *string, keys ...string) error { - if hash != nil { - hashValue, found := s.data.Load(*hash) - if !found { - return ErrCacheNotFound - } +// MapSet stores a key-value pair for specific hash. +func (s *MemoryStore) MapSet(hash string, key string, value []byte) error { + raw, _ := s.data.LoadOrStore(hash, make(map[string][]byte)) - hashMap, ok := hashValue.(map[string][]byte) - if !ok { - return errors.Join(ErrCacheFailedToDel, ErrCacheFailedToGet) - } + hashMap, ok := raw.(map[string][]byte) + if !ok { + return ErrCacheFailedToSet + } - for _, k := range keys { - delete(hashMap, k) - } + hashMap[key] = value - s.data.Store(*hash, hashMap) - return nil + s.data.Store(hash, hashMap) + return nil +} + +// MapDel removes a value by key in specific hash. +func (s *MemoryStore) MapDel(hash string, keys ...string) error { + hashValue, found := s.data.Load(hash) + if !found { + return ErrCacheNotFound + } + + hashMap, ok := hashValue.(map[string][]byte) + if !ok { + return errors.Join(ErrCacheFailedToDel, ErrCacheFailedToGet) } for _, k := range keys { - s.data.Delete(k) + delete(hashMap, k) } + + s.data.Store(hash, hashMap) return nil } -// GetAllForHash retrieves all key-value pairs for a specific hash. -func (s *MemoryStore) GetAllForHash(hash string) (map[string][]byte, error) { +// MapGetAll retrieves all key-value pairs for a specific hash. +func (s *MemoryStore) MapGetAll(hash string) (map[string][]byte, error) { hashValue, found := s.data.Load(hash) if !found { return nil, ErrCacheNotFound @@ -110,14 +113,14 @@ func (s *MemoryStore) GetAllForHash(hash string) (map[string][]byte, error) { return hashMap, nil } -// GetAllForHashAndDelete retrieves all key-value pairs for a specific hash and deletes the hash. -func (s *MemoryStore) GetAllForHashAndDelete(hash string) (map[string][]byte, error) { - hashMap, err := s.GetAllForHash(hash) +// MapExtractAll retrieves all key-value pairs for a specific hash and deletes the hash. +func (s *MemoryStore) MapExtractAll(hash string) (map[string][]byte, error) { + hashMap, err := s.MapGetAll(hash) if err != nil { return nil, err } - err = s.Del(nil, hash) + err = s.Del(hash) if err != nil { return nil, err } @@ -125,9 +128,9 @@ func (s *MemoryStore) GetAllForHashAndDelete(hash string) (map[string][]byte, er return hashMap, nil } -// CountElementsForHash returns the number of elements in a hash in memory. -func (s *MemoryStore) CountElementsForHash(hash string) (int64, error) { - hashMap, err := s.GetAllForHash(hash) +// MapLen returns the number of elements in a hash in memory. +func (s *MemoryStore) MapLen(hash string) (int64, error) { + hashMap, err := s.MapGetAll(hash) if err != nil { if errors.Is(err, ErrCacheNotFound) { return 0, nil diff --git a/internal/cache/redis.go b/internal/cache/redis.go index 259345579..3bc851c88 100644 --- a/internal/cache/redis.go +++ b/internal/cache/redis.go @@ -22,16 +22,9 @@ func NewRedisStore(ctx context.Context, c redis.UniversalClient) *RedisStore { } } -// Get retrieves a value by key and hash (if given). -func (r *RedisStore) Get(hash *string, key string) ([]byte, error) { - var result string - var err error - - if hash == nil { - result, err = r.client.Get(r.ctx, key).Result() - } else { - result, err = r.client.HGet(r.ctx, *hash, key).Result() - } +// Get retrieves a value by key. +func (r *RedisStore) Get(key string) ([]byte, error) { + result, err := r.client.Get(r.ctx, key).Result() if errors.Is(err, redis.Nil) { return nil, ErrCacheNotFound @@ -42,15 +35,9 @@ func (r *RedisStore) Get(hash *string, key string) ([]byte, error) { return []byte(result), nil } -// Set stores a value with a TTL for a specific hash (if given). -func (r *RedisStore) Set(hash *string, key string, value []byte, ttl time.Duration) error { - var err error - - if hash == nil { - err = r.client.Set(r.ctx, key, value, ttl).Err() - } else { - err = r.client.HSet(r.ctx, *hash, key, value).Err() - } +// Set stores a value with a TTL for key. +func (r *RedisStore) Set(key string, value []byte, ttl time.Duration) error { + err := r.client.Set(r.ctx, key, value, ttl).Err() if err != nil { return errors.Join(ErrCacheFailedToSet, err) @@ -60,15 +47,45 @@ func (r *RedisStore) Set(hash *string, key string, value []byte, ttl time.Durati } // Del removes a value by key. -func (r *RedisStore) Del(hash *string, keys ...string) error { - var result int64 - var err error - - if hash == nil { - result, err = r.client.Del(r.ctx, keys...).Result() - } else { - result, err = r.client.HDel(r.ctx, *hash, keys...).Result() +func (r *RedisStore) Del(keys ...string) error { + result, err := r.client.Del(r.ctx, keys...).Result() + + if err != nil { + return errors.Join(ErrCacheFailedToDel, err) + } + if result == 0 { + return ErrCacheNotFound } + return nil +} + +// MapGet retrieves a value by key and hash (if given). +func (r *RedisStore) MapGet(hash string, key string) ([]byte, error) { + result, err := r.client.HGet(r.ctx, hash, key).Result() + + if errors.Is(err, redis.Nil) { + return nil, ErrCacheNotFound + } else if err != nil { + return nil, errors.Join(ErrCacheFailedToGet, err) + } + + return []byte(result), nil +} + +// MapSet stores a value for a specific hash. +func (r *RedisStore) MapSet(hash string, key string, value []byte) error { + err := r.client.HSet(r.ctx, hash, key, value).Err() + + if err != nil { + return errors.Join(ErrCacheFailedToSet, err) + } + + return nil +} + +// MapDel removes a value by key in specific hash. +func (r *RedisStore) MapDel(hash string, keys ...string) error { + result, err := r.client.HDel(r.ctx, hash, keys...).Result() if err != nil { return errors.Join(ErrCacheFailedToDel, err) @@ -76,11 +93,12 @@ func (r *RedisStore) Del(hash *string, keys ...string) error { if result == 0 { return ErrCacheNotFound } + return nil } -// GetAllForHash retrieves all key-value pairs for a specific hash. -func (r *RedisStore) GetAllForHash(hash string) (map[string][]byte, error) { +// MapGetAll retrieves all key-value pairs for a specific hash. +func (r *RedisStore) MapGetAll(hash string) (map[string][]byte, error) { values, err := r.client.HGetAll(r.ctx, hash).Result() if err != nil { return nil, errors.Join(ErrCacheFailedToGet, err) @@ -93,8 +111,8 @@ func (r *RedisStore) GetAllForHash(hash string) (map[string][]byte, error) { return result, nil } -// GetAllForHashAndDelete retrieves all key-value pairs for a specific hash and remove them from cache, all in one transaction. -func (r *RedisStore) GetAllForHashAndDelete(hash string) (map[string][]byte, error) { +// MapExtractAll retrieves all key-value pairs for a specific hash and remove them from cache, all in one transaction. +func (r *RedisStore) MapExtractAll(hash string) (map[string][]byte, error) { tx := r.client.TxPipeline() getAllCmd := tx.HGetAll(r.ctx, hash) @@ -114,8 +132,8 @@ func (r *RedisStore) GetAllForHashAndDelete(hash string) (map[string][]byte, err return result, nil } -// CountElementsForHash returns the number of elements in a hash. -func (r *RedisStore) CountElementsForHash(hash string) (int64, error) { +// MapLen returns the number of elements in a hash. +func (r *RedisStore) MapLen(hash string) (int64, error) { count, err := r.client.HLen(r.ctx, hash).Result() if err != nil { return 0, errors.Join(ErrCacheFailedToGetCount, err) diff --git a/internal/metamorph/processor_helpers.go b/internal/metamorph/processor_helpers.go index 717d912b9..72ce5a4bf 100644 --- a/internal/metamorph/processor_helpers.go +++ b/internal/metamorph/processor_helpers.go @@ -49,7 +49,7 @@ func (p *Processor) setTransactionStatus(status store.UpdateStatus) error { return errors.Join(ErrFailedToSerialize, err) } - err = p.cacheStore.Set(&CacheStatusUpdateHash, status.Hash.String(), bytes, processStatusUpdatesIntervalDefault) + err = p.cacheStore.MapSet(CacheStatusUpdateHash, status.Hash.String(), bytes) if err != nil { return err } @@ -57,7 +57,7 @@ func (p *Processor) setTransactionStatus(status store.UpdateStatus) error { } func (p *Processor) getTransactionStatus(hash chainhash.Hash) (*store.UpdateStatus, error) { - bytes, err := p.cacheStore.Get(&CacheStatusUpdateHash, hash.String()) + bytes, err := p.cacheStore.MapGet(CacheStatusUpdateHash, hash.String()) if err != nil { return nil, err } @@ -73,7 +73,7 @@ func (p *Processor) getTransactionStatus(hash chainhash.Hash) (*store.UpdateStat func (p *Processor) getAndDeleteAllTransactionStatuses() (StatusUpdateMap, error) { statuses := make(StatusUpdateMap) - keys, err := p.cacheStore.GetAllForHashAndDelete(CacheStatusUpdateHash) + keys, err := p.cacheStore.MapExtractAll(CacheStatusUpdateHash) if err != nil { return nil, err } @@ -97,7 +97,7 @@ func (p *Processor) getAndDeleteAllTransactionStatuses() (StatusUpdateMap, error } func (p *Processor) getStatusUpdateCount() (int, error) { - count, err := p.cacheStore.CountElementsForHash(CacheStatusUpdateHash) + count, err := p.cacheStore.MapLen(CacheStatusUpdateHash) if err != nil { return 0, err }