Skip to content

Commit 20b70f1

Browse files
committed
use cache_db wrapper for caching functionality
1 parent 225955e commit 20b70f1

File tree

10 files changed

+162
-90
lines changed

10 files changed

+162
-90
lines changed

x/blockdb/cache_db.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved.
2+
// See the file LICENSE for licensing terms.
3+
4+
package blockdb
5+
6+
import (
7+
"slices"
8+
9+
"go.uber.org/zap"
10+
11+
"github.com/ava-labs/avalanchego/cache/lru"
12+
"github.com/ava-labs/avalanchego/database"
13+
)
14+
15+
var _ database.HeightIndex = (*cacheDB)(nil)
16+
17+
type cacheDB struct {
18+
db *Database
19+
cache *lru.Cache[BlockHeight, BlockData]
20+
}
21+
22+
func newCacheDB(db *Database, size uint16) *cacheDB {
23+
return &cacheDB{
24+
db: db,
25+
cache: lru.NewCache[BlockHeight, BlockData](int(size)),
26+
}
27+
}
28+
29+
func (c *cacheDB) Get(height BlockHeight) (BlockData, error) {
30+
c.db.closeMu.RLock()
31+
defer c.db.closeMu.RUnlock()
32+
33+
if c.db.closed {
34+
c.db.log.Error("Failed Get: database closed", zap.Uint64("height", height))
35+
return nil, database.ErrClosed
36+
}
37+
38+
if cached, ok := c.cache.Get(height); ok {
39+
return slices.Clone(cached), nil
40+
}
41+
data, err := c.db.getWithoutLock(height)
42+
if err != nil {
43+
return nil, err
44+
}
45+
c.cache.Put(height, slices.Clone(data))
46+
return data, nil
47+
}
48+
49+
func (c *cacheDB) Put(height BlockHeight, data BlockData) error {
50+
if err := c.db.Put(height, data); err != nil {
51+
return err
52+
}
53+
54+
c.cache.Put(height, slices.Clone(data))
55+
return nil
56+
}
57+
58+
func (c *cacheDB) Has(height BlockHeight) (bool, error) {
59+
c.db.closeMu.RLock()
60+
defer c.db.closeMu.RUnlock()
61+
62+
if c.db.closed {
63+
c.db.log.Error("Failed Has: database closed", zap.Uint64("height", height))
64+
return false, database.ErrClosed
65+
}
66+
67+
if _, ok := c.cache.Get(height); ok {
68+
return true, nil
69+
}
70+
return c.db.hasWithoutLock(height)
71+
}
72+
73+
func (c *cacheDB) Close() error {
74+
if err := c.db.Close(); err != nil {
75+
return err
76+
}
77+
c.cache.Flush()
78+
return nil
79+
}

x/blockdb/entry_cache_test.go renamed to x/blockdb/cache_db_test.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,29 @@ import (
1111
)
1212

1313
func TestCacheOnMiss(t *testing.T) {
14-
db, _ := newTestDatabase(t, DefaultConfig())
14+
db := newCacheDatabase(t, DefaultConfig())
1515
height := uint64(20)
1616
block := randomBlock(t)
1717
require.NoError(t, db.Put(height, block))
1818

1919
// Evict the entry from cache to simulate a cache miss
20-
db.blockCache.Evict(height)
20+
db.cache.Evict(height)
2121

2222
// Read the block - should populate the cache on cache miss
2323
_, err := db.Get(height)
2424
require.NoError(t, err)
2525

26-
_, ok := db.blockCache.Get(height)
26+
_, ok := db.cache.Get(height)
2727
require.True(t, ok)
2828
}
2929

