BatchedCommandRequest* msgToBatchUpdate( const Message& updateMsg ) { // Parsing DbMessage throws DbMessage dbMsg( updateMsg ); NamespaceString nss( dbMsg.getns() ); int flags = dbMsg.pullInt(); bool upsert = flags & UpdateOption_Upsert; bool multi = flags & UpdateOption_Multi; const BSONObj query = dbMsg.nextJsObj(); const BSONObj updateExpr = dbMsg.nextJsObj(); // No exceptions from here on BatchedUpdateDocument* updateDoc = new BatchedUpdateDocument; updateDoc->setQuery( query ); updateDoc->setUpdateExpr( updateExpr ); updateDoc->setUpsert( upsert ); updateDoc->setMulti( multi ); BatchedCommandRequest* request = new BatchedCommandRequest( BatchedCommandRequest::BatchType_Update ); request->setNS( nss.ns() ); request->getUpdateRequest()->addToUpdates( updateDoc ); return request; }
bool BatchedCommandRequest::containsNoIDUpsert(const BatchedCommandRequest& request) { if (request.getBatchType() != BatchedCommandRequest::BatchType_Update) return false; const vector<BatchedUpdateDocument*>& updates = request.getUpdateRequest()->getUpdates(); for (vector<BatchedUpdateDocument*>::const_iterator it = updates.begin(); it != updates.end(); ++it) { const BatchedUpdateDocument* updateDoc = *it; if (updateDoc->getUpsert() && updateDoc->getQuery()["_id"].eoo()) return true; } return false; }
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; }