@@ -108,44 +108,15 @@ func loadAndParseJournal(db ethdb.KeyValueStore, base *diskLayer) (snapshot, jou
108108 // So if there is no journal, or the journal is invalid(e.g. the journal
109109 // is not matched with disk layer; or the it's the legacy-format journal,
110110 // etc.), we just discard all diffs and try to recover them later.
111- journal := rawdb .ReadSnapshotJournal (db )
112- if len (journal ) == 0 {
113- log .Warn ("Loaded snapshot journal" , "diskroot" , base .root , "diffs" , "missing" )
114- return base , generator , nil
115- }
116- r := rlp .NewStream (bytes .NewReader (journal ), 0 )
117-
118- // Firstly, resolve the first element as the journal version
119- version , err := r .Uint ()
111+ var current snapshot = base
112+ err := iterateJournal (db , func (parent common.Hash , root common.Hash , destructSet map [common.Hash ]struct {}, accountData map [common.Hash ][]byte , storageData map [common.Hash ]map [common.Hash ][]byte ) error {
113+ current = newDiffLayer (current , root , destructSet , accountData , storageData )
114+ return nil
115+ })
120116 if err != nil {
121- log .Warn ("Failed to resolve the journal version" , "error" , err )
122117 return base , generator , nil
123118 }
124- if version != journalVersion {
125- log .Warn ("Discarded the snapshot journal with wrong version" , "required" , journalVersion , "got" , version )
126- return base , generator , nil
127- }
128- // Secondly, resolve the disk layer root, ensure it's continuous
129- // with disk layer. Note now we can ensure it's the snapshot journal
130- // correct version, so we expect everything can be resolved properly.
131- var root common.Hash
132- if err := r .Decode (& root ); err != nil {
133- return nil , journalGenerator {}, errors .New ("missing disk layer root" )
134- }
135- // The diff journal is not matched with disk, discard them.
136- // It can happen that Geth crashes without persisting the latest
137- // diff journal.
138- if ! bytes .Equal (root .Bytes (), base .root .Bytes ()) {
139- log .Warn ("Loaded snapshot journal" , "diskroot" , base .root , "diffs" , "unmatched" )
140- return base , generator , nil
141- }
142- // Load all the snapshot diffs from the journal
143- snapshot , err := loadDiffLayer (base , r )
144- if err != nil {
145- return nil , journalGenerator {}, err
146- }
147- log .Debug ("Loaded snapshot journal" , "diskroot" , base .root , "diffhead" , snapshot .Root ())
148- return snapshot , generator , nil
119+ return current , generator , nil
149120}
150121
151122// loadSnapshot loads a pre-existing state snapshot backed by a key-value store.
@@ -218,57 +189,6 @@ func loadSnapshot(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int,
218189 return snapshot , false , nil
219190}
220191
221- // loadDiffLayer reads the next sections of a snapshot journal, reconstructing a new
222- // diff and verifying that it can be linked to the requested parent.
223- func loadDiffLayer (parent snapshot , r * rlp.Stream ) (snapshot , error ) {
224- // Read the next diff journal entry
225- var root common.Hash
226- if err := r .Decode (& root ); err != nil {
227- // The first read may fail with EOF, marking the end of the journal
228- if err == io .EOF {
229- return parent , nil
230- }
231- return nil , fmt .Errorf ("load diff root: %v" , err )
232- }
233- var destructs []journalDestruct
234- if err := r .Decode (& destructs ); err != nil {
235- return nil , fmt .Errorf ("load diff destructs: %v" , err )
236- }
237- destructSet := make (map [common.Hash ]struct {})
238- for _ , entry := range destructs {
239- destructSet [entry .Hash ] = struct {}{}
240- }
241- var accounts []journalAccount
242- if err := r .Decode (& accounts ); err != nil {
243- return nil , fmt .Errorf ("load diff accounts: %v" , err )
244- }
245- accountData := make (map [common.Hash ][]byte )
246- for _ , entry := range accounts {
247- if len (entry .Blob ) > 0 { // RLP loses nil-ness, but `[]byte{}` is not a valid item, so reinterpret that
248- accountData [entry .Hash ] = entry .Blob
249- } else {
250- accountData [entry .Hash ] = nil
251- }
252- }
253- var storage []journalStorage
254- if err := r .Decode (& storage ); err != nil {
255- return nil , fmt .Errorf ("load diff storage: %v" , err )
256- }
257- storageData := make (map [common.Hash ]map [common.Hash ][]byte )
258- for _ , entry := range storage {
259- slots := make (map [common.Hash ][]byte )
260- for i , key := range entry .Keys {
261- if len (entry .Vals [i ]) > 0 { // RLP loses nil-ness, but `[]byte{}` is not a valid item, so reinterpret that
262- slots [key ] = entry .Vals [i ]
263- } else {
264- slots [key ] = nil
265- }
266- }
267- storageData [entry .Hash ] = slots
268- }
269- return loadDiffLayer (newDiffLayer (parent , root , destructSet , accountData , storageData ), r )
270- }
271-
272192// Journal terminates any in-progress snapshot generation, also implicitly pushing
273193// the progress into the database.
274194func (dl * diskLayer ) Journal (buffer * bytes.Buffer ) (common.Hash , error ) {
@@ -345,3 +265,96 @@ func (dl *diffLayer) Journal(buffer *bytes.Buffer) (common.Hash, error) {
345265 log .Debug ("Journalled diff layer" , "root" , dl .root , "parent" , dl .parent .Root ())
346266 return base , nil
347267}
268+
269+ // journalCallback is a function which is invoked by iterateJournal, every
270+ // time a difflayer is loaded from disk.
271+ type journalCallback = func (parent common.Hash , root common.Hash , destructs map [common.Hash ]struct {}, accounts map [common.Hash ][]byte , storage map [common.Hash ]map [common.Hash ][]byte ) error
272+
273+ // iterateJournal iterates through the journalled difflayers, loading them from
274+ // the database, and invoking the callback for each loaded layer.
275+ // The order is incremental; starting with the bottom-most difflayer, going towards
276+ // the most recent layer.
277+ // This method returns error either if there was some error reading from disk,
278+ // OR if the callback returns an error when invoked.
279+ func iterateJournal (db ethdb.KeyValueReader , callback journalCallback ) error {
280+ journal := rawdb .ReadSnapshotJournal (db )
281+ if len (journal ) == 0 {
282+ log .Warn ("Loaded snapshot journal" , "diffs" , "missing" )
283+ return nil
284+ }
285+ r := rlp .NewStream (bytes .NewReader (journal ), 0 )
286+ // Firstly, resolve the first element as the journal version
287+ version , err := r .Uint ()
288+ if err != nil {
289+ log .Warn ("Failed to resolve the journal version" , "error" , err )
290+ return errors .New ("failed to resolve journal version" )
291+ }
292+ if version != journalVersion {
293+ log .Warn ("Discarded the snapshot journal with wrong version" , "required" , journalVersion , "got" , version )
294+ return errors .New ("wrong journal version" )
295+ }
296+ // Secondly, resolve the disk layer root, ensure it's continuous
297+ // with disk layer. Note now we can ensure it's the snapshot journal
298+ // correct version, so we expect everything can be resolved properly.
299+ var parent common.Hash
300+ if err := r .Decode (& parent ); err != nil {
301+ return errors .New ("missing disk layer root" )
302+ }
303+ if baseRoot := rawdb .ReadSnapshotRoot (db ); baseRoot != parent {
304+ log .Warn ("Loaded snapshot journal" , "diskroot" , baseRoot , "diffs" , "unmatched" )
305+ return fmt .Errorf ("mismatched disk and diff layers" )
306+ }
307+ for {
308+ var (
309+ root common.Hash
310+ destructs []journalDestruct
311+ accounts []journalAccount
312+ storage []journalStorage
313+ destructSet = make (map [common.Hash ]struct {})
314+ accountData = make (map [common.Hash ][]byte )
315+ storageData = make (map [common.Hash ]map [common.Hash ][]byte )
316+ )
317+ // Read the next diff journal entry
318+ if err := r .Decode (& root ); err != nil {
319+ // The first read may fail with EOF, marking the end of the journal
320+ if errors .Is (err , io .EOF ) {
321+ return nil
322+ }
323+ return fmt .Errorf ("load diff root: %v" , err )
324+ }
325+ if err := r .Decode (& destructs ); err != nil {
326+ return fmt .Errorf ("load diff destructs: %v" , err )
327+ }
328+ if err := r .Decode (& accounts ); err != nil {
329+ return fmt .Errorf ("load diff accounts: %v" , err )
330+ }
331+ if err := r .Decode (& storage ); err != nil {
332+ return fmt .Errorf ("load diff storage: %v" , err )
333+ }
334+ for _ , entry := range destructs {
335+ destructSet [entry .Hash ] = struct {}{}
336+ }
337+ for _ , entry := range accounts {
338+ if len (entry .Blob ) > 0 { // RLP loses nil-ness, but `[]byte{}` is not a valid item, so reinterpret that
339+ accountData [entry .Hash ] = entry .Blob
340+ } else {
341+ accountData [entry .Hash ] = nil
342+ }
343+ }
344+ for _ , entry := range storage {
345+ slots := make (map [common.Hash ][]byte )
346+ for i , key := range entry .Keys {
347+ if len (entry .Vals [i ]) > 0 { // RLP loses nil-ness, but `[]byte{}` is not a valid item, so reinterpret that
348+ slots [key ] = entry .Vals [i ]
349+ } else {
350+ slots [key ] = nil
351+ }
352+ }
353+ storageData [entry .Hash ] = slots
354+ }
355+ if err := callback (parent , root , destructSet , accountData , storageData ); err != nil {
356+ return err
357+ }
358+ parent = root
359+ }
360+ }
0 commit comments