mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
swarm/shed: remove MockIndex
This commit is contained in:
parent
3685c959e0
commit
181cb23968
5 changed files with 23 additions and 286 deletions
|
|
@ -24,14 +24,10 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/swarm/shed"
|
"github.com/ethereum/go-ethereum/swarm/shed"
|
||||||
"github.com/ethereum/go-ethereum/swarm/storage"
|
"github.com/ethereum/go-ethereum/swarm/storage"
|
||||||
"github.com/ethereum/go-ethereum/swarm/storage/mock"
|
|
||||||
"github.com/ethereum/go-ethereum/swarm/storage/mock/mem"
|
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -47,7 +43,7 @@ type Store struct {
|
||||||
schemaName shed.StringField
|
schemaName shed.StringField
|
||||||
sizeCounter shed.Uint64Field
|
sizeCounter shed.Uint64Field
|
||||||
accessCounter shed.Uint64Field
|
accessCounter shed.Uint64Field
|
||||||
retrievalIndex shed.IndexInterface // example of swapable Index/MockIndex
|
retrievalIndex shed.Index
|
||||||
accessIndex shed.Index
|
accessIndex shed.Index
|
||||||
gcIndex shed.Index
|
gcIndex shed.Index
|
||||||
}
|
}
|
||||||
|
|
@ -55,7 +51,7 @@ type Store struct {
|
||||||
// New returns new Store. All fields and indexes are initialized
|
// New returns new Store. All fields and indexes are initialized
|
||||||
// and possible conflicts with schema from existing database is checked
|
// and possible conflicts with schema from existing database is checked
|
||||||
// automatically.
|
// automatically.
|
||||||
func New(path string, mockStore *mock.NodeStore) (s *Store, err error) {
|
func New(path string) (s *Store, err error) {
|
||||||
db, err := shed.NewDB(path)
|
db, err := shed.NewDB(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -74,7 +70,7 @@ func New(path string, mockStore *mock.NodeStore) (s *Store, err error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Index storing actual chunk address, data and store timestamp.
|
// Index storing actual chunk address, data and store timestamp.
|
||||||
retrievalIndex, err := db.NewIndex("Address->StoreTimestamp|Data", shed.IndexFuncs{
|
s.retrievalIndex, err = db.NewIndex("Address->StoreTimestamp|Data", shed.IndexFuncs{
|
||||||
EncodeKey: func(fields shed.IndexItem) (key []byte, err error) {
|
EncodeKey: func(fields shed.IndexItem) (key []byte, err error) {
|
||||||
return fields.Address, nil
|
return fields.Address, nil
|
||||||
},
|
},
|
||||||
|
|
@ -97,11 +93,6 @@ func New(path string, mockStore *mock.NodeStore) (s *Store, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
s.retrievalIndex = retrievalIndex
|
|
||||||
if mockStore != nil {
|
|
||||||
// If mock store is provided, use it for retrieval index.
|
|
||||||
s.retrievalIndex = retrievalIndex.NewMockIndex(mockStore)
|
|
||||||
}
|
|
||||||
// Index storing access timestamp for a particular address.
|
// Index storing access timestamp for a particular address.
|
||||||
// It is needed in order to update gc index keys for iteration order.
|
// It is needed in order to update gc index keys for iteration order.
|
||||||
s.accessIndex, err = db.NewIndex("Address->AccessTimestamp", shed.IndexFuncs{
|
s.accessIndex, err = db.NewIndex("Address->AccessTimestamp", shed.IndexFuncs{
|
||||||
|
|
@ -318,20 +309,7 @@ func Example_store() {
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
var mockStore *mock.NodeStore
|
s, err := New(dir)
|
||||||
// Configuring mock store using environment variable is
|
|
||||||
// just an example, it can be accomplished in more elegant ways.
|
|
||||||
if strings.EqualFold(os.Getenv("SWARM_USE_MOCKSTORE"), "true") {
|
|
||||||
// Global store is constructed here for example purposes.
|
|
||||||
// It should be available globally so that all nodes can access it.
|
|
||||||
globalStore := mem.NewGlobalStore()
|
|
||||||
// An arbitrary address is used for this example.
|
|
||||||
// In real situations this address should be the same as the Swarm
|
|
||||||
// node address.
|
|
||||||
mockStore = globalStore.NewNodeStore(common.HexToAddress("12345678"))
|
|
||||||
}
|
|
||||||
|
|
||||||
s, err := New(dir, mockStore)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package shed
|
package shed
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ethereum/go-ethereum/swarm/storage/mock"
|
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -94,10 +93,25 @@ func (db *DB) NewIndex(name string, funcs IndexFuncs) (f Index, err error) {
|
||||||
}
|
}
|
||||||
prefix := []byte{id}
|
prefix := []byte{id}
|
||||||
return Index{
|
return Index{
|
||||||
db: db,
|
db: db,
|
||||||
prefix: prefix,
|
prefix: prefix,
|
||||||
encodeKeyFunc: newIndexEncodeKeyFunc(funcs.EncodeKey, id),
|
// This function adjusts Index LevelDB key
|
||||||
decodeKeyFunc: newDecodeKeyFunc(funcs.DecodeKey),
|
// by appending the provided index id byte.
|
||||||
|
// This is needed to avoid collisions between keys of different
|
||||||
|
// indexes as all index ids are unique.
|
||||||
|
encodeKeyFunc: func(e IndexItem) (key []byte, err error) {
|
||||||
|
key, err = funcs.EncodeKey(e)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return append(append(make([]byte, 0, len(key)+1), prefix...), key...), nil
|
||||||
|
},
|
||||||
|
// This function reverses the encodeKeyFunc constructed key
|
||||||
|
// to transparently work with index keys without their index ids.
|
||||||
|
// It assumes that index keys are prefixed with only one byte.
|
||||||
|
decodeKeyFunc: func(key []byte) (e IndexItem, err error) {
|
||||||
|
return funcs.DecodeKey(key[1:])
|
||||||
|
},
|
||||||
encodeValueFunc: funcs.EncodeValue,
|
encodeValueFunc: funcs.EncodeValue,
|
||||||
decodeValueFunc: funcs.DecodeValue,
|
decodeValueFunc: funcs.DecodeValue,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
@ -242,68 +256,3 @@ func (f Index) IterateFrom(start IndexItem, fn IndexIterFunc) (err error) {
|
||||||
}
|
}
|
||||||
return it.Error()
|
return it.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMockIndex is a helper function to easily construct MockIndex
|
|
||||||
// when from the same definition of Index.
|
|
||||||
func (f Index) NewMockIndex(store *mock.NodeStore) (m MockIndex) {
|
|
||||||
return MockIndex{
|
|
||||||
store: store,
|
|
||||||
prefix: f.prefix,
|
|
||||||
encodeKeyFunc: f.encodeKeyFunc,
|
|
||||||
decodeKeyFunc: f.decodeKeyFunc,
|
|
||||||
encodeValueFunc: f.encodeValueFunc,
|
|
||||||
decodeValueFunc: f.decodeValueFunc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IndexInterface defines methods that are required for a simple index
|
|
||||||
// that does not use iterations.
|
|
||||||
// It can be used when Index should be swapped with MockIndex or any other
|
|
||||||
// IndexInterface implementation.
|
|
||||||
// In most cases, interface is not needed and it is recommended to use the
|
|
||||||
// Index implementation whenever possible.
|
|
||||||
type IndexInterface interface {
|
|
||||||
Get(keyFields IndexItem) (out IndexItem, err error)
|
|
||||||
Put(i IndexItem) (err error)
|
|
||||||
PutInBatch(batch *leveldb.Batch, i IndexItem) (err error)
|
|
||||||
Delete(keyFields IndexItem) (err error)
|
|
||||||
DeleteInBatch(batch *leveldb.Batch, keyFields IndexItem) (err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IndexIteratorInterface defines metods for a full index implementation with
|
|
||||||
// iterators. Index type implements this type.
|
|
||||||
// In most cases, interface is not needed and it is recommended to use the
|
|
||||||
// Index implementation whenever possible.
|
|
||||||
type IndexIteratorInterface interface {
|
|
||||||
IndexInterface
|
|
||||||
IterateAll(fn IndexIterFunc) (err error)
|
|
||||||
IterateFrom(start IndexItem, fn IndexIterFunc) (err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// newIndexEncodeKeyFunc adjusts Index and MockIndex LevelDB key
|
|
||||||
// by appending the provided index id byte.
|
|
||||||
// This is needed to avoid collisions between keys of different
|
|
||||||
// indexes as all index ids are unique.
|
|
||||||
func newIndexEncodeKeyFunc(
|
|
||||||
encodeKeyFunc func(fields IndexItem) (key []byte, err error),
|
|
||||||
id byte,
|
|
||||||
) (f func(e IndexItem) (key []byte, err error)) {
|
|
||||||
prefix := []byte{id}
|
|
||||||
return func(e IndexItem) (key []byte, err error) {
|
|
||||||
key, err = encodeKeyFunc(e)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return append(append(make([]byte, 0, len(key)+1), prefix...), key...), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// newDecodeKeyFunc reverses the newIndexEncodeKeyFunc constructd key
|
|
||||||
// to transparently work with index keys without their index ids.
|
|
||||||
// This function is used in NewIndex and NewMockIndex constructors.
|
|
||||||
// It assumes that index keys are prefixed with only one byte.
|
|
||||||
func newDecodeKeyFunc(decodeKeyFunc func(key []byte) (e IndexItem, err error)) (f func(key []byte) (e IndexItem, err error)) {
|
|
||||||
return func(key []byte) (e IndexItem, err error) {
|
|
||||||
return decodeKeyFunc(key[1:])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,113 +0,0 @@
|
||||||
// Copyright 2018 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package shed
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/ethereum/go-ethereum/swarm/storage/mock"
|
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MockIndex provides a way to inject a mock.NodeStore to store
|
|
||||||
// data centrally instead on provided DB. DB is used just for schema
|
|
||||||
// validation and identifying byte prefix for the particular index
|
|
||||||
// that is mocked.
|
|
||||||
// Iterator functions are not implemented and MockIndex can not replace
|
|
||||||
// indexes that rely on them.
|
|
||||||
// It implements IndexField interface.
|
|
||||||
type MockIndex struct {
|
|
||||||
store *mock.NodeStore
|
|
||||||
prefix []byte
|
|
||||||
encodeKeyFunc func(fields IndexItem) (key []byte, err error)
|
|
||||||
decodeKeyFunc func(key []byte) (e IndexItem, err error)
|
|
||||||
encodeValueFunc func(fields IndexItem) (value []byte, err error)
|
|
||||||
decodeValueFunc func(value []byte) (e IndexItem, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMockIndex returns a new MockIndex instance with defined name and
|
|
||||||
// encoding functions. The name must be unique and will be validated
|
|
||||||
// on database schema for a key prefix byte.
|
|
||||||
// The data will not be saved on the DB itself, but using a provided
|
|
||||||
// mock.NodeStore.
|
|
||||||
func (db *DB) NewMockIndex(store *mock.NodeStore, name string, funcs IndexFuncs) (f MockIndex, err error) {
|
|
||||||
id, err := db.schemaIndexPrefix(name)
|
|
||||||
if err != nil {
|
|
||||||
return f, err
|
|
||||||
}
|
|
||||||
return MockIndex{
|
|
||||||
store: store,
|
|
||||||
prefix: []byte{id},
|
|
||||||
encodeKeyFunc: newIndexEncodeKeyFunc(funcs.EncodeKey, id),
|
|
||||||
decodeKeyFunc: newDecodeKeyFunc(funcs.DecodeKey),
|
|
||||||
encodeValueFunc: funcs.EncodeValue,
|
|
||||||
decodeValueFunc: funcs.DecodeValue,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get accepts key fields represented as IndexItem to retrieve a
|
|
||||||
// value from the index and return maximum available information
|
|
||||||
// from the index represented as another IndexItem.
|
|
||||||
func (f MockIndex) Get(keyFields IndexItem) (out IndexItem, err error) {
|
|
||||||
key, err := f.encodeKeyFunc(keyFields)
|
|
||||||
if err != nil {
|
|
||||||
return out, err
|
|
||||||
}
|
|
||||||
value, err := f.store.Get(key)
|
|
||||||
if err != nil {
|
|
||||||
return out, err
|
|
||||||
}
|
|
||||||
out, err = f.decodeValueFunc(value)
|
|
||||||
if err != nil {
|
|
||||||
return out, err
|
|
||||||
}
|
|
||||||
return out.Join(keyFields), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put accepts IndexItem to encode information from it
|
|
||||||
// and save it to the database.
|
|
||||||
func (f MockIndex) Put(i IndexItem) (err error) {
|
|
||||||
key, err := f.encodeKeyFunc(i)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
value, err := f.encodeValueFunc(i)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return f.store.Put(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PutInBatch is the same as Put method.
|
|
||||||
// Batch is ignored and the data is saved to the mock store instantly.
|
|
||||||
func (f MockIndex) PutInBatch(_ *leveldb.Batch, i IndexItem) (err error) {
|
|
||||||
return f.Put(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete accepts IndexItem to remove a key/value pair
|
|
||||||
// form the database based on its fields.
|
|
||||||
func (f MockIndex) Delete(keyFields IndexItem) (err error) {
|
|
||||||
key, err := f.encodeKeyFunc(keyFields)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return f.store.Delete(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteInBatch is the same as Delete just the operation.
|
|
||||||
// Batch is ignored and the data is deleted on the mock store instantly.
|
|
||||||
func (f MockIndex) DeleteInBatch(_ *leveldb.Batch, keyFields IndexItem) (err error) {
|
|
||||||
return f.Delete(keyFields)
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
// Copyright 2018 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package shed
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/swarm/storage/mock/mem"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TestMockIndex validates put, get and delete functions of
|
|
||||||
// the MockIndex implementation.
|
|
||||||
func TestMockIndex(t *testing.T) {
|
|
||||||
db, cleanupFunc := newTestDB(t)
|
|
||||||
defer cleanupFunc()
|
|
||||||
|
|
||||||
globalStore := mem.NewGlobalStore()
|
|
||||||
|
|
||||||
index, err := db.NewMockIndex(
|
|
||||||
globalStore.NewNodeStore(common.HexToAddress("12345678")),
|
|
||||||
"retrieval",
|
|
||||||
retrievalIndexFuncs,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
testIndex(t, db, index)
|
|
||||||
}
|
|
||||||
|
|
@ -24,9 +24,6 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/swarm/storage/mock"
|
|
||||||
"github.com/ethereum/go-ethereum/swarm/storage/mock/mem"
|
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -62,29 +59,6 @@ func TestIndex(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
testIndex(t, db, index)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestIndex_NewMockIndex validates put, get and delete functions of
|
|
||||||
// the MockIndex implementation, when constructed with Index.NewMockIndex function.
|
|
||||||
func TestIndex_NewMockIndex(t *testing.T) {
|
|
||||||
db, cleanupFunc := newTestDB(t)
|
|
||||||
defer cleanupFunc()
|
|
||||||
|
|
||||||
index, err := db.NewIndex("retrieval", retrievalIndexFuncs)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
globalStore := mem.NewGlobalStore()
|
|
||||||
|
|
||||||
mockIndex := index.NewMockIndex(globalStore.NewNodeStore(common.HexToAddress("12345678")))
|
|
||||||
|
|
||||||
testIndex(t, db, mockIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
// testIndex validates put, get and delete functions of a index interface.
|
|
||||||
func testIndex(t *testing.T, db *DB, index IndexInterface) {
|
|
||||||
t.Run("put", func(t *testing.T) {
|
t.Run("put", func(t *testing.T) {
|
||||||
want := IndexItem{
|
want := IndexItem{
|
||||||
Address: []byte("put-hash"),
|
Address: []byte("put-hash"),
|
||||||
|
|
@ -196,9 +170,6 @@ func testIndex(t *testing.T, db *DB, index IndexInterface) {
|
||||||
}
|
}
|
||||||
|
|
||||||
wantErr := leveldb.ErrNotFound
|
wantErr := leveldb.ErrNotFound
|
||||||
if _, ok := index.(MockIndex); ok {
|
|
||||||
wantErr = mock.ErrNotFound
|
|
||||||
}
|
|
||||||
got, err = index.Get(IndexItem{
|
got, err = index.Get(IndexItem{
|
||||||
Address: want.Address,
|
Address: want.Address,
|
||||||
})
|
})
|
||||||
|
|
@ -236,9 +207,6 @@ func testIndex(t *testing.T, db *DB, index IndexInterface) {
|
||||||
}
|
}
|
||||||
|
|
||||||
wantErr := leveldb.ErrNotFound
|
wantErr := leveldb.ErrNotFound
|
||||||
if _, ok := index.(MockIndex); ok {
|
|
||||||
wantErr = mock.ErrNotFound
|
|
||||||
}
|
|
||||||
got, err = index.Get(IndexItem{
|
got, err = index.Get(IndexItem{
|
||||||
Address: want.Address,
|
Address: want.Address,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue