all: add read-only option to database (#22407)
* all: add read-only option to database * all: fixes tests * cmd/geth: migrate flags * cmd/geth: fix the compact * cmd/geth: fix the format * cmd/geth: fix log * cmd: add chain-readonly * core: add readonly notion to freezer * core/rawdb: add log * core/rawdb: fix freezer close * cmd: fix * cmd, core: construct db * core: update tests
This commit is contained in:
parent
aab35600bc
commit
0c70b83e00
@ -28,6 +28,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
@ -191,7 +192,7 @@ func initGenesis(ctx *cli.Context) error {
|
|||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
for _, name := range []string{"chaindata", "lightchaindata"} {
|
for _, name := range []string{"chaindata", "lightchaindata"} {
|
||||||
chaindb, err := stack.OpenDatabase(name, 0, 0, "")
|
chaindb, err := stack.OpenDatabase(name, 0, 0, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Failed to open database: %v", err)
|
utils.Fatalf("Failed to open database: %v", err)
|
||||||
}
|
}
|
||||||
@ -229,7 +230,7 @@ func importChain(ctx *cli.Context) error {
|
|||||||
stack, _ := makeConfigNode(ctx)
|
stack, _ := makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
chain, db := utils.MakeChain(ctx, stack, false)
|
chain, db := utils.MakeChain(ctx, stack)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
// Start periodically gathering memory profiles
|
// Start periodically gathering memory profiles
|
||||||
@ -304,7 +305,7 @@ func exportChain(ctx *cli.Context) error {
|
|||||||
stack, _ := makeConfigNode(ctx)
|
stack, _ := makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
chain, _ := utils.MakeChain(ctx, stack, true)
|
chain, _ := utils.MakeChain(ctx, stack)
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@ -340,7 +341,7 @@ func importPreimages(ctx *cli.Context) error {
|
|||||||
stack, _ := makeConfigNode(ctx)
|
stack, _ := makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
db := utils.MakeChainDatabase(ctx, stack)
|
db := utils.MakeChainDatabase(ctx, stack, false)
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
if err := utils.ImportPreimages(db, ctx.Args().First()); err != nil {
|
if err := utils.ImportPreimages(db, ctx.Args().First()); err != nil {
|
||||||
@ -359,7 +360,7 @@ func exportPreimages(ctx *cli.Context) error {
|
|||||||
stack, _ := makeConfigNode(ctx)
|
stack, _ := makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
db := utils.MakeChainDatabase(ctx, stack)
|
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
if err := utils.ExportPreimages(db, ctx.Args().First()); err != nil {
|
if err := utils.ExportPreimages(db, ctx.Args().First()); err != nil {
|
||||||
@ -373,21 +374,27 @@ func dump(ctx *cli.Context) error {
|
|||||||
stack, _ := makeConfigNode(ctx)
|
stack, _ := makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
chain, chainDb := utils.MakeChain(ctx, stack, true)
|
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||||
defer chainDb.Close()
|
|
||||||
for _, arg := range ctx.Args() {
|
for _, arg := range ctx.Args() {
|
||||||
var block *types.Block
|
var header *types.Header
|
||||||
if hashish(arg) {
|
if hashish(arg) {
|
||||||
block = chain.GetBlockByHash(common.HexToHash(arg))
|
hash := common.HexToHash(arg)
|
||||||
} else {
|
number := rawdb.ReadHeaderNumber(db, hash)
|
||||||
num, _ := strconv.Atoi(arg)
|
if number != nil {
|
||||||
block = chain.GetBlockByNumber(uint64(num))
|
header = rawdb.ReadHeader(db, hash, *number)
|
||||||
}
|
}
|
||||||
if block == nil {
|
} else {
|
||||||
|
number, _ := strconv.Atoi(arg)
|
||||||
|
hash := rawdb.ReadCanonicalHash(db, uint64(number))
|
||||||
|
if hash != (common.Hash{}) {
|
||||||
|
header = rawdb.ReadHeader(db, hash, uint64(number))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if header == nil {
|
||||||
fmt.Println("{}")
|
fmt.Println("{}")
|
||||||
utils.Fatalf("block not found")
|
utils.Fatalf("block not found")
|
||||||
} else {
|
} else {
|
||||||
state, err := state.New(block.Root(), state.NewDatabase(chainDb), nil)
|
state, err := state.New(header.Root, state.NewDatabase(db), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("could not create new state: %v", err)
|
utils.Fatalf("could not create new state: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBloc
|
|||||||
}
|
}
|
||||||
// Retrieve the DAO config flag from the database
|
// Retrieve the DAO config flag from the database
|
||||||
path := filepath.Join(datadir, "geth", "chaindata")
|
path := filepath.Join(datadir, "geth", "chaindata")
|
||||||
db, err := rawdb.NewLevelDBDatabase(path, 0, 0, "")
|
db, err := rawdb.NewLevelDBDatabase(path, 0, 0, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("test %d: failed to open test database: %v", test, err)
|
t.Fatalf("test %d: failed to open test database: %v", test, err)
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/console/prompt"
|
"github.com/ethereum/go-ethereum/console/prompt"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/ethdb/leveldb"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/syndtr/goleveldb/leveldb/opt"
|
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -65,43 +63,98 @@ Remove blockchain and state databases`,
|
|||||||
Action: utils.MigrateFlags(inspect),
|
Action: utils.MigrateFlags(inspect),
|
||||||
Name: "inspect",
|
Name: "inspect",
|
||||||
ArgsUsage: "<prefix> <start>",
|
ArgsUsage: "<prefix> <start>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.SyncModeFlag,
|
||||||
|
utils.MainnetFlag,
|
||||||
|
utils.RopstenFlag,
|
||||||
|
utils.RinkebyFlag,
|
||||||
|
utils.GoerliFlag,
|
||||||
|
utils.YoloV3Flag,
|
||||||
|
},
|
||||||
Usage: "Inspect the storage size for each type of data in the database",
|
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.`,
|
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.`,
|
||||||
}
|
}
|
||||||
dbStatCmd = cli.Command{
|
dbStatCmd = cli.Command{
|
||||||
Action: dbStats,
|
Action: utils.MigrateFlags(dbStats),
|
||||||
Name: "stats",
|
Name: "stats",
|
||||||
Usage: "Print leveldb statistics",
|
Usage: "Print leveldb statistics",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.SyncModeFlag,
|
||||||
|
utils.MainnetFlag,
|
||||||
|
utils.RopstenFlag,
|
||||||
|
utils.RinkebyFlag,
|
||||||
|
utils.GoerliFlag,
|
||||||
|
utils.YoloV3Flag,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
dbCompactCmd = cli.Command{
|
dbCompactCmd = cli.Command{
|
||||||
Action: dbCompact,
|
Action: utils.MigrateFlags(dbCompact),
|
||||||
Name: "compact",
|
Name: "compact",
|
||||||
Usage: "Compact leveldb database. WARNING: May take a very long time",
|
Usage: "Compact leveldb database. WARNING: May take a very long time",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.SyncModeFlag,
|
||||||
|
utils.MainnetFlag,
|
||||||
|
utils.RopstenFlag,
|
||||||
|
utils.RinkebyFlag,
|
||||||
|
utils.GoerliFlag,
|
||||||
|
utils.YoloV3Flag,
|
||||||
|
utils.CacheFlag,
|
||||||
|
utils.CacheDatabaseFlag,
|
||||||
|
},
|
||||||
Description: `This command performs a database compaction.
|
Description: `This command performs a database compaction.
|
||||||
WARNING: This operation may take a very long time to finish, and may cause database
|
WARNING: This operation may take a very long time to finish, and may cause database
|
||||||
corruption if it is aborted during execution'!`,
|
corruption if it is aborted during execution'!`,
|
||||||
}
|
}
|
||||||
dbGetCmd = cli.Command{
|
dbGetCmd = cli.Command{
|
||||||
Action: dbGet,
|
Action: utils.MigrateFlags(dbGet),
|
||||||
Name: "get",
|
Name: "get",
|
||||||
Usage: "Show the value of a database key",
|
Usage: "Show the value of a database key",
|
||||||
ArgsUsage: "<hex-encoded key>",
|
ArgsUsage: "<hex-encoded key>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.SyncModeFlag,
|
||||||
|
utils.MainnetFlag,
|
||||||
|
utils.RopstenFlag,
|
||||||
|
utils.RinkebyFlag,
|
||||||
|
utils.GoerliFlag,
|
||||||
|
utils.YoloV3Flag,
|
||||||
|
},
|
||||||
Description: "This command looks up the specified database key from the database.",
|
Description: "This command looks up the specified database key from the database.",
|
||||||
}
|
}
|
||||||
dbDeleteCmd = cli.Command{
|
dbDeleteCmd = cli.Command{
|
||||||
Action: dbDelete,
|
Action: utils.MigrateFlags(dbDelete),
|
||||||
Name: "delete",
|
Name: "delete",
|
||||||
Usage: "Delete a database key (WARNING: may corrupt your database)",
|
Usage: "Delete a database key (WARNING: may corrupt your database)",
|
||||||
ArgsUsage: "<hex-encoded key>",
|
ArgsUsage: "<hex-encoded key>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.SyncModeFlag,
|
||||||
|
utils.MainnetFlag,
|
||||||
|
utils.RopstenFlag,
|
||||||
|
utils.RinkebyFlag,
|
||||||
|
utils.GoerliFlag,
|
||||||
|
utils.YoloV3Flag,
|
||||||
|
},
|
||||||
Description: `This command deletes the specified database key from the database.
|
Description: `This command deletes the specified database key from the database.
|
||||||
WARNING: This is a low-level operation which may cause database corruption!`,
|
WARNING: This is a low-level operation which may cause database corruption!`,
|
||||||
}
|
}
|
||||||
dbPutCmd = cli.Command{
|
dbPutCmd = cli.Command{
|
||||||
Action: dbPut,
|
Action: utils.MigrateFlags(dbPut),
|
||||||
Name: "put",
|
Name: "put",
|
||||||
Usage: "Set the value of a database key (WARNING: may corrupt your database)",
|
Usage: "Set the value of a database key (WARNING: may corrupt your database)",
|
||||||
ArgsUsage: "<hex-encoded key> <hex-encoded value>",
|
ArgsUsage: "<hex-encoded key> <hex-encoded value>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.SyncModeFlag,
|
||||||
|
utils.MainnetFlag,
|
||||||
|
utils.RopstenFlag,
|
||||||
|
utils.RinkebyFlag,
|
||||||
|
utils.GoerliFlag,
|
||||||
|
utils.YoloV3Flag,
|
||||||
|
},
|
||||||
Description: `This command sets a given database key to the given value.
|
Description: `This command sets a given database key to the given value.
|
||||||
WARNING: This is a low-level operation which may cause database corruption!`,
|
WARNING: This is a low-level operation which may cause database corruption!`,
|
||||||
}
|
}
|
||||||
@ -192,10 +245,10 @@ func inspect(ctx *cli.Context) error {
|
|||||||
stack, _ := makeConfigNode(ctx)
|
stack, _ := makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
_, chainDb := utils.MakeChain(ctx, stack, true)
|
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||||
defer chainDb.Close()
|
defer db.Close()
|
||||||
|
|
||||||
return rawdb.InspectDatabase(chainDb, prefix, start)
|
return rawdb.InspectDatabase(db, prefix, start)
|
||||||
}
|
}
|
||||||
|
|
||||||
func showLeveldbStats(db ethdb.Stater) {
|
func showLeveldbStats(db ethdb.Stater) {
|
||||||
@ -214,49 +267,33 @@ func showLeveldbStats(db ethdb.Stater) {
|
|||||||
func dbStats(ctx *cli.Context) error {
|
func dbStats(ctx *cli.Context) error {
|
||||||
stack, _ := makeConfigNode(ctx)
|
stack, _ := makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
path := stack.ResolvePath("chaindata")
|
|
||||||
db, err := leveldb.NewCustom(path, "", func(options *opt.Options) {
|
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||||
options.ReadOnly = true
|
defer db.Close()
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
showLeveldbStats(db)
|
showLeveldbStats(db)
|
||||||
err = db.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Info("Close err", "error", err)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func dbCompact(ctx *cli.Context) error {
|
func dbCompact(ctx *cli.Context) error {
|
||||||
stack, _ := makeConfigNode(ctx)
|
stack, _ := makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
path := stack.ResolvePath("chaindata")
|
|
||||||
cache := ctx.GlobalInt(utils.CacheFlag.Name) * ctx.GlobalInt(utils.CacheDatabaseFlag.Name) / 100
|
db := utils.MakeChainDatabase(ctx, stack, false)
|
||||||
db, err := leveldb.NewCustom(path, "", func(options *opt.Options) {
|
defer db.Close()
|
||||||
options.OpenFilesCacheCapacity = utils.MakeDatabaseHandles()
|
|
||||||
options.BlockCacheCapacity = cache / 2 * opt.MiB
|
log.Info("Stats before compaction")
|
||||||
options.WriteBuffer = cache / 4 * opt.MiB // Two of these are used internally
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
showLeveldbStats(db)
|
showLeveldbStats(db)
|
||||||
|
|
||||||
log.Info("Triggering compaction")
|
log.Info("Triggering compaction")
|
||||||
err = db.Compact(nil, nil)
|
if err := db.Compact(nil, nil); err != nil {
|
||||||
if err != nil {
|
|
||||||
log.Info("Compact err", "error", err)
|
log.Info("Compact err", "error", err)
|
||||||
}
|
|
||||||
showLeveldbStats(db)
|
|
||||||
log.Info("Closing db")
|
|
||||||
err = db.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Info("Close err", "error", err)
|
|
||||||
}
|
|
||||||
log.Info("Exiting")
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
log.Info("Stats after compaction")
|
||||||
|
showLeveldbStats(db)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// dbGet shows the value of a given database key
|
// dbGet shows the value of a given database key
|
||||||
func dbGet(ctx *cli.Context) error {
|
func dbGet(ctx *cli.Context) error {
|
||||||
@ -265,14 +302,10 @@ func dbGet(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
stack, _ := makeConfigNode(ctx)
|
stack, _ := makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
path := stack.ResolvePath("chaindata")
|
|
||||||
db, err := leveldb.NewCustom(path, "", func(options *opt.Options) {
|
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||||
options.ReadOnly = true
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
key, err := hexutil.Decode(ctx.Args().Get(0))
|
key, err := hexutil.Decode(ctx.Args().Get(0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Info("Could not decode the key", "error", err)
|
log.Info("Could not decode the key", "error", err)
|
||||||
@ -283,7 +316,7 @@ func dbGet(ctx *cli.Context) error {
|
|||||||
log.Info("Get operation failed", "error", err)
|
log.Info("Get operation failed", "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("key %#x:\n\t%#x\n", key, data)
|
fmt.Printf("key %#x: %#x\n", key, data)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,13 +327,19 @@ func dbDelete(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
stack, _ := makeConfigNode(ctx)
|
stack, _ := makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
db := utils.MakeChainDatabase(ctx, stack)
|
|
||||||
|
db := utils.MakeChainDatabase(ctx, stack, false)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
key, err := hexutil.Decode(ctx.Args().Get(0))
|
key, err := hexutil.Decode(ctx.Args().Get(0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Info("Could not decode the key", "error", err)
|
log.Info("Could not decode the key", "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
data, err := db.Get(key)
|
||||||
|
if err == nil {
|
||||||
|
fmt.Printf("Previous value: %#x\n", data)
|
||||||
|
}
|
||||||
if err = db.Delete(key); err != nil {
|
if err = db.Delete(key); err != nil {
|
||||||
log.Info("Delete operation returned an error", "error", err)
|
log.Info("Delete operation returned an error", "error", err)
|
||||||
return err
|
return err
|
||||||
@ -315,8 +354,10 @@ func dbPut(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
stack, _ := makeConfigNode(ctx)
|
stack, _ := makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
db := utils.MakeChainDatabase(ctx, stack)
|
|
||||||
|
db := utils.MakeChainDatabase(ctx, stack, false)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
key []byte
|
key []byte
|
||||||
value []byte
|
value []byte
|
||||||
@ -335,7 +376,7 @@ func dbPut(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
data, err = db.Get(key)
|
data, err = db.Get(key)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Printf("Previous value:\n%#x\n", data)
|
fmt.Printf("Previous value: %#x\n", data)
|
||||||
}
|
}
|
||||||
return db.Put(key, value)
|
return db.Put(key, value)
|
||||||
}
|
}
|
||||||
|
@ -152,10 +152,8 @@ func pruneState(ctx *cli.Context) error {
|
|||||||
stack, config := makeConfigNode(ctx)
|
stack, config := makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
chain, chaindb := utils.MakeChain(ctx, stack, true)
|
chaindb := utils.MakeChainDatabase(ctx, stack, false)
|
||||||
defer chaindb.Close()
|
pruner, err := pruner.NewPruner(chaindb, stack.ResolvePath(""), stack.ResolvePath(config.Eth.TrieCleanCacheJournal), ctx.GlobalUint64(utils.BloomFilterSizeFlag.Name))
|
||||||
|
|
||||||
pruner, err := pruner.NewPruner(chaindb, chain.CurrentBlock().Header(), stack.ResolvePath(""), stack.ResolvePath(config.Eth.TrieCleanCacheJournal), ctx.GlobalUint64(utils.BloomFilterSizeFlag.Name))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to open snapshot tree", "error", err)
|
log.Error("Failed to open snapshot tree", "error", err)
|
||||||
return err
|
return err
|
||||||
@ -183,10 +181,13 @@ func verifyState(ctx *cli.Context) error {
|
|||||||
stack, _ := makeConfigNode(ctx)
|
stack, _ := makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
chain, chaindb := utils.MakeChain(ctx, stack, true)
|
chaindb := utils.MakeChainDatabase(ctx, stack, true)
|
||||||
defer chaindb.Close()
|
headBlock := rawdb.ReadHeadBlock(chaindb)
|
||||||
|
if headBlock == nil {
|
||||||
snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, chain.CurrentBlock().Root(), false, false, false)
|
log.Error("Failed to load head block")
|
||||||
|
return errors.New("no head block")
|
||||||
|
}
|
||||||
|
snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, headBlock.Root(), false, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to open snapshot tree", "error", err)
|
log.Error("Failed to open snapshot tree", "error", err)
|
||||||
return err
|
return err
|
||||||
@ -195,7 +196,7 @@ func verifyState(ctx *cli.Context) error {
|
|||||||
log.Error("Too many arguments given")
|
log.Error("Too many arguments given")
|
||||||
return errors.New("too many arguments")
|
return errors.New("too many arguments")
|
||||||
}
|
}
|
||||||
var root = chain.CurrentBlock().Root()
|
var root = headBlock.Root()
|
||||||
if ctx.NArg() == 1 {
|
if ctx.NArg() == 1 {
|
||||||
root, err = parseRoot(ctx.Args()[0])
|
root, err = parseRoot(ctx.Args()[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -218,19 +219,16 @@ func traverseState(ctx *cli.Context) error {
|
|||||||
stack, _ := makeConfigNode(ctx)
|
stack, _ := makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
chain, chaindb := utils.MakeChain(ctx, stack, true)
|
chaindb := utils.MakeChainDatabase(ctx, stack, true)
|
||||||
defer chaindb.Close()
|
headBlock := rawdb.ReadHeadBlock(chaindb)
|
||||||
|
if headBlock == nil {
|
||||||
|
log.Error("Failed to load head block")
|
||||||
|
return errors.New("no head block")
|
||||||
|
}
|
||||||
if ctx.NArg() > 1 {
|
if ctx.NArg() > 1 {
|
||||||
log.Error("Too many arguments given")
|
log.Error("Too many arguments given")
|
||||||
return errors.New("too many arguments")
|
return errors.New("too many arguments")
|
||||||
}
|
}
|
||||||
// Use the HEAD root as the default
|
|
||||||
head := chain.CurrentBlock()
|
|
||||||
if head == nil {
|
|
||||||
log.Error("Head block is missing")
|
|
||||||
return errors.New("head block is missing")
|
|
||||||
}
|
|
||||||
var (
|
var (
|
||||||
root common.Hash
|
root common.Hash
|
||||||
err error
|
err error
|
||||||
@ -243,8 +241,8 @@ func traverseState(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
log.Info("Start traversing the state", "root", root)
|
log.Info("Start traversing the state", "root", root)
|
||||||
} else {
|
} else {
|
||||||
root = head.Root()
|
root = headBlock.Root()
|
||||||
log.Info("Start traversing the state", "root", root, "number", head.NumberU64())
|
log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64())
|
||||||
}
|
}
|
||||||
triedb := trie.NewDatabase(chaindb)
|
triedb := trie.NewDatabase(chaindb)
|
||||||
t, err := trie.NewSecure(root, triedb)
|
t, err := trie.NewSecure(root, triedb)
|
||||||
@ -311,19 +309,16 @@ func traverseRawState(ctx *cli.Context) error {
|
|||||||
stack, _ := makeConfigNode(ctx)
|
stack, _ := makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
chain, chaindb := utils.MakeChain(ctx, stack, true)
|
chaindb := utils.MakeChainDatabase(ctx, stack, true)
|
||||||
defer chaindb.Close()
|
headBlock := rawdb.ReadHeadBlock(chaindb)
|
||||||
|
if headBlock == nil {
|
||||||
|
log.Error("Failed to load head block")
|
||||||
|
return errors.New("no head block")
|
||||||
|
}
|
||||||
if ctx.NArg() > 1 {
|
if ctx.NArg() > 1 {
|
||||||
log.Error("Too many arguments given")
|
log.Error("Too many arguments given")
|
||||||
return errors.New("too many arguments")
|
return errors.New("too many arguments")
|
||||||
}
|
}
|
||||||
// Use the HEAD root as the default
|
|
||||||
head := chain.CurrentBlock()
|
|
||||||
if head == nil {
|
|
||||||
log.Error("Head block is missing")
|
|
||||||
return errors.New("head block is missing")
|
|
||||||
}
|
|
||||||
var (
|
var (
|
||||||
root common.Hash
|
root common.Hash
|
||||||
err error
|
err error
|
||||||
@ -336,8 +331,8 @@ func traverseRawState(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
log.Info("Start traversing the state", "root", root)
|
log.Info("Start traversing the state", "root", root)
|
||||||
} else {
|
} else {
|
||||||
root = head.Root()
|
root = headBlock.Root()
|
||||||
log.Info("Start traversing the state", "root", root, "number", head.NumberU64())
|
log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64())
|
||||||
}
|
}
|
||||||
triedb := trie.NewDatabase(chaindb)
|
triedb := trie.NewDatabase(chaindb)
|
||||||
t, err := trie.NewSecure(root, triedb)
|
t, err := trie.NewSecure(root, triedb)
|
||||||
|
@ -1628,7 +1628,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
|||||||
if ctx.GlobalIsSet(DataDirFlag.Name) {
|
if ctx.GlobalIsSet(DataDirFlag.Name) {
|
||||||
// Check if we have an already initialized chain and fall back to
|
// Check if we have an already initialized chain and fall back to
|
||||||
// that if so. Otherwise we need to generate a new genesis spec.
|
// that if so. Otherwise we need to generate a new genesis spec.
|
||||||
chaindb := MakeChainDatabase(ctx, stack)
|
chaindb := MakeChainDatabase(ctx, stack, true)
|
||||||
if rawdb.ReadCanonicalHash(chaindb, 0) != (common.Hash{}) {
|
if rawdb.ReadCanonicalHash(chaindb, 0) != (common.Hash{}) {
|
||||||
cfg.Genesis = nil // fallback to db content
|
cfg.Genesis = nil // fallback to db content
|
||||||
}
|
}
|
||||||
@ -1749,7 +1749,7 @@ func SplitTagsFlag(tagsFlag string) map[string]string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails.
|
// MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails.
|
||||||
func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
|
func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb.Database {
|
||||||
var (
|
var (
|
||||||
cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
|
cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
|
||||||
handles = MakeDatabaseHandles()
|
handles = MakeDatabaseHandles()
|
||||||
@ -1759,10 +1759,10 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
|
|||||||
)
|
)
|
||||||
if ctx.GlobalString(SyncModeFlag.Name) == "light" {
|
if ctx.GlobalString(SyncModeFlag.Name) == "light" {
|
||||||
name := "lightchaindata"
|
name := "lightchaindata"
|
||||||
chainDb, err = stack.OpenDatabase(name, cache, handles, "")
|
chainDb, err = stack.OpenDatabase(name, cache, handles, "", readonly)
|
||||||
} else {
|
} else {
|
||||||
name := "chaindata"
|
name := "chaindata"
|
||||||
chainDb, err = stack.OpenDatabaseWithFreezer(name, cache, handles, ctx.GlobalString(AncientFlag.Name), "")
|
chainDb, err = stack.OpenDatabaseWithFreezer(name, cache, handles, ctx.GlobalString(AncientFlag.Name), "", readonly)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("Could not open database: %v", err)
|
Fatalf("Could not open database: %v", err)
|
||||||
@ -1790,9 +1790,9 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MakeChain creates a chain manager from set command line flags.
|
// MakeChain creates a chain manager from set command line flags.
|
||||||
func MakeChain(ctx *cli.Context, stack *node.Node, readOnly bool) (chain *core.BlockChain, chainDb ethdb.Database) {
|
func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) {
|
||||||
var err error
|
var err error
|
||||||
chainDb = MakeChainDatabase(ctx, stack)
|
chainDb = MakeChainDatabase(ctx, stack, false) // TODO(rjl493456442) support read-only database
|
||||||
config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
|
config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("%v", err)
|
Fatalf("%v", err)
|
||||||
@ -1841,12 +1841,10 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readOnly bool) (chain *core.B
|
|||||||
cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
|
cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
|
||||||
}
|
}
|
||||||
vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
|
vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
|
||||||
var limit *uint64
|
|
||||||
if ctx.GlobalIsSet(TxLookupLimitFlag.Name) && !readOnly {
|
// TODO(rjl493456442) disable snapshot generation/wiping if the chain is read only.
|
||||||
l := ctx.GlobalUint64(TxLookupLimitFlag.Name)
|
// Disable transaction indexing/unindexing by default.
|
||||||
limit = &l
|
chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil, nil)
|
||||||
}
|
|
||||||
chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil, limit)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("Can't create BlockChain: %v", err)
|
Fatalf("Can't create BlockChain: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
|
|||||||
b.Fatalf("cannot create temporary directory: %v", err)
|
b.Fatalf("cannot create temporary directory: %v", err)
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
db, err = rawdb.NewLevelDBDatabase(dir, 128, 128, "")
|
db, err = rawdb.NewLevelDBDatabase(dir, 128, 128, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("cannot create temporary database: %v", err)
|
b.Fatalf("cannot create temporary database: %v", err)
|
||||||
}
|
}
|
||||||
@ -255,7 +255,7 @@ func benchWriteChain(b *testing.B, full bool, count uint64) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("cannot create temporary directory: %v", err)
|
b.Fatalf("cannot create temporary directory: %v", err)
|
||||||
}
|
}
|
||||||
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "")
|
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||||
}
|
}
|
||||||
@ -272,7 +272,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
|||||||
}
|
}
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "")
|
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||||
}
|
}
|
||||||
@ -283,7 +283,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
|||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "")
|
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||||
}
|
}
|
||||||
|
@ -1762,7 +1762,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
|||||||
}
|
}
|
||||||
os.RemoveAll(datadir)
|
os.RemoveAll(datadir)
|
||||||
|
|
||||||
db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "")
|
db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create persistent database: %v", err)
|
t.Fatalf("Failed to create persistent database: %v", err)
|
||||||
}
|
}
|
||||||
@ -1817,7 +1817,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
|||||||
}
|
}
|
||||||
// Force run a freeze cycle
|
// Force run a freeze cycle
|
||||||
type freezer interface {
|
type freezer interface {
|
||||||
Freeze(threshold uint64)
|
Freeze(threshold uint64) error
|
||||||
Ancients() (uint64, error)
|
Ancients() (uint64, error)
|
||||||
}
|
}
|
||||||
db.(freezer).Freeze(tt.freezeThreshold)
|
db.(freezer).Freeze(tt.freezeThreshold)
|
||||||
@ -1830,7 +1830,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
|||||||
db.Close()
|
db.Close()
|
||||||
|
|
||||||
// Start a new blockchain back up and see where the repait leads us
|
// Start a new blockchain back up and see where the repait leads us
|
||||||
db, err = rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "")
|
db, err = rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to reopen persistent database: %v", err)
|
t.Fatalf("Failed to reopen persistent database: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -1961,7 +1961,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
|||||||
}
|
}
|
||||||
os.RemoveAll(datadir)
|
os.RemoveAll(datadir)
|
||||||
|
|
||||||
db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "")
|
db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create persistent database: %v", err)
|
t.Fatalf("Failed to create persistent database: %v", err)
|
||||||
}
|
}
|
||||||
@ -2023,7 +2023,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
|||||||
}
|
}
|
||||||
// Force run a freeze cycle
|
// Force run a freeze cycle
|
||||||
type freezer interface {
|
type freezer interface {
|
||||||
Freeze(threshold uint64)
|
Freeze(threshold uint64) error
|
||||||
Ancients() (uint64, error)
|
Ancients() (uint64, error)
|
||||||
}
|
}
|
||||||
db.(freezer).Freeze(tt.freezeThreshold)
|
db.(freezer).Freeze(tt.freezeThreshold)
|
||||||
|
@ -65,7 +65,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
|
|||||||
}
|
}
|
||||||
os.RemoveAll(datadir)
|
os.RemoveAll(datadir)
|
||||||
|
|
||||||
db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "")
|
db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create persistent database: %v", err)
|
t.Fatalf("Failed to create persistent database: %v", err)
|
||||||
}
|
}
|
||||||
@ -261,7 +261,7 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) {
|
|||||||
db.Close()
|
db.Close()
|
||||||
|
|
||||||
// Start a new blockchain back up and see where the repair leads us
|
// Start a new blockchain back up and see where the repair leads us
|
||||||
newdb, err := rawdb.NewLevelDBDatabaseWithFreezer(snaptest.datadir, 0, 0, snaptest.datadir, "")
|
newdb, err := rawdb.NewLevelDBDatabaseWithFreezer(snaptest.datadir, 0, 0, snaptest.datadir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to reopen persistent database: %v", err)
|
t.Fatalf("Failed to reopen persistent database: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -651,7 +651,7 @@ func TestFastVsFullChains(t *testing.T) {
|
|||||||
t.Fatalf("failed to create temp freezer dir: %v", err)
|
t.Fatalf("failed to create temp freezer dir: %v", err)
|
||||||
}
|
}
|
||||||
defer os.Remove(frdir)
|
defer os.Remove(frdir)
|
||||||
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "")
|
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
@ -725,7 +725,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
|||||||
t.Fatalf("failed to create temp freezer dir: %v", err)
|
t.Fatalf("failed to create temp freezer dir: %v", err)
|
||||||
}
|
}
|
||||||
defer os.Remove(dir)
|
defer os.Remove(dir)
|
||||||
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "")
|
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
@ -1592,7 +1592,7 @@ func TestBlockchainRecovery(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer os.Remove(frdir)
|
defer os.Remove(frdir)
|
||||||
|
|
||||||
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "")
|
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
@ -1649,7 +1649,7 @@ func TestIncompleteAncientReceiptChainInsertion(t *testing.T) {
|
|||||||
t.Fatalf("failed to create temp freezer dir: %v", err)
|
t.Fatalf("failed to create temp freezer dir: %v", err)
|
||||||
}
|
}
|
||||||
defer os.Remove(frdir)
|
defer os.Remove(frdir)
|
||||||
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "")
|
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
@ -1848,7 +1848,7 @@ func testInsertKnownChainData(t *testing.T, typ string) {
|
|||||||
t.Fatalf("failed to create temp freezer dir: %v", err)
|
t.Fatalf("failed to create temp freezer dir: %v", err)
|
||||||
}
|
}
|
||||||
defer os.Remove(dir)
|
defer os.Remove(dir)
|
||||||
chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "")
|
chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
@ -2128,7 +2128,7 @@ func TestTransactionIndices(t *testing.T) {
|
|||||||
t.Fatalf("failed to create temp freezer dir: %v", err)
|
t.Fatalf("failed to create temp freezer dir: %v", err)
|
||||||
}
|
}
|
||||||
defer os.Remove(frdir)
|
defer os.Remove(frdir)
|
||||||
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "")
|
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
@ -2156,7 +2156,7 @@ func TestTransactionIndices(t *testing.T) {
|
|||||||
// Init block chain with external ancients, check all needed indices has been indexed.
|
// Init block chain with external ancients, check all needed indices has been indexed.
|
||||||
limit := []uint64{0, 32, 64, 128}
|
limit := []uint64{0, 32, 64, 128}
|
||||||
for _, l := range limit {
|
for _, l := range limit {
|
||||||
ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "")
|
ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
@ -2176,7 +2176,7 @@ func TestTransactionIndices(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reconstruct a block chain which only reserves HEAD-64 tx indices
|
// Reconstruct a block chain which only reserves HEAD-64 tx indices
|
||||||
ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "")
|
ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
@ -2255,7 +2255,7 @@ func TestSkipStaleTxIndicesInFastSync(t *testing.T) {
|
|||||||
t.Fatalf("failed to create temp freezer dir: %v", err)
|
t.Fatalf("failed to create temp freezer dir: %v", err)
|
||||||
}
|
}
|
||||||
defer os.Remove(frdir)
|
defer os.Remove(frdir)
|
||||||
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "")
|
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -825,3 +825,29 @@ func FindCommonAncestor(db ethdb.Reader, a, b *types.Header) *types.Header {
|
|||||||
}
|
}
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadHeadHeader returns the current canonical head header.
|
||||||
|
func ReadHeadHeader(db ethdb.Reader) *types.Header {
|
||||||
|
headHeaderHash := ReadHeadHeaderHash(db)
|
||||||
|
if headHeaderHash == (common.Hash{}) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
headHeaderNumber := ReadHeaderNumber(db, headHeaderHash)
|
||||||
|
if headHeaderNumber == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ReadHeader(db, headHeaderHash, *headHeaderNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadHeadHeader returns the current canonical head block.
|
||||||
|
func ReadHeadBlock(db ethdb.Reader) *types.Block {
|
||||||
|
headBlockHash := ReadHeadBlockHash(db)
|
||||||
|
if headBlockHash == (common.Hash{}) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
headBlockNumber := ReadHeaderNumber(db, headBlockHash)
|
||||||
|
if headBlockNumber == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ReadBlock(db, headBlockHash, *headBlockNumber)
|
||||||
|
}
|
||||||
|
@ -440,7 +440,7 @@ func TestAncientStorage(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer os.Remove(frdir)
|
defer os.Remove(frdir)
|
||||||
|
|
||||||
db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "")
|
db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create database with ancient backend")
|
t.Fatalf("failed to create database with ancient backend")
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,10 @@ func (frdb *freezerdb) Close() error {
|
|||||||
// Freeze is a helper method used for external testing to trigger and block until
|
// Freeze is a helper method used for external testing to trigger and block until
|
||||||
// a freeze cycle completes, without having to sleep for a minute to trigger the
|
// a freeze cycle completes, without having to sleep for a minute to trigger the
|
||||||
// automatic background run.
|
// automatic background run.
|
||||||
func (frdb *freezerdb) Freeze(threshold uint64) {
|
func (frdb *freezerdb) Freeze(threshold uint64) error {
|
||||||
|
if frdb.AncientStore.(*freezer).readonly {
|
||||||
|
return errReadOnly
|
||||||
|
}
|
||||||
// Set the freezer threshold to a temporary value
|
// Set the freezer threshold to a temporary value
|
||||||
defer func(old uint64) {
|
defer func(old uint64) {
|
||||||
atomic.StoreUint64(&frdb.AncientStore.(*freezer).threshold, old)
|
atomic.StoreUint64(&frdb.AncientStore.(*freezer).threshold, old)
|
||||||
@ -68,6 +71,7 @@ func (frdb *freezerdb) Freeze(threshold uint64) {
|
|||||||
trigger := make(chan struct{}, 1)
|
trigger := make(chan struct{}, 1)
|
||||||
frdb.AncientStore.(*freezer).trigger <- trigger
|
frdb.AncientStore.(*freezer).trigger <- trigger
|
||||||
<-trigger
|
<-trigger
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// nofreezedb is a database wrapper that disables freezer data retrievals.
|
// nofreezedb is a database wrapper that disables freezer data retrievals.
|
||||||
@ -121,9 +125,9 @@ func NewDatabase(db ethdb.KeyValueStore) ethdb.Database {
|
|||||||
// NewDatabaseWithFreezer creates a high level database on top of a given key-
|
// NewDatabaseWithFreezer creates a high level database on top of a given key-
|
||||||
// value data store with a freezer moving immutable chain segments into cold
|
// value data store with a freezer moving immutable chain segments into cold
|
||||||
// storage.
|
// storage.
|
||||||
func NewDatabaseWithFreezer(db ethdb.KeyValueStore, freezer string, namespace string) (ethdb.Database, error) {
|
func NewDatabaseWithFreezer(db ethdb.KeyValueStore, freezer string, namespace string, readonly bool) (ethdb.Database, error) {
|
||||||
// Create the idle freezer instance
|
// Create the idle freezer instance
|
||||||
frdb, err := newFreezer(freezer, namespace)
|
frdb, err := newFreezer(freezer, namespace, readonly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -192,8 +196,9 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, freezer string, namespace st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Freezer is consistent with the key-value database, permit combining the two
|
// Freezer is consistent with the key-value database, permit combining the two
|
||||||
|
if !frdb.readonly {
|
||||||
go frdb.freeze(db)
|
go frdb.freeze(db)
|
||||||
|
}
|
||||||
return &freezerdb{
|
return &freezerdb{
|
||||||
KeyValueStore: db,
|
KeyValueStore: db,
|
||||||
AncientStore: frdb,
|
AncientStore: frdb,
|
||||||
@ -215,8 +220,8 @@ func NewMemoryDatabaseWithCap(size int) ethdb.Database {
|
|||||||
|
|
||||||
// NewLevelDBDatabase creates a persistent key-value database without a freezer
|
// NewLevelDBDatabase creates a persistent key-value database without a freezer
|
||||||
// moving immutable chain segments into cold storage.
|
// moving immutable chain segments into cold storage.
|
||||||
func NewLevelDBDatabase(file string, cache int, handles int, namespace string) (ethdb.Database, error) {
|
func NewLevelDBDatabase(file string, cache int, handles int, namespace string, readonly bool) (ethdb.Database, error) {
|
||||||
db, err := leveldb.New(file, cache, handles, namespace)
|
db, err := leveldb.New(file, cache, handles, namespace, readonly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -225,12 +230,12 @@ func NewLevelDBDatabase(file string, cache int, handles int, namespace string) (
|
|||||||
|
|
||||||
// NewLevelDBDatabaseWithFreezer creates a persistent key-value database with a
|
// NewLevelDBDatabaseWithFreezer creates a persistent key-value database with a
|
||||||
// freezer moving immutable chain segments into cold storage.
|
// freezer moving immutable chain segments into cold storage.
|
||||||
func NewLevelDBDatabaseWithFreezer(file string, cache int, handles int, freezer string, namespace string) (ethdb.Database, error) {
|
func NewLevelDBDatabaseWithFreezer(file string, cache int, handles int, freezer string, namespace string, readonly bool) (ethdb.Database, error) {
|
||||||
kvdb, err := leveldb.New(file, cache, handles, namespace)
|
kvdb, err := leveldb.New(file, cache, handles, namespace, readonly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
frdb, err := NewDatabaseWithFreezer(kvdb, freezer, namespace)
|
frdb, err := NewDatabaseWithFreezer(kvdb, freezer, namespace, readonly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
kvdb.Close()
|
kvdb.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -35,6 +35,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
// errReadOnly is returned if the freezer is opened in read only mode. All the
|
||||||
|
// mutations are disallowed.
|
||||||
|
errReadOnly = errors.New("read only")
|
||||||
|
|
||||||
// errUnknownTable is returned if the user attempts to read from a table that is
|
// errUnknownTable is returned if the user attempts to read from a table that is
|
||||||
// not tracked by the freezer.
|
// not tracked by the freezer.
|
||||||
errUnknownTable = errors.New("unknown table")
|
errUnknownTable = errors.New("unknown table")
|
||||||
@ -73,6 +77,7 @@ type freezer struct {
|
|||||||
frozen uint64 // Number of blocks already frozen
|
frozen uint64 // Number of blocks already frozen
|
||||||
threshold uint64 // Number of recent blocks not to freeze (params.FullImmutabilityThreshold apart from tests)
|
threshold uint64 // Number of recent blocks not to freeze (params.FullImmutabilityThreshold apart from tests)
|
||||||
|
|
||||||
|
readonly bool
|
||||||
tables map[string]*freezerTable // Data tables for storing everything
|
tables map[string]*freezerTable // Data tables for storing everything
|
||||||
instanceLock fileutil.Releaser // File-system lock to prevent double opens
|
instanceLock fileutil.Releaser // File-system lock to prevent double opens
|
||||||
|
|
||||||
@ -84,7 +89,7 @@ type freezer struct {
|
|||||||
|
|
||||||
// newFreezer creates a chain freezer that moves ancient chain data into
|
// newFreezer creates a chain freezer that moves ancient chain data into
|
||||||
// append-only flat file containers.
|
// append-only flat file containers.
|
||||||
func newFreezer(datadir string, namespace string) (*freezer, error) {
|
func newFreezer(datadir string, namespace string, readonly bool) (*freezer, error) {
|
||||||
// Create the initial freezer object
|
// Create the initial freezer object
|
||||||
var (
|
var (
|
||||||
readMeter = metrics.NewRegisteredMeter(namespace+"ancient/read", nil)
|
readMeter = metrics.NewRegisteredMeter(namespace+"ancient/read", nil)
|
||||||
@ -106,6 +111,7 @@ func newFreezer(datadir string, namespace string) (*freezer, error) {
|
|||||||
}
|
}
|
||||||
// Open all the supported data tables
|
// Open all the supported data tables
|
||||||
freezer := &freezer{
|
freezer := &freezer{
|
||||||
|
readonly: readonly,
|
||||||
threshold: params.FullImmutabilityThreshold,
|
threshold: params.FullImmutabilityThreshold,
|
||||||
tables: make(map[string]*freezerTable),
|
tables: make(map[string]*freezerTable),
|
||||||
instanceLock: lock,
|
instanceLock: lock,
|
||||||
@ -130,7 +136,7 @@ func newFreezer(datadir string, namespace string) (*freezer, error) {
|
|||||||
lock.Release()
|
lock.Release()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
log.Info("Opened ancient database", "database", datadir)
|
log.Info("Opened ancient database", "database", datadir, "readonly", readonly)
|
||||||
return freezer, nil
|
return freezer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +144,7 @@ func newFreezer(datadir string, namespace string) (*freezer, error) {
|
|||||||
func (f *freezer) Close() error {
|
func (f *freezer) Close() error {
|
||||||
var errs []error
|
var errs []error
|
||||||
f.closeOnce.Do(func() {
|
f.closeOnce.Do(func() {
|
||||||
f.quit <- struct{}{}
|
close(f.quit)
|
||||||
for _, table := range f.tables {
|
for _, table := range f.tables {
|
||||||
if err := table.Close(); err != nil {
|
if err := table.Close(); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
@ -191,6 +197,9 @@ func (f *freezer) AncientSize(kind string) (uint64, error) {
|
|||||||
// injection will be rejected. But if two injections with same number happen at
|
// injection will be rejected. But if two injections with same number happen at
|
||||||
// the same time, we can get into the trouble.
|
// the same time, we can get into the trouble.
|
||||||
func (f *freezer) AppendAncient(number uint64, hash, header, body, receipts, td []byte) (err error) {
|
func (f *freezer) AppendAncient(number uint64, hash, header, body, receipts, td []byte) (err error) {
|
||||||
|
if f.readonly {
|
||||||
|
return errReadOnly
|
||||||
|
}
|
||||||
// Ensure the binary blobs we are appending is continuous with freezer.
|
// Ensure the binary blobs we are appending is continuous with freezer.
|
||||||
if atomic.LoadUint64(&f.frozen) != number {
|
if atomic.LoadUint64(&f.frozen) != number {
|
||||||
return errOutOrderInsertion
|
return errOutOrderInsertion
|
||||||
@ -233,6 +242,9 @@ func (f *freezer) AppendAncient(number uint64, hash, header, body, receipts, td
|
|||||||
|
|
||||||
// TruncateAncients discards any recent data above the provided threshold number.
|
// TruncateAncients discards any recent data above the provided threshold number.
|
||||||
func (f *freezer) TruncateAncients(items uint64) error {
|
func (f *freezer) TruncateAncients(items uint64) error {
|
||||||
|
if f.readonly {
|
||||||
|
return errReadOnly
|
||||||
|
}
|
||||||
if atomic.LoadUint64(&f.frozen) <= items {
|
if atomic.LoadUint64(&f.frozen) <= items {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -85,8 +85,12 @@ type Pruner struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewPruner creates the pruner instance.
|
// NewPruner creates the pruner instance.
|
||||||
func NewPruner(db ethdb.Database, headHeader *types.Header, datadir, trieCachePath string, bloomSize uint64) (*Pruner, error) {
|
func NewPruner(db ethdb.Database, datadir, trieCachePath string, bloomSize uint64) (*Pruner, error) {
|
||||||
snaptree, err := snapshot.New(db, trie.NewDatabase(db), 256, headHeader.Root, false, false, false)
|
headBlock := rawdb.ReadHeadBlock(db)
|
||||||
|
if headBlock == nil {
|
||||||
|
return nil, errors.New("Failed to load head block")
|
||||||
|
}
|
||||||
|
snaptree, err := snapshot.New(db, trie.NewDatabase(db), 256, headBlock.Root(), false, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err // The relevant snapshot(s) might not exist
|
return nil, err // The relevant snapshot(s) might not exist
|
||||||
}
|
}
|
||||||
@ -104,7 +108,7 @@ func NewPruner(db ethdb.Database, headHeader *types.Header, datadir, trieCachePa
|
|||||||
stateBloom: stateBloom,
|
stateBloom: stateBloom,
|
||||||
datadir: datadir,
|
datadir: datadir,
|
||||||
trieCachePath: trieCachePath,
|
trieCachePath: trieCachePath,
|
||||||
headHeader: headHeader,
|
headHeader: headBlock.Header(),
|
||||||
snaptree: snaptree,
|
snaptree: snaptree,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -350,9 +354,9 @@ func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string) err
|
|||||||
if stateBloomPath == "" {
|
if stateBloomPath == "" {
|
||||||
return nil // nothing to recover
|
return nil // nothing to recover
|
||||||
}
|
}
|
||||||
headHeader, err := getHeadHeader(db)
|
headBlock := rawdb.ReadHeadBlock(db)
|
||||||
if err != nil {
|
if headBlock == nil {
|
||||||
return err
|
return errors.New("Failed to load head block")
|
||||||
}
|
}
|
||||||
// Initialize the snapshot tree in recovery mode to handle this special case:
|
// Initialize the snapshot tree in recovery mode to handle this special case:
|
||||||
// - Users run the `prune-state` command multiple times
|
// - Users run the `prune-state` command multiple times
|
||||||
@ -362,7 +366,7 @@ func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string) err
|
|||||||
// - The state HEAD is rewound already because of multiple incomplete `prune-state`
|
// - The state HEAD is rewound already because of multiple incomplete `prune-state`
|
||||||
// In this case, even the state HEAD is not exactly matched with snapshot, it
|
// In this case, even the state HEAD is not exactly matched with snapshot, it
|
||||||
// still feasible to recover the pruning correctly.
|
// still feasible to recover the pruning correctly.
|
||||||
snaptree, err := snapshot.New(db, trie.NewDatabase(db), 256, headHeader.Root, false, false, true)
|
snaptree, err := snapshot.New(db, trie.NewDatabase(db), 256, headBlock.Root(), false, false, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err // The relevant snapshot(s) might not exist
|
return err // The relevant snapshot(s) might not exist
|
||||||
}
|
}
|
||||||
@ -382,7 +386,7 @@ func RecoverPruning(datadir string, db ethdb.Database, trieCachePath string) err
|
|||||||
// otherwise the dangling state will be left.
|
// otherwise the dangling state will be left.
|
||||||
var (
|
var (
|
||||||
found bool
|
found bool
|
||||||
layers = snaptree.Snapshots(headHeader.Root, 128, true)
|
layers = snaptree.Snapshots(headBlock.Root(), 128, true)
|
||||||
middleRoots = make(map[common.Hash]struct{})
|
middleRoots = make(map[common.Hash]struct{})
|
||||||
)
|
)
|
||||||
for _, layer := range layers {
|
for _, layer := range layers {
|
||||||
@ -506,22 +510,6 @@ func findBloomFilter(datadir string) (string, common.Hash, error) {
|
|||||||
return stateBloomPath, stateBloomRoot, nil
|
return stateBloomPath, stateBloomRoot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getHeadHeader(db ethdb.Database) (*types.Header, error) {
|
|
||||||
headHeaderHash := rawdb.ReadHeadBlockHash(db)
|
|
||||||
if headHeaderHash == (common.Hash{}) {
|
|
||||||
return nil, errors.New("empty head block hash")
|
|
||||||
}
|
|
||||||
headHeaderNumber := rawdb.ReadHeaderNumber(db, headHeaderHash)
|
|
||||||
if headHeaderNumber == nil {
|
|
||||||
return nil, errors.New("empty head block number")
|
|
||||||
}
|
|
||||||
headHeader := rawdb.ReadHeader(db, headHeaderHash, *headHeaderNumber)
|
|
||||||
if headHeader == nil {
|
|
||||||
return nil, errors.New("empty head header")
|
|
||||||
}
|
|
||||||
return headHeader, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const warningLog = `
|
const warningLog = `
|
||||||
|
|
||||||
WARNING!
|
WARNING!
|
||||||
|
@ -524,7 +524,7 @@ func TestDiskSeek(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
diskdb, err := leveldb.New(dir, 256, 0, "")
|
diskdb, err := leveldb.New(dir, 256, 0, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||||||
log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024)
|
log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024)
|
||||||
|
|
||||||
// Assemble the Ethereum object
|
// Assemble the Ethereum object
|
||||||
chainDb, err := stack.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/")
|
chainDb, err := stack.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) {
|
|||||||
benchDataDir := node.DefaultDataDir() + "/geth/chaindata"
|
benchDataDir := node.DefaultDataDir() + "/geth/chaindata"
|
||||||
b.Log("Running bloombits benchmark section size:", sectionSize)
|
b.Log("Running bloombits benchmark section size:", sectionSize)
|
||||||
|
|
||||||
db, err := rawdb.NewLevelDBDatabase(benchDataDir, 128, 1024, "")
|
db, err := rawdb.NewLevelDBDatabase(benchDataDir, 128, 1024, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", benchDataDir, err)
|
b.Fatalf("error opening database at %v: %v", benchDataDir, err)
|
||||||
}
|
}
|
||||||
@ -126,7 +126,7 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) {
|
|||||||
for i := 0; i < benchFilterCnt; i++ {
|
for i := 0; i < benchFilterCnt; i++ {
|
||||||
if i%20 == 0 {
|
if i%20 == 0 {
|
||||||
db.Close()
|
db.Close()
|
||||||
db, _ = rawdb.NewLevelDBDatabase(benchDataDir, 128, 1024, "")
|
db, _ = rawdb.NewLevelDBDatabase(benchDataDir, 128, 1024, "", false)
|
||||||
backend = &testBackend{db: db, sections: cnt}
|
backend = &testBackend{db: db, sections: cnt}
|
||||||
}
|
}
|
||||||
var addr common.Address
|
var addr common.Address
|
||||||
@ -157,7 +157,7 @@ func clearBloomBits(db ethdb.Database) {
|
|||||||
func BenchmarkNoBloomBits(b *testing.B) {
|
func BenchmarkNoBloomBits(b *testing.B) {
|
||||||
benchDataDir := node.DefaultDataDir() + "/geth/chaindata"
|
benchDataDir := node.DefaultDataDir() + "/geth/chaindata"
|
||||||
b.Log("Running benchmark without bloombits")
|
b.Log("Running benchmark without bloombits")
|
||||||
db, err := rawdb.NewLevelDBDatabase(benchDataDir, 128, 1024, "")
|
db, err := rawdb.NewLevelDBDatabase(benchDataDir, 128, 1024, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", benchDataDir, err)
|
b.Fatalf("error opening database at %v: %v", benchDataDir, err)
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ func BenchmarkFilters(b *testing.B) {
|
|||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
db, _ = rawdb.NewLevelDBDatabase(dir, 0, 0, "")
|
db, _ = rawdb.NewLevelDBDatabase(dir, 0, 0, "", false)
|
||||||
backend = &testBackend{db: db}
|
backend = &testBackend{db: db}
|
||||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
@ -103,7 +103,7 @@ func TestFilters(t *testing.T) {
|
|||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
db, _ = rawdb.NewLevelDBDatabase(dir, 0, 0, "")
|
db, _ = rawdb.NewLevelDBDatabase(dir, 0, 0, "", false)
|
||||||
backend = &testBackend{db: db}
|
backend = &testBackend{db: db}
|
||||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
addr = crypto.PubkeyToAddress(key1.PublicKey)
|
addr = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
|
@ -178,7 +178,7 @@ func TestEth66Messages(t *testing.T) {
|
|||||||
// init the receipts
|
// init the receipts
|
||||||
{
|
{
|
||||||
receipts = []*types.Receipt{
|
receipts = []*types.Receipt{
|
||||||
&types.Receipt{
|
{
|
||||||
Status: types.ReceiptStatusFailed,
|
Status: types.ReceiptStatusFailed,
|
||||||
CumulativeGasUsed: 1,
|
CumulativeGasUsed: 1,
|
||||||
Logs: []*types.Log{
|
Logs: []*types.Log{
|
||||||
|
@ -83,7 +83,7 @@ type Database struct {
|
|||||||
|
|
||||||
// New returns a wrapped LevelDB object. The namespace is the prefix that the
|
// New returns a wrapped LevelDB object. The namespace is the prefix that the
|
||||||
// metrics reporting should use for surfacing internal stats.
|
// metrics reporting should use for surfacing internal stats.
|
||||||
func New(file string, cache int, handles int, namespace string) (*Database, error) {
|
func New(file string, cache int, handles int, namespace string, readonly bool) (*Database, error) {
|
||||||
return NewCustom(file, namespace, func(options *opt.Options) {
|
return NewCustom(file, namespace, func(options *opt.Options) {
|
||||||
// Ensure we have some minimal caching and file guarantees
|
// Ensure we have some minimal caching and file guarantees
|
||||||
if cache < minCache {
|
if cache < minCache {
|
||||||
@ -96,6 +96,9 @@ func New(file string, cache int, handles int, namespace string) (*Database, erro
|
|||||||
options.OpenFilesCacheCapacity = handles
|
options.OpenFilesCacheCapacity = handles
|
||||||
options.BlockCacheCapacity = cache / 2 * opt.MiB
|
options.BlockCacheCapacity = cache / 2 * opt.MiB
|
||||||
options.WriteBuffer = cache / 4 * opt.MiB // Two of these are used internally
|
options.WriteBuffer = cache / 4 * opt.MiB // Two of these are used internally
|
||||||
|
if readonly {
|
||||||
|
options.ReadOnly = true
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,11 +80,11 @@ type LightEthereum struct {
|
|||||||
|
|
||||||
// New creates an instance of the light client.
|
// New creates an instance of the light client.
|
||||||
func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) {
|
func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) {
|
||||||
chainDb, err := stack.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/")
|
chainDb, err := stack.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
lesDb, err := stack.OpenDatabase("les.client", 0, 0, "eth/db/lesclient/")
|
lesDb, err := stack.OpenDatabase("les.client", 0, 0, "eth/db/lesclient/", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ type LesServer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewLesServer(node *node.Node, e ethBackend, config *ethconfig.Config) (*LesServer, error) {
|
func NewLesServer(node *node.Node, e ethBackend, config *ethconfig.Config) (*LesServer, error) {
|
||||||
lesDb, err := node.OpenDatabase("les.server", 0, 0, "eth/db/lesserver/")
|
lesDb, err := node.OpenDatabase("les.server", 0, 0, "eth/db/lesserver/", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -547,7 +547,7 @@ func (n *Node) EventMux() *event.TypeMux {
|
|||||||
// OpenDatabase opens an existing database with the given name (or creates one if no
|
// OpenDatabase opens an existing database with the given name (or creates one if no
|
||||||
// previous can be found) from within the node's instance directory. If the node is
|
// previous can be found) from within the node's instance directory. If the node is
|
||||||
// ephemeral, a memory database is returned.
|
// ephemeral, a memory database is returned.
|
||||||
func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (ethdb.Database, error) {
|
func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, readonly bool) (ethdb.Database, error) {
|
||||||
n.lock.Lock()
|
n.lock.Lock()
|
||||||
defer n.lock.Unlock()
|
defer n.lock.Unlock()
|
||||||
if n.state == closedState {
|
if n.state == closedState {
|
||||||
@ -559,7 +559,7 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (
|
|||||||
if n.config.DataDir == "" {
|
if n.config.DataDir == "" {
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
} else {
|
} else {
|
||||||
db, err = rawdb.NewLevelDBDatabase(n.ResolvePath(name), cache, handles, namespace)
|
db, err = rawdb.NewLevelDBDatabase(n.ResolvePath(name), cache, handles, namespace, readonly)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -573,7 +573,7 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (
|
|||||||
// also attaching a chain freezer to it that moves ancient chain data from the
|
// also attaching a chain freezer to it that moves ancient chain data from the
|
||||||
// database to immutable append-only files. If the node is an ephemeral one, a
|
// database to immutable append-only files. If the node is an ephemeral one, a
|
||||||
// memory database is returned.
|
// memory database is returned.
|
||||||
func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer, namespace string) (ethdb.Database, error) {
|
func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer, namespace string, readonly bool) (ethdb.Database, error) {
|
||||||
n.lock.Lock()
|
n.lock.Lock()
|
||||||
defer n.lock.Unlock()
|
defer n.lock.Unlock()
|
||||||
if n.state == closedState {
|
if n.state == closedState {
|
||||||
@ -592,7 +592,7 @@ func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer,
|
|||||||
case !filepath.IsAbs(freezer):
|
case !filepath.IsAbs(freezer):
|
||||||
freezer = n.ResolvePath(freezer)
|
freezer = n.ResolvePath(freezer)
|
||||||
}
|
}
|
||||||
db, err = rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace)
|
db, err = rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace, readonly)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -158,7 +158,7 @@ func TestNodeCloseClosesDB(t *testing.T) {
|
|||||||
stack, _ := New(testNodeConfig())
|
stack, _ := New(testNodeConfig())
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
db, err := stack.OpenDatabase("mydb", 0, 0, "")
|
db, err := stack.OpenDatabase("mydb", 0, 0, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("can't open DB:", err)
|
t.Fatal("can't open DB:", err)
|
||||||
}
|
}
|
||||||
@ -181,7 +181,7 @@ func TestNodeOpenDatabaseFromLifecycleStart(t *testing.T) {
|
|||||||
var err error
|
var err error
|
||||||
stack.RegisterLifecycle(&InstrumentedService{
|
stack.RegisterLifecycle(&InstrumentedService{
|
||||||
startHook: func() {
|
startHook: func() {
|
||||||
db, err = stack.OpenDatabase("mydb", 0, 0, "")
|
db, err = stack.OpenDatabase("mydb", 0, 0, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("can't open DB:", err)
|
t.Fatal("can't open DB:", err)
|
||||||
}
|
}
|
||||||
@ -202,7 +202,7 @@ func TestNodeOpenDatabaseFromLifecycleStop(t *testing.T) {
|
|||||||
|
|
||||||
stack.RegisterLifecycle(&InstrumentedService{
|
stack.RegisterLifecycle(&InstrumentedService{
|
||||||
stopHook: func() {
|
stopHook: func() {
|
||||||
db, err := stack.OpenDatabase("mydb", 0, 0, "")
|
db, err := stack.OpenDatabase("mydb", 0, 0, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("can't open DB:", err)
|
t.Fatal("can't open DB:", err)
|
||||||
}
|
}
|
||||||
|
@ -1060,7 +1060,7 @@ func tempDB() (string, *Database) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("can't create temporary directory: %v", err))
|
panic(fmt.Sprintf("can't create temporary directory: %v", err))
|
||||||
}
|
}
|
||||||
diskdb, err := leveldb.New(dir, 256, 0, "")
|
diskdb, err := leveldb.New(dir, 256, 0, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("can't create temporary database: %v", err))
|
panic(fmt.Sprintf("can't create temporary database: %v", err))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user