-
Notifications
You must be signed in to change notification settings - Fork 939
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(shwap): Add caching to blockstore (#3615)
- Loading branch information
Showing
8 changed files
with
187 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package store | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
eds "github.com/celestiaorg/celestia-node/share/new_eds" | ||
"github.com/celestiaorg/celestia-node/store/cache" | ||
) | ||
|
||
// CachedStore is a store with an additional cache layer. New cache layer is created on top of the | ||
// original store cache. Parent store cache will be able to read from the new cache layer, but will | ||
// not be able to write to it. Making parent store cache and CachedStore cache independent for writes. | ||
type CachedStore struct { | ||
store *Store | ||
combinedCache *cache.DoubleCache | ||
} | ||
|
||
// WithCache wraps store with extra layer of cache. Created caching layer will have read access to original | ||
// store cache and will duplicate it's content. It updates parent store cache, to allow it to | ||
// read from additionally created cache layer. | ||
func (s *Store) WithCache(name string, size int) (*CachedStore, error) { | ||
newCache, err := cache.NewAccessorCache(name, size) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to create %s cache: %w", name, err) | ||
} | ||
|
||
wrappedCache := cache.NewDoubleCache(s.cache, newCache) | ||
s.metrics.addCacheMetrics(wrappedCache) | ||
// update parent store cache to allow it to read from both caches | ||
s.cache = wrappedCache | ||
return &CachedStore{ | ||
store: s, | ||
combinedCache: wrappedCache, | ||
}, nil | ||
} | ||
|
||
// GetByHeight returns accessor for given height and puts it into cache. | ||
func (cs *CachedStore) GetByHeight(ctx context.Context, height uint64) (eds.AccessorStreamer, error) { | ||
acc, err := cs.combinedCache.First().Get(height) | ||
if err == nil { | ||
return acc, err | ||
} | ||
return cs.combinedCache.Second().GetOrLoad(ctx, height, cs.openFile(height)) | ||
} | ||
|
||
func (cs *CachedStore) openFile(height uint64) cache.OpenAccessorFn { | ||
return func(ctx context.Context) (eds.AccessorStreamer, error) { | ||
// open file directly wihout calling GetByHeight of inner getter to | ||
// avoid hitting store cache second time | ||
path := cs.store.heightToPath(height) | ||
return cs.store.openFile(path) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package store | ||
|
||
import ( | ||
"context" | ||
"sync/atomic" | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/celestiaorg/celestia-node/store/cache" | ||
) | ||
|
||
func TestStore_WithCache(t *testing.T) { | ||
height := atomic.Uint64{} | ||
height.Store(1) | ||
|
||
t.Run("don't exist in first cache", func(t *testing.T) { | ||
// create store with no cache | ||
params := paramsNoCache() | ||
store, err := NewStore(params, t.TempDir()) | ||
require.NoError(t, err) | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | ||
t.Cleanup(cancel) | ||
eds, roots := randomEDS(t) | ||
height := height.Add(1) | ||
err = store.Put(ctx, roots, height, eds) | ||
require.NoError(t, err) | ||
|
||
// check that the height is not in the cache (cache was disabled) | ||
_, err = store.cache.Get(height) | ||
require.ErrorIs(t, err, cache.ErrCacheMiss) | ||
|
||
cachedStore, err := store.WithCache("test", 10) | ||
require.NoError(t, err) | ||
// load accessor to secondary cache by calling GetByHeight on cached store | ||
_, err = cachedStore.GetByHeight(ctx, height) | ||
require.NoError(t, err) | ||
|
||
// loaded accessor should be available in both original store and wrapped store | ||
_, err = store.cache.Get(height) | ||
require.NoError(t, err) | ||
_, err = cachedStore.combinedCache.Get(height) | ||
require.NoError(t, err) | ||
}) | ||
|
||
t.Run("exists in first cache", func(t *testing.T) { | ||
store, err := NewStore(DefaultParameters(), t.TempDir()) | ||
require.NoError(t, err) | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | ||
t.Cleanup(cancel) | ||
eds, roots := randomEDS(t) | ||
height := height.Add(1) | ||
err = store.Put(ctx, roots, height, eds) | ||
require.NoError(t, err) | ||
|
||
_, err = store.cache.Get(height) | ||
require.NoError(t, err) | ||
|
||
withCache, err := store.WithCache("test", 10) | ||
require.NoError(t, err) | ||
_, err = withCache.GetByHeight(ctx, height) | ||
require.NoError(t, err) | ||
|
||
_, err = withCache.combinedCache.Second().Get(height) | ||
require.ErrorIs(t, err, cache.ErrCacheMiss) | ||
}) | ||
} | ||
|
||
func paramsNoCache() *Parameters { | ||
params := DefaultParameters() | ||
params.RecentBlocksCacheSize = 0 | ||
return params | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters