mirror of
https://github.com/mongodb/mongo.git
synced 2024-12-01 09:32:32 +01:00
tiny bit faster updates when no match or upsert perhaps
This commit is contained in:
parent
96ee65be74
commit
09bf5bbf6b
312
db/update.cpp
312
db/update.cpp
@ -1064,187 +1064,187 @@ namespace mongo {
|
||||
}
|
||||
}
|
||||
|
||||
set<DiskLoc> 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<ClientCursor> cc;
|
||||
if( c->ok() ) {
|
||||
set<DiskLoc> seenObjects;
|
||||
MatchDetails details;
|
||||
auto_ptr<ClientCursor> 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<ModSet> 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<ModSetState> 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<BSONObj&>(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<ModSet> mymodset;
|
||||
if ( details.elemMatchKey && mods->hasDynamicArray() ) {
|
||||
useMods = mods->fixDynamicArray( details.elemMatchKey );
|
||||
mymodset.reset( useMods );
|
||||
forceRewrite = true;
|
||||
}
|
||||
|
||||
auto_ptr<ModSetState> 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<BSONObj&>(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 );
|
||||
|
Loading…
Reference in New Issue
Block a user