Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: snapshot and pruning functionality #140

Merged
merged 41 commits into from
Mar 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
f348dc1
refactor snapshot config
p0mvn Mar 13, 2022
9b34767
create pruning package and move pruning options into it
p0mvn Mar 13, 2022
f45b027
introduce snapshot options struct, similar to pruning options
p0mvn Mar 13, 2022
1468df4
implement pruning manager and unit test
p0mvn Mar 15, 2022
8e37e0d
snapshot inteval must be equal to pruning keep recent
p0mvn Mar 15, 2022
8ad567e
multistore PruneHeight stub and unit test with mocks
p0mvn Mar 15, 2022
49b269c
implement the barebones logic for pruning keep-every after snapshot a…
p0mvn Mar 16, 2022
e6be907
rename multistore PruneHeight to PruneSnapshotHeight and implement it
p0mvn Mar 16, 2022
4a78172
add logs
p0mvn Mar 16, 2022
19831f8
fix unit tests
p0mvn Mar 16, 2022
fa53501
refactor baseapp_test.go
p0mvn Mar 16, 2022
de9c030
refactor pruning options.go
p0mvn Mar 16, 2022
4df3ffd
finalize TestSnapshotWithPruning and ensure all unit tests pass
p0mvn Mar 16, 2022
ed59a43
implement GetSnapshotBlockRetentionHeights
p0mvn Mar 16, 2022
02b4c03
add pruning types and constructors to sdk types package
p0mvn Mar 16, 2022
b658d9b
clean up pruning and snaphot error messages and names
p0mvn Mar 16, 2022
e318a90
remove dependency on pruning types from baseapp_test.go
p0mvn Mar 16, 2022
1a78b81
further clean up baseapp_test.go
p0mvn Mar 16, 2022
fff4055
improve comment in options.go
p0mvn Mar 16, 2022
4487e79
fix comment in pruning/manager.go
p0mvn Mar 16, 2022
6e70a75
remove junk file
p0mvn Mar 16, 2022
24478ee
remove pruning-keep-every and use snapshot-interval instead
p0mvn Mar 17, 2022
d0ceed6
remveo all references to pruning-keep-every
p0mvn Mar 17, 2022
8733ac7
allow snapshot-keep-recent of 0, add more unit tests
p0mvn Mar 17, 2022
0b62de4
bug fixes related to prune-everything
p0mvn Mar 17, 2022
9d34297
add unit tests for app.init(), remove validation from snapshot manage…
p0mvn Mar 17, 2022
835cf32
clean up
p0mvn Mar 17, 2022
157bb38
optimize deletion from list while iterating
p0mvn Mar 17, 2022
e8e94cf
golangci-lint run --fix
p0mvn Mar 17, 2022
183b8e6
Update store/types/store.go
p0mvn Mar 18, 2022
3775b3e
restore config tests
p0mvn Mar 18, 2022
db8661c
rename Type to PruningStrategy, prefix strategy names with "Pruning"
p0mvn Mar 18, 2022
3be7f3d
change Snapshot to SnapshotIfApplicable
p0mvn Mar 21, 2022
c9d827c
Update snapshots/manager.go
p0mvn Mar 21, 2022
197552f
change log level in SnapshotIfApplicable
p0mvn Mar 21, 2022
948387d
add comments for stores in snapshot manager
p0mvn Mar 21, 2022
4f48a83
check for snapshots enabled with non-multi store
p0mvn Mar 22, 2022
56b4781
add documentation in snapshots/README.md
p0mvn Mar 22, 2022
bdb1112
get latest version directly from the db in Snapshot() to avoid data race
p0mvn Mar 22, 2022
a619355
update documentation in pruning/README.md and snapshots/README.md
p0mvn Mar 22, 2022
bc941a0
update iavl to v6 with the data race fix
p0mvn Mar 22, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 20 additions & 50 deletions baseapp/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,9 +334,7 @@ func (app *BaseApp) Commit() (res abci.ResponseCommit) {
app.halt()
}

if app.snapshotInterval > 0 && uint64(header.Height)%app.snapshotInterval == 0 {
go app.snapshot(header.Height)
}
app.snapshotManager.SnapshotIfApplicable(header.Height)

app.logger.Info("commited - baseapp", "height", commitID.Version, "commit_hash", commitID.Hash, "retain_height", retainHeight)
return abci.ResponseCommit{
Expand Down Expand Up @@ -367,36 +365,6 @@ func (app *BaseApp) halt() {
os.Exit(0)
}

// snapshot takes a snapshot of the current state and prunes any old snapshottypes.
func (app *BaseApp) snapshot(height int64) {
if app.snapshotManager == nil {
app.logger.Info("snapshot manager not configured")
return
}

app.logger.Info("creating state snapshot", "height", height)

snapshot, err := app.snapshotManager.Create(uint64(height))
if err != nil {
app.logger.Error("failed to create state snapshot", "height", height, "err", err)
return
}

app.logger.Info("completed state snapshot", "height", height, "format", snapshot.Format)

if app.snapshotKeepRecent > 0 {
app.logger.Debug("pruning state snapshots")

pruned, err := app.snapshotManager.Prune(app.snapshotKeepRecent)
if err != nil {
app.logger.Error("Failed to prune state snapshots", "err", err)
return
}

app.logger.Debug("pruned state snapshots", "pruned", pruned)
}
}

// Query implements the ABCI interface. It delegates to CommitMultiStore if it
// implements Queryable.
func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
Expand Down Expand Up @@ -707,25 +675,27 @@ 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.snapshotManager != nil {
ValarDragon marked this conversation as resolved.
Show resolved Hide resolved
// Define the state pruning offset, i.e. the block offset at which the
// underlying logical database is persisted to disk.
statePruningOffset := int64(app.snapshotManager.GetInterval())
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)
snapshotRetentionHeights := app.snapshotManager.GetSnapshotBlockRetentionHeights()
if snapshotRetentionHeights > 0 {
retentionHeight = minNonZero(retentionHeight, commitHeight-snapshotRetentionHeights)
}
}

