Skip to content
This repository was archived by the owner on Jun 6, 2025. It is now read-only.

Commit 8b4ed90

Browse files
rjl493456442holiman
authored andcommitted
core, cmd, trie: fix the condition of pathdb initialization (#28718)
Original problem was caused by #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 64cabd1 commit 8b4ed90

File tree

5 files changed

+95
-62
lines changed

5 files changed

+95
-62
lines changed

cmd/ronin/dbcmd.go

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

251-
// Remove the full node state database
252-
path := stack.ResolvePath("chaindata")
253-
if common.FileExist(path) {
254-
confirmAndRemoveDB(path, "full node state database")
255-
} else {
256-
log.Info("Full node state database missing", "path", path)
257-
}
258-
// Remove the full node ancient database
259-
path = config.Eth.DatabaseFreezer
251+
// Resolve folder paths.
252+
var (
253+
rootDir = stack.ResolvePath("chaindata")
254+
ancientDir = config.Eth.DatabaseFreezer
255+
)
260256
switch {
261-
case path == "":
262-
path = filepath.Join(stack.ResolvePath("chaindata"), "ancient")
263-
case !filepath.IsAbs(path):
264-
path = config.Node.ResolvePath(path)
265-
}
266-
if common.FileExist(path) {
267-
confirmAndRemoveDB(path, "full node ancient database")
268-
} else {
269-
log.Info("Full node ancient database missing", "path", path)
270-
}
271-
// Remove the light node database
272-
path = stack.ResolvePath("lightchaindata")
273-
if common.FileExist(path) {
274-
confirmAndRemoveDB(path, "light node database")
275-
} else {
276-
log.Info("Light node database missing", "path", path)
277-
}
257+
case ancientDir == "":
258+
ancientDir = filepath.Join(stack.ResolvePath("chaindata"), "ancient")
259+
case !filepath.IsAbs(ancientDir):
260+
ancientDir = config.Node.ResolvePath(ancientDir)
261+
}
262+
// Delete state data
263+
statePaths := []string{rootDir, filepath.Join(ancientDir, rawdb.StateFreezerName)}
264+
confirmAndRemoveDB(statePaths, "state data")
265+
266+
// Delete ancient chain
267+
chainPaths := []string{filepath.Join(ancientDir, rawdb.ChainFreezerName)}
268+
confirmAndRemoveDB(chainPaths, "ancient chain")
278269
return nil
279270
}
280271

