void IndexBuilder::run() { Client::initThread(name().c_str()); LOG(2) << "IndexBuilder building index " << _index; OperationContextImpl txn; Lock::ParallelBatchWriterMode::iAmABatchParticipant(txn.lockState()); txn.getClient()->getAuthorizationSession()->grantInternalAuthorization(); txn.getCurOp()->reset(HostAndPort(), dbInsert); NamespaceString ns(_index["ns"].String()); ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock dlk(txn.lockState(), ns.db(), MODE_X); Client::Context ctx(&txn, ns.getSystemIndexesCollection()); Database* db = dbHolder().get(&txn, ns.db().toString()); Status status = _build(&txn, db, true, &dlk); if ( !status.isOK() ) { error() << "IndexBuilder could not build index: " << status.toString(); fassert(28555, ErrorCodes::isInterruption(status.code())); } txn.getClient()->shutdown(); }
void SyncSourceFeedback::ensureMe(OperationContext* txn) { string myname = getHostName(); { Lock::DBLock dlk(txn->lockState(), "local", MODE_X); WriteUnitOfWork wunit(txn); Client::Context ctx(txn, "local"); // local.me is an identifier for a server for getLastError w:2+ if (!Helpers::getSingleton(txn, "local.me", _me) || !_me.hasField("host") || _me["host"].String() != myname) { // clean out local.me Helpers::emptyCollection(txn, "local.me"); // repopulate BSONObjBuilder b; b.appendOID("_id", 0, true); b.append("host", myname); _me = b.obj(); Helpers::putSingleton(txn, "local.me", _me); } wunit.commit(); // _me is used outside of a read lock, so we must copy it out of the mmap _me = _me.getOwned(); } }
Status WriteCmd::explain(OperationContext* txn, const std::string& dbname, const BSONObj& cmdObj, ExplainCommon::Verbosity verbosity, BSONObjBuilder* out) const { // For now we only explain update and delete write commands. if ( BatchedCommandRequest::BatchType_Update != _writeType && BatchedCommandRequest::BatchType_Delete != _writeType ) { return Status( ErrorCodes::IllegalOperation, "Only update and delete write ops can be explained" ); } // Parse the batch request. BatchedCommandRequest request( _writeType ); std::string errMsg; if ( !request.parseBSON( cmdObj, &errMsg ) || !request.isValid( &errMsg ) ) { return Status( ErrorCodes::FailedToParse, errMsg ); } // Note that this is a runCommmand, and therefore, the database and the collection name // are in different parts of the grammar for the command. But it's more convenient to // work with a NamespaceString. We built it here and replace it in the parsed command. // Internally, everything work with the namespace string as opposed to just the // collection name. NamespaceString nsString(dbname, request.getNS()); request.setNS(nsString.ns()); // Do the validation of the batch that is shared with non-explained write batches. Status isValid = WriteBatchExecutor::validateBatch( request ); if (!isValid.isOK()) { return isValid; } // Explain must do one additional piece of validation: For now we only explain // singleton batches. if ( request.sizeWriteOps() != 1u ) { return Status( ErrorCodes::InvalidLength, "explained write batches must be of size 1" ); } // Get a reference to the singleton batch item (it's the 0th item in the batch). BatchItemRef batchItem( &request, 0 ); if ( BatchedCommandRequest::BatchType_Update == _writeType ) { // Create the update request. UpdateRequest updateRequest( txn, nsString ); updateRequest.setQuery( batchItem.getUpdate()->getQuery() ); updateRequest.setUpdates( batchItem.getUpdate()->getUpdateExpr() ); updateRequest.setMulti( batchItem.getUpdate()->getMulti() ); updateRequest.setUpsert( batchItem.getUpdate()->getUpsert() ); updateRequest.setUpdateOpLog( true ); UpdateLifecycleImpl updateLifecycle( true, updateRequest.getNamespaceString() ); updateRequest.setLifecycle( &updateLifecycle ); updateRequest.setExplain(); // Explained updates can yield. updateRequest.setYieldPolicy(PlanExecutor::YIELD_AUTO); // Use the request to create an UpdateExecutor, and from it extract the // plan tree which will be used to execute this update. UpdateExecutor updateExecutor( &updateRequest, &txn->getCurOp()->debug() ); Status prepStatus = updateExecutor.prepare(); if ( !prepStatus.isOK() ) { return prepStatus; } // Explains of write commands are read-only, but we take an exclusive lock so // that timing info is more accurate. Lock::DBLock dlk(txn->lockState(), nsString.db(), MODE_IX); Client::Context ctx(txn, nsString); Status prepInLockStatus = updateExecutor.prepareInLock(ctx.db()); if ( !prepInLockStatus.isOK() ) { return prepInLockStatus; } // Executor registration and yield policy is handled internally by the update executor. PlanExecutor* exec = updateExecutor.getPlanExecutor(); // Explain the plan tree. return Explain::explainStages( exec, verbosity, out ); } else { invariant( BatchedCommandRequest::BatchType_Delete == _writeType ); // Create the delete request. DeleteRequest deleteRequest( txn, nsString ); deleteRequest.setQuery( batchItem.getDelete()->getQuery() ); deleteRequest.setMulti( batchItem.getDelete()->getLimit() != 1 ); deleteRequest.setUpdateOpLog(true); deleteRequest.setGod( false ); deleteRequest.setExplain(); // Explained deletes can yield. deleteRequest.setYieldPolicy(PlanExecutor::YIELD_AUTO); // Use the request to create a DeleteExecutor, and from it extract the // plan tree which will be used to execute this update. DeleteExecutor deleteExecutor( &deleteRequest ); Status prepStatus = deleteExecutor.prepare(); if ( !prepStatus.isOK() ) { return prepStatus; } // Explains of write commands are read-only, but we take a write lock so that timing // info is more accurate. Lock::DBLock dlk(txn->lockState(), nsString.db(), MODE_IX); Client::Context ctx(txn, nsString); Status prepInLockStatus = deleteExecutor.prepareInLock(ctx.db()); if ( !prepInLockStatus.isOK()) { return prepInLockStatus; } // Executor registration and yield policy is handled internally by the delete executor. PlanExecutor* exec = deleteExecutor.getPlanExecutor(); // Explain the plan tree. return Explain::explainStages( exec, verbosity, out ); } }