forked from TrueCloudLab/neoneo-go
storage: close function
add close function to storage interface add common defer function call which will close db connection remove context as soon as it's not needed anymore updated unit tests
This commit is contained in:
parent
b21a220712
commit
264dfef370
11 changed files with 42 additions and 27 deletions
|
@ -112,7 +112,7 @@ Main:
|
||||||
|
|
||||||
// initBlockChain initializes BlockChain with preselected DB.
|
// initBlockChain initializes BlockChain with preselected DB.
|
||||||
func initBlockChain(context context.Context, cfg config.Config) (*core.Blockchain, error) {
|
func initBlockChain(context context.Context, cfg config.Config) (*core.Blockchain, error) {
|
||||||
store, err := storage.NewStore(context, cfg.ApplicationConfiguration.DBConfiguration)
|
store, err := storage.NewStore(cfg.ApplicationConfiguration.DBConfiguration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, cli.NewExitError(fmt.Errorf("could not initialize storage: %s", err), 1)
|
return nil, cli.NewExitError(fmt.Errorf("could not initialize storage: %s", err), 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,12 @@ func (bc *Blockchain) init() error {
|
||||||
|
|
||||||
func (bc *Blockchain) run(ctx context.Context) {
|
func (bc *Blockchain) run(ctx context.Context) {
|
||||||
persistTimer := time.NewTimer(persistInterval)
|
persistTimer := time.NewTimer(persistInterval)
|
||||||
defer persistTimer.Stop()
|
defer func() {
|
||||||
|
persistTimer.Stop()
|
||||||
|
if err := bc.Store.Close(); err != nil {
|
||||||
|
log.Warnf("failed to close db: %s", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
|
|
@ -2,7 +2,6 @@ package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
@ -41,7 +40,7 @@ func (b *BoltDBBatch) Put(k, v []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBoltDBStore returns a new ready to use BoltDB storage with created bucket.
|
// NewBoltDBStore returns a new ready to use BoltDB storage with created bucket.
|
||||||
func NewBoltDBStore(ctx context.Context, cfg BoltDBOptions) (*BoltDBStore, error) {
|
func NewBoltDBStore(cfg BoltDBOptions) (*BoltDBStore, error) {
|
||||||
var opts *bbolt.Options // should be exposed via BoltDBOptions if anything needed
|
var opts *bbolt.Options // should be exposed via BoltDBOptions if anything needed
|
||||||
fileMode := os.FileMode(0600) // should be exposed via BoltDBOptions if anything needed
|
fileMode := os.FileMode(0600) // should be exposed via BoltDBOptions if anything needed
|
||||||
fileName := cfg.FilePath
|
fileName := cfg.FilePath
|
||||||
|
@ -62,12 +61,6 @@ func NewBoltDBStore(ctx context.Context, cfg BoltDBOptions) (*BoltDBStore, error
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
// graceful shutdown
|
|
||||||
go func() {
|
|
||||||
<-ctx.Done()
|
|
||||||
db.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
return &BoltDBStore{db: db}, nil
|
return &BoltDBStore{db: db}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -83,7 +82,7 @@ func openStore(t *testing.T) *BoltDBStore {
|
||||||
}()
|
}()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, file.Close())
|
require.NoError(t, file.Close())
|
||||||
boltDBStore, err := NewBoltDBStore(context.Background(), BoltDBOptions{FilePath: testFileName})
|
boltDBStore, err := NewBoltDBStore(BoltDBOptions{FilePath: testFileName})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
return boltDBStore
|
return boltDBStore
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
"github.com/syndtr/goleveldb/leveldb/opt"
|
"github.com/syndtr/goleveldb/leveldb/opt"
|
||||||
"github.com/syndtr/goleveldb/leveldb/util"
|
"github.com/syndtr/goleveldb/leveldb/util"
|
||||||
|
@ -22,7 +20,7 @@ type LevelDBStore struct {
|
||||||
|
|
||||||
// NewLevelDBStore return a new LevelDBStore object that will
|
// NewLevelDBStore return a new LevelDBStore object that will
|
||||||
// initialize the database found at the given path.
|
// initialize the database found at the given path.
|
||||||
func NewLevelDBStore(ctx context.Context, cfg LevelDBOptions) (*LevelDBStore, error) {
|
func NewLevelDBStore(cfg LevelDBOptions) (*LevelDBStore, error) {
|
||||||
var opts *opt.Options = nil // should be exposed via LevelDBOptions if anything needed
|
var opts *opt.Options = nil // should be exposed via LevelDBOptions if anything needed
|
||||||
|
|
||||||
db, err := leveldb.OpenFile(cfg.DataDirectoryPath, opts)
|
db, err := leveldb.OpenFile(cfg.DataDirectoryPath, opts)
|
||||||
|
@ -30,12 +28,6 @@ func NewLevelDBStore(ctx context.Context, cfg LevelDBOptions) (*LevelDBStore, er
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// graceful shutdown
|
|
||||||
go func() {
|
|
||||||
<-ctx.Done()
|
|
||||||
db.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
return &LevelDBStore{
|
return &LevelDBStore{
|
||||||
path: cfg.DataDirectoryPath,
|
path: cfg.DataDirectoryPath,
|
||||||
db: db,
|
db: db,
|
||||||
|
@ -72,3 +64,8 @@ func (s *LevelDBStore) Seek(key []byte, f func(k, v []byte)) {
|
||||||
func (s *LevelDBStore) Batch() Batch {
|
func (s *LevelDBStore) Batch() Batch {
|
||||||
return new(leveldb.Batch)
|
return new(leveldb.Batch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close implements the Store interface.
|
||||||
|
func (s *LevelDBStore) Close() error {
|
||||||
|
return s.db.Close()
|
||||||
|
}
|
||||||
|
|
|
@ -76,6 +76,14 @@ func (s *MemoryStore) Batch() Batch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close implements Store interface and clears up memory.
|
||||||
|
func (s *MemoryStore) Close() error {
|
||||||
|
s.Lock()
|
||||||
|
s.mem = nil
|
||||||
|
s.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func makeKey(k []byte) string {
|
func makeKey(k []byte) string {
|
||||||
return hex.EncodeToString(k)
|
return hex.EncodeToString(k)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetPut(t *testing.T) {
|
func TestGetPut(t *testing.T) {
|
||||||
|
@ -22,6 +23,7 @@ func TestGetPut(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
assert.Equal(t, value, newVal)
|
assert.Equal(t, value, newVal)
|
||||||
|
require.NoError(t, s.Close())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyNotExist(t *testing.T) {
|
func TestKeyNotExist(t *testing.T) {
|
||||||
|
@ -33,6 +35,7 @@ func TestKeyNotExist(t *testing.T) {
|
||||||
_, err := s.Get(key)
|
_, err := s.Get(key)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
assert.Equal(t, err.Error(), "key not found")
|
assert.Equal(t, err.Error(), "key not found")
|
||||||
|
require.NoError(t, s.Close())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPutBatch(t *testing.T) {
|
func TestPutBatch(t *testing.T) {
|
||||||
|
@ -54,4 +57,5 @@ func TestPutBatch(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
assert.Equal(t, value, newVal)
|
assert.Equal(t, value, newVal)
|
||||||
|
require.NoError(t, s.Close())
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,3 +92,8 @@ func (s *RedisStore) Seek(k []byte, f func(k, v []byte)) {
|
||||||
f([]byte(key), []byte(val))
|
f([]byte(key), []byte(val))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close implements the Store interface.
|
||||||
|
func (s *RedisStore) Close() error {
|
||||||
|
return s.client.Close()
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/alicebob/miniredis"
|
"github.com/alicebob/miniredis"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewRedisBatch(t *testing.T) {
|
func TestNewRedisBatch(t *testing.T) {
|
||||||
|
@ -26,6 +27,7 @@ func TestNewRedisStore(t *testing.T) {
|
||||||
assert.Nil(t, err, "NewRedisStore Get error")
|
assert.Nil(t, err, "NewRedisStore Get error")
|
||||||
|
|
||||||
assert.Equal(t, value, result)
|
assert.Equal(t, value, result)
|
||||||
|
require.NoError(t, redisStore.Close())
|
||||||
redisMock.Close()
|
redisMock.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,6 +125,7 @@ func TestRedisStore_GetAndPut(t *testing.T) {
|
||||||
redisMock.FlushDB()
|
redisMock.FlushDB()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
require.NoError(t, redisStore.Close())
|
||||||
redisMock.Close()
|
redisMock.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +137,7 @@ func TestRedisStore_PutBatch(t *testing.T) {
|
||||||
result, err := redisStore.Get([]byte("foo1"))
|
result, err := redisStore.Get([]byte("foo1"))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, []byte("bar1"), result)
|
assert.Equal(t, []byte("bar1"), result)
|
||||||
|
require.NoError(t, redisStore.Close())
|
||||||
mock.Close()
|
mock.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,6 +146,7 @@ func TestRedisStore_Seek(t *testing.T) {
|
||||||
redisStore.Seek([]byte("foo"), func(k, v []byte) {
|
redisStore.Seek([]byte("foo"), func(k, v []byte) {
|
||||||
assert.Equal(t, []byte("bar"), v)
|
assert.Equal(t, []byte("bar"), v)
|
||||||
})
|
})
|
||||||
|
require.NoError(t, redisStore.Close())
|
||||||
mock.Close()
|
mock.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
|
@ -37,6 +36,7 @@ type (
|
||||||
Put(k, v []byte) error
|
Put(k, v []byte) error
|
||||||
PutBatch(Batch) error
|
PutBatch(Batch) error
|
||||||
Seek(k []byte, f func(k, v []byte))
|
Seek(k []byte, f func(k, v []byte))
|
||||||
|
Close() error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Batch represents an abstraction on top of batch operations.
|
// Batch represents an abstraction on top of batch operations.
|
||||||
|
@ -75,18 +75,18 @@ func AppendPrefixInt(k KeyPrefix, n int) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStore creates storage with preselected in configuration database type.
|
// NewStore creates storage with preselected in configuration database type.
|
||||||
func NewStore(context context.Context, cfg DBConfiguration) (Store, error) {
|
func NewStore(cfg DBConfiguration) (Store, error) {
|
||||||
var store Store
|
var store Store
|
||||||
var err error
|
var err error
|
||||||
switch cfg.Type {
|
switch cfg.Type {
|
||||||
case "leveldb":
|
case "leveldb":
|
||||||
store, err = NewLevelDBStore(context, cfg.LevelDBOptions)
|
store, err = NewLevelDBStore(cfg.LevelDBOptions)
|
||||||
case "inmemory":
|
case "inmemory":
|
||||||
store = NewMemoryStore()
|
store = NewMemoryStore()
|
||||||
case "redis":
|
case "redis":
|
||||||
store, err = NewRedisStore(cfg.RedisDBOptions)
|
store, err = NewRedisStore(cfg.RedisDBOptions)
|
||||||
case "boltdb":
|
case "boltdb":
|
||||||
store, err = NewBoltDBStore(context, cfg.BoltDBOptions)
|
store, err = NewBoltDBStore(cfg.BoltDBOptions)
|
||||||
}
|
}
|
||||||
return store, err
|
return store, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,8 +246,7 @@ func TestHandler(t *testing.T) {
|
||||||
cfg, err := config.Load(configPath, net)
|
cfg, err := config.Load(configPath, net)
|
||||||
require.NoError(t, err, "could not load config")
|
require.NoError(t, err, "could not load config")
|
||||||
|
|
||||||
store, err := storage.NewLevelDBStore(context.Background(),
|
store, err := storage.NewLevelDBStore(cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions)
|
||||||
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions)
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
chain, err := core.NewBlockchain(context.Background(), store, cfg.ProtocolConfiguration)
|
chain, err := core.NewBlockchain(context.Background(), store, cfg.ProtocolConfiguration)
|
||||||
require.NoError(t, err, "could not create levelDB chain")
|
require.NoError(t, err, "could not create levelDB chain")
|
||||||
|
|
Loading…
Reference in a new issue