|
|
@ -19,6 +19,7 @@ package snapshot |
|
|
|
import ( |
|
|
|
import ( |
|
|
|
"bytes" |
|
|
|
"bytes" |
|
|
|
"encoding/binary" |
|
|
|
"encoding/binary" |
|
|
|
|
|
|
|
"fmt" |
|
|
|
"math/big" |
|
|
|
"math/big" |
|
|
|
"time" |
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
|
@ -116,6 +117,38 @@ func generateSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache i |
|
|
|
return base |
|
|
|
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,
|
|
|
|
// generate is a background thread that iterates over the state and storage tries,
|
|
|
|
// constructing the state snapshot. All the arguments are purely for statistics
|
|
|
|
// constructing the state snapshot. All the arguments are purely for statistics
|
|
|
|
// gethering and logging, since the method surfs the blocks as they arrive, often
|
|
|
|
// 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 { |
|
|
|
if batch.ValueSize() > ethdb.IdealBatchSize || abort != nil { |
|
|
|
// Only write and set the marker if we actually did something useful
|
|
|
|
// Only write and set the marker if we actually did something useful
|
|
|
|
if batch.ValueSize() > 0 { |
|
|
|
if batch.ValueSize() > 0 { |
|
|
|
|
|
|
|
// Ensure the generator entry is in sync with the data
|
|
|
|
|
|
|
|
marker := accountHash[:] |
|
|
|
|
|
|
|
journalProgress(batch, marker, stats) |
|
|
|
|
|
|
|
|
|
|
|
batch.Write() |
|
|
|
batch.Write() |
|
|
|
batch.Reset() |
|
|
|
batch.Reset() |
|
|
|
|
|
|
|
|
|
|
|
dl.lock.Lock() |
|
|
|
dl.lock.Lock() |
|
|
|
dl.genMarker = accountHash[:] |
|
|
|
dl.genMarker = marker |
|
|
|
dl.lock.Unlock() |
|
|
|
dl.lock.Unlock() |
|
|
|
} |
|
|
|
} |
|
|
|
if abort != nil { |
|
|
|
if abort != nil { |
|
|
@ -228,11 +265,15 @@ func (dl *diskLayer) generate(stats *generatorStats) { |
|
|
|
if batch.ValueSize() > ethdb.IdealBatchSize || abort != nil { |
|
|
|
if batch.ValueSize() > ethdb.IdealBatchSize || abort != nil { |
|
|
|
// Only write and set the marker if we actually did something useful
|
|
|
|
// Only write and set the marker if we actually did something useful
|
|
|
|
if batch.ValueSize() > 0 { |
|
|
|
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.Write() |
|
|
|
batch.Reset() |
|
|
|
batch.Reset() |
|
|
|
|
|
|
|
|
|
|
|
dl.lock.Lock() |
|
|
|
dl.lock.Lock() |
|
|
|
dl.genMarker = append(accountHash[:], storeIt.Key...) |
|
|
|
dl.genMarker = marker |
|
|
|
dl.lock.Unlock() |
|
|
|
dl.lock.Unlock() |
|
|
|
} |
|
|
|
} |
|
|
|
if abort != nil { |
|
|
|
if abort != nil { |
|
|
@ -264,6 +305,9 @@ func (dl *diskLayer) generate(stats *generatorStats) { |
|
|
|
} |
|
|
|
} |
|
|
|
// Snapshot fully generated, set the marker to nil
|
|
|
|
// Snapshot fully generated, set the marker to nil
|
|
|
|
if batch.ValueSize() > 0 { |
|
|
|
if batch.ValueSize() > 0 { |
|
|
|
|
|
|
|
// Ensure the generator entry is in sync with the data
|
|
|
|
|
|
|
|
journalProgress(batch, nil, stats) |
|
|
|
|
|
|
|
|
|
|
|
batch.Write() |
|
|
|
batch.Write() |
|
|
|
} |
|
|
|
} |
|
|
|
log.Info("Generated state snapshot", "accounts", stats.accounts, "slots", stats.slots, |
|
|
|
log.Info("Generated state snapshot", "accounts", stats.accounts, "slots", stats.slots, |
|
|
|