Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions common/failpoint/failpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func newName(s string) Name {
var (
PauseBeforeDumping = newName("PauseBeforeDumping")
SlowBSONDump = newName("SlowBSONDump")
PauseUntilResumed = newName("PauseUntilResumed")
)

// parseNames splits arg, a comma-separated list of failpoint names as
Expand Down
3 changes: 3 additions & 0 deletions mongodump/mongodump.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,9 @@ func (dump *MongoDump) Dump() (err error) {
if _, ok := failpoint.DefaultManager.Get(failpoint.PauseBeforeDumping); ok {
log.Logvf(log.Info, "failpoint.PauseBeforeDumping: sleeping 15 sec")
time.Sleep(15 * time.Second)
} else if fp, ok := failpoint.DefaultManager.Get(failpoint.PauseUntilResumed); ok {
log.Logvf(log.Info, "failpoint.PauseUntilResumed: waiting for resume signal")
fp.Wait()
}

// switch on what kind of execution to do
Expand Down
58 changes: 58 additions & 0 deletions mongodump/oplog_dump_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -546,3 +546,61 @@ func convertIndexToTTL(ctx context.Context, t *testing.T) {
)
require.NoError(t, res.Err())
}

// TestOplogRollover verifies that mongodump refuses to produce a dump when
// the oplog has rolled over during dumping and evicted the entry it captured
// its starting timestamp from.
//
// jstests/dump/oplog_rollover_test.js used to test this by racing a fixed
// 15-second sleep against a fixed amount of write load meant to overflow a
// deliberately tiny (2MB) oplog, and needed several rounds of "make this
// less racy" fixes over the years as host speed varied. That approach isn't
// available here anyway: the shared replica set used by Go integration
// tests can't be resized below 990MB (server-enforced), and forcing genuine
// eviction against that cluster turned out to depend on WiredTiger
// checkpoint/oldest-timestamp scheduling in ways that were empirically
// unpredictable even when forcing checkpoints and using majority write
// concern.
//
// Instead, this uses the PauseUntilResumed failpoint to block mongodump
// after it has captured its real starting timestamp, overwrites that
// timestamp with one guaranteed not to exist in the oplog, and resumes.
// mongodump then runs the exact same overflow-detection logic
// (checkOplogTimestampExists, in oplog_dump.go) it would in production,
// deterministically and without needing to write any data at all.
func TestOplogRollover(t *testing.T) {
testtype.SkipUnlessTestType(t, testtype.IntegrationTestType)
// Oplog is not available in a standalone topology.
testtype.SkipUnlessTestType(t, testtype.ReplSetTestType)

md, err := simpleMongoDumpInstance()
require.NoError(t, err)

md.ToolOptions.DB = ""
md.OutputOptions.Oplog = true
md.OutputOptions.Out = "oplog_rollover"
require.NoError(t, md.Init())
defer os.RemoveAll(md.OutputOptions.Out)

require.NoError(t, failpoint.DefaultManager.Parse(failpoint.PauseUntilResumed.String()))
defer failpoint.DefaultManager.Reset()

dumpErrCh := make(chan error, 1)
go func() {
dumpErrCh <- md.Dump()
}()

fp, ok := failpoint.DefaultManager.Get(failpoint.PauseUntilResumed)
require.True(t, ok, "PauseUntilResumed failpoint should be enabled")
fp.Reached()
md.oplogStart = bson.Timestamp{T: 1, I: 1}
fp.Signal()

err = <-dumpErrCh
require.ErrorContains(
t,
err,
"oplog overflow: mongodump was unable to capture all new oplog entries during execution",
"mongodump should crash when the oplog rolls over during dumping",
)
}
50 changes: 0 additions & 50 deletions test/qa-tests/jstests/dump/oplog_rollover_test.js

This file was deleted.