v := commitHeight - int64(app.minRetainBlocks)
Expand Down
29 changes: 17 additions & 12 deletions baseapp/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,24 @@ import (
"fmt"
"testing"

"github.com/cosmos/cosmos-sdk/snapshots"
snaphotsTestUtil "github.com/cosmos/cosmos-sdk/testutil/snapshots"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
tmprototypes "github.com/tendermint/tendermint/proto/tendermint/types"
dbm "github.com/tendermint/tm-db"

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

func TestGetBlockRentionHeight(t *testing.T) {
logger := defaultLogger()
db := dbm.NewMemDB()
name := t.Name()

snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), snaphotsTestUtil.GetTempDir(t))
require.NoError(t, err)

testCases := map[string]struct {
bapp *BaseApp
maxAgeBlocks int64
Expand All @@ -38,18 +43,18 @@ func TestGetBlockRentionHeight(t *testing.T) {
"pruning iavl snapshot only": {
bapp: NewBaseApp(
name, logger, db, nil,
SetPruning(sdk.PruningOptions{KeepEvery: 10000}),
SetPruning(sdk.NewPruningOptions(sdk.Nothing)),
SetMinRetainBlocks(1),
SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(10000, 1)),
),
maxAgeBlocks: 0,
commitHeight: 499000,
expected: 490000,
expected: 489000,
Copy link
Member Author

@p0mvn p0mvn Mar 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has changed because now we use snapshot-interval in place of pruning-keep-every. Although I added sdk.NewSnapshotOptions(10000, 1)), snapshot interval is used as another strategy for calculating the block retention height and it just takes precedence over the old strategy used by this unit test.

},
"pruning state sync snapshot only": {
bapp: NewBaseApp(
name, logger, db, nil,
SetSnapshotInterval(50000),
SetSnapshotKeepRecent(3),
SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(50000, 3)),
SetMinRetainBlocks(1),
),
maxAgeBlocks: 0,
Expand All @@ -68,9 +73,9 @@ func TestGetBlockRentionHeight(t *testing.T) {
"pruning all conditions": {
bapp: NewBaseApp(
name, logger, db, nil,
SetPruning(sdk.PruningOptions{KeepEvery: 10000}),
SetPruning(sdk.NewCustomPruningOptions(0, 0)),
SetMinRetainBlocks(400000),
SetSnapshotInterval(50000), SetSnapshotKeepRecent(3),
SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(50000, 3)),
),
maxAgeBlocks: 362880,
commitHeight: 499000,
Expand All @@ -79,9 +84,9 @@ func TestGetBlockRentionHeight(t *testing.T) {
"no pruning due to no persisted state": {
bapp: NewBaseApp(
name, logger, db, nil,
SetPruning(sdk.PruningOptions{KeepEvery: 10000}),
SetPruning(sdk.NewCustomPruningOptions(0, 0)),
SetMinRetainBlocks(400000),
SetSnapshotInterval(50000), SetSnapshotKeepRecent(3),
SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(50000, 3)),
),
maxAgeBlocks: 362880,
commitHeight: 10000,
Expand All @@ -90,9 +95,9 @@ func TestGetBlockRentionHeight(t *testing.T) {
"disable pruning": {
bapp: NewBaseApp(
name, logger, db, nil,
SetPruning(sdk.PruningOptions{KeepEvery: 10000}),
SetPruning(sdk.NewCustomPruningOptions(0, 0)),
SetMinRetainBlocks(0),
SetSnapshotInterval(50000), SetSnapshotKeepRecent(3),
SetSnapshot(snapshotStore, sdk.NewSnapshotOptions(50000, 3)),
),
maxAgeBlocks: 362880,
commitHeight: 499000,
Expand Down
23 changes: 7 additions & 16 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,7 @@ type BaseApp struct { // nolint: maligned
fauxMerkleMode bool // if true, IAVL MountStores uses MountStoresDB for simulation speed.

// manages snapshots, i.e. dumps of app state at certain intervals
snapshotManager *snapshots.Manager
snapshotInterval uint64 // block interval between state sync snapshots
snapshotKeepRecent uint32 // recent state sync snapshots to keep
snapshotManager *snapshots.Manager

// volatile states:
//
Expand Down Expand Up @@ -303,20 +301,13 @@ func (app *BaseApp) init() error {
app.setCheckState(tmproto.Header{})
app.Seal()

// 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 {
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)
}
rms, ok := app.cms.(*rootmulti.Store)
if !ok && app.snapshotManager != nil {
return errors.New("state sync snapshots require a rootmulti store")
}
if err := rms.GetPruning().Validate(); err != nil {
return err
}

return nil
}

Expand Down
Loading