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

Replay fixes for some more update cases

This commit is contained in:
Aaron 2009-02-04 16:15:22 -05:00
parent 62ec296ec2
commit 48d9093643
2 changed files with 161 additions and 174 deletions

View File

@ -351,11 +351,13 @@ namespace mongo {
if ( !matcher.matches(js) ) {
}
else {
BSONObjBuilder idPattern;
BSONElement id;
if ( js.getObjectID( id ) )
idPattern.append( id );
pattern = idPattern.doneAndDecouple();
if ( logop ) {
BSONObjBuilder idPattern;
BSONElement id;
if ( js.getObjectID( id ) )
idPattern.append( id );
pattern = idPattern.doneAndDecouple();
}
/* note: we only update one row and quit. if you do multiple later,
be careful or multikeys in arrays could break things badly. best
@ -408,18 +410,33 @@ namespace mongo {
vector<Mod> mods;
Mod::getMods(mods, updateobj);
BSONObjBuilder b;
b.appendElements(pattern);
BSONObjIterator i( pattern );
while( i.more() ) {
BSONElement e = i.next();
if ( e.eoo() )
break;
// Presumably the number of mods is small, so this loop isn't too expensive.
for( vector<Mod>::iterator i = mods.begin(); i != mods.end(); ++i ) {
if ( strcmp( e.fieldName(), i->fieldName ) == 0 )
continue;
b.append( e );
}
}
for ( vector<Mod>::iterator i = mods.begin(); i != mods.end(); i++ )
b.append(i->fieldName, i->getn());
BSONObj obj = b.done();
theDataFileMgr.insert(ns, (void*) obj.objdata(), obj.objsize());
theDataFileMgr.insert(ns, obj);
if ( profile )
ss << " fastmodinsert ";
if ( logOp )
logOp( "i", ns, obj );
return 3;
}
if ( profile )
ss << " upsert ";
theDataFileMgr.insert(ns, (void*) updateobj.objdata(), updateobj.objsize());
theDataFileMgr.insert(ns, updateobj);
if ( logOp )
logOp( "i", ns, updateobj );
return 4;
}
return 0;
@ -440,7 +457,7 @@ namespace mongo {
*/
void updateObjects(const char *ns, BSONObj updateobj, BSONObj pattern, bool upsert, stringstream& ss) {
int rc = __updateObjects(ns, updateobj, pattern, upsert, ss, true);
if ( rc != 5 && rc != 0 )
if ( rc != 5 && rc != 0 && rc != 4 && rc != 3 )
logOp("u", ns, updateobj, &pattern, &upsert);
}

View File

@ -88,7 +88,9 @@ namespace ReplTests {
dblock lk;
setClient( ns() );
auto_ptr< Cursor > c = theDataFileMgr.findAll( ns() );
for(; c->ok(); c->advance(), ++count );
for(; c->ok(); c->advance(), ++count ) {
// cout << "obj: " << c->current().toString() << endl;
}
return count;
}
static void applyAllOperations() {
@ -135,6 +137,14 @@ namespace ReplTests {
setClient( ns() );
theDataFileMgr.insert( ns(), o.objdata(), o.objsize() );
}
static BSONObj wid( const char *json ) {
class BSONObjBuilder b;
OID id;
id.init();
b.appendOID( "_id", &id );
b.appendElements( fromjson( json ) );
return b.doneAndDecouple();
}
private:
static DBDirectClient client_;
};
@ -244,101 +254,28 @@ namespace ReplTests {
BSONObj o_;
};
// TODO Maybe make this a test suite?
class UpdateBase {
public:
void run() {
runOne< Update >();
runOne< UpdateMultiple >();
runOne< UpsertInsert >();
runOne< UpsertNoInsert >();
}
class UpdateSpec {
public:
virtual BSONObj o() const = 0;
virtual BSONObj q() const = 0;
virtual BSONObj u() const = 0;
virtual BSONObj ou() const = 0;
};
protected:
UpdateBase( UpdateSpec *s ) : s_( s ) {}
private:
template< class T >
void runOne() const {
T test( s_ );
test.run();
}
class Update : public Base {
public:
Update( UpdateSpec *s ) : s_( s ) {}
protected:
void doIt() const {
client()->update( ns(), s_->q(), s_->u() );
}
void check() const {
ASSERT_EQUALS( 1, count() );
checkOne( s_->ou() );
}
void reset() const {
deleteAll( ns() );
insert( s_->o() );
}
UpdateSpec *s_;
};
class UpdateMultiple : public Update {
public:
UpdateMultiple( UpdateSpec *s ) : Update( s ) {}
void check() const {
ASSERT_EQUALS( 2, count() );
checkOne( s_->ou() );
checkOne( s_->o() );
}
void reset() const {
deleteAll( ns() );
insert( s_->o() );
insert( s_->o() );
}
};
class UpsertInsert : public Update {
public:
UpsertInsert( UpdateSpec *s ) : Update( s ) {}
void doIt() const {
client()->update( ns(), s_->q(), s_->u(), true );
}
void reset() const {
deleteAll( ns() );
}
};
class UpsertNoInsert : public Update {
public:
UpsertNoInsert( UpdateSpec *s ) : Update( s ) {}
void doIt() const {
client()->update( ns(), s_->q(), s_->u(), true );
}
};
UpdateSpec *s_;
};
class UpdateSameField : public Base {
public:
UpdateSameField() :
o_( fromjson( "{a:'b'}" ) ),
q_( fromjson( "{a:'b'}" ) ),
o1_( wid( "{a:'b'}" ) ),
o2_( wid( "{a:'b'}" ) ),
u_( fromjson( "{a:'c'}" ) ){}
void doIt() const {
client()->update( ns(), o_, u_ );
client()->update( ns(), q_, u_ );
}
void check() const {
ASSERT_EQUALS( 2, count() );
ASSERT( !client()->findOne( ns(), o_ ).isEmpty() );
ASSERT( !client()->findOne( ns(), q_ ).isEmpty() );
ASSERT( !client()->findOne( ns(), u_ ).isEmpty() );
}
void reset() const {
deleteAll( ns() );
insert( o_ );
insert( o_ );
insert( o1_ );
insert( o2_ );
}
private:
BSONObj o_, u_;
BSONObj q_, o1_, o2_, u_;
};
class UpdateSameFieldWithId : public Base {
@ -392,20 +329,6 @@ namespace ReplTests {
}
};
// class UpdateSameField : public UpdateBase {
// public:
// class Spec : public UpdateSpec {
// virtual BSONObj o() const { return f( "{\"a\":\"b\",\"m\":\"n\"}" ); }
// virtual BSONObj q() const { return f( "{\"a\":\"b\"}" ); }
// virtual BSONObj u() const { return f( "{\"a\":\"c\"}" ); }
// virtual BSONObj ou() const { return u(); }
// };
// static Spec spec;
// UpdateSameField() :
// UpdateBase( &spec ) {}
// };
// UpdateSameField::Spec UpdateSameField::spec;
class UpdateDifferentFieldExplicitId : public Base {
public:
UpdateDifferentFieldExplicitId() :
@ -427,75 +350,122 @@ namespace ReplTests {
BSONObj o_, q_, u_;
};
class UpdateDifferentField : public UpdateBase {
public:
class Spec : public UpdateSpec {
virtual BSONObj o() const { return f( "{\"a\":\"b\",\"m\":\"n\",\"x\":\"y\"}" ); }
virtual BSONObj q() const { return f( "{\"a\":\"b\"}" ); }
virtual BSONObj u() const { return f( "{\"a\":\"b\",\"x\":\"z\"}" ); }
virtual BSONObj ou() const { return u(); }
};
static Spec spec;
UpdateDifferentField() :
UpdateBase( &spec ) {}
class UpsertUpdateNoMods : public UpdateDifferentFieldExplicitId {
void doIt() const {
client()->update( ns(), q_, u_, true );
}
};
UpdateDifferentField::Spec UpdateDifferentField::spec;
class Set : public UpdateBase {
public:
class Spec : public UpdateSpec {
virtual BSONObj o() const { return f( "{\"a\":\"b\",\"m\":1}" ); }
virtual BSONObj q() const { return f( "{\"a\":\"b\"}" ); }
virtual BSONObj u() const { return f( "{\"$set\":{\"m\":5}}" ); }
virtual BSONObj ou() const { return f( "{\"a\":\"b\",\"m\":5}" ); }
};
static Spec spec;
Set() :
UpdateBase( &spec ) {}
};
Set::Spec Set::spec;
class SetSame : public UpdateBase {
public:
class Spec : public UpdateSpec {
virtual BSONObj o() const { return f( "{\"a\":10,\"m\":1}" ); }
virtual BSONObj q() const { return f( "{\"a\":10}" ); }
virtual BSONObj u() const { return f( "{\"$set\":{\"a\":11}}" ); }
virtual BSONObj ou() const { return f( "{\"a\":11,\"m\":1}" ); }
};
static Spec spec;
SetSame() :
UpdateBase( &spec ) {}
class UpsertInsertNoMods : public InsertAutoId {
void doIt() const {
client()->update( ns(), fromjson( "{a:'c'}" ), o_, true );
}
};
class UpdateSet : public Base {
public:
UpdateSet() :
o_( fromjson( "{'_id':1,a:5}" ) ),
q_( fromjson( "{a:5}" ) ),
u_( fromjson( "{$set:{a:7}}" ) ),
ou_( fromjson( "{'_id':1,a:7}" ) ) {}
void doIt() const {
client()->update( ns(), q_, u_ );
}
void check() const {
ASSERT_EQUALS( 1, count() );
checkOne( ou_ );
}
void reset() const {
deleteAll( ns() );
insert( o_ );
}
protected:
BSONObj o_, q_, u_, ou_;
};
class UpdateInc : public Base {
public:
UpdateInc() :
o_( fromjson( "{'_id':1,a:5}" ) ),
q_( fromjson( "{a:5}" ) ),
u_( fromjson( "{$inc:{a:3}}" ) ),
ou_( fromjson( "{'_id':1,a:8}" ) ) {}
void doIt() const {
client()->update( ns(), q_, u_ );
}
void check() const {
ASSERT_EQUALS( 1, count() );
checkOne( ou_ );
}
void reset() const {
deleteAll( ns() );
insert( o_ );
}
protected:
BSONObj o_, q_, u_, ou_;
};
SetSame::Spec SetSame::spec;
class Inc : public UpdateBase {
class UpsertInsertIdMod : public Base {
public:
class Spec : public UpdateSpec {
virtual BSONObj o() const { return f( "{\"a\":\"b\",\"m\":0}" ); }
virtual BSONObj q() const { return f( "{\"a\":\"b\"}" ); }
virtual BSONObj u() const { return f( "{\"$inc\":{\"m\":5}}" ); }
virtual BSONObj ou() const { return f( "{\"a\":\"b\",\"m\":5}" ); }
};
static Spec spec;
Inc() :
UpdateBase( &spec ) {}
UpsertInsertIdMod() :
q_( fromjson( "{'_id':5,a:4}" ) ),
u_( fromjson( "{$inc:{a:3}}" ) ),
ou_( fromjson( "{'_id':5,a:3}" ) ) {}
void doIt() const {
client()->update( ns(), q_, u_, true );
}
void check() const {
ASSERT_EQUALS( 1, count() );
checkOne( ou_ );
}
void reset() const {
deleteAll( ns() );
}
protected:
BSONObj q_, u_, ou_;
};
Inc::Spec Inc::spec;
class IncSame : public UpdateBase {
class UpsertInsertSet : public Base {
public:
class Spec : public UpdateSpec {
virtual BSONObj o() const { return f( "{\"a\":0,\"m\":\"n\"}" ); }
virtual BSONObj q() const { return f( "{\"a\":0}" ); }
virtual BSONObj u() const { return f( "{\"$inc\":{\"a\":2}}" ); }
virtual BSONObj ou() const { return f( "{\"a\":2,\"m\":\"n\"}" ); }
};
static Spec spec;
IncSame() :
UpdateBase( &spec ) {}
UpsertInsertSet() :
q_( fromjson( "{a:5}" ) ),
u_( fromjson( "{$set:{a:7}}" ) ),
ou_( fromjson( "{a:7}" ) ) {}
void doIt() const {
client()->update( ns(), q_, u_, true );
}
void check() const {
ASSERT_EQUALS( 2, count() );
ASSERT( !client()->findOne( ns(), ou_ ).isEmpty() );
}
void reset() const {
deleteAll( ns() );
insert( fromjson( "{'_id':7,a:7}" ) );
}
protected:
BSONObj o_, q_, u_, ou_;
};
class UpsertInsertInc : public Base {
public:
UpsertInsertInc() :
q_( fromjson( "{a:5}" ) ),
u_( fromjson( "{$inc:{a:3}}" ) ),
ou_( fromjson( "{a:3}" ) ) {}
void doIt() const {
client()->update( ns(), q_, u_, true );
}
void check() const {
ASSERT_EQUALS( 1, count() );
ASSERT( !client()->findOne( ns(), ou_ ).isEmpty() );
}
void reset() const {
deleteAll( ns() );
}
protected:
BSONObj o_, q_, u_, ou_;
};
IncSame::Spec IncSame::spec;
class Remove : public Base {
public:
@ -557,18 +527,18 @@ namespace ReplTests {
add< Idempotence::InsertWithId >();
add< Idempotence::InsertTwo >();
add< Idempotence::InsertTwoIdentical >();
// add< Idempotence::UpdateSameField >();
add< Idempotence::UpdateSameField >();
add< Idempotence::UpdateSameFieldWithId >();
add< Idempotence::UpdateSameFieldExplicitId >();
add< Idempotence::UpdateId >();
// add< Idempotence::UpdateDifferentField >();
add< Idempotence::UpdateDifferentFieldExplicitId >();
// add< Idempotence::Set >();
// FIXME Decide what is correct & uncomment
// add< Idempotence::SetSame >();
// add< Idempotence::Inc >();
// FIXME Decide what is correct & uncomment
// add< Idempotence::IncSame >();
add< Idempotence::UpsertUpdateNoMods >();
add< Idempotence::UpsertInsertNoMods >();
add< Idempotence::UpdateSet >();
add< Idempotence::UpdateInc >();
add< Idempotence::UpsertInsertIdMod >();
add< Idempotence::UpsertInsertSet >();
add< Idempotence::UpsertInsertInc >();
add< Idempotence::Remove >();
add< Idempotence::RemoveOne >();
add< Idempotence::FailingUpdate >();