Skip to content

Commit

Permalink
fix(snapshots): raise the per snapshot item limit (#304)
Browse files Browse the repository at this point in the history
Increases the snapshot per item size limit when restoring from state-sync
  • Loading branch information
mhofman authored and JeancarloBarrios committed Sep 28, 2024
1 parent e7ad651 commit 331ef2a
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 5 deletions.
23 changes: 23 additions & 0 deletions store/snapshots/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,29 @@ import (
storetypes "cosmossdk.io/store/types"
)

const (
opNone operation = ""
opSnapshot operation = "snapshot"
opPrune operation = "prune"
opRestore operation = "restore"

chunkBufferSize = 4

// snapshotMaxItemSize limits the size of both KVStore entries and snapshot
// extension payloads during a state-sync restore.
// Unexported so copied in manager_test.go for testing
snapshotMaxItemSize = int(512e6)
)

// operation represents a Manager operation. Only one operation can be in progress at a time.
type operation string

// restoreDone represents the result of a restore operation.
type restoreDone struct {
complete bool // if true, restore completed successfully (not prematurely)
err error // if non-nil, restore errored
}

// Manager manages snapshot and restore operations for an app, making sure only a single
// long-running operation is in progress at any given time, and provides convenience methods
// mirroring the ABCI interface.
Expand Down
87 changes: 82 additions & 5 deletions store/snapshots/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package snapshots_test

import (
"errors"
"io"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -237,12 +238,88 @@ func TestManager_Restore(t *testing.T) {
require.NoError(t, err)
}

func TestManager_TakeError(t *testing.T) {
snapshotter := &mockErrorSnapshotter{}
store, err := snapshots.NewStore(coretesting.NewMemDB(), GetTempDir(t))
const snapshotMaxItemSize = int(512e6) // Copied from github.com/cosmos/cosmos-sdk/snapshots

func TestManager_RestoreLargeItem(t *testing.T) {
store := setupStore(t)
target := &mockSnapshotter{}
extSnapshotter := newExtSnapshotter(0)
manager := snapshots.NewManager(store, target)
err := manager.RegisterExtensions(extSnapshotter)
require.NoError(t, err)
manager := snapshots.NewManager(store, opts, snapshotter, nil, log.NewNopLogger())

_, err = manager.Create(1)
largeItem := make([]byte, snapshotMaxItemSize)

// The protobuf wrapper introduces extra bytes
adjustedSize := 2*snapshotMaxItemSize - (&types.SnapshotItem{
Item: &types.SnapshotItem_ExtensionPayload{
ExtensionPayload: &types.SnapshotExtensionPayload{
Payload: largeItem,
},
},
}).Size()
largeItem = largeItem[:adjustedSize]
expectItems := [][]byte{largeItem}

chunks := snapshotItems(expectItems, newExtSnapshotter(1))

// Starting a restore works
err = manager.Restore(types.Snapshot{
Height: 3,
Format: 2,
Hash: []byte{1, 2, 3},
Chunks: 1,
Metadata: types.Metadata{ChunkHashes: checksums(chunks)},
})
require.NoError(t, err)

// Feeding the chunks should work
for i, chunk := range chunks {
done, err := manager.RestoreChunk(chunk)
require.NoError(t, err)
if i == len(chunks)-1 {
assert.True(t, done)
} else {
assert.False(t, done)
}
}

assert.Equal(t, expectItems, target.items)
assert.Equal(t, 1, len(extSnapshotter.state))
}

func TestManager_CannotRestoreTooLargeItem(t *testing.T) {
store := setupStore(t)
target := &mockSnapshotter{}
extSnapshotter := newExtSnapshotter(0)
manager := snapshots.NewManager(store, target)
err := manager.RegisterExtensions(extSnapshotter)
require.NoError(t, err)

// The protobuf wrapper introduces extra bytes
largeItem := make([]byte, snapshotMaxItemSize)
expectItems := [][]byte{largeItem}

chunks := snapshotItems(expectItems, newExtSnapshotter(1))

// Starting a restore works
err = manager.Restore(types.Snapshot{
Height: 3,
Format: 2,
Hash: []byte{1, 2, 3},
Chunks: 1,
Metadata: types.Metadata{ChunkHashes: checksums(chunks)},
})
require.NoError(t, err)

// Feeding the chunks fails
for _, chunk := range chunks {
_, err = manager.RestoreChunk(chunk)

if err != nil {
break
}
}
require.Error(t, err)
require.True(t, errors.Is(err, io.ErrShortBuffer))
}

0 comments on commit 331ef2a

Please sign in to comment.