0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 09:32:32 +01:00

fix replication with multiple $inc SERVER-1161

This commit is contained in:
Eliot Horowitz 2010-05-27 11:39:48 -04:00
parent aa3e6e29af
commit d5e520ff7c
3 changed files with 70 additions and 31 deletions

View File

@ -67,7 +67,7 @@ namespace mongo {
ms.incint = elt.numberInt() + in.numberInt();
}
ms.appendIncValue( bb );
ms.appendIncValue( bb , false );
}
template< class Builder >
@ -306,8 +306,10 @@ namespace mongo {
}
auto_ptr<ModSetState> ModSet::prepare(const BSONObj &obj) const {
DEBUGUPDATE( "\t start prepare" );
ModSetState * mss = new ModSetState( obj );
// Perform this check first, so that we don't leave a partially modified object on uassert.
for ( ModHolder::const_iterator i = _mods.begin(); i != _mods.end(); ++i ) {
DEBUGUPDATE( "\t\t prepare : " << i->first );
@ -407,9 +409,41 @@ namespace mongo {
mss->amIInPlacePossible( false );
}
}
DEBUGUPDATE( "\t mss\n" << mss->toString() << "\t--" );
return auto_ptr<ModSetState>( mss );
}
void ModState::appendForOpLog( BSONObjBuilder& b ) const {
if ( incType ){
DEBUGUPDATE( "\t\t\t\t\t appendForOpLog inc fieldname: " << m->fieldName << " short:" << m->shortFieldName );
BSONObjBuilder bb( b.subobjStart( "$set" ) );
appendIncValue( bb , true );
bb.done();
return;
}
const char * name = fixedOpName ? fixedOpName : Mod::modNames[op()];
DEBUGUPDATE( "\t\t\t\t\t appendForOpLog name:" << name << " fixed: " << fixed << " fn: " << m->fieldName );
BSONObjBuilder bb( b.subobjStart( name ) );
if ( fixed )
bb.appendAs( *fixed , m->fieldName );
else
bb.appendAs( m->elt , m->fieldName );
bb.done();
}
string ModState::toString() const {
stringstream ss;
if ( fixedOpName )
ss << " fixedOpName: " << fixedOpName;
if ( fixed )
ss << " fixed: " << fixed;
return ss.str();
}
void ModSetState::applyModsInPlace() {
for ( ModStateHolder::iterator i = _mods.begin(); i != _mods.end(); ++i ) {
@ -492,7 +526,7 @@ namespace mongo {
string field = root + e.fieldName();
FieldCompareResult cmp = compareDottedFieldNames( m->second.m->fieldName , field );
DEBUGUPDATE( "\t\t\t" << field << "\t" << m->second.m->fieldName << "\t" << cmp );
DEBUGUPDATE( "\t\t\t field:" << field << "\t mod:" << m->second.m->fieldName << "\t cmp:" << cmp );
switch ( cmp ){
@ -518,15 +552,18 @@ namespace mongo {
continue;
}
case LEFT_BEFORE: // Mod on a field that doesn't exist
DEBUGUPDATE( "\t\t\t\t creating new field for: " << m->second.m->fieldName );
_appendNewFromMods( root , m->second , b , onedownseen );
m++;
continue;
case SAME:
DEBUGUPDATE( "\t\t\t\t applying mod on: " << m->second.m->fieldName );
m->second.apply( b , e );
e = es.next();
m++;
continue;
case RIGHT_BEFORE: // field that doesn't have a MOD
DEBUGUPDATE( "\t\t\t\t just copying" );
b.append( e ); // if array, ignore field name
e = es.next();
continue;
@ -540,12 +577,14 @@ namespace mongo {
// finished looping the mods, just adding the rest of the elements
while ( e.type() ){
DEBUGUPDATE( "\t\t\t copying: " << e.fieldName() );
b.append( e ); // if array, ignore field name
e = es.next();
}
// do mods that don't have fields already
for ( ; m != mend; m++ ){
DEBUGUPDATE( "\t\t\t\t appending from mod at end: " << m->second.m->fieldName );
_appendNewFromMods( root , m->second , b , onedownseen );
}
}
@ -556,6 +595,14 @@ namespace mongo {
return b.obj();
}
string ModSetState::toString() const {
stringstream ss;
for ( ModStateHolder::const_iterator i=_mods.begin(); i!=_mods.end(); ++i ){
ss << "\t\t" << i->first << "\t" << i->second.toString() << "\n";
}
return ss.str();
}
BSONObj ModSet::createNewFromQuery( const BSONObj& query ){
BSONObj newObj;
@ -610,6 +657,7 @@ namespace mongo {
uassert( 10147 , "Invalid modifier specified" + string( fn ), e.type() == Object );
BSONObj j = e.embeddedObject();
DEBUGUPDATE( "\t" << j );
BSONObjIterator jt(j);
Mod::Op op = opFromStr( fn );
@ -639,7 +687,7 @@ namespace mongo {
_mods[m.fieldName] = m;
DEBUGUPDATE( "\t\t " << fieldName << "\t" << _hasDynamicArray );
DEBUGUPDATE( "\t\t " << fieldName << "\t" << m.fieldName << "\t" << _hasDynamicArray );
}
}

View File

@ -410,23 +410,7 @@ namespace mongo {
}
}
void appendForOpLog( BSONObjBuilder& b ) const {
if ( incType ){
BSONObjBuilder bb( b.subobjStart( "$set" ) );
appendIncValue( bb );
bb.done();
return;
}
const char * name = fixedOpName ? fixedOpName : Mod::modNames[op()];
BSONObjBuilder bb( b.subobjStart( name ) );
if ( fixed )
bb.appendAs( *fixed , m->fieldName );
else
bb.appendAs( m->elt , m->fieldName );
bb.done();
}
void appendForOpLog( BSONObjBuilder& b ) const;
template< class Builder >
void apply( Builder& b , BSONElement in ){
@ -434,18 +418,22 @@ namespace mongo {
}
template< class Builder >
void appendIncValue( Builder& b ) const {
void appendIncValue( Builder& b , bool useFullName ) const {
const char * n = useFullName ? m->fieldName : m->shortFieldName;
switch ( incType ){
case NumberDouble:
b.append( m->shortFieldName , incdouble ); break;
b.append( n , incdouble ); break;
case NumberLong:
b.append( m->shortFieldName , inclong ); break;
b.append( n , inclong ); break;
case NumberInt:
b.append( m->shortFieldName , incint ); break;
b.append( n , incint ); break;
default:
assert(0);
}
}
string toString() const;
};
/**
@ -576,6 +564,7 @@ namespace mongo {
}
}
string toString() const;
friend class ModSet;
};

View File

@ -109,19 +109,21 @@ printjson( as.rpos.findOne() )
//am.getSisterDB( "local" ).getCollection( "oplog.$main" ).find().limit(10).sort( { $natural : -1 } ).forEach( printjson )
t = am.b;
t.update( { "_id" : "fun"}, { $inc : {"ws.fs.cp.wsj" : 6743} } , true, false)
t.update( { "_id" : "fun"}, { $inc : {"a.b.c.x" : 6743} } , true, false)
block()
check( "b 1" );
t.update( { "_id" : "fun"}, { $inc : {"ws.fs.cp.wsj" : 5} } , true, false)
t.update( { "_id" : "fun"}, { $inc : {"a.b.c.x" : 5} } , true, false)
block()
check( "b 2" );
t.update( { "_id" : "fun"}, { $inc : {"ws.fs.cp.wsj" : 100, "ws.fs.cp.forbes" : 911} } , true, false)
t.update( { "_id" : "fun"}, { $inc : {"a.b.c.x" : 100, "a.b.c.y" : 911} } , true, false)
block()
printjson( t.findOne() )
printjson( as.b.findOne() )
//check( "b 3" );
assert.eq( { _id : "fun" , a : { b : { c : { x : 6848 , y : 911 } } } } , as.b.findOne() , "b 3" );
//printjson( t.findOne() )
//printjson( as.b.findOne() )
//am.getSisterDB( "local" ).getCollection( "oplog.$main" ).find().sort( { $natural : -1 } ).limit(3).forEach( printjson )
check( "b 4" );