summaryrefslogtreecommitdiff
path: root/src/mongo/db/repl/oplog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/repl/oplog.cpp')
-rw-r--r--src/mongo/db/repl/oplog.cpp131
1 files changed, 71 insertions, 60 deletions
diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp
index 43a1eba5042..76df271ed78 100644
--- a/src/mongo/db/repl/oplog.cpp
+++ b/src/mongo/db/repl/oplog.cpp
@@ -116,6 +116,11 @@ namespace {
// cached copy...so don't rename, drop, etc.!!!
Collection* _localOplogCollection = nullptr;
+// Specifies whether we abort initial sync when attempting to apply a renameCollection operation.
+// If set to true, users risk corrupting their data. This should only be enabled by expert users
+// of the server who understand the risks this poses.
+MONGO_EXPORT_SERVER_PARAMETER(allowUnsafeRenamesDuringInitialSync, bool, false);
+
PseudoRandom hashGenerator(std::unique_ptr<SecureRandom>(SecureRandom::create())->nextInt64());
// Synchronizes the section where a new Timestamp is generated and when it actually
@@ -663,6 +668,45 @@ std::map<std::string, ApplyOpMetadata> opsMap = {
} // namespace
+std::pair<BSONObj, NamespaceString> prepForApplyOpsIndexInsert(const BSONElement& fieldO,
+ const BSONObj& op,
+ const NamespaceString& requestNss) {
+ uassert(ErrorCodes::NoSuchKey,
+ str::stream() << "Missing expected index spec in field 'o': " << op,
+ !fieldO.eoo());
+ uassert(ErrorCodes::TypeMismatch,
+ str::stream() << "Expected object for index spec in field 'o': " << op,
+ fieldO.isABSONObj());
+ BSONObj indexSpec = fieldO.embeddedObject();
+
+ std::string indexNs;
+ uassertStatusOK(bsonExtractStringField(indexSpec, "ns", &indexNs));
+ const NamespaceString indexNss(indexNs);
+ uassert(ErrorCodes::InvalidNamespace,
+ str::stream() << "Invalid namespace in index spec: " << op,
+ indexNss.isValid());
+ uassert(ErrorCodes::InvalidNamespace,
+ str::stream() << "Database name mismatch for database (" << requestNss.db()
+ << ") while creating index: "
+ << op,
+ requestNss.db() == indexNss.db());
+
+ if (!indexSpec["v"]) {
+ // If the "v" field isn't present in the index specification, then we assume it is a
+ // v=1 index from an older version of MongoDB. This is because
+ // (1) we haven't built v=0 indexes as the default for a long time, and
+ // (2) the index version has been included in the corresponding oplog entry since
+ // v=2 indexes were introduced.
+ BSONObjBuilder bob;
+
+ bob.append("v", static_cast<int>(IndexVersion::kV1));
+ bob.appendElements(indexSpec);
+
+ indexSpec = bob.obj();
+ }
+
+ return std::make_pair(indexSpec, indexNss);
+}
// @return failure status if an update should have happened and the document DNE.
// See replset initial sync code.
Status applyOperation_inlock(OperationContext* txn,
@@ -688,6 +732,7 @@ Status applyOperation_inlock(OperationContext* txn,
o = fieldO.embeddedObject();
const StringData ns = fieldNs.valueStringData();
+ NamespaceString requestNss{ns};
BSONObj o2;
if (fieldO2.isABSONObj())
@@ -718,27 +763,11 @@ Status applyOperation_inlock(OperationContext* txn,
invariant(*opType != 'c'); // commands are processed in applyCommand_inlock()
if (*opType == 'i') {
- if (nsToCollectionSubstring(ns) == "system.indexes") {
- uassert(ErrorCodes::NoSuchKey,
- str::stream() << "Missing expected index spec in field 'o': " << op,
- !fieldO.eoo());
- uassert(ErrorCodes::TypeMismatch,
- str::stream() << "Expected object for index spec in field 'o': " << op,
- fieldO.isABSONObj());
- BSONObj indexSpec = fieldO.embeddedObject();
-
- std::string indexNs;
- uassertStatusOK(bsonExtractStringField(indexSpec, "ns", &indexNs));
- const NamespaceString indexNss(indexNs);
- uassert(ErrorCodes::InvalidNamespace,
- str::stream() << "Invalid namespace in index spec: " << op,
- indexNss.isValid());
- uassert(ErrorCodes::InvalidNamespace,
- str::stream() << "Database name mismatch for database ("
- << nsToDatabaseSubstring(ns)
- << ") while creating index: "
- << op,
- nsToDatabaseSubstring(ns) == indexNss.db());
+ if (requestNss.isSystemDotIndexes()) {
+ BSONObj indexSpec;
+ NamespaceString indexNss;
+ std::tie(indexSpec, indexNss) =
+ repl::prepForApplyOpsIndexInsert(fieldO, op, requestNss);
// Check if collection exists.
auto indexCollection = db->getCollection(indexNss);
@@ -749,20 +778,6 @@ Status applyOperation_inlock(OperationContext* txn,
opCounters->gotInsert();
- if (!indexSpec["v"]) {
- // If the "v" field isn't present in the index specification, then we assume it is a
- // v=1 index from an older version of MongoDB. This is because
- // (1) we haven't built v=0 indexes as the default for a long time, and
- // (2) the index version has been included in the corresponding oplog entry since
- // v=2 indexes were introduced.
- BSONObjBuilder bob;
-
- bob.append("v", static_cast<int>(IndexVersion::kV1));
- bob.appendElements(indexSpec);
-
- indexSpec = bob.obj();
- }
-
bool relaxIndexConstraints =
ReplicationCoordinator::get(txn)->shouldRelaxIndexConstraints(indexNss);
if (indexSpec["background"].trueValue()) {
@@ -863,13 +878,12 @@ Status applyOperation_inlock(OperationContext* txn,
BSONObjBuilder b;
b.append(o.getField("_id"));
- const NamespaceString requestNs(ns);
- UpdateRequest request(requestNs);
+ UpdateRequest request(requestNss);
request.setQuery(b.done());
request.setUpdates(o);
request.setUpsert();
- UpdateLifecycleImpl updateLifecycle(requestNs);
+ UpdateLifecycleImpl updateLifecycle(requestNss);
request.setLifecycle(&updateLifecycle);
UpdateResult res = update(txn, db, request);
@@ -894,13 +908,12 @@ Status applyOperation_inlock(OperationContext* txn,
str::stream() << "Failed to apply update due to missing _id: " << op.toString(),
updateCriteria.hasField("_id"));
- const NamespaceString requestNs(ns);
- UpdateRequest request(requestNs);
+ UpdateRequest request(requestNss);
request.setQuery(updateCriteria);
request.setUpdates(o);
request.setUpsert(upsert);
- UpdateLifecycleImpl updateLifecycle(requestNs);
+ UpdateLifecycleImpl updateLifecycle(requestNss);
request.setLifecycle(&updateLifecycle);
UpdateResult ur = update(txn, db, request);
@@ -954,7 +967,12 @@ Status applyOperation_inlock(OperationContext* txn,
o.hasField("_id"));
if (opType[1] == 0) {
- deleteObjects(txn, collection, ns, o, PlanExecutor::YIELD_MANUAL, /*justOne*/ valueB);
+ deleteObjects(txn,
+ collection,
+ requestNss.ns().c_str(),
+ o,
+ PlanExecutor::YIELD_MANUAL,
+ /*justOne*/ valueB);
} else
verify(opType[1] == 'b'); // "db" advertisement
if (incrementOpsAppliedStats) {
@@ -970,16 +988,6 @@ Status applyOperation_inlock(OperationContext* txn,
14825, str::stream() << "error in applyOperation : unknown opType " << *opType);
}
- // AuthorizationManager's logOp method registers a RecoveryUnit::Change and to do so we need
- // to a new WriteUnitOfWork, if we dont have a wrapping unit of work already. If we already
- // have a wrapping WUOW, the extra nexting is harmless. The logOp really should have been
- // done in the WUOW that did the write, but this won't happen because applyOps turns off
- // observers.
- WriteUnitOfWork wuow(txn);
- getGlobalAuthorizationManager()->logOp(
- txn, opType, ns.toString().c_str(), o, fieldO2.isABSONObj() ? &o2 : NULL);
- wuow.commit();
-
return Status::OK();
}
@@ -1021,9 +1029,15 @@ Status applyCommand_inlock(OperationContext* txn,
// Applying renameCollection during initial sync might lead to data corruption, so we restart
// the initial sync.
if (!inSteadyStateReplication && o.firstElementFieldName() == std::string("renameCollection")) {
- return Status(ErrorCodes::OplogOperationUnsupported,
- str::stream() << "Applying renameCollection not supported in initial sync: "
- << redact(op));
+ if (!allowUnsafeRenamesDuringInitialSync.load()) {
+ return Status(ErrorCodes::OplogOperationUnsupported,
+ str::stream()
+ << "Applying renameCollection not supported in initial sync: "
+ << redact(op));
+ }
+ warning() << "allowUnsafeRenamesDuringInitialSync set to true. Applying renameCollection "
+ "operation during initial sync even though it may lead to data corruption: "
+ << redact(op);
}
// Applying commands in repl is done under Global W-lock, so it is safe to not
@@ -1071,11 +1085,8 @@ Status applyCommand_inlock(OperationContext* txn,
break;
}
default:
- if (_oplogCollectionName == masterSlaveOplogName) {
- error() << "Failed command " << redact(o) << " on " << nss.db()
- << " with status " << status << " during oplog application";
- } else if (curOpToApply.acceptableErrors.find(status.code()) ==
- curOpToApply.acceptableErrors.end()) {
+ if (curOpToApply.acceptableErrors.find(status.code()) ==
+ curOpToApply.acceptableErrors.end()) {
error() << "Failed command " << redact(o) << " on " << nss.db()
<< " with status " << status << " during oplog application";
return status;