diff options
author | Yuhong Zhang <danielzhangyh@gmail.com> | 2021-05-10 01:13:11 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-05-11 14:11:28 +0000 |
commit | a14ed641bb351eae6030b2d1346b5ad457ee3c18 (patch) | |
tree | 44dbbb1dfad6237ff95662c50d070fcc71c8595a | |
parent | bebf55ebc71bb6d9070691b4b31662082465992c (diff) | |
download | mongo-a14ed641bb351eae6030b2d1346b5ad457ee3c18.tar.gz |
SERVER-55260 Test multiple statement ids per oplog entry with applyOps
-rw-r--r-- | jstests/core/apply_ops1.js | 35 | ||||
-rw-r--r-- | src/mongo/db/repl/apply_ops_test.cpp | 62 |
2 files changed, 95 insertions, 2 deletions
diff --git a/jstests/core/apply_ops1.js b/jstests/core/apply_ops1.js index 7c6982e047a..92242bd971a 100644 --- a/jstests/core/apply_ops1.js +++ b/jstests/core/apply_ops1.js @@ -401,6 +401,41 @@ assert.eq(true, res.results[0], "Valid insert with transaction number failed"); assert.eq(true, res.results[1], "Valid update with transaction number failed"); assert.eq(true, res.results[2], "Valid delete with transaction number failed"); +// Ops with multiple statement IDs are valid. +res = db.runCommand({ + applyOps: [ + { + op: "i", + ns: t.getFullName(), + o: {_id: 7, x: 24}, + lsid: lsid, + txnNumber: NumberLong(3), + stmtId: [NumberInt(0), NumberInt(1)] + }, + { + op: "u", + ns: t.getFullName(), + o2: {_id: 8}, + o: {$set: {x: 25}}, + lsid: lsid, + txnNumber: NumberLong(3), + stmtId: [NumberInt(2), NumberInt(3)] + }, + { + op: "d", + ns: t.getFullName(), + o: {_id: 7}, + lsid: lsid, + txnNumber: NumberLong(4), + stmtId: [NumberInt(0), NumberInt(1)] + }, + ] +}); + +assert.eq(true, res.results[0], "Valid insert with multiple statement IDs failed"); +assert.eq(true, res.results[1], "Valid update with multiple statement IDs failed"); +assert.eq(true, res.results[2], "Valid delete with multiple statement IDs failed"); + // When applying a "u" (update) op, we default to 'UpdateNode' update semantics, and $set // operations add new fields in lexicographic order. res = assert.commandWorked(db.adminCommand({ diff --git a/src/mongo/db/repl/apply_ops_test.cpp b/src/mongo/db/repl/apply_ops_test.cpp index 6999de3ca98..2f1480c48cc 100644 --- a/src/mongo/db/repl/apply_ops_test.cpp +++ b/src/mongo/db/repl/apply_ops_test.cpp @@ -336,7 +336,9 @@ TEST_F(ApplyOpsTest, ApplyOpsPropagatesOplogApplicationMode) { /** * Generates oplog entries with the given number used for the timestamp. */ -OplogEntry makeOplogEntry(OpTypeEnum opType, const BSONObj& oField) { +OplogEntry makeOplogEntry(OpTypeEnum opType, + const BSONObj& oField, + const std::vector<StmtId>& stmtIds = {}) { return {DurableOplogEntry(OpTime(Timestamp(1, 1), 1), // optime boost::none, // hash opType, // op type @@ -349,7 +351,7 @@ OplogEntry makeOplogEntry(OpTypeEnum opType, const BSONObj& oField) { {}, // sessionInfo boost::none, // upsert Date_t(), // wall clock time - {}, // statement ids + stmtIds, // statement ids boost::none, // optime of previous write within same transaction boost::none, // pre-image optime boost::none, // post-image optime @@ -453,6 +455,62 @@ TEST_F(ApplyOpsTest, ExtractOperationsReturnsOperationsWithSameOpTimeAsApplyOps) ASSERT(operations.cend() == it); } +TEST_F(ApplyOpsTest, ExtractOperationsFromApplyOpsMultiStmtIds) { + NamespaceString ns1("test.a"); + auto ui1 = UUID::gen(); + auto op1 = BSON("op" + << "i" + << "ns" << ns1.ns() << "ui" << ui1 << "o" << BSON("_id" << 1)); + + NamespaceString ns2("test.b"); + auto ui2 = UUID::gen(); + auto op2 = BSON("op" + << "u" + << "ns" << ns2.ns() << "ui" << ui2 << "b" << true << "o" << BSON("x" << 1) + << "o2" << BSON("_id" << 2)); + + auto oplogEntry = + makeOplogEntry(OpTypeEnum::kCommand, BSON("applyOps" << BSON_ARRAY(op1 << op2)), {0, 1}); + + auto operations = ApplyOps::extractOperations(oplogEntry); + ASSERT_EQUALS(2U, operations.size()) + << "Unexpected number of operations extracted: " << oplogEntry.toBSONForLogging(); + + // Check extracted CRUD operations. + auto it = operations.cbegin(); + { + ASSERT(operations.cend() != it); + const auto& operation1 = *(it++); + ASSERT(OpTypeEnum::kInsert == operation1.getOpType()) + << "Unexpected op type: " << operation1.toBSONForLogging(); + ASSERT_EQUALS(ui1, *operation1.getUuid()); + ASSERT_EQUALS(ns1, operation1.getNss()); + ASSERT_BSONOBJ_EQ(BSON("_id" << 1), operation1.getOperationToApply()); + + // OpTime of CRUD operation should match applyOps. + ASSERT_EQUALS(oplogEntry.getOpTime(), operation1.getOpTime()); + } + + { + ASSERT(operations.cend() != it); + const auto& operation2 = *(it++); + ASSERT(OpTypeEnum::kUpdate == operation2.getOpType()) + << "Unexpected op type: " << operation2.toBSONForLogging(); + ASSERT_EQUALS(ui2, *operation2.getUuid()); + ASSERT_EQUALS(ns2, operation2.getNss()); + ASSERT_BSONOBJ_EQ(BSON("x" << 1), operation2.getOperationToApply()); + + auto optionalUpsertBool = operation2.getUpsert(); + ASSERT(optionalUpsertBool); + ASSERT(*optionalUpsertBool); + + // OpTime of CRUD operation should match applyOps. + ASSERT_EQUALS(oplogEntry.getOpTime(), operation2.getOpTime()); + } + + ASSERT(operations.cend() == it); +} + TEST_F(ApplyOpsTest, ApplyOpsFailsToDropAdmin) { auto opCtx = cc().makeOperationContext(); auto mode = OplogApplication::Mode::kApplyOpsCmd; |