diff options
Diffstat (limited to 'src/mongo/db/catalog')
| -rw-r--r-- | src/mongo/db/catalog/apply_ops.cpp | 57 | ||||
| -rw-r--r-- | src/mongo/db/catalog/capped_utils.cpp | 5 | ||||
| -rw-r--r-- | src/mongo/db/catalog/collection_catalog_entry.h | 2 | ||||
| -rw-r--r-- | src/mongo/db/catalog/database.cpp | 19 | ||||
| -rw-r--r-- | src/mongo/db/catalog/index_create.cpp | 39 |
5 files changed, 71 insertions, 51 deletions
diff --git a/src/mongo/db/catalog/apply_ops.cpp b/src/mongo/db/catalog/apply_ops.cpp index a7306940d68..552376301cb 100644 --- a/src/mongo/db/catalog/apply_ops.cpp +++ b/src/mongo/db/catalog/apply_ops.cpp @@ -180,39 +180,32 @@ Status _applyOps(OperationContext* opCtx, NamespaceString requestNss{ns}; if (nss.isSystemDotIndexes()) { - BSONObj indexSpec; - NamespaceString indexNss; - std::tie(indexSpec, indexNss) = - repl::prepForApplyOpsIndexInsert(fieldO, opObj, requestNss); - if (!indexSpec["collation"]) { - // If the index spec does not include a collation, explicitly - // specify the simple collation, so the index does not inherit the - // collection default collation. - auto indexVersion = indexSpec["v"]; - // The index version is populated by prepForApplyOpsIndexInsert(). - invariant(indexVersion); - if (indexVersion.isNumber() && - (indexVersion.numberInt() >= - static_cast<int>(IndexDescriptor::IndexVersion::kV2))) { - BSONObjBuilder bob; - bob.append("collation", CollationSpec::kSimpleSpec); - bob.appendElements(indexSpec); - indexSpec = bob.obj(); - } - } - BSONObjBuilder command; - command.append("createIndexes", indexNss.coll()); - { - BSONArrayBuilder indexes(command.subarrayStart("indexes")); - indexes.append(indexSpec); - indexes.doneFast(); + invariant(opCtx->lockState()->isW()); + + // Disable background index builds when inserting into system.indexes. + // This causes the TempRelease to fail within applyOperation_inlock(), + // leading to the background index being built in the foreground. + // We do not want a background index build because we need to validate + // the index spec and also to avoid issues resulting from any metadata + // changes before the background thread starts. + Lock::GlobalWrite nestedGlobalWriteLock(opCtx->lockState()); + + OldClientContext ctx(opCtx, nss.ns()); + status = + repl::applyOperation_inlock(opCtx, ctx.db(), opObj, alwaysUpsert); + + // applyOperation_inlock() builds the index but does not notify the + // OpObserver. Previously, applyOps relied on the createIndexes command + // to perform this function. The value used for the 'forMigrate' + // argument is consistent with create_indexes.cpp. + if (status.isOK()) { + WriteUnitOfWork wuow(opCtx); + auto opObserver = getGlobalServiceContext()->getOpObserver(); + invariant(opObserver); + auto indexSpec = fieldO.embeddedObject(); + opObserver->onCreateIndex(opCtx, nss.ns(), indexSpec, false); + wuow.commit(); } - const BSONObj commandObj = command.done(); - - DBDirectClient client(opCtx); - BSONObj infoObj; - client.runCommand(nsToDatabase(ns), commandObj, infoObj); - status = getStatusFromCommandResult(infoObj); } else { AutoGetCollection autoColl(opCtx, nss, MODE_IX); if (!autoColl.getCollection() && !nss.isSystemDotIndexes()) { diff --git a/src/mongo/db/catalog/capped_utils.cpp b/src/mongo/db/catalog/capped_utils.cpp index 71f74628f01..63b46d3c3a8 100644 --- a/src/mongo/db/catalog/capped_utils.cpp +++ b/src/mongo/db/catalog/capped_utils.cpp @@ -66,13 +66,13 @@ Status emptyCapped(OperationContext* txn, const NamespaceString& collectionName) } Database* db = autoDb.getDb(); - massert(13429, "no such database", db); + uassert(ErrorCodes::NamespaceNotFound, "no such database", db); Collection* collection = db->getCollection(collectionName); uassert(ErrorCodes::CommandNotSupportedOnView, str::stream() << "emptycapped not supported on view: " << collectionName.ns(), collection || !db->getViewCatalog()->lookup(txn, collectionName.ns())); - massert(28584, "no such collection", collection); + uassert(ErrorCodes::NamespaceNotFound, "no such collection", collection); if (collectionName.isSystem() && !collectionName.isSystemDotProfile()) { return Status(ErrorCodes::IllegalOperation, @@ -268,6 +268,7 @@ Status convertToCapped(OperationContext* txn, const NamespaceString& collectionN Status status = db->dropCollection(txn, longTmpName); if (!status.isOK()) return status; + wunit.commit(); } diff --git a/src/mongo/db/catalog/collection_catalog_entry.h b/src/mongo/db/catalog/collection_catalog_entry.h index dd6a1f506f1..38e5b12d234 100644 --- a/src/mongo/db/catalog/collection_catalog_entry.h +++ b/src/mongo/db/catalog/collection_catalog_entry.h @@ -64,6 +64,8 @@ public: virtual BSONObj getIndexSpec(OperationContext* txn, StringData idxName) const = 0; + virtual void getReadyIndexes(OperationContext* txn, std::vector<std::string>* names) const = 0; + /** * Returns true if the index identified by 'indexName' is multikey, and returns false otherwise. * diff --git a/src/mongo/db/catalog/database.cpp b/src/mongo/db/catalog/database.cpp index 23fdfb84e95..4b27ff0e48f 100644 --- a/src/mongo/db/catalog/database.cpp +++ b/src/mongo/db/catalog/database.cpp @@ -564,15 +564,26 @@ Collection* Database::createCollection(OperationContext* txn, : ic->getDefaultIdIndexSpec(featureCompatibilityVersion))); } } - - if (nss.isSystem()) { - authindex::createSystemIndexes(txn, collection); - } } getGlobalServiceContext()->getOpObserver()->onCreateCollection( txn, nss, options, fullIdIndexSpec); + // It is necessary to create the system index *after* running the onCreateCollection so that + // the oplog timestamp for the index creation is after the oplog timestamp for the + // collection creation. This way both primary and any secondaries will see the index created + // after the collection is created. + if (createIdIndex && nss.isSystem()) { + // We only want to create the indexes here on the primary. On secondaries, they will + // be created by the normal oplog application process. + auto coordinator = repl::ReplicationCoordinator::get(txn); + const bool canAcceptWrites = + (coordinator->getReplicationMode() != repl::ReplicationCoordinator::modeReplSet) || + coordinator->canAcceptWritesForDatabase(nss.db()) || nss.isSystemDotProfile(); + if (canAcceptWrites) { + authindex::createSystemIndexes(txn, collection); + } + } return collection; } diff --git a/src/mongo/db/catalog/index_create.cpp b/src/mongo/db/catalog/index_create.cpp index 17a3d981d5d..6a323605521 100644 --- a/src/mongo/db/catalog/index_create.cpp +++ b/src/mongo/db/catalog/index_create.cpp @@ -65,6 +65,8 @@ using std::endl; MONGO_FP_DECLARE(crashAfterStartingIndexBuild); MONGO_FP_DECLARE(hangAfterStartingIndexBuild); MONGO_FP_DECLARE(hangAfterStartingIndexBuildUnlocked); +MONGO_FP_DECLARE(hangBeforeIndexBuildOf); +MONGO_FP_DECLARE(hangAfterIndexBuildOf); std::atomic<std::int32_t> maxIndexBuildMemoryUsageMegabytes(500); // NOLINT @@ -282,6 +284,16 @@ StatusWith<std::vector<BSONObj>> MultiIndexBlock::init(const std::vector<BSONObj return indexInfoObjs; } +void failPointHangDuringBuild(FailPoint* fp, StringData where, const BSONObj& doc) { + MONGO_FAIL_POINT_BLOCK(*fp, data) { + int i = doc.getIntField("i"); + if (data.getData()["i"].numberInt() == i) { + log() << "Hanging " << where << " index build of i=" << i; + MONGO_FAIL_POINT_PAUSE_WHILE_SET((*fp)); + } + } +} + Status MultiIndexBlock::insertAllDocumentsInCollection(std::set<RecordId>* dupsOut) { const char* curopMessage = _buildInBackground ? "Index Build (background)" : "Index Build"; const auto numRecords = _collection->numRecords(_txn); @@ -307,11 +319,20 @@ Status MultiIndexBlock::insertAllDocumentsInCollection(std::set<RecordId>* dupsO PlanExecutor::ExecState state; int retries = 0; // non-zero when retrying our last document. while (retries || - (PlanExecutor::ADVANCED == (state = exec->getNextSnapshotted(&objToIndex, &loc)))) { + (PlanExecutor::ADVANCED == (state = exec->getNextSnapshotted(&objToIndex, &loc))) || + MONGO_FAIL_POINT(hangAfterStartingIndexBuild)) { try { if (_allowInterruption) _txn->checkForInterrupt(); + if (!(retries || (PlanExecutor::ADVANCED == state))) { + // The only reason we are still in the loop is hangAfterStartingIndexBuild. + log() << "Hanging index build due to 'hangAfterStartingIndexBuild' failpoint"; + invariant(_allowInterruption); + sleepmillis(1000); + continue; + } + // Make sure we are working with the latest version of the document. if (objToIndex.snapshotId() != _txn->recoveryUnit()->getSnapshotId() && !_collection->findDoc(_txn, loc, &objToIndex)) { @@ -323,6 +344,8 @@ Status MultiIndexBlock::insertAllDocumentsInCollection(std::set<RecordId>* dupsO // Done before insert so we can retry document if it WCEs. progress->setTotalWhileRunning(_collection->numRecords(_txn)); + failPointHangDuringBuild(&hangBeforeIndexBuildOf, "before", objToIndex.value()); + WriteUnitOfWork wunit(_txn); Status ret = insert(objToIndex.value(), loc); if (_buildInBackground) @@ -340,6 +363,8 @@ Status MultiIndexBlock::insertAllDocumentsInCollection(std::set<RecordId>* dupsO if (_buildInBackground) exec->restoreState(); // Handles any WCEs internally. + failPointHangDuringBuild(&hangAfterIndexBuildOf, "after", objToIndex.value()); + // Go to the next document progress->hit(); n++; @@ -362,18 +387,6 @@ Status MultiIndexBlock::insertAllDocumentsInCollection(std::set<RecordId>* dupsO WorkingSetCommon::toStatusString(objToIndex.value()), state == PlanExecutor::IS_EOF); - if (MONGO_FAIL_POINT(hangAfterStartingIndexBuild)) { - // Need the index build to hang before the progress meter is marked as finished so we can - // reliably check that the index build has actually started in js tests. - while (MONGO_FAIL_POINT(hangAfterStartingIndexBuild)) { - log() << "Hanging index build due to 'hangAfterStartingIndexBuild' failpoint"; - sleepmillis(1000); - } - - // Check for interrupt to allow for killop prior to index build completion. - _txn->checkForInterrupt(); - } - if (MONGO_FAIL_POINT(hangAfterStartingIndexBuildUnlocked)) { // Unlock before hanging so replication recognizes we've completed. Locker::LockSnapshot lockInfo; |
