summaryrefslogtreecommitdiff
path: root/src/mongo/db/commands/create_indexes.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/commands/create_indexes.cpp')
-rw-r--r--src/mongo/db/commands/create_indexes.cpp414
1 files changed, 212 insertions, 202 deletions
diff --git a/src/mongo/db/commands/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp
index 83dc5e72177..c18c33b7ce4 100644
--- a/src/mongo/db/commands/create_indexes.cpp
+++ b/src/mongo/db/commands/create_indexes.cpp
@@ -52,251 +52,261 @@
namespace mongo {
- using std::string;
-
- /**
- * { createIndexes : "bar", indexes : [ { ns : "test.bar", key : { x : 1 }, name: "x_1" } ] }
- */
- class CmdCreateIndex : public Command {
- public:
- CmdCreateIndex() : Command( "createIndexes" ){}
-
- virtual bool isWriteCommandForConfigServer() const { return false; }
- virtual bool slaveOk() const { return false; } // TODO: this could be made true...
-
- virtual Status checkAuthForCommand(ClientBasic* client,
- const std::string& dbname,
- const BSONObj& cmdObj) {
- ActionSet actions;
- actions.addAction(ActionType::createIndex);
- Privilege p(parseResourcePattern(dbname, cmdObj), actions);
- if (AuthorizationSession::get(client)->isAuthorizedForPrivilege(p))
- return Status::OK();
- return Status(ErrorCodes::Unauthorized, "Unauthorized");
- }
-
+using std::string;
- BSONObj _addNsToSpec( const NamespaceString& ns, const BSONObj& obj ) {
- BSONObjBuilder b;
- b.append( "ns", ns );
- b.appendElements( obj );
- return b.obj();
+/**
+ * { createIndexes : "bar", indexes : [ { ns : "test.bar", key : { x : 1 }, name: "x_1" } ] }
+ */
+class CmdCreateIndex : public Command {
+public:
+ CmdCreateIndex() : Command("createIndexes") {}
+
+ virtual bool isWriteCommandForConfigServer() const {
+ return false;
+ }
+ virtual bool slaveOk() const {
+ return false;
+ } // TODO: this could be made true...
+
+ virtual Status checkAuthForCommand(ClientBasic* client,
+ const std::string& dbname,
+ const BSONObj& cmdObj) {
+ ActionSet actions;
+ actions.addAction(ActionType::createIndex);
+ Privilege p(parseResourcePattern(dbname, cmdObj), actions);
+ if (AuthorizationSession::get(client)->isAuthorizedForPrivilege(p))
+ return Status::OK();
+ return Status(ErrorCodes::Unauthorized, "Unauthorized");
+ }
+
+
+ BSONObj _addNsToSpec(const NamespaceString& ns, const BSONObj& obj) {
+ BSONObjBuilder b;
+ b.append("ns", ns);
+ b.appendElements(obj);
+ return b.obj();
+ }
+
+ virtual bool run(OperationContext* txn,
+ const string& dbname,
+ BSONObj& cmdObj,
+ int options,
+ string& errmsg,
+ BSONObjBuilder& result) {
+ // --- parse
+
+ NamespaceString ns(dbname, cmdObj[name].String());
+ Status status = userAllowedWriteNS(ns);
+ if (!status.isOK())
+ return appendCommandStatus(result, status);
+
+ if (cmdObj["indexes"].type() != Array) {
+ errmsg = "indexes has to be an array";
+ result.append("cmdObj", cmdObj);
+ return false;
}
- virtual bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int options,
- string& errmsg, BSONObjBuilder& result) {
- // --- parse
-
- NamespaceString ns( dbname, cmdObj[name].String() );
- Status status = userAllowedWriteNS( ns );
- if ( !status.isOK() )
- return appendCommandStatus( result, status );
-
- if ( cmdObj["indexes"].type() != Array ) {
- errmsg = "indexes has to be an array";
- result.append( "cmdObj", cmdObj );
- return false;
+ std::vector<BSONObj> specs;
+ {
+ BSONObjIterator i(cmdObj["indexes"].Obj());
+ while (i.more()) {
+ BSONElement e = i.next();
+ if (e.type() != Object) {
+ errmsg = "everything in indexes has to be an Object";
+ result.append("cmdObj", cmdObj);
+ return false;
+ }
+ specs.push_back(e.Obj());
}
+ }
- std::vector<BSONObj> specs;
- {
- BSONObjIterator i( cmdObj["indexes"].Obj() );
- while ( i.more() ) {
- BSONElement e = i.next();
- if ( e.type() != Object ) {
- errmsg = "everything in indexes has to be an Object";
- result.append( "cmdObj", cmdObj );
- return false;
- }
- specs.push_back( e.Obj() );
- }
+ if (specs.size() == 0) {
+ errmsg = "no indexes to add";
+ return false;
+ }
+
+ // check specs
+ for (size_t i = 0; i < specs.size(); i++) {
+ BSONObj spec = specs[i];
+ if (spec["ns"].eoo()) {
+ spec = _addNsToSpec(ns, spec);
+ specs[i] = spec;
}
- if ( specs.size() == 0 ) {
- errmsg = "no indexes to add";
+ if (spec["ns"].type() != String) {
+ errmsg = "spec has no ns";
+ result.append("spec", spec);
return false;
}
-
- // check specs
- for ( size_t i = 0; i < specs.size(); i++ ) {
- BSONObj spec = specs[i];
- if ( spec["ns"].eoo() ) {
- spec = _addNsToSpec( ns, spec );
- specs[i] = spec;
- }
-
- if ( spec["ns"].type() != String ) {
- errmsg = "spec has no ns";
- result.append( "spec", spec );
- return false;
- }
- if ( ns != spec["ns"].String() ) {
- errmsg = "namespace mismatch";
- result.append( "spec", spec );
- return false;
- }
+ if (ns != spec["ns"].String()) {
+ errmsg = "namespace mismatch";
+ result.append("spec", spec);
+ return false;
}
+ }
- // now we know we have to create index(es)
- // Note: createIndexes command does not currently respect shard versioning.
- ScopedTransaction transaction(txn, MODE_IX);
- Lock::DBLock dbLock(txn->lockState(), ns.db(), MODE_X);
- if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns)) {
- return appendCommandStatus(result, Status(ErrorCodes::NotMaster, str::stream()
- << "Not primary while creating indexes in " << ns.ns()));
- }
+ // now we know we have to create index(es)
+ // Note: createIndexes command does not currently respect shard versioning.
+ ScopedTransaction transaction(txn, MODE_IX);
+ Lock::DBLock dbLock(txn->lockState(), ns.db(), MODE_X);
+ if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns)) {
+ return appendCommandStatus(
+ result,
+ Status(ErrorCodes::NotMaster,
+ str::stream() << "Not primary while creating indexes in " << ns.ns()));
+ }
- Database* db = dbHolder().get(txn, ns.db());
- if (!db) {
- db = dbHolder().openDb(txn, ns.db());
- }
+ Database* db = dbHolder().get(txn, ns.db());
+ if (!db) {
+ db = dbHolder().openDb(txn, ns.db());
+ }
- Collection* collection = db->getCollection( ns.ns() );
- result.appendBool( "createdCollectionAutomatically", collection == NULL );
- if ( !collection ) {
- MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN {
- WriteUnitOfWork wunit(txn);
- collection = db->createCollection(txn, ns.ns(), CollectionOptions());
- invariant( collection );
- wunit.commit();
- } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "createIndexes", ns.ns());
+ Collection* collection = db->getCollection(ns.ns());
+ result.appendBool("createdCollectionAutomatically", collection == NULL);
+ if (!collection) {
+ MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN {
+ WriteUnitOfWork wunit(txn);
+ collection = db->createCollection(txn, ns.ns(), CollectionOptions());
+ invariant(collection);
+ wunit.commit();
}
+ MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "createIndexes", ns.ns());
+ }
- const int numIndexesBefore = collection->getIndexCatalog()->numIndexesTotal(txn);
- result.append("numIndexesBefore", numIndexesBefore);
+ const int numIndexesBefore = collection->getIndexCatalog()->numIndexesTotal(txn);
+ result.append("numIndexesBefore", numIndexesBefore);
- MultiIndexBlock indexer(txn, collection);
- indexer.allowBackgroundBuilding();
- indexer.allowInterruption();
+ MultiIndexBlock indexer(txn, collection);
+ indexer.allowBackgroundBuilding();
+ indexer.allowInterruption();
- const size_t origSpecsSize = specs.size();
- indexer.removeExistingIndexes(&specs);
+ const size_t origSpecsSize = specs.size();
+ indexer.removeExistingIndexes(&specs);
- if (specs.size() == 0) {
- result.append("numIndexesAfter", numIndexesBefore);
- result.append( "note", "all indexes already exist" );
- return true;
- }
+ if (specs.size() == 0) {
+ result.append("numIndexesAfter", numIndexesBefore);
+ result.append("note", "all indexes already exist");
+ return true;
+ }
- if (specs.size() != origSpecsSize) {
- result.append( "note", "index already exists" );
- }
+ if (specs.size() != origSpecsSize) {
+ result.append("note", "index already exists");
+ }
- for ( size_t i = 0; i < specs.size(); i++ ) {
- const BSONObj& spec = specs[i];
- if ( spec["unique"].trueValue() ) {
- status = checkUniqueIndexConstraints(txn, ns.ns(), spec["key"].Obj());
+ for (size_t i = 0; i < specs.size(); i++) {
+ const BSONObj& spec = specs[i];
+ if (spec["unique"].trueValue()) {
+ status = checkUniqueIndexConstraints(txn, ns.ns(), spec["key"].Obj());
- if ( !status.isOK() ) {
- appendCommandStatus( result, status );
- return false;
- }
+ if (!status.isOK()) {
+ appendCommandStatus(result, status);
+ return false;
}
}
+ }
- MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN {
- uassertStatusOK(indexer.init(specs));
- } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "createIndexes", ns.ns());
+ MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN {
+ uassertStatusOK(indexer.init(specs));
+ }
+ MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "createIndexes", ns.ns());
- // If we're a background index, replace exclusive db lock with an intent lock, so that
- // other readers and writers can proceed during this phase.
- if (indexer.getBuildInBackground()) {
- txn->recoveryUnit()->abandonSnapshot();
- dbLock.relockWithMode(MODE_IX);
- if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns)) {
- return appendCommandStatus(result, Status(ErrorCodes::NotMaster, str::stream()
- << "Not primary while creating background indexes in " << ns.ns()));
- }
+ // If we're a background index, replace exclusive db lock with an intent lock, so that
+ // other readers and writers can proceed during this phase.
+ if (indexer.getBuildInBackground()) {
+ txn->recoveryUnit()->abandonSnapshot();
+ dbLock.relockWithMode(MODE_IX);
+ if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns)) {
+ return appendCommandStatus(
+ result,
+ Status(ErrorCodes::NotMaster,
+ str::stream() << "Not primary while creating background indexes in "
+ << ns.ns()));
}
+ }
- try {
- Lock::CollectionLock colLock(txn->lockState(), ns.ns(), MODE_IX);
- uassertStatusOK(indexer.insertAllDocumentsInCollection());
- }
- catch (const DBException& e) {
- invariant(e.getCode() != ErrorCodes::WriteConflict);
- // Must have exclusive DB lock before we clean up the index build via the
- // destructor of 'indexer'.
- if (indexer.getBuildInBackground()) {
- try {
- // This function cannot throw today, but we will preemptively prepare for
- // that day, to avoid data corruption due to lack of index cleanup.
- txn->recoveryUnit()->abandonSnapshot();
- dbLock.relockWithMode(MODE_X);
- if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns)) {
- return appendCommandStatus(
- result,
- Status(ErrorCodes::NotMaster, str::stream()
- << "Not primary while creating background indexes in "
- << ns.ns() << ": cleaning up index build failure due to "
- << e.toString()));
- }
- }
- catch (...) {
- std::terminate();
+ try {
+ Lock::CollectionLock colLock(txn->lockState(), ns.ns(), MODE_IX);
+ uassertStatusOK(indexer.insertAllDocumentsInCollection());
+ } catch (const DBException& e) {
+ invariant(e.getCode() != ErrorCodes::WriteConflict);
+ // Must have exclusive DB lock before we clean up the index build via the
+ // destructor of 'indexer'.
+ if (indexer.getBuildInBackground()) {
+ try {
+ // This function cannot throw today, but we will preemptively prepare for
+ // that day, to avoid data corruption due to lack of index cleanup.
+ txn->recoveryUnit()->abandonSnapshot();
+ dbLock.relockWithMode(MODE_X);
+ if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns)) {
+ return appendCommandStatus(
+ result,
+ Status(ErrorCodes::NotMaster,
+ str::stream()
+ << "Not primary while creating background indexes in "
+ << ns.ns() << ": cleaning up index build failure due to "
+ << e.toString()));
}
+ } catch (...) {
+ std::terminate();
}
- throw;
}
- // Need to return db lock back to exclusive, to complete the index build.
- if (indexer.getBuildInBackground()) {
- txn->recoveryUnit()->abandonSnapshot();
- dbLock.relockWithMode(MODE_X);
- uassert(ErrorCodes::NotMaster,
- str::stream() << "Not primary while completing index build in " << dbname,
- repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns));
-
- Database* db = dbHolder().get(txn, ns.db());
- uassert(28551, "database dropped during index build", db);
- uassert(28552, "collection dropped during index build",
- db->getCollection(ns.ns()));
- }
-
- MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN {
- WriteUnitOfWork wunit(txn);
+ throw;
+ }
+ // Need to return db lock back to exclusive, to complete the index build.
+ if (indexer.getBuildInBackground()) {
+ txn->recoveryUnit()->abandonSnapshot();
+ dbLock.relockWithMode(MODE_X);
+ uassert(ErrorCodes::NotMaster,
+ str::stream() << "Not primary while completing index build in " << dbname,
+ repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns));
- indexer.commit();
+ Database* db = dbHolder().get(txn, ns.db());
+ uassert(28551, "database dropped during index build", db);
+ uassert(28552, "collection dropped during index build", db->getCollection(ns.ns()));
+ }
- for ( size_t i = 0; i < specs.size(); i++ ) {
- std::string systemIndexes = ns.getSystemIndexesCollection();
- getGlobalServiceContext()->getOpObserver()->onCreateIndex(txn,
- systemIndexes,
- specs[i]);
- }
+ MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN {
+ WriteUnitOfWork wunit(txn);
- wunit.commit();
- } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "createIndexes", ns.ns());
+ indexer.commit();
- result.append( "numIndexesAfter", collection->getIndexCatalog()->numIndexesTotal(txn) );
+ for (size_t i = 0; i < specs.size(); i++) {
+ std::string systemIndexes = ns.getSystemIndexesCollection();
+ getGlobalServiceContext()->getOpObserver()->onCreateIndex(
+ txn, systemIndexes, specs[i]);
+ }
- return true;
+ wunit.commit();
}
+ MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "createIndexes", ns.ns());
- private:
- static Status checkUniqueIndexConstraints(OperationContext* txn,
- StringData ns,
- const BSONObj& newIdxKey) {
+ result.append("numIndexesAfter", collection->getIndexCatalog()->numIndexesTotal(txn));
- invariant(txn->lockState()->isCollectionLockedForMode(ns, MODE_X));
+ return true;
+ }
- if ( shardingState.enabled() ) {
- CollectionMetadataPtr metadata(
- shardingState.getCollectionMetadata( ns.toString() ));
+private:
+ static Status checkUniqueIndexConstraints(OperationContext* txn,
+ StringData ns,
+ const BSONObj& newIdxKey) {
+ invariant(txn->lockState()->isCollectionLockedForMode(ns, MODE_X));
- if ( metadata ) {
- ShardKeyPattern shardKeyPattern(metadata->getKeyPattern());
- if (!shardKeyPattern.isUniqueIndexCompatible(newIdxKey)) {
- return Status(ErrorCodes::CannotCreateIndex,
- str::stream() << "cannot create unique index over " << newIdxKey
- << " with shard key pattern "
- << shardKeyPattern.toBSON());
- }
+ if (shardingState.enabled()) {
+ CollectionMetadataPtr metadata(shardingState.getCollectionMetadata(ns.toString()));
+
+ if (metadata) {
+ ShardKeyPattern shardKeyPattern(metadata->getKeyPattern());
+ if (!shardKeyPattern.isUniqueIndexCompatible(newIdxKey)) {
+ return Status(ErrorCodes::CannotCreateIndex,
+ str::stream() << "cannot create unique index over " << newIdxKey
+ << " with shard key pattern "
+ << shardKeyPattern.toBSON());
}
}
-
- return Status::OK();
}
- } cmdCreateIndex;
+ return Status::OK();
+ }
+} cmdCreateIndex;
}