diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 2965b99d94..9450c09e7e 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -336,7 +336,7 @@ func importChain(ctx *cli.Context) error { fmt.Printf("Import done in %v.\n\n", time.Since(start)) // Output pre-compaction stats mostly to see the import trashing - showLeveldbStats(db) + showDBStats(db) // Print the memory statistics used by the importing mem := new(runtime.MemStats) @@ -359,7 +359,7 @@ func importChain(ctx *cli.Context) error { } fmt.Printf("Compaction done in %v.\n\n", time.Since(start)) - showLeveldbStats(db) + showDBStats(db) return importErr } diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 742eadd5f3..4b683569a4 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -407,17 +407,13 @@ func checkStateContent(ctx *cli.Context) error { return nil } -func showLeveldbStats(db ethdb.KeyValueStater) { - if stats, err := db.Stat("leveldb.stats"); err != nil { +func showDBStats(db ethdb.KeyValueStater) { + stats, err := db.Stat() + if 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) + return } + fmt.Println(stats) } func dbStats(ctx *cli.Context) error { @@ -427,7 +423,7 @@ func dbStats(ctx *cli.Context) error { db := utils.MakeChainDatabase(ctx, stack, true) defer db.Close() - showLeveldbStats(db) + showDBStats(db) return nil } @@ -439,7 +435,7 @@ func dbCompact(ctx *cli.Context) error { defer db.Close() log.Info("Stats before compaction") - showLeveldbStats(db) + showDBStats(db) log.Info("Triggering compaction") if err := db.Compact(nil, nil); err != nil { @@ -447,7 +443,7 @@ func dbCompact(ctx *cli.Context) error { return err } log.Info("Stats after compaction") - showLeveldbStats(db) + showDBStats(db) return nil } diff --git a/core/rawdb/table.go b/core/rawdb/table.go index 19e4ed5b5c..90849fe9d9 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -147,9 +147,9 @@ func (t *table) NewIterator(prefix []byte, start []byte) ethdb.Iterator { } } -// Stat returns a particular internal stat of the database. -func (t *table) Stat(property string) (string, error) { - return t.db.Stat(property) +// Stat returns the statistic data of the database. +func (t *table) Stat() (string, error) { + return t.db.Stat() } // Compact flattens the underlying data store for the given key range. In essence, diff --git a/ethdb/database.go b/ethdb/database.go index 3ec1f70e3b..9ef5942a13 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -39,8 +39,8 @@ type KeyValueWriter interface { // KeyValueStater wraps the Stat method of a backing data store. type KeyValueStater interface { - // Stat returns a particular internal stat of the database. - Stat(property string) (string, error) + // Stat returns the statistic data of the database. + Stat() (string, error) } // Compacter wraps the Compact method of a backing data store. diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index 64f51cf217..92838ad7ab 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -22,7 +22,6 @@ package leveldb import ( "fmt" - "strings" "sync" "time" @@ -244,14 +243,53 @@ func (db *Database) NewSnapshot() (ethdb.Snapshot, error) { return &snapshot{db: snap}, nil } -// Stat returns a particular internal stat of the database. -func (db *Database) Stat(property string) (string, error) { - if property == "" { - property = "leveldb.stats" - } else if !strings.HasPrefix(property, "leveldb.") { - property = "leveldb." + property +// Stat returns the statistic data of the database. +func (db *Database) Stat() (string, error) { + var stats leveldb.DBStats + if err := db.db.Stats(&stats); err != nil { + return "", err } - return db.db.GetProperty(property) + var ( + message string + totalRead int64 + totalWrite int64 + totalSize int64 + totalTables int + totalDuration time.Duration + ) + if len(stats.LevelSizes) > 0 { + message += " Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB)\n" + + "-------+------------+---------------+---------------+---------------+---------------\n" + for level, size := range stats.LevelSizes { + read := stats.LevelRead[level] + write := stats.LevelWrite[level] + duration := stats.LevelDurations[level] + tables := stats.LevelTablesCounts[level] + + if tables == 0 && duration == 0 { + continue + } + totalTables += tables + totalSize += size + totalRead += read + totalWrite += write + totalDuration += duration + message += fmt.Sprintf(" %3d | %10d | %13.5f | %13.5f | %13.5f | %13.5f\n", + level, tables, float64(size)/1048576.0, duration.Seconds(), + float64(read)/1048576.0, float64(write)/1048576.0) + } + message += "-------+------------+---------------+---------------+---------------+---------------\n" + message += fmt.Sprintf(" Total | %10d | %13.5f | %13.5f | %13.5f | %13.5f\n", + totalTables, float64(totalSize)/1048576.0, totalDuration.Seconds(), + float64(totalRead)/1048576.0, float64(totalWrite)/1048576.0) + message += "-------+------------+---------------+---------------+---------------+---------------\n\n" + } + message += fmt.Sprintf("Read(MB):%.5f Write(MB):%.5f\n", float64(stats.IORead)/1048576.0, float64(stats.IOWrite)/1048576.0) + message += fmt.Sprintf("BlockCache(MB):%.5f FileCache:%d\n", float64(stats.BlockCacheSize)/1048576.0, stats.OpenedTablesCount) + message += fmt.Sprintf("MemoryCompaction:%d Level0Compaction:%d NonLevel0Compaction:%d SeekCompaction:%d\n", stats.MemComp, stats.Level0Comp, stats.NonLevel0Comp, stats.SeekComp) + message += fmt.Sprintf("WriteDelayCount:%d WriteDelayDuration:%s Paused:%t\n", stats.WriteDelayCount, common.PrettyDuration(stats.WriteDelayDuration), stats.WritePaused) + message += fmt.Sprintf("Snapshots:%d Iterators:%d\n", stats.AliveSnapshots, stats.AliveIterators) + return message, nil } // Compact flattens the underlying data store for the given key range. In essence, diff --git a/ethdb/memorydb/memorydb.go b/ethdb/memorydb/memorydb.go index d1233acb21..9b0872f89a 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -182,9 +182,9 @@ func (db *Database) NewSnapshot() (ethdb.Snapshot, error) { return newSnapshot(db), nil } -// Stat returns a particular internal stat of the database. -func (db *Database) Stat(property string) (string, error) { - return "", errors.New("unknown property") +// Stat returns the statistic data of the database. +func (db *Database) Stat() (string, error) { + return "", nil } // Compact is not supported on a memory database, but there's no need either as diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 0fac07c960..130d6617b5 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -416,10 +416,8 @@ func upperBound(prefix []byte) (limit []byte) { } // Stat returns the internal metrics of Pebble in a text format. It's a developer -// method to read everything there is to read independent of Pebble version. -// -// The property is unused in Pebble as there's only one thing to retrieve. -func (d *Database) Stat(property string) (string, error) { +// method to read everything there is to read, independent of Pebble version. +func (d *Database) Stat() (string, error) { return d.db.Metrics().String(), nil } diff --git a/ethdb/remotedb/remotedb.go b/ethdb/remotedb/remotedb.go index c1c803caf2..bfecde4a32 100644 --- a/ethdb/remotedb/remotedb.go +++ b/ethdb/remotedb/remotedb.go @@ -126,8 +126,8 @@ func (db *Database) NewIterator(prefix []byte, start []byte) ethdb.Iterator { panic("not supported") } -func (db *Database) Stat(property string) (string, error) { - panic("not supported") +func (db *Database) Stat() (string, error) { + return "", nil } func (db *Database) AncientDatadir() (string, error) { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1c209fb5a4..0ecedf1130 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -2108,8 +2108,8 @@ func (api *DebugAPI) PrintBlock(ctx context.Context, number uint64) (string, err } // ChaindbProperty returns leveldb properties of the key-value database. -func (api *DebugAPI) ChaindbProperty(property string) (string, error) { - return api.b.ChainDb().Stat(property) +func (api *DebugAPI) ChaindbProperty() (string, error) { + return api.b.ChainDb().Stat() } // ChaindbCompact flattens the entire key-value database into a single level, diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 1da7d737dd..4a1a37d722 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -263,7 +263,6 @@ web3._extend({ new web3._extend.Method({ name: 'chaindbProperty', call: 'debug_chaindbProperty', - params: 1, outputFormatter: console.log }), new web3._extend.Method({ diff --git a/trie/trie_test.go b/trie/trie_test.go index f31fd393f5..5f706a28be 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -820,7 +820,7 @@ func (s *spongeDb) Delete(key []byte) error { panic("implement func (s *spongeDb) NewBatch() ethdb.Batch { return &spongeBatch{s} } func (s *spongeDb) NewBatchWithSize(size int) ethdb.Batch { return &spongeBatch{s} } func (s *spongeDb) NewSnapshot() (ethdb.Snapshot, error) { panic("implement me") } -func (s *spongeDb) Stat(property string) (string, error) { panic("implement me") } +func (s *spongeDb) Stat() (string, error) { panic("implement me") } func (s *spongeDb) Compact(start []byte, limit []byte) error { panic("implement me") } func (s *spongeDb) Close() error { return nil } func (s *spongeDb) Put(key []byte, value []byte) error {