summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorAllison Chang <allison.chang@10gen.com>2017-07-18 15:24:45 -0400
committerAllison Chang <allison.chang@10gen.com>2017-08-03 18:22:07 -0400
commit225c4d1a70b7756ee77fd404aab131bf1f1c9fce (patch)
tree08ea6109b64e7f15cc4aa8fc6ea5f1430cfcdd9b /src/mongo
parentc9daa25a50dee5c50ae2ac929cfd67dcdd95dd2a (diff)
downloadmongo-225c4d1a70b7756ee77fd404aab131bf1f1c9fce.tar.gz
SERVER-29667 Update rollback of document refetch to use UUIDs
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/client/dbclient.cpp31
-rw-r--r--src/mongo/client/dbclientinterface.h8
-rw-r--r--src/mongo/db/repl/rollback_source.h9
-rw-r--r--src/mongo/db/repl/rollback_source_impl.cpp9
-rw-r--r--src/mongo/db/repl/rollback_source_impl.h2
-rw-r--r--src/mongo/db/repl/rs_rollback.cpp195
-rw-r--r--src/mongo/db/repl/rs_rollback.h20
-rw-r--r--src/mongo/db/repl/rs_rollback_no_uuid_test.cpp9
-rw-r--r--src/mongo/db/repl/rs_rollback_test.cpp155
9 files changed, 248 insertions, 190 deletions
diff --git a/src/mongo/client/dbclient.cpp b/src/mongo/client/dbclient.cpp
index 74d26aac7d5..44db52dc622 100644
--- a/src/mongo/client/dbclient.cpp
+++ b/src/mongo/client/dbclient.cpp
@@ -651,6 +651,37 @@ BSONObj DBClientBase::findOne(const string& ns,
return v.empty() ? BSONObj() : v[0];
}
+BSONObj DBClientBase::findOneByUUID(const std::string& db, UUID uuid, const BSONObj& filter) {
+ list<BSONObj> results;
+ BSONObj res;
+
+ BSONObjBuilder cmdBuilder;
+ uuid.appendToBuilder(&cmdBuilder, "find");
+ cmdBuilder.append("filter", filter);
+ cmdBuilder.append("limit", 1);
+ cmdBuilder.append("singleBatch", true);
+
+ BSONObj cmd = cmdBuilder.obj();
+
+ if (runCommand(db, cmd, res, QueryOption_SlaveOk)) {
+ BSONObj cursorObj = res.getObjectField("cursor");
+ BSONObj docs = cursorObj.getObjectField("firstBatch");
+ BSONObjIterator it(docs);
+ while (it.more()) {
+ BSONElement e = it.next();
+ results.push_back(e.Obj().getOwned());
+ }
+ invariant(results.size() <= 1);
+ if (results.empty()) {
+ return BSONObj();
+ }
+ return results.front();
+ }
+ uasserted(
+ 40586,
+ str::stream() << "find command using UUID failed. Command: " << cmd << " Result: " << res);
+}
+
namespace {
/**
diff --git a/src/mongo/client/dbclientinterface.h b/src/mongo/client/dbclientinterface.h
index ab9a4864cb6..f57618bca00 100644
--- a/src/mongo/client/dbclientinterface.h
+++ b/src/mongo/client/dbclientinterface.h
@@ -198,6 +198,14 @@ public:
const BSONObj* fieldsToReturn = 0,
int queryOptions = 0);
+ /**
+ * @return a single object that matches the filter within the collection specified by the UUID.
+ * If the command fails, an assertion error is thrown. Otherwise, if no document matches
+ * the query, an empty BSONObj is returned.
+ * @throws AssertionException
+ */
+ virtual BSONObj findOneByUUID(const std::string& db, UUID uuid, const BSONObj& filter);
+
virtual std::string getServerAddress() const = 0;
/** helper function. run a simple command where the command expression is simply
diff --git a/src/mongo/db/repl/rollback_source.h b/src/mongo/db/repl/rollback_source.h
index cafba0eb74c..0c55bcb9ae2 100644
--- a/src/mongo/db/repl/rollback_source.h
+++ b/src/mongo/db/repl/rollback_source.h
@@ -76,11 +76,18 @@ public:
virtual BSONObj getLastOperation() const = 0;
/**
- * Fetch a single document from the sync source.
+ * Fetch a single document from the sync source using the namespace.
*/
virtual BSONObj findOne(const NamespaceString& nss, const BSONObj& filter) const = 0;
/**
+ * Fetch a single document from the sync source using the UUID.
+ */
+ virtual BSONObj findOneByUUID(const std::string& db,
+ UUID uuid,
+ const BSONObj& filter) const = 0;
+
+ /**
* Clones a single collection from the sync source.
*/
virtual void copyCollectionFromRemote(OperationContext* opCtx,
diff --git a/src/mongo/db/repl/rollback_source_impl.cpp b/src/mongo/db/repl/rollback_source_impl.cpp
index cbb8e66aa90..3e05e8a41be 100644
--- a/src/mongo/db/repl/rollback_source_impl.cpp
+++ b/src/mongo/db/repl/rollback_source_impl.cpp
@@ -73,6 +73,12 @@ BSONObj RollbackSourceImpl::findOne(const NamespaceString& nss, const BSONObj& f
return _getConnection()->findOne(nss.toString(), filter, NULL, QueryOption_SlaveOk).getOwned();
}
+BSONObj RollbackSourceImpl::findOneByUUID(const std::string& db,
+ UUID uuid,
+ const BSONObj& filter) const {
+ return _getConnection()->findOneByUUID(db, uuid, filter);
+}
+
void RollbackSourceImpl::copyCollectionFromRemote(OperationContext* opCtx,
const NamespaceString& nss) const {
std::string errmsg;
@@ -92,8 +98,7 @@ void RollbackSourceImpl::copyCollectionFromRemote(OperationContext* opCtx,
StatusWith<BSONObj> RollbackSourceImpl::getCollectionInfoByUUID(const std::string& db,
const UUID& uuid) const {
- std::list<BSONObj> info =
- _getConnection()->getCollectionInfos(db, BSON("options.uuid" << uuid));
+ std::list<BSONObj> info = _getConnection()->getCollectionInfos(db, BSON("info.uuid" << uuid));
if (info.empty()) {
return StatusWith<BSONObj>(ErrorCodes::NoSuchKey,
str::stream()
diff --git a/src/mongo/db/repl/rollback_source_impl.h b/src/mongo/db/repl/rollback_source_impl.h
index e9995bb5981..1654194ea5d 100644
--- a/src/mongo/db/repl/rollback_source_impl.h
+++ b/src/mongo/db/repl/rollback_source_impl.h
@@ -66,6 +66,8 @@ public:
BSONObj findOne(const NamespaceString& nss, const BSONObj& filter) const override;
+ BSONObj findOneByUUID(const std::string& db, UUID uuid, const BSONObj& filter) const override;
+
void copyCollectionFromRemote(OperationContext* opCtx,
const NamespaceString& nss) const override;
diff --git a/src/mongo/db/repl/rs_rollback.cpp b/src/mongo/db/repl/rs_rollback.cpp
index b6fbd0e4b50..891262f6f4f 100644
--- a/src/mongo/db/repl/rs_rollback.cpp
+++ b/src/mongo/db/repl/rs_rollback.cpp
@@ -93,7 +93,7 @@ namespace repl {
using namespace rollback_internal;
bool DocID::operator<(const DocID& other) const {
- int comp = strcmp(ns, other.ns);
+ int comp = uuid.toString().compare(other.uuid.toString());
if (comp < 0)
return true;
if (comp > 0)
@@ -110,28 +110,18 @@ bool DocID::operator==(const DocID& other) const {
return !(*this < other || other < *this);
}
-void FixUpInfo::removeAllDocsToRefetchFor(const std::string& collection) {
- docsToRefetch.erase(docsToRefetch.lower_bound(DocID::minFor(collection.c_str())),
- docsToRefetch.upper_bound(DocID::maxFor(collection.c_str())));
+void FixUpInfo::removeAllDocsToRefetchFor(UUID collectionUUID) {
+ docsToRefetch.erase(docsToRefetch.lower_bound(DocID::minFor(collectionUUID)),
+ docsToRefetch.upper_bound(DocID::maxFor(collectionUUID)));
}
-// TODO: This function will not be fully functional until the entire
-// rollback via refetch for non-WT project is complete. See SERVER-30171.
void FixUpInfo::removeRedundantOperations() {
- // These loops and their bodies can be done in any order. The final result of the FixUpInfo
- // members will be the same.
-
- // for (const auto& collection : collectionsToDrop) {
- // removeAllDocsToRefetchFor(collection);
- // indexesToDrop.erase(collection);
- // collectionsToResyncMetadata.erase(collection);
- // }
-
- for (const auto& collection : collectionsToResyncData) {
- removeAllDocsToRefetchFor(collection);
- // indexesToDrop.erase(collection);
- // collectionsToResyncMetadata.erase(collection);
- // collectionsToDrop.erase(collection);
+ for (const auto& collectionUUID : collectionsToDrop) {
+ removeAllDocsToRefetchFor(collectionUUID);
+ indexesToDrop.erase(collectionUUID);
+ indexesToCreate.erase(collectionUUID);
+ collectionsToRename.erase(collectionUUID);
+ collectionsToResyncMetadata.erase(collectionUUID);
}
}
@@ -240,9 +230,9 @@ Status rollback_internal::updateFixUpInfoFromLocalOplogEntry(FixUpInfo& fixUpInf
if (oplogEntry.getOpType() == OpTypeEnum::kNoop)
return Status::OK();
- DocID doc;
- doc.ownedObj = oplogEntry.raw;
- doc.ns = oplogEntry.raw.getStringField("ns");
+ // If we are inserting/updating/deleting a document in the oplog entry, we will update
+ // the doc._id field when we actually insert the docID into the docsToRefetch set.
+ DocID doc = DocID(oplogEntry.raw, BSONElement(), *uuid);
if (oplogEntry.getNamespace().isEmpty()) {
throw RSFatalException(str::stream() << "Local op on rollback has no ns: "
@@ -266,18 +256,19 @@ Status rollback_internal::updateFixUpInfoFromLocalOplogEntry(FixUpInfo& fixUpInf
invariant(sessionId);
invariant(oplogEntry.getStatementId());
- DocID txnDoc;
- BSONObjBuilder txnBob;
- txnBob.append("_id", sessionId->toBSON());
- txnDoc.ownedObj = txnBob.obj();
- txnDoc._id = txnDoc.ownedObj.firstElement();
- // TODO: SERVER-29667
+ // TODO: SERVER-30076
// Once collection uuids replace namespace strings for rollback, this will need to be
- // changed to the uuid of the session transaction table collection.
- txnDoc.ns = NamespaceString::kSessionTransactionsTableNamespace.ns().c_str();
-
- fixUpInfo.docsToRefetch.insert(txnDoc);
- fixUpInfo.refetchTransactionDocs = true;
+ // changed to the uuid of the session transaction table collection. Need to add
+ // txnDoc.uuid with the proper uuid.
+ // DocID txnDoc;
+ // BSONObjBuilder txnBob;
+ // txnBob.append("_id", sessionId->toBSON());
+ // txnDoc.ownedObj = txnBob.obj();
+ // txnDoc._id = txnDoc.ownedObj.firstElement();
+ // txnDoc.ns = NamespaceString::kSessionTransactionsTableNamespace.ns().c_str();
+ //
+ // fixUpInfo.docsToRefetch.insert(txnDoc);
+ // fixUpInfo.refetchTransactionDocs = true;
}
if (oplogEntry.getOpType() == OpTypeEnum::kCommand) {
@@ -350,7 +341,7 @@ Status rollback_internal::updateFixUpInfoFromLocalOplogEntry(FixUpInfo& fixUpInf
"Missing index name in dropIndexes operation on rollback.");
}
- BSONObj obj2 = *(oplogEntry.getObject2());
+ BSONObj obj2 = oplogEntry.getObject2().get().getOwned();
// Inserts the index name and the index spec of the index to be created into the map
// of index name and index specs that need to be created for the given collection.
@@ -434,14 +425,14 @@ Status rollback_internal::updateFixUpInfoFromLocalOplogEntry(FixUpInfo& fixUpInf
}
}
- // Checks if the renameColl ection is a cross-database rename. If the dropSource
+ // Checks if the renameCollection is a cross-database rename. If the dropSource
// field is present in the oplog entry then the renameCollection must be a
// cross-database rename. The field will be absent in renames in the same
// database.
auto dropSource = obj.getField("dropSource");
if (!dropSource.eoo()) {
return fixUpInfo.recordCrossDatabaseRenameRollbackInfo(
- dropSource, obj, nss, *uuid, oplogEntry.getOpTime());
+ dropSource, obj, NamespaceString(ns), *uuid, oplogEntry.getOpTime());
}
RenameCollectionInfo info;
@@ -571,11 +562,10 @@ Status rollback_internal::updateFixUpInfoFromLocalOplogEntry(FixUpInfo& fixUpInf
doc._id = oplogEntry.getIdElement();
if (doc._id.eoo()) {
- std::string message = str::stream() << "Cannot roll back op with no _id. ns: " << doc.ns;
+ std::string message = str::stream() << "Cannot roll back op with no _id. ns: " << nss.ns();
severe() << message << ", document: " << redact(oplogEntry.toBSON());
throw RSFatalException(message);
}
-
fixUpInfo.docsToRefetch.insert(doc);
return Status::OK();
}
@@ -659,8 +649,9 @@ void dropIndex(OperationContext* opCtx,
*/
void rollbackCreateIndexes(OperationContext* opCtx, UUID uuid, std::set<std::string> indexNames) {
- Collection* collection = UUIDCatalog::get(opCtx).lookupCollectionByUUID(uuid);
NamespaceString nss = UUIDCatalog::get(opCtx).lookupNSSByUUID(uuid);
+ Lock::DBLock dbLock(opCtx, nss.db(), MODE_X);
+ Collection* collection = UUIDCatalog::get(opCtx).lookupCollectionByUUID(uuid);
// If we cannot find the collection, we skip over dropping the index.
if (!collection) {
@@ -669,8 +660,6 @@ void rollbackCreateIndexes(OperationContext* opCtx, UUID uuid, std::set<std::str
return;
}
- Lock::DBLock dbLock(opCtx, nss.db(), MODE_X);
-
// If we cannot find the index catalog, we skip over dropping the index.
auto indexCatalog = collection->getIndexCatalog();
if (!indexCatalog) {
@@ -696,9 +685,9 @@ void rollbackDropIndexes(OperationContext* opCtx,
UUID uuid,
std::map<std::string, BSONObj> indexNames) {
- Collection* collection = UUIDCatalog::get(opCtx).lookupCollectionByUUID(uuid);
NamespaceString nss = UUIDCatalog::get(opCtx).lookupNSSByUUID(uuid);
-
+ Lock::DBLock dbLock(opCtx, nss.db(), MODE_X);
+ Collection* collection = UUIDCatalog::get(opCtx).lookupCollectionByUUID(uuid);
// If we cannot find the collection, we skip over dropping the index.
if (!collection) {
LOG(2) << "Cannot find the collection with uuid: " << uuid.toString()
@@ -706,18 +695,18 @@ void rollbackDropIndexes(OperationContext* opCtx,
return;
}
- Lock::DBLock dbLock(opCtx, nss.db(), MODE_X);
-
for (auto itIndex = indexNames.begin(); itIndex != indexNames.end(); itIndex++) {
+
const string indexName = itIndex->first;
BSONObj indexSpec = itIndex->second;
-
// We replace the namespace field because it is possible that a
// renameCollection command has occurred, changing the namespace of the
// collection from what it initially was during the creation of this index.
BSONObjBuilder updatedNss;
updatedNss.append("ns", nss.ns());
- indexSpec.addField(updatedNss.obj().firstElement());
+
+ BSONObj updatedNssObj = updatedNss.obj();
+ indexSpec.addField(updatedNssObj.firstElement());
createIndexForApplyOps(opCtx, indexSpec, nss, {});
@@ -871,6 +860,9 @@ void rollbackRenameCollection(OperationContext* opCtx, UUID uuid, RenameCollecti
severe() << "Unable to roll back renameCollection command: " << status.toString();
throw RSFatalException("Unable to rollback renameCollection command");
}
+
+ log() << "Renamed collection from " << info.renameFrom.ns() << "to " << info.renameTo.ns()
+ << " with uuid: " << uuid;
}
void syncFixUp(OperationContext* opCtx,
@@ -880,8 +872,9 @@ void syncFixUp(OperationContext* opCtx,
ReplicationProcess* replicationProcess) {
unsigned long long totalSize = 0;
- // namespace -> doc id -> doc
- map<string, map<DocID, BSONObj>> goodVersions;
+ // UUID -> doc id -> doc
+ stdx::unordered_map<UUID, std::map<DocID, BSONObj>, UUID::Hash> goodVersions;
+ auto& catalog = UUIDCatalog::get(opCtx);
// Fetches all the goodVersions of each document from the current sync source.
unsigned long long numFetched = 0;
@@ -891,11 +884,15 @@ void syncFixUp(OperationContext* opCtx,
for (auto&& doc : fixUpInfo.docsToRefetch) {
invariant(!doc._id.eoo()); // This is checked when we insert to the set.
+ UUID uuid = doc.uuid;
+ NamespaceString nss = catalog.lookupNSSByUUID(uuid);
+
try {
- LOG(2) << "Refetching document, namespace: " << doc.ns << ", _id: " << redact(doc._id);
+ LOG(2) << "Refetching document, namespace: " << nss.toString()
+ << ", _id: " << redact(doc._id);
// TODO : Slow. Lots of round trips.
numFetched++;
- BSONObj good = rollbackSource.findOne(NamespaceString(doc.ns), doc._id.wrap());
+ BSONObj good = rollbackSource.findOneByUUID(nss.db().toString(), uuid, doc._id.wrap());
totalSize += good.objsize();
// Checks that the total amount of data that needs to be refetched is at most
@@ -906,7 +903,8 @@ void syncFixUp(OperationContext* opCtx,
}
// Note good might be empty, indicating we should delete it.
- goodVersions[doc.ns][doc] = good;
+ goodVersions[uuid].insert(std::pair<DocID, BSONObj>(doc, good));
+
} catch (const DBException& ex) {
// If the collection turned into a view, we might get an error trying to
// refetch documents, but these errors should be ignored, as we'll be creating
@@ -914,7 +912,7 @@ void syncFixUp(OperationContext* opCtx,
if (ex.getCode() == ErrorCodes::CommandNotSupportedOnView)
continue;
- log() << "Rollback couldn't re-get from ns: " << doc.ns << " _id: " << redact(doc._id)
+ log() << "Rollback couldn't re-fetch from uuid: " << uuid << " _id: " << redact(doc._id)
<< ' ' << numFetched << '/' << fixUpInfo.docsToRefetch.size() << ": "
<< redact(ex);
throw;
@@ -937,16 +935,20 @@ void syncFixUp(OperationContext* opCtx,
// when undoing renameCollection operations.
for (auto uuid : fixUpInfo.collectionsToDrop) {
- // TODO: This invariant will be uncommented once the rollback via refetch for non-WT
- // project is complete. See SERVER-30171.
- // invariant(!fixUpInfo.indexesToDrop.count(uuid));
+ // Checks that if the collection is going to be dropped, all commands that
+ // were done on the collection to be dropped were removed during the function
+ // call to removeRedundantOperations().
+ invariant(!fixUpInfo.indexesToDrop.count(uuid));
+ invariant(!fixUpInfo.indexesToCreate.count(uuid));
+ invariant(!fixUpInfo.collectionsToRename.count(uuid));
+ invariant(!fixUpInfo.collectionsToResyncMetadata.count(uuid));
- Collection* collection = UUIDCatalog::get(opCtx).lookupCollectionByUUID(uuid);
NamespaceString nss = UUIDCatalog::get(opCtx).lookupNSSByUUID(uuid);
-
AutoGetDb dbLock(opCtx, nss.db(), MODE_X);
+
Database* db = dbLock.getDb();
if (db) {
+ Collection* collection = UUIDCatalog::get(opCtx).lookupCollectionByUUID(uuid);
dropCollection(opCtx, nss, collection, db);
log() << "Dropped collection with UUID: " << uuid << " and nss: " << nss;
}
@@ -977,32 +979,7 @@ void syncFixUp(OperationContext* opCtx,
}
// Full collection data and metadata resync.
- if (!fixUpInfo.collectionsToResyncData.empty() ||
- !fixUpInfo.collectionsToResyncMetadata.empty()) {
-
- // Reloads the collection data from the sync source in order
- // to roll back a drop/dropIndexes/renameCollection operation.
- for (const string& ns : fixUpInfo.collectionsToResyncData) {
- log() << "Resyncing collection, namespace: " << ns;
-
- // TODO: This invariant will be uncommented once the
- // rollback via refetch for non-WT project is complete. See SERVER-30171.
- // invariant(!fixUpInfo.indexesToDrop.count(ns));
- // invariant(!fixUpInfo.collectionsToResyncMetadata.count(ns));
-
- const NamespaceString nss(ns);
-
- {
- Lock::DBLock dbLock(opCtx, nss.db(), MODE_X);
- Database* db = dbHolder().openDb(opCtx, nss.db().toString());
- invariant(db);
- WriteUnitOfWork wunit(opCtx);
- fassertStatusOK(40505, db->dropCollectionEvenIfSystem(opCtx, nss));
- wunit.commit();
- }
-
- rollbackSource.copyCollectionFromRemote(opCtx, nss);
- }
+ if (!fixUpInfo.collectionsToResyncMetadata.empty()) {
// Retrieves collections from the sync source in order to obtain the collection
// flags needed to roll back collMod operations. We roll back collMod operations
@@ -1013,14 +990,16 @@ void syncFixUp(OperationContext* opCtx,
for (auto uuid : fixUpInfo.collectionsToResyncMetadata) {
log() << "Resyncing collection metadata, uuid: " << uuid;
- Collection* collection = UUIDCatalog::get(opCtx).lookupCollectionByUUID(uuid);
- invariant(collection);
- NamespaceString nss = collection->ns();
+ NamespaceString nss = UUIDCatalog::get(opCtx).lookupNSSByUUID(uuid);
Lock::DBLock dbLock(opCtx, nss.db(), MODE_X);
+
auto db = dbHolder().openDb(opCtx, nss.db().toString());
invariant(db);
+ Collection* collection = UUIDCatalog::get(opCtx).lookupCollectionByUUID(uuid);
+ invariant(collection);
+
auto cce = collection->getCatalogEntry();
auto infoResult = rollbackSource.getCollectionInfoByUUID(nss.db().toString(), uuid);
@@ -1115,7 +1094,7 @@ void syncFixUp(OperationContext* opCtx,
for (auto it = fixUpInfo.indexesToDrop.begin(); it != fixUpInfo.indexesToDrop.end(); it++) {
UUID uuid = it->first;
- auto indexNames = it->second;
+ std::set<std::string> indexNames = it->second;
rollbackCreateIndexes(opCtx, uuid, indexNames);
}
@@ -1125,7 +1104,7 @@ void syncFixUp(OperationContext* opCtx,
for (auto it = fixUpInfo.indexesToCreate.begin(); it != fixUpInfo.indexesToCreate.end(); it++) {
UUID uuid = it->first;
- auto indexNames = it->second;
+ std::map<std::string, BSONObj> indexNames = it->second;
rollbackDropIndexes(opCtx, uuid, indexNames);
}
@@ -1140,13 +1119,14 @@ void syncFixUp(OperationContext* opCtx,
// Keeps an archive of items rolled back if the collection has not been dropped
// while rolling back createCollection operations.
- const auto& ns = nsAndGoodVersionsByDocID.first;
+
+ const auto& uuid = nsAndGoodVersionsByDocID.first;
unique_ptr<Helpers::RemoveSaver> removeSaver;
+ invariant(!fixUpInfo.collectionsToDrop.count(uuid));
- // TODO: This invariant will be uncommented once the
- // rollback via refetch for non-WT project is complete. See SERVER-30171
- // invariant(!fixUpInfo.collectionsToDrop.count(ns));
- removeSaver.reset(new Helpers::RemoveSaver("rollback", "", ns));
+ NamespaceString nss = catalog.lookupNSSByUUID(uuid);
+
+ removeSaver.reset(new Helpers::RemoveSaver("rollback", "", nss.ns()));
const auto& goodVersionsByDocID = nsAndGoodVersionsByDocID.second;
for (const auto& idAndDoc : goodVersionsByDocID) {
@@ -1160,15 +1140,12 @@ void syncFixUp(OperationContext* opCtx,
const DocID& doc = idAndDoc.first;
BSONObj pattern = doc._id.wrap(); // { _id : ... }
try {
- verify(doc.ns && *doc.ns);
- invariant(!fixUpInfo.collectionsToResyncData.count(doc.ns));
// TODO: Lots of overhead in context. This can be faster.
const NamespaceString docNss(doc.ns);
Lock::DBLock docDbLock(opCtx, docNss.db(), MODE_X);
- OldClientContext ctx(opCtx, doc.ns);
-
- Collection* collection = ctx.db()->getCollection(opCtx, docNss);
+ OldClientContext ctx(opCtx, doc.ns.toString());
+ Collection* collection = catalog.lookupCollectionByUUID(uuid);
// Adds the doc to our rollback file if the collection was not dropped while
// rolling back createCollection operations. Does not log an error when
@@ -1182,16 +1159,16 @@ void syncFixUp(OperationContext* opCtx,
if (found) {
auto status = removeSaver->goingToDelete(obj);
if (!status.isOK()) {
- severe() << "Rollback cannot write document in namespace " << doc.ns
+ severe() << "Rollback cannot write document in namespace " << nss.ns()
<< " to archive file: " << redact(status);
throw RSFatalException(str::stream()
<< "Rollback cannot write document in namespace "
- << doc.ns
+ << nss.ns()
<< " to archive file.");
}
} else {
error() << "Rollback cannot find object: " << pattern << " in namespace "
- << doc.ns;
+ << nss.ns();
}
}
@@ -1215,7 +1192,7 @@ void syncFixUp(OperationContext* opCtx,
const auto findOneStart = clock->now();
RecordId loc = Helpers::findOne(opCtx, collection, pattern, false);
if (clock->now() - findOneStart > Milliseconds(200))
- warning() << "Roll back slow no _id index for " << doc.ns
+ warning() << "Roll back slow no _id index for " << nss.ns()
<< " perhaps?";
// Would be faster but requires index:
// RecordId loc = Helpers::findById(nsd, pattern);
@@ -1242,7 +1219,7 @@ void syncFixUp(OperationContext* opCtx,
// eventually.
warning() << "Ignoring failure to roll back change to capped "
- << "collection " << doc.ns << " with _id "
+ << "collection " << nss.ns() << " with _id "
<< redact(idAndDoc.first._id.toString(
/*includeFieldName*/ false))
<< ": " << redact(e);
@@ -1250,7 +1227,7 @@ void syncFixUp(OperationContext* opCtx,
} else {
deleteObjects(opCtx,
collection,
- docNss,
+ nss,
pattern,
true, // justOne
true); // god
@@ -1260,19 +1237,19 @@ void syncFixUp(OperationContext* opCtx,
// TODO faster...
updates++;
- UpdateRequest request(docNss);
+ UpdateRequest request(nss);
request.setQuery(pattern);
request.setUpdates(idAndDoc.second);
request.setGod();
request.setUpsert();
- UpdateLifecycleImpl updateLifecycle(docNss);
+ UpdateLifecycleImpl updateLifecycle(nss);
request.setLifecycle(&updateLifecycle);
update(opCtx, ctx.db(), request);
}
} catch (const DBException& e) {
- log() << "Exception in rollback ns:" << doc.ns << ' ' << pattern.toString() << ' '
+ log() << "Exception in rollback ns:" << nss.ns() << ' ' << pattern.toString() << ' '
<< redact(e) << " ndeletes:" << deletes;
throw;
}
diff --git a/src/mongo/db/repl/rs_rollback.h b/src/mongo/db/repl/rs_rollback.h
index 73a9ba91fb4..b4659313608 100644
--- a/src/mongo/db/repl/rs_rollback.h
+++ b/src/mongo/db/repl/rs_rollback.h
@@ -215,19 +215,24 @@ namespace rollback_internal {
struct DocID {
BSONObj ownedObj;
- const char* ns;
+ StringData ns;
BSONElement _id;
+ UUID uuid;
+
+ DocID(BSONObj obj, BSONElement id, UUID ui)
+ : ownedObj(obj), ns(obj.getStringField("ns")), _id(id), uuid(ui) {}
+
bool operator<(const DocID& other) const;
bool operator==(const DocID& other) const;
- static DocID minFor(const char* ns) {
+ static DocID minFor(UUID uuid) {
auto obj = BSON("" << MINKEY);
- return {obj, ns, obj.firstElement()};
+ return DocID(obj, obj.firstElement(), uuid);
}
- static DocID maxFor(const char* ns) {
+ static DocID maxFor(UUID uuid) {
auto obj = BSON("" << MAXKEY);
- return {obj, ns, obj.firstElement()};
+ return DocID(obj, obj.firstElement(), uuid);
}
};
@@ -245,9 +250,6 @@ struct FixUpInfo {
// we only need to refetch it once.
std::set<DocID> docsToRefetch;
- // Namespaces of collections that need to be resynced from the sync source.
- std::set<std::string> collectionsToResyncData;
-
// UUID of collections that need to be dropped.
stdx::unordered_set<UUID, UUID::Hash> collectionsToDrop;
@@ -293,7 +295,7 @@ struct FixUpInfo {
* Removes all documents in the docsToRefetch set that are in
* the collection passed into the function.
*/
- void removeAllDocsToRefetchFor(const std::string& collection);
+ void removeAllDocsToRefetchFor(UUID uuid);
/**
* Removes any redundant operations that may have happened during
diff --git a/src/mongo/db/repl/rs_rollback_no_uuid_test.cpp b/src/mongo/db/repl/rs_rollback_no_uuid_test.cpp
index f20292dd957..57e2ca10c9f 100644
--- a/src/mongo/db/repl/rs_rollback_no_uuid_test.cpp
+++ b/src/mongo/db/repl/rs_rollback_no_uuid_test.cpp
@@ -72,6 +72,7 @@ public:
const HostAndPort& getSource() const override;
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;
void copyCollectionFromRemote(OperationContext* opCtx,
const NamespaceString& nss) const override;
StatusWith<BSONObj> getCollectionInfoByUUID(const std::string& db,
@@ -109,12 +110,18 @@ 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();
+}
+
void RollbackSourceMock::copyCollectionFromRemote(OperationContext* opCtx,
const NamespaceString& nss) const {}
StatusWith<BSONObj> RollbackSourceMock::getCollectionInfoByUUID(const std::string& db,
const UUID& uuid) const {
- return BSON("info" << BSON("uuid" << uuid) << "options" << BSONObj());
+ return BSON("options" << BSONObj() << "info" << BSON("uuid" << uuid));
}
StatusWith<BSONObj> RollbackSourceMock::getCollectionInfo(const NamespaceString& nss) const {
diff --git a/src/mongo/db/repl/rs_rollback_test.cpp b/src/mongo/db/repl/rs_rollback_test.cpp
index 30422f1456b..c2a67fe5c4a 100644
--- a/src/mongo/db/repl/rs_rollback_test.cpp
+++ b/src/mongo/db/repl/rs_rollback_test.cpp
@@ -74,6 +74,9 @@ public:
const HostAndPort& getSource() const override;
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;
+
void copyCollectionFromRemote(OperationContext* opCtx,
const NamespaceString& nss) const override;
StatusWith<BSONObj> getCollectionInfoByUUID(const std::string& db,
@@ -111,6 +114,12 @@ 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();
+}
+
void RollbackSourceMock::copyCollectionFromRemote(OperationContext* opCtx,
const NamespaceString& nss) const {}
@@ -120,7 +129,7 @@ StatusWith<BSONObj> RollbackSourceMock::getCollectionInfo(const NamespaceString&
StatusWith<BSONObj> RollbackSourceMock::getCollectionInfoByUUID(const std::string& db,
const UUID& uuid) const {
- return BSON("options" << BSON("uuid" << uuid));
+ return BSON("options" << BSONObj() << "info" << BSON("uuid" << uuid));
}
@@ -387,7 +396,7 @@ int _testRollbackDelete(OperationContext* opCtx,
: RollbackSourceMock(std::move(oplog)),
called(false),
_documentAtSource(documentAtSource) {}
- BSONObj findOne(const NamespaceString& nss, const BSONObj& filter) const {
+ BSONObj findOneByUUID(const std::string& db, UUID uuid, const BSONObj& filter) const {
called = true;
return _documentAtSource;
}
@@ -982,7 +991,7 @@ TEST_F(RSRollbackTest, RollbackRenameCollectionInSameDatabaseCommand) {
// StatusWith<BSONObj> getCollectionInfoByUUID(const std::string& db, const UUID& uuid) const
// {
// getCollectionInfoCalled = true;
-// return BSON("options" << BSON("uuid" << uuid << "temp" << true));
+// return BSON("info" << BSON("uuid" << uuid) << "options" << BSON("temp" << true)));
// }
// mutable bool getCollectionInfoCalled = false;
// };
@@ -1634,7 +1643,9 @@ TEST_F(RSRollbackTest, RollbackApplyOpsCommand) {
RollbackSourceLocal(std::unique_ptr<OplogInterface> oplog)
: RollbackSourceMock(std::move(oplog)) {}
- BSONObj findOne(const NamespaceString& nss, const BSONObj& filter) const override {
+ BSONObj findOneByUUID(const std::string& db,
+ UUID uuid,
+ const BSONObj& filter) const override {
int numFields = 0;
for (const auto element : filter) {
++numFields;
@@ -1964,49 +1975,53 @@ DEATH_TEST_F(RSRollbackTest, LocalEntryWithTxnNumberWithoutStmtIdIsFatal, "invar
RSFatalException);
}
-TEST(RSRollbackTest, LocalEntryWithTxnNumberAddsTransactionTableDocToBeRefetched) {
- FixUpInfo fui;
- auto entryWithoutTxnNumber =
- BSON("ts" << Timestamp(Seconds(1), 0) << "t" << 1LL << "h" << 1LL << "op"
- << "i"
- << "ui"
- << UUID::gen()
- << "ns"
- << "test.t2"
- << "o"
- << BSON("_id" << 2 << "a" << 2));
- ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(fui, entryWithoutTxnNumber));
-
- // With no txnNumber present, no extra documents need to be refetched.
- ASSERT_EQ(fui.docsToRefetch.size(), 1U);
-
- auto entryWithTxnNumber =
- BSON("ts" << Timestamp(Seconds(1), 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());
- ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(fui, entryWithTxnNumber));
-
- // If txnNumber is present, the session transactions table document corresponding to the oplog
- // entry's sessionId also needs to be refetched.
- ASSERT_EQ(fui.docsToRefetch.size(), 3U);
-
- DocID expectedTxnDoc;
- expectedTxnDoc.ownedObj = BSON("_id" << entryWithTxnNumber["lsid"]);
- expectedTxnDoc._id = expectedTxnDoc.ownedObj.firstElement();
- expectedTxnDoc.ns = NamespaceString::kSessionTransactionsTableNamespace.ns().c_str();
- ASSERT_TRUE(fui.docsToRefetch.find(expectedTxnDoc) != fui.docsToRefetch.end());
-}
+// TODO: Uncomment this test once transactions have been updated to work with the proper
+// uuid. See SERVER-30076.
+// TEST(RSRollbackTest, LocalEntryWithTxnNumberAddsTransactionTableDocToBeRefetched) {
+// FixUpInfo fui;
+// auto entryWithoutTxnNumber =
+// BSON("ts" << Timestamp(Seconds(1), 0) << "t" << 1LL << "h" << 1LL << "op"
+// << "i"
+// << "ui"
+// << UUID::gen()
+// << "ns"
+// << "test.t2"
+// << "o"
+// << BSON("_id" << 2 << "a" << 2));
+// ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(fui, entryWithoutTxnNumber));
+//
+// // With no txnNumber present, no extra documents need to be refetched.
+// ASSERT_EQ(fui.docsToRefetch.size(), 1U);
+//
+// UUID uuid = UUID::gen();
+// auto entryWithTxnNumber =
+// BSON("ts" << Timestamp(Seconds(1), 0) << "t" << 1LL << "h" << 1LL << "op"
+// << "i"
+// << "ui"
+// << uuid
+// << "ns"
+// << "test.t"
+// << "o"
+// << BSON("_id" << 1 << "a" << 1)
+// << "txnNumber"
+// << 1LL
+// << "stmtId"
+// << 1
+// << "lsid"
+// << makeLogicalSessionIdForTest().toBSON());
+// ASSERT_OK(updateFixUpInfoFromLocalOplogEntry(fui, entryWithTxnNumber));
+//
+// // If txnNumber is present, the session transactions table document corresponding to the oplog
+// // entry's sessionId also needs to be refetched.
+// ASSERT_EQ(fui.docsToRefetch.size(), 3U);
+//
+// DocID expectedTxnDoc;
+// expectedTxnDoc.ownedObj = BSON("_id" << entryWithTxnNumber["lsid"]);
+// expectedTxnDoc._id = expectedTxnDoc.ownedObj.firstElement();
+// expectedTxnDoc.ns = NamespaceString::kSessionTransactionsTableNamespace.ns().c_str();
+// expectedTxnDoc.uuid = uuid;
+// ASSERT_TRUE(fui.docsToRefetch.find(expectedTxnDoc) != fui.docsToRefetch.end());
+//}
TEST_F(RSRollbackTest, RollbackReturnsImmediatelyOnFailureToTransitionToRollback) {
// On failing to transition to ROLLBACK, rollback() should return immediately and not call
@@ -2116,51 +2131,55 @@ TEST(FixUpInfoTest, RemoveAllDocsToRefetchForWorks) {
const auto normalHolder = BSON("" << OID::gen());
const auto normalKey = normalHolder.firstElement();
+ UUID uuid1 = UUID::gen();
+ UUID uuid2 = UUID::gen();
+ UUID uuid3 = UUID::gen();
+
// Can't use ASSERT_EQ with this since it isn't ostream-able. Failures will at least give you
// the size. If that isn't enough, use GDB.
using DocSet = std::set<DocID>;
FixUpInfo fui;
fui.docsToRefetch = {
- DocID::minFor("a"),
- DocID{{}, "a", normalKey},
- DocID::maxFor("a"),
+ DocID::minFor(uuid1),
+ DocID{{}, normalKey, uuid1},
+ DocID::maxFor(uuid1),
- DocID::minFor("b"),
- DocID{{}, "b", normalKey},
- DocID::maxFor("b"),
+ DocID::minFor(uuid2),
+ DocID{{}, normalKey, uuid2},
+ DocID::maxFor(uuid2),
- DocID::minFor("c"),
- DocID{{}, "c", normalKey},
- DocID::maxFor("c"),
+ DocID::minFor(uuid3),
+ DocID{{}, normalKey, uuid3},
+ DocID::maxFor(uuid3),
};
// Remove from the middle.
- fui.removeAllDocsToRefetchFor("b");
+ fui.removeAllDocsToRefetchFor(uuid2);
ASSERT((fui.docsToRefetch ==
DocSet{
- DocID::minFor("a"),
- DocID{{}, "a", normalKey},
- DocID::maxFor("a"),
+ DocID::minFor(uuid1),
+ DocID{{}, normalKey, uuid1},
+ DocID::maxFor(uuid1),
- DocID::minFor("c"),
- DocID{{}, "c", normalKey},
- DocID::maxFor("c"),
+ DocID::minFor(uuid3),
+ DocID{{}, normalKey, uuid3},
+ DocID::maxFor(uuid3),
}))
<< "remaining docs: " << fui.docsToRefetch.size();
// Remove from the end.
- fui.removeAllDocsToRefetchFor("c");
+ fui.removeAllDocsToRefetchFor(uuid3);
ASSERT((fui.docsToRefetch ==
DocSet{
- DocID::minFor("a"), // This comment helps clang-format.
- DocID{{}, "a", normalKey},
- DocID::maxFor("a"),
+ DocID::minFor(uuid1), // This comment helps clang-format.
+ DocID{{}, normalKey, uuid1},
+ DocID::maxFor(uuid1),
}))
<< "remaining docs: " << fui.docsToRefetch.size();
// Everything else.
- fui.removeAllDocsToRefetchFor("a");
+ fui.removeAllDocsToRefetchFor(uuid1);
ASSERT((fui.docsToRefetch == DocSet{})) << "remaining docs: " << fui.docsToRefetch.size();
}