Skip to content

Commit 6729abd

Browse files
committed
fix: persist snapshot once for avoiding badger vlog
1 parent f74b456 commit 6729abd

File tree

3 files changed

+18
-20
lines changed

3 files changed

+18
-20
lines changed

block/internal/cache/generic_cache.go

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ func (c *Cache[T]) getDAIncludedByHeight(blockHeight uint64) (uint64, bool) {
141141
return c.getDAIncluded(hash)
142142
}
143143

144-
// setDAIncluded records DA inclusion and persists the snapshot.
144+
// setDAIncluded records DA inclusion in memory.
145145
// If a previous entry already exists at blockHeight (e.g. a placeholder from
146146
// RestoreFromStore), it is evicted from daIncluded to avoid orphan leaks.
147147
func (c *Cache[T]) setDAIncluded(hash string, daHeight uint64, blockHeight uint64) {
@@ -151,14 +151,11 @@ func (c *Cache[T]) setDAIncluded(hash string, daHeight uint64, blockHeight uint6
151151
c.daIncluded.Add(hash, daHeight)
152152
c.hashByHeight.Add(blockHeight, hash)
153153
c.setMaxDAHeight(daHeight)
154-
_ = c.persistSnapshot(context.Background())
155154
}
156155

157-
// removeDAIncluded removes the DA-included status of the hash from the cache
158-
// and rewrites the window snapshot.
156+
// removeDAIncluded removes the DA-included status of the hash from the cache.
159157
func (c *Cache[T]) removeDAIncluded(hash string) {
160158
c.daIncluded.Remove(hash)
161-
_ = c.persistSnapshot(context.Background())
162159
}
163160

164161
// daHeight returns the maximum DA height from all DA-included items.
@@ -185,7 +182,7 @@ func (c *Cache[T]) removeSeen(hash string) {
185182
}
186183

187184
// deleteAllForHeight removes all items and their associated data from the
188-
// cache at the given height and rewrites the window snapshot.
185+
// cache at the given height.
189186
func (c *Cache[T]) deleteAllForHeight(height uint64) {
190187
c.itemsByHeight.Remove(height)
191188

@@ -200,13 +197,10 @@ func (c *Cache[T]) deleteAllForHeight(height uint64) {
200197
c.hashes.Remove(hash)
201198
c.daIncluded.Remove(hash)
202199
}
203-
204-
_ = c.persistSnapshot(context.Background())
205200
}
206201

207-
// persistSnapshot writes all current in-flight [blockHeight, daHeight] pairs
208-
// to the store under a single key. Called on every mutation; payload is tiny
209-
// (typically <10 entries × 16 bytes).
202+
// persistSnapshot writes all current in-flight [blockHeight, daHeight] pairs to the store under a single key.
203+
// Only called explicitly via SaveToStore. NEVER CALL IT ON HOT-PATH TO AVOID BAGER WRITE AMPLIFICATION.
210204
func (c *Cache[T]) persistSnapshot(ctx context.Context) error {
211205
if c.store == nil || c.storeKeyPrefix == "" {
212206
return nil

block/internal/cache/generic_cache_test.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -178,19 +178,20 @@ func TestCache_RestoreFromStore_PlaceholderOverwrittenByRealHash(t *testing.T) {
178178
assert.Equal(t, uint64(99), daH)
179179
}
180180

181-
// TestCache_RestoreFromStore_RoundTrip verifies that setDAIncluded persists a
181+
// TestCache_RestoreFromStore_RoundTrip verifies that SaveToStore persists a
182182
// snapshot that a freshly-constructed cache can fully recover.
183183
func TestCache_RestoreFromStore_RoundTrip(t *testing.T) {
184184
st := testMemStore(t)
185185
ctx := context.Background()
186186

187-
// First cache instance: write some in-flight entries.
187+
// First cache instance: write some in-flight entries, then flush (shutdown).
188188
c1 := NewCache[testItem](st, "rt/")
189189
c1.setDAIncluded("hashA", 10, 1)
190190
c1.setDAIncluded("hashB", 20, 2)
191191
c1.setDAIncluded("hashC", 30, 3)
192192
// Remove one entry to confirm deletions are also snapshotted.
193193
c1.removeDAIncluded("hashB")
194+
require.NoError(t, c1.SaveToStore(ctx))
194195

195196
// Second cache instance on same store: should recover {hashA→10, hashC→30}.
196197
c2 := NewCache[testItem](st, "rt/")
@@ -324,6 +325,7 @@ func TestCache_ClearFromStore(t *testing.T) {
324325
c := NewCache[testItem](st, "clear-test/")
325326
c.setDAIncluded("hash1", 100, 1)
326327
c.setDAIncluded("hash2", 200, 2)
328+
require.NoError(t, c.SaveToStore(ctx))
327329

328330
// Verify the snapshot key was written before clearing.
329331
_, err := st.GetMetadata(ctx, "clear-test/__snap")
@@ -381,9 +383,10 @@ func TestCache_NoPlaceholderLeakAfterRefire(t *testing.T) {
381383
st := testMemStore(t)
382384
ctx := context.Background()
383385

384-
// Step 1: initial run — write a real hash for height 3.
386+
// Step 1: initial run — write a real hash for height 3, then flush (shutdown).
385387
c1 := NewCache[testItem](st, "pfx/")
386388
c1.setDAIncluded("realHash3", 99, 3)
389+
require.NoError(t, c1.SaveToStore(ctx))
387390
// snapshot now contains [{blockHeight:3, daHeight:99}]
388391

389392
// Step 2: restart — placeholder installed for height 3.
@@ -424,9 +427,10 @@ func TestCache_RestartIdempotent(t *testing.T) {
424427
const blockH = uint64(5)
425428
const daH = uint64(42)
426429

427-
// ── Run 1: normal operation, height 5 in-flight ──────────────────────────
430+
// ── Run 1: normal operation, height 5 in-flight; flush at shutdown ───────
428431
c1 := NewCache[testItem](st, "pfx/")
429432
c1.setDAIncluded(realHash, daH, blockH)
433+
require.NoError(t, c1.SaveToStore(ctx))
430434
// snapshot: [{5, 42}]
431435

432436
for restart := 1; restart <= 3; restart++ {
@@ -442,16 +446,16 @@ func TestCache_RestartIdempotent(t *testing.T) {
442446
require.True(t, ok, "restart %d: height-based lookup must succeed", restart)
443447
assert.Equal(t, daH, gotDAH, "restart %d: height-based DA height correct", restart)
444448

445-
// ── DA retriever re-fires with the real hash
449+
// ── DA retriever re-fires with the real hash, then flushes (shutdown).
446450
cR.setDAIncluded(realHash, daH, blockH)
451+
require.NoError(t, cR.SaveToStore(ctx), "restart %d: SaveToStore", restart)
447452

448453
// After re-fire: real hash present, no orphan, snapshot updated.
449454
_, realPresent := cR.daIncluded.Get(realHash)
450455
assert.True(t, realPresent, "restart %d: real hash present after re-fire", restart)
451456
assert.Equal(t, 1, cR.daIncluded.Len(), "restart %d: no orphan after re-fire", restart)
452457

453-
// The snapshot rewritten by re-fire must still encode the right data
458+
// The snapshot written by SaveToStore must still encode the right data
454459
// so the next restart can load it correctly.
455-
// (persistSnapshot fires inside setDAIncluded, so the store is up to date.)
456460
}
457461
}

block/internal/submitting/submitter_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -700,10 +700,10 @@ func TestSubmitter_setNodeHeightToDAHeight_AfterRestart(t *testing.T) {
700700
require.NoError(t, batch.SetHeight(3))
701701
require.NoError(t, batch.Commit())
702702

703-
// Mark height 3 as DA-included in the pre-restart cache.
704-
// persistSnapshot fires here and writes the snapshot key to st1.
703+
// Mark height 3 as DA-included in the pre-restart cache, then flush (shutdown).
705704
cm1.SetHeaderDAIncluded(h3.Hash().String(), 12, 3)
706705
cm1.SetDataDAIncluded(d3.DACommitment().String(), 12, 3)
706+
require.NoError(t, cm1.SaveToStore())
707707

708708
// Persist DAIncludedHeight = 2 (height 3 is in-flight, not yet finalized).
709709
daIncBz := make([]byte, 8)

0 commit comments

Comments
 (0)