diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index de6cf8ae58..c4dca75cec 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -367,7 +367,7 @@ var ( } JournalFileFlag = &cli.BoolFlag{ Name: "journalfile", - Usage: "Enable the in-memory trie node layers to store to wal file when shutdown in pbss (default = false)", + Usage: "Enable journal file to store the TrieJournal when shutdown in pbss (default = false)", Value: false, Category: flags.StateCategory, } diff --git a/eth/backend.go b/eth/backend.go index d025d640cc..245d30b953 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -69,7 +69,7 @@ import ( const ( ChainDBNamespace = "eth/db/chaindata/" - JournalFile = "state.journal" + JournalFile = "trie.journal" ChainData = "chaindata" ) diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 84807e8870..5f7455b8b9 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -320,7 +320,7 @@ func (db *Database) Enable(root common.Hash) error { // Drop the stale state journal in persistent database and // reset the persistent state id back to zero. batch := db.diskdb.NewBatch() - db.journal.JournalDelete() + db.journal.Delete() rawdb.WritePersistentStateID(batch, 0) if err := batch.Write(); err != nil { return err @@ -384,7 +384,7 @@ func (db *Database) Recover(root common.Hash, loader triestate.TrieLoader) error // disk layer won't be accessible from outside. db.tree.reset(dl) } - db.journal.JournalDelete() + db.journal.Delete() _, err := truncateFromHead(db.diskdb, db.freezer, dl.stateID()) if err != nil { return err diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index 4ee4d3c431..6fcb160bdd 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -527,36 +527,35 @@ func TestJournal(t *testing.T) { } } -//func TestCorruptedJournal(t *testing.T) { -// tester := newTester(t, 0) -// defer tester.release() -// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true))) -// -// if err := tester.db.Journal(tester.lastHash()); err != nil { -// t.Errorf("Failed to journal, err: %v", err) -// } -// tester.db.Close() -// _, root := rawdb.ReadAccountTrieNode(tester.db.diskdb, nil) -// -// // Mutate the journal in disk, it should be regarded as invalid -// blob := rawdb.ReadTrieJournal(tester.db.diskdb) -// blob[0] = 1 -// rawdb.WriteTrieJournal(tester.db.diskdb, blob) -// -// // Verify states, all not-yet-written states should be discarded -// tester.db = New(tester.db.diskdb, nil) -// for i := 0; i < len(tester.roots); i++ { -// if tester.roots[i] == root { -// if err := tester.verifyState(root); err != nil { -// t.Fatalf("Disk state is corrupted, err: %v", err) -// } -// continue -// } -// if err := tester.verifyState(tester.roots[i]); err == nil { -// t.Fatal("Unexpected state") -// } -// } -//} +func TestCorruptedJournal(t *testing.T) { + tester := newTester(t, 0) + defer tester.release() + + if err := tester.db.Journal(tester.lastHash()); err != nil { + t.Errorf("Failed to journal, err: %v", err) + } + tester.db.Close() + _, root := rawdb.ReadAccountTrieNode(tester.db.diskdb, nil) + + // Mutate the journal in disk, it should be regarded as invalid + blob := rawdb.ReadTrieJournal(tester.db.diskdb) + blob[0] = 1 + rawdb.WriteTrieJournal(tester.db.diskdb, blob) + + // Verify states, all not-yet-written states should be discarded + tester.db = New(tester.db.diskdb, nil) + for i := 0; i < len(tester.roots); i++ { + if tester.roots[i] == root { + if err := tester.verifyState(root); err != nil { + t.Fatalf("Disk state is corrupted, err: %v", err) + } + continue + } + if err := tester.verifyState(tester.roots[i]); err == nil { + t.Fatal("Unexpected state") + } + } +} // TestTailTruncateHistory function is designed to test a specific edge case where, // when history objects are removed from the end, it should trigger a state flush diff --git a/triedb/pathdb/journal.go b/triedb/pathdb/journal.go index d576137e76..85e193a707 100644 --- a/triedb/pathdb/journal.go +++ b/triedb/pathdb/journal.go @@ -74,25 +74,25 @@ type journalStorage struct { Slots [][]byte } -// journalDB is a journal implementation that stores the journal in db. -type journalDB struct { +// journalKV is a journal implementation that stores the journal in db as a single kv. +type journalKV struct { Journal journalBuf bytes.Buffer // Used for temporary storage in memory, and finally uniformly written to the database during sync. diskdb ethdb.Database // Persistent storage for matured trie nodes } -// journalWAL is a journal implementation that stores the journal in a file. -type journalWAL struct { +// journalFile is a journal implementation that stores the journal in a file. +type journalFile struct { Journal - journalFile string - journalFd *os.File + file string // the file used to store the TrieJournal + fd *os.File // the file's fd } // loadJournal tries to parse the layer journal from the disk. func (db *Database) loadJournal(diskRoot common.Hash) (layer, error) { start := time.Now() - r, err := db.journal.NewJournalReader() - defer db.journal.JournalClose() + r, err := db.journal.newJournalReader() + defer db.journal.Close() if err != nil { return nil, err @@ -459,9 +459,9 @@ func (db *Database) Journal(root common.Hash) error { return errDatabaseReadOnly } // Firstly write out the metadata of journal - db.journal.JournalDelete() - journal := db.journal.NewJournalWriter() - defer db.journal.JournalClose() + db.journal.Delete() + journal := db.journal.newJournalWriter() + defer db.journal.Close() if err := rlp.Encode(journal, journalVersion); err != nil { return err @@ -482,9 +482,9 @@ func (db *Database) Journal(root common.Hash) error { } // Store the journal into the database and return - // JournalSize returns the size of the journal in bytes, It must be called before JournalWriterSync. - journalSize := db.journal.JournalSize() - db.journal.JournalWriterSync() + // Size returns the size of the journal in bytes, It must be called before Sync. + journalSize := db.journal.Size() + db.journal.Sync() // Set the db in read only mode to reject all following mutations db.readOnly = true @@ -493,42 +493,42 @@ func (db *Database) Journal(root common.Hash) error { } type Journal interface { - // NewJournalWriter creates a new journal writer. - NewJournalWriter() io.Writer + // newJournalWriter creates a new journal writer. + newJournalWriter() io.Writer - // NewJournalReader creates a new journal reader. - NewJournalReader() (*rlp.Stream, error) + // newJournalReader creates a new journal reader. + newJournalReader() (*rlp.Stream, error) - // JournalWriterSync flushes the journal writer. - JournalWriterSync() + // Sync flushes the journal writer. + Sync() - // JournalDelete deletes the journal. - JournalDelete() + // Delete deletes the journal. + Delete() - // JournalClose closes the journal. - JournalClose() + // Close closes the journal. + Close() - // JournalSize returns the size of the journal. - JournalSize() uint64 + // Size returns the size of the journal. + Size() uint64 } -func newJournal(journalFile string, db ethdb.Database) Journal { - if len(journalFile) == 0 { - return &journalDB{ +func newJournal(file string, db ethdb.Database) Journal { + if len(file) == 0 { + return &journalKV{ diskdb: db, } } else { - return &journalWAL{ - journalFile: journalFile, + return &journalFile{ + file: file, } } } -func (db *journalDB) NewJournalWriter() io.Writer { +func (db *journalKV) newJournalWriter() io.Writer { return &db.journalBuf } -func (db *journalDB) NewJournalReader() (*rlp.Stream, error) { +func (db *journalKV) newJournalReader() (*rlp.Stream, error) { journal := rawdb.ReadTrieJournal(db.diskdb) if len(journal) == 0 { return nil, errMissJournal @@ -536,52 +536,52 @@ func (db *journalDB) NewJournalReader() (*rlp.Stream, error) { return rlp.NewStream(bytes.NewReader(journal), 0), nil } -func (db *journalDB) JournalWriterSync() { +func (db *journalKV) Sync() { rawdb.WriteTrieJournal(db.diskdb, db.journalBuf.Bytes()) db.journalBuf.Reset() } -func (db *journalDB) JournalDelete() { +func (db *journalKV) Delete() { rawdb.DeleteTrieJournal(db.diskdb) } -func (db *journalDB) JournalClose() { +func (db *journalKV) Close() { } -func (db *journalDB) JournalSize() uint64 { +func (db *journalKV) Size() uint64 { return uint64(db.journalBuf.Len()) } -// NewJournalWriter creates a new journal writer. -func (wal *journalWAL) NewJournalWriter() io.Writer { +// newJournalWriter creates a new journal writer. +func (wal *journalFile) newJournalWriter() io.Writer { var err error - wal.journalFd, err = os.OpenFile(wal.journalFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + wal.fd, err = os.OpenFile(wal.file, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if err != nil { return nil } - return wal.journalFd + return wal.fd } -// NewJournalReader creates a new journal reader. -func (wal *journalWAL) NewJournalReader() (*rlp.Stream, error) { +// newJournalReader creates a new journal reader. +func (wal *journalFile) newJournalReader() (*rlp.Stream, error) { var err error - wal.journalFd, err = os.Open(wal.journalFile) + wal.fd, err = os.Open(wal.file) if errors.Is(err, fs.ErrNotExist) { return nil, errMissJournal } if err != nil { return nil, err } - return rlp.NewStream(wal.journalFd, 0), nil + return rlp.NewStream(wal.fd, 0), nil } -// JournalWriterSync flushes the journal writer. -func (wal *journalWAL) JournalWriterSync() { +// Sync flushes the journal writer. +func (wal *journalFile) Sync() { } -// JournalDelete deletes the journal. -func (wal *journalWAL) JournalDelete() { - file := wal.journalFile +// Delete deletes the journal. +func (wal *journalFile) Delete() { + file := wal.file _, err := os.Stat(file) if os.IsNotExist(err) { return @@ -592,15 +592,15 @@ func (wal *journalWAL) JournalDelete() { } } -// JournalClose closes the journal. -func (wal *journalWAL) JournalClose() { - wal.journalFd.Close() +// Close closes the journal. +func (wal *journalFile) Close() { + wal.fd.Close() } -// JournalSize returns the size of the journal. -func (wal *journalWAL) JournalSize() uint64 { - if wal.journalFd != nil { - fileInfo, err := wal.journalFd.Stat() +// Size returns the size of the journal. +func (wal *journalFile) Size() uint64 { + if wal.fd != nil { + fileInfo, err := wal.fd.Stat() if err != nil { log.Crit("Failed to stat journal", "err", err) }