diff options
author | Gregory Wlodarek <gregory.wlodarek@mongodb.com> | 2021-04-28 17:32:43 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-04-29 13:52:08 +0000 |
commit | 9b437dbad5f9b570a579ee3feb92206d79033ecc (patch) | |
tree | b9f032d457adbd04b6a7fa12a7c7b8675f89fc3e | |
parent | b649876de8765d7a9d25d6aaec6a86b0d67ca9e2 (diff) | |
download | mongo-9b437dbad5f9b570a579ee3feb92206d79033ecc.tar.gz |
SERVER-56445 Upsert violates multi-timestamp constraints when inserting into a full capped collection
-rw-r--r-- | jstests/core/capped_upsert.js | 19 | ||||
-rw-r--r-- | src/mongo/db/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/exec/upsert_stage.cpp | 16 |
3 files changed, 32 insertions, 4 deletions
diff --git a/jstests/core/capped_upsert.js b/jstests/core/capped_upsert.js new file mode 100644 index 00000000000..38f5afe3b24 --- /dev/null +++ b/jstests/core/capped_upsert.js @@ -0,0 +1,19 @@ +/** + * Tests upserting into a capped collection with deletes needed. + * + * @tags: [ + * requires_capped, + * # Capped collections cannot be sharded + * assumes_unsharded_collection, + * ] + */ +(function() { +"use strict"; + +const coll = db.capped_upsert; +coll.drop(); + +assert.commandWorked(db.createCollection(coll.getName(), {capped: true, size: 100000, max: 1})); +assert.commandWorked(coll.insert({text: "a"})); +assert.commandWorked(coll.save({_id: 123, text: "b"})); +}()); diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index b44f18ffb60..ddebf40045a 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -1300,6 +1300,7 @@ env.Library( 'update/update_driver', ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/repl/local_oplog_info', 'catalog/database_holder', 'commands/server_status_core', 'kill_sessions', diff --git a/src/mongo/db/exec/upsert_stage.cpp b/src/mongo/db/exec/upsert_stage.cpp index 4f7403d28d5..8e3dcc0f755 100644 --- a/src/mongo/db/exec/upsert_stage.cpp +++ b/src/mongo/db/exec/upsert_stage.cpp @@ -31,6 +31,7 @@ #include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/curop_failpoint_helpers.h" +#include "mongo/db/repl/local_oplog_info.h" #include "mongo/db/s/operation_sharding_state.h" #include "mongo/db/update/storage_validation.h" #include "mongo/s/would_change_owning_shard_exception.h" @@ -148,11 +149,18 @@ void UpsertStage::_performInsert(BSONObj newDocument) { writeConflictRetry(opCtx(), "upsert", collection()->ns().ns(), [&] { WriteUnitOfWork wunit(opCtx()); + InsertStatement insertStmt(_params.request->getStmtIds(), newDocument); + + auto replCoord = repl::ReplicationCoordinator::get(opCtx()); + if (collection()->isCapped() && + !replCoord->isOplogDisabledFor(opCtx(), collection()->ns())) { + auto oplogInfo = repl::LocalOplogInfo::get(opCtx()); + auto oplogSlots = oplogInfo->getNextOpTimes(opCtx(), /*batchSize=*/1); + insertStmt.oplogSlot = oplogSlots.front(); + } + uassertStatusOK(collection()->insertDocument( - opCtx(), - InsertStatement(_params.request->getStmtIds(), newDocument), - _params.opDebug, - _params.request->isFromMigration())); + opCtx(), insertStmt, _params.opDebug, _params.request->isFromMigration())); // Technically, we should save/restore state here, but since we are going to return // immediately after, it would just be wasted work. |