Browse Source

Merge pull request #2337 from tendermint/anton/cleveldb

BlockIntervalSeconds metric & DB tests cleanup & benchmark improv.
pull/2370/merge
Anton Kaliaev 6 years ago
committed by GitHub
parent
commit
64fc8f8157
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 121 additions and 59 deletions
  1. +1
    -0
      CHANGELOG_PENDING.md
  2. +3
    -3
      Vagrantfile
  3. +4
    -4
      config/config.go
  4. +1
    -1
      config/toml.go
  5. +4
    -4
      consensus/metrics.go
  6. +1
    -1
      consensus/state.go
  7. +39
    -4
      docs/introduction/install.md
  8. +1
    -1
      docs/tendermint-core/configuration.md
  9. +0
    -3
      libs/db/LICENSE.md
  10. +0
    -1
      libs/db/README.md
  11. +12
    -6
      libs/db/backend_test.go
  12. +8
    -3
      libs/db/c_level_db_test.go
  13. +2
    -3
      libs/db/common_test.go
  14. +18
    -6
      libs/db/db_test.go
  15. +2
    -0
      libs/db/go_level_db_test.go
  16. +11
    -5
      libs/db/util_test.go
  17. +14
    -14
      state/txindex/kv/kv_test.go

+ 1
- 0
CHANGELOG_PENDING.md View File

@ -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:

+ 3
- 3
Vagrantfile View File

@ -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
config/config.go View File

@ -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
config/toml.go View File

@ -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


+ 4
- 4
consensus/metrics.go View File

@ -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
consensus/state.go View File

@ -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(),
)
}


+ 39
- 4
docs/introduction/install.md View File

@ -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/
```

+ 1
- 1
docs/tendermint-core/configuration.md View File

@ -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


+ 0
- 3
libs/db/LICENSE.md View File

@ -1,3 +0,0 @@
Tendermint Go-DB Copyright (C) 2015 All in Bits, Inc
Released under the Apache2.0 license

+ 0
- 1
libs/db/README.md View File

@ -1 +0,0 @@
TODO: syndtr/goleveldb should be replaced with actual LevelDB instance

+ 12
- 6
libs/db/backend_test.go View File

@ -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.


+ 8
- 3
libs/db/c_level_db_test.go View File

@ -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)


+ 2
- 3
libs/db/common_test.go View File

@ -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
libs/db/db_test.go View File

@ -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)


+ 2
- 0
libs/db/go_level_db_test.go View File

@ -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
libs/db/util_test.go View File

@ -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
state/txindex/kv/kv_test.go View File

@ -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()


Loading…
Cancel
Save