3030
func TestCacheGet(t *testing.T) {
31-
db, _ := newTestDatabase(t, DefaultConfig())
31+
db := newCacheDatabase(t, DefaultConfig())
3232
height := uint64(30)
3333
block := randomBlock(t)
3434

3535
// Populate cache directly without writing to database
36-
db.blockCache.Put(height, block)
36+
db.cache.Put(height, block)
3737

3838
// Get should return the block from cache
3939
data, err := db.Get(height)
@@ -42,12 +42,12 @@ func TestCacheGet(t *testing.T) {
4242
}
4343

4444
func TestCacheHas(t *testing.T) {
45-
db, _ := newTestDatabase(t, DefaultConfig())
45+
db := newCacheDatabase(t, DefaultConfig())
4646
height := uint64(40)
4747
block := randomBlock(t)
4848

4949
// Populate cache directly without writing to database
50-
db.blockCache.Put(height, block)
50+
db.cache.Put(height, block)
5151

5252
// Has should return true from cache even though block is not in database
5353
has, err := db.Has(height)
@@ -56,7 +56,7 @@ func TestCacheHas(t *testing.T) {
5656
}
5757

5858
func TestCachePutStoresClone(t *testing.T) {
59-
db, _ := newTestDatabase(t, DefaultConfig())
59+
db := newCacheDatabase(t, DefaultConfig())
6060
height := uint64(40)
6161
block := randomBlock(t)
6262
clone := slices.Clone(block)
@@ -66,13 +66,13 @@ func TestCachePutStoresClone(t *testing.T) {
6666
clone[0] = 99
6767

6868
// Cache should have the original unmodified data
69-
cached, ok := db.blockCache.Get(height)
69+
cached, ok := db.cache.Get(height)
7070
require.True(t, ok)
7171
require.Equal(t, block, cached)
7272
}
7373

7474
func TestCacheGetReturnsClone(t *testing.T) {
75-
db, _ := newTestDatabase(t, DefaultConfig())
75+
db := newCacheDatabase(t, DefaultConfig())
7676
height := uint64(50)
7777
block := randomBlock(t)
7878
require.NoError(t, db.Put(height, block))
@@ -83,7 +83,7 @@ func TestCacheGetReturnsClone(t *testing.T) {
8383
data[0] = 99
8484

8585
// Cache should still have the original unmodified data
86-
cached, ok := db.blockCache.Get(height)
86+
cached, ok := db.cache.Get(height)
8787
require.True(t, ok)
8888
require.Equal(t, block, cached)
8989

@@ -94,20 +94,20 @@ func TestCacheGetReturnsClone(t *testing.T) {
9494
}
9595

9696
func TestCachePutOverridesSameHeight(t *testing.T) {
97-
db, _ := newTestDatabase(t, DefaultConfig())
97+
db := newCacheDatabase(t, DefaultConfig())
9898
height := uint64(60)
9999
b1 := randomBlock(t)
100100
require.NoError(t, db.Put(height, b1))
101101

102102
// Verify first block is in cache
103-
cached, ok := db.blockCache.Get(height)
103+
cached, ok := db.cache.Get(height)
104104
require.True(t, ok)
105105
require.Equal(t, b1, cached)
106106

107107
// Put second block at same height and verify it overrides the first one
108108
b2 := randomBlock(t)
109109
require.NoError(t, db.Put(height, b2))
110-
cached, ok = db.blockCache.Get(height)
110+
cached, ok = db.cache.Get(height)
111111
require.True(t, ok)
112112
require.Equal(t, b2, cached)
113113
require.NotEqual(t, b1, cached)

x/blockdb/config.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const DefaultMaxDataFileSize = 500 * 1024 * 1024 * 1024
1212
const DefaultMaxDataFiles = 10
1313

1414
// DefaultBlockCacheSize is the default size of the block cache.
15-
const DefaultBlockCacheSize = 256
15+
const DefaultBlockCacheSize uint16 = 256
1616

1717
// DatabaseConfig contains configuration parameters for BlockDB.
1818
type DatabaseConfig struct {
@@ -32,7 +32,7 @@ type DatabaseConfig struct {
3232
MaxDataFiles int
3333

3434
// BlockCacheSize is the size of the block cache (default: 256).
35-
BlockCacheSize int
35+
BlockCacheSize uint16
3636

3737
// CheckpointInterval defines how frequently (in blocks) the index file header is updated (default: 1024).
3838
CheckpointInterval uint64
@@ -99,7 +99,7 @@ func (c DatabaseConfig) WithMaxDataFiles(maxFiles int) DatabaseConfig {
9999
}
100100

101101
// WithBlockCacheSize returns a copy of the config with BlockCacheSize set to the given value.
102-
func (c DatabaseConfig) WithBlockCacheSize(size int) DatabaseConfig {
102+
func (c DatabaseConfig) WithBlockCacheSize(size uint16) DatabaseConfig {
103103
c.BlockCacheSize = size
104104
return c
105105
}
@@ -127,8 +127,5 @@ func (c DatabaseConfig) Validate() error {
127127
if c.MaxDataFileSize == 0 {
128128
return errors.New("MaxDataFileSize must be positive")
129129
}
130-
if c.BlockCacheSize < 1 {
131-
return errors.New("BlockCacheSize cannot be less than 1")
132-
}
133130
return nil
134131
}

x/blockdb/database.go

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"math"
1313
"os"
1414
"path/filepath"
15-
"slices"
1615
"sync"
1716
"sync/atomic"
1817

@@ -177,7 +176,6 @@ type Database struct {
177176
log logging.Logger
178177
closed bool
179178
fileCache *lru.Cache[int, *os.File]
180-
blockCache *lru.Cache[BlockHeight, BlockData]
181179
compressor compression.Compressor
182180

183181
// closeMu prevents the database from being closed while in use and prevents
@@ -199,7 +197,7 @@ type Database struct {
199197
// Parameters:
200198
// - config: Configuration parameters
201199
// - log: Logger instance for structured logging
202-
func New(config DatabaseConfig, log logging.Logger) (*Database, error) {
200+
func New(config DatabaseConfig, log logging.Logger) (database.HeightIndex, error) {
203201
if err := config.Validate(); err != nil {
204202
return nil, err
205203
}
@@ -225,7 +223,6 @@ func New(config DatabaseConfig, log logging.Logger) (*Database, error) {
225223
f.Close()
226224
}
227225
}),
228-
blockCache: lru.NewCache[BlockHeight, BlockData](config.BlockCacheSize),
229226
compressor: compressor,
230227
}
231228

@@ -234,7 +231,7 @@ func New(config DatabaseConfig, log logging.Logger) (*Database, error) {
234231
zap.String("dataDir", config.DataDir),
235232
zap.Uint64("maxDataFileSize", config.MaxDataFileSize),
236233
zap.Int("maxDataFiles", config.MaxDataFiles),
237-
zap.Int("blockCacheSize", config.BlockCacheSize),
234+
zap.Uint16("blockCacheSize", config.BlockCacheSize),
238235
)
239236

240237
if err := s.openAndInitializeIndex(); err != nil {
@@ -260,6 +257,9 @@ func New(config DatabaseConfig, log logging.Logger) (*Database, error) {
260257
zap.Uint64("maxBlockHeight", maxHeight),
261258
)
262259

260+
if config.BlockCacheSize > 0 {
261+
return newCacheDB(s, config.BlockCacheSize), nil
262+
}
263263
return s, nil
264264
}
265265

@@ -279,7 +279,6 @@ func (s *Database) Close() error {
279279
}
280280

281281
s.closeFiles()
282-
s.blockCache.Flush()
283282

284283
s.log.Info("Block database closed successfully")
285284
return err
@@ -291,9 +290,7 @@ func (s *Database) Put(height BlockHeight, block BlockData) error {
291290
defer s.closeMu.RUnlock()
292291

293292
if s.closed {
294-
s.log.Error("Failed to write block: database is closed",
295-
zap.Uint64("height", height),
296-
)
293+
s.log.Error("Failed Put: database closed", zap.Uint64("height", height))
297294
return database.ErrClosed
298295
}
299296

@@ -376,7 +373,6 @@ func (s *Database) Put(height BlockHeight, block BlockData) error {
376373
)
377374
return err
378375
}
379-
s.blockCache.Put(height, slices.Clone(block))
380376

381377
s.log.Debug("Block written successfully",
382378
zap.Uint64("height", height),
@@ -441,10 +437,10 @@ func (s *Database) Get(height BlockHeight) (BlockData, error) {
441437
return nil, database.ErrClosed
442438
}
443439

444-
if c, ok := s.blockCache.Get(height); ok {
445-
return slices.Clone(c), nil
446-
}
440+
return s.getWithoutLock(height)
441+
}
447442

443+
func (s *Database) getWithoutLock(height BlockHeight) (BlockData, error) {
448444
indexEntry, err := s.readBlockIndex(height)
449445
if err != nil {
450446
return nil, err
@@ -495,7 +491,6 @@ func (s *Database) Get(height BlockHeight) (BlockData, error) {
495491
return nil, fmt.Errorf("checksum mismatch: calculated %d, stored %d", calculatedChecksum, bh.Checksum)
496492
}
497493

498-
s.blockCache.Put(height, slices.Clone(decompressed))
499494
return decompressed, nil
500495
}
501496

@@ -509,9 +504,10 @@ func (s *Database) Has(height BlockHeight) (bool, error) {
509504
return false, database.ErrClosed
510505
}
511506

512-
if _, ok := s.blockCache.Get(height); ok {
513-
return true, nil
514-
}
507+
return s.hasWithoutLock(height)
508+
}
509+
510+
func (s *Database) hasWithoutLock(height BlockHeight) (bool, error) {
515511
_, err := s.readBlockIndex(height)
516512
if err != nil {
517513
if errors.Is(err, database.ErrNotFound) || errors.Is(err, ErrInvalidBlockHeight) {

0 commit comments

Comments
 (0)