mirror of
https://github.com/tendermint/tendermint.git
synced 2026-08-17 20:56:14 +00:00
Merge pull request #2337 from tendermint/anton/cleveldb
BlockIntervalSeconds metric & DB tests cleanup & benchmark improv.
This commit is contained in:
@@ -21,5 +21,6 @@ FEATURES:
|
||||
|
||||
IMPROVEMENTS:
|
||||
- [types] add Address to GenesisValidator [\#1714](https://github.com/tendermint/tendermint/issues/1714)
|
||||
- [metrics] `consensus.block_interval_metrics` is now gauge, not histogram (you will be able to see spikes, if any)
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
Vendored
+3
-3
@@ -29,10 +29,10 @@ Vagrant.configure("2") do |config|
|
||||
usermod -a -G docker vagrant
|
||||
|
||||
# install go
|
||||
wget -q https://dl.google.com/go/go1.10.1.linux-amd64.tar.gz
|
||||
tar -xvf go1.10.1.linux-amd64.tar.gz
|
||||
wget -q https://dl.google.com/go/go1.11.linux-amd64.tar.gz
|
||||
tar -xvf go1.11.linux-amd64.tar.gz
|
||||
mv go /usr/local
|
||||
rm -f go1.10.1.linux-amd64.tar.gz
|
||||
rm -f go1.11.linux-amd64.tar.gz
|
||||
|
||||
# cleanup
|
||||
apt-get autoremove -y
|
||||
|
||||
+4
-4
@@ -113,7 +113,7 @@ type BaseConfig struct {
|
||||
// and verifying their commits
|
||||
FastSync bool `mapstructure:"fast_sync"`
|
||||
|
||||
// Database backend: leveldb | memdb
|
||||
// Database backend: leveldb | memdb | cleveldb
|
||||
DBBackend string `mapstructure:"db_backend"`
|
||||
|
||||
// Database directory
|
||||
@@ -587,15 +587,15 @@ type TxIndexConfig struct {
|
||||
// Comma-separated list of tags to index (by default the only tag is "tx.hash")
|
||||
//
|
||||
// You can also index transactions by height by adding "tx.height" tag here.
|
||||
//
|
||||
//
|
||||
// It's recommended to index only a subset of tags due to possible memory
|
||||
// bloat. This is, of course, depends on the indexer's DB and the volume of
|
||||
// transactions.
|
||||
IndexTags string `mapstructure:"index_tags"`
|
||||
|
||||
// When set to true, tells indexer to index all tags (predefined tags:
|
||||
// "tx.hash", "tx.height" and all tags from DeliverTx responses).
|
||||
//
|
||||
// "tx.hash", "tx.height" and all tags from DeliverTx responses).
|
||||
//
|
||||
// Note this may be not desirable (see the comment above). IndexTags has a
|
||||
// precedence over IndexAllTags (i.e. when given both, IndexTags will be
|
||||
// indexed).
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ moniker = "{{ .BaseConfig.Moniker }}"
|
||||
# and verifying their commits
|
||||
fast_sync = {{ .BaseConfig.FastSync }}
|
||||
|
||||
# Database backend: leveldb | memdb
|
||||
# Database backend: leveldb | memdb | cleveldb
|
||||
db_backend = "{{ .BaseConfig.DBBackend }}"
|
||||
|
||||
# Database directory
|
||||
|
||||
@@ -30,7 +30,7 @@ type Metrics struct {
|
||||
ByzantineValidatorsPower metrics.Gauge
|
||||
|
||||
// Time between this and the last block.
|
||||
BlockIntervalSeconds metrics.Histogram
|
||||
BlockIntervalSeconds metrics.Gauge
|
||||
|
||||
// Number of transactions.
|
||||
NumTxs metrics.Gauge
|
||||
@@ -85,11 +85,11 @@ func PrometheusMetrics() *Metrics {
|
||||
Help: "Total power of the byzantine validators.",
|
||||
}, []string{}),
|
||||
|
||||
BlockIntervalSeconds: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{
|
||||
|
||||
BlockIntervalSeconds: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||
Subsystem: "consensus",
|
||||
Name: "block_interval_seconds",
|
||||
Help: "Time between this and the last block.",
|
||||
Buckets: []float64{1, 2.5, 5, 10, 60},
|
||||
}, []string{}),
|
||||
|
||||
NumTxs: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{
|
||||
@@ -124,7 +124,7 @@ func NopMetrics() *Metrics {
|
||||
ByzantineValidators: discard.NewGauge(),
|
||||
ByzantineValidatorsPower: discard.NewGauge(),
|
||||
|
||||
BlockIntervalSeconds: discard.NewHistogram(),
|
||||
BlockIntervalSeconds: discard.NewGauge(),
|
||||
|
||||
NumTxs: discard.NewGauge(),
|
||||
BlockSizeBytes: discard.NewGauge(),
|
||||
|
||||
+1
-1
@@ -1374,7 +1374,7 @@ func (cs *ConsensusState) recordMetrics(height int64, block *types.Block) {
|
||||
|
||||
if height > 1 {
|
||||
lastBlockMeta := cs.blockStore.LoadBlockMeta(height - 1)
|
||||
cs.metrics.BlockIntervalSeconds.Observe(
|
||||
cs.metrics.BlockIntervalSeconds.Set(
|
||||
block.Time.Sub(lastBlockMeta.Header.Time).Seconds(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -48,6 +48,15 @@ to put the binary in `./build`.
|
||||
|
||||
The latest `tendermint version` is now installed.
|
||||
|
||||
## Run
|
||||
|
||||
To start a one-node blockchain with a simple in-process application:
|
||||
|
||||
```
|
||||
tendermint init
|
||||
tendermint node --proxy_app=kvstore
|
||||
```
|
||||
|
||||
## Reinstall
|
||||
|
||||
If you already have Tendermint installed, and you make updates, simply
|
||||
@@ -66,11 +75,37 @@ make get_vendor_deps
|
||||
make install
|
||||
```
|
||||
|
||||
## Run
|
||||
## Compile with CLevelDB support
|
||||
|
||||
To start a one-node blockchain with a simple in-process application:
|
||||
Install [LevelDB](https://github.com/google/leveldb) (minimum version is 1.7)
|
||||
with snappy. Example for Ubuntu:
|
||||
|
||||
```
|
||||
tendermint init
|
||||
tendermint node --proxy_app=kvstore
|
||||
sudo apt-get update
|
||||
sudo apt install build-essential
|
||||
|
||||
sudo apt-get install libsnappy-dev
|
||||
|
||||
wget https://github.com/google/leveldb/archive/v1.20.tar.gz && \
|
||||
tar -zxvf v1.20.tar.gz && \
|
||||
cd leveldb-1.20/ && \
|
||||
make && \
|
||||
sudo scp -r out-static/lib* out-shared/lib* /usr/local/lib/ && \
|
||||
cd include/ && \
|
||||
sudo scp -r leveldb /usr/local/include/ && \
|
||||
sudo ldconfig && \
|
||||
rm -f v1.20.tar.gz
|
||||
```
|
||||
|
||||
Set database backend to cleveldb:
|
||||
|
||||
```
|
||||
# config/config.toml
|
||||
db_backend = "cleveldb"
|
||||
```
|
||||
|
||||
To build Tendermint, run
|
||||
|
||||
```
|
||||
CGO_LDFLAGS="-lsnappy" go build -ldflags "-X github.com/tendermint/tendermint/version.GitCommit=`git rev-parse --short=8 HEAD`" -tags "tendermint gcc" -o build/tendermint ./cmd/tendermint/
|
||||
```
|
||||
|
||||
@@ -30,7 +30,7 @@ moniker = "anonymous"
|
||||
# and verifying their commits
|
||||
fast_sync = true
|
||||
|
||||
# Database backend: leveldb | memdb
|
||||
# Database backend: leveldb | memdb | cleveldb
|
||||
db_backend = "leveldb"
|
||||
|
||||
# Database directory
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
Tendermint Go-DB Copyright (C) 2015 All in Bits, Inc
|
||||
|
||||
Released under the Apache2.0 license
|
||||
@@ -1 +0,0 @@
|
||||
TODO: syndtr/goleveldb should be replaced with actual LevelDB instance
|
||||
+12
-6
@@ -13,7 +13,10 @@ import (
|
||||
)
|
||||
|
||||
func cleanupDBDir(dir, name string) {
|
||||
os.RemoveAll(filepath.Join(dir, name) + ".db")
|
||||
err := os.RemoveAll(filepath.Join(dir, name) + ".db")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testBackendGetSetDelete(t *testing.T, backend DBBackendType) {
|
||||
@@ -21,6 +24,7 @@ func testBackendGetSetDelete(t *testing.T, backend DBBackendType) {
|
||||
dirname, err := ioutil.TempDir("", fmt.Sprintf("test_backend_%s_", backend))
|
||||
require.Nil(t, err)
|
||||
db := NewDB("testdb", backend, dirname)
|
||||
defer cleanupDBDir(dirname, "testdb")
|
||||
|
||||
// A nonexistent key should return nil, even if the key is empty
|
||||
require.Nil(t, db.Get([]byte("")))
|
||||
@@ -55,9 +59,10 @@ func TestBackendsGetSetDelete(t *testing.T) {
|
||||
|
||||
func withDB(t *testing.T, creator dbCreator, fn func(DB)) {
|
||||
name := fmt.Sprintf("test_%x", cmn.RandStr(12))
|
||||
db, err := creator(name, "")
|
||||
defer cleanupDBDir("", name)
|
||||
assert.Nil(t, err)
|
||||
dir := os.TempDir()
|
||||
db, err := creator(name, dir)
|
||||
require.Nil(t, err)
|
||||
defer cleanupDBDir(dir, name)
|
||||
fn(db)
|
||||
db.Close()
|
||||
}
|
||||
@@ -161,8 +166,9 @@ func TestDBIterator(t *testing.T) {
|
||||
|
||||
func testDBIterator(t *testing.T, backend DBBackendType) {
|
||||
name := fmt.Sprintf("test_%x", cmn.RandStr(12))
|
||||
db := NewDB(name, backend, "")
|
||||
defer cleanupDBDir("", name)
|
||||
dir := os.TempDir()
|
||||
db := NewDB(name, backend, dir)
|
||||
defer cleanupDBDir(dir, name)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
if i != 6 { // but skip 6.
|
||||
|
||||
@@ -5,9 +5,11 @@ package db
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
)
|
||||
|
||||
@@ -32,7 +34,7 @@ func BenchmarkRandomReadsWrites2(b *testing.B) {
|
||||
// Write something
|
||||
{
|
||||
idx := (int64(cmn.RandInt()) % numItems)
|
||||
internal[idx] += 1
|
||||
internal[idx]++
|
||||
val := internal[idx]
|
||||
idxBytes := int642Bytes(int64(idx))
|
||||
valBytes := int642Bytes(int64(val))
|
||||
@@ -88,8 +90,11 @@ func bytes2Int64(buf []byte) int64 {
|
||||
|
||||
func TestCLevelDBBackend(t *testing.T) {
|
||||
name := fmt.Sprintf("test_%x", cmn.RandStr(12))
|
||||
db := NewDB(name, LevelDBBackend, "")
|
||||
defer cleanupDBDir("", name)
|
||||
// Can't use "" (current directory) or "./" here because levigo.Open returns:
|
||||
// "Error initializing DB: IO error: test_XXX.db: Invalid argument"
|
||||
dir := os.TempDir()
|
||||
db := NewDB(name, LevelDBBackend, dir)
|
||||
defer cleanupDBDir(dir, name)
|
||||
|
||||
_, ok := db.(*CLevelDB)
|
||||
assert.True(t, ok)
|
||||
|
||||
@@ -60,11 +60,10 @@ func checkValuePanics(t *testing.T, itr Iterator) {
|
||||
assert.Panics(t, func() { itr.Key() }, "checkValuePanics expected panic but didn't")
|
||||
}
|
||||
|
||||
func newTempDB(t *testing.T, backend DBBackendType) (db DB) {
|
||||
func newTempDB(t *testing.T, backend DBBackendType) (db DB, dbDir string) {
|
||||
dirname, err := ioutil.TempDir("", "db_common_test")
|
||||
require.Nil(t, err)
|
||||
db = NewDB("testdb", backend, dirname)
|
||||
return db
|
||||
return NewDB("testdb", backend, dirname), dirname
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
+18
-6
@@ -2,6 +2,7 @@ package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -10,7 +11,9 @@ import (
|
||||
func TestDBIteratorSingleKey(t *testing.T) {
|
||||
for backend := range backends {
|
||||
t.Run(fmt.Sprintf("Backend %s", backend), func(t *testing.T) {
|
||||
db := newTempDB(t, backend)
|
||||
db, dir := newTempDB(t, backend)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
db.SetSync(bz("1"), bz("value_1"))
|
||||
itr := db.Iterator(nil, nil)
|
||||
|
||||
@@ -28,7 +31,9 @@ func TestDBIteratorSingleKey(t *testing.T) {
|
||||
func TestDBIteratorTwoKeys(t *testing.T) {
|
||||
for backend := range backends {
|
||||
t.Run(fmt.Sprintf("Backend %s", backend), func(t *testing.T) {
|
||||
db := newTempDB(t, backend)
|
||||
db, dir := newTempDB(t, backend)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
db.SetSync(bz("1"), bz("value_1"))
|
||||
db.SetSync(bz("2"), bz("value_1"))
|
||||
|
||||
@@ -54,7 +59,8 @@ func TestDBIteratorTwoKeys(t *testing.T) {
|
||||
func TestDBIteratorMany(t *testing.T) {
|
||||
for backend := range backends {
|
||||
t.Run(fmt.Sprintf("Backend %s", backend), func(t *testing.T) {
|
||||
db := newTempDB(t, backend)
|
||||
db, dir := newTempDB(t, backend)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
keys := make([][]byte, 100)
|
||||
for i := 0; i < 100; i++ {
|
||||
@@ -78,7 +84,9 @@ func TestDBIteratorMany(t *testing.T) {
|
||||
func TestDBIteratorEmpty(t *testing.T) {
|
||||
for backend := range backends {
|
||||
t.Run(fmt.Sprintf("Backend %s", backend), func(t *testing.T) {
|
||||
db := newTempDB(t, backend)
|
||||
db, dir := newTempDB(t, backend)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
itr := db.Iterator(nil, nil)
|
||||
|
||||
checkInvalid(t, itr)
|
||||
@@ -89,7 +97,9 @@ func TestDBIteratorEmpty(t *testing.T) {
|
||||
func TestDBIteratorEmptyBeginAfter(t *testing.T) {
|
||||
for backend := range backends {
|
||||
t.Run(fmt.Sprintf("Backend %s", backend), func(t *testing.T) {
|
||||
db := newTempDB(t, backend)
|
||||
db, dir := newTempDB(t, backend)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
itr := db.Iterator(bz("1"), nil)
|
||||
|
||||
checkInvalid(t, itr)
|
||||
@@ -100,7 +110,9 @@ func TestDBIteratorEmptyBeginAfter(t *testing.T) {
|
||||
func TestDBIteratorNonemptyBeginAfter(t *testing.T) {
|
||||
for backend := range backends {
|
||||
t.Run(fmt.Sprintf("Backend %s", backend), func(t *testing.T) {
|
||||
db := newTempDB(t, backend)
|
||||
db, dir := newTempDB(t, backend)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
db.SetSync(bz("1"), bz("value_1"))
|
||||
itr := db.Iterator(bz("2"), nil)
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/syndtr/goleveldb/leveldb/opt"
|
||||
@@ -17,6 +18,7 @@ func TestNewGoLevelDB(t *testing.T) {
|
||||
// Test write locks
|
||||
db, err := NewGoLevelDB(name, "")
|
||||
require.Nil(t, err)
|
||||
defer os.RemoveAll("./" + name + ".db")
|
||||
_, err = NewGoLevelDB(name, "")
|
||||
require.NotNil(t, err)
|
||||
db.Close() // Close the db to release the lock
|
||||
|
||||
+11
-5
@@ -2,6 +2,7 @@ package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -9,7 +10,8 @@ import (
|
||||
func TestPrefixIteratorNoMatchNil(t *testing.T) {
|
||||
for backend := range backends {
|
||||
t.Run(fmt.Sprintf("Prefix w/ backend %s", backend), func(t *testing.T) {
|
||||
db := newTempDB(t, backend)
|
||||
db, dir := newTempDB(t, backend)
|
||||
defer os.RemoveAll(dir)
|
||||
itr := IteratePrefix(db, []byte("2"))
|
||||
|
||||
checkInvalid(t, itr)
|
||||
@@ -21,7 +23,8 @@ func TestPrefixIteratorNoMatchNil(t *testing.T) {
|
||||
func TestPrefixIteratorNoMatch1(t *testing.T) {
|
||||
for backend := range backends {
|
||||
t.Run(fmt.Sprintf("Prefix w/ backend %s", backend), func(t *testing.T) {
|
||||
db := newTempDB(t, backend)
|
||||
db, dir := newTempDB(t, backend)
|
||||
defer os.RemoveAll(dir)
|
||||
itr := IteratePrefix(db, []byte("2"))
|
||||
db.SetSync(bz("1"), bz("value_1"))
|
||||
|
||||
@@ -34,7 +37,8 @@ func TestPrefixIteratorNoMatch1(t *testing.T) {
|
||||
func TestPrefixIteratorNoMatch2(t *testing.T) {
|
||||
for backend := range backends {
|
||||
t.Run(fmt.Sprintf("Prefix w/ backend %s", backend), func(t *testing.T) {
|
||||
db := newTempDB(t, backend)
|
||||
db, dir := newTempDB(t, backend)
|
||||
defer os.RemoveAll(dir)
|
||||
db.SetSync(bz("3"), bz("value_3"))
|
||||
itr := IteratePrefix(db, []byte("4"))
|
||||
|
||||
@@ -47,7 +51,8 @@ func TestPrefixIteratorNoMatch2(t *testing.T) {
|
||||
func TestPrefixIteratorMatch1(t *testing.T) {
|
||||
for backend := range backends {
|
||||
t.Run(fmt.Sprintf("Prefix w/ backend %s", backend), func(t *testing.T) {
|
||||
db := newTempDB(t, backend)
|
||||
db, dir := newTempDB(t, backend)
|
||||
defer os.RemoveAll(dir)
|
||||
db.SetSync(bz("2"), bz("value_2"))
|
||||
itr := IteratePrefix(db, bz("2"))
|
||||
|
||||
@@ -65,7 +70,8 @@ func TestPrefixIteratorMatch1(t *testing.T) {
|
||||
func TestPrefixIteratorMatches1N(t *testing.T) {
|
||||
for backend := range backends {
|
||||
t.Run(fmt.Sprintf("Prefix w/ backend %s", backend), func(t *testing.T) {
|
||||
db := newTempDB(t, backend)
|
||||
db, dir := newTempDB(t, backend)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
// prefixed
|
||||
db.SetSync(bz("a/1"), bz("value_1"))
|
||||
|
||||
+14
-14
@@ -190,19 +190,6 @@ func txResultWithTags(tags []cmn.KVPair) *types.TxResult {
|
||||
}
|
||||
|
||||
func benchmarkTxIndex(txsCount int64, b *testing.B) {
|
||||
tx := types.Tx("HELLO WORLD")
|
||||
txResult := &types.TxResult{
|
||||
Height: 1,
|
||||
Index: 0,
|
||||
Tx: tx,
|
||||
Result: abci.ResponseDeliverTx{
|
||||
Data: []byte{0},
|
||||
Code: abci.CodeTypeOK,
|
||||
Log: "",
|
||||
Tags: []cmn.KVPair{},
|
||||
},
|
||||
}
|
||||
|
||||
dir, err := ioutil.TempDir("", "tx_index_db")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
@@ -213,11 +200,24 @@ func benchmarkTxIndex(txsCount int64, b *testing.B) {
|
||||
indexer := NewTxIndex(store)
|
||||
|
||||
batch := txindex.NewBatch(txsCount)
|
||||
txIndex := uint32(0)
|
||||
for i := int64(0); i < txsCount; i++ {
|
||||
tx := cmn.RandBytes(250)
|
||||
txResult := &types.TxResult{
|
||||
Height: 1,
|
||||
Index: txIndex,
|
||||
Tx: tx,
|
||||
Result: abci.ResponseDeliverTx{
|
||||
Data: []byte{0},
|
||||
Code: abci.CodeTypeOK,
|
||||
Log: "",
|
||||
Tags: []cmn.KVPair{},
|
||||
},
|
||||
}
|
||||
if err := batch.Add(txResult); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
txResult.Index++
|
||||
txIndex++
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
Reference in New Issue
Block a user