Skip to content

Commit ef7c706

Browse files
committed
add locking to cached Put
1 parent 20b70f1 commit ef7c706

File tree

1 file changed

+20
-2
lines changed

1 file changed

+20
-2
lines changed

x/blockdb/cache_db.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,25 @@ package blockdb
55

66
import (
77
"slices"
8+
"sync"
89

910
"go.uber.org/zap"
1011

1112
"github.com/ava-labs/avalanchego/cache/lru"
1213
"github.com/ava-labs/avalanchego/database"
1314
)
1415

16+
// numShards is the number of mutex shards used to reduce lock contention for
17+
// concurrent Put operations. Using 256 shards provides a good balance between
18+
// memory usage (~2KB) and concurrency.
19+
const numShards = 256
20+
1521
var _ database.HeightIndex = (*cacheDB)(nil)
1622

1723
type cacheDB struct {
18-
db *Database
19-
cache *lru.Cache[BlockHeight, BlockData]
24+
db *Database
25+
cache *lru.Cache[BlockHeight, BlockData]
26+
shards [numShards]sync.Mutex
2027
}
2128

2229
func newCacheDB(db *Database, size uint16) *cacheDB {
@@ -46,7 +53,18 @@ func (c *cacheDB) Get(height BlockHeight) (BlockData, error) {
4653
return data, nil
4754
}
4855

56+
// Put writes block data at the specified height to both the underlying database
57+
// and the cache.
58+
//
59+
// Concurrent calls to Put with the same height are serialized using sharded
60+
// locking to ensure cache consistency with the underlying database.
61+
// This allows concurrent writes to different heights while preventing race
62+
// conditions for writes to the same height.
4963
func (c *cacheDB) Put(height BlockHeight, data BlockData) error {
64+
shard := &c.shards[height%numShards]
65+
shard.Lock()
66+
defer shard.Unlock()
67+
5068
if err := c.db.Put(height, data); err != nil {
5169
return err
5270
}

0 commit comments

Comments
 (0)