Merge PR #5579: Fix Restart application issue
This commit is contained in:
+43
-31
@@ -28,13 +28,13 @@ const (
|
||||
// cacheMultiStore which is for cache-wrapping other MultiStores. It implements
|
||||
// the CommitMultiStore interface.
|
||||
type Store struct {
|
||||
db dbm.DB
|
||||
lastCommitID types.CommitID
|
||||
pruningOpts types.PruningOptions
|
||||
storesParams map[types.StoreKey]storeParams
|
||||
stores map[types.StoreKey]types.CommitKVStore
|
||||
keysByName map[string]types.StoreKey
|
||||
lazyLoading bool
|
||||
db dbm.DB
|
||||
lastCommitInfo commitInfo
|
||||
pruningOpts types.PruningOptions
|
||||
storesParams map[types.StoreKey]storeParams
|
||||
stores map[types.StoreKey]types.CommitKVStore
|
||||
keysByName map[string]types.StoreKey
|
||||
lazyLoading bool
|
||||
|
||||
traceWriter io.Writer
|
||||
traceContext types.TraceContext
|
||||
@@ -146,11 +146,12 @@ func (rs *Store) LoadVersion(ver int64) error {
|
||||
|
||||
func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error {
|
||||
infos := make(map[string]storeInfo)
|
||||
var lastCommitID types.CommitID
|
||||
var cInfo commitInfo
|
||||
|
||||
// load old data if we are not version 0
|
||||
if ver != 0 {
|
||||
cInfo, err := getCommitInfo(rs.db, ver)
|
||||
var err error
|
||||
cInfo, err = getCommitInfo(rs.db, ver)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -159,7 +160,6 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error {
|
||||
for _, storeInfo := range cInfo.StoreInfos {
|
||||
infos[storeInfo.Name] = storeInfo
|
||||
}
|
||||
lastCommitID = cInfo.CommitID()
|
||||
}
|
||||
|
||||
// load each Store (note this doesn't panic on unmounted keys now)
|
||||
@@ -197,7 +197,7 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error {
|
||||
}
|
||||
}
|
||||
|
||||
rs.lastCommitID = lastCommitID
|
||||
rs.lastCommitInfo = cInfo
|
||||
rs.stores = newStores
|
||||
|
||||
return nil
|
||||
@@ -281,29 +281,26 @@ func (rs *Store) TracingEnabled() bool {
|
||||
|
||||
// Implements Committer/CommitStore.
|
||||
func (rs *Store) LastCommitID() types.CommitID {
|
||||
return rs.lastCommitID
|
||||
return rs.lastCommitInfo.CommitID()
|
||||
}
|
||||
|
||||
// Implements Committer/CommitStore.
|
||||
func (rs *Store) Commit() types.CommitID {
|
||||
|
||||
// Commit stores.
|
||||
version := rs.lastCommitID.Version + 1
|
||||
commitInfo := commitStores(version, rs.stores)
|
||||
version := rs.lastCommitInfo.Version + 1
|
||||
rs.lastCommitInfo = commitStores(version, rs.stores)
|
||||
|
||||
// Need to update atomically.
|
||||
batch := rs.db.NewBatch()
|
||||
defer batch.Close()
|
||||
setCommitInfo(batch, version, commitInfo)
|
||||
setLatestVersion(batch, version)
|
||||
batch.Write()
|
||||
// write CommitInfo to disk only if this version was flushed to disk
|
||||
if rs.pruningOpts.FlushVersion(version) {
|
||||
flushCommitInfo(rs.db, version, rs.lastCommitInfo)
|
||||
}
|
||||
|
||||
// Prepare for next version.
|
||||
commitID := types.CommitID{
|
||||
Version: version,
|
||||
Hash: commitInfo.Hash(),
|
||||
Hash: rs.lastCommitInfo.Hash(),
|
||||
}
|
||||
rs.lastCommitID = commitID
|
||||
return commitID
|
||||
}
|
||||
|
||||
@@ -412,7 +409,6 @@ func (rs *Store) getStoreByName(name string) types.Store {
|
||||
// Ie. `req.Path` here is `/<substore>/<path>`, and trimmed to `/<path>` for the substore.
|
||||
// TODO: add proof for `multistore -> substore`.
|
||||
func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery {
|
||||
// Query just routes this to a substore.
|
||||
path := req.Path
|
||||
storeName, subpath, err := parsePath(path)
|
||||
if err != nil {
|
||||
@@ -441,9 +437,18 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery {
|
||||
return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "proof is unexpectedly empty; ensure height has not been pruned"))
|
||||
}
|
||||
|
||||
commitInfo, errMsg := getCommitInfo(rs.db, res.Height)
|
||||
if errMsg != nil {
|
||||
return sdkerrors.QueryResult(err)
|
||||
// If the request's height is the latest height we've committed, then utilize
|
||||
// the store's lastCommitInfo as this commit info may not be flushed to disk.
|
||||
// Otherwise, we query for the commit info from disk.
|
||||
var commitInfo commitInfo
|
||||
|
||||
if res.Height == rs.lastCommitInfo.Version {
|
||||
commitInfo = rs.lastCommitInfo
|
||||
} else {
|
||||
commitInfo, err = getCommitInfo(rs.db, res.Height)
|
||||
if err != nil {
|
||||
return sdkerrors.QueryResult(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Restore origin path and append proof op.
|
||||
@@ -626,26 +631,22 @@ func commitStores(version int64, storeMap map[types.StoreKey]types.CommitKVStore
|
||||
storeInfos := make([]storeInfo, 0, len(storeMap))
|
||||
|
||||
for key, store := range storeMap {
|
||||
// Commit
|
||||
commitID := store.Commit()
|
||||
|
||||
if store.GetStoreType() == types.StoreTypeTransient {
|
||||
continue
|
||||
}
|
||||
|
||||
// Record CommitID
|
||||
si := storeInfo{}
|
||||
si.Name = key.Name()
|
||||
si.Core.CommitID = commitID
|
||||
// si.Core.StoreType = store.GetStoreType()
|
||||
storeInfos = append(storeInfos, si)
|
||||
}
|
||||
|
||||
ci := commitInfo{
|
||||
return commitInfo{
|
||||
Version: version,
|
||||
StoreInfos: storeInfos,
|
||||
}
|
||||
return ci
|
||||
}
|
||||
|
||||
// Gets commitInfo from disk.
|
||||
@@ -676,3 +677,14 @@ func setCommitInfo(batch dbm.Batch, version int64, cInfo commitInfo) {
|
||||
cInfoKey := fmt.Sprintf(commitInfoKeyFmt, version)
|
||||
batch.Set([]byte(cInfoKey), cInfoBytes)
|
||||
}
|
||||
|
||||
// flushCommitInfo flushes a commitInfo for given version to the DB. Note, this
|
||||
// needs to happen atomically.
|
||||
func flushCommitInfo(db dbm.DB, version int64, cInfo commitInfo) {
|
||||
batch := db.NewBatch()
|
||||
defer batch.Close()
|
||||
|
||||
setCommitInfo(batch, version, cInfo)
|
||||
setLatestVersion(batch, version)
|
||||
batch.Write()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package rootmulti
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -53,7 +54,7 @@ func TestStoreMount(t *testing.T) {
|
||||
|
||||
func TestCacheMultiStoreWithVersion(t *testing.T) {
|
||||
var db dbm.DB = dbm.NewMemDB()
|
||||
ms := newMultiStoreWithMounts(db, types.PruneSyncable)
|
||||
ms := newMultiStoreWithMounts(db, types.PruneNothing)
|
||||
err := ms.LoadLatestVersion()
|
||||
require.Nil(t, err)
|
||||
|
||||
@@ -90,7 +91,7 @@ func TestCacheMultiStoreWithVersion(t *testing.T) {
|
||||
|
||||
func TestHashStableWithEmptyCommit(t *testing.T) {
|
||||
var db dbm.DB = dbm.NewMemDB()
|
||||
ms := newMultiStoreWithMounts(db, types.PruneSyncable)
|
||||
ms := newMultiStoreWithMounts(db, types.PruneNothing)
|
||||
err := ms.LoadLatestVersion()
|
||||
require.Nil(t, err)
|
||||
|
||||
@@ -114,7 +115,7 @@ func TestHashStableWithEmptyCommit(t *testing.T) {
|
||||
|
||||
func TestMultistoreCommitLoad(t *testing.T) {
|
||||
var db dbm.DB = dbm.NewMemDB()
|
||||
store := newMultiStoreWithMounts(db, types.PruneSyncable)
|
||||
store := newMultiStoreWithMounts(db, types.PruneNothing)
|
||||
err := store.LoadLatestVersion()
|
||||
require.Nil(t, err)
|
||||
|
||||
@@ -139,7 +140,7 @@ func TestMultistoreCommitLoad(t *testing.T) {
|
||||
}
|
||||
|
||||
// Load the latest multistore again and check version.
|
||||
store = newMultiStoreWithMounts(db, types.PruneSyncable)
|
||||
store = newMultiStoreWithMounts(db, types.PruneNothing)
|
||||
err = store.LoadLatestVersion()
|
||||
require.Nil(t, err)
|
||||
commitID = getExpectedCommitID(store, nCommits)
|
||||
@@ -152,7 +153,7 @@ func TestMultistoreCommitLoad(t *testing.T) {
|
||||
|
||||
// Load an older multistore and check version.
|
||||
ver := nCommits - 1
|
||||
store = newMultiStoreWithMounts(db, types.PruneSyncable)
|
||||
store = newMultiStoreWithMounts(db, types.PruneNothing)
|
||||
err = store.LoadVersion(ver)
|
||||
require.Nil(t, err)
|
||||
commitID = getExpectedCommitID(store, ver)
|
||||
@@ -289,6 +290,88 @@ func TestParsePath(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestMultiStoreRestart(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
pruning := types.PruningOptions{
|
||||
KeepEvery: 3,
|
||||
SnapshotEvery: 6,
|
||||
}
|
||||
multi := newMultiStoreWithMounts(db, pruning)
|
||||
err := multi.LoadLatestVersion()
|
||||
require.Nil(t, err)
|
||||
|
||||
initCid := multi.LastCommitID()
|
||||
|
||||
k, v := "wind", "blows"
|
||||
k2, v2 := "water", "flows"
|
||||
k3, v3 := "fire", "burns"
|
||||
|
||||
for i := 1; i < 3; i++ {
|
||||
// Set and commit data in one store.
|
||||
store1 := multi.getStoreByName("store1").(types.KVStore)
|
||||
store1.Set([]byte(k), []byte(fmt.Sprintf("%s:%d", v, i)))
|
||||
|
||||
// ... and another.
|
||||
store2 := multi.getStoreByName("store2").(types.KVStore)
|
||||
store2.Set([]byte(k2), []byte(fmt.Sprintf("%s:%d", v2, i)))
|
||||
|
||||
// ... and another.
|
||||
store3 := multi.getStoreByName("store3").(types.KVStore)
|
||||
store3.Set([]byte(k3), []byte(fmt.Sprintf("%s:%d", v3, i)))
|
||||
|
||||
multi.Commit()
|
||||
|
||||
cinfo, err := getCommitInfo(multi.db, int64(i))
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t, commitInfo{}, cinfo)
|
||||
}
|
||||
|
||||
// Set and commit data in one store.
|
||||
store1 := multi.getStoreByName("store1").(types.KVStore)
|
||||
store1.Set([]byte(k), []byte(fmt.Sprintf("%s:%d", v, 3)))
|
||||
|
||||
// ... and another.
|
||||
store2 := multi.getStoreByName("store2").(types.KVStore)
|
||||
store2.Set([]byte(k2), []byte(fmt.Sprintf("%s:%d", v2, 3)))
|
||||
|
||||
multi.Commit()
|
||||
|
||||
flushedCinfo, err := getCommitInfo(multi.db, 3)
|
||||
require.Nil(t, err)
|
||||
require.NotEqual(t, initCid, flushedCinfo, "CID is different after flush to disk")
|
||||
|
||||
// ... and another.
|
||||
store3 := multi.getStoreByName("store3").(types.KVStore)
|
||||
store3.Set([]byte(k3), []byte(fmt.Sprintf("%s:%d", v3, 3)))
|
||||
|
||||
multi.Commit()
|
||||
|
||||
postFlushCinfo, err := getCommitInfo(multi.db, 4)
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t, commitInfo{}, postFlushCinfo, "Commit changed after in-memory commit")
|
||||
|
||||
multi = newMultiStoreWithMounts(db, pruning)
|
||||
err = multi.LoadLatestVersion()
|
||||
require.Nil(t, err)
|
||||
|
||||
reloadedCid := multi.LastCommitID()
|
||||
require.Equal(t, flushedCinfo.CommitID(), reloadedCid, "Reloaded CID is not the same as last flushed CID")
|
||||
|
||||
// Check that store1 and store2 retained date from 3rd commit
|
||||
store1 = multi.getStoreByName("store1").(types.KVStore)
|
||||
val := store1.Get([]byte(k))
|
||||
require.Equal(t, []byte(fmt.Sprintf("%s:%d", v, 3)), val, "Reloaded value not the same as last flushed value")
|
||||
|
||||
store2 = multi.getStoreByName("store2").(types.KVStore)
|
||||
val2 := store2.Get([]byte(k2))
|
||||
require.Equal(t, []byte(fmt.Sprintf("%s:%d", v2, 3)), val2, "Reloaded value not the same as last flushed value")
|
||||
|
||||
// Check that store3 still has data from last commit even though update happened on 2nd commit
|
||||
store3 = multi.getStoreByName("store3").(types.KVStore)
|
||||
val3 := store3.Get([]byte(k3))
|
||||
require.Equal(t, []byte(fmt.Sprintf("%s:%d", v3, 2)), val3, "Reloaded value not the same as last flushed value")
|
||||
}
|
||||
|
||||
func TestMultiStoreQuery(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
multi := newMultiStoreWithMounts(db, types.PruneNothing)
|
||||
|
||||
Reference in New Issue
Block a user