Skip to content

Commit 7c30f4d

Browse files
authored
Merge pull request ethereum#21804 from karalabe/snapshot-marker-sync
core/state/snapshot: update generator marker in sync with flushes
2 parents 040928d + 7b7b327 commit 7c30f4d

File tree

4 files changed

+58
-42
lines changed

4 files changed

+58
-42
lines changed

core/blockchain_snapshot_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,7 @@ func testSnapshot(t *testing.T, tt *snapshotTest) {
675675
if _, err := chain.InsertChain(blocks[startPoint:]); err != nil {
676676
t.Fatalf("Failed to import canonical chain tail: %v", err)
677677
}
678-
// Set the flag for writing legacy journal if ncessary
678+
// Set the flag for writing legacy journal if necessary
679679
if tt.legacy {
680680
chain.writeLegacyJournal = true
681681
}
@@ -708,7 +708,6 @@ func testSnapshot(t *testing.T, tt *snapshotTest) {
708708
} else if tt.gapped > 0 {
709709
// Insert blocks without enabling snapshot if gapping is required.
710710
chain.Stop()
711-
712711
gappedBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], engine, gendb, tt.gapped, func(i int, b *BlockGen) {})
713712

714713
// Insert a few more blocks without enabling snapshot
@@ -766,6 +765,7 @@ func testSnapshot(t *testing.T, tt *snapshotTest) {
766765
defer chain.Stop()
767766
} else {
768767
chain.Stop()
768+
769769
// Restart the chain normally
770770
chain, err = NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
771771
if err != nil {

core/state/snapshot/generate.go

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package snapshot
1919
import (
2020
"bytes"
2121
"encoding/binary"
22+
"fmt"
2223
"math/big"
2324
"time"
2425

@@ -116,6 +117,38 @@ func generateSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache i
116117
return base
117118
}
118119

120+
// journalProgress persists the generator stats into the database to resume later.
121+
func journalProgress(db ethdb.KeyValueWriter, marker []byte, stats *generatorStats) {
122+
// Write out the generator marker. Note it's a standalone disk layer generator
123+
// which is not mixed with journal. It's ok if the generator is persisted while
124+
// journal is not.
125+
entry := journalGenerator{
126+
Done: marker == nil,
127+
Marker: marker,
128+
}
129+
if stats != nil {
130+
entry.Wiping = (stats.wiping != nil)
131+
entry.Accounts = stats.accounts
132+
entry.Slots = stats.slots
133+
entry.Storage = uint64(stats.storage)
134+
}
135+
blob, err := rlp.EncodeToBytes(entry)
136+
if err != nil {
137+
panic(err) // Cannot happen, here to catch dev errors
138+
}
139+
var logstr string
140+
switch len(marker) {
141+
case 0:
142+
logstr = "done"
143+
case common.HashLength:
144+
logstr = fmt.Sprintf("%#x", marker)
145+
default:
146+
logstr = fmt.Sprintf("%#x:%#x", marker[:common.HashLength], marker[common.HashLength:])
147+
}
148+
log.Debug("Journalled generator progress", "progress", logstr)
149+
rawdb.WriteSnapshotGenerator(db, blob)
150+
}
151+
119152
// generate is a background thread that iterates over the state and storage tries,
120153
// constructing the state snapshot. All the arguments are purely for statistics
121154
// gethering and logging, since the method surfs the blocks as they arrive, often
@@ -187,11 +220,15 @@ func (dl *diskLayer) generate(stats *generatorStats) {
187220
if batch.ValueSize() > ethdb.IdealBatchSize || abort != nil {
188221
// Only write and set the marker if we actually did something useful
189222
if batch.ValueSize() > 0 {
223+
// Ensure the generator entry is in sync with the data
224+
marker := accountHash[:]
225+
journalProgress(batch, marker, stats)
226+
190227
batch.Write()
191228
batch.Reset()
192229

193230
dl.lock.Lock()
194-
dl.genMarker = accountHash[:]
231+
dl.genMarker = marker
195232
dl.lock.Unlock()
196233
}
197234
if abort != nil {
@@ -228,11 +265,15 @@ func (dl *diskLayer) generate(stats *generatorStats) {
228265
if batch.ValueSize() > ethdb.IdealBatchSize || abort != nil {
229266
// Only write and set the marker if we actually did something useful
230267
if batch.ValueSize() > 0 {
268+
// Ensure the generator entry is in sync with the data
269+
marker := append(accountHash[:], storeIt.Key...)
270+
journalProgress(batch, marker, stats)
271+
231272
batch.Write()
232273
batch.Reset()
233274

234275
dl.lock.Lock()
235-
dl.genMarker = append(accountHash[:], storeIt.Key...)
276+
dl.genMarker = marker
236277
dl.lock.Unlock()
237278
}
238279
if abort != nil {
@@ -264,6 +305,9 @@ func (dl *diskLayer) generate(stats *generatorStats) {
264305
}
265306
// Snapshot fully generated, set the marker to nil
266307
if batch.ValueSize() > 0 {
308+
// Ensure the generator entry is in sync with the data
309+
journalProgress(batch, nil, stats)
310+
267311
batch.Write()
268312
}
269313
log.Info("Generated state snapshot", "accounts", stats.accounts, "slots", stats.slots,

core/state/snapshot/journal.go

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,8 @@ func loadDiffLayer(parent snapshot, r *rlp.Stream) (snapshot, error) {
276276
return loadDiffLayer(newDiffLayer(parent, root, destructSet, accountData, storageData), r)
277277
}
278278

279-
// Journal writes the persistent layer generator stats into a buffer to be stored
280-
// in the database as the snapshot journal.
279+
// Journal terminates any in-progress snapshot generation, also implicitly pushing
280+
// the progress into the database.
281281
func (dl *diskLayer) Journal(buffer *bytes.Buffer) (common.Hash, error) {
282282
// If the snapshot is currently being generated, abort it
283283
var stats *generatorStats
@@ -296,25 +296,10 @@ func (dl *diskLayer) Journal(buffer *bytes.Buffer) (common.Hash, error) {
296296
if dl.stale {
297297
return common.Hash{}, ErrSnapshotStale
298298
}
299-
// Write out the generator marker. Note it's a standalone disk layer generator
300-
// which is not mixed with journal. It's ok if the generator is persisted while
301-
// journal is not.
302-
entry := journalGenerator{
303-
Done: dl.genMarker == nil,
304-
Marker: dl.genMarker,
305-
}
306-
if stats != nil {
307-
entry.Wiping = (stats.wiping != nil)
308-
entry.Accounts = stats.accounts
309-
entry.Slots = stats.slots
310-
entry.Storage = uint64(stats.storage)
311-
}
312-
blob, err := rlp.EncodeToBytes(entry)
313-
if err != nil {
314-
return common.Hash{}, err
315-
}
316-
log.Debug("Journalled disk layer", "root", dl.root, "complete", dl.genMarker == nil)
317-
rawdb.WriteSnapshotGenerator(dl.diskdb, blob)
299+
// Ensure the generator stats is written even if none was ran this cycle
300+
journalProgress(dl.diskdb, dl.genMarker, stats)
301+
302+
log.Debug("Journalled disk layer", "root", dl.root)
318303
return dl.root, nil
319304
}
320305

@@ -401,6 +386,7 @@ func (dl *diskLayer) LegacyJournal(buffer *bytes.Buffer) (common.Hash, error) {
401386
entry.Slots = stats.slots
402387
entry.Storage = uint64(stats.storage)
403388
}
389+
log.Debug("Legacy journalled disk layer", "root", dl.root)
404390
if err := rlp.Encode(buffer, entry); err != nil {
405391
return common.Hash{}, err
406392
}
@@ -455,6 +441,6 @@ func (dl *diffLayer) LegacyJournal(buffer *bytes.Buffer) (common.Hash, error) {
455441
if err := rlp.Encode(buffer, storage); err != nil {
456442
return common.Hash{}, err
457443
}
458-
log.Debug("Journalled diff layer", "root", dl.root, "parent", dl.parent.Root())
444+
log.Debug("Legacy journalled disk layer", "root", dl.root, "parent", dl.parent.Root())
459445
return base, nil
460446
}

core/state/snapshot/snapshot.go

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -512,22 +512,8 @@ func diffToDisk(bottom *diffLayer) *diskLayer {
512512
// Update the snapshot block marker and write any remainder data
513513
rawdb.WriteSnapshotRoot(batch, bottom.root)
514514

515-
// Write out the generator marker
516-
entry := journalGenerator{
517-
Done: base.genMarker == nil,
518-
Marker: base.genMarker,
519-
}
520-
if stats != nil {
521-
entry.Wiping = (stats.wiping != nil)
522-
entry.Accounts = stats.accounts
523-
entry.Slots = stats.slots
524-
entry.Storage = uint64(stats.storage)
525-
}
526-
blob, err := rlp.EncodeToBytes(entry)
527-
if err != nil {
528-
panic(fmt.Sprintf("Failed to RLP encode generator %v", err))
529-
}
530-
rawdb.WriteSnapshotGenerator(batch, blob)
515+
// Write out the generator progress marker and report
516+
journalProgress(batch, base.genMarker, stats)
531517

532518
// Flush all the updates in the single db operation. Ensure the
533519
// disk layer transition is atomic.

0 commit comments

Comments
 (0)