diff options
Diffstat (limited to 'src/mongo/db/catalog/coll_mod.cpp')
-rw-r--r-- | src/mongo/db/catalog/coll_mod.cpp | 250 |
1 files changed, 121 insertions, 129 deletions
diff --git a/src/mongo/db/catalog/coll_mod.cpp b/src/mongo/db/catalog/coll_mod.cpp index 768ee713b0a..00a3a643a5b 100644 --- a/src/mongo/db/catalog/coll_mod.cpp +++ b/src/mongo/db/catalog/coll_mod.cpp @@ -40,148 +40,140 @@ #include "mongo/db/service_context.h" namespace mongo { - Status collMod(OperationContext* txn, - const NamespaceString& ns, - const BSONObj& cmdObj, - BSONObjBuilder* result) { - StringData dbName = ns.db(); - ScopedTransaction transaction(txn, MODE_IX); - AutoGetDb autoDb(txn, dbName, MODE_X); - Database* const db = autoDb.getDb(); - Collection* coll = db ? db->getCollection(ns) : NULL; - - // If db/collection does not exist, short circuit and return. - if (!db || !coll) { - return Status(ErrorCodes::NamespaceNotFound, "ns does not exist"); - } +Status collMod(OperationContext* txn, + const NamespaceString& ns, + const BSONObj& cmdObj, + BSONObjBuilder* result) { + StringData dbName = ns.db(); + ScopedTransaction transaction(txn, MODE_IX); + AutoGetDb autoDb(txn, dbName, MODE_X); + Database* const db = autoDb.getDb(); + Collection* coll = db ? db->getCollection(ns) : NULL; + + // If db/collection does not exist, short circuit and return. + if (!db || !coll) { + return Status(ErrorCodes::NamespaceNotFound, "ns does not exist"); + } - OldClientContext ctx(txn, ns); + OldClientContext ctx(txn, ns); - bool userInitiatedWritesAndNotPrimary = txn->writesAreReplicated() && - !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns); + bool userInitiatedWritesAndNotPrimary = txn->writesAreReplicated() && + !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns); - if (userInitiatedWritesAndNotPrimary) { - return Status(ErrorCodes::NotMaster, - str::stream() << "Not primary while setting collection options on " - << ns.toString()); - } + if (userInitiatedWritesAndNotPrimary) { + return Status(ErrorCodes::NotMaster, + str::stream() << "Not primary while setting collection options on " + << ns.toString()); + } + + WriteUnitOfWork wunit(txn); - WriteUnitOfWork wunit(txn); + Status errorStatus = Status::OK(); - Status errorStatus = Status::OK(); + BSONForEach(e, cmdObj) { + if (str::equals("collMod", e.fieldName())) { + // no-op + } else if (str::startsWith(e.fieldName(), "$")) { + // no-op ignore top-level fields prefixed with $. They are for the command processor + } else if (LiteParsedQuery::cmdOptionMaxTimeMS == e.fieldNameStringData()) { + // no-op + } else if (str::equals("index", e.fieldName())) { + BSONObj indexObj = e.Obj(); + BSONObj keyPattern = indexObj.getObjectField("keyPattern"); - BSONForEach(e, cmdObj) { - if (str::equals("collMod", e.fieldName())) { - // no-op + if (keyPattern.isEmpty()) { + errorStatus = Status(ErrorCodes::InvalidOptions, "no keyPattern specified"); + continue; } - else if (str::startsWith(e.fieldName(), "$")) { - // no-op ignore top-level fields prefixed with $. They are for the command processor + + BSONElement newExpireSecs = indexObj["expireAfterSeconds"]; + if (newExpireSecs.eoo()) { + errorStatus = Status(ErrorCodes::InvalidOptions, "no expireAfterSeconds field"); + continue; } - else if (LiteParsedQuery::cmdOptionMaxTimeMS == e.fieldNameStringData()) { - // no-op + if (!newExpireSecs.isNumber()) { + errorStatus = + Status(ErrorCodes::InvalidOptions, "expireAfterSeconds field must be a number"); + continue; } - else if (str::equals("index", e.fieldName())) { - BSONObj indexObj = e.Obj(); - BSONObj keyPattern = indexObj.getObjectField("keyPattern"); - - if (keyPattern.isEmpty()){ - errorStatus = Status(ErrorCodes::InvalidOptions, "no keyPattern specified"); - continue; - } - - BSONElement newExpireSecs = indexObj["expireAfterSeconds"]; - if (newExpireSecs.eoo()) { - errorStatus = Status(ErrorCodes::InvalidOptions, "no expireAfterSeconds field"); - continue; - } - if (! newExpireSecs.isNumber()) { - errorStatus = Status(ErrorCodes::InvalidOptions, - "expireAfterSeconds field must be a number"); - continue; - } - - const IndexDescriptor* idx = coll->getIndexCatalog() - ->findIndexByKeyPattern(txn, keyPattern); - if (idx == NULL) { - errorStatus = Status(ErrorCodes::InvalidOptions, - str::stream() << "cannot find index " << keyPattern - << " for ns " << ns.toString()); - continue; - } - BSONElement oldExpireSecs = idx->infoObj().getField("expireAfterSeconds"); - if (oldExpireSecs.eoo()){ - errorStatus = Status(ErrorCodes::InvalidOptions, - "no expireAfterSeconds field to update"); - continue; - } - if (! oldExpireSecs.isNumber()) { - errorStatus = Status(ErrorCodes::InvalidOptions, - "existing expireAfterSeconds field is not a number"); - continue; - } - - if (oldExpireSecs != newExpireSecs) { - result->appendAs(oldExpireSecs, "expireAfterSeconds_old"); - // Change the value of "expireAfterSeconds" on disk. - coll->getCatalogEntry()->updateTTLSetting(txn, - idx->indexName(), - newExpireSecs.numberLong()); - // Notify the index catalog that the definition of this index changed. - idx = coll->getIndexCatalog()->refreshEntry(txn, idx); - result->appendAs(newExpireSecs , "expireAfterSeconds_new"); - } + + const IndexDescriptor* idx = + coll->getIndexCatalog()->findIndexByKeyPattern(txn, keyPattern); + if (idx == NULL) { + errorStatus = Status(ErrorCodes::InvalidOptions, + str::stream() << "cannot find index " << keyPattern + << " for ns " << ns.toString()); + continue; } - else if (str::equals("validator", e.fieldName())) { - auto status = coll->setValidator(txn, e.Obj()); - if (!status.isOK()) - errorStatus = std::move(status); + BSONElement oldExpireSecs = idx->infoObj().getField("expireAfterSeconds"); + if (oldExpireSecs.eoo()) { + errorStatus = + Status(ErrorCodes::InvalidOptions, "no expireAfterSeconds field to update"); + continue; } - else { - // As of SERVER-17312 we only support these two options. When SERVER-17320 is - // resolved this will need to be enhanced to handle other options. - typedef CollectionOptions CO; - const StringData name = e.fieldNameStringData(); - const int flag = (name == "usePowerOf2Sizes") ? CO::Flag_UsePowerOf2Sizes : - (name == "noPadding") ? CO::Flag_NoPadding : - 0; - if (!flag) { - errorStatus = Status(ErrorCodes::InvalidOptions, - str::stream() << "unknown option to collMod: " << name); - continue; - } - - CollectionCatalogEntry* cce = coll->getCatalogEntry(); - - const int oldFlags = cce->getCollectionOptions(txn).flags; - const bool oldSetting = oldFlags & flag; - const bool newSetting = e.trueValue(); - - result->appendBool(name.toString() + "_old", oldSetting); - result->appendBool(name.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(txn, newFlags); - - const CollectionOptions newOptions = cce->getCollectionOptions(txn); - invariant(newOptions.flags == newFlags); - invariant(newOptions.flagsSet); + if (!oldExpireSecs.isNumber()) { + errorStatus = Status(ErrorCodes::InvalidOptions, + "existing expireAfterSeconds field is not a number"); + continue; } - } - if (!errorStatus.isOK()) { - return errorStatus; - } + if (oldExpireSecs != newExpireSecs) { + result->appendAs(oldExpireSecs, "expireAfterSeconds_old"); + // Change the value of "expireAfterSeconds" on disk. + coll->getCatalogEntry()->updateTTLSetting( + txn, idx->indexName(), newExpireSecs.numberLong()); + // Notify the index catalog that the definition of this index changed. + idx = coll->getIndexCatalog()->refreshEntry(txn, idx); + result->appendAs(newExpireSecs, "expireAfterSeconds_new"); + } + } else if (str::equals("validator", e.fieldName())) { + auto status = coll->setValidator(txn, e.Obj()); + if (!status.isOK()) + errorStatus = std::move(status); + } else { + // As of SERVER-17312 we only support these two options. When SERVER-17320 is + // resolved this will need to be enhanced to handle other options. + typedef CollectionOptions CO; + const StringData name = e.fieldNameStringData(); + const int flag = (name == "usePowerOf2Sizes") + ? CO::Flag_UsePowerOf2Sizes + : (name == "noPadding") ? CO::Flag_NoPadding : 0; + if (!flag) { + errorStatus = Status(ErrorCodes::InvalidOptions, + str::stream() << "unknown option to collMod: " << name); + continue; + } + + CollectionCatalogEntry* cce = coll->getCatalogEntry(); + + const int oldFlags = cce->getCollectionOptions(txn).flags; + const bool oldSetting = oldFlags & flag; + const bool newSetting = e.trueValue(); + + result->appendBool(name.toString() + "_old", oldSetting); + result->appendBool(name.toString() + "_new", newSetting); + + const int newFlags = newSetting ? (oldFlags | flag) // set flag + : (oldFlags & ~flag); // clear flag - getGlobalServiceContext()->getOpObserver()->onCollMod(txn, - (dbName.toString() + ".$cmd").c_str(), - cmdObj); + // 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(txn, newFlags); - wunit.commit(); - return Status::OK(); + const CollectionOptions newOptions = cce->getCollectionOptions(txn); + invariant(newOptions.flags == newFlags); + invariant(newOptions.flagsSet); + } + } + + if (!errorStatus.isOK()) { + return errorStatus; } -} // namespace mongo + + getGlobalServiceContext()->getOpObserver()->onCollMod( + txn, (dbName.toString() + ".$cmd").c_str(), cmdObj); + + wunit.commit(); + return Status::OK(); +} +} // namespace mongo |