Beispiel #1
0
    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();
        }
    }
Beispiel #3
0
    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 );
        }
    }