void forceDatabaseRefresh(OperationContext* opCtx, const StringData dbName) { invariant(!opCtx->lockState()->isLocked()); invariant(!opCtx->getClient()->isInDirectClient()); auto const shardingState = ShardingState::get(opCtx); invariant(shardingState->canAcceptShardedCommands()); const auto refreshedDbVersion = uassertStatusOK(Grid::get(opCtx)->catalogCache()->getDatabaseWithRefresh(opCtx, dbName)) .databaseVersion(); // First, check under a shared lock if another thread already updated the cached version. // This is a best-effort optimization to make as few threads as possible to convoy on the // exclusive lock below. auto databaseHolder = DatabaseHolder::get(opCtx); { // Take the DBLock directly rather than using AutoGetDb, to prevent a recursive call // into checkDbVersion(). Lock::DBLock dbLock(opCtx, dbName, MODE_IS); auto db = databaseHolder->getDb(opCtx, dbName); if (!db) { log() << "Database " << dbName << " has been dropped; not caching the refreshed databaseVersion"; return; } auto& dss = DatabaseShardingState::get(db); auto dssLock = DatabaseShardingState::DSSLock::lock(opCtx, &dss); const auto cachedDbVersion = dss.getDbVersion(opCtx, dssLock); if (cachedDbVersion && cachedDbVersion->getUuid() == refreshedDbVersion.getUuid() && cachedDbVersion->getLastMod() >= refreshedDbVersion.getLastMod()) { LOG(2) << "Skipping setting cached databaseVersion for " << dbName << " to refreshed version " << refreshedDbVersion.toBSON() << " because current cached databaseVersion is already " << cachedDbVersion->toBSON(); return; } } // The cached version is older than the refreshed version; update the cached version. Lock::DBLock dbLock(opCtx, dbName, MODE_X); auto db = databaseHolder->getDb(opCtx, dbName); if (!db) { log() << "Database " << dbName << " has been dropped; not caching the refreshed databaseVersion"; return; } auto& dss = DatabaseShardingState::get(db); auto dssLock = DatabaseShardingState::DSSLock::lockExclusive(opCtx, &dss); dss.setDbVersion(opCtx, std::move(refreshedDbVersion), dssLock); }
bool run(OperationContext* opCtx, const std::string& dbNameUnused, const BSONObj& cmdObj, BSONObjBuilder& result) final { Lock::GlobalLock global(opCtx, MODE_X); // This command will fail without modifying the catalog if there are any databases that are // marked drop-pending. (Otherwise, the Database object will be reconstructed when // re-opening the catalog, but with the drop pending flag cleared.) auto databaseHolder = DatabaseHolder::get(opCtx); std::vector<std::string> allDbs; getGlobalServiceContext()->getStorageEngine()->listDatabases(&allDbs); for (auto&& dbName : allDbs) { const auto db = databaseHolder->getDb(opCtx, dbName); if (db->isDropPending(opCtx)) { uasserted(ErrorCodes::DatabaseDropPending, str::stream() << "cannot restart the catalog because database " << dbName << " is pending removal"); } } log() << "Closing database catalog"; auto state = catalog::closeCatalog(opCtx); log() << "Reopening database catalog"; catalog::openCatalog(opCtx, state); return true; }
void DurableViewCatalog::onExternalChange(OperationContext* opCtx, const NamespaceString& name) { dassert(opCtx->lockState()->isDbLockedForMode(name.db(), MODE_IX)); auto databaseHolder = DatabaseHolder::get(opCtx); auto db = databaseHolder->getDb(opCtx, name.db()); if (db) { opCtx->recoveryUnit()->onCommit( [db](boost::optional<Timestamp>) { ViewCatalog::get(db)->invalidate(); }); } }
void MojDbSandwichDatabase::postUpdate(MojDbStorageTxn* txn, MojSize size) { if (txn) { // TODO: implement quotas // XXX: static_cast<MojDbSandwichTxn*>(txn)->didUpdate(size); } else { if (engine()->lazySync()) engine()->getUpdater()->sendEvent( getDb() ); } }
MojErr MojDbSandwichDatabase::close() { LOG_TRACE("Entering function %s", __FUNCTION__); MojErr err = MojErrNone; if (m_db.Valid()) { err = closeImpl(); if (engine()->lazySync()) engine()->getUpdater()->close( getDb() ); } return err; }
MinVisibleTimestampMap closeCatalog(OperationContext* opCtx) { invariant(opCtx->lockState()->isW()); MinVisibleTimestampMap minVisibleTimestampMap; std::vector<std::string> allDbs; opCtx->getServiceContext()->getStorageEngine()->listDatabases(&allDbs); auto databaseHolder = DatabaseHolder::get(opCtx); for (auto&& dbName : allDbs) { const auto db = databaseHolder->getDb(opCtx, dbName); for (auto collIt = db->begin(opCtx); collIt != db->end(opCtx); ++collIt) { auto coll = *collIt; if (!coll) { break; } OptionalCollectionUUID uuid = coll->uuid(); boost::optional<Timestamp> minVisible = coll->getMinimumVisibleSnapshot(); // If there's a minimum visible, invariant there's also a UUID. invariant(!minVisible || uuid); if (uuid && minVisible) { LOG(1) << "closeCatalog: preserving min visible timestamp. Collection: " << coll->ns() << " UUID: " << uuid << " TS: " << minVisible; minVisibleTimestampMap[*uuid] = *minVisible; } } } // Need to mark the UUIDCatalog as open if we our closeAll fails, dismissed if successful. auto reopenOnFailure = makeGuard([opCtx] { UUIDCatalog::get(opCtx).onOpenCatalog(opCtx); }); // Closing UUID Catalog: only lookupNSSByUUID will fall back to using pre-closing state to // allow authorization for currently unknown UUIDs. This is needed because authorization needs // to work before acquiring locks, and might otherwise spuriously regard a UUID as unknown // while reloading the catalog. UUIDCatalog::get(opCtx).onCloseCatalog(opCtx); LOG(1) << "closeCatalog: closing UUID catalog"; // Close all databases. log() << "closeCatalog: closing all databases"; databaseHolder->closeAll(opCtx); // Close the storage engine's catalog. log() << "closeCatalog: closing storage engine catalog"; opCtx->getServiceContext()->getStorageEngine()->closeCatalog(opCtx); reopenOnFailure.dismiss(); return minVisibleTimestampMap; }
MojErr MojDbSandwichDatabase::open(const MojChar* dbName, MojDbSandwichEngine* eng) { LOG_TRACE("Entering function %s", __FUNCTION__); MojAssert(dbName && eng); // save eng and name m_engine = eng; MojErr err = m_name.assign(dbName); MojErrCheck(err); if (engine()->lazySync()) engine()->getUpdater()->open( getDb() ); return MojErrNone; }
Cursor::const_iterator& Cursor::const_iterator::operator++() { // fetch next row log_debug("mysql_stmt_fetch"); int ret = ::mysql_stmt_fetch(getStmt()); if (ret == 1) throw Error("mysql_stmt_fetch", getDb()); else if (ret == MYSQL_NO_DATA) cursor = Cursor(); #ifdef MYSQL_DATA_TRUNCATED else if (ret == MYSQL_DATA_TRUNCATED) { log_error("mysql_stmt_fetch returned MYSQL_DATA_TRUNCATED"); throw std::runtime_error("mysql_stmt_fetch returned MYSQL_DATA_TRUNCATED"); } #endif }
ConnectionProperties::ConnectionProperties(Database *database, MainWin *mainwin) { QPushButton *pBOK; QPushButton *pBCancel; QWidget *layoutWidget; QVBoxLayout *verticalLayout; setWindowFlags(Qt::FramelessWindowHint); this->setAttribute(Qt::WA_DeleteOnClose); resize(256, 288); setModal(true); setParent(mainwin); setWindowFlags(Qt::Window); setWindowModality(Qt::WindowModal); pBOK = new QPushButton(this); pBOK->setObjectName(QString::fromUtf8("pBOK")); pBOK->setAutoDefault(false); pBOK->setGeometry(QRect(30, 250, 75, 23)); QFont font; font.setFamily(QString::fromUtf8("Verdana")); pBOK->setFont(font); pBCancel = new QPushButton(this); pBCancel->setObjectName(QString::fromUtf8("pBCancel")); pBCancel->setGeometry(QRect(140, 250, 75, 23)); pBCancel->setFont(font); pBCancel->setAutoDefault(false); setDb(new QLineEdit(this)); getDb()->setObjectName(QString::fromUtf8("lEDb")); getDb()->setGeometry(QRect(100, 90, 133, 20)); getDb()->setFont(font); getDb()->setAutoFillBackground(true); getDb()->setInputMethodHints(Qt::ImhNone); setSrv(new QLineEdit(this)); getSrv()->setObjectName(QString::fromUtf8("lESrv")); getSrv()->setGeometry(QRect(100, 47, 133, 20)); getSrv()->setFont(font); setPort(new QLineEdit(this)); getPort()->setObjectName(QString::fromUtf8("lEPort")); getPort()->setGeometry(QRect(100, 130, 133, 20)); getPort()->setFont(font); getPort()->setInputMethodHints(Qt::ImhFormattedNumbersOnly); getPort()->setInputMask("00000"); setUser(new QLineEdit(this)); getUser()->setObjectName(QString::fromUtf8("lEUser")); getUser()->setGeometry(QRect(100, 171, 133, 20)); getUser()->setFont(font); setPass(new QLineEdit(this)); getPass()->setObjectName(QString::fromUtf8("lEPass")); getPass()->setGeometry(QRect(100, 213, 133, 20)); getPass()->setEchoMode(QLineEdit::Password); getPass()->setFont(font); layoutWidget = new QWidget(this); layoutWidget->setObjectName(QString::fromUtf8("layoutWidget")); layoutWidget->setGeometry(QRect(20, 40, 71, 201)); verticalLayout = new QVBoxLayout(layoutWidget); verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); verticalLayout->setContentsMargins(0, 0, 0, 0); lSrv = new QLabel(layoutWidget); lSrv->setObjectName(QString::fromUtf8("lSrv")); lSrv->setFont(font); verticalLayout->addWidget(lSrv); lDb = new QLabel(layoutWidget); lDb->setObjectName(QString::fromUtf8("lDb")); lDb->setFont(font); verticalLayout->addWidget(lDb); lPort = new QLabel(layoutWidget); lPort->setObjectName(QString::fromUtf8("lPort")); lPort->setFont(font); verticalLayout->addWidget(lPort); lUser = new QLabel(layoutWidget); lUser->setObjectName(QString::fromUtf8("lUser")); lUser->setFont(font); verticalLayout->addWidget(lUser); lPass = new QLabel(layoutWidget); lPass->setObjectName(QString::fromUtf8("lPass")); lPass->setFont(font); verticalLayout->addWidget(lPass); lTitle = new QLabel(this); lTitle->setObjectName(QString::fromUtf8("lTitle")); lTitle->setGeometry(QRect(20, 10, 211, 21)); lTitle->setAlignment(Qt::AlignHCenter); QFont font1; font1.setFamily(QString::fromUtf8("Verdana")); font1.setPointSize(14); lTitle->setFont(font1); QWidget::setTabOrder(getSrv(), getDb()); QWidget::setTabOrder(getDb(), getPort()); QWidget::setTabOrder(getPort(), getUser()); QWidget::setTabOrder(getUser(), getPass()); QWidget::setTabOrder(getPass(), pBOK); QWidget::setTabOrder(pBOK, pBCancel); QObject::connect(pBCancel, SIGNAL(clicked()), this, SLOT(close())); QObject::connect(pBOK, SIGNAL(clicked()), this, SLOT(okslot())); QObject::connect(this, SIGNAL(oksignal(QString,qint32,QString,QString,QString)), mainwin, SLOT(newDatabase(QString,qint32,QString,QString,QString))); QObject::connect(getSrv(), SIGNAL(returnPressed()), getDb(), SLOT(setFocus())); QObject::connect(getDb(), SIGNAL(returnPressed()), getPort(), SLOT(setFocus())); QObject::connect(getPort(), SIGNAL(returnPressed()), getUser(), SLOT(setFocus())); QObject::connect(getUser(), SIGNAL(returnPressed()), getPass(), SLOT(setFocus())); QObject::connect(getPass(), SIGNAL(returnPressed()), pBOK, SLOT(setFocus())); setWindowTitle(QApplication::translate("Connection", "Connection", 0, QApplication::UnicodeUTF8)); pBOK->setText(QApplication::translate("Connection", "OK", 0, QApplication::UnicodeUTF8)); pBCancel->setText(QApplication::translate("Connection", "Cancel", 0, QApplication::UnicodeUTF8)); if(!database->getDatabaseStatus()) { getSrv()->setText(database->getHost()); getDb()->setText(database->getName()); getPort()->setText(database->getPort()); getUser()->setText(database->getUser()); getPass()->setText(database->getPassword()); } else { QSqlDatabase database_connection = QSqlDatabase::database(QString("base").append(QString::number(database->getId()))); getSrv()->setText(database_connection.hostName()); getDb()->setText(database->getName()); getPort()->setText(QString::number(database_connection.port())); getUser()->setText(database_connection.userName()); getPass()->setText(database_connection.password()); } lTitle->setText(QApplication::translate("Connection", "Connection", 0, QApplication::UnicodeUTF8)); lSrv->setText(QApplication::translate("Connection", "Server", 0, QApplication::UnicodeUTF8)); lDb->setText(QApplication::translate("Connection", "Database", 0, QApplication::UnicodeUTF8)); lPort->setText(QApplication::translate("Connection", "Port", 0, QApplication::UnicodeUTF8)); lUser->setText(QApplication::translate("Connection", "Username", 0, QApplication::UnicodeUTF8)); lPass->setText(QApplication::translate("Connection", "Password", 0, QApplication::UnicodeUTF8)); }
Status createCollectionForApplyOps(OperationContext* opCtx, const std::string& dbName, const BSONElement& ui, const BSONObj& cmdObj, const BSONObj& idIndex) { invariant(opCtx->lockState()->isDbLockedForMode(dbName, MODE_X)); const NamespaceString newCollName(CommandHelpers::parseNsCollectionRequired(dbName, cmdObj)); auto newCmd = cmdObj; auto databaseHolder = DatabaseHolder::get(opCtx); auto* const db = databaseHolder->getDb(opCtx, dbName); // If a UUID is given, see if we need to rename a collection out of the way, and whether the // collection already exists under a different name. If so, rename it into place. As this is // done during replay of the oplog, the operations do not need to be atomic, just idempotent. // We need to do the renaming part in a separate transaction, as we cannot transactionally // create a database on MMAPv1, which could result in createCollection failing if the database // does not yet exist. if (ui.ok()) { // Return an optional, indicating whether we need to early return (if the collection already // exists, or in case of an error). using Result = boost::optional<Status>; auto result = writeConflictRetry(opCtx, "createCollectionForApplyOps", newCollName.ns(), [&] { WriteUnitOfWork wunit(opCtx); // Options need the field to be named "uuid", so parse/recreate. auto uuid = uassertStatusOK(UUID::parse(ui)); uassert(ErrorCodes::InvalidUUID, "Invalid UUID in applyOps create command: " + uuid.toString(), uuid.isRFC4122v4()); auto& catalog = UUIDCatalog::get(opCtx); const auto currentName = catalog.lookupNSSByUUID(uuid); auto serviceContext = opCtx->getServiceContext(); auto opObserver = serviceContext->getOpObserver(); if (currentName == newCollName) return Result(Status::OK()); if (currentName.isDropPendingNamespace()) { log() << "CMD: create " << newCollName << " - existing collection with conflicting UUID " << uuid << " is in a drop-pending state: " << currentName; return Result(Status(ErrorCodes::NamespaceExists, str::stream() << "existing collection " << currentName.toString() << " with conflicting UUID " << uuid.toString() << " is in a drop-pending state.")); } // In the case of oplog replay, a future command may have created or renamed a // collection with that same name. In that case, renaming this future collection to // a random temporary name is correct: once all entries are replayed no temporary // names will remain. On MMAPv1 the rename can result in index names that are too // long. However this should only happen for initial sync and "resync collection" // for rollback, so we can let the error propagate resulting in an abort and restart // of the initial sync or result in rollback to fassert, requiring a resync of that // node. const bool stayTemp = true; if (auto futureColl = db ? db->getCollection(opCtx, newCollName) : nullptr) { auto tmpNameResult = db->makeUniqueCollectionNamespace(opCtx, "tmp%%%%%.create"); if (!tmpNameResult.isOK()) { return Result(tmpNameResult.getStatus().withContext( str::stream() << "Cannot generate temporary " "collection namespace for applyOps " "create command: collection: " << newCollName)); } const auto& tmpName = tmpNameResult.getValue(); // It is ok to log this because this doesn't happen very frequently. log() << "CMD: create " << newCollName << " - renaming existing collection with conflicting UUID " << uuid << " to temporary collection " << tmpName; Status status = db->renameCollection(opCtx, newCollName, tmpName, stayTemp); if (!status.isOK()) return Result(status); opObserver->onRenameCollection(opCtx, newCollName, tmpName, futureColl->uuid(), /*dropTargetUUID*/ {}, /*numRecords*/ 0U, stayTemp); } // If the collection with the requested UUID already exists, but with a different // name, just rename it to 'newCollName'. if (catalog.lookupCollectionByUUID(uuid)) { uassert(40655, str::stream() << "Invalid name " << newCollName << " for UUID " << uuid, currentName.db() == newCollName.db()); Status status = db->renameCollection(opCtx, currentName, newCollName, stayTemp); if (!status.isOK()) return Result(status); opObserver->onRenameCollection(opCtx, currentName, newCollName, uuid, /*dropTargetUUID*/ {}, /*numRecords*/ 0U, stayTemp); wunit.commit(); return Result(Status::OK()); } // A new collection with the specific UUID must be created, so add the UUID to the // creation options. Regular user collection creation commands cannot do this. auto uuidObj = uuid.toBSON(); newCmd = cmdObj.addField(uuidObj.firstElement()); wunit.commit(); return Result(boost::none); }); if (result) { return *result; } } return createCollection( opCtx, newCollName, newCmd, idIndex, CollectionOptions::parseForStorage); }
/** * Return whether there are non-local databases. If there was an error becauses the wrong mongod * version was used for these datafiles, a DBException with status ErrorCodes::MustDowngrade is * thrown. */ bool repairDatabasesAndCheckVersion(OperationContext* opCtx) { auto const storageEngine = opCtx->getServiceContext()->getStorageEngine(); Lock::GlobalWrite lk(opCtx); std::vector<std::string> dbNames = storageEngine->listDatabases(); // Rebuilding indexes must be done before a database can be opened, except when using repair, // which rebuilds all indexes when it is done. if (!storageGlobalParams.readOnly && !storageGlobalParams.repair) { // Determine whether this is a replica set node running in standalone mode. If we're in // repair mode, we cannot set the flag yet as it needs to open a database and look through a // collection. Rebuild the necessary indexes after setting the flag. setReplSetMemberInStandaloneMode(opCtx); rebuildIndexes(opCtx, storageEngine); } bool ensuredCollectionProperties = false; // Repair all databases first, so that we do not try to open them if they are in bad shape auto databaseHolder = DatabaseHolder::get(opCtx); if (storageGlobalParams.repair) { invariant(!storageGlobalParams.readOnly); if (MONGO_FAIL_POINT(exitBeforeDataRepair)) { log() << "Exiting because 'exitBeforeDataRepair' fail point was set."; quickExit(EXIT_ABRUPT); } // Ensure that the local database is repaired first, if it exists, so that we can open it // before any other database to be able to determine if this is a replica set node running // in standalone mode before rebuilding any indexes. auto dbNamesIt = std::find(dbNames.begin(), dbNames.end(), NamespaceString::kLocalDb); if (dbNamesIt != dbNames.end()) { std::swap(dbNames.front(), *dbNamesIt); invariant(dbNames.front() == NamespaceString::kLocalDb); } stdx::function<void(const std::string& dbName)> onRecordStoreRepair = [opCtx](const std::string& dbName) { if (dbName == NamespaceString::kLocalDb) { setReplSetMemberInStandaloneMode(opCtx); } }; for (const auto& dbName : dbNames) { LOG(1) << " Repairing database: " << dbName; fassertNoTrace(18506, repairDatabase(opCtx, storageEngine, dbName, onRecordStoreRepair)); } // All collections must have UUIDs before restoring the FCV document to a version that // requires UUIDs. uassertStatusOK(ensureCollectionProperties(opCtx, dbNames)); ensuredCollectionProperties = true; // Attempt to restore the featureCompatibilityVersion document if it is missing. NamespaceString fcvNSS(NamespaceString::kServerConfigurationNamespace); auto db = databaseHolder->getDb(opCtx, fcvNSS.db()); Collection* versionColl; BSONObj featureCompatibilityVersion; if (!db || !(versionColl = db->getCollection(opCtx, fcvNSS)) || !Helpers::findOne(opCtx, versionColl, BSON("_id" << FeatureCompatibilityVersionParser::kParameterName), featureCompatibilityVersion)) { uassertStatusOK(restoreMissingFeatureCompatibilityVersionDocument(opCtx, dbNames)); } } if (!ensuredCollectionProperties) { uassertStatusOK(ensureCollectionProperties(opCtx, dbNames)); } if (!storageGlobalParams.readOnly) { // We open the "local" database before calling hasReplSetConfigDoc() to ensure the in-memory // catalog entries for the 'kSystemReplSetNamespace' collection have been populated if the // collection exists. If the "local" database didn't exist at this point yet, then it will // be created. If the mongod is running in a read-only mode, then it is fine to not open the // "local" database and populate the catalog entries because we won't attempt to drop the // temporary collections anyway. Lock::DBLock dbLock(opCtx, NamespaceString::kSystemReplSetNamespace.db(), MODE_X); databaseHolder->openDb(opCtx, NamespaceString::kSystemReplSetNamespace.db()); } if (storageGlobalParams.repair) { if (MONGO_FAIL_POINT(exitBeforeRepairInvalidatesConfig)) { log() << "Exiting because 'exitBeforeRepairInvalidatesConfig' fail point was set."; quickExit(EXIT_ABRUPT); } // This must be done after opening the "local" database as it modifies the replica set // config. auto repairObserver = StorageRepairObserver::get(opCtx->getServiceContext()); repairObserver->onRepairDone(opCtx); if (repairObserver->isDataModified()) { warning() << "Modifications made by repair:"; const auto& mods = repairObserver->getModifications(); for (const auto& mod : mods) { warning() << " " << mod; } if (hasReplSetConfigDoc(opCtx)) { warning() << "WARNING: Repair may have modified replicated data. This node will no " "longer be able to join a replica set without a full re-sync"; } } } const repl::ReplSettings& replSettings = repl::ReplicationCoordinator::get(opCtx)->getSettings(); // On replica set members we only clear temp collections on DBs other than "local" during // promotion to primary. On pure slaves, they are only cleared when the oplog tells them // to. The local DB is special because it is not replicated. See SERVER-10927 for more // details. const bool shouldClearNonLocalTmpCollections = !(hasReplSetConfigDoc(opCtx) || replSettings.usingReplSets()); // To check whether a featureCompatibilityVersion document exists. bool fcvDocumentExists = false; // To check whether we have databases other than local. bool nonLocalDatabases = false; // Refresh list of database names to include newly-created admin, if it exists. dbNames = storageEngine->listDatabases(); for (const auto& dbName : dbNames) { if (dbName != "local") { nonLocalDatabases = true; } LOG(1) << " Recovering database: " << dbName; auto db = databaseHolder->openDb(opCtx, dbName); invariant(db); // First thing after opening the database is to check for file compatibility, // otherwise we might crash if this is a deprecated format. auto status = storageEngine->currentFilesCompatible(opCtx); if (!status.isOK()) { if (status.code() == ErrorCodes::CanRepairToDowngrade) { // Convert CanRepairToDowngrade statuses to MustUpgrade statuses to avoid logging a // potentially confusing and inaccurate message. // // TODO SERVER-24097: Log a message informing the user that they can start the // current version of mongod with --repair and then proceed with normal startup. status = {ErrorCodes::MustUpgrade, status.reason()}; } severe() << "Unable to start mongod due to an incompatibility with the data files and" " this version of mongod: " << redact(status); severe() << "Please consult our documentation when trying to downgrade to a previous" " major release"; quickExit(EXIT_NEED_UPGRADE); MONGO_UNREACHABLE; } // If the server configuration collection already contains a valid // featureCompatibilityVersion document, cache it in-memory as a server parameter. if (dbName == "admin") { if (Collection* versionColl = db->getCollection(opCtx, NamespaceString::kServerConfigurationNamespace)) { BSONObj featureCompatibilityVersion; if (Helpers::findOne( opCtx, versionColl, BSON("_id" << FeatureCompatibilityVersionParser::kParameterName), featureCompatibilityVersion)) { auto swVersion = FeatureCompatibilityVersionParser::parse(featureCompatibilityVersion); // Note this error path captures all cases of an FCV document existing, // but with any value other than "4.0" or "4.2". This includes unexpected // cases with no path forward such as the FCV value not being a string. uassert(ErrorCodes::MustDowngrade, str::stream() << "UPGRADE PROBLEM: Found an invalid " "featureCompatibilityVersion document (ERROR: " << swVersion.getStatus() << "). If the current featureCompatibilityVersion is below " "4.0, see the documentation on upgrading at " << feature_compatibility_version_documentation::kUpgradeLink << ".", swVersion.isOK()); fcvDocumentExists = true; auto version = swVersion.getValue(); serverGlobalParams.featureCompatibility.setVersion(version); FeatureCompatibilityVersion::updateMinWireVersion(); // On startup, if the version is in an upgrading or downrading state, print a // warning. if (version == ServerGlobalParams::FeatureCompatibility::Version::kUpgradingTo42) { log() << "** WARNING: A featureCompatibilityVersion upgrade did not " << "complete. " << startupWarningsLog; log() << "** The current featureCompatibilityVersion is " << FeatureCompatibilityVersionParser::toString(version) << "." << startupWarningsLog; log() << "** To fix this, use the setFeatureCompatibilityVersion " << "command to resume upgrade to 4.2." << startupWarningsLog; } else if (version == ServerGlobalParams::FeatureCompatibility::Version:: kDowngradingTo40) { log() << "** WARNING: A featureCompatibilityVersion downgrade did not " << "complete. " << startupWarningsLog; log() << "** The current featureCompatibilityVersion is " << FeatureCompatibilityVersionParser::toString(version) << "." << startupWarningsLog; log() << "** To fix this, use the setFeatureCompatibilityVersion " << "command to resume downgrade to 4.0." << startupWarningsLog; } } } } if (replSettings.usingReplSets()) { // We only care about _id indexes and drop-pending collections if we are in a replset. db->checkForIdIndexesAndDropPendingCollections(opCtx); // Ensure oplog is capped (mongodb does not guarantee order of inserts on noncapped // collections) if (db->name() == "local") { checkForCappedOplog(opCtx, db); } } if (!storageGlobalParams.readOnly && (shouldClearNonLocalTmpCollections || dbName == "local")) { db->clearTmpCollections(opCtx); } } // Fail to start up if there is no featureCompatibilityVersion document and there are non-local // databases present. if (!fcvDocumentExists && nonLocalDatabases) { severe() << "Unable to start up mongod due to missing featureCompatibilityVersion document."; severe() << "Please run with --repair to restore the document."; fassertFailedNoTrace(40652); } LOG(1) << "done repairDatabases"; return nonLocalDatabases; }