|
|
@@ -17,12 +17,11 @@
|
|
|
package snapshot
|
|
|
|
|
|
import (
|
|
|
- "bufio"
|
|
|
+ "bytes"
|
|
|
"encoding/binary"
|
|
|
"errors"
|
|
|
"fmt"
|
|
|
"io"
|
|
|
- "os"
|
|
|
"time"
|
|
|
|
|
|
"github.com/VictoriaMetrics/fastcache"
|
|
|
@@ -58,7 +57,7 @@ type journalStorage struct {
|
|
|
}
|
|
|
|
|
|
// loadSnapshot loads a pre-existing state snapshot backed by a key-value store.
|
|
|
-func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, journal string, cache int, root common.Hash) (snapshot, error) {
|
|
|
+func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int, root common.Hash) (snapshot, error) {
|
|
|
// Retrieve the block number and hash of the snapshot, failing if no snapshot
|
|
|
// is present in the database (or crashed mid-update).
|
|
|
baseRoot := rawdb.ReadSnapshotRoot(diskdb)
|
|
|
@@ -71,13 +70,13 @@ func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, journal str
|
|
|
cache: fastcache.New(cache * 1024 * 1024),
|
|
|
root: baseRoot,
|
|
|
}
|
|
|
- // Open the journal, it must exist since even for 0 layer it stores whether
|
|
|
+ // Retrieve the journal, it must exist since even for 0 layer it stores whether
|
|
|
// we've already generated the snapshot or are in progress only
|
|
|
- file, err := os.Open(journal)
|
|
|
- if err != nil {
|
|
|
- return nil, err
|
|
|
+ journal := rawdb.ReadSnapshotJournal(diskdb)
|
|
|
+ if len(journal) == 0 {
|
|
|
+ return nil, errors.New("missing or corrupted snapshot journal")
|
|
|
}
|
|
|
- r := rlp.NewStream(file, 0)
|
|
|
+ r := rlp.NewStream(bytes.NewReader(journal), 0)
|
|
|
|
|
|
// Read the snapshot generation progress for the disk layer
|
|
|
var generator journalGenerator
|
|
|
@@ -162,9 +161,9 @@ func loadDiffLayer(parent snapshot, r *rlp.Stream) (snapshot, error) {
|
|
|
return loadDiffLayer(newDiffLayer(parent, root, accountData, storageData), r)
|
|
|
}
|
|
|
|
|
|
-// Journal is the internal version of Journal that also returns the journal file
|
|
|
-// so subsequent layers know where to write to.
|
|
|
-func (dl *diskLayer) Journal(path string) (io.WriteCloser, common.Hash, error) {
|
|
|
+// Journal writes the persistent layer generator stats into a buffer to be stored
|
|
|
+// in the database as the snapshot journal.
|
|
|
+func (dl *diskLayer) Journal(buffer *bytes.Buffer) (common.Hash, error) {
|
|
|
// If the snapshot is currenty being generated, abort it
|
|
|
var stats *generatorStats
|
|
|
if dl.genAbort != nil {
|
|
|
@@ -180,12 +179,7 @@ func (dl *diskLayer) Journal(path string) (io.WriteCloser, common.Hash, error) {
|
|
|
defer dl.lock.RUnlock()
|
|
|
|
|
|
if dl.stale {
|
|
|
- return nil, common.Hash{}, ErrSnapshotStale
|
|
|
- }
|
|
|
- // We've reached the bottom, open the journal
|
|
|
- file, err := os.Create(path)
|
|
|
- if err != nil {
|
|
|
- return nil, common.Hash{}, err
|
|
|
+ return common.Hash{}, ErrSnapshotStale
|
|
|
}
|
|
|
// Write out the generator marker
|
|
|
entry := journalGenerator{
|
|
|
@@ -198,44 +192,37 @@ func (dl *diskLayer) Journal(path string) (io.WriteCloser, common.Hash, error) {
|
|
|
entry.Slots = stats.slots
|
|
|
entry.Storage = uint64(stats.storage)
|
|
|
}
|
|
|
- if err := rlp.Encode(file, entry); err != nil {
|
|
|
- file.Close()
|
|
|
- return nil, common.Hash{}, err
|
|
|
+ if err := rlp.Encode(buffer, entry); err != nil {
|
|
|
+ return common.Hash{}, err
|
|
|
}
|
|
|
- return file, dl.root, nil
|
|
|
+ return dl.root, nil
|
|
|
}
|
|
|
|
|
|
-// Journal is the internal version of Journal that also returns the journal file
|
|
|
-// so subsequent layers know where to write to.
|
|
|
-func (dl *diffLayer) Journal(path string) (io.WriteCloser, common.Hash, error) {
|
|
|
+// Journal writes the memory layer contents into a buffer to be stored in the
|
|
|
+// database as the snapshot journal.
|
|
|
+func (dl *diffLayer) Journal(buffer *bytes.Buffer) (common.Hash, error) {
|
|
|
// Journal the parent first
|
|
|
- writer, base, err := dl.parent.Journal(path)
|
|
|
+ base, err := dl.parent.Journal(buffer)
|
|
|
if err != nil {
|
|
|
- return nil, common.Hash{}, err
|
|
|
+ return common.Hash{}, err
|
|
|
}
|
|
|
// Ensure the layer didn't get stale
|
|
|
dl.lock.RLock()
|
|
|
defer dl.lock.RUnlock()
|
|
|
|
|
|
if dl.stale {
|
|
|
- writer.Close()
|
|
|
- return nil, common.Hash{}, ErrSnapshotStale
|
|
|
+ return common.Hash{}, ErrSnapshotStale
|
|
|
}
|
|
|
// Everything below was journalled, persist this layer too
|
|
|
- buf := bufio.NewWriter(writer)
|
|
|
- if err := rlp.Encode(buf, dl.root); err != nil {
|
|
|
- buf.Flush()
|
|
|
- writer.Close()
|
|
|
- return nil, common.Hash{}, err
|
|
|
+ if err := rlp.Encode(buffer, dl.root); err != nil {
|
|
|
+ return common.Hash{}, err
|
|
|
}
|
|
|
accounts := make([]journalAccount, 0, len(dl.accountData))
|
|
|
for hash, blob := range dl.accountData {
|
|
|
accounts = append(accounts, journalAccount{Hash: hash, Blob: blob})
|
|
|
}
|
|
|
- if err := rlp.Encode(buf, accounts); err != nil {
|
|
|
- buf.Flush()
|
|
|
- writer.Close()
|
|
|
- return nil, common.Hash{}, err
|
|
|
+ if err := rlp.Encode(buffer, accounts); err != nil {
|
|
|
+ return common.Hash{}, err
|
|
|
}
|
|
|
storage := make([]journalStorage, 0, len(dl.storageData))
|
|
|
for hash, slots := range dl.storageData {
|
|
|
@@ -247,11 +234,8 @@ func (dl *diffLayer) Journal(path string) (io.WriteCloser, common.Hash, error) {
|
|
|
}
|
|
|
storage = append(storage, journalStorage{Hash: hash, Keys: keys, Vals: vals})
|
|
|
}
|
|
|
- if err := rlp.Encode(buf, storage); err != nil {
|
|
|
- buf.Flush()
|
|
|
- writer.Close()
|
|
|
- return nil, common.Hash{}, err
|
|
|
+ if err := rlp.Encode(buffer, storage); err != nil {
|
|
|
+ return common.Hash{}, err
|
|
|
}
|
|
|
- buf.Flush()
|
|
|
- return writer, base, nil
|
|
|
+ return base, nil
|
|
|
}
|