Skip to content

Commit 0950d78

Browse files
committed
execution/cache, execution/commitment: address #22154 review
- CodeStore.Evict: tableSizeBytes starts at 0 each process start, so a persistent TblCodeCache that already exceeds the cap would never be pruned (unbounded growth across restarts). Seed it once from the table via sumTableBytes, in the same key+value byte units the eviction loop decrements. - BranchCache.Get: only count a pinned hit/miss when the prefix actually routes to a pinned storage trunk; account-trie and tail-only lookups no longer inflate pinnedMisses. - AdaptivePinController: the value threaded through OnBlockComplete is a txNum (that is what SharedDomains has at commit), not a block number; rename the parameter, the write-only promotedAtBlock field, and the log keys to txNum so the diagnostics are accurate. No behaviour change.
1 parent fcfc99b commit 0950d78

4 files changed

Lines changed: 54 additions & 10 deletions

File tree

execution/cache/code_store.go

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ type CodeStore struct {
2121
// LRU and entries re-derive from CodeDomain.
2222
tableCapBytes uint64
2323
tableSizeBytes atomic.Int64
24+
tableSeeded atomic.Bool
2425

2526
memHits atomic.Uint64
2627
tableHits atomic.Uint64
@@ -97,7 +98,21 @@ func (s *CodeStore) PutByHash(tx kv.RwTx, codeHash, code []byte) error {
9798
// order when over capacity. Safe: evicted entries are re-derivable from
9899
// CodeDomain on miss. Call on a write tx (e.g., at commit), never on reads.
99100
func (s *CodeStore) Evict(tx kv.RwTx) error {
100-
if s == nil || s.tableCapBytes == 0 || uint64(s.tableSizeBytes.Load()) <= s.tableCapBytes {
101+
if s == nil || s.tableCapBytes == 0 {
102+
return nil
103+
}
104+
// tableSizeBytes starts at 0 each process start; seed it once from the
105+
// persistent table (in the same key+value byte units the eviction loop
106+
// decrements) so a backing that already exceeds the cap gets pruned rather
107+
// than growing unbounded across restarts.
108+
if s.tableSeeded.CompareAndSwap(false, true) {
109+
total, err := sumTableBytes(tx)
110+
if err != nil {
111+
return err
112+
}
113+
s.tableSizeBytes.Store(total)
114+
}
115+
if uint64(s.tableSizeBytes.Load()) <= s.tableCapBytes {
101116
return nil
102117
}
103118
c, err := tx.RwCursor(kv.TblCodeCache)
@@ -121,3 +136,21 @@ func (s *CodeStore) Evict(tx kv.RwTx) error {
121136
}
122137
return nil
123138
}
139+
140+
// sumTableBytes returns the total key+value byte size of TblCodeCache, in the
141+
// same units Evict tracks and decrements.
142+
func sumTableBytes(tx kv.RwTx) (int64, error) {
143+
c, err := tx.Cursor(kv.TblCodeCache)
144+
if err != nil {
145+
return 0, err
146+
}
147+
defer c.Close()
148+
var total int64
149+
for k, v, err := c.First(); k != nil; k, v, err = c.Next() {
150+
if err != nil {
151+
return 0, err
152+
}
153+
total += int64(len(k) + len(v))
154+
}
155+
return total, nil
156+
}

execution/cache/code_store_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,13 @@ func TestCodeStore_TwoTierAndEvict(t *testing.T) {
6060
}
6161
require.NoError(t, small.Evict(tx))
6262
require.LessOrEqual(t, small.tableSizeBytes.Load(), int64(128))
63+
64+
// Restart scenario: a fresh store (tableSizeBytes=0) over an already-full
65+
// backing must still prune — seed the size from the table, don't grow
66+
// unbounded. Without the seed, Evict's under-cap early return would skip.
67+
restarted := NewCodeStore(1<<20, 128)
68+
require.Zero(t, restarted.tableSizeBytes.Load())
69+
require.NoError(t, restarted.Evict(tx))
70+
require.LessOrEqual(t, restarted.tableSizeBytes.Load(), int64(128),
71+
"a fresh store must seed its size from the backing and prune, not grow unbounded across restarts")
6372
}

execution/commitment/adaptive_pin.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ type DbBranchesProvider func(contractHash []byte) map[string][]byte
7171

7272
type adaptiveContractState struct {
7373
contractHash [32]byte
74-
promotedAtBlock uint64
74+
promotedAtTxNum uint64
7575
preload *ContractTrunkPreload // serial-BFS path (nil when parallel)
7676
parallel *ContractTrunkPreloadParallel // parallel-wave-BFS path (nil when serial)
7777
coldBlocksInARow int
@@ -161,7 +161,7 @@ func (c *AdaptivePinController) onCacheMiss(prefix []byte) {
161161
// OnBlockComplete consumes the per-block miss snapshot and decides
162162
// promotions, extensions, and demotions. Synchronous — preloads run
163163
// inline so the new pin set is available for the next block's reads.
164-
func (c *AdaptivePinController) OnBlockComplete(ctx context.Context, blockNum uint64, reader CommitmentReader) {
164+
func (c *AdaptivePinController) OnBlockComplete(ctx context.Context, txNum uint64, reader CommitmentReader) {
165165
misses := c.snapshotMisses()
166166

167167
c.mu.Lock()
@@ -173,7 +173,7 @@ func (c *AdaptivePinController) OnBlockComplete(ctx context.Context, blockNum ui
173173
if c.parallelResolverFactory != nil {
174174
r, release, err := c.parallelResolverFactory()
175175
if err != nil {
176-
c.warnf("[adaptive-pin] parallel resolver factory failed, falling back to serial", "err", err, "block", blockNum)
176+
c.warnf("[adaptive-pin] parallel resolver factory failed, falling back to serial", "err", err, "txNum", txNum)
177177
} else {
178178
parallelResolve = r
179179
releaseParallel = release
@@ -215,7 +215,7 @@ func (c *AdaptivePinController) OnBlockComplete(ctx context.Context, blockNum ui
215215
if len(misses) > 0 && len(c.states) < c.cfg.MaxPromotedContracts {
216216
candidates := pickPromotionCandidates(misses, c.cfg.PromoteThresholdMisses, c.cfg.MaxPromotedContracts-len(c.states))
217217
for _, hash := range candidates {
218-
state, err := c.promoteLocked(ctx, hash, blockNum, parallelResolve, reader)
218+
state, err := c.promoteLocked(ctx, hash, txNum, parallelResolve, reader)
219219
if err != nil {
220220
c.warnf("[adaptive-pin] initial-view failed", "hash", hex.EncodeToString(hash[:]), "err", err)
221221
continue
@@ -238,7 +238,7 @@ func (c *AdaptivePinController) OnBlockComplete(ctx context.Context, blockNum ui
238238

239239
if c.logger != nil && (promoted+extended+demoted > 0 || len(c.states) > 0) {
240240
c.logger.Info("[adaptive-pin]",
241-
"block", blockNum,
241+
"txNum", txNum,
242242
"promoted_total", len(c.states),
243243
"promoted_this_block", promoted,
244244
"extended_this_block", extended,
@@ -278,7 +278,7 @@ func (c *AdaptivePinController) demoteLocked(hash [32]byte, state *adaptiveContr
278278
func (c *AdaptivePinController) promoteLocked(
279279
ctx context.Context,
280280
hash [32]byte,
281-
blockNum uint64,
281+
txNum uint64,
282282
parallelResolve BatchBranchResolver,
283283
reader CommitmentReader,
284284
) (*adaptiveContractState, error) {
@@ -299,7 +299,7 @@ func (c *AdaptivePinController) promoteLocked(
299299
}
300300
return &adaptiveContractState{
301301
contractHash: hash,
302-
promotedAtBlock: blockNum,
302+
promotedAtTxNum: txNum,
303303
parallel: p,
304304
}, nil
305305
}
@@ -315,7 +315,7 @@ func (c *AdaptivePinController) promoteLocked(
315315
}
316316
return &adaptiveContractState{
317317
contractHash: hash,
318-
promotedAtBlock: blockNum,
318+
promotedAtTxNum: txNum,
319319
preload: p,
320320
}, nil
321321
}

execution/commitment/branch_cache.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,8 @@ func (c *BranchCache) lookup(prefix []byte) (*branchCacheEntry, bool) {
483483
return nil, false
484484
}
485485
// Pinned tier: per-contract storage trunk (fixed skeleton + deep overflow).
486+
// Only a lookup that actually routes to a pinned trunk counts toward the
487+
// pinned hit/miss stats; account-trie and tail-only prefixes are excluded.
486488
if st, _, stor, ok := c.storageRoute(prefix, false); ok {
487489
var entry *branchCacheEntry
488490
if slot := st.slot(stor); slot != nil {
@@ -494,8 +496,8 @@ func (c *BranchCache) lookup(prefix []byte) (*branchCacheEntry, bool) {
494496
c.pinnedHits.Add(1)
495497
return entry, true
496498
}
499+
c.pinnedMisses.Add(1)
497500
}
498-
c.pinnedMisses.Add(1)
499501
entry, ok := c.tail.Get(maphash.Hash(prefix))
500502
if !ok {
501503
c.tailMisses.Add(1)

0 commit comments

Comments
 (0)