Skip to content

Commit 3cda898

Browse files
rjl493456442holiman
authored andcommitted
core, cmd, trie: fix the condition of pathdb initialization (ethereum#28718)
Original problem was caused by ethereum#28595, where we made it so that as soon as we start to sync, the root of the disk layer is deleted. That is not wrong per se, but another part of the code uses the "presence of the root" as an init-check for the pathdb. And, since the init-check now failed, the code tried to re-initialize it which failed since a sync was already ongoing. The total impact being: after a state-sync has begun, if the node for some reason is is shut down, it will refuse to start up again, with the error message: `Fatal: Failed to register the Ethereum service: waiting for sync.`. This change also modifies how `geth removedb` works, so that the user is prompted for two things: `state data` and `ancient chain`. The former includes both the chaindb aswell as any state history stored in ancients. --------- Co-authored-by: Martin HS <[email protected]>
1 parent 998007e commit 3cda898

File tree

5 files changed

+95
-62
lines changed

5 files changed

+95
-62
lines changed

cmd/geth/dbcmd.go

Lines changed: 56 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -198,60 +198,73 @@ WARNING: This is a low-level operation which may cause database corruption!`,
198198
func removeDB(ctx *cli.Context) error {
199199
stack, config := makeConfigNode(ctx)
200200

201-
// Remove the full node state database
202-
path := stack.ResolvePath("chaindata")
203-
if common.FileExist(path) {
204-
confirmAndRemoveDB(path, "full node state database")
205-
} else {
206-
log.Info("Full node state database missing", "path", path)
207-
}
208-
// Remove the full node ancient database
209-
path = config.Eth.DatabaseFreezer
201+
// Resolve folder paths.
202+
var (
203+
rootDir = stack.ResolvePath("chaindata")
204+
ancientDir = config.Eth.DatabaseFreezer
205+
)
210206
switch {
211-
case path == "":
212-
path = filepath.Join(stack.ResolvePath("chaindata"), "ancient")
213-
case !filepath.IsAbs(path):
214-
path = config.Node.ResolvePath(path)
215-
}
216-
if common.FileExist(path) {
217-
confirmAndRemoveDB(path, "full node ancient database")
218-
} else {
219-
log.Info("Full node ancient database missing", "path", path)
220-
}
221-
// Remove the light node database
222-
path = stack.ResolvePath("lightchaindata")
223-
if common.FileExist(path) {
224-
confirmAndRemoveDB(path, "light node database")
225-
} else {
226-
log.Info("Light node database missing", "path", path)
227-
}
207+
case ancientDir == "":
208+
ancientDir = filepath.Join(stack.ResolvePath("chaindata"), "ancient")
209+
case !filepath.IsAbs(ancientDir):
210+
ancientDir = config.Node.ResolvePath(ancientDir)
211+
}
212+
// Delete state data
213+
statePaths := []string{rootDir, filepath.Join(ancientDir, rawdb.StateFreezerName)}
214+
confirmAndRemoveDB(statePaths, "state data")
215+
216+
// Delete ancient chain
217+
chainPaths := []string{filepath.Join(ancientDir, rawdb.ChainFreezerName)}
218+
confirmAndRemoveDB(chainPaths, "ancient chain")
228219
return nil
229220
}
230221

222+
// removeFolder deletes all files (not folders) inside the directory 'dir' (but
223+
// not files in subfolders).
224+
func removeFolder(dir string) {
225+
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
226+
// If we're at the top level folder, recurse into
227+
if path == dir {
228+
return nil
229+
}
230+
// Delete all the files, but not subfolders
231+
if !info.IsDir() {
232+
os.Remove(path)
233+
return nil
234+
}
235+
return filepath.SkipDir
236+
})
237+
}
238+
231239
// confirmAndRemoveDB prompts the user for a last confirmation and removes the
232-
// folder if accepted.
233-
func confirmAndRemoveDB(database string, kind string) {
234-
confirm, err := prompt.Stdin.PromptConfirm(fmt.Sprintf("Remove %s (%s)?", kind, database))
240+
// list of folders if accepted.
241+
func confirmAndRemoveDB(paths []string, kind string) {
242+
msg := fmt.Sprintf("Location(s) of '%s': \n", kind)
243+
for _, path := range paths {
244+
msg += fmt.Sprintf("\t- %s\n", path)
245+
}
246+
fmt.Println(msg)
247+
248+
confirm, err := prompt.Stdin.PromptConfirm(fmt.Sprintf("Remove '%s'?", kind))
235249
switch {
236250
case err != nil:
237251
utils.Fatalf("%v", err)
238252
case !confirm:
239-
log.Info("Database deletion skipped", "path", database)
253+
log.Info("Database deletion skipped", "kind", kind, "paths", paths)
240254
default:
241-
start := time.Now()
242-
filepath.Walk(database, func(path string, info os.FileInfo, err error) error {
243-
// If we're at the top level folder, recurse into
244-
if path == database {
245-
return nil
255+
var (
256+
deleted []string
257+
start = time.Now()
258+
)
259+
for _, path := range paths {
260+
if common.FileExist(path) {
261+
removeFolder(path)
262+
deleted = append(deleted, path)
263+
} else {
264+
log.Info("Folder is not existent", "path", path)
246265
}
247-
// Delete all the files, but not subfolders
248-
if !info.IsDir() {
249-
os.Remove(path)
250-
return nil
251-
}
252-
return filepath.SkipDir
253-
})
254-
log.Info("Database successfully deleted", "path", database, "elapsed", common.PrettyDuration(time.Since(start)))
266+
}
267+
log.Info("Database successfully deleted", "kind", kind, "paths", deleted, "elapsed", common.PrettyDuration(time.Since(start)))
255268
}
256269
}
257270

core/rawdb/ancient_scheme.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,14 @@ var stateFreezerNoSnappy = map[string]bool{
6868

6969
// The list of identifiers of ancient stores.
7070
var (
71-
chainFreezerName = "chain" // the folder name of chain segment ancient store.
72-
stateFreezerName = "state" // the folder name of reverse diff ancient store.
71+
ChainFreezerName = "chain" // the folder name of chain segment ancient store.
72+
StateFreezerName = "state" // the folder name of reverse diff ancient store.
7373
)
7474

7575
// freezers the collections of all builtin freezers.
76-
var freezers = []string{chainFreezerName, stateFreezerName}
76+
var freezers = []string{ChainFreezerName, StateFreezerName}
7777

7878
// NewStateFreezer initializes the freezer for state history.
7979
func NewStateFreezer(ancientDir string, readOnly bool) (*ResettableFreezer, error) {
80-
return NewResettableFreezer(filepath.Join(ancientDir, stateFreezerName), "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy)
80+
return NewResettableFreezer(filepath.Join(ancientDir, StateFreezerName), "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy)
8181
}

core/rawdb/ancient_utils.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,14 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) {
8181
var infos []freezerInfo
8282
for _, freezer := range freezers {
8383
switch freezer {
84-
case chainFreezerName:
85-
info, err := inspect(chainFreezerName, chainFreezerNoSnappy, db)
84+
case ChainFreezerName:
85+
info, err := inspect(ChainFreezerName, chainFreezerNoSnappy, db)
8686
if err != nil {
8787
return nil, err
8888
}
8989
infos = append(infos, info)
9090

91-
case stateFreezerName:
91+
case StateFreezerName:
9292
if ReadStateScheme(db) != PathScheme {
9393
continue
9494
}
@@ -102,7 +102,7 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) {
102102
}
103103
defer f.Close()
104104

105-
info, err := inspect(stateFreezerName, stateFreezerNoSnappy, f)
105+
info, err := inspect(StateFreezerName, stateFreezerNoSnappy, f)
106106
if err != nil {
107107
return nil, err
108108
}
@@ -125,9 +125,9 @@ func InspectFreezerTable(ancient string, freezerName string, tableName string, s
125125
tables map[string]bool
126126
)
127127
switch freezerName {
128-
case chainFreezerName:
128+
case ChainFreezerName:
129129
path, tables = resolveChainFreezerDir(ancient), chainFreezerNoSnappy
130-
case stateFreezerName:
130+
case StateFreezerName:
131131
path, tables = filepath.Join(ancient, freezerName), stateFreezerNoSnappy
132132
default:
133133
return fmt.Errorf("unknown freezer, supported ones: %v", freezers)

core/rawdb/database.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ func resolveChainFreezerDir(ancient string) string {
178178
// sub folder, if not then two possibilities:
179179
// - chain freezer is not initialized
180180
// - chain freezer exists in legacy location (root ancient folder)
181-
freezer := path.Join(ancient, chainFreezerName)
181+
freezer := path.Join(ancient, ChainFreezerName)
182182
if !common.FileExist(freezer) {
183183
if !common.FileExist(ancient) {
184184
// The entire ancient store is not initialized, still use the sub

trie/triedb/pathdb/database.go

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -170,14 +170,31 @@ func New(diskdb ethdb.Database, config *Config) *Database {
170170
}
171171
db.freezer = freezer
172172

173-
// Truncate the extra state histories above in freezer in case
174-
// it's not aligned with the disk layer.
175-
pruned, err := truncateFromHead(db.diskdb, freezer, db.tree.bottom().stateID())
176-
if err != nil {
177-
log.Crit("Failed to truncate extra state histories", "err", err)
178-
}
179-
if pruned != 0 {
180-
log.Warn("Truncated extra state histories", "number", pruned)
173+
diskLayerID := db.tree.bottom().stateID()
174+
if diskLayerID == 0 {
175+
// Reset the entire state histories in case the trie database is
176+
// not initialized yet, as these state histories are not expected.
177+
frozen, err := db.freezer.Ancients()
178+
if err != nil {
179+
log.Crit("Failed to retrieve head of state history", "err", err)
180+
}
181+
if frozen != 0 {
182+
err := db.freezer.Reset()
183+
if err != nil {
184+
log.Crit("Failed to reset state histories", "err", err)
185+
}
186+
log.Info("Truncated extraneous state history")
187+
}
188+
} else {
189+
// Truncate the extra state histories above in freezer in case
190+
// it's not aligned with the disk layer.
191+
pruned, err := truncateFromHead(db.diskdb, freezer, diskLayerID)
192+
if err != nil {
193+
log.Crit("Failed to truncate extra state histories", "err", err)
194+
}
195+
if pruned != 0 {
196+
log.Warn("Truncated extra state histories", "number", pruned)
197+
}
181198
}
182199
}
183200
// Disable database in case node is still in the initial state sync stage.
@@ -431,6 +448,9 @@ func (db *Database) Initialized(genesisRoot common.Hash) bool {
431448
inited = true
432449
}
433450
})
451+
if !inited {
452+
inited = rawdb.ReadSnapSyncStatusFlag(db.diskdb) != rawdb.StateSyncUnknown
453+
}
434454
return inited
435455
}
436456

0 commit comments

Comments
 (0)