Commit db64ffcb authored by liuyuhang's avatar liuyuhang

add kvmvccMavl function

parent ed0f98f0
......@@ -147,6 +147,13 @@ enableMVCC=false
enableMavlPrune=false
pruneHeight=10000
[store.sub.kvmvccMavl]
enableMVCCIter=false
enableMavlPrefix=false
enableMVCC=false
enableMavlPrune=false
pruneHeight=10000
[wallet]
minFee=100000
driver="leveldb"
......
......@@ -4,4 +4,5 @@ import (
_ "github.com/33cn/plugin/plugin/store/kvdb" //auto gen
_ "github.com/33cn/plugin/plugin/store/kvmvcc" //auto gen
_ "github.com/33cn/plugin/plugin/store/mpt" //auto gen
_ "github.com/33cn/plugin/plugin/store/kvmvccMavl" //auto gen
)
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package kvmvccMavl
import (
clog "github.com/33cn/chain33/common/log"
log "github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/queue"
drivers "github.com/33cn/chain33/system/store"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/system/store/mavl"
"github.com/33cn/plugin/plugin/store/kvmvcc"
"github.com/hashicorp/golang-lru"
"encoding/json"
"errors"
)
var (
kmlog = log.New("module", "kvmvccMavl")
ErrStateHashLost = errors.New("ErrStateHashLost")
kvmvccMavlFork int64 = 200 * 10000
)
// SetLogLevel set log level
func SetLogLevel(level string) {
clog.SetLogLevel(level)
}
// DisableLog disable log output
func DisableLog() {
kmlog.SetHandler(log.DiscardHandler())
}
func init() {
drivers.Reg("kvmvccMavl", New)
}
// KVMVCCMavlStore provide kvmvcc and mavl store interface implementation
type KVMVCCMavlStore struct {
*drivers.BaseStore
*kvmvccdb.KVMVCCStore
*mavl.Store
cance *lru.Cache
}
type subKVMVCCConfig struct {
EnableMVCCIter bool `json:"enableMVCCIter"`
}
type subMavlConfig struct {
EnableMavlPrefix bool `json:"enableMavlPrefix"`
EnableMVCC bool `json:"enableMVCC"`
EnableMavlPrune bool `json:"enableMavlPrune"`
PruneHeight int32 `json:"pruneHeight"`
}
type subConfig struct {
EnableMVCCIter bool `json:"enableMVCCIter"`
EnableMavlPrefix bool `json:"enableMavlPrefix"`
EnableMVCC bool `json:"enableMVCC"`
EnableMavlPrune bool `json:"enableMavlPrune"`
PruneHeight int32 `json:"pruneHeight"`
}
// New construct KVMVCCStore module
func New(cfg *types.Store, sub []byte) queue.Module {
bs := drivers.NewBaseStore(cfg)
var kvms *KVMVCCMavlStore
var subcfg subConfig
var subKVMVCCcfg subKVMVCCConfig
var subMavlcfg subMavlConfig
if sub != nil {
types.MustDecode(sub, &subcfg)
subKVMVCCcfg.EnableMVCCIter = subcfg.EnableMVCCIter
subMavlcfg.EnableMavlPrefix = subcfg.EnableMavlPrefix
subMavlcfg.EnableMVCC = subcfg.EnableMVCC
subMavlcfg.EnableMavlPrune = subcfg.EnableMavlPrune
subMavlcfg.PruneHeight = subcfg.PruneHeight
}
mvcVal, _ := json.Marshal(&subKVMVCCcfg)
mavlVal, _ := json.Marshal(&subMavlcfg)
cance, err := lru.New(1024)
if err != nil {
panic("new KVMVCCMavlStore fail")
}
mvccCfg := &types.Store{}
mvccCfg.Name = "kvmvcc"
mvccCfg.Driver = cfg.Driver
mvccCfg.DbPath = cfg.DbPath + "/kvmvcc"
mvccCfg.DbCache = cfg.DbCache
mvccCfg.LocalDBVersion = cfg.LocalDBVersion
mavlCfg := &types.Store{}
mavlCfg.Name = "mavl"
mavlCfg.Driver = cfg.Driver
mavlCfg.DbPath = cfg.DbPath + "/mavl"
mavlCfg.DbCache = cfg.DbCache
mavlCfg.LocalDBVersion = cfg.LocalDBVersion
kvms = &KVMVCCMavlStore{bs, kvmvccdb.New(mvccCfg, mvcVal).(*kvmvccdb.KVMVCCStore),
mavl.New(mavlCfg, mavlVal).(*mavl.Store), cance}
bs.SetChild(kvms)
return kvms
}
// Close the KVMVCCStore module
func (kvmMavls *KVMVCCMavlStore) Close() {
kvmMavls.BaseStore.Close()
kvmMavls.KVMVCCStore.Close()
kvmMavls.Store.Close()
kmlog.Info("store kvdb closed")
}
// Set kvs with statehash to KVMVCCStore
func (kvmMavls *KVMVCCMavlStore) Set(datas *types.StoreSet, sync bool) ([]byte, error) {
// 这里后续需要考虑分叉回退
if datas.Height < kvmvccMavlFork {
hash, err := kvmMavls.Store.Set(datas, sync)
if err != nil {
return hash, err
}
_, err = kvmMavls.KVMVCCStore.Set(datas, sync)
if err != nil {
return hash, err
}
if err == nil {
kvmMavls.cance.Add(string(hash), datas.Height)
}
return hash, err
}
// 仅仅做kvmvcc
hash, err := kvmMavls.KVMVCCStore.Set(datas, sync)
if err == nil {
kvmMavls.cance.Add(string(hash), datas.Height)
}
return hash, err
}
// Get kvs with statehash from KVMVCCStore
func (kvmMavls *KVMVCCMavlStore) Get(datas *types.StoreGet) [][]byte {
if value, ok := kvmMavls.cance.Get(string(datas.StateHash)); ok {
if value.(int64) < kvmvccMavlFork {
return kvmMavls.Store.Get(datas)
}
return kvmMavls.KVMVCCStore.Get(datas)
}
return kvmMavls.KVMVCCStore.Get(datas)
}
// MemSet set kvs to the mem of KVMVCCStore module and return the StateHash
func (kvmMavls *KVMVCCMavlStore) MemSet(datas *types.StoreSet, sync bool) ([]byte, error) {
// 这里后续需要考虑分叉回退
if datas.Height < kvmvccMavlFork {
hash, err := kvmMavls.Store.MemSet(datas, sync)
if err != nil {
return hash, err
}
_, err = kvmMavls.KVMVCCStore.MemSet(datas, sync)
if err != nil {
return hash, err
}
if err == nil {
kvmMavls.cance.Add(string(hash), datas.Height)
}
return hash, err
}
// 仅仅做kvmvcc
hash, err := kvmMavls.KVMVCCStore.MemSet(datas, sync)
if err == nil {
kvmMavls.cance.Add(string(hash), datas.Height)
}
return hash, err
}
// Commit kvs in the mem of KVMVCCStore module to state db and return the StateHash
func (kvmMavls *KVMVCCMavlStore) Commit(req *types.ReqHash) ([]byte, error) {
if value, ok := kvmMavls.cance.Get(string(req.Hash)); ok {
if value.(int64) < kvmvccMavlFork {
hash, err := kvmMavls.Store.Commit(req)
if err != nil {
return hash, err
}
_, err = kvmMavls.KVMVCCStore.Commit(req)
if err != nil {
return hash, err
}
return hash, err
}
return kvmMavls.KVMVCCStore.Commit(req)
}
return kvmMavls.KVMVCCStore.Commit(req)
}
// Rollback kvs in the mem of KVMVCCStore module and return the StateHash
func (kvmMavls *KVMVCCMavlStore) Rollback(req *types.ReqHash) ([]byte, error) {
if value, ok := kvmMavls.cance.Get(string(req.Hash)); ok {
if value.(int64) < kvmvccMavlFork {
hash, err := kvmMavls.Store.Rollback(req)
if err != nil {
return hash, err
}
_, err = kvmMavls.KVMVCCStore.Rollback(req)
if err != nil {
return hash, err
}
return hash, err
}
return kvmMavls.KVMVCCStore.Rollback(req)
}
return kvmMavls.KVMVCCStore.Rollback(req)
}
// IterateRangeByStateHash travel with Prefix by StateHash to get the latest version kvs.
func (kvmMavls *KVMVCCMavlStore) IterateRangeByStateHash(statehash []byte, start []byte, end []byte, ascending bool, fn func(key, value []byte) bool) {
if value, ok := kvmMavls.cance.Get(string(statehash)); ok {
if value.(int64) < kvmvccMavlFork {
kvmMavls.Store.IterateRangeByStateHash(statehash, start, end, ascending, fn)
}
kvmMavls.KVMVCCStore.IterateRangeByStateHash(statehash, start, end, ascending, fn)
}
kvmMavls.KVMVCCStore.IterateRangeByStateHash(statehash, start, end, ascending, fn)
}
// ProcEvent handles supported events
func (kvmMavls *KVMVCCMavlStore) ProcEvent(msg queue.Message) {
msg.ReplyErr("KVMVCCMavlStore", types.ErrActionNotSupport)
}
// Del set kvs to nil with StateHash
func (kvmMavls *KVMVCCMavlStore) Del(req *types.StoreDel) ([]byte, error) {
// 这里后续需要考虑分叉回退
if req.Height < kvmvccMavlFork {
hash, err := kvmMavls.Store.Del(req)
if err != nil {
return hash, err
}
_, err = kvmMavls.KVMVCCStore.Del(req)
if err != nil {
return hash, err
}
if err == nil {
kvmMavls.cance.Remove(string(req.StateHash))
}
return hash, err
}
// 仅仅做kvmvcc
hash, err := kvmMavls.KVMVCCStore.Del(req)
if err == nil {
kvmMavls.cance.Remove(string(req.StateHash))
}
return hash, err
}
\ No newline at end of file
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package kvmvccMavl
import (
"encoding/json"
"io/ioutil"
"os"
"testing"
"time"
"fmt"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/common"
drivers "github.com/33cn/chain33/system/store"
"github.com/33cn/chain33/types"
"github.com/stretchr/testify/assert"
)
const MaxKeylenth int = 64
func newStoreCfg(dir string) *types.Store {
return &types.Store{Name: "kvmvccMavl_test", Driver: "leveldb", DbPath: dir, DbCache: 100}
}
func newStoreCfgIter(dir string) (*types.Store, []byte) {
return &types.Store{Name: "kvmvccMavl_test", Driver: "leveldb", DbPath: dir, DbCache: 100}, enableConfig()
}
func TestKvmvccdbNewClose(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCMavlStore)
assert.NotNil(t, store)
store.Close()
}
func TestKvmvccdbSetGet(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCMavlStore)
assert.NotNil(t, store)
keys0 := [][]byte{[]byte("mk1"), []byte("mk2")}
get0 := &types.StoreGet{StateHash: drivers.EmptyRoot[:], Keys: keys0}
values0 := store.Get(get0)
//kmlog.Info("info", "info", values0)
// Get exist key, result nil
assert.Len(t, values0, 2)
assert.Equal(t, []byte(nil), values0[0])
assert.Equal(t, []byte(nil), values0[1])
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: []byte("k1"), Value: []byte("v1")})
kv = append(kv, &types.KeyValue{Key: []byte("k2"), Value: []byte("v2")})
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
hash, err := store.Set(datas, true)
assert.Nil(t, err)
keys := [][]byte{[]byte("k1"), []byte("k2")}
get1 := &types.StoreGet{StateHash: hash, Keys: keys}
values := store.Get(get1)
assert.Len(t, values, 2)
assert.Equal(t, []byte("v1"), values[0])
assert.Equal(t, []byte("v2"), values[1])
keys = [][]byte{[]byte("k1")}
get2 := &types.StoreGet{StateHash: hash, Keys: keys}
values2 := store.Get(get2)
assert.Len(t, values2, 1)
assert.Equal(t, []byte("v1"), values2[0])
get3 := &types.StoreGet{StateHash: drivers.EmptyRoot[:], Keys: keys}
values3 := store.Get(get3)
assert.Len(t, values3, 1)
}
func TestKvmvccdbMemSet(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCMavlStore)
assert.NotNil(t, store)
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: []byte("mk1"), Value: []byte("v1")})
kv = append(kv, &types.KeyValue{Key: []byte("mk2"), Value: []byte("v2")})
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
hash, err := store.MemSet(datas, true)
assert.Nil(t, err)
keys := [][]byte{[]byte("mk1"), []byte("mk2")}
get1 := &types.StoreGet{StateHash: hash, Keys: keys}
values := store.Get(get1)
assert.Len(t, values, 2)
assert.Nil(t, values[0])
assert.Nil(t, values[1])
actHash, _ := store.Commit(&types.ReqHash{Hash: hash})
assert.Equal(t, hash, actHash)
notExistHash, _ := store.Commit(&types.ReqHash{Hash: drivers.EmptyRoot[:]})
assert.Nil(t, notExistHash)
values = store.Get(get1)
assert.Len(t, values, 2)
assert.Equal(t, values[0], kv[0].Value)
assert.Equal(t, values[1], kv[1].Value)
}
func TestKvmvccdbRollback(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCMavlStore)
assert.NotNil(t, store)
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: []byte("mk1"), Value: []byte("v1")})
kv = append(kv, &types.KeyValue{Key: []byte("mk2"), Value: []byte("v2")})
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
hash, err := store.MemSet(datas, true)
assert.Nil(t, err)
keys := [][]byte{[]byte("mk1"), []byte("mk2")}
get1 := &types.StoreGet{StateHash: hash, Keys: keys}
values := store.Get(get1)
assert.Len(t, values, 2)
assert.Nil(t, values[0])
assert.Nil(t, values[1])
actHash, _ := store.Rollback(&types.ReqHash{Hash: hash})
assert.Equal(t, hash, actHash)
notExistHash, err := store.Rollback(&types.ReqHash{Hash: drivers.EmptyRoot[:]})
assert.Nil(t, notExistHash)
assert.Equal(t, types.ErrHashNotFound.Error(), err.Error())
}
/*
func TestKvmvccdbRollbackBatch(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCMavlStore)
assert.NotNil(t, store)
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: []byte("mk1"), Value: []byte("v1")})
kv = append(kv, &types.KeyValue{Key: []byte("mk2"), Value: []byte("v2")})
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
hash, err := store.MemSet(datas, true)
assert.Nil(t, err)
var kvset []*types.KeyValue
req := &types.ReqHash{Hash: hash}
hash1 := make([]byte, len(hash))
copy(hash1, hash)
store.Commit(req)
for i := 1; i <= 202; i++ {
kvset = nil
datas1 := &types.StoreSet{StateHash: hash1, KV: datas.KV, Height: datas.Height + int64(i)}
s1 := fmt.Sprintf("v1-%03d", datas.Height+int64(i))
s2 := fmt.Sprintf("v2-%03d", datas.Height+int64(i))
datas.KV[0].Value = []byte(s1)
datas.KV[1].Value = []byte(s2)
hash1 = calcHash(datas1)
//zzh
//kmlog.Debug("KVMVCCStore MemSet AddMVCC", "prestatehash", common.ToHex(datas.StateHash), "hash", common.ToHex(hash), "height", datas.Height)
kmlog.Info("KVMVCCStore MemSet AddMVCC for 202", "prestatehash", common.ToHex(datas1.StateHash), "hash", common.ToHex(hash1), "height", datas1.Height)
kvlist, err := store.mvcc.AddMVCC(datas1.KV, hash1, datas1.StateHash, datas1.Height)
if err != nil {
kmlog.Info("KVMVCCStore MemSet AddMVCC failed for 202, continue")
continue
}
if len(kvlist) > 0 {
kvset = append(kvset, kvlist...)
}
store.kvsetmap[string(hash1)] = kvset
req := &types.ReqHash{Hash: hash1}
store.Commit(req)
}
maxVersion, err := store.mvcc.GetMaxVersion()
assert.Equal(t, err, nil)
assert.Equal(t, int64(202), maxVersion)
keys := [][]byte{[]byte("mk1"), []byte("mk2")}
get1 := &types.StoreGet{StateHash: hash, Keys: keys}
values := store.Get(get1)
assert.Len(t, values, 2)
assert.Equal(t, []byte("v1"), values[0])
assert.Equal(t, []byte("v2"), values[1])
var kv2 []*types.KeyValue
kv2 = append(kv2, &types.KeyValue{Key: []byte("mk1"), Value: []byte("v11")})
kv2 = append(kv2, &types.KeyValue{Key: []byte("mk2"), Value: []byte("v22")})
//触发批量回滚
datas2 := &types.StoreSet{StateHash: hash, KV: kv2, Height: 1}
hash, err = store.MemSet(datas2, true)
assert.Nil(t, err)
req = &types.ReqHash{Hash: hash}
store.Commit(req)
maxVersion, err = store.mvcc.GetMaxVersion()
assert.Equal(t, nil, err)
assert.Equal(t, int64(3), maxVersion)
get2 := &types.StoreGet{StateHash: hash, Keys: keys}
values2 := store.Get(get2)
assert.Len(t, values, 2)
assert.Equal(t, values2[0], kv2[0].Value)
assert.Equal(t, values2[1], kv2[1].Value)
datas3 := &types.StoreSet{StateHash: hash, KV: kv2, Height: 2}
hash, err = store.MemSet(datas3, true)
assert.Nil(t, err)
req = &types.ReqHash{Hash: hash}
store.Commit(req)
maxVersion, err = store.mvcc.GetMaxVersion()
assert.Equal(t, nil, err)
assert.Equal(t, int64(2), maxVersion)
}
*/
func enableConfig() []byte {
data, _ := json.Marshal(&subConfig{EnableMVCCIter: true})
return data
}
func TestIterateRangeByStateHash(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg, sub := newStoreCfgIter(dir)
store := New(storeCfg, sub).(*KVMVCCMavlStore)
assert.NotNil(t, store)
execaddr := "0111vcBNSEA7fZhAdLJphDwQRQJa111"
addr := "06htvcBNSEA7fZhAdLJphDwQRQJaHpy"
addr1 := "16htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
addr2 := "26htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
addr3 := "36htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
addr4 := "46htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
accCoin := account.NewCoinsAccount()
account1 := &types.Account{
Balance: 1000 * 1e8,
Addr: addr1,
}
account2 := &types.Account{
Balance: 900 * 1e8,
Addr: addr2,
}
account3 := &types.Account{
Balance: 800 * 1e8,
Addr: addr3,
}
account4 := &types.Account{
Balance: 700 * 1e8,
Addr: addr4,
}
set1 := accCoin.GetKVSet(account1)
set2 := accCoin.GetKVSet(account2)
set3 := accCoin.GetKVSet(account3)
set4 := accCoin.GetKVSet(account4)
set5 := accCoin.GetExecKVSet(execaddr, account4)
fmt.Println("---test case1-1 ---")
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: set4[0].GetKey(), Value: set4[0].GetValue()})
kv = append(kv, &types.KeyValue{Key: set3[0].GetKey(), Value: set3[0].GetValue()})
kv = append(kv, &types.KeyValue{Key: set1[0].GetKey(), Value: set1[0].GetValue()})
kv = append(kv, &types.KeyValue{Key: set2[0].GetKey(), Value: set2[0].GetValue()})
kv = append(kv, &types.KeyValue{Key: set5[0].GetKey(), Value: set5[0].GetValue()})
for i := 0; i < len(kv); i++ {
fmt.Println("key:", string(kv[i].Key), "value:", string(kv[i].Value))
}
datas := &types.StoreSet{StateHash: drivers.EmptyRoot[:], KV: kv, Height: 0}
hash, err := store.MemSet(datas, true)
assert.Nil(t, err)
var kvset []*types.KeyValue
req := &types.ReqHash{Hash: hash}
hash1 := make([]byte, len(hash))
copy(hash1, hash)
store.Commit(req)
resp := &types.ReplyGetTotalCoins{}
resp.Count = 100000
store.IterateRangeByStateHash(hash, []byte("mavl-coins-bty-"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(4), resp.Num)
assert.Equal(t, int64(340000000000), resp.Amount)
fmt.Println("---test case1-2 ---")
for i := 1; i <= 10; i++ {
kvset = nil
s1 := fmt.Sprintf("%03d", 11-i)
addrx := addr + s1
account := &types.Account{
Balance: ((1000 + int64(i)) * 1e8),
Addr: addrx,
}
set := accCoin.GetKVSet(account)
fmt.Println("key:", string(set[0].GetKey()), "value:", set[0].GetValue())
kvset = append(kvset, &types.KeyValue{Key: set[0].GetKey(), Value: set[0].GetValue()})
datas1 := &types.StoreSet{StateHash: hash1, KV: kvset, Height: datas.Height + int64(i)}
hash1, err = store.MemSet(datas1, true)
assert.Nil(t, err)
req := &types.ReqHash{Hash: hash1}
store.Commit(req)
}
resp = &types.ReplyGetTotalCoins{}
resp.Count = 100000
store.IterateRangeByStateHash(hash1, []byte("mavl-coins-bty-"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(14), resp.Num)
assert.Equal(t, int64(1345500000000), resp.Amount)
fmt.Println("---test case1-3 ---")
resp = &types.ReplyGetTotalCoins{}
resp.Count = 100000
store.IterateRangeByStateHash(hash1, []byte("mavl-coins-bty-06htvcBNSEA7fZhAdLJphDwQRQJaHpy003"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(12), resp.Num)
assert.Equal(t, int64(1143600000000), resp.Amount)
fmt.Println("---test case1-4 ---")
resp = &types.ReplyGetTotalCoins{}
resp.Count = 2
store.IterateRangeByStateHash(hash1, []byte("mavl-coins-bty-06htvcBNSEA7fZhAdLJphDwQRQJaHpy003"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(2), resp.Num)
assert.Equal(t, int64(201500000000), resp.Amount)
fmt.Println("---test case1-5 ---")
resp = &types.ReplyGetTotalCoins{}
resp.Count = 2
store.IterateRangeByStateHash(hash1, []byte("mavl-coins-bty-"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(2), resp.Num)
assert.Equal(t, int64(201900000000), resp.Amount)
fmt.Println("---test case1-6 ---")
resp = &types.ReplyGetTotalCoins{}
resp.Count = 10000
store.IterateRangeByStateHash(hash, []byte("mavl-coins-bty-"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(0), resp.Num)
assert.Equal(t, int64(0), resp.Amount)
}
func GetRandomString(length int) string {
return common.GetRandPrintString(20, length)
}
func BenchmarkGet(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCMavlStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var keys [][]byte
var hash = drivers.EmptyRoot[:]
for i := 0; i < b.N; i++ {
key := GetRandomString(MaxKeylenth)
value := fmt.Sprintf("%s%d", key, i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
if i%10000 == 0 {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
kv = nil
}
}
if kv != nil {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
//kv = nil
}
assert.Nil(b, err)
start := time.Now()
b.ResetTimer()
for _, key := range keys {
getData := &types.StoreGet{
StateHash: hash,
Keys: [][]byte{key}}
store.Get(getData)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkGet cost time is", end.Sub(start), "num is", b.N)
}
func BenchmarkStoreGetKvs4N(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCMavlStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
kvnum := 30
for i := 0; i < kvnum; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
hash, err := store.Set(datas, true)
assert.Nil(b, err)
getData := &types.StoreGet{
StateHash: hash,
Keys: keys}
start := time.Now()
b.ResetTimer()
for i := 0; i < b.N; i++ {
values := store.Get(getData)
assert.Len(b, values, kvnum)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkStoreGetKvs4N cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
func BenchmarkStoreGetKvsForNN(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCMavlStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
var hashes [][]byte
for i := 0; i < b.N; i++ {
datas.Height = int64(i)
value = fmt.Sprintf("vv%d", i)
for j := 0; j < 30; j++ {
datas.KV[j].Value = []byte(value)
}
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
datas.StateHash = hash
hashes = append(hashes, hash)
}
start := time.Now()
b.ResetTimer()
getData := &types.StoreGet{
StateHash: hashes[0],
Keys: keys}
for i := 0; i < b.N; i++ {
getData.StateHash = hashes[i]
store.Get(getData)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkStoreGetKvsForNN cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
func BenchmarkStoreGetKvsFor10000(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCMavlStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
var hashes [][]byte
blocks := 10000
times := 10000
start1 := time.Now()
for i := 0; i < blocks; i++ {
datas.Height = int64(i)
value = fmt.Sprintf("vv%d", i)
for j := 0; j < 30; j++ {
datas.KV[j].Value = []byte(value)
}
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
datas.StateHash = hash
hashes = append(hashes, hash)
}
end1 := time.Now()
start := time.Now()
b.ResetTimer()
getData := &types.StoreGet{
StateHash: hashes[0],
Keys: keys}
for i := 0; i < times; i++ {
getData.StateHash = hashes[i]
store.Get(getData)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkStoreGetKvsFor10000 MemSet&Commit cost time is ", end1.Sub(start1), "blocks is", blocks)
fmt.Println("kvmvcc BenchmarkStoreGetKvsFor10000 Get cost time is", end.Sub(start), "num is ", times, ",blocks is ", blocks)
b.StopTimer()
}
func BenchmarkGetIter(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg, sub := newStoreCfgIter(dir)
store := New(storeCfg, sub).(*KVMVCCMavlStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var keys [][]byte
var hash = drivers.EmptyRoot[:]
for i := 0; i < b.N; i++ {
key := GetRandomString(MaxKeylenth)
value := fmt.Sprintf("%s%d", key, i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
if i%10000 == 0 {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
kv = nil
}
}
if kv != nil {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
//kv = nil
}
assert.Nil(b, err)
start := time.Now()
b.ResetTimer()
for _, key := range keys {
getData := &types.StoreGet{
StateHash: hash,
Keys: [][]byte{key}}
store.Get(getData)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkGet cost time is", end.Sub(start), "num is", b.N)
}
func BenchmarkSet(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCMavlStore)
assert.NotNil(b, store)
b.Log(dir)
var kv []*types.KeyValue
var keys [][]byte
var hash = drivers.EmptyRoot[:]
start := time.Now()
for i := 0; i < b.N; i++ {
key := GetRandomString(MaxKeylenth)
value := fmt.Sprintf("%s%d", key, i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
if i%10000 == 0 {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
kv = nil
}
}
if kv != nil {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
_, err = store.Set(datas, true)
assert.Nil(b, err)
//kv = nil
}
end := time.Now()
fmt.Println("mpt BenchmarkSet cost time is", end.Sub(start), "num is", b.N)
}
//上一个用例,一次性插入多对kv;本用例每次插入30对kv,分多次插入,测试性能表现。
func BenchmarkStoreSet(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCMavlStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
for i := 0; i < b.N; i++ {
hash, err := store.Set(datas, true)
assert.Nil(b, err)
assert.NotNil(b, hash)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkSet cost time is", end.Sub(start), "num is", b.N)
}
func BenchmarkSetIter(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg, sub := newStoreCfgIter(dir)
store := New(storeCfg, sub).(*KVMVCCMavlStore)
assert.NotNil(b, store)
b.Log(dir)
var kv []*types.KeyValue
var keys [][]byte
var hash = drivers.EmptyRoot[:]
start := time.Now()
for i := 0; i < b.N; i++ {
key := GetRandomString(MaxKeylenth)
value := fmt.Sprintf("%s%d", key, i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
if i%10000 == 0 {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
kv = nil
}
}
if kv != nil {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
_, err = store.Set(datas, true)
assert.Nil(b, err)
//kv = nil
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkSet cost time is", end.Sub(start), "num is", b.N)
}
func isDirExists(path string) bool {
fi, err := os.Stat(path)
if err != nil {
return os.IsExist(err)
}
return fi.IsDir()
}
//一次设定多对kv,测试一次的时间/多少对kv,来算平均一对kv的耗时。
func BenchmarkMemSet(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCMavlStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < b.N; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
assert.NotNil(b, hash)
end := time.Now()
fmt.Println("kvmvcc BenchmarkMemSet cost time is", end.Sub(start), "num is", b.N)
}
//一次设定30对kv,设定N次,计算每次设定30对kv的耗时。
func BenchmarkStoreMemSet(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCMavlStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
for i := 0; i < b.N; i++ {
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
assert.NotNil(b, hash)
req := &types.ReqHash{
Hash: hash}
store.Rollback(req)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkStoreMemSet cost time is", end.Sub(start), "num is", b.N)
}
func BenchmarkCommit(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCMavlStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < b.N; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
end := time.Now()
fmt.Println("kvmvcc BenchmarkCommit cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
func BenchmarkStoreCommit(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCMavlStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
for i := 0; i < b.N; i++ {
datas.Height = int64(i)
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
datas.StateHash = hash
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkStoreCommit cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
//一次设定多对kv,测试一次的时间/多少对kv,来算平均一对kv的耗时。
func BenchmarkIterMemSet(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg, sub := newStoreCfgIter(dir)
store := New(storeCfg, sub).(*KVMVCCMavlStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < b.N; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
assert.NotNil(b, hash)
end := time.Now()
fmt.Println("kvmvcc BenchmarkMemSet cost time is", end.Sub(start), "num is", b.N)
}
func BenchmarkIterCommit(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg, sub := newStoreCfgIter(dir)
store := New(storeCfg, sub).(*KVMVCCMavlStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < b.N; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
end := time.Now()
fmt.Println("kvmvcc BenchmarkCommit cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package kvmvccMavl
import (
"github.com/33cn/chain33/common"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/queue"
drivers "github.com/33cn/chain33/system/store"
"github.com/33cn/chain33/types"
"github.com/golang/protobuf/proto"
)
var maxRollbackNum = 200
// KVMVCCStore provide kvmvcc store interface implementation
type KVMVCCStore struct {
db dbm.DB
mvcc dbm.MVCC
kvsetmap map[string][]*types.KeyValue
enableMVCCIter bool
}
// NewKVMVCC construct KVMVCCStore module
func NewKVMVCC(cfg *types.Store, sub *subKVMVCCConfig, db dbm.DB) *KVMVCCStore {
bs := drivers.NewBaseStore(cfg)
var kvs *KVMVCCStore
enable := false
if sub != nil {
enable = sub.EnableMVCCIter
}
if enable {
kvs = &KVMVCCStore{db, dbm.NewMVCCIter(bs.GetDB()), make(map[string][]*types.KeyValue), true}
} else {
kvs = &KVMVCCStore{db, dbm.NewMVCC(bs.GetDB()), make(map[string][]*types.KeyValue), false}
}
return kvs
}
// Close the KVMVCCStore module
func (mvccs *KVMVCCStore) Close() {
kmlog.Info("store kvdb closed")
}
// Set kvs with statehash to KVMVCCStore
func (mvccs *KVMVCCStore) Set(datas *types.StoreSet, sync bool) ([]byte, error) {
hash := calcHash(datas)
kvlist, err := mvccs.mvcc.AddMVCC(datas.KV, hash, datas.StateHash, datas.Height)
if err != nil {
return nil, err
}
mvccs.saveKVSets(kvlist)
return hash, nil
}
// Get kvs with statehash from KVMVCCStore
func (mvccs *KVMVCCStore) Get(datas *types.StoreGet) [][]byte {
values := make([][]byte, len(datas.Keys))
version, err := mvccs.mvcc.GetVersion(datas.StateHash)
if err != nil {
kmlog.Error("Get version by hash failed.", "hash", common.ToHex(datas.StateHash))
return values
}
for i := 0; i < len(datas.Keys); i++ {
value, err := mvccs.mvcc.GetV(datas.Keys[i], version)
if err != nil {
kmlog.Error("GetV by Keys failed.", "Key", string(datas.Keys[i]), "version", version)
} else if value != nil {
values[i] = value
}
}
return values
}
// MemSet set kvs to the mem of KVMVCCStore module and return the StateHash
func (mvccs *KVMVCCStore) MemSet(datas *types.StoreSet, sync bool) ([]byte, error) {
kvset, err := mvccs.checkVersion(datas.Height)
if err != nil {
return nil, err
}
hash := calcHash(datas)
//kmlog.Debug("KVMVCCStore MemSet AddMVCC", "prestatehash", common.ToHex(datas.StateHash), "hash", common.ToHex(hash), "height", datas.Height)
kvlist, err := mvccs.mvcc.AddMVCC(datas.KV, hash, datas.StateHash, datas.Height)
if err != nil {
return nil, err
}
if len(kvlist) > 0 {
kvset = append(kvset, kvlist...)
}
mvccs.kvsetmap[string(hash)] = kvset
return hash, nil
}
// Commit kvs in the mem of KVMVCCStore module to state db and return the StateHash
func (mvccs *KVMVCCStore) Commit(req *types.ReqHash) ([]byte, error) {
_, ok := mvccs.kvsetmap[string(req.Hash)]
if !ok {
kmlog.Error("store kvmvcc commit", "err", types.ErrHashNotFound)
return nil, types.ErrHashNotFound
}
//kmlog.Debug("KVMVCCStore Commit saveKVSets", "hash", common.ToHex(req.Hash))
mvccs.saveKVSets(mvccs.kvsetmap[string(req.Hash)])
delete(mvccs.kvsetmap, string(req.Hash))
return req.Hash, nil
}
// Rollback kvs in the mem of KVMVCCStore module and return the StateHash
func (mvccs *KVMVCCStore) Rollback(req *types.ReqHash) ([]byte, error) {
_, ok := mvccs.kvsetmap[string(req.Hash)]
if !ok {
kmlog.Error("store kvmvcc rollback", "err", types.ErrHashNotFound)
return nil, types.ErrHashNotFound
}
//kmlog.Debug("KVMVCCStore Rollback", "hash", common.ToHex(req.Hash))
delete(mvccs.kvsetmap, string(req.Hash))
return req.Hash, nil
}
// IterateRangeByStateHash travel with Prefix by StateHash to get the latest version kvs.
func (mvccs *KVMVCCStore) IterateRangeByStateHash(statehash []byte, start []byte, end []byte, ascending bool, fn func(key, value []byte) bool) {
if !mvccs.enableMVCCIter {
panic("call IterateRangeByStateHash when disable mvcc iter")
}
//按照kv最新值来进行遍历处理,要求statehash必须是最新区块的statehash,否则不支持该接口
maxVersion, err := mvccs.mvcc.GetMaxVersion()
if err != nil {
kmlog.Error("KVMVCCStore IterateRangeByStateHash can't get max version, ignore the call.", "err", err)
return
}
version, err := mvccs.mvcc.GetVersion(statehash)
if err != nil {
kmlog.Error("KVMVCCStore IterateRangeByStateHash can't get version, ignore the call.", "stateHash", common.ToHex(statehash), "err", err)
return
}
if version != maxVersion {
kmlog.Error("KVMVCCStore IterateRangeByStateHash call failed for maxVersion does not match version.", "maxVersion", maxVersion, "version", version, "stateHash", common.ToHex(statehash))
return
}
//kmlog.Info("KVMVCCStore do the IterateRangeByStateHash")
listhelper := dbm.NewListHelper(mvccs.mvcc.(*dbm.MVCCIter))
listhelper.IteratorCallback(start, end, 0, 1, fn)
}
// ProcEvent handles supported events
func (mvccs *KVMVCCStore) ProcEvent(msg queue.Message) {
msg.ReplyErr("KVStore", types.ErrActionNotSupport)
}
// Del set kvs to nil with StateHash
func (mvccs *KVMVCCStore) Del(req *types.StoreDel) ([]byte, error) {
kvset, err := mvccs.mvcc.DelMVCC(req.StateHash, req.Height, true)
if err != nil {
kmlog.Error("store kvmvcc del", "err", err)
return nil, err
}
kmlog.Info("KVMVCCStore Del", "hash", common.ToHex(req.StateHash), "height", req.Height)
mvccs.saveKVSets(kvset)
return req.StateHash, nil
}
func (mvccs *KVMVCCStore) saveKVSets(kvset []*types.KeyValue) {
if len(kvset) == 0 {
return
}
storeBatch := mvccs.db.NewBatch(true)
for i := 0; i < len(kvset); i++ {
if kvset[i].Value == nil {
storeBatch.Delete(kvset[i].Key)
} else {
storeBatch.Set(kvset[i].Key, kvset[i].Value)
}
}
storeBatch.Write()
}
func (mvccs *KVMVCCStore) checkVersion(height int64) ([]*types.KeyValue, error) {
//检查新加入区块的height和现有的version的关系,来判断是否要回滚数据
maxVersion, err := mvccs.mvcc.GetMaxVersion()
if err != nil {
if err != types.ErrNotFound {
kmlog.Error("store kvmvcc checkVersion GetMaxVersion failed", "err", err)
panic(err)
} else {
maxVersion = -1
}
}
//kmlog.Debug("store kvmvcc checkVersion ", "maxVersion", maxVersion, "currentVersion", height)
var kvset []*types.KeyValue
if maxVersion < height-1 {
kmlog.Error("store kvmvcc checkVersion found statehash lost", "maxVersion", maxVersion, "height", height)
return nil, ErrStateHashLost
} else if maxVersion == height-1 {
return nil, nil
} else {
count := 1
for i := maxVersion; i >= height; i-- {
hash, err := mvccs.mvcc.GetVersionHash(i)
if err != nil {
kmlog.Warn("store kvmvcc checkVersion GetVersionHash failed", "height", i, "maxVersion", maxVersion)
continue
}
kvlist, err := mvccs.mvcc.DelMVCC(hash, i, false)
if err != nil {
kmlog.Warn("store kvmvcc checkVersion DelMVCC failed", "height", i, "err", err)
continue
}
kvset = append(kvset, kvlist...)
kmlog.Debug("store kvmvcc checkVersion DelMVCC4Height", "height", i, "maxVersion", maxVersion)
//为避免高度差过大时出现异常,做一个保护,一次最多回滚200个区块
count++
if count >= maxRollbackNum {
break
}
}
}
return kvset, nil
}
func calcHash(datas proto.Message) []byte {
b := types.Encode(datas)
return common.Sha256(b)
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package kvmvccMavl
import (
"encoding/json"
"io/ioutil"
"os"
"testing"
"time"
"fmt"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/common"
drivers "github.com/33cn/chain33/system/store"
"github.com/33cn/chain33/types"
"github.com/stretchr/testify/assert"
)
const MaxKeylenth int = 64
func newStoreCfg(dir string) *types.Store {
return &types.Store{Name: "kvmvcc_test", Driver: "leveldb", DbPath: dir, DbCache: 100}
}
func newStoreCfgIter(dir string) (*types.Store, []byte) {
return &types.Store{Name: "kvmvcc_test", Driver: "leveldb", DbPath: dir, DbCache: 100}, enableConfig()
}
func TestKvmvccdbNewClose(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCStore)
assert.NotNil(t, store)
store.Close()
}
func TestKvmvccdbSetGet(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCStore)
assert.NotNil(t, store)
keys0 := [][]byte{[]byte("mk1"), []byte("mk2")}
get0 := &types.StoreGet{StateHash: drivers.EmptyRoot[:], Keys: keys0}
values0 := store.Get(get0)
//klog.Info("info", "info", values0)
// Get exist key, result nil
assert.Len(t, values0, 2)
assert.Equal(t, []byte(nil), values0[0])
assert.Equal(t, []byte(nil), values0[1])
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: []byte("k1"), Value: []byte("v1")})
kv = append(kv, &types.KeyValue{Key: []byte("k2"), Value: []byte("v2")})
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
hash, err := store.Set(datas, true)
assert.Nil(t, err)
keys := [][]byte{[]byte("k1"), []byte("k2")}
get1 := &types.StoreGet{StateHash: hash, Keys: keys}
values := store.Get(get1)
assert.Len(t, values, 2)
assert.Equal(t, []byte("v1"), values[0])
assert.Equal(t, []byte("v2"), values[1])
keys = [][]byte{[]byte("k1")}
get2 := &types.StoreGet{StateHash: hash, Keys: keys}
values2 := store.Get(get2)
assert.Len(t, values2, 1)
assert.Equal(t, []byte("v1"), values2[0])
get3 := &types.StoreGet{StateHash: drivers.EmptyRoot[:], Keys: keys}
values3 := store.Get(get3)
assert.Len(t, values3, 1)
}
func TestKvmvccdbMemSet(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCStore)
assert.NotNil(t, store)
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: []byte("mk1"), Value: []byte("v1")})
kv = append(kv, &types.KeyValue{Key: []byte("mk2"), Value: []byte("v2")})
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
hash, err := store.MemSet(datas, true)
assert.Nil(t, err)
keys := [][]byte{[]byte("mk1"), []byte("mk2")}
get1 := &types.StoreGet{StateHash: hash, Keys: keys}
values := store.Get(get1)
assert.Len(t, values, 2)
assert.Nil(t, values[0])
assert.Nil(t, values[1])
actHash, _ := store.Commit(&types.ReqHash{Hash: hash})
assert.Equal(t, hash, actHash)
notExistHash, _ := store.Commit(&types.ReqHash{Hash: drivers.EmptyRoot[:]})
assert.Nil(t, notExistHash)
values = store.Get(get1)
assert.Len(t, values, 2)
assert.Equal(t, values[0], kv[0].Value)
assert.Equal(t, values[1], kv[1].Value)
}
func TestKvmvccdbRollback(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCStore)
assert.NotNil(t, store)
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: []byte("mk1"), Value: []byte("v1")})
kv = append(kv, &types.KeyValue{Key: []byte("mk2"), Value: []byte("v2")})
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
hash, err := store.MemSet(datas, true)
assert.Nil(t, err)
keys := [][]byte{[]byte("mk1"), []byte("mk2")}
get1 := &types.StoreGet{StateHash: hash, Keys: keys}
values := store.Get(get1)
assert.Len(t, values, 2)
assert.Nil(t, values[0])
assert.Nil(t, values[1])
actHash, _ := store.Rollback(&types.ReqHash{Hash: hash})
assert.Equal(t, hash, actHash)
notExistHash, err := store.Rollback(&types.ReqHash{Hash: drivers.EmptyRoot[:]})
assert.Nil(t, notExistHash)
assert.Equal(t, types.ErrHashNotFound.Error(), err.Error())
}
func TestKvmvccdbRollbackBatch(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCStore)
assert.NotNil(t, store)
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: []byte("mk1"), Value: []byte("v1")})
kv = append(kv, &types.KeyValue{Key: []byte("mk2"), Value: []byte("v2")})
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
hash, err := store.MemSet(datas, true)
assert.Nil(t, err)
var kvset []*types.KeyValue
req := &types.ReqHash{Hash: hash}
hash1 := make([]byte, len(hash))
copy(hash1, hash)
store.Commit(req)
for i := 1; i <= 202; i++ {
kvset = nil
datas1 := &types.StoreSet{StateHash: hash1, KV: datas.KV, Height: datas.Height + int64(i)}
s1 := fmt.Sprintf("v1-%03d", datas.Height+int64(i))
s2 := fmt.Sprintf("v2-%03d", datas.Height+int64(i))
datas.KV[0].Value = []byte(s1)
datas.KV[1].Value = []byte(s2)
hash1 = calcHash(datas1)
//zzh
//klog.Debug("KVMVCCStore MemSet AddMVCC", "prestatehash", common.ToHex(datas.StateHash), "hash", common.ToHex(hash), "height", datas.Height)
klog.Info("KVMVCCStore MemSet AddMVCC for 202", "prestatehash", common.ToHex(datas1.StateHash), "hash", common.ToHex(hash1), "height", datas1.Height)
kvlist, err := store.mvcc.AddMVCC(datas1.KV, hash1, datas1.StateHash, datas1.Height)
if err != nil {
klog.Info("KVMVCCStore MemSet AddMVCC failed for 202, continue")
continue
}
if len(kvlist) > 0 {
kvset = append(kvset, kvlist...)
}
store.kvsetmap[string(hash1)] = kvset
req := &types.ReqHash{Hash: hash1}
store.Commit(req)
}
maxVersion, err := store.mvcc.GetMaxVersion()
assert.Equal(t, err, nil)
assert.Equal(t, int64(202), maxVersion)
keys := [][]byte{[]byte("mk1"), []byte("mk2")}
get1 := &types.StoreGet{StateHash: hash, Keys: keys}
values := store.Get(get1)
assert.Len(t, values, 2)
assert.Equal(t, []byte("v1"), values[0])
assert.Equal(t, []byte("v2"), values[1])
var kv2 []*types.KeyValue
kv2 = append(kv2, &types.KeyValue{Key: []byte("mk1"), Value: []byte("v11")})
kv2 = append(kv2, &types.KeyValue{Key: []byte("mk2"), Value: []byte("v22")})
//触发批量回滚
datas2 := &types.StoreSet{StateHash: hash, KV: kv2, Height: 1}
hash, err = store.MemSet(datas2, true)
assert.Nil(t, err)
req = &types.ReqHash{Hash: hash}
store.Commit(req)
maxVersion, err = store.mvcc.GetMaxVersion()
assert.Equal(t, nil, err)
assert.Equal(t, int64(3), maxVersion)
get2 := &types.StoreGet{StateHash: hash, Keys: keys}
values2 := store.Get(get2)
assert.Len(t, values, 2)
assert.Equal(t, values2[0], kv2[0].Value)
assert.Equal(t, values2[1], kv2[1].Value)
datas3 := &types.StoreSet{StateHash: hash, KV: kv2, Height: 2}
hash, err = store.MemSet(datas3, true)
assert.Nil(t, err)
req = &types.ReqHash{Hash: hash}
store.Commit(req)
maxVersion, err = store.mvcc.GetMaxVersion()
assert.Equal(t, nil, err)
assert.Equal(t, int64(2), maxVersion)
}
func enableConfig() []byte {
data, _ := json.Marshal(&subConfig{EnableMVCCIter: true})
return data
}
func TestIterateRangeByStateHash(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg, sub := newStoreCfgIter(dir)
store := New(storeCfg, sub).(*KVMVCCStore)
assert.NotNil(t, store)
execaddr := "0111vcBNSEA7fZhAdLJphDwQRQJa111"
addr := "06htvcBNSEA7fZhAdLJphDwQRQJaHpy"
addr1 := "16htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
addr2 := "26htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
addr3 := "36htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
addr4 := "46htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
accCoin := account.NewCoinsAccount()
account1 := &types.Account{
Balance: 1000 * 1e8,
Addr: addr1,
}
account2 := &types.Account{
Balance: 900 * 1e8,
Addr: addr2,
}
account3 := &types.Account{
Balance: 800 * 1e8,
Addr: addr3,
}
account4 := &types.Account{
Balance: 700 * 1e8,
Addr: addr4,
}
set1 := accCoin.GetKVSet(account1)
set2 := accCoin.GetKVSet(account2)
set3 := accCoin.GetKVSet(account3)
set4 := accCoin.GetKVSet(account4)
set5 := accCoin.GetExecKVSet(execaddr, account4)
fmt.Println("---test case1-1 ---")
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: set4[0].GetKey(), Value: set4[0].GetValue()})
kv = append(kv, &types.KeyValue{Key: set3[0].GetKey(), Value: set3[0].GetValue()})
kv = append(kv, &types.KeyValue{Key: set1[0].GetKey(), Value: set1[0].GetValue()})
kv = append(kv, &types.KeyValue{Key: set2[0].GetKey(), Value: set2[0].GetValue()})
kv = append(kv, &types.KeyValue{Key: set5[0].GetKey(), Value: set5[0].GetValue()})
for i := 0; i < len(kv); i++ {
fmt.Println("key:", string(kv[i].Key), "value:", string(kv[i].Value))
}
datas := &types.StoreSet{StateHash: drivers.EmptyRoot[:], KV: kv, Height: 0}
hash, err := store.MemSet(datas, true)
assert.Nil(t, err)
var kvset []*types.KeyValue
req := &types.ReqHash{Hash: hash}
hash1 := make([]byte, len(hash))
copy(hash1, hash)
store.Commit(req)
resp := &types.ReplyGetTotalCoins{}
resp.Count = 100000
store.IterateRangeByStateHash(hash, []byte("mavl-coins-bty-"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(4), resp.Num)
assert.Equal(t, int64(340000000000), resp.Amount)
fmt.Println("---test case1-2 ---")
for i := 1; i <= 10; i++ {
kvset = nil
s1 := fmt.Sprintf("%03d", 11-i)
addrx := addr + s1
account := &types.Account{
Balance: ((1000 + int64(i)) * 1e8),
Addr: addrx,
}
set := accCoin.GetKVSet(account)
fmt.Println("key:", string(set[0].GetKey()), "value:", set[0].GetValue())
kvset = append(kvset, &types.KeyValue{Key: set[0].GetKey(), Value: set[0].GetValue()})
datas1 := &types.StoreSet{StateHash: hash1, KV: kvset, Height: datas.Height + int64(i)}
hash1, err = store.MemSet(datas1, true)
assert.Nil(t, err)
req := &types.ReqHash{Hash: hash1}
store.Commit(req)
}
resp = &types.ReplyGetTotalCoins{}
resp.Count = 100000
store.IterateRangeByStateHash(hash1, []byte("mavl-coins-bty-"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(14), resp.Num)
assert.Equal(t, int64(1345500000000), resp.Amount)
fmt.Println("---test case1-3 ---")
resp = &types.ReplyGetTotalCoins{}
resp.Count = 100000
store.IterateRangeByStateHash(hash1, []byte("mavl-coins-bty-06htvcBNSEA7fZhAdLJphDwQRQJaHpy003"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(12), resp.Num)
assert.Equal(t, int64(1143600000000), resp.Amount)
fmt.Println("---test case1-4 ---")
resp = &types.ReplyGetTotalCoins{}
resp.Count = 2
store.IterateRangeByStateHash(hash1, []byte("mavl-coins-bty-06htvcBNSEA7fZhAdLJphDwQRQJaHpy003"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(2), resp.Num)
assert.Equal(t, int64(201500000000), resp.Amount)
fmt.Println("---test case1-5 ---")
resp = &types.ReplyGetTotalCoins{}
resp.Count = 2
store.IterateRangeByStateHash(hash1, []byte("mavl-coins-bty-"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(2), resp.Num)
assert.Equal(t, int64(201900000000), resp.Amount)
fmt.Println("---test case1-6 ---")
resp = &types.ReplyGetTotalCoins{}
resp.Count = 10000
store.IterateRangeByStateHash(hash, []byte("mavl-coins-bty-"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(0), resp.Num)
assert.Equal(t, int64(0), resp.Amount)
}
func GetRandomString(length int) string {
return common.GetRandPrintString(20, length)
}
func BenchmarkGet(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var keys [][]byte
var hash = drivers.EmptyRoot[:]
for i := 0; i < b.N; i++ {
key := GetRandomString(MaxKeylenth)
value := fmt.Sprintf("%s%d", key, i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
if i%10000 == 0 {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
kv = nil
}
}
if kv != nil {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
//kv = nil
}
assert.Nil(b, err)
start := time.Now()
b.ResetTimer()
for _, key := range keys {
getData := &types.StoreGet{
StateHash: hash,
Keys: [][]byte{key}}
store.Get(getData)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkGet cost time is", end.Sub(start), "num is", b.N)
}
func BenchmarkStoreGetKvs4N(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
kvnum := 30
for i := 0; i < kvnum; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
hash, err := store.Set(datas, true)
assert.Nil(b, err)
getData := &types.StoreGet{
StateHash: hash,
Keys: keys}
start := time.Now()
b.ResetTimer()
for i := 0; i < b.N; i++ {
values := store.Get(getData)
assert.Len(b, values, kvnum)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkStoreGetKvs4N cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
func BenchmarkStoreGetKvsForNN(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
var hashes [][]byte
for i := 0; i < b.N; i++ {
datas.Height = int64(i)
value = fmt.Sprintf("vv%d", i)
for j := 0; j < 30; j++ {
datas.KV[j].Value = []byte(value)
}
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
datas.StateHash = hash
hashes = append(hashes, hash)
}
start := time.Now()
b.ResetTimer()
getData := &types.StoreGet{
StateHash: hashes[0],
Keys: keys}
for i := 0; i < b.N; i++ {
getData.StateHash = hashes[i]
store.Get(getData)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkStoreGetKvsForNN cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
func BenchmarkStoreGetKvsFor10000(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
var hashes [][]byte
blocks := 10000
times := 10000
start1 := time.Now()
for i := 0; i < blocks; i++ {
datas.Height = int64(i)
value = fmt.Sprintf("vv%d", i)
for j := 0; j < 30; j++ {
datas.KV[j].Value = []byte(value)
}
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
datas.StateHash = hash
hashes = append(hashes, hash)
}
end1 := time.Now()
start := time.Now()
b.ResetTimer()
getData := &types.StoreGet{
StateHash: hashes[0],
Keys: keys}
for i := 0; i < times; i++ {
getData.StateHash = hashes[i]
store.Get(getData)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkStoreGetKvsFor10000 MemSet&Commit cost time is ", end1.Sub(start1), "blocks is", blocks)
fmt.Println("kvmvcc BenchmarkStoreGetKvsFor10000 Get cost time is", end.Sub(start), "num is ", times, ",blocks is ", blocks)
b.StopTimer()
}
func BenchmarkGetIter(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg, sub := newStoreCfgIter(dir)
store := New(storeCfg, sub).(*KVMVCCStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var keys [][]byte
var hash = drivers.EmptyRoot[:]
for i := 0; i < b.N; i++ {
key := GetRandomString(MaxKeylenth)
value := fmt.Sprintf("%s%d", key, i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
if i%10000 == 0 {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
kv = nil
}
}
if kv != nil {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
//kv = nil
}
assert.Nil(b, err)
start := time.Now()
b.ResetTimer()
for _, key := range keys {
getData := &types.StoreGet{
StateHash: hash,
Keys: [][]byte{key}}
store.Get(getData)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkGet cost time is", end.Sub(start), "num is", b.N)
}
func BenchmarkSet(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCStore)
assert.NotNil(b, store)
b.Log(dir)
var kv []*types.KeyValue
var keys [][]byte
var hash = drivers.EmptyRoot[:]
start := time.Now()
for i := 0; i < b.N; i++ {
key := GetRandomString(MaxKeylenth)
value := fmt.Sprintf("%s%d", key, i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
if i%10000 == 0 {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
kv = nil
}
}
if kv != nil {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
_, err = store.Set(datas, true)
assert.Nil(b, err)
//kv = nil
}
end := time.Now()
fmt.Println("mpt BenchmarkSet cost time is", end.Sub(start), "num is", b.N)
}
//上一个用例,一次性插入多对kv;本用例每次插入30对kv,分多次插入,测试性能表现。
func BenchmarkStoreSet(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
for i := 0; i < b.N; i++ {
hash, err := store.Set(datas, true)
assert.Nil(b, err)
assert.NotNil(b, hash)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkSet cost time is", end.Sub(start), "num is", b.N)
}
func BenchmarkSetIter(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg, sub := newStoreCfgIter(dir)
store := New(storeCfg, sub).(*KVMVCCStore)
assert.NotNil(b, store)
b.Log(dir)
var kv []*types.KeyValue
var keys [][]byte
var hash = drivers.EmptyRoot[:]
start := time.Now()
for i := 0; i < b.N; i++ {
key := GetRandomString(MaxKeylenth)
value := fmt.Sprintf("%s%d", key, i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
if i%10000 == 0 {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
kv = nil
}
}
if kv != nil {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
_, err = store.Set(datas, true)
assert.Nil(b, err)
//kv = nil
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkSet cost time is", end.Sub(start), "num is", b.N)
}
func isDirExists(path string) bool {
fi, err := os.Stat(path)
if err != nil {
return os.IsExist(err)
}
return fi.IsDir()
}
//一次设定多对kv,测试一次的时间/多少对kv,来算平均一对kv的耗时。
func BenchmarkMemSet(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < b.N; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
assert.NotNil(b, hash)
end := time.Now()
fmt.Println("kvmvcc BenchmarkMemSet cost time is", end.Sub(start), "num is", b.N)
}
//一次设定30对kv,设定N次,计算每次设定30对kv的耗时。
func BenchmarkStoreMemSet(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
for i := 0; i < b.N; i++ {
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
assert.NotNil(b, hash)
req := &types.ReqHash{
Hash: hash}
store.Rollback(req)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkStoreMemSet cost time is", end.Sub(start), "num is", b.N)
}
func BenchmarkCommit(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < b.N; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
end := time.Now()
fmt.Println("kvmvcc BenchmarkCommit cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
func BenchmarkStoreCommit(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVMVCCStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
for i := 0; i < b.N; i++ {
datas.Height = int64(i)
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
datas.StateHash = hash
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkStoreCommit cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
//一次设定多对kv,测试一次的时间/多少对kv,来算平均一对kv的耗时。
func BenchmarkIterMemSet(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg, sub := newStoreCfgIter(dir)
store := New(storeCfg, sub).(*KVMVCCStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < b.N; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
assert.NotNil(b, hash)
end := time.Now()
fmt.Println("kvmvcc BenchmarkMemSet cost time is", end.Sub(start), "num is", b.N)
}
func BenchmarkIterCommit(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg, sub := newStoreCfgIter(dir)
store := New(storeCfg, sub).(*KVMVCCStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < b.N; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
end := time.Now()
fmt.Println("kvmvcc BenchmarkCommit cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package mavl 默克尔平衡树接口
package kvmvccMavl
import (
"sync"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/queue"
"github.com/33cn/chain33/system/store/mavl/db"
"github.com/33cn/chain33/types"
dbm "github.com/33cn/chain33/common/db"
)
// Store mavl store struct
type MavlStore struct {
db dbm.DB
trees *sync.Map
enableMavlPrefix bool
enableMVCC bool
enableMavlPrune bool
pruneHeight int32
}
// NewMavl new mavl store module
func NewMavl(cfg *types.Store, sub *subMavlConfig, db dbm.DB) *MavlStore {
var subcfg subMavlConfig
if sub != nil {
subcfg.EnableMavlPrefix = sub.EnableMavlPrefix
subcfg.EnableMVCC = sub.EnableMVCC
subcfg.EnableMavlPrune = sub.EnableMavlPrune
subcfg.PruneHeight = sub.PruneHeight
}
mavls := &MavlStore{db, &sync.Map{}, subcfg.EnableMavlPrefix, subcfg.EnableMVCC, subcfg.EnableMavlPrune, subcfg.PruneHeight}
mavl.EnableMavlPrefix(subcfg.EnableMavlPrefix)
mavl.EnableMVCC(subcfg.EnableMVCC)
mavl.EnablePrune(subcfg.EnableMavlPrune)
mavl.SetPruneHeight(int(subcfg.PruneHeight))
return mavls
}
// Close close mavl store
func (mavls *MavlStore) Close() {
mavl.ClosePrune()
kmlog.Info("store mavl closed")
}
// Set set k v to mavl store db; sync is true represent write sync
func (mavls *MavlStore) Set(datas *types.StoreSet, sync bool) ([]byte, error) {
return mavl.SetKVPair(mavls.db, datas, sync)
}
// Get get values by keys
func (mavls *MavlStore) Get(datas *types.StoreGet) [][]byte {
var tree *mavl.Tree
var err error
values := make([][]byte, len(datas.Keys))
search := string(datas.StateHash)
if data, ok := mavls.trees.Load(search); ok {
tree = data.(*mavl.Tree)
} else {
tree = mavl.NewTree(mavls.db, true)
//get接口也应该传入高度
//tree.SetBlockHeight(datas.Height)
err = tree.Load(datas.StateHash)
kmlog.Debug("store mavl get tree", "err", err, "StateHash", common.ToHex(datas.StateHash))
}
if err == nil {
for i := 0; i < len(datas.Keys); i++ {
_, value, exit := tree.Get(datas.Keys[i])
if exit {
values[i] = value
}
}
}
return values
}
// MemSet set keys values to memcory mavl, return root hash and error
func (mavls *MavlStore) MemSet(datas *types.StoreSet, sync bool) ([]byte, error) {
beg := types.Now()
defer func() {
kmlog.Info("MemSet", "cost", types.Since(beg))
}()
if len(datas.KV) == 0 {
kmlog.Info("store mavl memset,use preStateHash as stateHash for kvset is null")
mavls.trees.Store(string(datas.StateHash), nil)
return datas.StateHash, nil
}
tree := mavl.NewTree(mavls.db, sync)
tree.SetBlockHeight(datas.Height)
err := tree.Load(datas.StateHash)
if err != nil {
return nil, err
}
for i := 0; i < len(datas.KV); i++ {
tree.Set(datas.KV[i].Key, datas.KV[i].Value)
}
hash := tree.Hash()
mavls.trees.Store(string(hash), tree)
return hash, nil
}
// Commit convert memcory mavl to storage db
func (mavls *MavlStore) Commit(req *types.ReqHash) ([]byte, error) {
beg := types.Now()
defer func() {
kmlog.Info("Commit", "cost", types.Since(beg))
}()
tree, ok := mavls.trees.Load(string(req.Hash))
if !ok {
kmlog.Error("store mavl commit", "err", types.ErrHashNotFound)
return nil, types.ErrHashNotFound
}
if tree == nil {
kmlog.Info("store mavl commit,do nothing for kvset is null")
mavls.trees.Delete(string(req.Hash))
return req.Hash, nil
}
hash := tree.(*mavl.Tree).Save()
if hash == nil {
kmlog.Error("store mavl commit", "err", types.ErrHashNotFound)
return nil, types.ErrDataBaseDamage
}
mavls.trees.Delete(string(req.Hash))
return req.Hash, nil
}
// Rollback 回退将缓存的mavl树删除掉
func (mavls *MavlStore) Rollback(req *types.ReqHash) ([]byte, error) {
beg := types.Now()
defer func() {
kmlog.Info("Rollback", "cost", types.Since(beg))
}()
_, ok := mavls.trees.Load(string(req.Hash))
if !ok {
kmlog.Error("store mavl rollback", "err", types.ErrHashNotFound)
return nil, types.ErrHashNotFound
}
mavls.trees.Delete(string(req.Hash))
return req.Hash, nil
}
// IterateRangeByStateHash 迭代实现功能; statehash:当前状态hash, start:开始查找的key, end: 结束的key, ascending:升序,降序, fn 迭代回调函数
func (mavls *MavlStore) IterateRangeByStateHash(statehash []byte, start []byte, end []byte, ascending bool, fn func(key, value []byte) bool) {
mavl.IterateRangeByStateHash(mavls.db, statehash, start, end, ascending, fn)
}
// ProcEvent not support message
func (mavls *MavlStore) ProcEvent(msg queue.Message) {
msg.ReplyErr("Store", types.ErrActionNotSupport)
}
// Del ...
func (mavls *MavlStore) Del(req *types.StoreDel) ([]byte, error) {
//not support
return nil, nil
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package kvmvccMavl
import (
"io/ioutil"
"os"
"testing"
"fmt"
"time"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/common"
drivers "github.com/33cn/chain33/system/store"
mavldb "github.com/33cn/chain33/system/store/mavl/db"
"github.com/33cn/chain33/types"
"github.com/stretchr/testify/assert"
)
const MaxKeylenth int = 64
func newStoreCfg(dir string) *types.Store {
return &types.Store{Name: "mavl_test", Driver: "leveldb", DbPath: dir, DbCache: 100}
}
func TestKvdbNewClose(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*Store)
assert.NotNil(t, store)
store.Close()
}
func TestKvddbSetGet(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*Store)
assert.NotNil(t, store)
keys0 := [][]byte{[]byte("mk1"), []byte("mk2")}
get0 := &types.StoreGet{StateHash: drivers.EmptyRoot[:], Keys: keys0}
values0 := store.Get(get0)
mlog.Info("info", "info", values0)
// Get exist key, result nil
assert.Len(t, values0, 2)
assert.Equal(t, []byte(nil), values0[0])
assert.Equal(t, []byte(nil), values0[1])
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: []byte("k1"), Value: []byte("v1")})
kv = append(kv, &types.KeyValue{Key: []byte("k2"), Value: []byte("v2")})
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
}
hash, err := store.Set(datas, true)
assert.Nil(t, err)
keys := [][]byte{[]byte("k1"), []byte("k2")}
get1 := &types.StoreGet{StateHash: hash, Keys: keys}
values := store.Get(get1)
assert.Len(t, values, 2)
assert.Equal(t, []byte("v1"), values[0])
assert.Equal(t, []byte("v2"), values[1])
keys = [][]byte{[]byte("k1")}
get2 := &types.StoreGet{StateHash: hash, Keys: keys}
values2 := store.Get(get2)
assert.Len(t, values2, 1)
assert.Equal(t, []byte("v1"), values2[0])
get3 := &types.StoreGet{StateHash: drivers.EmptyRoot[:], Keys: keys}
values3 := store.Get(get3)
assert.Len(t, values3, 1)
assert.Equal(t, []byte(nil), values3[0])
}
func TestKvdbMemSet(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*Store)
assert.NotNil(t, store)
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: []byte("mk1"), Value: []byte("v1")})
kv = append(kv, &types.KeyValue{Key: []byte("mk2"), Value: []byte("v2")})
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
}
hash, err := store.MemSet(datas, true)
assert.Nil(t, err)
keys := [][]byte{[]byte("mk1"), []byte("mk2")}
get1 := &types.StoreGet{StateHash: hash, Keys: keys}
values := store.Get(get1)
assert.Len(t, values, 2)
actHash, _ := store.Commit(&types.ReqHash{Hash: hash})
assert.Equal(t, hash, actHash)
notExistHash, _ := store.Commit(&types.ReqHash{Hash: drivers.EmptyRoot[:]})
assert.Nil(t, notExistHash)
}
func TestKvdbRollback(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*Store)
assert.NotNil(t, store)
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: []byte("mk1"), Value: []byte("v1")})
kv = append(kv, &types.KeyValue{Key: []byte("mk2"), Value: []byte("v2")})
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
}
hash, err := store.MemSet(datas, true)
assert.Nil(t, err)
keys := [][]byte{[]byte("mk1"), []byte("mk2")}
get1 := &types.StoreGet{StateHash: hash, Keys: keys}
values := store.Get(get1)
assert.Len(t, values, 2)
actHash, _ := store.Rollback(&types.ReqHash{Hash: hash})
assert.Equal(t, hash, actHash)
notExistHash, _ := store.Rollback(&types.ReqHash{Hash: drivers.EmptyRoot[:]})
assert.Nil(t, notExistHash)
}
var checkKVResult []*types.KeyValue
func checkKV(k, v []byte) bool {
checkKVResult = append(checkKVResult,
&types.KeyValue{Key: k, Value: v})
mlog.Debug("checkKV", "key", string(k), "value", string(v))
return false
}
func TestKvdbIterate(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*Store)
assert.NotNil(t, store)
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: []byte("mk1"), Value: []byte("v1")})
kv = append(kv, &types.KeyValue{Key: []byte("mk2"), Value: []byte("v2")})
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
}
hash, err := store.Set(datas, true)
assert.Nil(t, err)
store.IterateRangeByStateHash(hash, []byte("mk1"), []byte("mk3"), true, checkKV)
assert.Len(t, checkKVResult, 2)
assert.Equal(t, []byte("v1"), checkKVResult[0].Value)
assert.Equal(t, []byte("v2"), checkKVResult[1].Value)
}
type StatTool struct {
Amount int64
AmountActive int64
AmountFrozen int64
}
func (t *StatTool) AddItem(value [][]byte) {
for i := 0; i < len(value); i++ {
var acc types.Account
err := types.Decode(value[i], &acc)
if err != nil {
return
}
t.Amount += acc.Balance
t.Amount += acc.Frozen
t.AmountActive += acc.Balance
t.AmountFrozen += acc.Frozen
}
}
func (t *StatTool) Reset() {
t.Amount = 0
t.AmountActive = 0
t.AmountFrozen = 0
}
func genPrefixEdge(prefix []byte) (r []byte) {
for j := 0; j < len(prefix); j++ {
r = append(r, prefix[j])
}
i := len(prefix) - 1
for i >= 0 {
if r[i] < 0xff {
r[i]++
break
} else {
i--
}
}
return r
}
func TestIterateCallBack_Mode1(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var store_cfg = newStoreCfg(dir)
store := New(store_cfg, nil).(*Store)
assert.NotNil(t, store)
//mavldb.EnableMavlPrefix(true)
//defer mavldb.EnableMavlPrefix(false)
//var accountdb *account.DB
accountdb := account.NewCoinsAccount()
key := "mavl-coins-bty-exec-16htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp:1JmFaA6unrCFYEWPGRi7uuXY1KthTJxJEP"
prefix := "mavl-coins-bty-exec-"
execAddr1 := "16htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
addr := "1JmFaA6unrCFYEWPGRi7uuXY1KthTJxJEP"
var acc = &types.Account{
Currency: 0,
Balance: 1,
Frozen: 1,
Addr: addr,
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: accountdb.GetExecKVSet(execAddr1, acc),
Height: 0}
hash0, err := store.Set(datas, true)
assert.Nil(t, err)
execAddr2 := "26htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
datas = &types.StoreSet{
StateHash: hash0,
KV: accountdb.GetExecKVSet(execAddr2, acc),
Height: 1}
hash1, err := store.Set(datas, true)
assert.Nil(t, err)
execAddr3 := "36htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
datas = &types.StoreSet{
StateHash: hash1,
KV: accountdb.GetExecKVSet(execAddr3, acc),
Height: 2}
hash2, err := store.Set(datas, true)
assert.Nil(t, err)
fmt.Println("func TestIterateCallBack------test case1-------")
req := &types.StoreList{StateHash: hash2, Start: []byte(prefix), Suffix: []byte(addr), End: genPrefixEdge([]byte(prefix)), Count: 5, Mode: 1}
query := drivers.NewStoreListQuery(store, req)
resp2 := query.Run()
tool := &StatTool{}
tool.AddItem(resp2.Values)
assert.Equal(t, int64(3), resp2.Num)
assert.Equal(t, (0), len(resp2.NextKey))
assert.Equal(t, (3), len(resp2.Keys))
assert.Equal(t, (3), len(resp2.Values))
assert.Equal(t, int64(6), tool.Amount)
assert.Equal(t, int64(3), tool.AmountActive)
assert.Equal(t, int64(3), tool.AmountFrozen)
tool.Reset()
fmt.Println("func TestIterateCallBack------test case2-------")
resp1 := &types.StoreListReply{}
resp1.Suffix = []byte(addr)
resp1.Start = []byte(prefix)
resp1.End = genPrefixEdge([]byte(prefix))
resp1.Count = 5
resp1.Mode = 1
query = &drivers.StorelistQuery{StoreListReply: resp1}
store.IterateRangeByStateHash(hash1, resp1.Start, resp1.End, true, query.IterateCallBack)
tool.AddItem(resp1.Values)
assert.Equal(t, int64(2), resp1.Num)
assert.Equal(t, (0), len(resp1.NextKey))
assert.Equal(t, (2), len(resp1.Keys))
assert.Equal(t, (2), len(resp1.Values))
assert.Equal(t, int64(4), tool.Amount)
assert.Equal(t, int64(2), tool.AmountActive)
assert.Equal(t, int64(2), tool.AmountFrozen)
tool.Reset()
fmt.Println("func TestIterateCallBack------test case3-------")
resp0 := &types.StoreListReply{}
resp0.Suffix = []byte(addr)
resp0.Start = []byte(prefix)
resp0.End = genPrefixEdge([]byte(prefix))
resp0.Count = 5
resp0.Mode = 1
query = &drivers.StorelistQuery{StoreListReply: resp0}
store.IterateRangeByStateHash(hash0, resp0.Start, resp0.End, true, query.IterateCallBack)
tool.AddItem(resp0.Values)
assert.Equal(t, int64(1), resp0.Num)
assert.Equal(t, 0, len(resp0.NextKey))
assert.Equal(t, 1, len(resp0.Keys))
assert.Equal(t, 1, len(resp0.Values))
assert.Equal(t, int64(2), tool.Amount)
assert.Equal(t, int64(1), tool.AmountActive)
assert.Equal(t, int64(1), tool.AmountFrozen)
tool.Reset()
fmt.Println("func TestIterateCallBack------test case4-------")
resp := &types.StoreListReply{}
resp.Suffix = []byte(addr)
resp.Start = []byte(prefix)
resp.End = genPrefixEdge([]byte(prefix))
resp.Count = 1
resp.Mode = 1
query = &drivers.StorelistQuery{StoreListReply: resp}
store.IterateRangeByStateHash(hash2, resp.Start, resp.End, true, query.IterateCallBack)
tool.AddItem(resp.Values)
assert.Equal(t, int64(1), resp.Num)
assert.Equal(t, len([]byte(key)), len(resp.NextKey))
assert.Equal(t, (1), len(resp.Keys))
assert.Equal(t, (1), len(resp.Values))
assert.Equal(t, int64(2), tool.Amount)
assert.Equal(t, int64(1), tool.AmountActive)
assert.Equal(t, int64(1), tool.AmountFrozen)
tool.Reset()
fmt.Println("func TestIterateCallBack------test case5-------")
resp = &types.StoreListReply{}
resp.Suffix = []byte(addr)
resp.Start = []byte(prefix)
resp.End = genPrefixEdge([]byte(prefix))
resp.Count = 2
resp.Mode = 1
query = &drivers.StorelistQuery{StoreListReply: resp}
store.IterateRangeByStateHash(hash2, resp.Start, resp.End, true, query.IterateCallBack)
tool.AddItem(resp.Values)
assert.Equal(t, int64(2), resp.Num)
assert.Equal(t, len([]byte(key)), len(resp.NextKey))
assert.Equal(t, (2), len(resp.Keys))
assert.Equal(t, (2), len(resp.Values))
assert.Equal(t, int64(4), tool.Amount)
assert.Equal(t, int64(2), tool.AmountActive)
assert.Equal(t, int64(2), tool.AmountFrozen)
tool.Reset()
}
func TestIterateCallBack_Mode2(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var store_cfg = newStoreCfg(dir)
store := New(store_cfg, nil).(*Store)
assert.NotNil(t, store)
//mavldb.EnableMavlPrefix(true)
//defer mavldb.EnableMavlPrefix(false)
//var accountdb *account.DB
accountdb := account.NewCoinsAccount()
key := "mavl-coins-bty-exec-16htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp:1JmFaA6unrCFYEWPGRi7uuXY1KthTJxJEP"
prefix := "mavl-coins-bty-exec-"
execAddr1 := "16htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
addr := "1JmFaA6unrCFYEWPGRi7uuXY1KthTJxJEP"
var acc = &types.Account{
Currency: 0,
Balance: 1,
Frozen: 1,
Addr: addr,
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: accountdb.GetExecKVSet(execAddr1, acc),
Height: 0}
hash0, err := store.Set(datas, true)
assert.Nil(t, err)
execAddr2 := "26htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
datas = &types.StoreSet{
StateHash: hash0,
KV: accountdb.GetExecKVSet(execAddr2, acc),
Height: 1}
hash1, err := store.Set(datas, true)
assert.Nil(t, err)
execAddr3 := "36htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
datas = &types.StoreSet{
StateHash: hash1,
KV: accountdb.GetExecKVSet(execAddr3, acc),
Height: 2}
hash2, err := store.Set(datas, true)
assert.Nil(t, err)
fmt.Println("func TestIterateCallBack------test case1-------")
resp2 := &types.StoreListReply{}
resp2.Suffix = []byte(addr)
resp2.Start = []byte(prefix)
resp2.End = genPrefixEdge([]byte(prefix))
resp2.Count = 5
resp2.Mode = 2
query := &drivers.StorelistQuery{StoreListReply: resp2}
store.IterateRangeByStateHash(hash2, resp2.Start, nil, true, query.IterateCallBack)
tool := &StatTool{}
tool.AddItem(resp2.Values)
assert.Equal(t, int64(3), resp2.Num)
assert.Equal(t, (0), len(resp2.NextKey))
assert.Equal(t, (3), len(resp2.Keys))
assert.Equal(t, (3), len(resp2.Values))
assert.Equal(t, int64(6), tool.Amount)
assert.Equal(t, int64(3), tool.AmountActive)
assert.Equal(t, int64(3), tool.AmountFrozen)
tool.Reset()
fmt.Println("func TestIterateCallBack------test case2-------")
resp1 := &types.StoreListReply{}
resp1.Suffix = []byte(addr)
resp1.Start = []byte(prefix)
resp1.End = genPrefixEdge([]byte(prefix))
resp1.Count = 5
resp1.Mode = 2
query = &drivers.StorelistQuery{StoreListReply: resp1}
store.IterateRangeByStateHash(hash1, resp1.Start, resp1.End, true, query.IterateCallBack)
tool.AddItem(resp1.Values)
assert.Equal(t, int64(2), resp1.Num)
assert.Equal(t, (0), len(resp1.NextKey))
assert.Equal(t, (2), len(resp1.Keys))
assert.Equal(t, (2), len(resp1.Values))
assert.Equal(t, int64(4), tool.Amount)
assert.Equal(t, int64(2), tool.AmountActive)
assert.Equal(t, int64(2), tool.AmountFrozen)
tool.Reset()
fmt.Println("func TestIterateCallBack------test case3-------")
resp0 := &types.StoreListReply{}
resp0.Suffix = []byte(addr)
resp0.Start = []byte(prefix)
resp0.End = genPrefixEdge([]byte(prefix))
resp0.Count = 5
resp0.Mode = 2
query = &drivers.StorelistQuery{StoreListReply: resp0}
store.IterateRangeByStateHash(hash0, resp0.Start, nil, true, query.IterateCallBack)
tool.AddItem(resp0.Values)
assert.Equal(t, int64(1), resp0.Num)
assert.Equal(t, (0), len(resp0.NextKey))
assert.Equal(t, (1), len(resp0.Keys))
assert.Equal(t, (1), len(resp0.Values))
assert.Equal(t, int64(2), tool.Amount)
assert.Equal(t, int64(1), tool.AmountActive)
assert.Equal(t, int64(1), tool.AmountFrozen)
tool.Reset()
fmt.Println("func TestIterateCallBack------test case4-------")
resp := &types.StoreListReply{}
resp.Suffix = []byte(addr)
resp.Start = []byte(prefix)
resp.End = genPrefixEdge([]byte(prefix))
resp.Count = 1
resp.Mode = 2
query = &drivers.StorelistQuery{StoreListReply: resp}
store.IterateRangeByStateHash(hash2, resp.Start, nil, true, query.IterateCallBack)
tool.AddItem(resp.Values)
assert.Equal(t, int64(1), resp.Num)
assert.Equal(t, len([]byte(key)), len(resp.NextKey))
assert.Equal(t, (1), len(resp.Keys))
assert.Equal(t, (1), len(resp.Values))
assert.Equal(t, int64(2), tool.Amount)
assert.Equal(t, int64(1), tool.AmountActive)
assert.Equal(t, int64(1), tool.AmountFrozen)
tool.Reset()
fmt.Println("func TestIterateCallBack------test case5-------")
resp = &types.StoreListReply{}
resp.Suffix = []byte(addr)
resp.Start = []byte(prefix)
resp.End = genPrefixEdge([]byte(prefix))
resp.Count = 2
resp.Mode = 2
query = &drivers.StorelistQuery{StoreListReply: resp}
store.IterateRangeByStateHash(hash2, resp.Start, nil, true, query.IterateCallBack)
tool.AddItem(resp.Values)
assert.Equal(t, int64(2), resp.Num)
assert.Equal(t, len([]byte(key)), len(resp.NextKey))
assert.Equal(t, (2), len(resp.Keys))
assert.Equal(t, (2), len(resp.Values))
assert.Equal(t, int64(4), tool.Amount)
assert.Equal(t, int64(2), tool.AmountActive)
assert.Equal(t, int64(2), tool.AmountFrozen)
tool.Reset()
fmt.Println("func TestIterateCallBack------test case6-------")
resp = &types.StoreListReply{}
resp.End = []byte(addr)
resp.Start = []byte("mavl-coins-bty-exec-26htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp:")
resp.End = genPrefixEdge([]byte("mavl-coins-bty-exec-26htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp:"))
resp.Count = 1
resp.Mode = 2
query = &drivers.StorelistQuery{StoreListReply: resp}
store.IterateRangeByStateHash(hash2, resp.Start, resp.End, true, query.IterateCallBack)
tool.AddItem(resp.Values)
assert.Equal(t, int64(1), resp.Num)
assert.Equal(t, len([]byte(key)), len(resp.NextKey))
assert.Equal(t, (1), len(resp.Keys))
assert.Equal(t, (1), len(resp.Values))
assert.Equal(t, int64(2), tool.Amount)
assert.Equal(t, int64(1), tool.AmountActive)
assert.Equal(t, int64(1), tool.AmountFrozen)
tool.Reset()
}
func GetRandomString(length int) string {
return common.GetRandPrintString(20, length)
}
func TestKvdbIterateTimes(t *testing.T) {
checkKVResult = checkKVResult[:0]
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*Store)
assert.NotNil(t, store)
var kv []*types.KeyValue
var key string
var value string
for i := 0; i < 1000; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
kv = append(kv, &types.KeyValue{Key: []byte(key), Value: []byte(value)})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
}
hash, err := store.Set(datas, true)
assert.Nil(t, err)
start := time.Now()
store.IterateRangeByStateHash(hash, nil, nil, true, checkKV)
end := time.Now()
fmt.Println("mavl cost time is", end.Sub(start))
assert.Len(t, checkKVResult, 1000)
}
func BenchmarkGet(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*Store)
assert.NotNil(b, store)
mavldb.EnableMavlPrefix(true)
defer mavldb.EnableMavlPrefix(false)
var kv []*types.KeyValue
var keys [][]byte
var hash = drivers.EmptyRoot[:]
fmt.Println("N = ", b.N)
for i := 0; i < b.N; i++ {
key := GetRandomString(MaxKeylenth)
value := fmt.Sprintf("%s%d", key, i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(key), Value: []byte(value)})
if i%10000 == 0 {
datas := &types.StoreSet{StateHash: hash, KV: kv}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
kv = nil
}
}
if kv != nil {
datas := &types.StoreSet{StateHash: hash, KV: kv}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
}
start := time.Now()
b.ResetTimer()
for _, key := range keys {
getData := &types.StoreGet{
StateHash: hash,
Keys: [][]byte{key},
}
store.Get(getData)
}
end := time.Now()
fmt.Println("mavl BenchmarkGet cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
//这个用例测试Store.Get接口,一次调用会返回一组kvs(30对kv);前一个用例每次查询一个kv。
func BenchmarkStoreGetKvs4N(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*Store)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
kvnum := 30
for i := 0; i < kvnum; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(key))
kv = append(kv, &types.KeyValue{Key: []byte(key), Value: []byte(value)})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
}
hash, err := store.Set(datas, true)
assert.Nil(b, err)
getData := &types.StoreGet{
StateHash: hash,
Keys: keys,
}
start := time.Now()
b.ResetTimer()
for i := 0; i < b.N; i++ {
values := store.Get(getData)
assert.Len(b, values, kvnum)
}
end := time.Now()
fmt.Println("mavl BenchmarkStoreGetKvs4N cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
//这个用例测试Store.Get接口,一次调用会返回一组kvs(30对kv),数据构造模拟真实情况,N条数据、N次查询。
func BenchmarkStoreGetKvsForNN(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*Store)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(key), Value: []byte(value)})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
}
var hashes [][]byte
for i := 0; i < b.N; i++ {
datas.Height = int64(i)
value = fmt.Sprintf("vv%d", i)
for j := 0; j < 10; j++ {
datas.KV[j].Value = []byte(value)
}
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
datas.StateHash = hash
hashes = append(hashes, hash)
}
start := time.Now()
b.ResetTimer()
getData := &types.StoreGet{
StateHash: hashes[0],
Keys: keys,
}
for i := 0; i < b.N; i++ {
getData.StateHash = hashes[i]
store.Get(getData)
}
end := time.Now()
fmt.Println("mavl BenchmarkStoreGetKvsForNN cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
//这个用例测试Store.Get接口,一次调用会返回一组kvs(30对kv),数据构造模拟真实情况,预置10000条数据,重复调用10000次。
func BenchmarkStoreGetKvsFor10000(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*Store)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(key), Value: []byte(value)})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
}
var hashes [][]byte
blocks := 10000
times := 10000
start1 := time.Now()
for i := 0; i < blocks; i++ {
datas.Height = int64(i)
value = fmt.Sprintf("vv%d", i)
for j := 0; j < 30; j++ {
datas.KV[j].Value = []byte(value)
}
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
datas.StateHash = hash
hashes = append(hashes, hash)
}
end1 := time.Now()
start := time.Now()
b.ResetTimer()
getData := &types.StoreGet{
StateHash: hashes[0],
Keys: keys,
}
for i := 0; i < times; i++ {
getData.StateHash = hashes[i]
store.Get(getData)
}
end := time.Now()
fmt.Println("mavl BenchmarkStoreGetKvsFor10000 MemSet&Commit cost time is ", end1.Sub(start1), "blocks is", blocks)
fmt.Println("mavl BenchmarkStoreGetKvsFor10000 Get cost time is", end.Sub(start), "num is ", times, ",blocks is ", blocks)
b.StopTimer()
}
func BenchmarkSet(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*Store)
assert.NotNil(b, store)
mavldb.EnableMavlPrefix(true)
defer mavldb.EnableMavlPrefix(false)
var kv []*types.KeyValue
var keys [][]byte
var hash = drivers.EmptyRoot[:]
start := time.Now()
for i := 0; i < b.N; i++ {
key := GetRandomString(MaxKeylenth)
value := fmt.Sprintf("%s%d", key, i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(key), Value: []byte(value)})
if i%10000 == 0 {
datas := &types.StoreSet{StateHash: hash, KV: kv}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
kv = nil
}
}
if kv != nil {
datas := &types.StoreSet{StateHash: hash, KV: kv}
_, err = store.Set(datas, true)
assert.Nil(b, err)
}
end := time.Now()
fmt.Println("mavl BenchmarkSet cost time is", end.Sub(start), "num is", b.N)
}
//这个用例测试Store.Set接口,一次调用保存一组kvs(30对)到数据库中。
func BenchmarkStoreSetKvs(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*Store)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(key), Value: []byte(value)})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
}
start := time.Now()
b.ResetTimer()
for i := 0; i < b.N; i++ {
hash, err := store.Set(datas, true)
assert.Nil(b, err)
assert.NotNil(b, hash)
}
end := time.Now()
fmt.Println("mavl BenchmarkSet cost time is", end.Sub(start), "num is", b.N)
}
func BenchmarkMemSet(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*Store)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < b.N; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(key), Value: []byte(value)})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
}
start := time.Now()
b.ResetTimer()
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
assert.NotNil(b, hash)
end := time.Now()
fmt.Println("mavl BenchmarkMemSet cost time is", end.Sub(start), "num is", b.N)
}
//这个用例测试Store.MemSet接口,一次调用保存一组kvs(30对)到数据库中。
func BenchmarkStoreMemSet(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*Store)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(key), Value: []byte(value)})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
}
start := time.Now()
b.ResetTimer()
for i := 0; i < b.N; i++ {
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
assert.NotNil(b, hash)
}
end := time.Now()
fmt.Println("mavl BenchmarkMemSet cost time is", end.Sub(start), "num is", b.N)
}
func BenchmarkCommit(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*Store)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < b.N; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(key), Value: []byte(value)})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
}
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
start := time.Now()
b.ResetTimer()
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
end := time.Now()
fmt.Println("mavl BenchmarkCommit cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
//模拟真实的数据提交操作,数据之间的关系也保持正确(hash计算),统计的时间包括MemSet和Commit,可以减去之前用例中测试出来的MemSet的时间来估算Commit耗时
func BenchmarkStoreCommit(b *testing.B) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*Store)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(key), Value: []byte(value)})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
}
start := time.Now()
b.ResetTimer()
for i := 0; i < b.N; i++ {
datas.Height = int64(i)
value = fmt.Sprintf("vv%d", i)
for j := 0; j < 10; j++ {
datas.KV[j].Value = []byte(value)
}
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
datas.StateHash = hash
}
end := time.Now()
fmt.Println("mavl BenchmarkCommit cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment