void Database::clearTmpCollections(OperationContext* txn) { invariant(txn->lockState()->isDbLockedForMode(name(), MODE_X)); list<string> collections; _dbEntry->getCollectionNamespaces(&collections); for (list<string>::iterator i = collections.begin(); i != collections.end(); ++i) { string ns = *i; invariant(NamespaceString::normal(ns)); CollectionCatalogEntry* coll = _dbEntry->getCollectionCatalogEntry(ns); CollectionOptions options = coll->getCollectionOptions(txn); if (!options.temp) continue; try { WriteUnitOfWork wunit(txn); Status status = dropCollection(txn, ns); if (!status.isOK()) { warning() << "could not drop temp collection '" << ns << "': " << redact(status); continue; } wunit.commit(); } catch (const WriteConflictException& exp) { warning() << "could not drop temp collection '" << ns << "' due to " "WriteConflictException"; txn->recoveryUnit()->abandonSnapshot(); } } }
void Database::clearTmpCollections(OperationContext* txn) { txn->lockState()->assertWriteLocked( _name ); list<string> collections; _dbEntry->getCollectionNamespaces( &collections ); for ( list<string>::iterator i = collections.begin(); i != collections.end(); ++i ) { string ns = *i; invariant( NamespaceString::normal( ns ) ); CollectionCatalogEntry* coll = _dbEntry->getCollectionCatalogEntry( txn, ns ); CollectionOptions options = coll->getCollectionOptions( txn ); if ( !options.temp ) continue; WriteUnitOfWork wunit(txn); Status status = dropCollection( txn, ns ); if ( !status.isOK() ) { warning() << "could not drop temp collection '" << ns << "': " << status; continue; } string cmdNs = _name + ".$cmd"; repl::logOp( txn, "c", cmdNs.c_str(), BSON( "drop" << nsToCollectionSubstring( ns ) ) ); wunit.commit(); } }
/** * Set a collection option flag for 'UsePowerOf2Sizes' or 'NoPadding'. Appends both the new and * old flag setting to the given 'result' builder. */ void setCollectionOptionFlag(OperationContext* opCtx, Collection* coll, BSONElement& collOptionElement, BSONObjBuilder* result) { const StringData flagName = collOptionElement.fieldNameStringData(); int flag; if (flagName == "usePowerOf2Sizes") { flag = CollectionOptions::Flag_UsePowerOf2Sizes; } else if (flagName == "noPadding") { flag = CollectionOptions::Flag_NoPadding; } else { flag = 0; } CollectionCatalogEntry* cce = coll->getCatalogEntry(); const int oldFlags = cce->getCollectionOptions(opCtx).flags; const bool oldSetting = oldFlags & flag; const bool newSetting = collOptionElement.trueValue(); result->appendBool(flagName.toString() + "_old", oldSetting); result->appendBool(flagName.toString() + "_new", newSetting); const int newFlags = newSetting ? (oldFlags | flag) // set flag : (oldFlags & ~flag); // clear flag // NOTE we do this unconditionally to ensure that we note that the user has // explicitly set flags, even if they are just setting the default. cce->updateFlags(opCtx, newFlags); const CollectionOptions newOptions = cce->getCollectionOptions(opCtx); invariant(newOptions.flags == newFlags); invariant(newOptions.flagsSet); }
void Database::clearTmpCollections(OperationContext* txn) { invariant(txn->lockState()->isDbLockedForMode(name(), MODE_X)); list<string> collections; _dbEntry->getCollectionNamespaces( &collections ); for ( list<string>::iterator i = collections.begin(); i != collections.end(); ++i ) { string ns = *i; invariant( NamespaceString::normal( ns ) ); CollectionCatalogEntry* coll = _dbEntry->getCollectionCatalogEntry( ns ); CollectionOptions options = coll->getCollectionOptions( txn ); if ( !options.temp ) continue; try { WriteUnitOfWork wunit(txn); Status status = dropCollection( txn, ns ); if ( !status.isOK() ) { warning() << "could not drop temp collection '" << ns << "': " << status; continue; } string cmdNs = _name + ".$cmd"; repl::logOp( txn, "c", cmdNs.c_str(), BSON( "drop" << nsToCollectionSubstring( ns ) ) ); wunit.commit(); } catch (const WriteConflictException& exp) { warning() << "could not drop temp collection '" << ns << "' due to " "WriteConflictException"; txn->recoveryUnit()->commitAndRestart(); } } }
bool run(OperationContext* opCtx, const string& dbname, const BSONObj& cmdObj, BSONObjBuilder& result) { if (MONGO_FAIL_POINT(validateCmdCollectionNotValid)) { result.appendBool("valid", false); return true; } const NamespaceString nss(CommandHelpers::parseNsCollectionRequired(dbname, cmdObj)); const bool full = cmdObj["full"].trueValue(); const bool scanData = cmdObj["scandata"].trueValue(); ValidateCmdLevel level = kValidateIndex; if (full) { level = kValidateFull; } else if (scanData) { level = kValidateRecordStore; } if (!nss.isNormal() && full) { CommandHelpers::appendCommandStatus( result, {ErrorCodes::CommandFailed, "Can only run full validate on a regular collection"}); return false; } if (!serverGlobalParams.quiet.load()) { LOG(0) << "CMD: validate " << nss.ns(); } AutoGetDb ctx(opCtx, nss.db(), MODE_IX); auto collLk = stdx::make_unique<Lock::CollectionLock>(opCtx->lockState(), nss.ns(), MODE_X); Collection* collection = ctx.getDb() ? ctx.getDb()->getCollection(opCtx, nss) : NULL; if (!collection) { if (ctx.getDb() && ctx.getDb()->getViewCatalog()->lookup(opCtx, nss.ns())) { return CommandHelpers::appendCommandStatus( result, {ErrorCodes::CommandNotSupportedOnView, "Cannot validate a view"}); } CommandHelpers::appendCommandStatus(result, {ErrorCodes::NamespaceNotFound, "ns not found"}); return false; } // Omit background validation logic until it is fully implemented and vetted. const bool background = false; /* bool isInRecordIdOrder = collection->getRecordStore()->isInRecordIdOrder(); if (isInRecordIdOrder && !full) { background = true; } if (cmdObj.hasElement("background")) { background = cmdObj["background"].trueValue(); } if (!isInRecordIdOrder && background) { appendCommandStatus(result, {ErrorCodes::CommandFailed, "This storage engine does not support the background option, use " "background:false"}); return false; } if (full && background) { appendCommandStatus(result, {ErrorCodes::CommandFailed, "A full validate cannot run in the background, use full:false"}); return false; } */ result.append("ns", nss.ns()); // Only one validation per collection can be in progress, the rest wait in order. { stdx::unique_lock<stdx::mutex> lock(_validationMutex); try { while (_validationsInProgress.find(nss.ns()) != _validationsInProgress.end()) { opCtx->waitForConditionOrInterrupt(_validationNotifier, lock); } } catch (AssertionException& e) { CommandHelpers::appendCommandStatus( result, {ErrorCodes::CommandFailed, str::stream() << "Exception during validation: " << e.toString()}); return false; } _validationsInProgress.insert(nss.ns()); } ON_BLOCK_EXIT([&] { stdx::lock_guard<stdx::mutex> lock(_validationMutex); _validationsInProgress.erase(nss.ns()); _validationNotifier.notify_all(); }); ValidateResults results; Status status = collection->validate(opCtx, level, background, std::move(collLk), &results, &result); if (!status.isOK()) { return CommandHelpers::appendCommandStatus(result, status); } CollectionCatalogEntry* catalogEntry = collection->getCatalogEntry(); CollectionOptions opts = catalogEntry->getCollectionOptions(opCtx); // Skip checking UUID on system.indexes and system.namespaces until SERVER-30095 and // SERVER-29926 are resolved. bool skipUUIDCheck = nss.coll() == "system.indexes" || nss.coll() == "system.namespaces"; if (!skipUUIDCheck) { // All collections must have a UUID. if (!opts.uuid) { results.errors.push_back(str::stream() << "UUID missing on collection " << nss.ns() << " but SchemaVersion=3.6"); results.valid = false; } } if (!full) { results.warnings.push_back( "Some checks omitted for speed. use {full:true} option to do more thorough scan."); } result.appendBool("valid", results.valid); result.append("warnings", results.warnings); result.append("errors", results.errors); if (!results.valid) { result.append("advice", "A corrupt namespace has been detected. See " "http://dochub.mongodb.org/core/data-recovery for recovery steps."); } return true; }
bool run(OperationContext* opCtx, const string& dbname, const BSONObj& cmdObj, BSONObjBuilder& result) { if (MONGO_FAIL_POINT(validateCmdCollectionNotValid)) { result.appendBool("valid", false); return true; } const NamespaceString nss(CommandHelpers::parseNsCollectionRequired(dbname, cmdObj)); const bool full = cmdObj["full"].trueValue(); const bool scanData = cmdObj["scandata"].trueValue(); ValidateCmdLevel level = kValidateIndex; if (full) { level = kValidateFull; } else if (scanData) { level = kValidateRecordStore; } if (!nss.isNormal() && full) { uasserted(ErrorCodes::CommandFailed, "Can only run full validate on a regular collection"); } if (!serverGlobalParams.quiet.load()) { LOG(0) << "CMD: validate " << nss.ns(); } AutoGetDb ctx(opCtx, nss.db(), MODE_IX); Lock::CollectionLock collLk(opCtx, nss, MODE_X); Collection* collection = ctx.getDb() ? ctx.getDb()->getCollection(opCtx, nss) : NULL; if (!collection) { if (ctx.getDb() && ViewCatalog::get(ctx.getDb())->lookup(opCtx, nss.ns())) { uasserted(ErrorCodes::CommandNotSupportedOnView, "Cannot validate a view"); } uasserted(ErrorCodes::NamespaceNotFound, "ns not found"); } result.append("ns", nss.ns()); // Only one validation per collection can be in progress, the rest wait in order. { stdx::unique_lock<stdx::mutex> lock(_validationMutex); try { while (_validationsInProgress.find(nss.ns()) != _validationsInProgress.end()) { opCtx->waitForConditionOrInterrupt(_validationNotifier, lock); } } catch (AssertionException& e) { CommandHelpers::appendCommandStatusNoThrow( result, {ErrorCodes::CommandFailed, str::stream() << "Exception during validation: " << e.toString()}); return false; } _validationsInProgress.insert(nss.ns()); } ON_BLOCK_EXIT([&] { stdx::lock_guard<stdx::mutex> lock(_validationMutex); _validationsInProgress.erase(nss.ns()); _validationNotifier.notify_all(); }); // TODO SERVER-30357: Add support for background validation. const bool background = false; ValidateResults results; Status status = collection->validate(opCtx, level, background, &results, &result); if (!status.isOK()) { return CommandHelpers::appendCommandStatusNoThrow(result, status); } CollectionCatalogEntry* catalogEntry = collection->getCatalogEntry(); CollectionOptions opts = catalogEntry->getCollectionOptions(opCtx); // All collections must have a UUID. if (!opts.uuid) { results.errors.push_back(str::stream() << "UUID missing on collection " << nss.ns() << " but SchemaVersion=3.6"); results.valid = false; } if (!full) { results.warnings.push_back( "Some checks omitted for speed. use {full:true} option to do more thorough scan."); } result.appendBool("valid", results.valid); result.append("warnings", results.warnings); result.append("errors", results.errors); result.append("extraIndexEntries", results.extraIndexEntries); result.append("missingIndexEntries", results.missingIndexEntries); if (!results.valid) { result.append("advice", "A corrupt namespace has been detected. See " "http://dochub.mongodb.org/core/data-recovery for recovery steps."); } return true; }