diff options
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/commands/create_indexes.cpp | 1 | ||||
-rw-r--r-- | src/mongo/db/commands/write_commands/batch_executor.cpp | 87 | ||||
-rw-r--r-- | src/mongo/db/instance.cpp | 131 | ||||
-rw-r--r-- | src/mongo/db/operation_context_impl.cpp | 6 |
4 files changed, 137 insertions, 88 deletions
diff --git a/src/mongo/db/commands/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp index f11cb545351..7b27aee91bb 100644 --- a/src/mongo/db/commands/create_indexes.cpp +++ b/src/mongo/db/commands/create_indexes.cpp @@ -40,6 +40,7 @@ #include "mongo/db/catalog/index_create.h" #include "mongo/db/client.h" #include "mongo/db/commands.h" +#include "mongo/db/curop.h" #include "mongo/db/ops/insert.h" #include "mongo/db/repl/oplog.h" #include "mongo/db/operation_context_impl.h" diff --git a/src/mongo/db/commands/write_commands/batch_executor.cpp b/src/mongo/db/commands/write_commands/batch_executor.cpp index 081075548a2..99ec9d61111 100644 --- a/src/mongo/db/commands/write_commands/batch_executor.cpp +++ b/src/mongo/db/commands/write_commands/batch_executor.cpp @@ -657,7 +657,6 @@ namespace mongo { static void singleCreateIndex( OperationContext* txn, const BSONObj& indexDesc, - Collection* collection, WriteOpResult* result ); static void multiUpdate( OperationContext* txn, @@ -1028,13 +1027,13 @@ namespace mongo { normalizedInsert.getValue(); try { - if (state->lockAndCheck(result)) { - if (!state->request->isInsertIndexRequest()) { + if (!state->request->isInsertIndexRequest()) { + if (state->lockAndCheck(result)) { singleInsert(state->txn, insertDoc, state->getCollection(), result); } - else { - singleCreateIndex(state->txn, insertDoc, state->getCollection(), result); - } + } + else { + singleCreateIndex(state->txn, insertDoc, result); } } catch (const DBException& ex) { @@ -1107,45 +1106,57 @@ namespace mongo { } /** - * Perform a single index insert into a collection. Requires the index descriptor be - * preprocessed and the collection already has been created. + * Perform a single index creation on a collection. Requires the index descriptor be + * preprocessed. * * Might fault or error, otherwise populates the result. */ - static void singleCreateIndex( OperationContext* txn, - const BSONObj& indexDesc, - Collection* collection, - WriteOpResult* result ) { - - const string indexNS = collection->ns().getSystemIndexesCollection(); - - txn->lockState()->assertWriteLocked( indexNS ); - - MultiIndexBlock indexer(txn, collection); - indexer.allowBackgroundBuilding(); - indexer.allowInterruption(); + static void singleCreateIndex(OperationContext* txn, + const BSONObj& indexDesc, + WriteOpResult* result) { - Status status = indexer.init(indexDesc); - if ( status.code() == ErrorCodes::IndexAlreadyExists ) { - result->getStats().n = 0; - return; // inserting an existing index is a no-op. + BSONElement nsElement = indexDesc["ns"]; + uassert(ErrorCodes::NoSuchKey, + "Missing \"ns\" field in index description", + !nsElement.eoo()); + uassert(ErrorCodes::TypeMismatch, + str::stream() << "Expected \"ns\" field of index description to be a " "string, " + "but found a " << typeName(nsElement.type()), + nsElement.type() == String); + const NamespaceString ns(nsElement.valueStringData()); + BSONObjBuilder cmdBuilder; + cmdBuilder << "createIndexes" << ns.coll(); + cmdBuilder << "indexes" << BSON_ARRAY(indexDesc); + BSONObj cmd = cmdBuilder.done(); + Command* createIndexesCmd = Command::findCommand("createIndexes"); + invariant(createIndexesCmd); + std::string errmsg; + BSONObjBuilder resultBuilder; + const bool success = createIndexesCmd->run( + txn, + ns.db().toString(), + cmd, + 0, + errmsg, + resultBuilder, + false /* fromrepl */); + Command::appendCommandStatus(resultBuilder, success, errmsg); + BSONObj cmdResult = resultBuilder.done(); + uassertStatusOK(Command::getStatusFromCommandResult(cmdResult)); + const long long numIndexesBefore = cmdResult["numIndexesBefore"].safeNumberLong(); + const long long numIndexesAfter = cmdResult["numIndexesAfter"].safeNumberLong(); + if (numIndexesAfter - numIndexesBefore == 1) { + result->getStats().n = 1; } - if (!status.isOK()) { - result->setError(toWriteError(status)); - return; + else if (numIndexesAfter != 0 && numIndexesAfter != numIndexesBefore) { + severe() << + "Created multiple indexes while attempting to create only 1; numIndexesBefore = " << + numIndexesBefore << "; numIndexesAfter = " << numIndexesAfter; + fassertFailed(28547); } - - status = indexer.insertAllDocumentsInCollection(); - if (!status.isOK()) { - result->setError(toWriteError(status)); - return; + else { + result->getStats().n = 0; } - - WriteUnitOfWork wunit(txn); - indexer.commit(); - repl::logOp( txn, "i", indexNS.c_str(), indexDesc ); - result->getStats().n = 1; - wunit.commit(); } static void multiUpdate( OperationContext* txn, diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp index 3671c10fc10..b59bb396471 100644 --- a/src/mongo/db/instance.cpp +++ b/src/mongo/db/instance.cpp @@ -42,6 +42,7 @@ #include "mongo/db/auth/authorization_session.h" #include "mongo/db/background.h" #include "mongo/db/clientcursor.h" +#include "mongo/db/commands.h" #include "mongo/db/commands/fsync.h" #include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/concurrency/write_conflict_exception.h" @@ -806,7 +807,7 @@ namespace { dbresponse.response = resp; dbresponse.responseTo = m.header().getId(); - + if( exhaust ) { curop.debug().exhaust = true; dbresponse.exhaustNS = ns; @@ -820,50 +821,6 @@ namespace { const char *ns, /*modifies*/BSONObj& js) { - if ( nsToCollectionSubstring( ns ) == "system.indexes" ) { - string targetNS = js["ns"].String(); - uassertStatusOK( userAllowedWriteNS( targetNS ) ); - - Collection* collection = ctx.db()->getCollection( txn, targetNS ); - if ( !collection ) { - // implicitly create - WriteUnitOfWork wunit(txn); - collection = ctx.db()->createCollection( txn, targetNS ); - verify( collection ); - repl::logOp(txn, - "c", - (ctx.db()->name() + ".$cmd").c_str(), - BSON("create" << nsToCollectionSubstring(targetNS))); - wunit.commit(); - } - - // Only permit interrupting an (index build) insert if the - // insert comes from a socket client request rather than a - // parent operation using the client interface. The parent - // operation might not support interrupts. - const bool mayInterrupt = txn->getCurOp()->parent() == NULL; - - txn->getCurOp()->setQuery(js); - - MultiIndexBlock indexer(txn, collection); - indexer.allowBackgroundBuilding(); - if (mayInterrupt) - indexer.allowInterruption(); - - Status status = indexer.init(js); - if ( status.code() == ErrorCodes::IndexAlreadyExists ) - return; // inserting an existing index is a no-op. - uassertStatusOK(status); - uassertStatusOK(indexer.insertAllDocumentsInCollection()); - - WriteUnitOfWork wunit(txn); - indexer.commit(); - repl::logOp(txn, "i", ns, js); - wunit.commit(); - - return; - } - StatusWith<BSONObj> fixed = fixDocumentForInsert( js ); uassertStatusOK( fixed.getStatus() ); if ( !fixed.getValue().isEmpty() ) @@ -911,13 +868,93 @@ namespace { op.debug().ninserted = i; } + static void convertSystemIndexInsertsToCommands( + DbMessage& d, + BSONArrayBuilder* allCmdsBuilder) { + while (d.moreJSObjs()) { + BSONObj spec = d.nextJsObj(); + BSONElement indexNsElement = spec["ns"]; + uassert(ErrorCodes::NoSuchKey, + str::stream() << "Missing \"ns\" field while inserting into " << d.getns(), + !indexNsElement.eoo()); + uassert(ErrorCodes::TypeMismatch, + str::stream() << "Expected \"ns\" field to have type String, not " << + typeName(indexNsElement.type()) << " while inserting into " << d.getns(), + indexNsElement.type() == String); + const StringData nsToIndex(indexNsElement.valueStringData()); + BSONObjBuilder cmdObjBuilder(allCmdsBuilder->subobjStart()); + cmdObjBuilder << "createIndexes" << nsToCollectionSubstring(nsToIndex); + BSONArrayBuilder specArrayBuilder(cmdObjBuilder.subarrayStart("indexes")); + while (true) { + BSONObjBuilder specBuilder(specArrayBuilder.subobjStart()); + BSONElement specNsElement = spec["ns"]; + if ((specNsElement.type() != String) || + (specNsElement.valueStringData() != nsToIndex)) { + + break; + } + for (BSONObjIterator iter(spec); iter.more();) { + BSONElement element = iter.next(); + if (element.fieldNameStringData() != "ns") { + specBuilder.append(element); + } + } + if (!d.moreJSObjs()) { + break; + } + spec = d.nextJsObj(); + } + } + } + + static void insertSystemIndexes(OperationContext* txn, DbMessage& d, CurOp& curOp) { + BSONArrayBuilder allCmdsBuilder; + try { + convertSystemIndexInsertsToCommands(d, &allCmdsBuilder); + } + catch (const DBException& ex) { + setLastError(ex.getCode(), ex.getInfo().msg.c_str()); + curOp.debug().exceptionInfo = ex.getInfo(); + return; + } + BSONArray allCmds(allCmdsBuilder.done()); + Command* createIndexesCmd = Command::findCommand("createIndexes"); + invariant(createIndexesCmd); + const bool keepGoing = d.reservedField() & InsertOption_ContinueOnError; + for (BSONObjIterator iter(allCmds); iter.more();) { + try { + BSONObjBuilder resultBuilder; + BSONObj cmdObj = iter.next().Obj(); + Command::execCommand( + txn, + createIndexesCmd, + 0, /* what should I use for query option? */ + d.getns(), + cmdObj, + resultBuilder, + false /* fromRepl */); + uassertStatusOK(Command::getStatusFromCommandResult(resultBuilder.done())); + } + catch (const DBException& ex) { + setLastError(ex.getCode(), ex.getInfo().msg.c_str()); + curOp.debug().exceptionInfo = ex.getInfo(); + if (!keepGoing) { + return; + } + } + } + } + void receivedInsert(OperationContext* txn, Message& m, CurOp& op) { DbMessage d(m); const char *ns = d.getns(); - const NamespaceString nsString(ns); op.debug().ns = ns; - uassertStatusOK( userAllowedWriteNS( ns ) ); + if (nsToCollectionSubstring(ns) == "system.indexes") { + insertSystemIndexes(txn, d, op); + return; + } + const NamespaceString nsString(ns); if( !d.moreJSObjs() ) { // strange. should we complain? diff --git a/src/mongo/db/operation_context_impl.cpp b/src/mongo/db/operation_context_impl.cpp index 19d4bcd0128..00e7a0ea104 100644 --- a/src/mongo/db/operation_context_impl.cpp +++ b/src/mongo/db/operation_context_impl.cpp @@ -169,9 +169,9 @@ namespace { return; } - uassert(ErrorCodes::InterruptedAtShutdown, - "interrupted at shutdown", - !getGlobalEnvironment()->getKillAllOperations()); + if (getGlobalEnvironment()->getKillAllOperations()) { + uasserted(ErrorCodes::InterruptedAtShutdown, "interrupted at shutdown"); + } if (c->curop()->maxTimeHasExpired()) { c->curop()->kill(); |