summaryrefslogtreecommitdiff
path: root/src/mongo/db/repl/rs_rollback_test.cpp
diff options
context:
space:
mode:
authorJack Mulrow <jack.mulrow@mongodb.com>2017-08-16 18:07:02 -0400
committerJack Mulrow <jack.mulrow@mongodb.com>2017-08-23 12:41:47 -0400
commitc1e7921e9d69bd9a37761deb58d119a324341a54 (patch)
tree86e7fb3084d9aea2f08263f261474c1163de15cc /src/mongo/db/repl/rs_rollback_test.cpp
parentee6a79935e98b4a12bc74cb385e7d5f62633347e (diff)
downloadmongo-c1e7921e9d69bd9a37761deb58d119a324341a54.tar.gz
SERVER-30508 Fail rollback via refetch if transactions collection UUID is different on sync source
Diffstat (limited to 'src/mongo/db/repl/rs_rollback_test.cpp')
-rw-r--r--src/mongo/db/repl/rs_rollback_test.cpp116
1 files changed, 103 insertions, 13 deletions
diff --git a/src/mongo/db/repl/rs_rollback_test.cpp b/src/mongo/db/repl/rs_rollback_test.cpp
index ec966c4cb01..ee1caf718be 100644
--- a/src/mongo/db/repl/rs_rollback_test.cpp
+++ b/src/mongo/db/repl/rs_rollback_test.cpp
@@ -75,7 +75,9 @@ public:
BSONObj getLastOperation() const override;
BSONObj findOne(const NamespaceString& nss, const BSONObj& filter) const override;
- BSONObj findOneByUUID(const std::string& db, UUID uuid, const BSONObj& filter) const override;
+ std::pair<BSONObj, NamespaceString> findOneByUUID(const std::string& db,
+ UUID uuid,
+ const BSONObj& filter) const override;
void copyCollectionFromRemote(OperationContext* opCtx,
const NamespaceString& nss) const override;
@@ -114,10 +116,10 @@ BSONObj RollbackSourceMock::findOne(const NamespaceString& nss, const BSONObj& f
return BSONObj();
}
-BSONObj RollbackSourceMock::findOneByUUID(const std::string& db,
- UUID uuid,
- const BSONObj& filter) const {
- return BSONObj();
+std::pair<BSONObj, NamespaceString> RollbackSourceMock::findOneByUUID(const std::string& db,
+ UUID uuid,
+ const BSONObj& filter) const {
+ return {BSONObj(), NamespaceString()};
}
void RollbackSourceMock::copyCollectionFromRemote(OperationContext* opCtx,
@@ -396,9 +398,11 @@ int _testRollbackDelete(OperationContext* opCtx,
: RollbackSourceMock(std::move(oplog)),
called(false),
_documentAtSource(documentAtSource) {}
- BSONObj findOneByUUID(const std::string& db, UUID uuid, const BSONObj& filter) const {
+ std::pair<BSONObj, NamespaceString> findOneByUUID(const std::string& db,
+ UUID uuid,
+ const BSONObj& filter) const override {
called = true;
- return _documentAtSource;
+ return {_documentAtSource, NamespaceString()};
}
mutable bool called;
@@ -1643,9 +1647,9 @@ TEST_F(RSRollbackTest, RollbackApplyOpsCommand) {
RollbackSourceLocal(std::unique_ptr<OplogInterface> oplog)
: RollbackSourceMock(std::move(oplog)) {}
- BSONObj findOneByUUID(const std::string& db,
- UUID uuid,
- const BSONObj& filter) const override {
+ std::pair<BSONObj, NamespaceString> findOneByUUID(const std::string& db,
+ UUID uuid,
+ const BSONObj& filter) const override {
int numFields = 0;
for (const auto element : filter) {
++numFields;
@@ -1655,11 +1659,11 @@ TEST_F(RSRollbackTest, RollbackApplyOpsCommand) {
searchedIds.insert(filter.firstElement().numberInt());
switch (filter.firstElement().numberInt()) {
case 1:
- return BSON("_id" << 1 << "v" << 1);
+ return {BSON("_id" << 1 << "v" << 1), NamespaceString()};
case 2:
- return BSON("_id" << 2 << "v" << 3);
+ return {BSON("_id" << 2 << "v" << 3), NamespaceString()};
case 3:
- return BSON("_id" << 3 << "v" << 5);
+ return {BSON("_id" << 3 << "v" << 5), NamespaceString()};
case 4:
return {};
}
@@ -2048,6 +2052,92 @@ TEST_F(RSRollbackTest, LocalEntryWithTxnNumberAddsTransactionTableDocToBeRefetch
ASSERT_TRUE(fui.docsToRefetch.find(expectedTxnDoc) != fui.docsToRefetch.end());
}
+TEST_F(RSRollbackTest, RollbackFailsIfTransactionDocumentRefetchReturnsDifferentNamespace) {
+ createOplog(_opCtx.get());
+
+ // Create a valid FixUpInfo struct for rolling back a single CRUD operation that has a
+ // transaction number and session id.
+ FixUpInfo fui;
+
+ auto entryWithTxnNumber =
+ BSON("ts" << Timestamp(Seconds(2), 0) << "t" << 1LL << "h" << 1LL << "op"
+ << "i"
+ << "ui"
+ << UUID::gen()
+ << "ns"
+ << "test.t"
+ << "o"
+ << BSON("_id" << 1 << "a" << 1)
+ << "txnNumber"
+ << 1LL
+ << "stmtId"
+ << 1
+ << "lsid"
+ << makeLogicalSessionIdForTest().toBSON());
+
+ UUID transactionTableUUID = UUID::gen();
+ fui.transactionTableUUID = transactionTableUUID;
+
+ auto commonOperation =
+ std::make_pair(BSON("ts" << Timestamp(Seconds(1), 0) << "h" << 1LL), RecordId(1));
+ fui.commonPoint = OpTime(Timestamp(Seconds(1), 0), 1LL);
+ fui.commonPointOurDiskloc = RecordId(1);
+
+ fui.rbid = 1;
+
+ // The FixUpInfo will have an extra doc to refetch: the corresponding transaction table entry.
+ ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(fui, entryWithTxnNumber));
+ ASSERT_EQ(fui.docsToRefetch.size(), 2U);
+
+ {
+ class RollbackSourceLocal : public RollbackSourceMock {
+ public:
+ RollbackSourceLocal(std::unique_ptr<OplogInterface> oplog)
+ : RollbackSourceMock(std::move(oplog)) {}
+ std::pair<BSONObj, NamespaceString> findOneByUUID(
+ const std::string& db, UUID uuid, const BSONObj& filter) const override {
+ return {BSONObj(), NamespaceString::kSessionTransactionsTableNamespace};
+ }
+ int getRollbackId() const override {
+ return 1;
+ }
+ };
+
+ // Should not throw, since findOneByUUID will return the expected namespace.
+ syncFixUp(_opCtx.get(),
+ fui,
+ RollbackSourceLocal(
+ std::unique_ptr<OplogInterface>(new OplogInterfaceMock({commonOperation}))),
+ _coordinator,
+ _replicationProcess.get());
+ }
+
+ {
+ class RollbackSourceLocal : public RollbackSourceMock {
+ public:
+ RollbackSourceLocal(std::unique_ptr<OplogInterface> oplog)
+ : RollbackSourceMock(std::move(oplog)) {}
+ std::pair<BSONObj, NamespaceString> findOneByUUID(
+ const std::string& db, UUID uuid, const BSONObj& filter) const override {
+ return {BSONObj(), NamespaceString("foo.bar")};
+ }
+ int getRollbackId() const override {
+ return 1;
+ }
+ };
+
+ // The returned namespace will not be the expected one, implying a rename/drop of the
+ // transactions collection across this node and the sync source, so rollback should fail.
+ ASSERT_THROWS(syncFixUp(_opCtx.get(),
+ fui,
+ RollbackSourceLocal(std::unique_ptr<OplogInterface>(
+ new OplogInterfaceMock({commonOperation}))),
+ _coordinator,
+ _replicationProcess.get()),
+ RSFatalException);
+ }
+}
+
TEST_F(RSRollbackTest, RollbackReturnsImmediatelyOnFailureToTransitionToRollback) {
// On failing to transition to ROLLBACK, rollback() should return immediately and not call
// syncRollback(). We provide an empty oplog so that if syncRollback() is called erroneously,