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; }
// 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; } }
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 ); } }
// 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() ); } }
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; }