mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 19:00:46 +00:00
cmd/XDC: add db commands: stats, compact, put, get, delete (#22014)
This commit is contained in:
parent
742103c19c
commit
4224367396
3 changed files with 279 additions and 73 deletions
|
|
@ -27,7 +27,6 @@ import (
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/cmd/utils"
|
"github.com/XinFinOrg/XDPoSChain/cmd/utils"
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
"github.com/XinFinOrg/XDPoSChain/console"
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/core"
|
"github.com/XinFinOrg/XDPoSChain/core"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/state"
|
"github.com/XinFinOrg/XDPoSChain/core/state"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||||
|
|
@ -132,19 +131,6 @@ if already existing.`,
|
||||||
},
|
},
|
||||||
Description: `
|
Description: `
|
||||||
The export-preimages command export hash preimages to an RLP encoded stream`,
|
The export-preimages command export hash preimages to an RLP encoded stream`,
|
||||||
}
|
|
||||||
removedbCommand = &cli.Command{
|
|
||||||
Action: removeDB,
|
|
||||||
Name: "removedb",
|
|
||||||
Usage: "Remove blockchain and state databases",
|
|
||||||
ArgsUsage: " ",
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
utils.DataDirFlag,
|
|
||||||
utils.XDCXDataDirFlag,
|
|
||||||
utils.LightModeFlag,
|
|
||||||
},
|
|
||||||
Description: `
|
|
||||||
Remove blockchain and state databases`,
|
|
||||||
}
|
}
|
||||||
dumpCommand = &cli.Command{
|
dumpCommand = &cli.Command{
|
||||||
Action: dump,
|
Action: dump,
|
||||||
|
|
@ -224,8 +210,8 @@ func importChain(ctx *cli.Context) error {
|
||||||
// Start metrics export if enabled
|
// Start metrics export if enabled
|
||||||
utils.SetupMetrics(&cfg.Metrics)
|
utils.SetupMetrics(&cfg.Metrics)
|
||||||
|
|
||||||
chain, chainDb := utils.MakeChain(ctx, stack, false)
|
chain, db := utils.MakeChain(ctx, stack, false)
|
||||||
defer chainDb.Close()
|
defer db.Close()
|
||||||
|
|
||||||
// Start periodically gathering memory profiles
|
// Start periodically gathering memory profiles
|
||||||
var peakMemAlloc, peakMemSys uint64
|
var peakMemAlloc, peakMemSys uint64
|
||||||
|
|
@ -245,13 +231,17 @@ func importChain(ctx *cli.Context) error {
|
||||||
// Import the chain
|
// Import the chain
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
|
var importErr error
|
||||||
|
|
||||||
if ctx.Args().Len() == 1 {
|
if ctx.Args().Len() == 1 {
|
||||||
if err := utils.ImportChain(chain, ctx.Args().First()); err != nil {
|
if err := utils.ImportChain(chain, ctx.Args().First()); err != nil {
|
||||||
|
importErr = err
|
||||||
log.Error("Import error", "err", err)
|
log.Error("Import error", "err", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, arg := range ctx.Args().Slice() {
|
for _, arg := range ctx.Args().Slice() {
|
||||||
if err := utils.ImportChain(chain, arg); err != nil {
|
if err := utils.ImportChain(chain, arg); err != nil {
|
||||||
|
importErr = err
|
||||||
log.Error("Import error", "file", arg, "err", err)
|
log.Error("Import error", "file", arg, "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -260,19 +250,7 @@ func importChain(ctx *cli.Context) error {
|
||||||
fmt.Printf("Import done in %v.\n\n", time.Since(start))
|
fmt.Printf("Import done in %v.\n\n", time.Since(start))
|
||||||
|
|
||||||
// Output pre-compaction stats mostly to see the import trashing
|
// Output pre-compaction stats mostly to see the import trashing
|
||||||
db := chainDb
|
showLeveldbStats(db)
|
||||||
|
|
||||||
stats, err := db.Get([]byte("leveldb.stats"))
|
|
||||||
if err != nil {
|
|
||||||
utils.Fatalf("Failed to read database stats: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Println(stats)
|
|
||||||
|
|
||||||
ioStats, err := db.Get([]byte("leveldb.iostats"))
|
|
||||||
if err != nil {
|
|
||||||
utils.Fatalf("Failed to read database iostats: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Println(ioStats)
|
|
||||||
|
|
||||||
// Print the memory statistics used by the importing
|
// Print the memory statistics used by the importing
|
||||||
mem := new(runtime.MemStats)
|
mem := new(runtime.MemStats)
|
||||||
|
|
@ -283,31 +261,20 @@ func importChain(ctx *cli.Context) error {
|
||||||
fmt.Printf("Allocations: %.3f million\n", float64(mem.Mallocs)/1000000)
|
fmt.Printf("Allocations: %.3f million\n", float64(mem.Mallocs)/1000000)
|
||||||
fmt.Printf("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs))
|
fmt.Printf("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs))
|
||||||
|
|
||||||
if ctx.IsSet(utils.NoCompactionFlag.Name) {
|
if ctx.Bool(utils.NoCompactionFlag.Name) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compact the entire database to more accurately measure disk io and print the stats
|
// Compact the entire database to more accurately measure disk io and print the stats
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
fmt.Println("Compacting entire database...")
|
fmt.Println("Compacting entire database...")
|
||||||
if err = db.Compact(nil, nil); err != nil {
|
if err := db.Compact(nil, nil); err != nil {
|
||||||
utils.Fatalf("Compaction failed: %v", err)
|
utils.Fatalf("Compaction failed: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("Compaction done in %v.\n\n", time.Since(start))
|
fmt.Printf("Compaction done in %v.\n\n", time.Since(start))
|
||||||
|
|
||||||
stats, err = db.Get([]byte("leveldb.stats"))
|
showLeveldbStats(db)
|
||||||
if err != nil {
|
return importErr
|
||||||
utils.Fatalf("Failed to read database stats: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Println(stats)
|
|
||||||
|
|
||||||
ioStats, err = db.Get([]byte("leveldb.iostats"))
|
|
||||||
if err != nil {
|
|
||||||
utils.Fatalf("Failed to read database iostats: %v", err)
|
|
||||||
}
|
|
||||||
fmt.Println(ioStats)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func exportChain(ctx *cli.Context) error {
|
func exportChain(ctx *cli.Context) error {
|
||||||
|
|
@ -385,35 +352,6 @@ func exportPreimages(ctx *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeDB(ctx *cli.Context) error {
|
|
||||||
stack, _ := makeConfigNode(ctx)
|
|
||||||
|
|
||||||
for _, name := range []string{"chaindata", "lightchaindata"} {
|
|
||||||
// Ensure the database exists in the first place
|
|
||||||
logger := log.New("database", name)
|
|
||||||
|
|
||||||
dbdir := stack.ResolvePath(name)
|
|
||||||
if !common.FileExist(dbdir) {
|
|
||||||
logger.Info("Database doesn't exist, skipping", "path", dbdir)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Confirm removal and execute
|
|
||||||
fmt.Println(dbdir)
|
|
||||||
confirm, err := console.Stdin.PromptConfirm("Remove this database?")
|
|
||||||
switch {
|
|
||||||
case err != nil:
|
|
||||||
utils.Fatalf("%v", err)
|
|
||||||
case !confirm:
|
|
||||||
logger.Warn("Database deletion aborted")
|
|
||||||
default:
|
|
||||||
start := time.Now()
|
|
||||||
os.RemoveAll(dbdir)
|
|
||||||
logger.Info("Database successfully deleted", "elapsed", common.PrettyDuration(time.Since(start)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func dump(ctx *cli.Context) error {
|
func dump(ctx *cli.Context) error {
|
||||||
stack, _ := makeFullNode(ctx)
|
stack, _ := makeFullNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
|
||||||
259
cmd/XDC/dbcmd.go
Normal file
259
cmd/XDC/dbcmd.go
Normal file
|
|
@ -0,0 +1,259 @@
|
||||||
|
// Copyright 2020 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/cmd/utils"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/console"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/ethdb"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/log"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
removedbCommand = &cli.Command{
|
||||||
|
Action: removeDB,
|
||||||
|
Name: "removedb",
|
||||||
|
Usage: "Remove blockchain and state databases",
|
||||||
|
ArgsUsage: " ",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.XDCXDataDirFlag,
|
||||||
|
utils.LightModeFlag,
|
||||||
|
},
|
||||||
|
Description: `
|
||||||
|
Remove blockchain and state databases`,
|
||||||
|
}
|
||||||
|
dbCommand = &cli.Command{
|
||||||
|
Name: "db",
|
||||||
|
Usage: "Low level database operations",
|
||||||
|
ArgsUsage: "",
|
||||||
|
Subcommands: []*cli.Command{
|
||||||
|
dbStatCmd,
|
||||||
|
dbCompactCmd,
|
||||||
|
dbGetCmd,
|
||||||
|
dbDeleteCmd,
|
||||||
|
dbPutCmd,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
dbStatCmd = &cli.Command{
|
||||||
|
Action: dbStats,
|
||||||
|
Name: "stats",
|
||||||
|
Usage: "Print leveldb statistics",
|
||||||
|
}
|
||||||
|
dbCompactCmd = &cli.Command{
|
||||||
|
Action: dbCompact,
|
||||||
|
Name: "compact",
|
||||||
|
Usage: "Compact leveldb database. WARNING: May take a very long time",
|
||||||
|
Description: `This command performs a database compaction.
|
||||||
|
WARNING: This operation may take a very long time to finish, and may cause database
|
||||||
|
corruption if it is aborted during execution'!`,
|
||||||
|
}
|
||||||
|
dbGetCmd = &cli.Command{
|
||||||
|
Action: dbGet,
|
||||||
|
Name: "get",
|
||||||
|
Usage: "Show the value of a database key",
|
||||||
|
ArgsUsage: "<hex-encoded key>",
|
||||||
|
Description: "This command looks up the specified database key from the database.",
|
||||||
|
}
|
||||||
|
dbDeleteCmd = &cli.Command{
|
||||||
|
Action: dbDelete,
|
||||||
|
Name: "delete",
|
||||||
|
Usage: "Delete a database key (WARNING: may corrupt your database)",
|
||||||
|
ArgsUsage: "<hex-encoded key>",
|
||||||
|
Description: `This command deletes the specified database key from the database.
|
||||||
|
WARNING: This is a low-level operation which may cause database corruption!`,
|
||||||
|
}
|
||||||
|
dbPutCmd = &cli.Command{
|
||||||
|
Action: dbPut,
|
||||||
|
Name: "put",
|
||||||
|
Usage: "Set the value of a database key (WARNING: may corrupt your database)",
|
||||||
|
ArgsUsage: "<hex-encoded key> <hex-encoded 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!`,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func removeDB(ctx *cli.Context) error {
|
||||||
|
stack, _ := makeConfigNode(ctx)
|
||||||
|
for _, name := range []string{"chaindata", "lightchaindata"} {
|
||||||
|
// Ensure the database exists in the first place
|
||||||
|
logger := log.New("database", name)
|
||||||
|
|
||||||
|
dbdir := stack.ResolvePath(name)
|
||||||
|
if !common.FileExist(dbdir) {
|
||||||
|
logger.Info("Database doesn't exist, skipping", "path", dbdir)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
confirmAndRemoveDB(dbdir, name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// confirmAndRemoveDB prompts the user for a last confirmation and removes the
|
||||||
|
// folder if accepted.
|
||||||
|
func confirmAndRemoveDB(database string, kind string) {
|
||||||
|
confirm, err := console.Stdin.PromptConfirm(fmt.Sprintf("Remove %s (%s)?", kind, database))
|
||||||
|
switch {
|
||||||
|
case err != nil:
|
||||||
|
utils.Fatalf("%v", err)
|
||||||
|
case !confirm:
|
||||||
|
log.Warn("Database deletion aborted", "path", database)
|
||||||
|
default:
|
||||||
|
start := time.Now()
|
||||||
|
os.RemoveAll(database)
|
||||||
|
log.Info("Database successfully deleted", "path", database, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func showLeveldbStats(db ethdb.Stater) {
|
||||||
|
if stats, err := db.Stat("leveldb.stats"); err != nil {
|
||||||
|
log.Warn("Failed to read database stats", "error", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println(stats)
|
||||||
|
}
|
||||||
|
if ioStats, err := db.Stat("leveldb.iostats"); err != nil {
|
||||||
|
log.Warn("Failed to read database iostats", "error", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println(ioStats)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dbStats(ctx *cli.Context) error {
|
||||||
|
stack, _ := makeConfigNode(ctx)
|
||||||
|
defer stack.Close()
|
||||||
|
|
||||||
|
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
showLeveldbStats(db)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dbCompact(ctx *cli.Context) error {
|
||||||
|
stack, _ := makeConfigNode(ctx)
|
||||||
|
defer stack.Close()
|
||||||
|
|
||||||
|
db := utils.MakeChainDatabase(ctx, stack, false)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
log.Info("Stats before compaction")
|
||||||
|
showLeveldbStats(db)
|
||||||
|
|
||||||
|
log.Info("Triggering compaction")
|
||||||
|
if err := db.Compact(nil, nil); err != nil {
|
||||||
|
log.Info("Compact err", "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Stats after compaction")
|
||||||
|
showLeveldbStats(db)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// dbGet shows the value of a given database key
|
||||||
|
func dbGet(ctx *cli.Context) error {
|
||||||
|
if ctx.NArg() != 1 {
|
||||||
|
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
|
||||||
|
}
|
||||||
|
stack, _ := makeConfigNode(ctx)
|
||||||
|
defer stack.Close()
|
||||||
|
|
||||||
|
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
key, err := common.ParseHexOrString(ctx.Args().Get(0))
|
||||||
|
if err != nil {
|
||||||
|
log.Info("Could not decode the key", "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := db.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
log.Info("Get operation failed", "key", fmt.Sprintf("%#x", key), "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("key %#x:\n\t%#x\n", key, data)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// dbDelete deletes a key from the database
|
||||||
|
func dbDelete(ctx *cli.Context) error {
|
||||||
|
if ctx.NArg() != 1 {
|
||||||
|
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
|
||||||
|
}
|
||||||
|
stack, _ := makeConfigNode(ctx)
|
||||||
|
defer stack.Close()
|
||||||
|
|
||||||
|
db := utils.MakeChainDatabase(ctx, stack, false)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
key, err := common.ParseHexOrString(ctx.Args().Get(0))
|
||||||
|
if err != nil {
|
||||||
|
log.Info("Could not decode the key", "error", 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 {
|
||||||
|
log.Info("Delete operation returned an error", "key", fmt.Sprintf("%#x", key), "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// dbPut overwrite a value in the database
|
||||||
|
func dbPut(ctx *cli.Context) error {
|
||||||
|
if ctx.NArg() != 2 {
|
||||||
|
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
|
||||||
|
}
|
||||||
|
stack, _ := makeConfigNode(ctx)
|
||||||
|
defer stack.Close()
|
||||||
|
|
||||||
|
db := utils.MakeChainDatabase(ctx, stack, false)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
var (
|
||||||
|
key []byte
|
||||||
|
value []byte
|
||||||
|
data []byte
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
key, err = common.ParseHexOrString(ctx.Args().Get(0))
|
||||||
|
if err != nil {
|
||||||
|
log.Info("Could not decode the key", "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
value, err = hexutil.Decode(ctx.Args().Get(1))
|
||||||
|
if err != nil {
|
||||||
|
log.Info("Could not decode the value", "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data, err = db.Get(key)
|
||||||
|
if err == nil {
|
||||||
|
fmt.Printf("Previous value:\n%#x\n", data)
|
||||||
|
}
|
||||||
|
return db.Put(key, value)
|
||||||
|
}
|
||||||
|
|
@ -188,6 +188,8 @@ func init() {
|
||||||
initCommand,
|
initCommand,
|
||||||
importCommand,
|
importCommand,
|
||||||
exportCommand,
|
exportCommand,
|
||||||
|
importPreimagesCommand,
|
||||||
|
exportPreimagesCommand,
|
||||||
removedbCommand,
|
removedbCommand,
|
||||||
dumpCommand,
|
dumpCommand,
|
||||||
// See accountcmd.go:
|
// See accountcmd.go:
|
||||||
|
|
@ -198,9 +200,16 @@ func init() {
|
||||||
attachCommand,
|
attachCommand,
|
||||||
javascriptCommand,
|
javascriptCommand,
|
||||||
// See misccmd.go:
|
// See misccmd.go:
|
||||||
|
makecacheCommand,
|
||||||
|
makedagCommand,
|
||||||
versionCommand,
|
versionCommand,
|
||||||
|
licenseCommand,
|
||||||
// See config.go
|
// See config.go
|
||||||
dumpConfigCommand,
|
dumpConfigCommand,
|
||||||
|
// see dbcmd.go
|
||||||
|
dbCommand,
|
||||||
|
// See cmd/utils/flags_legacy.go
|
||||||
|
utils.ShowDeprecated,
|
||||||
}
|
}
|
||||||
sort.Sort(cli.CommandsByName(app.Commands))
|
sort.Sort(cli.CommandsByName(app.Commands))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue