diff --git a/db/update.cpp b/db/update.cpp index 11aafd083bb..6a2f4b613f0 100644 --- a/db/update.cpp +++ b/db/update.cpp @@ -1064,187 +1064,187 @@ namespace mongo { } } - set seenObjects; - int numModded = 0; long long nscanned = 0; - MatchDetails details; shared_ptr< MultiCursor::CursorOp > opPtr( new UpdateOp( mods.get() && mods->hasDynamicArray() ) ); shared_ptr< MultiCursor > c( new MultiCursor( ns, patternOrig, BSONObj(), opPtr, true ) ); - auto_ptr cc; + if( c->ok() ) { + set seenObjects; + MatchDetails details; + auto_ptr cc; + do { + nscanned++; - while ( c->ok() ) { - nscanned++; + bool atomic = c->matcher()->docMatcher().atomic(); - bool atomic = c->matcher()->docMatcher().atomic(); + // May have already matched in UpdateOp, but do again to get details set correctly + if ( ! c->matcher()->matchesCurrent( c.get(), &details ) ) { + c->advance(); - // May have already matched in UpdateOp, but do again to get details set correctly - if ( ! c->matcher()->matchesCurrent( c.get(), &details ) ) { - c->advance(); - - if ( nscanned % 256 == 0 && ! atomic ) { - if ( cc.get() == 0 ) { - shared_ptr< Cursor > cPtr = c; - cc.reset( new ClientCursor( QueryOption_NoCursorTimeout , cPtr , ns ) ); + if ( nscanned % 256 == 0 && ! atomic ) { + if ( cc.get() == 0 ) { + shared_ptr< Cursor > cPtr = c; + cc.reset( new ClientCursor( QueryOption_NoCursorTimeout , cPtr , ns ) ); + } + if ( ! cc->yield() ) { + cc.release(); + // TODO should we assert or something? + break; + } + if ( !c->ok() ) { + break; + } } - if ( ! cc->yield() ) { - cc.release(); - // TODO should we assert or something? - break; - } - if ( !c->ok() ) { - break; - } - } - continue; - } - - Record *r = c->_current(); - DiskLoc loc = c->currLoc(); - - // TODO Maybe this is unnecessary since we have seenObjects - if ( c->getsetdup( loc ) ) { - c->advance(); - continue; - } - - BSONObj js(r); - - BSONObj pattern = patternOrig; - - if ( logop ) { - BSONObjBuilder idPattern; - BSONElement id; - // NOTE: If the matching object lacks an id, we'll log - // with the original pattern. This isn't replay-safe. - // It might make sense to suppress the log instead - // if there's no id. - if ( js.getObjectID( id ) ) { - idPattern.append( id ); - pattern = idPattern.obj(); - } - else { - uassert( 10157 , "multi-update requires all modified objects to have an _id" , ! multi ); - } - } - - if ( profile && !multi ) // todo https://jira.mongodb.org/browse/SERVER-3052 - ss << " nscanned:" << nscanned; - - /* look for $inc etc. note as listed here, all fields to inc must be this type, you can't set some - regular ones at the moment. */ - if ( isOperatorUpdate ) { - - if ( multi ) { - c->advance(); // go to next record in case this one moves - if ( seenObjects.count( loc ) ) - continue; + continue; } - const BSONObj& onDisk = loc.obj(); + Record *r = c->_current(); + DiskLoc loc = c->currLoc(); - ModSet * useMods = mods.get(); - bool forceRewrite = false; - - auto_ptr mymodset; - if ( details.elemMatchKey && mods->hasDynamicArray() ) { - useMods = mods->fixDynamicArray( details.elemMatchKey ); - mymodset.reset( useMods ); - forceRewrite = true; + // TODO Maybe this is unnecessary since we have seenObjects + if ( c->getsetdup( loc ) ) { + c->advance(); + continue; } - auto_ptr mss = useMods->prepare( onDisk ); + BSONObj js(r); - bool indexHack = multi && ( modsIsIndexed || ! mss->canApplyInPlace() ); - - if ( indexHack ) { - if ( cc.get() ) - cc->updateLocation(); - else - c->noteLocation(); - } - - if ( modsIsIndexed <= 0 && mss->canApplyInPlace() ) { - mss->applyModsInPlace( true );// const_cast(onDisk) ); - - DEBUGUPDATE( "\t\t\t doing in place update" ); - if ( profile && !multi ) // todo https://jira.mongodb.org/browse/SERVER-3052 - ss << " fastmod "; - - if ( modsIsIndexed ) { - seenObjects.insert( loc ); - } - } - else { - if ( rs ) - rs->goingToDelete( onDisk ); - - BSONObj newObj = mss->createNewFromMods(); - checkTooLarge(newObj); - DiskLoc newLoc = theDataFileMgr.updateRecord(ns, d, nsdt, r, loc , newObj.objdata(), newObj.objsize(), debug); - if ( newLoc != loc || modsIsIndexed ) { - // object moved, need to make sure we don' get again - seenObjects.insert( newLoc ); - } - - } + BSONObj pattern = patternOrig; if ( logop ) { - DEV assert( mods->size() ); - - if ( mss->haveArrayDepMod() ) { - BSONObjBuilder patternBuilder; - patternBuilder.appendElements( pattern ); - mss->appendSizeSpecForArrayDepMods( patternBuilder ); - pattern = patternBuilder.obj(); - } - - if ( forceRewrite || mss->needOpLogRewrite() ) { - DEBUGUPDATE( "\t rewrite update: " << mss->getOpLogRewrite() ); - logOp("u", ns, mss->getOpLogRewrite() , &pattern ); + BSONObjBuilder idPattern; + BSONElement id; + // NOTE: If the matching object lacks an id, we'll log + // with the original pattern. This isn't replay-safe. + // It might make sense to suppress the log instead + // if there's no id. + if ( js.getObjectID( id ) ) { + idPattern.append( id ); + pattern = idPattern.obj(); } else { - logOp("u", ns, updateobj, &pattern ); - } - } - numModded++; - if ( ! multi ) - return UpdateResult( 1 , 1 , numModded ); - if ( indexHack ) - c->checkLocation(); - - if ( nscanned % 64 == 0 && ! atomic ) { - if ( cc.get() == 0 ) { - shared_ptr< Cursor > cPtr = c; - cc.reset( new ClientCursor( QueryOption_NoCursorTimeout , cPtr , ns ) ); - } - if ( ! cc->yield() ) { - cc.release(); - break; - } - if ( !c->ok() ) { - break; + uassert( 10157 , "multi-update requires all modified objects to have an _id" , ! multi ); } } - if (atomic) - getDur().commitIfNeeded(); + if ( profile && !multi ) // todo https://jira.mongodb.org/browse/SERVER-3052 + ss << " nscanned:" << nscanned; - continue; - } + /* look for $inc etc. note as listed here, all fields to inc must be this type, you can't set some + regular ones at the moment. */ + if ( isOperatorUpdate ) { - uassert( 10158 , "multi update only works with $ operators" , ! multi ); + if ( multi ) { + c->advance(); // go to next record in case this one moves + if ( seenObjects.count( loc ) ) + continue; + } - BSONElementManipulator::lookForTimestamps( updateobj ); - checkNoMods( updateobj ); - theDataFileMgr.updateRecord(ns, d, nsdt, r, loc , updateobj.objdata(), updateobj.objsize(), debug, god); - if ( logop ) { - DEV wassert( !god ); // god doesn't get logged, this would be bad. - logOp("u", ns, updateobj, &pattern ); - } - return UpdateResult( 1 , 0 , 1 ); - } // end cursor loop + const BSONObj& onDisk = loc.obj(); + + ModSet * useMods = mods.get(); + bool forceRewrite = false; + + auto_ptr mymodset; + if ( details.elemMatchKey && mods->hasDynamicArray() ) { + useMods = mods->fixDynamicArray( details.elemMatchKey ); + mymodset.reset( useMods ); + forceRewrite = true; + } + + auto_ptr mss = useMods->prepare( onDisk ); + + bool indexHack = multi && ( modsIsIndexed || ! mss->canApplyInPlace() ); + + if ( indexHack ) { + if ( cc.get() ) + cc->updateLocation(); + else + c->noteLocation(); + } + + if ( modsIsIndexed <= 0 && mss->canApplyInPlace() ) { + mss->applyModsInPlace( true );// const_cast(onDisk) ); + + DEBUGUPDATE( "\t\t\t doing in place update" ); + if ( profile && !multi ) // todo https://jira.mongodb.org/browse/SERVER-3052 + ss << " fastmod "; + + if ( modsIsIndexed ) { + seenObjects.insert( loc ); + } + } + else { + if ( rs ) + rs->goingToDelete( onDisk ); + + BSONObj newObj = mss->createNewFromMods(); + checkTooLarge(newObj); + DiskLoc newLoc = theDataFileMgr.updateRecord(ns, d, nsdt, r, loc , newObj.objdata(), newObj.objsize(), debug); + if ( newLoc != loc || modsIsIndexed ) { + // object moved, need to make sure we don' get again + seenObjects.insert( newLoc ); + } + + } + + if ( logop ) { + DEV assert( mods->size() ); + + if ( mss->haveArrayDepMod() ) { + BSONObjBuilder patternBuilder; + patternBuilder.appendElements( pattern ); + mss->appendSizeSpecForArrayDepMods( patternBuilder ); + pattern = patternBuilder.obj(); + } + + if ( forceRewrite || mss->needOpLogRewrite() ) { + DEBUGUPDATE( "\t rewrite update: " << mss->getOpLogRewrite() ); + logOp("u", ns, mss->getOpLogRewrite() , &pattern ); + } + else { + logOp("u", ns, updateobj, &pattern ); + } + } + numModded++; + if ( ! multi ) + return UpdateResult( 1 , 1 , numModded ); + if ( indexHack ) + c->checkLocation(); + + if ( nscanned % 64 == 0 && ! atomic ) { + if ( cc.get() == 0 ) { + shared_ptr< Cursor > cPtr = c; + cc.reset( new ClientCursor( QueryOption_NoCursorTimeout , cPtr , ns ) ); + } + if ( ! cc->yield() ) { + cc.release(); + break; + } + if ( !c->ok() ) { + break; + } + } + + if (atomic) + getDur().commitIfNeeded(); + + continue; + } + + uassert( 10158 , "multi update only works with $ operators" , ! multi ); + + BSONElementManipulator::lookForTimestamps( updateobj ); + checkNoMods( updateobj ); + theDataFileMgr.updateRecord(ns, d, nsdt, r, loc , updateobj.objdata(), updateobj.objsize(), debug, god); + if ( logop ) { + DEV wassert( !god ); // god doesn't get logged, this would be bad. + logOp("u", ns, updateobj, &pattern ); + } + return UpdateResult( 1 , 0 , 1 ); + } while ( c->ok() ); + } // endif if ( numModded ) return UpdateResult( 1 , 1 , numModded );