Skip to content

Commit

Permalink
Merge PR #6475: Pruning Refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderbez committed Jun 24, 2020
1 parent 4e2f207 commit e20c2f5
Show file tree
Hide file tree
Showing 20 changed files with 527 additions and 307 deletions.
54 changes: 33 additions & 21 deletions baseapp/baseapp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) {

func checkStore(t *testing.T, db dbm.DB, ver int64, storeKey string, k, v []byte) {
rs := rootmulti.NewStore(db)
rs.SetPruning(store.PruneSyncable)
rs.SetPruning(store.PruneDefault)
key := sdk.NewKVStoreKey(storeKey)
rs.MountStoreWithDB(key, store.StoreTypeIAVL, nil)
err := rs.LoadLatestVersion()
Expand Down Expand Up @@ -273,7 +273,7 @@ func TestSetLoader(t *testing.T) {

func TestAppVersionSetterGetter(t *testing.T) {
logger := defaultLogger()
pruningOpt := SetPruning(store.PruneSyncable)
pruningOpt := SetPruning(store.PruneDefault)
db := dbm.NewMemDB()
name := t.Name()
app := NewBaseApp(name, logger, db, nil, pruningOpt)
Expand Down Expand Up @@ -329,8 +329,9 @@ func TestLoadVersionInvalid(t *testing.T) {
func TestLoadVersionPruning(t *testing.T) {
logger := log.NewNopLogger()
pruningOptions := store.PruningOptions{
KeepEvery: 2,
SnapshotEvery: 6,
KeepRecent: 2,
KeepEvery: 3,
Interval: 1,
}
pruningOpt := SetPruning(pruningOptions)
db := dbm.NewMemDB()
Expand All @@ -351,6 +352,7 @@ func TestLoadVersionPruning(t *testing.T) {
require.Equal(t, int64(0), lastHeight)
require.Equal(t, emptyCommitID, lastID)

<<<<<<< HEAD
// execute a block
header := abci.Header{Height: 1}
app.BeginBlock(abci.RequestBeginBlock{Header: header})
Expand All @@ -374,28 +376,32 @@ func TestLoadVersionPruning(t *testing.T) {
err = app.LoadLatestVersion(capKey)
require.Nil(t, err)
testLoadVersionHelper(t, app, int64(2), commitID2)
=======
var lastCommitID sdk.CommitID
>>>>>>> 4716260a6... Merge PR #6475: Pruning Refactor

// Commit seven blocks, of which 7 (latest) is kept in addition to 6, 5
// (keep recent) and 3 (keep every).
for i := int64(1); i <= 7; i++ {
app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: i}})
res := app.Commit()
lastCommitID = sdk.CommitID{Version: i, Hash: res.Data}
}

// re-execute block 3 and check it is same CommitID
header = abci.Header{Height: 3}
app.BeginBlock(abci.RequestBeginBlock{Header: header})
res = app.Commit()
recommitID3 := sdk.CommitID{Version: 3, Hash: res.Data}
require.Equal(t, commitID3, recommitID3, "Commits of identical blocks not equal after reload")

// execute a block, collect commit ID
header = abci.Header{Height: 4}
app.BeginBlock(abci.RequestBeginBlock{Header: header})
res = app.Commit()
commitID4 := sdk.CommitID{Version: 4, Hash: res.Data}
for _, v := range []int64{1, 2, 4} {
_, err = app.cms.CacheMultiStoreWithVersion(v)
require.Error(t, err)
}

// execute a block
header = abci.Header{Height: 5}
app.BeginBlock(abci.RequestBeginBlock{Header: header})
res = app.Commit()
for _, v := range []int64{3, 5, 6, 7} {
_, err = app.cms.CacheMultiStoreWithVersion(v)
require.NoError(t, err)
}

// reload with LoadLatestVersion, check it loads last flushed version
// reload with LoadLatestVersion, check it loads last version
app = NewBaseApp(name, logger, db, nil, pruningOpt)
app.MountStores(capKey)
<<<<<<< HEAD
err = app.LoadLatestVersion(capKey)
require.Nil(t, err)
testLoadVersionHelper(t, app, int64(4), commitID4)
Expand All @@ -406,6 +412,12 @@ func TestLoadVersionPruning(t *testing.T) {
app.MountStores(capKey)
err = app.LoadVersion(2, capKey)
require.NotNil(t, err)
=======

err = app.LoadLatestVersion()
require.Nil(t, err)
testLoadVersionHelper(t, app, int64(7), lastCommitID)
>>>>>>> 4716260a6... Merge PR #6475: Pruning Refactor
}

func testLoadVersionHelper(t *testing.T, app *BaseApp, expectedHeight int64, expectedID sdk.CommitID) {
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
go 1.13

module github.com/cosmos/cosmos-sdk

require (
Expand Down Expand Up @@ -31,6 +33,4 @@ require (
gopkg.in/yaml.v2 v2.3.0
)

go 1.13

replace github.com/keybase/go-keychain => github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4
20 changes: 13 additions & 7 deletions server/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"fmt"
"strings"

"github.com/cosmos/cosmos-sdk/store"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)

Expand All @@ -19,6 +19,11 @@ type BaseConfig struct {
// specified in this config (e.g. 0.25token1;0.0001token2).
MinGasPrices string `mapstructure:"minimum-gas-prices"`

Pruning string `mapstructure:"pruning"`
PruningKeepRecent string `mapstructure:"pruning-keep-recent"`
PruningKeepEvery string `mapstructure:"pruning-keep-every"`
PruningInterval string `mapstructure:"pruning-interval"`

// HaltHeight contains a non-zero block height at which a node will gracefully
// halt and shutdown that can be used to assist upgrades and testing.
//
Expand All @@ -34,8 +39,6 @@ type BaseConfig struct {

// InterBlockCache enables inter-block caching.
InterBlockCache bool `mapstructure:"inter-block-cache"`

Pruning string `mapstructure:"pruning"`
}

// Config defines the server's top level configuration
Expand Down Expand Up @@ -73,10 +76,13 @@ func (c *Config) GetMinGasPrices() sdk.DecCoins {
// DefaultConfig returns server's default configuration.
func DefaultConfig() *Config {
return &Config{
BaseConfig{
MinGasPrices: defaultMinGasPrices,
InterBlockCache: true,
Pruning: store.PruningStrategySyncable,
BaseConfig: BaseConfig{
MinGasPrices: defaultMinGasPrices,
InterBlockCache: true,
Pruning: storetypes.PruningOptionDefault,
PruningKeepRecent: "0",
PruningKeepEvery: "0",
PruningInterval: "0",
},
}
}
17 changes: 11 additions & 6 deletions server/config/toml.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ const defaultConfigTemplate = `# This is a TOML config file.
# specified in this config (e.g. 0.25token1;0.0001token2).
minimum-gas-prices = "{{ .BaseConfig.MinGasPrices }}"
# default: the last 100 states are kept in addition to every 500th state; pruning at 10 block intervals
# nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node)
# everything: all saved states will be deleted, storing only the current state; pruning at 10 block intervals
# custom: allow pruning options to be manually specified through 'pruning-keep-recent', 'pruning-keep-every', and 'pruning-interval'
pruning = "{{ .BaseConfig.Pruning }}"
# These are applied if and only if the pruning strategy is custom.
pruning-keep-recent = "{{ .BaseConfig.PruningKeepRecent }}"
pruning-keep-every = "{{ .BaseConfig.PruningKeepEvery }}"
pruning-interval = "{{ .BaseConfig.PruningInterval }}"
# HaltHeight contains a non-zero block height at which a node will gracefully
# halt and shutdown that can be used to assist upgrades and testing.
#
Expand All @@ -33,12 +44,6 @@ halt-time = {{ .BaseConfig.HaltTime }}
# InterBlockCache enables inter-block caching.
inter-block-cache = {{ .BaseConfig.InterBlockCache }}
# Pruning sets the pruning strategy: syncable, nothing, everything
# syncable: only those states not needed for state syncing will be deleted (keeps last 100 + every 10000th)
# nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node)
# everything: all saved states will be deleted, storing only the current state
pruning = "{{ .BaseConfig.Pruning }}"
`

var configTemplate *template.Template
Expand Down
38 changes: 38 additions & 0 deletions server/pruning.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package server

import (
"fmt"
"strings"

"github.com/spf13/viper"

"github.com/cosmos/cosmos-sdk/store"
"github.com/cosmos/cosmos-sdk/store/types"
)

// GetPruningOptionsFromFlags parses command flags and returns the correct
// PruningOptions. If a pruning strategy is provided, that will be parsed and
// returned, otherwise, it is assumed custom pruning options are provided.
func GetPruningOptionsFromFlags() (types.PruningOptions, error) {
strategy := strings.ToLower(viper.GetString(FlagPruning))

switch strategy {
case types.PruningOptionDefault, types.PruningOptionNothing, types.PruningOptionEverything:
return types.NewPruningOptionsFromString(strategy), nil

case types.PruningOptionCustom:
opts := types.NewPruningOptions(
viper.GetUint64(FlagPruningKeepRecent),
viper.GetUint64(FlagPruningKeepEvery), viper.GetUint64(FlagPruningInterval),
)

if err := opts.Validate(); err != nil {
return opts, fmt.Errorf("invalid custom pruning options: %w", err)
}

return opts, nil

default:
return store.PruningOptions{}, fmt.Errorf("unknown pruning strategy %s", strategy)
}
}
64 changes: 64 additions & 0 deletions server/pruning_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package server

import (
"testing"

"github.com/spf13/viper"
"github.com/stretchr/testify/require"

"github.com/cosmos/cosmos-sdk/store/types"
)

func TestGetPruningOptionsFromFlags(t *testing.T) {
tests := []struct {
name string
initParams func()
expectedOptions types.PruningOptions
wantErr bool
}{
{
name: FlagPruning,
initParams: func() {
viper.Set(FlagPruning, types.PruningOptionNothing)
},
expectedOptions: types.PruneNothing,
},
{
name: "custom pruning options",
initParams: func() {
viper.Set(FlagPruning, types.PruningOptionCustom)
viper.Set(FlagPruningKeepRecent, 1234)
viper.Set(FlagPruningKeepEvery, 4321)
viper.Set(FlagPruningInterval, 10)
},
expectedOptions: types.PruningOptions{
KeepRecent: 1234,
KeepEvery: 4321,
Interval: 10,
},
},
{
name: types.PruningOptionDefault,
initParams: func() {},
expectedOptions: types.PruneDefault,
},
}

for _, tt := range tests {
tt := tt

t.Run(tt.name, func(j *testing.T) {
viper.Reset()
viper.SetDefault(FlagPruning, types.PruningOptionDefault)
tt.initParams()

opts, err := GetPruningOptionsFromFlags()
if tt.wantErr {
require.Error(t, err)
return
}

require.Equal(t, tt.expectedOptions, opts)
})
}
}
28 changes: 23 additions & 5 deletions server/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,26 @@ import (
"github.com/tendermint/tendermint/p2p"
pvm "github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/proxy"

storetypes "github.com/cosmos/cosmos-sdk/store/types"
)

// Tendermint full-node start flags
const (
flagWithTendermint = "with-tendermint"
flagAddress = "address"
flagTraceStore = "trace-store"
flagPruning = "pruning"
flagCPUProfile = "cpu-profile"
FlagMinGasPrices = "minimum-gas-prices"
FlagHaltHeight = "halt-height"
FlagHaltTime = "halt-time"
FlagInterBlockCache = "inter-block-cache"
FlagUnsafeSkipUpgrades = "unsafe-skip-upgrades"

FlagPruning = "pruning"
FlagPruningKeepRecent = "pruning-keep-recent"
FlagPruningKeepEvery = "pruning-keep-every"
FlagPruningInterval = "pruning-interval"
)

// StartCmd runs the service passed in, either stand-alone or in-process with
Expand All @@ -41,11 +47,15 @@ func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command {
Long: `Run the full node application with Tendermint in or out of process. By
default, the application will run with Tendermint in process.
Pruning options can be provided via the '--pruning' flag. The options are as follows:
Pruning options can be provided via the '--pruning' flag or alternatively with '--pruning-keep-recent',
'pruning-keep-every', and 'pruning-interval' together.
syncable: only those states not needed for state syncing will be deleted (flushes every 100th to disk and keeps every 10000th)
For '--pruning' the options are as follows:
default: the last 100 states are kept in addition to every 500th state; pruning at 10 block intervals
nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node)
everything: all saved states will be deleted, storing only the current state
everything: all saved states will be deleted, storing only the current state; pruning at 10 block intervals
custom: allow pruning options to be manually specified through 'pruning-keep-recent', 'pruning-keep-every', and 'pruning-interval'
Node halting configurations exist in the form of two flags: '--halt-height' and '--halt-time'. During
the ABCI Commit phase, the node will check if the current block height is greater than or equal to
Expand Down Expand Up @@ -73,7 +83,6 @@ which accepts a path for the resulting pprof file.
cmd.Flags().Bool(flagWithTendermint, true, "Run abci app embedded in-process with tendermint")
cmd.Flags().String(flagAddress, "tcp://0.0.0.0:26658", "Listen address")
cmd.Flags().String(flagTraceStore, "", "Enable KVStore tracing to an output file")
cmd.Flags().String(flagPruning, "syncable", "Pruning strategy: syncable, nothing, everything")
cmd.Flags().String(
FlagMinGasPrices, "",
"Minimum gas prices to accept for transactions; Any fee in a tx must meet this minimum (e.g. 0.01photino;0.0001stake)",
Expand All @@ -84,6 +93,15 @@ which accepts a path for the resulting pprof file.
cmd.Flags().Bool(FlagInterBlockCache, true, "Enable inter-block caching")
cmd.Flags().String(flagCPUProfile, "", "Enable CPU profiling and write to the provided file")

cmd.Flags().String(FlagPruning, storetypes.PruningOptionDefault, "Pruning strategy (default|nothing|everything|custom)")
cmd.Flags().Uint64(FlagPruningKeepRecent, 0, "Number of recent heights to keep on disk (ignored if pruning is not 'custom')")
cmd.Flags().Uint64(FlagPruningKeepEvery, 0, "Offset heights to keep on disk after 'keep-every' (ignored if pruning is not 'custom')")
cmd.Flags().Uint64(FlagPruningInterval, 0, "Height interval at which pruned heights are removed from disk (ignored if pruning is not 'custom')")
viper.BindPFlag(FlagPruning, cmd.Flags().Lookup(FlagPruning))
viper.BindPFlag(FlagPruningKeepRecent, cmd.Flags().Lookup(FlagPruningKeepRecent))
viper.BindPFlag(FlagPruningKeepEvery, cmd.Flags().Lookup(FlagPruningKeepEvery))
viper.BindPFlag(FlagPruningInterval, cmd.Flags().Lookup(FlagPruningInterval))

// add support for all Tendermint-specific command line options
tcmd.AddNodeFlags(cmd)
return cmd
Expand Down
6 changes: 3 additions & 3 deletions store/cache/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestGetOrSetStoreCache(t *testing.T) {
sKey := types.NewKVStoreKey("test")
tree, err := iavl.NewMutableTree(db, 100)
require.NoError(t, err)
store := iavlstore.UnsafeNewStore(tree, types.PruneNothing)
store := iavlstore.UnsafeNewStore(tree)
store2 := mngr.GetStoreCache(sKey, store)

require.NotNil(t, store2)
Expand All @@ -34,7 +34,7 @@ func TestUnwrap(t *testing.T) {
sKey := types.NewKVStoreKey("test")
tree, err := iavl.NewMutableTree(db, 100)
require.NoError(t, err)
store := iavlstore.UnsafeNewStore(tree, types.PruneNothing)
store := iavlstore.UnsafeNewStore(tree)
_ = mngr.GetStoreCache(sKey, store)

require.Equal(t, store, mngr.Unwrap(sKey))
Expand All @@ -48,7 +48,7 @@ func TestStoreCache(t *testing.T) {
sKey := types.NewKVStoreKey("test")
tree, err := iavl.NewMutableTree(db, 100)
require.NoError(t, err)
store := iavlstore.UnsafeNewStore(tree, types.PruneNothing)
store := iavlstore.UnsafeNewStore(tree)
kvStore := mngr.GetStoreCache(sKey, store)

for i := uint(0); i < cache.DefaultCommitKVStoreCacheSize*2; i++ {
Expand Down
Loading

0 comments on commit e20c2f5

Please sign in to comment.