diff --git a/CHANGELOG.md b/CHANGELOG.md index 2079ed817a7..825f34e63ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking Changes +* (store)[\#11152](https://github.com/cosmos/cosmos-sdk/pull/11152) Remove `keep-every` from pruning options. * [\#10950](https://github.com/cosmos/cosmos-sdk/pull/10950) Add `envPrefix` parameter to `cmd.Execute`. * (x/mint) [\#10441](https://github.com/cosmos/cosmos-sdk/pull/10441) The `NewAppModule` function now accepts an inflation calculation function as an argument. * [\#10295](https://github.com/cosmos/cosmos-sdk/pull/10295) Remove store type aliases from /types diff --git a/baseapp/abci.go b/baseapp/abci.go index 9f9a80b91fc..2742f5cf81e 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -709,22 +709,6 @@ func (app *BaseApp) GetBlockRetentionHeight(commitHeight int64) int64 { retentionHeight = commitHeight - cp.Evidence.MaxAgeNumBlocks } - // Define the state pruning offset, i.e. the block offset at which the - // underlying logical database is persisted to disk. - statePruningOffset := int64(app.cms.GetPruning().KeepEvery) - if statePruningOffset > 0 { - if commitHeight > statePruningOffset { - v := commitHeight - (commitHeight % statePruningOffset) - retentionHeight = minNonZero(retentionHeight, v) - } else { - // Hitting this case means we have persisting enabled but have yet to reach - // a height in which we persist state, so we return zero regardless of other - // conditions. Otherwise, we could end up pruning blocks without having - // any state committed to disk. - return 0 - } - } - if app.snapshotInterval > 0 && app.snapshotKeepRecent > 0 { v := commitHeight - int64((app.snapshotInterval * uint64(app.snapshotKeepRecent))) retentionHeight = minNonZero(retentionHeight, v) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 338c7c4d0cb..181bb6f7f5a 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -39,12 +39,11 @@ func TestGetBlockRentionHeight(t *testing.T) { "pruning iavl snapshot only": { bapp: baseapp.NewBaseApp( name, logger, db, - baseapp.SetPruning(sdk.PruningOptions{KeepEvery: 10000}), baseapp.SetMinRetainBlocks(1), ), maxAgeBlocks: 0, commitHeight: 499000, - expected: 490000, + expected: 498999, }, "pruning state sync snapshot only": { bapp: baseapp.NewBaseApp( @@ -69,7 +68,6 @@ func TestGetBlockRentionHeight(t *testing.T) { "pruning all conditions": { bapp: baseapp.NewBaseApp( name, logger, db, - baseapp.SetPruning(sdk.PruningOptions{KeepEvery: 10000}), baseapp.SetMinRetainBlocks(400000), baseapp.SetSnapshotInterval(50000), baseapp.SetSnapshotKeepRecent(3), ), @@ -80,7 +78,6 @@ func TestGetBlockRentionHeight(t *testing.T) { "no pruning due to no persisted state": { bapp: baseapp.NewBaseApp( name, logger, db, - baseapp.SetPruning(sdk.PruningOptions{KeepEvery: 10000}), baseapp.SetMinRetainBlocks(400000), baseapp.SetSnapshotInterval(50000), baseapp.SetSnapshotKeepRecent(3), ), @@ -91,7 +88,6 @@ func TestGetBlockRentionHeight(t *testing.T) { "disable pruning": { bapp: baseapp.NewBaseApp( name, logger, db, - baseapp.SetPruning(sdk.PruningOptions{KeepEvery: 10000}), baseapp.SetMinRetainBlocks(0), baseapp.SetSnapshotInterval(50000), baseapp.SetSnapshotKeepRecent(3), ), diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 0f1a1263f5c..20f90bb7360 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -292,16 +292,9 @@ func (app *BaseApp) init() error { // make sure the snapshot interval is a multiple of the pruning KeepEvery interval if app.snapshotManager != nil && app.snapshotInterval > 0 { - rms, ok := app.cms.(*rootmulti.Store) - if !ok { + if _, ok := app.cms.(*rootmulti.Store); !ok { return errors.New("state sync snapshots require a rootmulti store") } - pruningOpts := rms.GetPruning() - if pruningOpts.KeepEvery > 0 && app.snapshotInterval%pruningOpts.KeepEvery != 0 { - return fmt.Errorf( - "state sync snapshot interval %v must be a multiple of pruning keep every interval %v", - app.snapshotInterval, pruningOpts.KeepEvery) - } } return nil diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 18031a80fb6..d642c61581e 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -184,7 +184,6 @@ func setupBaseAppWithSnapshots(t *testing.T, blocks uint, blockTxs int, options app := setupBaseApp(t, append(options, baseapp.SetSnapshotStore(snapshotStore), baseapp.SetSnapshotInterval(snapshotInterval), - baseapp.SetPruning(sdk.PruningOptions{KeepEvery: 1}), routerOpt)...) app.InitChain(abci.RequestInitChain{}) @@ -480,7 +479,6 @@ func TestLoadVersionPruning(t *testing.T) { logger := log.NewNopLogger() pruningOptions := storetypes.PruningOptions{ KeepRecent: 2, - KeepEvery: 3, Interval: 1, } pruningOpt := baseapp.SetPruning(pruningOptions) diff --git a/go.sum b/go.sum index 445f0305359..211c612ffe1 100644 --- a/go.sum +++ b/go.sum @@ -288,7 +288,6 @@ github.com/cosmos/cosmos-sdk/errors v1.0.0-beta.2/go.mod h1:Gi7pzVRnvZ1N16JAXpLA github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= -github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= github.com/cosmos/iavl v0.17.3 h1:s2N819a2olOmiauVa0WAhoIJq9EhSXE9HDBAoR9k+8Y= github.com/cosmos/iavl v0.17.3/go.mod h1:prJoErZFABYZGDHka1R6Oay4z9PrNeFFiMKHDAMOi4w= github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76 h1:DdzS1m6o/pCqeZ8VOAit/gyATedRgjvkVI+UCrLpyuU= @@ -324,7 +323,6 @@ github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFM github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/badger/v3 v3.2103.2/go.mod h1:RHo4/GmYcKKh5Lxu63wLEMHJ70Pac2JqZRYGhlyAo2M= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= @@ -537,8 +535,6 @@ github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9 github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/certificate-transparency-go v1.1.1/go.mod h1:FDKqPvSXawb2ecErVRrD+nfy23RCzyl7eqVCEmlT1Zs= github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -1657,7 +1653,6 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211113001501-0c823b97ae02/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/server/config/config.go b/server/config/config.go index 803808b19a7..2c16c57baf1 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -31,7 +31,6 @@ type BaseConfig struct { 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 @@ -207,7 +206,6 @@ func DefaultConfig() *Config { InterBlockCache: true, Pruning: storetypes.PruningOptionDefault, PruningKeepRecent: "0", - PruningKeepEvery: "0", PruningInterval: "0", MinRetainBlocks: 0, IndexEvents: make([]string, 0), @@ -265,7 +263,6 @@ func GetConfig(v *viper.Viper) Config { InterBlockCache: v.GetBool("inter-block-cache"), Pruning: v.GetString("pruning"), PruningKeepRecent: v.GetString("pruning-keep-recent"), - PruningKeepEvery: v.GetString("pruning-keep-every"), PruningInterval: v.GetString("pruning-interval"), HaltHeight: v.GetUint64("halt-height"), HaltTime: v.GetUint64("halt-time"), diff --git a/server/config/toml.go b/server/config/toml.go index 1fe85947049..1da82593ce6 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -22,15 +22,14 @@ 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 +# default: the last 362880 states are kept, 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' +# custom: allow pruning options to be manually specified through 'pruning-keep-recent' 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 @@ -202,7 +201,7 @@ enable-unsafe-cors = {{ .GRPCWeb.EnableUnsafeCORS }} [state-sync] # snapshot-interval specifies the block interval at which local state sync snapshots are -# taken (0 to disable). Must be a multiple of pruning-keep-every. +# taken (0 to disable). snapshot-interval = {{ .StateSync.SnapshotInterval }} # snapshot-keep-recent specifies the number of recent snapshots to keep and serve (0 to keep all). diff --git a/server/pruning.go b/server/pruning.go index 44aa4ba2d1e..fb2ba34e8f8 100644 --- a/server/pruning.go +++ b/server/pruning.go @@ -24,7 +24,6 @@ func GetPruningOptionsFromFlags(appOpts types.AppOptions) (storetypes.PruningOpt case storetypes.PruningOptionCustom: opts := storetypes.NewPruningOptions( cast.ToUint64(appOpts.Get(FlagPruningKeepRecent)), - cast.ToUint64(appOpts.Get(FlagPruningKeepEvery)), cast.ToUint64(appOpts.Get(FlagPruningInterval)), ) diff --git a/server/pruning_test.go b/server/pruning_test.go index baef9b59163..8b4af74cad8 100644 --- a/server/pruning_test.go +++ b/server/pruning_test.go @@ -31,14 +31,12 @@ func TestGetPruningOptionsFromFlags(t *testing.T) { v := viper.New() v.Set(FlagPruning, types.PruningOptionCustom) v.Set(FlagPruningKeepRecent, 1234) - v.Set(FlagPruningKeepEvery, 4321) v.Set(FlagPruningInterval, 10) return v }, expectedOptions: types.PruningOptions{ KeepRecent: 1234, - KeepEvery: 4321, Interval: 10, }, }, diff --git a/server/start.go b/server/start.go index 9bd6c5ef39f..45d7c920ea5 100644 --- a/server/start.go +++ b/server/start.go @@ -48,7 +48,6 @@ const ( FlagPruning = "pruning" FlagPruningKeepRecent = "pruning-keep-recent" - FlagPruningKeepEvery = "pruning-keep-every" FlagPruningInterval = "pruning-interval" FlagIndexEvents = "index-events" FlagMinRetainBlocks = "min-retain-blocks" @@ -77,15 +76,15 @@ func StartCmd(appCreator types.AppCreator, defaultNodeHome string) *cobra.Comman 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 or alternatively with '--pruning-keep-recent', -'pruning-keep-every', and 'pruning-interval' together. +Pruning options can be provided via the '--pruning' flag or alternatively with '--pruning-keep-recent' +and 'pruning-interval' together. 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 +default: the last 362880 states are kept, 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' +custom: allow pruning options to be manually specified through 'pruning-keep-recent' 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 @@ -147,7 +146,6 @@ which accepts a path for the resulting pprof file. cmd.Flags().Bool(FlagTrace, false, "Provide full stack traces for errors in ABCI Log") 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')") cmd.Flags().Uint(FlagInvCheckPeriod, 0, "Assert registered invariants every N blocks") cmd.Flags().Uint64(FlagMinRetainBlocks, 0, "Minimum block height offset during ABCI commit to prune Tendermint blocks") diff --git a/snapshots/README.md b/snapshots/README.md index dfe2d66e724..8f6e526f083 100644 --- a/snapshots/README.md +++ b/snapshots/README.md @@ -28,9 +28,7 @@ filesystem under `/data/snapshots/`, with metadata in a LevelDB datab Snapshots are taken asynchronously, i.e. new blocks will be applied concurrently with snapshots being taken. This is possible because IAVL supports querying -immutable historical heights. However, this requires `state-sync.snapshot-interval` -to be a multiple of `pruning-keep-every`, to prevent a height from being removed -while it is being snapshotted. +immutable historical heights. When a remote node is state syncing, Tendermint calls the ABCI method `ListSnapshots` to list available local snapshots and `LoadSnapshotChunk` to diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 0a98fb0bcf7..bd73c2fb774 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -428,14 +428,7 @@ func (rs *Store) Commit() types.CommitID { // be pruned, where pruneHeight = (commitHeight - 1) - KeepRecent. if int64(rs.pruningOpts.KeepRecent) < previousHeight { pruneHeight := previousHeight - int64(rs.pruningOpts.KeepRecent) - // We consider this height to be pruned iff: - // - // - KeepEvery is zero as that means that all heights should be pruned. - // - KeepEvery % (height - KeepRecent) != 0 as that means the height is not - // a 'snapshot' height. - if rs.pruningOpts.KeepEvery == 0 || pruneHeight%int64(rs.pruningOpts.KeepEvery) != 0 { - rs.pruneHeights = append(rs.pruneHeights, pruneHeight) - } + rs.pruneHeights = append(rs.pruneHeights, pruneHeight) } // batch prune if the current height is a pruning interval height diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 6f8111f1351..7cd09bfeea0 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -329,7 +329,6 @@ func TestMultiStoreRestart(t *testing.T) { db := dbm.NewMemDB() pruning := types.PruningOptions{ KeepRecent: 2, - KeepEvery: 3, Interval: 1, } multi := newMultiStoreWithMounts(db, pruning) @@ -488,9 +487,9 @@ func TestMultiStore_Pruning(t *testing.T) { }{ {"prune nothing", 10, types.PruneNothing, nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, {"prune everything", 10, types.PruneEverything, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9}, []int64{10}}, - {"prune some; no batch", 10, types.NewPruningOptions(2, 3, 1), []int64{1, 2, 4, 5, 7}, []int64{3, 6, 8, 9, 10}}, - {"prune some; small batch", 10, types.NewPruningOptions(2, 3, 3), []int64{1, 2, 4, 5}, []int64{3, 6, 7, 8, 9, 10}}, - {"prune some; large batch", 10, types.NewPruningOptions(2, 3, 11), nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, + {"prune some; no batch", 10, types.NewPruningOptions(2, 1), []int64{1, 2, 4, 5, 7}, []int64{3, 6, 8, 9, 10}}, + {"prune some; small batch", 10, types.NewPruningOptions(2, 3), []int64{1, 2, 4, 5}, []int64{3, 6, 7, 8, 9, 10}}, + {"prune some; large batch", 10, types.NewPruningOptions(2, 11), nil, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, } for _, tc := range testCases { @@ -520,7 +519,7 @@ func TestMultiStore_Pruning(t *testing.T) { func TestMultiStore_PruningRestart(t *testing.T) { db := dbm.NewMemDB() - ms := newMultiStoreWithMounts(db, types.NewPruningOptions(2, 3, 11)) + ms := newMultiStoreWithMounts(db, types.NewPruningOptions(2, 11)) require.NoError(t, ms.LoadLatestVersion()) // Commit enough to build up heights to prune, where on the next block we should @@ -534,13 +533,13 @@ func TestMultiStore_PruningRestart(t *testing.T) { // ensure we've persisted the current batch of heights to prune to the store's DB ph, err := getPruningHeights(ms.db) require.NoError(t, err) - require.Equal(t, pruneHeights, ph) + require.Equal(t, []int64{1, 2, 3, 4, 5, 6, 7}, ph) // "restart" - ms = newMultiStoreWithMounts(db, types.NewPruningOptions(2, 3, 11)) + ms = newMultiStoreWithMounts(db, types.NewPruningOptions(2, 11)) err = ms.LoadLatestVersion() require.NoError(t, err) - require.Equal(t, pruneHeights, ms.pruneHeights) + require.Equal(t, []int64{1, 2, 3, 4, 5, 6, 7}, ms.pruneHeights) // commit one more block and ensure the heights have been pruned ms.Commit() diff --git a/store/types/pruning.go b/store/types/pruning.go index 4419acb950d..774f806fe1c 100644 --- a/store/types/pruning.go +++ b/store/types/pruning.go @@ -1,6 +1,8 @@ package types -import "fmt" +import ( + "fmt" +) // Pruning option string constants const ( @@ -16,15 +18,15 @@ var ( // at every 10th height. The last 362880 heights are kept assuming the typical // block time is 5s and typical unbonding period is 21 days. If these values // do not match the applications' requirements, use the "custom" option. - PruneDefault = NewPruningOptions(362880, 100, 10) + PruneDefault = NewPruningOptions(362880, 10) // PruneEverything defines a pruning strategy where all committed heights are // deleted, storing only the current height and where to-be pruned heights are // pruned at every 10th height. - PruneEverything = NewPruningOptions(0, 0, 10) + PruneEverything = NewPruningOptions(0, 10) // PruneNothing defines a pruning strategy where all heights are kept on disk. - PruneNothing = NewPruningOptions(0, 1, 0) + PruneNothing = NewPruningOptions(0, 0) ) // PruningOptions defines the pruning strategy used when determining which @@ -33,30 +35,20 @@ type PruningOptions struct { // KeepRecent defines how many recent heights to keep on disk. KeepRecent uint64 - // KeepEvery defines how many offset heights are kept on disk past KeepRecent. - KeepEvery uint64 - // Interval defines when the pruned heights are removed from disk. Interval uint64 } -func NewPruningOptions(keepRecent, keepEvery, interval uint64) PruningOptions { +func NewPruningOptions(keepRecent, interval uint64) PruningOptions { return PruningOptions{ KeepRecent: keepRecent, - KeepEvery: keepEvery, Interval: interval, } } func (po PruningOptions) Validate() error { - if po.KeepEvery == 0 && po.Interval == 0 { - return fmt.Errorf("invalid 'Interval' when pruning everything: %d", po.Interval) - } - if po.KeepEvery == 1 && po.Interval != 0 { // prune nothing - return fmt.Errorf("invalid 'Interval' when pruning nothing: %d", po.Interval) - } - if po.KeepEvery > 1 && po.Interval == 0 { - return fmt.Errorf("invalid 'Interval' when pruning: %d", po.Interval) + if po.KeepRecent > 0 && po.Interval == 0 { + return fmt.Errorf("invalid 'Interval' when pruning recent heights: %d", po.Interval) } return nil diff --git a/store/types/pruning_test.go b/store/types/pruning_test.go index 2b88905ee8d..d524aea70ed 100644 --- a/store/types/pruning_test.go +++ b/store/types/pruning_test.go @@ -9,20 +9,17 @@ import ( func TestPruningOptions_Validate(t *testing.T) { testCases := []struct { keepRecent uint64 - keepEvery uint64 interval uint64 expectErr bool }{ - {100, 500, 10, false}, // default - {0, 0, 10, false}, // everything - {0, 1, 0, false}, // nothing - {0, 10, 10, false}, - {100, 0, 0, true}, // invalid interval - {0, 1, 5, true}, // invalid interval + {100, 10, false}, // default + {0, 10, false}, // everything + {0, 0, false}, // nothing + {100, 0, true}, // invalid interval } for _, tc := range testCases { - po := NewPruningOptions(tc.keepRecent, tc.keepEvery, tc.interval) + po := NewPruningOptions(tc.keepRecent, tc.interval) err := po.Validate() require.Equal(t, tc.expectErr, err != nil, "options: %v, err: %s", po, err) } diff --git a/store/v2/multi/store.go b/store/v2/multi/store.go index 08555da03c6..5ad1e33fa6a 100644 --- a/store/v2/multi/store.go +++ b/store/v2/multi/store.go @@ -521,35 +521,40 @@ func (s *Store) Commit() types.CommitID { // Substores read-lock this mutex; lock to prevent racey invalidation of underlying txns s.mtx.Lock() defer s.mtx.Unlock() + // Determine the target version versions, err := s.stateDB.Versions() if err != nil { panic(err) } + target := versions.Last() + 1 if target > math.MaxInt64 { panic(ErrMaximumHeight) } + // Fast forward to initial version if needed if s.InitialVersion != 0 && target < s.InitialVersion { target = s.InitialVersion } + cid, err := s.commit(target) if err != nil { panic(err) } + // Prune if necessary previous := cid.Version - 1 - if s.Pruning.KeepEvery != 1 && s.Pruning.Interval != 0 && cid.Version%int64(s.Pruning.Interval) == 0 { + if s.Pruning.Interval != 0 && cid.Version%int64(s.Pruning.Interval) == 0 { // The range of newly prunable versions lastPrunable := previous - int64(s.Pruning.KeepRecent) firstPrunable := lastPrunable - int64(s.Pruning.Interval) + for version := firstPrunable; version <= lastPrunable; version++ { - if s.Pruning.KeepEvery == 0 || version%int64(s.Pruning.KeepEvery) != 0 { - s.stateDB.DeleteVersion(uint64(version)) - if s.StateCommitmentDB != nil { - s.StateCommitmentDB.DeleteVersion(uint64(version)) - } + s.stateDB.DeleteVersion(uint64(version)) + + if s.StateCommitmentDB != nil { + s.StateCommitmentDB.DeleteVersion(uint64(version)) } } } diff --git a/store/v2/multi/store_test.go b/store/v2/multi/store_test.go index 435277fcbae..49904829aee 100644 --- a/store/v2/multi/store_test.go +++ b/store/v2/multi/store_test.go @@ -398,8 +398,8 @@ func TestPruning(t *testing.T) { types.PruningOptions kept []uint64 }{ - {types.PruningOptions{2, 4, 10}, []uint64{4, 8, 9, 10}}, - {types.PruningOptions{0, 4, 10}, []uint64{4, 8, 10}}, + {types.PruningOptions{2, 10}, []uint64{8, 9, 10}}, + {types.PruningOptions{0, 10}, []uint64{10}}, {types.PruneEverything, []uint64{10}}, {types.PruneNothing, []uint64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}, } @@ -423,6 +423,7 @@ func TestPruning(t *testing.T) { for _, db := range dbs { versions, err := db.Versions() require.NoError(t, err) + kept := sliceToSet(tc.kept) for v := uint64(1); v <= 10; v++ { _, has := kept[v] @@ -434,19 +435,21 @@ func TestPruning(t *testing.T) { // Test pruning interval // Save up to 20th version while checking history at specific version checkpoints testCheckPoints := map[uint64][]uint64{ - 5: []uint64{1, 2, 3, 4, 5}, - 10: []uint64{5, 10}, - 15: []uint64{5, 10, 11, 12, 13, 14, 15}, - 20: []uint64{5, 10, 15, 20}, + 5: {1, 2, 3, 4, 5}, + 10: {10}, + 15: {10, 11, 12, 13, 14, 15}, + 20: {20}, } + db := memdb.NewDB() opts := simpleStoreConfig(t) - opts.Pruning = types.PruningOptions{0, 5, 10} + opts.Pruning = types.PruningOptions{0, 10} store, err := NewStore(db, opts) require.NoError(t, err) for i := byte(1); i <= 20; i++ { store.GetKVStore(skey_1).Set([]byte{i}, []byte{i}) + cid := store.Commit() latest := uint64(i) require.Equal(t, latest, uint64(cid.Version)) @@ -455,8 +458,10 @@ func TestPruning(t *testing.T) { if !has { continue } + versions, err := db.Versions() require.NoError(t, err) + keptMap := sliceToSet(kept) for v := uint64(1); v <= latest; v++ { _, has := keptMap[v]