summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/commands/create_indexes.cpp1
-rw-r--r--src/mongo/db/commands/write_commands/batch_executor.cpp87
-rw-r--r--src/mongo/db/instance.cpp131
-rw-r--r--src/mongo/db/operation_context_impl.cpp6
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();