|
|
@@ -19,6 +19,7 @@ package snapshot
|
|
|
import (
|
|
|
"bytes"
|
|
|
"encoding/binary"
|
|
|
+ "fmt"
|
|
|
"math/big"
|
|
|
"time"
|
|
|
|
|
|
@@ -116,6 +117,38 @@ func generateSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache i
|
|
|
return base
|
|
|
}
|
|
|
|
|
|
+// journalProgress persists the generator stats into the database to resume later.
|
|
|
+func journalProgress(db ethdb.KeyValueWriter, marker []byte, stats *generatorStats) {
|
|
|
+ // Write out the generator marker. Note it's a standalone disk layer generator
|
|
|
+ // which is not mixed with journal. It's ok if the generator is persisted while
|
|
|
+ // journal is not.
|
|
|
+ entry := journalGenerator{
|
|
|
+ Done: marker == nil,
|
|
|
+ Marker: marker,
|
|
|
+ }
|
|
|
+ if stats != nil {
|
|
|
+ entry.Wiping = (stats.wiping != nil)
|
|
|
+ entry.Accounts = stats.accounts
|
|
|
+ entry.Slots = stats.slots
|
|
|
+ entry.Storage = uint64(stats.storage)
|
|
|
+ }
|
|
|
+ blob, err := rlp.EncodeToBytes(entry)
|
|
|
+ if err != nil {
|
|
|
+ panic(err) // Cannot happen, here to catch dev errors
|
|
|
+ }
|
|
|
+ var logstr string
|
|
|
+ switch len(marker) {
|
|
|
+ case 0:
|
|
|
+ logstr = "done"
|
|
|
+ case common.HashLength:
|
|
|
+ logstr = fmt.Sprintf("%#x", marker)
|
|
|
+ default:
|
|
|
+ logstr = fmt.Sprintf("%#x:%#x", marker[:common.HashLength], marker[common.HashLength:])
|
|
|
+ }
|
|
|
+ log.Debug("Journalled generator progress", "progress", logstr)
|
|
|
+ rawdb.WriteSnapshotGenerator(db, blob)
|
|
|
+}
|
|
|
+
|
|
|
// generate is a background thread that iterates over the state and storage tries,
|
|
|
// constructing the state snapshot. All the arguments are purely for statistics
|
|
|
// gethering and logging, since the method surfs the blocks as they arrive, often
|
|
|
@@ -187,11 +220,15 @@ func (dl *diskLayer) generate(stats *generatorStats) {
|
|
|
if batch.ValueSize() > ethdb.IdealBatchSize || abort != nil {
|
|
|
// Only write and set the marker if we actually did something useful
|
|
|
if batch.ValueSize() > 0 {
|
|
|
+ // Ensure the generator entry is in sync with the data
|
|
|
+ marker := accountHash[:]
|
|
|
+ journalProgress(batch, marker, stats)
|
|
|
+
|
|
|
batch.Write()
|
|
|
batch.Reset()
|
|
|
|
|
|
dl.lock.Lock()
|
|
|
- dl.genMarker = accountHash[:]
|
|
|
+ dl.genMarker = marker
|
|
|
dl.lock.Unlock()
|
|
|
}
|
|
|
if abort != nil {
|
|
|
@@ -228,11 +265,15 @@ func (dl *diskLayer) generate(stats *generatorStats) {
|
|
|
if batch.ValueSize() > ethdb.IdealBatchSize || abort != nil {
|
|
|
// Only write and set the marker if we actually did something useful
|
|
|
if batch.ValueSize() > 0 {
|
|
|
+ // Ensure the generator entry is in sync with the data
|
|
|
+ marker := append(accountHash[:], storeIt.Key...)
|
|
|
+ journalProgress(batch, marker, stats)
|
|
|
+
|
|
|
batch.Write()
|
|
|
batch.Reset()
|
|
|
|
|
|
dl.lock.Lock()
|
|
|
- dl.genMarker = append(accountHash[:], storeIt.Key...)
|
|
|
+ dl.genMarker = marker
|
|
|
dl.lock.Unlock()
|
|
|
}
|
|
|
if abort != nil {
|
|
|
@@ -264,6 +305,9 @@ func (dl *diskLayer) generate(stats *generatorStats) {
|
|
|
}
|
|
|
// Snapshot fully generated, set the marker to nil
|
|
|
if batch.ValueSize() > 0 {
|
|
|
+ // Ensure the generator entry is in sync with the data
|
|
|
+ journalProgress(batch, nil, stats)
|
|
|
+
|
|
|
batch.Write()
|
|
|
}
|
|
|
log.Info("Generated state snapshot", "accounts", stats.accounts, "slots", stats.slots,
|