BatchedCommandRequest* msgToBatchInsert( const Message& insertMsg ) {

        // Parsing DbMessage throws
        DbMessage dbMsg( insertMsg );
        NamespaceString nss( dbMsg.getns() );
        bool coe = dbMsg.reservedField() & Reserved_InsertOption_ContinueOnError;

        vector<BSONObj> docs;
        do {
            docs.push_back( dbMsg.nextJsObj() );
        }
        while ( dbMsg.moreJSObjs() );

        // Continue-on-error == unordered
        bool ordered = !coe;

        // No exceptions from here on
        BatchedCommandRequest* request =
            new BatchedCommandRequest( BatchedCommandRequest::BatchType_Insert );
        request->setNS( nss.ns() );
        for ( vector<BSONObj>::const_iterator it = docs.begin(); it != docs.end(); ++it ) {
            request->getInsertRequest()->addToDocuments( *it );
        }
        request->setOrdered( ordered );

        return request;
    }
Example #2
0
// Goes over the request and preprocesses normalized versions of all the inserts in the request
static void normalizeInserts( const BatchedCommandRequest& request,
                              vector<StatusWith<BSONObj> >* normalInserts ) {

    for ( size_t i = 0; i < request.sizeWriteOps(); ++i ) {
        BSONObj insertDoc = request.getInsertRequest()->getDocumentsAt( i );
        StatusWith<BSONObj> normalInsert = fixDocumentForInsert( insertDoc );
        normalInserts->push_back( normalInsert );
        if ( request.getOrdered() && !normalInsert.isOK() )
            break;
    }
}
Example #3
0
    void msgToBatchInserts( const Message& insertMsg,
                            vector<BatchedCommandRequest*>* insertRequests ) {

        // Parsing DbMessage throws
        DbMessage dbMsg( insertMsg );
        NamespaceString nss( dbMsg.getns() );

        // Continue-on-error == unordered
        bool coe = dbMsg.reservedField() & Reserved_InsertOption_ContinueOnError;
        bool ordered = !coe;

        while ( insertRequests->empty() || dbMsg.moreJSObjs() ) {

            // Collect docs for next batch, but don't exceed maximum size
            int totalInsertSize = 0;
            vector<BSONObj> docs;
            do {
                const char* prevObjMark = dbMsg.markGet();
                BSONObj nextObj = dbMsg.nextJsObj();
                if ( totalInsertSize + nextObj.objsize() <= BSONObjMaxUserSize ) {
                    docs.push_back( nextObj );
                    totalInsertSize += docs.back().objsize();
                }
                else {
                    // Size limit exceeded, rollback to previous insert position
                    dbMsg.markReset( prevObjMark );
                    break;
                }
            }
            while ( docs.size() < BatchedCommandRequest::kMaxWriteBatchSize
                    && dbMsg.moreJSObjs() );

            dassert( !docs.empty() );

            // No exceptions from here on
            BatchedCommandRequest* request =
                new BatchedCommandRequest( BatchedCommandRequest::BatchType_Insert );
            request->setNSS( nss );
            for ( vector<BSONObj>::const_iterator it = docs.begin(); it != docs.end(); ++it ) {
                request->getInsertRequest()->addToDocuments( *it );
            }
            request->setOrdered( ordered );
            request->setWriteConcern( WriteConcernOptions::Acknowledged );

            insertRequests->push_back( request );
        }
    }
Example #4
0
    // Goes over the request and preprocesses normalized versions of all the inserts in the request
    static void normalizeInserts( const BatchedCommandRequest& request,
                                  vector<StatusWith<BSONObj> >* normalizedInserts,
                                  vector<PregeneratedKeys>* pregen ) {

        normalizedInserts->reserve(request.sizeWriteOps());
        for ( size_t i = 0; i < request.sizeWriteOps(); ++i ) {
            BSONObj insertDoc = request.getInsertRequest()->getDocumentsAt( i );
            StatusWith<BSONObj> normalInsert = fixDocumentForInsert( insertDoc );
            normalizedInserts->push_back( normalInsert );
            if ( request.getOrdered() && !normalInsert.isOK() )
                break;

            if ( !normalInsert.getValue().isEmpty() )
                insertDoc = normalInsert.getValue();

            pregen->push_back( PregeneratedKeys() );
            GeneratorHolder::getInstance()->prepare( request.getTargetingNS(),
                                                     insertDoc,
                                                     &pregen->back() );
        }
    }
Example #5
0
bool WriteBatchExecutor::applyWriteItem( const BatchedCommandRequest& request,
        int index,
        WriteStats* stats,
        BatchedErrorDetail* error ) {
    const string& ns = request.getNS();

    // Clear operation's LastError before starting.
    _le->reset( true );

    //uint64_t itemTimeMicros = 0;
    bool opSuccess = true;

    // Each write operation executes in its own PageFaultRetryableSection.  This means that
    // a single batch can throw multiple PageFaultException's, which is not the case for
    // other operations.
    PageFaultRetryableSection s;
    while ( true ) {
        try {
            // Execute the write item as a child operation of the current operation.
            CurOp childOp( _client, _client->curop() );

            // TODO Modify CurOp "wrapped" constructor to take an opcode, so calling .reset()
            // is unneeded
            childOp.reset( _client->getRemote(), getOpCode( request.getBatchType() ) );

            childOp.ensureStarted();
            OpDebug& opDebug = childOp.debug();
            opDebug.ns = ns;
            {
                Client::WriteContext ctx( ns );

                switch ( request.getBatchType() ) {
                case BatchedCommandRequest::BatchType_Insert:
                    opSuccess =
                        applyInsert( ns,
                                     request.getInsertRequest()->getDocumentsAt( index ),
                                     &childOp,
                                     stats,
                                     error );
                    break;
                case BatchedCommandRequest::BatchType_Update:
                    opSuccess = applyUpdate( ns,
                                             *request.getUpdateRequest()->getUpdatesAt( index ),
                                             &childOp,
                                             stats,
                                             error );
                    break;
                default:
                    dassert( request.getBatchType() ==
                             BatchedCommandRequest::BatchType_Delete );
                    opSuccess = applyDelete( ns,
                                             *request.getDeleteRequest()->getDeletesAt( index ),
                                             &childOp,
                                             stats,
                                             error );
                    break;
                }
            }
            childOp.done();
            //itemTimeMicros = childOp.totalTimeMicros();

            opDebug.executionTime = childOp.totalTimeMillis();
            opDebug.recordStats();

            // Log operation if running with at least "-v", or if exceeds slow threshold.
            if ( logger::globalLogDomain()->shouldLog( logger::LogSeverity::Debug( 1 ) )
                    || opDebug.executionTime > cmdLine.slowMS + childOp.getExpectedLatencyMs() ) {

                MONGO_TLOG(1) << opDebug.report( childOp ) << endl;
            }

            // TODO Log operation if logLevel >= 3 and assertion thrown (as assembleResponse()
            // does).

            // Save operation to system.profile if shouldDBProfile().
            if ( childOp.shouldDBProfile( opDebug.executionTime ) ) {
                profile( *_client, getOpCode( request.getBatchType() ), childOp );
            }
            break;
        }
        catch ( PageFaultException& e ) {
            e.touch();
        }
    }

    return opSuccess;
}