diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index fbfdb48fc3..f63aba07f1 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -408,16 +408,11 @@ func checkStateContent(ctx *cli.Context) error { } func showDBStats(db ethdb.KeyValueStater) { - if stats, err := db.Stat("stats"); err != nil { + if stats, err := db.Stat(); err != nil { log.Warn("Failed to read database stats", "error", err) } else { fmt.Println(stats) } - if ioStats, err := db.Stat("iostats"); err != nil { - log.Warn("Failed to read database iostats", "error", err) - } else { - fmt.Println(ioStats) - } } func dbStats(ctx *cli.Context) error { diff --git a/core/rawdb/table.go b/core/rawdb/table.go index 19e4ed5b5c..4687ff07fe 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -148,8 +148,8 @@ 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) +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..fa306c56d1 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -183,8 +183,8 @@ func (db *Database) NewSnapshot() (ethdb.Snapshot, error) { } // Stat returns a particular internal stat of the database. -func (db *Database) Stat(property string) (string, error) { - return "", errors.New("unknown property") +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 48ebdbe0f7..130d6617b5 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -417,21 +417,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. -func (d *Database) Stat(property string) (string, error) { - metrics := d.db.Metrics() - if property == "iostats" { - total := metrics.Total() - return fmt.Sprintf("Read(MB):%.5f Write(MB):%.5f", - float64(total.BytesRead)/1048576.0, // 1024*1024 - float64(total.BytesFlushed+total.BytesCompacted)/1048576.0), nil - } - if property == "disk.size" { - return fmt.Sprintf("%d", metrics.Total().Size), nil - } - if property == "stats" { - return metrics.String(), nil - } - return "", fmt.Errorf("pebble stat property %s does not exists", property) +func (d *Database) Stat() (string, error) { + return d.db.Metrics().String(), nil } // Compact flattens the underlying data store for the given key range. In essence, 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 f211dcc659..242a79c1f1 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -2109,8 +2109,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 da60a7423d..d2b63db142 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 {