mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 19:30:44 +00:00
dbcmd inspect trie depth
This commit is contained in:
parent
c974722dc0
commit
9276cfdb9f
2 changed files with 157 additions and 0 deletions
|
|
@ -70,6 +70,7 @@ Remove blockchain and state databases`,
|
|||
ArgsUsage: "",
|
||||
Subcommands: []*cli.Command{
|
||||
dbInspectCmd,
|
||||
dbInspectTrieDepthCmd,
|
||||
dbStatCmd,
|
||||
dbCompactCmd,
|
||||
dbGetCmd,
|
||||
|
|
@ -92,6 +93,14 @@ Remove blockchain and state databases`,
|
|||
Usage: "Inspect the storage size for each type of data in the database",
|
||||
Description: `This commands iterates the entire database. If the optional 'prefix' and 'start' arguments are provided, then the iteration is limited to the given subset of data.`,
|
||||
}
|
||||
dbInspectTrieDepthCmd = &cli.Command{
|
||||
Action: inspectTrieDepth,
|
||||
Name: "inspect-trie-depth",
|
||||
Usage: "Inspect the depth of the trie",
|
||||
ArgsUsage: "<start> <end>",
|
||||
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
|
||||
Description: "This command inspects the depth of the trie",
|
||||
}
|
||||
dbCheckStateContentCmd = &cli.Command{
|
||||
Action: checkStateContent,
|
||||
Name: "check-state-content",
|
||||
|
|
@ -331,6 +340,16 @@ func inspect(ctx *cli.Context) error {
|
|||
return rawdb.InspectDatabase(db, prefix, start)
|
||||
}
|
||||
|
||||
func inspectTrieDepth(ctx *cli.Context) error {
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
defer stack.Close()
|
||||
|
||||
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||
defer db.Close()
|
||||
|
||||
return rawdb.InspectTrieDepth(db)
|
||||
}
|
||||
|
||||
func checkStateContent(ctx *cli.Context) error {
|
||||
var (
|
||||
prefix []byte
|
||||
|
|
|
|||
|
|
@ -798,3 +798,141 @@ func SafeDeleteRange(db ethdb.KeyValueStore, start, end []byte, hashScheme bool,
|
|||
}
|
||||
return batch.Write()
|
||||
}
|
||||
|
||||
// InspectTrieDepth traverses all path-based trie nodes in the database
|
||||
// and calculates the depth distribution of nodes in the account trie
|
||||
// and storage tries. Uses a streaming algorithm that processes nodes
|
||||
// in lexicographic order without loading all paths into memory.
|
||||
func InspectTrieDepth(db ethdb.Database) error {
|
||||
var (
|
||||
start = time.Now()
|
||||
|
||||
accountDepths [65]int64
|
||||
storageDepths [65]int64
|
||||
accountCount int64
|
||||
storageCount int64
|
||||
storageTriesCnt int64
|
||||
nodeCount int64
|
||||
)
|
||||
|
||||
log.Info("Calculating trie depth distribution (streaming)...")
|
||||
|
||||
// Process account trie nodes (prefix "A")
|
||||
// Keys are already in lexicographic order from the database iterator
|
||||
accountStack := make([]string, 0, 65)
|
||||
|
||||
it := db.NewIterator(TrieNodeAccountPrefix, nil)
|
||||
for it.Next() {
|
||||
ok, path := ResolveAccountTrieNodeKey(it.Key())
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
pathStr := string(path)
|
||||
|
||||
// Pop until stack top is a strict prefix of current path
|
||||
for len(accountStack) > 0 {
|
||||
top := accountStack[len(accountStack)-1]
|
||||
if len(top) < len(pathStr) && pathStr[:len(top)] == top {
|
||||
break
|
||||
}
|
||||
accountStack = accountStack[:len(accountStack)-1]
|
||||
}
|
||||
|
||||
depth := len(accountStack)
|
||||
accountDepths[depth]++
|
||||
accountCount++
|
||||
nodeCount++
|
||||
|
||||
accountStack = append(accountStack, pathStr)
|
||||
|
||||
if nodeCount%10000000 == 0 {
|
||||
log.Info("Processing nodes", "count", nodeCount, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||
}
|
||||
}
|
||||
it.Release()
|
||||
if err := it.Error(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info("Finished account trie", "nodes", accountCount, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||
|
||||
// Process storage trie nodes (prefix "O")
|
||||
// Keys are ordered by (accountHash, path), so when accountHash changes,
|
||||
// we're starting a new trie and need to reset the stack
|
||||
var (
|
||||
storageStack = make([]string, 0, 65)
|
||||
currentAccountHash common.Hash
|
||||
firstStorageTrie = true
|
||||
)
|
||||
|
||||
it = db.NewIterator(TrieNodeStoragePrefix, nil)
|
||||
for it.Next() {
|
||||
ok, accountHash, path := ResolveStorageTrieNode(it.Key())
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if we're starting a new storage trie
|
||||
if accountHash != currentAccountHash {
|
||||
if !firstStorageTrie {
|
||||
storageTriesCnt++
|
||||
}
|
||||
firstStorageTrie = false
|
||||
currentAccountHash = accountHash
|
||||
storageStack = storageStack[:0] // Reset stack for new trie
|
||||
}
|
||||
|
||||
pathStr := string(path)
|
||||
|
||||
// Pop until stack top is a strict prefix of current path
|
||||
for len(storageStack) > 0 {
|
||||
top := storageStack[len(storageStack)-1]
|
||||
if len(top) < len(pathStr) && pathStr[:len(top)] == top {
|
||||
break
|
||||
}
|
||||
storageStack = storageStack[:len(storageStack)-1]
|
||||
}
|
||||
|
||||
depth := len(storageStack)
|
||||
storageDepths[depth]++
|
||||
storageCount++
|
||||
nodeCount++
|
||||
|
||||
storageStack = append(storageStack, pathStr)
|
||||
|
||||
if nodeCount%10000000 == 0 {
|
||||
log.Info("Processing nodes", "count", nodeCount, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||
}
|
||||
}
|
||||
it.Release()
|
||||
if err := it.Error(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Count the last storage trie if we processed any
|
||||
if !firstStorageTrie {
|
||||
storageTriesCnt++
|
||||
}
|
||||
|
||||
log.Info("Depth calculation complete",
|
||||
"accountNodes", accountCount,
|
||||
"storageNodes", storageCount,
|
||||
"storageTries", storageTriesCnt,
|
||||
"elapsed", common.PrettyDuration(time.Since(start)))
|
||||
|
||||
// Print results
|
||||
fmt.Println("\n=== Trie Depth Distribution ===")
|
||||
fmt.Printf("\nAccount Trie: %d nodes\n", accountCount)
|
||||
fmt.Printf("Storage Tries: %d nodes across %d tries\n\n", storageCount, storageTriesCnt)
|
||||
|
||||
fmt.Println("Depth | Account Nodes | Storage Nodes")
|
||||
fmt.Println("------|---------------|---------------")
|
||||
for i := 0; i < 65; i++ {
|
||||
if accountDepths[i] > 0 || storageDepths[i] > 0 {
|
||||
fmt.Printf("%5d | %13d | %13d\n", i, accountDepths[i], storageDepths[i])
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue