diff --git a/state/execution.go b/state/execution.go index 802d12c49..f6898cb4d 100644 --- a/state/execution.go +++ b/state/execution.go @@ -9,7 +9,7 @@ import ( . "github.com/tendermint/go-common" crypto "github.com/tendermint/go-crypto" "github.com/tendermint/tendermint/proxy" - txindexer "github.com/tendermint/tendermint/state/tx/indexer" + "github.com/tendermint/tendermint/state/txindex" "github.com/tendermint/tendermint/types" ) @@ -241,12 +241,12 @@ func (s *State) ApplyBlock(eventCache types.Fireable, proxyAppConn proxy.AppConn return fmt.Errorf("Commit failed for application: %v", err) } - batch := txindexer.NewBatch() + batch := txindex.NewBatch() for i, r := range txResults { tx := block.Txs[i] batch.Index(tx.Hash(), *r) } - s.TxIndexer.Batch(batch) + s.TxIndexer.AddBatch(batch) return nil } diff --git a/state/execution_test.go b/state/execution_test.go index 8b9cf4a73..2da801964 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -11,7 +11,7 @@ import ( cfg "github.com/tendermint/tendermint/config/tendermint_test" "github.com/tendermint/tendermint/mempool" "github.com/tendermint/tendermint/proxy" - txindexer "github.com/tendermint/tendermint/state/tx/indexer" + "github.com/tendermint/tendermint/state/txindex" "github.com/tendermint/tendermint/types" ) @@ -81,10 +81,10 @@ type dummyIndexer struct { Indexed int } -func (indexer *dummyIndexer) Tx(hash []byte) (*types.TxResult, error) { +func (indexer *dummyIndexer) Get(hash []byte) (*types.TxResult, error) { return nil, nil } -func (indexer *dummyIndexer) Batch(batch *txindexer.Batch) error { +func (indexer *dummyIndexer) AddBatch(batch *txindex.Batch) error { indexer.Indexed += batch.Size() return nil } diff --git a/state/state.go b/state/state.go index cecb38418..14b324d5f 100644 --- a/state/state.go +++ b/state/state.go @@ -10,8 +10,8 @@ import ( cfg "github.com/tendermint/go-config" dbm "github.com/tendermint/go-db" "github.com/tendermint/go-wire" - "github.com/tendermint/tendermint/state/tx" - txindexer "github.com/tendermint/tendermint/state/tx/indexer" + "github.com/tendermint/tendermint/state/txindex" + "github.com/tendermint/tendermint/state/txindex/null" "github.com/tendermint/tendermint/types" ) @@ -41,7 +41,7 @@ type State struct { // AppHash is updated after Commit AppHash []byte - TxIndexer tx.Indexer `json:"-"` // Transaction indexer. + TxIndexer txindex.TxIndexer `json:"-"` // Transaction indexer. } func LoadState(db dbm.DB) *State { @@ -49,7 +49,7 @@ func LoadState(db dbm.DB) *State { } func loadState(db dbm.DB, key []byte) *State { - s := &State{db: db, TxIndexer: &txindexer.Null{}} + s := &State{db: db, TxIndexer: &null.TxIndex{}} buf := db.Get(key) if len(buf) == 0 { return nil @@ -188,6 +188,6 @@ func MakeGenesisState(db dbm.DB, genDoc *types.GenesisDoc) *State { Validators: types.NewValidatorSet(validators), LastValidators: types.NewValidatorSet(nil), AppHash: genDoc.AppHash, - TxIndexer: &txindexer.Null{}, // we do not need indexer during replay and in tests + TxIndexer: &null.TxIndex{}, // we do not need indexer during replay and in tests } } diff --git a/state/tx/indexer.go b/state/tx/indexer.go deleted file mode 100644 index be7f304c4..000000000 --- a/state/tx/indexer.go +++ /dev/null @@ -1,21 +0,0 @@ -package tx - -import ( - txindexer "github.com/tendermint/tendermint/state/tx/indexer" - "github.com/tendermint/tendermint/types" -) - -// Indexer interface defines methods to index and search transactions. -type Indexer interface { - - // Batch analyzes, indexes or stores a batch of transactions. - // - // NOTE We do not specify Index method for analyzing a single transaction - // here because it bears heavy perfomance loses. Almost all advanced indexers - // support batching. - Batch(b *txindexer.Batch) error - - // Tx returns specified transaction or nil if the transaction is not indexed - // or stored. - Tx(hash []byte) (*types.TxResult, error) -} diff --git a/state/tx/indexer/batch.go b/state/tx/indexer/batch.go deleted file mode 100644 index 78137f598..000000000 --- a/state/tx/indexer/batch.go +++ /dev/null @@ -1,32 +0,0 @@ -package indexer - -import "github.com/tendermint/tendermint/types" - -// A Batch groups together multiple Index operations you would like performed -// at the same time. The Batch structure is NOT thread-safe. You should only -// perform operations on a batch from a single thread at a time. Once batch -// execution has started, you may not modify it. -type Batch struct { - Ops map[string]types.TxResult -} - -// NewBatch creates a new Batch. -func NewBatch() *Batch { - return &Batch{ - Ops: make(map[string]types.TxResult), - } -} - -// Index adds or updates entry for the given hash. -func (b *Batch) Index(hash []byte, result types.TxResult) error { - if len(hash) == 0 { - return ErrorEmptyHash - } - b.Ops[string(hash)] = result - return nil -} - -// Size returns the total number of operations inside the batch. -func (b *Batch) Size() int { - return len(b.Ops) -} diff --git a/state/tx/indexer/error.go b/state/tx/indexer/error.go deleted file mode 100644 index 9d20593d1..000000000 --- a/state/tx/indexer/error.go +++ /dev/null @@ -1,6 +0,0 @@ -package indexer - -import "errors" - -// ErrorEmptyHash indicates empty hash -var ErrorEmptyHash = errors.New("Transaction hash cannot be empty") diff --git a/state/tx/indexer/null.go b/state/tx/indexer/null.go deleted file mode 100644 index a322602d0..000000000 --- a/state/tx/indexer/null.go +++ /dev/null @@ -1,19 +0,0 @@ -package indexer - -import ( - "errors" - "github.com/tendermint/tendermint/types" -) - -// Null acts as a /dev/null. -type Null struct{} - -// Tx panics. -func (indexer *Null) Tx(hash []byte) (*types.TxResult, error) { - return nil, errors.New(`Indexing is disabled (set 'tx_indexer = "kv"' in config)`) -} - -// Batch returns nil. -func (indexer *Null) Batch(batch *Batch) error { - return nil -} diff --git a/state/txindex/indexer.go b/state/txindex/indexer.go new file mode 100644 index 000000000..a962eba7d --- /dev/null +++ b/state/txindex/indexer.go @@ -0,0 +1,60 @@ +package txindex + +import ( + "errors" + + "github.com/tendermint/tendermint/types" +) + +// Indexer interface defines methods to index and search transactions. +type TxIndexer interface { + + // Batch analyzes, indexes or stores a batch of transactions. + // + // NOTE We do not specify Index method for analyzing a single transaction + // here because it bears heavy perfomance loses. Almost all advanced indexers + // support batching. + AddBatch(b *Batch) error + + // Tx returns specified transaction or nil if the transaction is not indexed + // or stored. + Get(hash []byte) (*types.TxResult, error) +} + +//---------------------------------------------------- +// Txs are written as a batch + +// A Batch groups together multiple Index operations you would like performed +// at the same time. The Batch structure is NOT thread-safe. You should only +// perform operations on a batch from a single thread at a time. Once batch +// execution has started, you may not modify it. +type Batch struct { + Ops map[string]types.TxResult +} + +// NewBatch creates a new Batch. +func NewBatch() *Batch { + return &Batch{ + Ops: make(map[string]types.TxResult), + } +} + +// Index adds or updates entry for the given hash. +func (b *Batch) Index(hash []byte, result types.TxResult) error { + if len(hash) == 0 { + return ErrorEmptyHash + } + b.Ops[string(hash)] = result + return nil +} + +// Size returns the total number of operations inside the batch. +func (b *Batch) Size() int { + return len(b.Ops) +} + +//---------------------------------------------------- +// Errors + +// ErrorEmptyHash indicates empty hash +var ErrorEmptyHash = errors.New("Transaction hash cannot be empty") diff --git a/state/tx/indexer/kv.go b/state/txindex/kv/kv.go similarity index 52% rename from state/tx/indexer/kv.go rename to state/txindex/kv/kv.go index 4f6fb3581..b76e6a3b0 100644 --- a/state/tx/indexer/kv.go +++ b/state/txindex/kv/kv.go @@ -1,4 +1,4 @@ -package indexer +package kv import ( "bytes" @@ -6,28 +6,29 @@ import ( db "github.com/tendermint/go-db" "github.com/tendermint/go-wire" + "github.com/tendermint/tendermint/state/txindex" "github.com/tendermint/tendermint/types" ) -// KV is a simplest possible indexer, backed by Key-Value storage (levelDB). +// TxIndex is the simplest possible indexer, backed by Key-Value storage (levelDB). // It could only index transaction by its identifier. -type KV struct { +type TxIndex struct { store db.DB } -// NewKV returns new instance of KV indexer. -func NewKV(store db.DB) *KV { - return &KV{store: store} +// NewTxIndex returns new instance of TxIndex. +func NewTxIndex(store db.DB) *TxIndex { + return &TxIndex{store: store} } -// Tx gets transaction from the KV storage and returns it or nil if the +// Get gets transaction from the TxIndex storage and returns it or nil if the // transaction is not found. -func (indexer *KV) Tx(hash []byte) (*types.TxResult, error) { +func (txi *TxIndex) Get(hash []byte) (*types.TxResult, error) { if len(hash) == 0 { - return nil, ErrorEmptyHash + return nil, txindex.ErrorEmptyHash } - rawBytes := indexer.store.Get(hash) + rawBytes := txi.store.Get(hash) if rawBytes == nil { return nil, nil } @@ -43,9 +44,9 @@ func (indexer *KV) Tx(hash []byte) (*types.TxResult, error) { return txResult, nil } -// Batch writes a batch of transactions into the KV storage. -func (indexer *KV) Batch(b *Batch) error { - storeBatch := indexer.store.NewBatch() +// Batch writes a batch of transactions into the TxIndex storage. +func (txi *TxIndex) AddBatch(b *txindex.Batch) error { + storeBatch := txi.store.NewBatch() for hash, result := range b.Ops { rawBytes := wire.BinaryBytes(&result) storeBatch.Set([]byte(hash), rawBytes) diff --git a/state/tx/indexer/kv_test.go b/state/txindex/kv/kv_test.go similarity index 57% rename from state/tx/indexer/kv_test.go rename to state/txindex/kv/kv_test.go index c797151af..022e227e3 100644 --- a/state/tx/indexer/kv_test.go +++ b/state/txindex/kv/kv_test.go @@ -1,4 +1,4 @@ -package indexer +package kv import ( "fmt" @@ -10,27 +10,28 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/abci/types" db "github.com/tendermint/go-db" + "github.com/tendermint/tendermint/state/txindex" "github.com/tendermint/tendermint/types" ) -func TestKVIndex(t *testing.T) { - indexer := &KV{store: db.NewMemDB()} +func TestTxIndex(t *testing.T) { + indexer := &TxIndex{store: db.NewMemDB()} tx := types.Tx("HELLO WORLD") txResult := &types.TxResult{1, 1, abci.ResponseDeliverTx{Data: []byte{0}, Code: abci.CodeType_OK, Log: ""}} hash := tx.Hash() - batch := NewBatch() + batch := txindex.NewBatch() batch.Index(hash, *txResult) - err := indexer.Batch(batch) + err := indexer.AddBatch(batch) require.Nil(t, err) - loadedTxResult, err := indexer.Tx(hash) + loadedTxResult, err := indexer.Get(hash) require.Nil(t, err) assert.Equal(t, txResult, loadedTxResult) } -func benchmarkKVIndex(txsCount int, b *testing.B) { +func benchmarkTxIndex(txsCount int, b *testing.B) { txResult := &types.TxResult{1, 1, abci.ResponseDeliverTx{Data: []byte{0}, Code: abci.CodeType_OK, Log: ""}} dir, err := ioutil.TempDir("", "tx_indexer_db") @@ -40,9 +41,9 @@ func benchmarkKVIndex(txsCount int, b *testing.B) { defer os.RemoveAll(dir) store := db.NewDB("tx_indexer", "leveldb", dir) - indexer := &KV{store: store} + indexer := &TxIndex{store: store} - batch := NewBatch() + batch := txindex.NewBatch() for i := 0; i < txsCount; i++ { batch.Index([]byte(fmt.Sprintf("hash%v", i)), *txResult) } @@ -50,12 +51,12 @@ func benchmarkKVIndex(txsCount int, b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { - err = indexer.Batch(batch) + err = indexer.AddBatch(batch) } } -func BenchmarkKVIndex1(b *testing.B) { benchmarkKVIndex(1, b) } -func BenchmarkKVIndex500(b *testing.B) { benchmarkKVIndex(500, b) } -func BenchmarkKVIndex1000(b *testing.B) { benchmarkKVIndex(1000, b) } -func BenchmarkKVIndex2000(b *testing.B) { benchmarkKVIndex(2000, b) } -func BenchmarkKVIndex10000(b *testing.B) { benchmarkKVIndex(10000, b) } +func BenchmarkTxIndex1(b *testing.B) { benchmarkTxIndex(1, b) } +func BenchmarkTxIndex500(b *testing.B) { benchmarkTxIndex(500, b) } +func BenchmarkTxIndex1000(b *testing.B) { benchmarkTxIndex(1000, b) } +func BenchmarkTxIndex2000(b *testing.B) { benchmarkTxIndex(2000, b) } +func BenchmarkTxIndex10000(b *testing.B) { benchmarkTxIndex(10000, b) } diff --git a/state/txindex/null/null.go b/state/txindex/null/null.go new file mode 100644 index 000000000..e48e34cf5 --- /dev/null +++ b/state/txindex/null/null.go @@ -0,0 +1,21 @@ +package null + +import ( + "errors" + + "github.com/tendermint/tendermint/state/txindex" + "github.com/tendermint/tendermint/types" +) + +// TxIndex acts as a /dev/null. +type TxIndex struct{} + +// Tx panics. +func (txi *TxIndex) Get(hash []byte) (*types.TxResult, error) { + return nil, errors.New(`Indexing is disabled (set 'tx_indexer = "kv"' in config)`) +} + +// Batch returns nil. +func (txi *TxIndex) AddBatch(batch *txindex.Batch) error { + return nil +}