diff options
-rw-r--r-- | jstests/noPassthrough/index_build_capped_position_lost.js | 51 | ||||
-rw-r--r-- | src/mongo/db/catalog/multi_index_block.cpp | 7 |
2 files changed, 56 insertions, 2 deletions
diff --git a/jstests/noPassthrough/index_build_capped_position_lost.js b/jstests/noPassthrough/index_build_capped_position_lost.js new file mode 100644 index 00000000000..a1c7d454fb8 --- /dev/null +++ b/jstests/noPassthrough/index_build_capped_position_lost.js @@ -0,0 +1,51 @@ +/** + * Capped cursors return CappedPositionLost when the document they were positioned on gets deleted. + * When this occurs during the collection scan phase of an index build, it will get restarted. + */ +(function() { +"use strict"; + +load("jstests/libs/fail_point_util.js"); +load("jstests/noPassthrough/libs/index_build.js"); + +const conn = MongoRunner.runMongod({}); + +const dbName = "test"; +const collName = "index_build_capped_position_lost"; + +const db = conn.getDB(dbName); +assert.commandWorked( + db.createCollection(collName, {capped: true, size: 1024 * 1024 * 1024, max: 5})); + +const coll = db.getCollection(collName); + +for (let i = 0; i < 5; i++) { + assert.commandWorked(coll.insert({a: i})); +} + +// Hang the collection scan phase of the index build when it's halfway finished. +let fp = configureFailPoint( + conn, "hangIndexBuildDuringCollectionScanPhaseAfterInsertion", {fieldsToMatch: {a: 3}}); + +const awaitCreateIndex = IndexBuildTest.startIndexBuild(conn, coll.getFullName(), {a: 1}); +fp.wait(); + +// Rollover the capped collection. +for (let i = 5; i < 10; i++) { + assert.commandWorked(coll.insert({a: i})); +} + +fp.off(); +checkLog.containsJson(conn, 5470300, { + error: function(error) { + return error.code === ErrorCodes.CappedPositionLost; + } +}); // Collection scan restarted. +checkLog.containsJson(conn, 20391, {totalRecords: 5}); // Collection scan complete. + +awaitCreateIndex(); + +IndexBuildTest.assertIndexes(coll, 2, ["_id_", "a_1"]); + +MongoRunner.stopMongod(conn); +}()); diff --git a/src/mongo/db/catalog/multi_index_block.cpp b/src/mongo/db/catalog/multi_index_block.cpp index a4c39f1d56f..fb51a69d4e7 100644 --- a/src/mongo/db/catalog/multi_index_block.cpp +++ b/src/mongo/db/catalog/multi_index_block.cpp @@ -444,10 +444,13 @@ Status MultiIndexBlock::insertAllDocumentsInCollection( RecoveryUnit::toString(opCtx->recoveryUnit()->getTimestampReadSource()), "duration"_attr = duration_cast<Milliseconds>(Seconds(timer.seconds()))); } catch (DBException& ex) { - if (ex.code() == ErrorCodes::ReadConcernMajorityNotAvailableYet) { + if (ex.code() == ErrorCodes::ReadConcernMajorityNotAvailableYet || + ex.code() == ErrorCodes::CappedPositionLost) { // Forced replica set re-configs will clear the majority committed snapshot, // which may be used by the collection scan. The collection scan will restart - // from the beginning in this case. + // from the beginning in this case. Capped cursors are invalidated when the document + // they were positioned on gets deleted. The collection scan will restart in both + // cases. restartCollectionScan = true; logAndBackoff( 5470300, |