272+
// removeFolder deletes all files (not folders) inside the directory 'dir' (but
273+
// not files in subfolders).
274+
func removeFolder(dir string) {
275+
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
276+
// If we're at the top level folder, recurse into
277+
if path == dir {
278+
return nil
279+
}
280+
// Delete all the files, but not subfolders
281+
if !info.IsDir() {
282+
os.Remove(path)
283+
return nil
284+
}
285+
return filepath.SkipDir
286+
})
287+
}
288+
281289
// confirmAndRemoveDB prompts the user for a last confirmation and removes the
282-
// folder if accepted.
283-
func confirmAndRemoveDB(database string, kind string) {
284-
confirm, err := prompt.Stdin.PromptConfirm(fmt.Sprintf("Remove %s (%s)?", kind, database))
290+
// list of folders if accepted.
291+
func confirmAndRemoveDB(paths []string, kind string) {
292+
msg := fmt.Sprintf("Location(s) of '%s': \n", kind)
293+
for _, path := range paths {
294+
msg += fmt.Sprintf("\t- %s\n", path)
295+
}
296+
fmt.Println(msg)
297+
298+
confirm, err := prompt.Stdin.PromptConfirm(fmt.Sprintf("Remove '%s'?", kind))
285299
switch {
286300
case err != nil:
287301
utils.Fatalf("%v", err)
288302
case !confirm:
289-
log.Info("Database deletion skipped", "path", database)
303+
log.Info("Database deletion skipped", "kind", kind, "paths", paths)
290304
default:
291-
start := time.Now()
292-
filepath.Walk(database, func(path string, info os.FileInfo, err error) error {
293-
// If we're at the top level folder, recurse into
294-
if path == database {
295-
return nil
305+
var (
306+
deleted []string
307+
start = time.Now()
308+
)
309+
for _, path := range paths {
310+
if common.FileExist(path) {
311+
removeFolder(path)
312+
deleted = append(deleted, path)
313+
} else {
314+
log.Info("Folder is not existent", "path", path)
296315
}
297-
// Delete all the files, but not subfolders
298-
if !info.IsDir() {
299-
os.Remove(path)
300-
return nil
301-
}
302-
return filepath.SkipDir
303-
})
304-
log.Info("Database successfully deleted", "path", database, "elapsed", common.PrettyDuration(time.Since(start)))
316+
}
317+
log.Info("Database successfully deleted", "kind", kind, "paths", deleted, "elapsed", common.PrettyDuration(time.Since(start)))
305318
}
306319
}
307320

core/rawdb/ancient_scheme.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,16 +73,16 @@ var chainFreezerNoSnappy = map[string]bool{
7373

7474
// The list of identifiers of ancient stores. It can split more in the futures.
7575
var (
76-
chainFreezerName = "chain" // the folder name of chain segment ancient store.
77-
stateFreezerName = "state" // the folder name of reverse diff ancient store.
76+
ChainFreezerName = "chain" // the folder name of chain segment ancient store.
77+
StateFreezerName = "state" // the folder name of reverse diff ancient store.
7878
)
7979

8080
// freezers the collections of all builtin freezers.
81-
var freezers = []string{chainFreezerName, stateFreezerName}
81+
var freezers = []string{ChainFreezerName, StateFreezerName}
8282

8383
// NewStateFreezer initializes the freezer for state history.
8484
func NewStateFreezer(ancientDir string, readOnly bool) (*ResettableFreezer, error) {
8585
return NewResettableFreezer(
86-
filepath.Join(ancientDir, stateFreezerName), namespace, readOnly,
86+
filepath.Join(ancientDir, StateFreezerName), namespace, readOnly,
8787
stateHistoryTableSize, stateFreezerNoSnappy)
8888
}

core/rawdb/ancient_utils.go

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

92-
case stateFreezerName:
92+
case StateFreezerName:
9393
if ReadStateScheme(db) != PathScheme {
9494
log.Info("Skip inspecting state freezer", "reason", "state freezer is supported for PathScheme only")
9595
continue
@@ -104,7 +104,7 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) {
104104
}
105105
defer f.Close()
106106

107-
info, err := inspect(stateFreezerName, stateFreezerNoSnappy, f)
107+
info, err := inspect(StateFreezerName, stateFreezerNoSnappy, f)
108108
if err != nil {
109109
return nil, err
110110
}
@@ -128,9 +128,9 @@ func InspectFreezerTable(ancient string, freezerName string, tableName string, s
128128
)
129129

130130
switch freezerName {
131-
case chainFreezerName:
131+
case ChainFreezerName:
132132
path, tables = resolveChainFreezerDir(ancient), chainFreezerNoSnappy
133-
case stateFreezerName:
133+
case StateFreezerName:
134134
path, tables = filepath.Join(ancient, freezerName), stateFreezerNoSnappy
135135
default:
136136
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
@@ -173,7 +173,7 @@ func resolveChainFreezerDir(ancient string) string {
173173
// - chain freezer is not initialized
174174
// - it's legacy location, chain freezer is present in the root ancient folder
175175

176-
freezer := path.Join(ancient, chainFreezerName)
176+
freezer := path.Join(ancient, ChainFreezerName)
177177
if !common.FileExist(freezer) {
178178
if !common.FileExist(ancient) {
179179
// 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
@@ -167,14 +167,31 @@ func New(diskdb ethdb.Database, config *Config) *Database {
167167
log.Crit("Failed to open state history freezer", "err", err)
168168
}
169169

170-
// Truncate the extra state histories above the current diskLayer
171-
// in freezer in case it's not aligned with the disk layer.
172-
pruned, err := truncateFromHead(db.diskdb, db.freezer, db.tree.bottom().stateID())
173-
if err != nil {
174-
log.Crit("Failed to truncate state history freezer", "err", err)
175-
}
176-
if pruned > 0 {
177-
log.Warn("Truncated extra state histories from freezer", "count", pruned)
170+
diskLayerID := db.tree.bottom().stateID()
171+
if diskLayerID == 0 {
172+
// Reset the entire state histories in case the trie database is
173+
// not initialized yet, as these state histories are not expected.
174+
frozen, err := db.freezer.Ancients()
175+
if err != nil {
176+
log.Crit("Failed to retrieve head of state history", "err", err)
177+
}
178+
if frozen != 0 {
179+
err := db.freezer.Reset()
180+
if err != nil {
181+
log.Crit("Failed to reset state histories", "err", err)
182+
}
183+
log.Info("Truncated extraneous state history")
184+
}
185+
} else {
186+
// Truncate the extra state histories above in freezer in case
187+
// it's not aligned with the disk layer.
188+
pruned, err := truncateFromHead(db.diskdb, db.freezer, diskLayerID)
189+
if err != nil {
190+
log.Crit("Failed to truncate extra state histories", "err", err)
191+
}
192+
if pruned != 0 {
193+
log.Warn("Truncated extra state histories", "number", pruned)
194+
}
178195
}
179196
}
180197
// Disable database in case node is still in the initial state sync stage.
@@ -405,6 +422,9 @@ func (db *Database) Initialized(genesisRoot common.Hash) bool {
405422
inited = true
406423
}
407424
})
425+
if !inited {
426+
inited = rawdb.ReadSnapSyncStatusFlag(db.diskdb) != rawdb.StateSyncUnknown
427+
}
408428
return inited
409429
}
410430

0 commit comments

Comments
 (0)