Skip to content

Commit

Permalink
etcdutl: Fix snapshot restore memory alloc issue
Browse files Browse the repository at this point in the history
When running the snapshot command, allow receiving an initial memory map
allocation for the database, avoiding future memory allocation issues.

Co-authored-by: Benjamin Wang <[email protected]>
Co-authored-by: Fatih USTA <[email protected]>
Signed-off-by: Ivan Valdes <[email protected]>
  • Loading branch information
3 people committed Feb 13, 2024
1 parent d69adf4 commit 4f66aa9
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 8 deletions.
7 changes: 6 additions & 1 deletion etcdutl/etcdutl/snapshot_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (

"go.etcd.io/etcd/etcdutl/v3/snapshot"
"go.etcd.io/etcd/pkg/v3/cobrautl"
"go.etcd.io/etcd/server/v3/storage/backend"
"go.etcd.io/etcd/server/v3/storage/datadir"
)

Expand All @@ -38,6 +39,7 @@ var (
restorePeerURLs string
restoreName string
skipHashCheck bool
initialMmapSize = backend.InitialMmapSize
markCompacted bool
revisionBump uint64
)
Expand Down Expand Up @@ -77,6 +79,7 @@ func NewSnapshotRestoreCommand() *cobra.Command {
cmd.Flags().StringVar(&restorePeerURLs, "initial-advertise-peer-urls", defaultInitialAdvertisePeerURLs, "List of this member's peer URLs to advertise to the rest of the cluster")
cmd.Flags().StringVar(&restoreName, "name", defaultName, "Human-readable name for this member")
cmd.Flags().BoolVar(&skipHashCheck, "skip-hash-check", false, "Ignore snapshot integrity hash value (required if copied from data directory)")
cmd.Flags().Uint64Var(&initialMmapSize, "initial-memory-map-size", initialMmapSize, "Initial memory map size of the database in bytes. It uses the default value if not defined or defined to 0")
cmd.Flags().Uint64Var(&revisionBump, "bump-revision", 0, "How much to increase the latest revision after restore")
cmd.Flags().BoolVar(&markCompacted, "mark-compacted", false, "Mark the latest revision after restore as the point of scheduled compaction (required if --bump-revision > 0, disallowed otherwise)")

Expand Down Expand Up @@ -104,7 +107,7 @@ func SnapshotStatusCommandFunc(cmd *cobra.Command, args []string) {

func snapshotRestoreCommandFunc(_ *cobra.Command, args []string) {
SnapshotRestoreCommandFunc(restoreCluster, restoreClusterToken, restoreDataDir, restoreWalDir,
restorePeerURLs, restoreName, skipHashCheck, revisionBump, markCompacted, args)
restorePeerURLs, restoreName, skipHashCheck, initialMmapSize, revisionBump, markCompacted, args)
}

func SnapshotRestoreCommandFunc(restoreCluster string,
Expand All @@ -114,6 +117,7 @@ func SnapshotRestoreCommandFunc(restoreCluster string,
restorePeerURLs string,
restoreName string,
skipHashCheck bool,
initialMmapSize uint64,
revisionBump uint64,
markCompacted bool,
args []string) {
Expand Down Expand Up @@ -149,6 +153,7 @@ func SnapshotRestoreCommandFunc(restoreCluster string,
InitialCluster: restoreCluster,
InitialClusterToken: restoreClusterToken,
SkipHashCheck: skipHashCheck,
InitialMmapSize: initialMmapSize,
RevisionBump: revisionBump,
MarkCompacted: markCompacted,
}); err != nil {
Expand Down
16 changes: 12 additions & 4 deletions etcdutl/snapshot/v3_snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ type v3Manager struct {
snapDir string
cl *membership.RaftCluster

skipHashCheck bool
skipHashCheck bool
initialMmapSize uint64
}

// hasChecksum returns "true" if the file size "n"
Expand Down Expand Up @@ -204,6 +205,9 @@ type RestoreConfig struct {
// (required if copied from data directory).
SkipHashCheck bool

// InitialMmapSize is the database initial memory map size.
InitialMmapSize uint64

// RevisionBump is the amount to increase the latest revision after restore,
// to allow administrators to trick clients into thinking that revision never decreased.
// If 0, revision bumping is skipped.
Expand Down Expand Up @@ -233,6 +237,7 @@ func (s *v3Manager) Restore(cfg RestoreConfig) error {
PeerURLs: pURLs,
InitialPeerURLsMap: ics,
InitialClusterToken: cfg.InitialClusterToken,
InitialMmapSize: cfg.InitialMmapSize,

Check failure on line 240 in etcdutl/snapshot/v3_snapshot.go

View workflow job for this annotation

GitHub Actions / test

unknown field InitialMmapSize in struct literal of type config.ServerConfig
}
if err = srv.VerifyBootstrap(); err != nil {
return err
Expand Down Expand Up @@ -263,13 +268,15 @@ func (s *v3Manager) Restore(cfg RestoreConfig) error {
s.walDir = walDir
s.snapDir = filepath.Join(dataDir, "member", "snap")
s.skipHashCheck = cfg.SkipHashCheck
s.initialMmapSize = cfg.InitialMmapSize

s.lg.Info(
"restoring snapshot",
zap.String("path", s.srcDbPath),
zap.String("wal-dir", s.walDir),
zap.String("data-dir", dataDir),
zap.String("snap-dir", s.snapDir),
zap.Uint64("initial-memory-map-size", s.initialMmapSize),
)

if err = s.saveDB(); err != nil {
Expand Down Expand Up @@ -297,6 +304,7 @@ func (s *v3Manager) Restore(cfg RestoreConfig) error {
zap.String("wal-dir", s.walDir),
zap.String("data-dir", dataDir),
zap.String("snap-dir", s.snapDir),
zap.Uint64("initial-memory-map-size", s.initialMmapSize),
)

return verify.VerifyIfEnabled(verify.Config{
Expand All @@ -317,7 +325,7 @@ func (s *v3Manager) saveDB() error {
return err
}

be := backend.NewDefaultBackend(s.lg, s.outDbPath())
be := backend.NewDefaultBackend(s.lg, s.outDbPath(), backend.WithMmapSize(s.initialMmapSize))
defer be.Close()

err = schema.NewMembershipBackend(s.lg, be).TrimMembershipFromBackend()
Expand Down Expand Up @@ -472,7 +480,7 @@ func (s *v3Manager) saveWALAndSnap() (*raftpb.HardState, error) {
}

// add members again to persist them to the backend we create.
be := backend.NewDefaultBackend(s.lg, s.outDbPath())
be := backend.NewDefaultBackend(s.lg, s.outDbPath(), backend.WithMmapSize(s.initialMmapSize))
defer be.Close()
s.cl.SetBackend(schema.NewMembershipBackend(s.lg, be))
for _, m := range s.cl.Members() {
Expand Down Expand Up @@ -551,7 +559,7 @@ func (s *v3Manager) saveWALAndSnap() (*raftpb.HardState, error) {
}

func (s *v3Manager) updateCIndex(commit uint64, term uint64) error {
be := backend.NewDefaultBackend(s.lg, s.outDbPath())
be := backend.NewDefaultBackend(s.lg, s.outDbPath(), backend.WithMmapSize(s.initialMmapSize))
defer be.Close()

cindex.UpdateConsistentIndexForce(be.BatchTx(), commit, term)
Expand Down
6 changes: 3 additions & 3 deletions server/storage/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ var (

defragLimit = 10000

// initialMmapSize is the initial size of the mmapped region. Setting this larger than
// InitialMmapSize is the initial size of the mmapped region. Setting this larger than
// the potential max db size can prevent writer from blocking reader.
// This only works for linux.
initialMmapSize = uint64(10 * 1024 * 1024 * 1024)
InitialMmapSize = uint64(10 * 1024 * 1024 * 1024)

// minSnapshotWarningTimeout is the minimum threshold to trigger a long running snapshot warning.
minSnapshotWarningTimeout = 30 * time.Second
Expand Down Expand Up @@ -157,7 +157,7 @@ func DefaultBackendConfig(lg *zap.Logger) BackendConfig {
return BackendConfig{
BatchInterval: defaultBatchInterval,
BatchLimit: defaultBatchLimit,
MmapSize: initialMmapSize,
MmapSize: InitialMmapSize,
Logger: lg,
}
}
Expand Down

0 comments on commit 4f66aa9

Please sign in to comment.