Skip to content

Commit c0afdc9

Browse files
core: separated databases for block data (ethereum#2227)
* core: use finalized block as the chain freeze indicator (ethereum#28683) * core/rawdb: use max(finality, head-90k) as chain freezing threshold * core: impl multi database for block data * core: fix db inspect total size bug * core: add tips for user who use multi-database * core: adapt some cmd for multi-database * core: adapter blockBlobSidecars * core: fix freezer readHeader bug --------- Co-authored-by: rjl493456442 <[email protected]>
1 parent fb435eb commit c0afdc9

27 files changed

+693
-227
lines changed

cmd/geth/chaincmd.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,12 +268,18 @@ func initGenesis(ctx *cli.Context) error {
268268
defer chaindb.Close()
269269

270270
// if the trie data dir has been set, new trie db with a new state database
271-
if ctx.IsSet(utils.SeparateDBFlag.Name) {
271+
if ctx.IsSet(utils.MultiDataBaseFlag.Name) {
272272
statediskdb, dbErr := stack.OpenDatabaseWithFreezer(name+"/state", 0, 0, "", "", false, false, false, false)
273273
if dbErr != nil {
274274
utils.Fatalf("Failed to open separate trie database: %v", dbErr)
275275
}
276276
chaindb.SetStateStore(statediskdb)
277+
blockdb, err := stack.OpenDatabaseWithFreezer(name+"/block", 0, 0, "", "", false, false, false, false)
278+
if err != nil {
279+
utils.Fatalf("Failed to open separate block database: %v", err)
280+
}
281+
chaindb.SetBlockStore(blockdb)
282+
log.Warn("Multi-database is an experimental feature")
277283
}
278284

279285
triedb := utils.MakeTrieDatabase(ctx, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle())
@@ -474,6 +480,13 @@ func dumpGenesis(ctx *cli.Context) error {
474480
}
475481
continue
476482
}
483+
// set the separate state & block database
484+
if stack.CheckIfMultiDataBase() && err == nil {
485+
stateDiskDb := utils.MakeStateDataBase(ctx, stack, true, false)
486+
db.SetStateStore(stateDiskDb)
487+
blockDb := utils.MakeBlockDatabase(ctx, stack, true, false)
488+
db.SetBlockStore(blockDb)
489+
}
477490
genesis, err := core.ReadGenesis(db)
478491
if err != nil {
479492
utils.Fatalf("failed to read genesis: %s", err)
@@ -746,7 +759,7 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth
746759
arg := ctx.Args().First()
747760
if hashish(arg) {
748761
hash := common.HexToHash(arg)
749-
if number := rawdb.ReadHeaderNumber(db, hash); number != nil {
762+
if number := rawdb.ReadHeaderNumber(db.BlockStore(), hash); number != nil {
750763
header = rawdb.ReadHeader(db, hash, *number)
751764
} else {
752765
return nil, nil, common.Hash{}, fmt.Errorf("block %x not found", hash)
@@ -815,6 +828,7 @@ func dump(ctx *cli.Context) error {
815828
if err != nil {
816829
return err
817830
}
831+
defer db.Close()
818832
triedb := utils.MakeTrieDatabase(ctx, db, true, true, false) // always enable preimage lookup
819833
defer triedb.Close()
820834

cmd/geth/config.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
211211
if ctx.IsSet(utils.OverrideDefaultExtraReserveForBlobRequests.Name) {
212212
params.DefaultExtraReserveForBlobRequests = ctx.Uint64(utils.OverrideDefaultExtraReserveForBlobRequests.Name)
213213
}
214-
if ctx.IsSet(utils.SeparateDBFlag.Name) && !stack.IsSeparatedDB() {
215-
utils.Fatalf("Failed to locate separate database subdirectory when separatedb parameter has been set")
216-
}
214+
217215
backend, eth := utils.RegisterEthService(stack, &cfg.Eth)
218216

219217
// Create gauge with geth system and build information

cmd/geth/dbcmd.go

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -396,8 +396,8 @@ func inspectTrie(ctx *cli.Context) error {
396396
var headerBlockHash common.Hash
397397
if ctx.NArg() >= 1 {
398398
if ctx.Args().Get(0) == "latest" {
399-
headerHash := rawdb.ReadHeadHeaderHash(db)
400-
blockNumber = *(rawdb.ReadHeaderNumber(db, headerHash))
399+
headerHash := rawdb.ReadHeadHeaderHash(db.BlockStore())
400+
blockNumber = *(rawdb.ReadHeaderNumber(db.BlockStore(), headerHash))
401401
} else if ctx.Args().Get(0) == "snapshot" {
402402
trieRootHash = rawdb.ReadSnapshotRoot(db)
403403
blockNumber = math.MaxUint64
@@ -519,14 +519,19 @@ func checkStateContent(ctx *cli.Context) error {
519519
db := utils.MakeChainDatabase(ctx, stack, true, false)
520520
defer db.Close()
521521
var (
522-
it = rawdb.NewKeyLengthIterator(db.NewIterator(prefix, start), 32)
522+
it ethdb.Iterator
523523
hasher = crypto.NewKeccakState()
524524
got = make([]byte, 32)
525525
errs int
526526
count int
527527
startTime = time.Now()
528528
lastLog = time.Now()
529529
)
530+
if stack.CheckIfMultiDataBase() {
531+
it = rawdb.NewKeyLengthIterator(db.StateStore().NewIterator(prefix, start), 32)
532+
} else {
533+
it = rawdb.NewKeyLengthIterator(db.NewIterator(prefix, start), 32)
534+
}
530535
for it.Next() {
531536
count++
532537
k := it.Key()
@@ -573,9 +578,11 @@ func dbStats(ctx *cli.Context) error {
573578
defer db.Close()
574579

575580
showLeveldbStats(db)
576-
if db.StateStore() != nil {
581+
if stack.CheckIfMultiDataBase() {
577582
fmt.Println("show stats of state store")
578583
showLeveldbStats(db.StateStore())
584+
fmt.Println("show stats of block store")
585+
showLeveldbStats(db.BlockStore())
579586
}
580587

581588
return nil
@@ -591,10 +598,11 @@ func dbCompact(ctx *cli.Context) error {
591598
log.Info("Stats before compaction")
592599
showLeveldbStats(db)
593600

594-
statediskdb := db.StateStore()
595-
if statediskdb != nil {
601+
if stack.CheckIfMultiDataBase() {
596602
fmt.Println("show stats of state store")
597-
showLeveldbStats(statediskdb)
603+
showLeveldbStats(db.StateStore())
604+
fmt.Println("show stats of block store")
605+
showLeveldbStats(db.BlockStore())
598606
}
599607

600608
log.Info("Triggering compaction")
@@ -603,18 +611,24 @@ func dbCompact(ctx *cli.Context) error {
603611
return err
604612
}
605613

606-
if statediskdb != nil {
607-
if err := statediskdb.Compact(nil, nil); err != nil {
614+
if stack.CheckIfMultiDataBase() {
615+
if err := db.StateStore().Compact(nil, nil); err != nil {
616+
log.Error("Compact err", "error", err)
617+
return err
618+
}
619+
if err := db.BlockStore().Compact(nil, nil); err != nil {
608620
log.Error("Compact err", "error", err)
609621
return err
610622
}
611623
}
612624

613625
log.Info("Stats after compaction")
614626
showLeveldbStats(db)
615-
if statediskdb != nil {
627+
if stack.CheckIfMultiDataBase() {
616628
fmt.Println("show stats of state store after compaction")
617-
showLeveldbStats(statediskdb)
629+
showLeveldbStats(db.StateStore())
630+
fmt.Println("show stats of block store after compaction")
631+
showLeveldbStats(db.BlockStore())
618632
}
619633
return nil
620634
}
@@ -635,18 +649,18 @@ func dbGet(ctx *cli.Context) error {
635649
log.Info("Could not decode the key", "error", err)
636650
return err
637651
}
652+
opDb := db
653+
if stack.CheckIfMultiDataBase() {
654+
keyType := rawdb.DataTypeByKey(key)
655+
if keyType == rawdb.StateDataType {
656+
opDb = db.StateStore()
657+
} else if keyType == rawdb.BlockDataType {
658+
opDb = db.BlockStore()
659+
}
660+
}
638661

639-
statediskdb := db.StateStore()
640-
data, err := db.Get(key)
662+
data, err := opDb.Get(key)
641663
if err != nil {
642-
// if separate trie db exist, try to get it from separate db
643-
if statediskdb != nil {
644-
statedata, dberr := statediskdb.Get(key)
645-
if dberr == nil {
646-
fmt.Printf("key %#x: %#x\n", key, statedata)
647-
return nil
648-
}
649-
}
650664
log.Info("Get operation failed", "key", fmt.Sprintf("%#x", key), "error", err)
651665
return err
652666
}
@@ -809,11 +823,21 @@ func dbDelete(ctx *cli.Context) error {
809823
log.Info("Could not decode the key", "error", err)
810824
return err
811825
}
812-
data, err := db.Get(key)
826+
opDb := db
827+
if stack.CheckIfMultiDataBase() {
828+
keyType := rawdb.DataTypeByKey(key)
829+
if keyType == rawdb.StateDataType {
830+
opDb = db.StateStore()
831+
} else if keyType == rawdb.BlockDataType {
832+
opDb = db.BlockStore()
833+
}
834+
}
835+
836+
data, err := opDb.Get(key)
813837
if err == nil {
814838
fmt.Printf("Previous value: %#x\n", data)
815839
}
816-
if err = db.Delete(key); err != nil {
840+
if err = opDb.Delete(key); err != nil {
817841
log.Info("Delete operation returned an error", "key", fmt.Sprintf("%#x", key), "error", err)
818842
return err
819843
}
@@ -923,11 +947,22 @@ func dbPut(ctx *cli.Context) error {
923947
log.Info("Could not decode the value", "error", err)
924948
return err
925949
}
926-
data, err = db.Get(key)
950+
951+
opDb := db
952+
if stack.CheckIfMultiDataBase() {
953+
keyType := rawdb.DataTypeByKey(key)
954+
if keyType == rawdb.StateDataType {
955+
opDb = db.StateStore()
956+
} else if keyType == rawdb.BlockDataType {
957+
opDb = db.BlockStore()
958+
}
959+
}
960+
961+
data, err = opDb.Get(key)
927962
if err == nil {
928963
fmt.Printf("Previous value: %#x\n", data)
929964
}
930-
return db.Put(key, value)
965+
return opDb.Put(key, value)
931966
}
932967

933968
// dbDumpTrie shows the key-value slots of a given storage trie
@@ -940,7 +975,6 @@ func dbDumpTrie(ctx *cli.Context) error {
940975

941976
db := utils.MakeChainDatabase(ctx, stack, true, false)
942977
defer db.Close()
943-
944978
triedb := utils.MakeTrieDatabase(ctx, db, false, true, false)
945979
defer triedb.Close()
946980

@@ -1019,7 +1053,7 @@ func freezerInspect(ctx *cli.Context) error {
10191053
stack, _ := makeConfigNode(ctx)
10201054
ancient := stack.ResolveAncient("chaindata", ctx.String(utils.AncientFlag.Name))
10211055
stack.Close()
1022-
return rawdb.InspectFreezerTable(ancient, freezer, table, start, end)
1056+
return rawdb.InspectFreezerTable(ancient, freezer, table, start, end, stack.CheckIfMultiDataBase())
10231057
}
10241058

10251059
func importLDBdata(ctx *cli.Context) error {
@@ -1159,11 +1193,11 @@ func showMetaData(ctx *cli.Context) error {
11591193
defer stack.Close()
11601194
db := utils.MakeChainDatabase(ctx, stack, true, false)
11611195
defer db.Close()
1162-
ancients, err := db.Ancients()
1196+
ancients, err := db.BlockStore().Ancients()
11631197
if err != nil {
11641198
fmt.Fprintf(os.Stderr, "Error accessing ancients: %v", err)
11651199
}
1166-
data := rawdb.ReadChainMetadata(db)
1200+
data := rawdb.ReadChainMetadataFromMultiDatabase(db)
11671201
data = append(data, []string{"frozen", fmt.Sprintf("%d items", ancients)})
11681202
data = append(data, []string{"snapshotGenerator", snapshot.ParseGeneratorStatus(rawdb.ReadSnapshotGenerator(db))})
11691203
if b := rawdb.ReadHeadBlock(db); b != nil {
@@ -1224,8 +1258,8 @@ func hbss2pbss(ctx *cli.Context) error {
12241258
log.Info("hbss2pbss triedb", "scheme", triedb.Scheme())
12251259
defer triedb.Close()
12261260

1227-
headerHash := rawdb.ReadHeadHeaderHash(db)
1228-
blockNumber := rawdb.ReadHeaderNumber(db, headerHash)
1261+
headerHash := rawdb.ReadHeadHeaderHash(db.BlockStore())
1262+
blockNumber := rawdb.ReadHeaderNumber(db.BlockStore(), headerHash)
12291263
if blockNumber == nil {
12301264
log.Error("read header number failed.")
12311265
return fmt.Errorf("read header number failed")

cmd/geth/pruneblock_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,11 @@ func BlockchainCreator(t *testing.T, chaindbPath, AncientPath string, blockRemai
178178

179179
// Force run a freeze cycle
180180
type freezer interface {
181-
Freeze(threshold uint64) error
181+
Freeze() error
182182
Ancients() (uint64, error)
183183
}
184-
db.(freezer).Freeze(10)
184+
blockchain.SetFinalized(blocks[len(blocks)-1].Header())
185+
db.(freezer).Freeze()
185186

186187
frozen, err := db.Ancients()
187188
//make sure there're frozen items

cmd/geth/snapshot.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,15 @@ func pruneBlock(ctx *cli.Context) error {
355355
if !ctx.IsSet(utils.AncientFlag.Name) {
356356
return errors.New("datadir.ancient must be set")
357357
} else {
358-
oldAncientPath = ctx.String(utils.AncientFlag.Name)
358+
if stack.CheckIfMultiDataBase() {
359+
ancientPath := ctx.String(utils.AncientFlag.Name)
360+
index := strings.LastIndex(ancientPath, "/ancient/chain")
361+
if index != -1 {
362+
oldAncientPath = ancientPath[:index] + "/block/ancient/chain"
363+
}
364+
} else {
365+
oldAncientPath = ctx.String(utils.AncientFlag.Name)
366+
}
359367
if !filepath.IsAbs(oldAncientPath) {
360368
// force absolute paths, which often fail due to the splicing of relative paths
361369
return errors.New("datadir.ancient not abs path")
@@ -852,6 +860,7 @@ func dumpState(ctx *cli.Context) error {
852860
if err != nil {
853861
return err
854862
}
863+
defer db.Close()
855864
triedb := utils.MakeTrieDatabase(ctx, db, false, true, false)
856865
defer triedb.Close()
857866

cmd/utils/flags.go

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,10 @@ var (
9393
Value: flags.DirectoryString(node.DefaultDataDir()),
9494
Category: flags.EthCategory,
9595
}
96-
SeparateDBFlag = &cli.BoolFlag{
97-
Name: "separatedb",
98-
Usage: "Enable a separated trie database, it will be created within a subdirectory called state, " +
99-
"Users can copy this state directory to another directory or disk, and then create a symbolic link to the state directory under the chaindata",
96+
MultiDataBaseFlag = &cli.BoolFlag{
97+
Name: "multidatabase",
98+
Usage: "Enable a separated state and block database, it will be created within two subdirectory called state and block, " +
99+
"Users can copy this state or block directory to another directory or disk, and then create a symbolic link to the state directory under the chaindata",
100100
Category: flags.EthCategory,
101101
}
102102
DirectBroadcastFlag = &cli.BoolFlag{
@@ -1150,7 +1150,7 @@ var (
11501150
DBEngineFlag,
11511151
StateSchemeFlag,
11521152
HttpHeaderFlag,
1153-
SeparateDBFlag,
1153+
MultiDataBaseFlag,
11541154
}
11551155
)
11561156

@@ -2387,9 +2387,11 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly, disableFree
23872387
default:
23882388
chainDb, err = stack.OpenDatabaseWithFreezer("chaindata", cache, handles, ctx.String(AncientFlag.Name), "", readonly, disableFreeze, false, false)
23892389
// set the separate state database
2390-
if stack.IsSeparatedDB() && err == nil {
2390+
if stack.CheckIfMultiDataBase() && err == nil {
23912391
stateDiskDb := MakeStateDataBase(ctx, stack, readonly, false)
23922392
chainDb.SetStateStore(stateDiskDb)
2393+
blockDb := MakeBlockDatabase(ctx, stack, readonly, false)
2394+
chainDb.SetBlockStore(blockDb)
23932395
}
23942396
}
23952397
if err != nil {
@@ -2401,14 +2403,25 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly, disableFree
24012403
// MakeStateDataBase open a separate state database using the flags passed to the client and will hard crash if it fails.
24022404
func MakeStateDataBase(ctx *cli.Context, stack *node.Node, readonly, disableFreeze bool) ethdb.Database {
24032405
cache := ctx.Int(CacheFlag.Name) * ctx.Int(CacheDatabaseFlag.Name) / 100
2404-
handles := MakeDatabaseHandles(ctx.Int(FDLimitFlag.Name)) / 2
2406+
handles := MakeDatabaseHandles(ctx.Int(FDLimitFlag.Name)) * 90 / 100
24052407
statediskdb, err := stack.OpenDatabaseWithFreezer("chaindata/state", cache, handles, "", "", readonly, disableFreeze, false, false)
24062408
if err != nil {
24072409
Fatalf("Failed to open separate trie database: %v", err)
24082410
}
24092411
return statediskdb
24102412
}
24112413

2414+
// MakeBlockDatabase open a separate block database using the flags passed to the client and will hard crash if it fails.
2415+
func MakeBlockDatabase(ctx *cli.Context, stack *node.Node, readonly, disableFreeze bool) ethdb.Database {
2416+
cache := ctx.Int(CacheFlag.Name) * ctx.Int(CacheDatabaseFlag.Name) / 100
2417+
handles := MakeDatabaseHandles(ctx.Int(FDLimitFlag.Name)) / 10
2418+
blockDb, err := stack.OpenDatabaseWithFreezer("chaindata/block", cache, handles, "", "", readonly, disableFreeze, false, false)
2419+
if err != nil {
2420+
Fatalf("Failed to open separate block database: %v", err)
2421+
}
2422+
return blockDb
2423+
}
2424+
24122425
// tryMakeReadOnlyDatabase try to open the chain database in read-only mode,
24132426
// or fallback to write mode if the database is not initialized.
24142427
//

0 commit comments

Comments
 (0)