chunk.h   chunk.h 
skipping to change at line 213 skipping to change at line 213
private: private:
DBConfig * _config; DBConfig * _config;
string _ns; string _ns;
ShardKeyPattern _key; ShardKeyPattern _key;
bool _unique; bool _unique;
vector<Chunk*> _chunks; vector<Chunk*> _chunks;
map<string,unsigned long long> _maxMarkers; map<string,unsigned long long> _maxMarkers;
typedef map<BSONObj,Chunk*,BSONObjCmp> ChunkMap;
ChunkMap _chunkMap;
unsigned long long _sequenceNumber; unsigned long long _sequenceNumber;
friend class Chunk; friend class Chunk;
static unsigned long long NextSequenceNumber; static unsigned long long NextSequenceNumber;
}; };
// like BSONObjCmp. for use as an STL comparison functor // like BSONObjCmp. for use as an STL comparison functor
// key-order in "order" argument must match key-order in shardkey // key-order in "order" argument must match key-order in shardkey
class ChunkCmp { class ChunkCmp {
public: public:
 End of changes. 1 change blocks. 
0 lines changed or deleted 3 lines changed or added


 client.h   client.h 
skipping to change at line 167 skipping to change at line 167
}; };
private: private:
CurOp * _curOp; CurOp * _curOp;
Context * _context; Context * _context;
bool _shutdown; bool _shutdown;
list<string> _tempCollections; list<string> _tempCollections;
const char *_desc; const char *_desc;
bool _god; bool _god;
AuthenticationInfo _ai; AuthenticationInfo _ai;
OpTime _lastOp;
BSONObj _handshake;
BSONObj _remoteId;
public: public:
AuthenticationInfo * getAuthenticationInfo(){ return &_ai; } AuthenticationInfo * getAuthenticationInfo(){ return &_ai; }
bool isAdmin() { return _ai.isAuthorized( "admin" ); } bool isAdmin() { return _ai.isAuthorized( "admin" ); }
CurOp* curop() { return _curOp; } CurOp* curop() { return _curOp; }
Context* getContext(){ return _context; } Context* getContext(){ return _context; }
Database* database() { return _context ? _context->db() : 0; } Database* database() { return _context ? _context->db() : 0; }
skipping to change at line 188 skipping to change at line 191
Client(const char *desc); Client(const char *desc);
~Client(); ~Client();
const char *desc() const { return _desc; } const char *desc() const { return _desc; }
void addTempCollection( const string& ns ){ void addTempCollection( const string& ns ){
_tempCollections.push_back( ns ); _tempCollections.push_back( ns );
} }
void setLastOp( const OpTime& op ){
_lastOp = op;
}
OpTime getLastOp() const {
return _lastOp;
}
void appendLastOp( BSONObjBuilder& b ){
if ( ! _lastOp.isNull() )
b.appendTimestamp( "lastOp" , _lastOp.asDate() );
}
/* each thread which does db operations has a Client object in TLS. /* each thread which does db operations has a Client object in TLS.
call this when your thread starts. call this when your thread starts.
*/ */
static void initThread(const char *desc); static void initThread(const char *desc);
/* /*
this has to be called as the client goes away, but before thread termination this has to be called as the client goes away, but before thread termination
@return true if anything was done @return true if anything was done
*/ */
bool shutdown(); bool shutdown();
bool isGod() const { return _god; } bool isGod() const { return _god; }
friend class CurOp; friend class CurOp;
string toString() const; string toString() const;
void gotHandshake( const BSONObj& o );
BSONObj getRemoteID() const { return _remoteId; }
BSONObj getHandshake() const { return _handshake; }
}; };
inline Client& cc() { inline Client& cc() {
return *currentClient.get(); return *currentClient.get();
} }
/* each thread which does db operations has a Client object in TLS. /* each thread which does db operations has a Client object in TLS.
call this when your thread starts. call this when your thread starts.
*/ */
inline void Client::initThread(const char *desc) { inline void Client::initThread(const char *desc) {
 End of changes. 3 change blocks. 
0 lines changed or deleted 21 lines changed or added


 clientcursor.h   clientcursor.h 
skipping to change at line 34 skipping to change at line 34
#pragma once #pragma once
#include "../stdafx.h" #include "../stdafx.h"
#include "cursor.h" #include "cursor.h"
#include "jsobj.h" #include "jsobj.h"
#include "../util/message.h" #include "../util/message.h"
#include "diskloc.h" #include "diskloc.h"
#include "dbhelpers.h" #include "dbhelpers.h"
#include "matcher.h" #include "matcher.h"
#include "../client/dbclient.h"
namespace mongo { namespace mongo {
typedef long long CursorId; /* passed to the client so it can send back on getMore */ typedef long long CursorId; /* passed to the client so it can send back on getMore */
class Cursor; /* internal server cursor base class */ class Cursor; /* internal server cursor base class */
class ClientCursor; class ClientCursor;
/* todo: make this map be per connection. this will prevent cursor hij acking security attacks perhaps. /* todo: make this map be per connection. this will prevent cursor hij acking security attacks perhaps.
*/ */
typedef map<CursorId, ClientCursor*> CCById; typedef map<CursorId, ClientCursor*> CCById;
skipping to change at line 107 skipping to change at line 108
release(); release();
} }
}; };
/*const*/ CursorId cursorid; /*const*/ CursorId cursorid;
string ns; string ns;
auto_ptr<CoveredIndexMatcher> matcher; auto_ptr<CoveredIndexMatcher> matcher;
auto_ptr<Cursor> c; auto_ptr<Cursor> c;
int pos; // # objects into the curs or so far int pos; // # objects into the curs or so far
BSONObj query; BSONObj query;
int _queryOptions;
OpTime _slaveReadTill;
ClientCursor(auto_ptr<Cursor>& _c, const char *_ns, bool okToTimeou t) : ClientCursor(int queryOptions, auto_ptr<Cursor>& _c, const char *_n s) :
_idleAgeMillis(0), _pinValue(0), _idleAgeMillis(0), _pinValue(0),
_doingDeletes(false), _doingDeletes(false),
ns(_ns), c(_c), ns(_ns), c(_c),
pos(0) pos(0), _queryOptions(queryOptions)
{ {
if( !okToTimeout ) if( queryOptions & QueryOption_NoCursorTimeout )
noTimeout(); noTimeout();
recursive_scoped_lock lock(ccmutex); recursive_scoped_lock lock(ccmutex);
cursorid = allocCursorId_inlock(); cursorid = allocCursorId_inlock();
clientCursorsById.insert( make_pair(cursorid, this) ); clientCursorsById.insert( make_pair(cursorid, this) );
} }
~ClientCursor(); ~ClientCursor();
DiskLoc lastLoc() const { DiskLoc lastLoc() const {
return _lastLoc; return _lastLoc;
} }
skipping to change at line 144 skipping to change at line 147
/** /**
* do a dbtemprelease * do a dbtemprelease
* note: caller should check matcher.docMatcher().atomic() first an d not yield if atomic - * note: caller should check matcher.docMatcher().atomic() first an d not yield if atomic -
* we don't do herein as this->matcher (above) is only initia lized for true queries/getmore. * we don't do herein as this->matcher (above) is only initia lized for true queries/getmore.
* (ie not set for remote/update) * (ie not set for remote/update)
* @return if the cursor is still valid. * @return if the cursor is still valid.
* if false is returned, then this ClientCursor should be c onsidered deleted - * if false is returned, then this ClientCursor should be c onsidered deleted -
* in fact, the whole database could be gone. * in fact, the whole database could be gone.
*/ */
bool yield(); bool yield();
struct YieldLock {
YieldLock( ClientCursor * cc )
: _cc( cc ) , _id( cc->cursorid ) , _doingDeletes( cc->_doi
ngDeletes ) {
cc->updateLocation();
_unlock = new dbtempreleasecond();
}
~YieldLock(){
assert( ! _unlock );
}
bool stillOk(){
delete _unlock;
_unlock = 0;
if ( ClientCursor::find( _id , false ) == 0 ){
// i was deleted
return false;
}
_cc->_doingDeletes = _doingDeletes;
return true;
}
ClientCursor * _cc;
CursorId _id;
bool _doingDeletes;
dbtempreleasecond * _unlock;
};
YieldLock yieldHold(){
return YieldLock( this );
}
// --- some pass through helpers for Cursor ---
BSONObj indexKeyPattern() {
return c->indexKeyPattern();
}
bool ok(){
return c->ok();
}
bool advance(){
return c->advance();
}
bool currentMatches(){
if ( ! matcher.get() )
return true;
return matcher->matchesCurrent( c.get() );
}
BSONObj current(){
return c->current();
}
private: private:
void setLastLoc_inlock(DiskLoc); void setLastLoc_inlock(DiskLoc);
static ClientCursor* find_inlock(CursorId id, bool warn = true) { static ClientCursor* find_inlock(CursorId id, bool warn = true) {
CCById::iterator it = clientCursorsById.find(id); CCById::iterator it = clientCursorsById.find(id);
if ( it == clientCursorsById.end() ) { if ( it == clientCursorsById.end() ) {
if ( warn ) if ( warn )
OCCASIONALLY out() << "ClientCursor::find(): cursor not found in map " << id << " (ok after a drop)\n"; OCCASIONALLY out() << "ClientCursor::find(): cursor not found in map " << id << " (ok after a drop)\n";
return 0; return 0;
} }
skipping to change at line 201 skipping to change at line 264
} }
/** /**
* @param millis amount of idle passed time since last call * @param millis amount of idle passed time since last call
*/ */
bool shouldTimeout( unsigned millis ){ bool shouldTimeout( unsigned millis ){
_idleAgeMillis += millis; _idleAgeMillis += millis;
return _idleAgeMillis > 600000 && _pinValue == 0; return _idleAgeMillis > 600000 && _pinValue == 0;
} }
void storeOpForSlave( DiskLoc last );
void updateSlaveLocation( CurOp& curop );
unsigned idleTime(){ unsigned idleTime(){
return _idleAgeMillis; return _idleAgeMillis;
} }
static void idleTimeReport(unsigned millis); static void idleTimeReport(unsigned millis);
private: private:
// cursors normally timeout after an inactivy period to prevent exc ess memory use // cursors normally timeout after an inactivy period to prevent exc ess memory use
// setting this prevents timeout of the cursor in question. // setting this prevents timeout of the cursor in question.
void noTimeout() { void noTimeout() {
_pinValue++; _pinValue++;
 End of changes. 7 change blocks. 
3 lines changed or deleted 70 lines changed or added


 concurrency.h   concurrency.h 
skipping to change at line 32 skipping to change at line 32
name level name level
Logstream::mutex 1 Logstream::mutex 1
ClientCursor::ccmutex 2 ClientCursor::ccmutex 2
dblock 3 dblock 3
End func name with _inlock to indicate "caller must lock before callin g". End func name with _inlock to indicate "caller must lock before callin g".
*/ */
#pragma once #pragma once
#if BOOST_VERSION >= 103500 #include "../util/locks.h"
#include <boost/thread/shared_mutex.hpp>
#undef assert
#define assert xassert
#define HAVE_READLOCK
#else
#warning built with boost version 1.34 or older - limited concurrency
#endif
namespace mongo { namespace mongo {
inline bool readLockSupported(){ inline bool readLockSupported(){
#ifdef HAVE_READLOCK
return true; return true;
#else
return false;
#endif
} }
string sayClientState(); string sayClientState();
bool haveClient(); bool haveClient();
void curopWaitingForLock( int type ); void curopWaitingForLock( int type );
void curopGotLock(); void curopGotLock();
/* mutex time stats */ /* mutex time stats */
class MutexInfo { class MutexInfo {
skipping to change at line 90 skipping to change at line 79
} }
void getTimingInfo(unsigned long long &s, unsigned long long &tl) c onst { void getTimingInfo(unsigned long long &s, unsigned long long &tl) c onst {
s = start; s = start;
tl = timeLocked; tl = timeLocked;
} }
unsigned long long getTimeLocked() const { unsigned long long getTimeLocked() const {
return timeLocked; return timeLocked;
} }
}; };
#ifdef HAVE_READLOCK
//#if 0
class MongoMutex { class MongoMutex {
MutexInfo _minfo; MutexInfo _minfo;
boost::shared_mutex _m; RWLock _m;
ThreadLocalValue<int> _state; ThreadLocalValue<int> _state;
/* we use a separate TLS value for releasedEarly - that is ok as /* we use a separate TLS value for releasedEarly - that is ok as
our normal/common code path, we never even touch it. our normal/common code path, we never even touch it.
*/ */
ThreadLocalValue<bool> _releasedEarly; ThreadLocalValue<bool> _releasedEarly;
public: public:
/** /**
* @return * @return
* > 0 write lock * > 0 write lock
skipping to change at line 116 skipping to change at line 103
* < 0 read lock * < 0 read lock
*/ */
int getState(){ return _state.get(); } int getState(){ return _state.get(); }
void assertWriteLocked() { void assertWriteLocked() {
assert( getState() > 0 ); assert( getState() > 0 );
DEV assert( !_releasedEarly.get() ); DEV assert( !_releasedEarly.get() );
} }
bool atLeastReadLocked() { return _state.get() != 0; } bool atLeastReadLocked() { return _state.get() != 0; }
void assertAtLeastReadLocked() { assert(atLeastReadLocked()); } void assertAtLeastReadLocked() { assert(atLeastReadLocked()); }
bool _checkWriteLockAlready(){ void lock() {
//DEV cout << "LOCK" << endl; //DEV cout << "LOCK" << endl;
DEV assert( haveClient() ); DEV assert( haveClient() );
int s = _state.get(); int s = _state.get();
if( s > 0 ) { if( s > 0 ) {
_state.set(s+1); _state.set(s+1);
return true; return;
} }
massert( 10293 , (string)"internal error: locks are not upgrade able: " + sayClientState() , s == 0 ); massert( 10293 , (string)"internal error: locks are not upgrade able: " + sayClientState() , s == 0 );
return false;
}
void lock() {
if ( _checkWriteLockAlready() )
return;
_state.set(1); _state.set(1);
curopWaitingForLock( 1 ); curopWaitingForLock( 1 );
_m.lock(); _m.lock();
curopGotLock(); curopGotLock();
_minfo.entered(); _minfo.entered();
} }
bool lock_try() {
if ( _checkWriteLockAlready() )
return true;
curopWaitingForLock( 1 );
boost::system_time until = get_system_time();
until += boost::posix_time::milliseconds(0);
bool got = _m.timed_lock( until );
curopGotLock();
if ( got ){
_minfo.entered();
_state.set(1);
}
return got;
}
void unlock() { void unlock() {
//DEV cout << "UNLOCK" << endl; //DEV cout << "UNLOCK" << endl;
int s = _state.get(); int s = _state.get();
if( s > 1 ) { if( s > 1 ) {
_state.set(s-1); _state.set(s-1);
return; return;
} }
if( s != 1 ) { if( s != 1 ) {
if( _releasedEarly.get() ) { if( _releasedEarly.get() ) {
_releasedEarly.set(false); _releasedEarly.set(false);
skipping to change at line 222 skipping to change at line 179
} }
bool lock_shared_try( int millis ) { bool lock_shared_try( int millis ) {
int s = _state.get(); int s = _state.get();
if ( s ){ if ( s ){
// we already have a lock, so no need to try // we already have a lock, so no need to try
lock_shared(); lock_shared();
return true; return true;
} }
boost::system_time until = get_system_time(); bool got = _m.lock_shared_try( millis );
until += boost::posix_time::milliseconds(2);
bool got = _m.timed_lock_shared( until );
if ( got ) if ( got )
_state.set(-1); _state.set(-1);
return got; return got;
} }
void unlock_shared() { void unlock_shared() {
//DEV cout << " UNLOCKSHARED" << endl; //DEV cout << " UNLOCKSHARED" << endl;
int s = _state.get(); int s = _state.get();
if( s > 0 ) { if( s > 0 ) {
assert( s > 1 ); /* we must have done a lock write first to have s > 1 */ assert( s > 1 ); /* we must have done a lock write first to have s > 1 */
skipping to change at line 249 skipping to change at line 204
_state.set(s+1); _state.set(s+1);
return; return;
} }
assert( s == -1 ); assert( s == -1 );
_state.set(0); _state.set(0);
_m.unlock_shared(); _m.unlock_shared();
} }
MutexInfo& info() { return _minfo; } MutexInfo& info() { return _minfo; }
}; };
#else
/* this will be for old versions of boost */
class MongoMutex {
MutexInfo _minfo;
boost::recursive_mutex m;
ThreadLocalValue<bool> _releasedEarly;
public:
MongoMutex() { }
void lock() {
#ifdef HAVE_READLOCK
m.lock();
#error this should be impossible?
#else
boost::detail::thread::lock_ops<boost::recursive_mutex>::lock(m
);
#endif
_minfo.entered();
}
bool lock_try(){
lock();
return true;
}
void releaseEarly() {
assertWriteLocked(); // aso must not be recursive, although we
don't verify that in the old boost version
assert( !_releasedEarly.get() );
_releasedEarly.set(true);
_unlock();
}
void _unlock() {
_minfo.leaving();
#ifdef HAVE_READLOCK
m.unlock();
#else
boost::detail::thread::lock_ops<boost::recursive_mutex>::unlock
(m);
#endif
}
void unlock() {
if( _releasedEarly.get() ) {
_releasedEarly.set(false);
return;
}
_unlock();
}
void lock_shared() { lock(); }
bool lock_shared_try( int millis ) {
while ( millis-- ){
if ( getState() ){
sleepmillis(1);
continue;
}
lock_shared();
return true;
}
return false;
}
void unlock_shared() { unlock(); }
MutexInfo& info() { return _minfo; }
void assertWriteLocked() {
assert( info().isLocked() );
}
void assertAtLeastReadLocked() {
assert( info().isLocked() );
}
bool atLeastReadLocked() { return info().isLocked(); }
int getState(){ return info().isLocked() ? 1 : 0; }
};
#endif
extern MongoMutex &dbMutex; extern MongoMutex &dbMutex;
void dbunlocking_write(); void dbunlocking_write();
void dbunlocking_read(); void dbunlocking_read();
struct writelock { struct writelock {
writelock(const string& ns) { writelock(const string& ns) {
dbMutex.lock(); dbMutex.lock();
} }
skipping to change at line 366 skipping to change at line 250
dbunlocking_read(); dbunlocking_read();
dbMutex.unlock_shared(); dbMutex.unlock_shared();
} }
} }
bool got(){ bool got(){
return _got; return _got;
} }
bool _got; bool _got;
}; };
struct writelocktry {
writelocktry( const string&ns ){
_got = dbMutex.lock_try();
}
~writelocktry() {
if ( _got ){
dbunlocking_write();
dbMutex.unlock();
}
}
bool got(){
return _got;
}
bool _got;
};
struct atleastreadlock { struct atleastreadlock {
atleastreadlock( const string& ns ){ atleastreadlock( const string& ns ){
_prev = dbMutex.getState(); _prev = dbMutex.getState();
if ( _prev == 0 ) if ( _prev == 0 )
dbMutex.lock_shared(); dbMutex.lock_shared();
} }
~atleastreadlock(){ ~atleastreadlock(){
if ( _prev == 0 ) if ( _prev == 0 )
dbMutex.unlock_shared(); dbMutex.unlock_shared();
} }
 End of changes. 13 change blocks. 
140 lines changed or deleted 5 lines changed or added


 connpool.h   connpool.h 
skipping to change at line 64 skipping to change at line 64
mongo::mutex poolMutex; mongo::mutex poolMutex;
map<string,PoolForHost*> pools; // servername -> pool map<string,PoolForHost*> pools; // servername -> pool
list<DBConnectionHook*> _hooks; list<DBConnectionHook*> _hooks;
void onCreate( DBClientBase * conn ); void onCreate( DBClientBase * conn );
void onHandedOut( DBClientBase * conn ); void onHandedOut( DBClientBase * conn );
public: public:
void flush(); void flush();
DBClientBase *get(const string& host); DBClientBase *get(const string& host);
void release(const string& host, DBClientBase *c) { void release(const string& host, DBClientBase *c) {
if ( c->isFailed() ){ if ( c->isFailed() )
delete c;
return; return;
}
scoped_lock L(poolMutex); scoped_lock L(poolMutex);
pools[host]->pool.push(c); pools[host]->pool.push(c);
} }
void addHook( DBConnectionHook * hook ); void addHook( DBConnectionHook * hook );
}; };
extern DBConnectionPool pool; extern DBConnectionPool pool;
/** Use to get a connection from the pool. On exceptions things /** Use to get a connection from the pool. On exceptions things
clean up nicely. clean up nicely.
 End of changes. 2 change blocks. 
3 lines changed or deleted 1 lines changed or added


 curop.h   curop.h 
skipping to change at line 57 skipping to change at line 57
unsigned long long _end; unsigned long long _end;
bool _active; bool _active;
int _op; int _op;
bool _command; bool _command;
int _lockType; // see concurrency.h for values int _lockType; // see concurrency.h for values
bool _waitingForLock; bool _waitingForLock;
int _dbprofile; // 0=off, 1=slow, 2=all int _dbprofile; // 0=off, 1=slow, 2=all
AtomicUInt _opNum; AtomicUInt _opNum;
char _ns[Namespace::MaxNsLen+2]; char _ns[Namespace::MaxNsLen+2];
struct sockaddr_in _remote; struct SockAddr _remote;
char _queryBuf[256]; char _queryBuf[256];
void resetQuery(int x=0) { *((int *)_queryBuf) = x; } void resetQuery(int x=0) { *((int *)_queryBuf) = x; }
OpDebug _debug; OpDebug _debug;
ThreadSafeString _message; ThreadSafeString _message;
ProgressMeter _progressMeter; ProgressMeter _progressMeter;
skipping to change at line 121 skipping to change at line 121
void reset(){ void reset(){
_reset(); _reset();
_start = _checkpoint = 0; _start = _checkpoint = 0;
_active = true; _active = true;
_opNum = _nextOpNum++; _opNum = _nextOpNum++;
_ns[0] = '?'; // just in case not set later _ns[0] = '?'; // just in case not set later
_debug.reset(); _debug.reset();
resetQuery(); resetQuery();
} }
void reset( const sockaddr_in & remote, int op ) { void reset( const SockAddr & remote, int op ) {
reset(); reset();
_remote = remote; _remote = remote;
_op = op; _op = op;
} }
void markCommand(){ void markCommand(){
_command = true; _command = true;
} }
void waitingForLock( int type ){ void waitingForLock( int type ){
skipping to change at line 207 skipping to change at line 207
} }
void setQuery(const BSONObj& query) { void setQuery(const BSONObj& query) {
if( query.objsize() > (int) sizeof(_queryBuf) ) { if( query.objsize() > (int) sizeof(_queryBuf) ) {
resetQuery(1); // flag as too big and return resetQuery(1); // flag as too big and return
return; return;
} }
memcpy(_queryBuf, query.objdata(), query.objsize()); memcpy(_queryBuf, query.objdata(), query.objsize());
} }
Client * getClient() const {
return _client;
}
CurOp( Client * client , CurOp * wrapped = 0 ) { CurOp( Client * client , CurOp * wrapped = 0 ) {
_client = client; _client = client;
_wrapped = wrapped; _wrapped = wrapped;
if ( _wrapped ){ if ( _wrapped ){
_client->_curOp = this; _client->_curOp = this;
} }
_start = _checkpoint = 0; _start = _checkpoint = 0;
_active = false; _active = false;
_reset(); _reset();
_op = 0; _op = 0;
skipping to change at line 240 skipping to change at line 244
if( ! cc().getAuthenticationInfo()->isAuthorized("admin") ) { if( ! cc().getAuthenticationInfo()->isAuthorized("admin") ) {
BSONObjBuilder b; BSONObjBuilder b;
b.append("err", "unauthorized"); b.append("err", "unauthorized");
return b.obj(); return b.obj();
} }
return infoNoauth(); return infoNoauth();
} }
BSONObj infoNoauth(); BSONObj infoNoauth();
string getRemoteString(){ string getRemoteString( bool incPort = true ){
stringstream ss; return _remote.toString(incPort);
ss << inet_ntoa( _remote.sin_addr ) << ":" << ntohs( _remote.si
n_port );
return ss.str();
} }
ProgressMeter& setMessage( const char * msg , long long progressMet erTotal = 0 , int secondsBetween = 3 ){ ProgressMeter& setMessage( const char * msg , long long progressMet erTotal = 0 , int secondsBetween = 3 ){
_message = msg;
if ( progressMeterTotal ){ if ( progressMeterTotal ){
assert( ! _progressMeter.isActive() ); if ( _progressMeter.isActive() ){
cout << "about to assert, old _message: " << _message <
< endl;
assert( ! _progressMeter.isActive() );
}
_progressMeter.reset( progressMeterTotal , secondsBetween ) ; _progressMeter.reset( progressMeterTotal , secondsBetween ) ;
} }
else { else {
_progressMeter.finished(); _progressMeter.finished();
} }
_message = msg;
return _progressMeter; return _progressMeter;
} }
string getMessage() const { return _message; } string getMessage() const { return _message; }
ProgressMeter getProgressMeter() { return _progressMeter; } ProgressMeter getProgressMeter() { return _progressMeter; }
friend class Client; friend class Client;
}; };
/* 0 = ok /* 0 = ok
 End of changes. 7 change blocks. 
9 lines changed or deleted 17 lines changed or added


 database.h   database.h 
skipping to change at line 139 skipping to change at line 139
files.push_back(0); files.push_back(0);
p = files[n]; p = files[n];
} }
if ( p == 0 ) { if ( p == 0 ) {
boost::filesystem::path fullName = fileName( n ); boost::filesystem::path fullName = fileName( n );
string fullNameString = fullName.string(); string fullNameString = fullName.string();
p = new MongoDataFile(n); p = new MongoDataFile(n);
int minSize = 0; int minSize = 0;
if ( n != 0 && files[ n - 1 ] ) if ( n != 0 && files[ n - 1 ] )
minSize = files[ n - 1 ]->getHeader()->fileLength; minSize = files[ n - 1 ]->getHeader()->fileLength;
if ( sizeNeeded + MDFHeader::headerSize() > minSize ) if ( sizeNeeded + DataFileHeader::HeaderSize > minSize )
minSize = sizeNeeded + MDFHeader::headerSize(); minSize = sizeNeeded + DataFileHeader::HeaderSize;
try { try {
p->open( fullNameString.c_str(), minSize, preallocateOn ly ); p->open( fullNameString.c_str(), minSize, preallocateOn ly );
} }
catch ( AssertionException& ) { catch ( AssertionException& ) {
delete p; delete p;
throw; throw;
} }
if ( preallocateOnly ) if ( preallocateOnly )
delete p; delete p;
else else
files[n] = p; files[n] = p;
} }
return preallocateOnly ? 0 : p; return preallocateOnly ? 0 : p;
} }
MongoDataFile* addAFile( int sizeNeeded, bool preallocateNextFile ) { MongoDataFile* addAFile( int sizeNeeded = 0, bool preallocateNextFi le = false ) {
int n = (int) files.size(); int n = (int) files.size();
MongoDataFile *ret = getFile( n, sizeNeeded ); MongoDataFile *ret = getFile( n, sizeNeeded );
if ( preallocateNextFile ) if ( preallocateNextFile )
preallocateAFile(); preallocateAFile();
return ret; return ret;
} }
// safe to call this multiple times - the implementation will only preallocate one file // safe to call this multiple times - the implementation will only preallocate one file
void preallocateAFile() { void preallocateAFile() {
int n = (int) files.size(); int n = (int) files.size();
getFile( n, 0, true ); getFile( n, 0, true );
} }
MongoDataFile* suitableFile( int sizeNeeded, bool preallocate ) { MongoDataFile* suitableFile( int sizeNeeded ) {
MongoDataFile* f = newestFile(); MongoDataFile* f = newestFile();
if ( !f ) {
f = addAFile( sizeNeeded, preallocate );
}
for ( int i = 0; i < 8; i++ ) { for ( int i = 0; i < 8; i++ ) {
if ( f->getHeader()->unusedLength >= sizeNeeded ) if ( f->getHeader()->unusedLength >= sizeNeeded )
break; break;
f = addAFile( sizeNeeded, preallocate ); f = addAFile( sizeNeeded );
if ( f->getHeader()->fileLength >= MongoDataFile::maxSize() ) // this is as big as they get so might as well stop if ( f->getHeader()->fileLength >= MongoDataFile::maxSize() ) // this is as big as they get so might as well stop
break; break;
} }
return f; return f;
} }
Extent* allocExtent( const char *ns, int size, bool capped ) { Extent* allocExtent( const char *ns, int size, bool capped ) {
Extent *e = DataFileMgr::allocFromFreeList( ns, size, capped ); Extent *e = DataFileMgr::allocFromFreeList( ns, size, capped );
if( e ) return e; if( e ) return e;
return suitableFile( size, !capped )->createExtent( ns, size, c apped ); return suitableFile( size )->createExtent( ns, size, capped );
} }
MongoDataFile* newestFile() { MongoDataFile* newestFile() {
int n = (int) files.size(); int n = (int) files.size();
if ( n > 0 ) { if ( n > 0 ) n--;
n--;
} else {
return 0;
}
return getFile(n); return getFile(n);
} }
/** /**
* @return true if success, false otherwise * @return true if success, false otherwise
*/ */
bool setProfilingLevel( int newLevel , string& errmsg ); bool setProfilingLevel( int newLevel , string& errmsg );
void finishInit(); void finishInit();
 End of changes. 7 change blocks. 
14 lines changed or deleted 7 lines changed or added


 dbclient.h   dbclient.h 
skipping to change at line 755 skipping to change at line 755
DBClientPaired *clientPaired; DBClientPaired *clientPaired;
auto_ptr<MessagingPort> p; auto_ptr<MessagingPort> p;
auto_ptr<SockAddr> server; auto_ptr<SockAddr> server;
bool failed; // true if some sort of fatal error has ever happened bool failed; // true if some sort of fatal error has ever happened
bool autoReconnect; bool autoReconnect;
time_t lastReconnectTry; time_t lastReconnectTry;
string serverAddress; // remember for reconnects string serverAddress; // remember for reconnects
void _checkConnection(); void _checkConnection();
void checkConnection() { if( failed ) _checkConnection(); } void checkConnection() { if( failed ) _checkConnection(); }
map< string, pair<string,string> > authCache; map< string, pair<string,string> > authCache;
int _timeout;
public: public:
/** /**
@param _autoReconnect if true, automatically reconnect on a conn ection failure @param _autoReconnect if true, automatically reconnect on a conn ection failure
@param cp used by DBClientPaired. You do not need to specify th is parameter @param cp used by DBClientPaired. You do not need to specify th is parameter
@param timeout tcp timeout in seconds - this is for read/write, not connect
*/ */
DBClientConnection(bool _autoReconnect=false,DBClientPaired* cp=0) DBClientConnection(bool _autoReconnect=false,DBClientPaired* cp=0,i
: nt timeout=0) :
clientPaired(cp), failed(false), autoReconnect(_autoReconne clientPaired(cp), failed(false), autoReconnect(_autoReconne
ct), lastReconnectTry(0) { } ct), lastReconnectTry(0), _timeout(timeout) { }
/** Connect to a Mongo database server. /** Connect to a Mongo database server.
If autoReconnect is true, you can try to use the DBClientConnect ion even when If autoReconnect is true, you can try to use the DBClientConnect ion even when
false was returned -- it will try to connect again. false was returned -- it will try to connect again.
@param serverHostname host to connect to. can include port numb er ( 127.0.0.1 , 127.0.0.1:5555 ) @param serverHostname host to connect to. can include port numb er ( 127.0.0.1 , 127.0.0.1:5555 )
If you use IPv6 you must add a port number ( ::1:27017 )
@param errmsg any relevant error message will appended to the st ring @param errmsg any relevant error message will appended to the st ring
@return false if fails to connect. @return false if fails to connect.
*/ */
virtual bool connect(const string &serverHostname, string& errmsg); virtual bool connect(const string &serverHostname, string& errmsg);
/** Connect to a Mongo database server. Exception throwing version . /** Connect to a Mongo database server. Exception throwing version .
Throws a UserException if cannot connect. Throws a UserException if cannot connect.
If autoReconnect is true, you can try to use the DBClientConnect ion even when If autoReconnect is true, you can try to use the DBClientConnect ion even when
false was returned -- it will try to connect again. false was returned -- it will try to connect again.
skipping to change at line 910 skipping to change at line 913
/* this is the callback from our underlying connections to notify u s that we got a "not master" error. /* this is the callback from our underlying connections to notify u s that we got a "not master" error.
*/ */
void isntMaster() { void isntMaster() {
master = ( ( master == Left ) ? NotSetR : NotSetL ); master = ( ( master == Left ) ? NotSetR : NotSetL );
} }
string getServerAddress() const { string getServerAddress() const {
return left.getServerAddress() + "," + right.getServerAddress() ; return left.getServerAddress() + "," + right.getServerAddress() ;
} }
DBClientConnection& masterConn();
DBClientConnection& slaveConn(); DBClientConnection& slaveConn();
/* TODO - not yet implemented. mongos may need these. */ /* TODO - not yet implemented. mongos may need these. */
virtual bool call( Message &toSend, Message &response, bool assertO k=true ) { assert(false); return false; } virtual bool call( Message &toSend, Message &response, bool assertO k=true ) { assert(false); return false; }
virtual void say( Message &toSend ) { assert(false); } virtual void say( Message &toSend ) { assert(false); }
virtual void sayPiggyBack( Message &toSend ) { assert(false); } virtual void sayPiggyBack( Message &toSend ) { assert(false); }
virtual void checkResponse( const char *data, int nReturned ) { ass ert(false); } virtual void checkResponse( const char *data, int nReturned ) { ass ert(false); }
bool isFailed() const { bool isFailed() const {
// TODO: this really should check isFailed on current master as well // TODO: this really should check isFailed on current master as well
return master < Left; return master > NotSetR;
} }
}; };
/** pings server to check if it's up
*/
bool serverAlive( const string &uri );
DBClientBase * createDirectClient(); DBClientBase * createDirectClient();
} // namespace mongo } // namespace mongo
 End of changes. 7 change blocks. 
6 lines changed or deleted 12 lines changed or added


 dbmessage.h   dbmessage.h 
skipping to change at line 71 skipping to change at line 71
const char *data() { const char *data() {
return (char *) (((int *)&nReturned)+1); return (char *) (((int *)&nReturned)+1);
} }
int resultFlags() { int resultFlags() {
return dataAsInt(); return dataAsInt();
} }
int& _resultFlags() { int& _resultFlags() {
return dataAsInt(); return dataAsInt();
} }
void setResultFlagsToOk() { void setResultFlagsToOk() {
_resultFlags() = 0; // ResultFlag_AwaitCapable _resultFlags() = ResultFlag_AwaitCapable;
} }
}; };
#pragma pack() #pragma pack()
/* For the database/server protocol, these objects and functions encaps ulate /* For the database/server protocol, these objects and functions encaps ulate
the various messages transmitted over the connection. the various messages transmitted over the connection.
*/ */
class DbMessage { class DbMessage {
public: public:
skipping to change at line 145 skipping to change at line 145
if ( nextjsobj == data ) { if ( nextjsobj == data ) {
nextjsobj += strlen(data) + 1; // skip namespace nextjsobj += strlen(data) + 1; // skip namespace
massert( 13066 , "Message contains no documents", theEnd > nextjsobj ); massert( 13066 , "Message contains no documents", theEnd > nextjsobj );
} }
massert( 10304 , "Remaining data too small for BSON object", t heEnd - nextjsobj > 3 ); massert( 10304 , "Remaining data too small for BSON object", t heEnd - nextjsobj > 3 );
BSONObj js(nextjsobj); BSONObj js(nextjsobj);
massert( 10305 , "Invalid object size", js.objsize() > 3 ); massert( 10305 , "Invalid object size", js.objsize() > 3 );
massert( 10306 , "Next object larger than available space", massert( 10306 , "Next object larger than available space",
js.objsize() < ( theEnd - data ) ); js.objsize() < ( theEnd - data ) );
if ( objcheck && !js.valid() ) { if ( objcheck && !js.valid() ) {
if ( logLevel >= 3 ) {
log() << "bad object: " << js.hexDump() << endl;
}
massert( 10307 , "bad object in message", false); massert( 10307 , "bad object in message", false);
} }
nextjsobj += js.objsize(); nextjsobj += js.objsize();
if ( nextjsobj >= theEnd ) if ( nextjsobj >= theEnd )
nextjsobj = 0; nextjsobj = 0;
return js; return js;
} }
const Message& msg() { const Message& msg() {
return m; return m;
 End of changes. 2 change blocks. 
4 lines changed or deleted 1 lines changed or added


 engine.h   engine.h 
skipping to change at line 165 skipping to change at line 165
} }
protected: protected:
virtual Scope * createScope() = 0; virtual Scope * createScope() = 0;
private: private:
void ( *_scopeInitCallback )( Scope & ); void ( *_scopeInitCallback )( Scope & );
static void ( *_connectCallback )( DBClientWithCommands & ); static void ( *_connectCallback )( DBClientWithCommands & );
}; };
bool hasJSReturn( const string& s );
extern ScriptEngine * globalScriptEngine; extern ScriptEngine * globalScriptEngine;
} }
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 engine_spidermonkey.h   engine_spidermonkey.h 
skipping to change at line 45 skipping to change at line 45
#ifdef WIN32 #ifdef WIN32
#include "jstypes.h" #include "jstypes.h"
#undef JS_PUBLIC_API #undef JS_PUBLIC_API
#undef JS_PUBLIC_DATA #undef JS_PUBLIC_DATA
#define JS_PUBLIC_API(t) t #define JS_PUBLIC_API(t) t
#define JS_PUBLIC_DATA(t) t #define JS_PUBLIC_DATA(t) t
#endif #endif
#include "jsapi.h" #include "jsapi.h"
#include "jsobj.h"
#include "jsdate.h" #include "jsdate.h"
#include "jsregexp.h" #include "jsregexp.h"
#else #else
#include "js/jsapi.h" #include "js/jsapi.h"
#include "js/jsobj.h" #include "js/jsobj.h"
#include "js/jsdate.h" #include "js/jsdate.h"
#include "js/jsregexp.h" #include "js/jsregexp.h"
 End of changes. 1 change blocks. 
1 lines changed or deleted 0 lines changed or added


 goodies.h   goodies.h 
skipping to change at line 21 skipping to change at line 21
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#if defined(_WIN32)
# include <windows.h>
#endif
namespace mongo { namespace mongo {
#if !defined(_WIN32) && !defined(NOEXECINFO) && !defined(__freebsd__) && !d efined(__sun__) #if !defined(_WIN32) && !defined(NOEXECINFO) && !defined(__freebsd__) && !d efined(__sun__)
} // namespace mongo } // namespace mongo
#include <pthread.h> #include <pthread.h>
#include <execinfo.h> #include <execinfo.h>
namespace mongo { namespace mongo {
skipping to change at line 220 skipping to change at line 216
t.tv_nsec = 0; t.tv_nsec = 0;
if ( nanosleep( &t , 0 ) ){ if ( nanosleep( &t , 0 ) ){
cout << "nanosleep failed" << endl; cout << "nanosleep failed" << endl;
} }
} }
inline void sleepmicros(int s) { inline void sleepmicros(int s) {
if ( s <= 0 ) if ( s <= 0 )
return; return;
struct timespec t; struct timespec t;
t.tv_sec = (int)(s / 1000000); t.tv_sec = (int)(s / 1000000);
t.tv_nsec = s % 1000000; t.tv_nsec = 1000 * ( s % 1000000 );
if ( nanosleep( &t , 0 ) ){ struct timespec out;
if ( nanosleep( &t , &out ) ){
cout << "nanosleep failed" << endl; cout << "nanosleep failed" << endl;
} }
} }
inline void sleepmillis(int s) { inline void sleepmillis(int s) {
sleepmicros( s * 1000 ); sleepmicros( s * 1000 );
} }
#endif #endif
// note this wraps // note this wraps
inline int tdiff(unsigned told, unsigned tnew) { inline int tdiff(unsigned told, unsigned tnew) {
skipping to change at line 289 skipping to change at line 286
class StaticObserver : boost::noncopyable { class StaticObserver : boost::noncopyable {
public: public:
~StaticObserver() { __destroyingStatics = true; } ~StaticObserver() { __destroyingStatics = true; }
}; };
// On pthread systems, it is an error to destroy a mutex while held. S tatic global // On pthread systems, it is an error to destroy a mutex while held. S tatic global
// mutexes may be held upon shutdown in our implementation, and this wa y we avoid // mutexes may be held upon shutdown in our implementation, and this wa y we avoid
// destroying them. // destroying them.
class mutex : boost::noncopyable { class mutex : boost::noncopyable {
public: public:
mutex() { new (_buf) boost::mutex(); } mutex() { _m = new boost::mutex(); }
~mutex() { ~mutex() {
if( !__destroyingStatics ) { if( !__destroyingStatics ) {
boost().boost::mutex::~mutex(); delete _m;
} }
} }
class scoped_lock : boost::noncopyable { class scoped_lock : boost::noncopyable {
public: public:
scoped_lock( mongo::mutex &m ) : _l( m.boost() ) {} scoped_lock( mongo::mutex &m ) : _l( m.boost() ) {}
boost::mutex::scoped_lock &boost() { return _l; } boost::mutex::scoped_lock &boost() { return _l; }
private: private:
boost::mutex::scoped_lock _l; boost::mutex::scoped_lock _l;
}; };
private: private:
boost::mutex &boost() { return *( boost::mutex * )( _buf ); } boost::mutex &boost() { return *_m; }
char _buf[ sizeof( boost::mutex ) ]; boost::mutex *_m;
}; };
typedef mongo::mutex::scoped_lock scoped_lock; typedef mongo::mutex::scoped_lock scoped_lock;
typedef boost::recursive_mutex::scoped_lock recursive_scoped_lock; typedef boost::recursive_mutex::scoped_lock recursive_scoped_lock;
// simple scoped timer // simple scoped timer
class Timer { class Timer {
public: public:
Timer() { Timer() {
reset(); reset();
 End of changes. 5 change blocks. 
10 lines changed or deleted 7 lines changed or added


 hashtab.h   hashtab.h 
skipping to change at line 39 skipping to change at line 39
#pragma pack(1) #pragma pack(1)
/* you should define: /* you should define:
int Key::hash() return > 0 always. int Key::hash() return > 0 always.
*/ */
template < template <
class Key, class Key,
class Type class Type,
class PTR
> >
class HashTable : boost::noncopyable { class HashTable : boost::noncopyable {
public: public:
const char *name; const char *name;
struct Node { struct Node {
int hash; int hash;
Key k; Key k;
Type value; Type value;
bool inUse() { bool inUse() {
return hash != 0; return hash != 0;
} }
void setUnused() { void setUnused() {
hash = 0; hash = 0;
} }
} *nodes; };
PTR _buf;
int n; int n;
int maxChain; int maxChain;
Node& nodes(int i) {
return *((Node*) _buf.at(i * sizeof(Node), sizeof(Node)));
}
int _find(const Key& k, bool& found) { int _find(const Key& k, bool& found) {
found = false; found = false;
int h = k.hash(); int h = k.hash();
int i = h % n; int i = h % n;
int start = i; int start = i;
int chain = 0; int chain = 0;
int firstNonUsed = -1; int firstNonUsed = -1;
while ( 1 ) { while ( 1 ) {
if ( !nodes[i].inUse() ) { if ( !nodes(i).inUse() ) {
if ( firstNonUsed < 0 ) if ( firstNonUsed < 0 )
firstNonUsed = i; firstNonUsed = i;
} }
if ( nodes[i].hash == h && nodes[i].k == k ) { if ( nodes(i).hash == h && nodes(i).k == k ) {
if ( chain >= 200 ) if ( chain >= 200 )
out() << "warning: hashtable " << name << " long ch ain " << endl; out() << "warning: hashtable " << name << " long ch ain " << endl;
found = true; found = true;
return i; return i;
} }
chain++; chain++;
i = (i+1) % n; i = (i+1) % n;
if ( i == start ) { if ( i == start ) {
// shouldn't get here / defensive for infinite loops // shouldn't get here / defensive for infinite loops
out() << "error: hashtable " << name << " is full n:" < < n << endl; out() << "error: hashtable " << name << " is full n:" < < n << endl;
skipping to change at line 95 skipping to change at line 101
if ( firstNonUsed >= 0 ) if ( firstNonUsed >= 0 )
return firstNonUsed; return firstNonUsed;
out() << "error: hashtable " << name << " max chain n:" << n << endl; out() << "error: hashtable " << name << " max chain n:" << n << endl;
return -1; return -1;
} }
} }
} }
public: public:
/* buf must be all zeroes on initialization. */ /* buf must be all zeroes on initialization. */
HashTable(void *buf, int buflen, const char *_name) : name(_name) { HashTable(PTR buf, int buflen, const char *_name) : name(_name) {
int m = sizeof(Node); int m = sizeof(Node);
// out() << "hashtab init, buflen:" << buflen << " m:" << m << endl; // out() << "hashtab init, buflen:" << buflen << " m:" << m << endl;
n = buflen / m; n = buflen / m;
if ( (n & 1) == 0 ) if ( (n & 1) == 0 )
n--; n--;
maxChain = (int) (n * 0.05); maxChain = (int) (n * 0.05);
nodes = (Node *) buf; _buf = buf;
//nodes = (Node *) buf;
assert( sizeof(Node) == 628 ); assert( sizeof(Node) == 628 );
//out() << "HashTable() " << _name << " sizeof(node):" << sizeo f(Node) << " n:" << n << endl; //out() << "HashTable() " << _name << " sizeof(node):" << sizeo f(Node) << " n:" << n << endl;
} }
Type* get(const Key& k) { Type* get(const Key& k) {
bool found; bool found;
int i = _find(k, found); int i = _find(k, found);
if ( found ) if ( found )
return &nodes[i].value; return &nodes(i).value;
return 0; return 0;
} }
void kill(const Key& k) { void kill(const Key& k) {
bool found; bool found;
int i = _find(k, found); int i = _find(k, found);
if ( i >= 0 && found ) { if ( i >= 0 && found ) {
nodes[i].k.kill(); Node& n = nodes(i);
nodes[i].setUnused(); n.k.kill();
n.setUnused();
} }
} }
/* /*
void drop(const Key& k) { void drop(const Key& k) {
bool found; bool found;
int i = _find(k, found); int i = _find(k, found);
if ( i >= 0 && found ) { if ( i >= 0 && found ) {
nodes[i].setUnused(); nodes[i].setUnused();
} }
} }
*/ */
/** returns false if too full */ /** returns false if too full */
bool put(const Key& k, const Type& value) { bool put(const Key& k, const Type& value) {
bool found; bool found;
int i = _find(k, found); int i = _find(k, found);
if ( i < 0 ) if ( i < 0 )
return false; return false;
Node& n = nodes(i);
if ( !found ) { if ( !found ) {
nodes[i].k = k; n.k = k;
nodes[i].hash = k.hash(); n.hash = k.hash();
} }
else { else {
assert( nodes[i].hash == k.hash() ); assert( n.hash == k.hash() );
} }
nodes[i].value = value; n.value = value;
return true; return true;
} }
typedef void (*IteratorCallback)( const Key& k , Type& v ); typedef void (*IteratorCallback)( const Key& k , Type& v );
void iterAll( IteratorCallback callback ){ void iterAll( IteratorCallback callback ){
for ( int i=0; i<n; i++ ){ for ( int i=0; i<n; i++ ){
if ( ! nodes[i].inUse() ) if ( ! nodes(i).inUse() )
continue; continue;
callback( nodes[i].k , nodes[i].value ); callback( nodes(i).k , nodes(i).value );
} }
} }
}; };
#pragma pack() #pragma pack()
} // namespace mongo } // namespace mongo
 End of changes. 15 change blocks. 
15 lines changed or deleted 24 lines changed or added


 instance.h   instance.h 
skipping to change at line 109 skipping to change at line 109
DbResponse(Message *r, MSGID rt) : response(r), responseTo(rt) { DbResponse(Message *r, MSGID rt) : response(r), responseTo(rt) {
} }
DbResponse() { DbResponse() {
response = 0; response = 0;
} }
~DbResponse() { ~DbResponse() {
delete response; delete response;
} }
}; };
static SockAddr unknownAddress( "0.0.0.0", 0 ); bool assembleResponse( Message &m, DbResponse &dbresponse, const SockAd
dr &client = unknownAddress );
bool assembleResponse( Message &m, DbResponse &dbresponse, const sockad
dr_in &client = unknownAddress.sa );
void getDatabaseNames( vector< string > &names ); void getDatabaseNames( vector< string > &names );
// --- local client --- // --- local client ---
class DBDirectClient : public DBClientBase { class DBDirectClient : public DBClientBase {
public: public:
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0, virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0,
const BSONObj *fieldsToRetur n = 0, int queryOptions = 0); const BSONObj *fieldsToRetur n = 0, int queryOptions = 0);
 End of changes. 1 change blocks. 
4 lines changed or deleted 2 lines changed or added


 jsobj.h   jsobj.h 
skipping to change at line 532 skipping to change at line 532
/** Retrieve the regex flags (options) for a Regex element */ /** Retrieve the regex flags (options) for a Regex element */
const char *regexFlags() const { const char *regexFlags() const {
const char *p = regex(); const char *p = regex();
return p + strlen(p) + 1; return p + strlen(p) + 1;
} }
/** like operator== but doesn't check the fieldname, /** like operator== but doesn't check the fieldname,
just the value. just the value.
*/ */
bool valuesEqual(const BSONElement& r) const { bool valuesEqual(const BSONElement& r) const {
switch( type() ) { return woCompare( r , false ) == 0;
case NumberLong:
return _numberLong() == r.numberLong() && r.isNumber();
case NumberDouble:
return _numberDouble() == r.number() && r.isNumber();
case NumberInt:
return _numberInt() == r.numberInt() && r.isNumber();
default:
;
}
bool match= valuesize() == r.valuesize() &&
memcmp(value(),r.value(),valuesize()) == 0;
return match && canonicalType() == r.canonicalType();
} }
/** Returns true if elements are equal. */ /** Returns true if elements are equal. */
bool operator==(const BSONElement& r) const { bool operator==(const BSONElement& r) const {
if ( strcmp(fieldName(), r.fieldName()) != 0 ) return woCompare( r , true ) == 0;
return false;
return valuesEqual(r);
} }
/** Well ordered comparison. /** Well ordered comparison.
@return <0: l<r. 0:l==r. >0:l>r @return <0: l<r. 0:l==r. >0:l>r
order by type, field name, and field value. order by type, field name, and field value.
If considerFieldName is true, pay attention to the field name. If considerFieldName is true, pay attention to the field name.
*/ */
int woCompare( const BSONElement &e, bool considerFieldName = true ) const; int woCompare( const BSONElement &e, bool considerFieldName = true ) const;
const char * rawdata() const { const char * rawdata() const {
skipping to change at line 597 skipping to change at line 583
bool isABSONObj() const { bool isABSONObj() const {
switch( type() ){ switch( type() ){
case Object: case Object:
case Array: case Array:
return true; return true;
default: default:
return false; return false;
} }
} }
OpTime optime() const {
return OpTime( *reinterpret_cast< const unsigned long long* >(
value() ) );
}
Date_t timestampTime() const{ Date_t timestampTime() const{
unsigned long long t = ((unsigned int*)(value() + 4 ))[0]; unsigned long long t = ((unsigned int*)(value() + 4 ))[0];
return t * 1000; return t * 1000;
} }
unsigned int timestampInc() const{ unsigned int timestampInc() const{
return ((unsigned int*)(value() ))[0]; return ((unsigned int*)(value() ))[0];
} }
const char * dbrefNS() const { const char * dbrefNS() const {
uassert( 10063 , "not a dbref" , type() == DBRef ); uassert( 10063 , "not a dbref" , type() == DBRef );
skipping to change at line 759 skipping to change at line 749
~BSONObj() { _objdata = 0; } ~BSONObj() { _objdata = 0; }
void appendSelfToBufBuilder(BufBuilder& b) const { void appendSelfToBufBuilder(BufBuilder& b) const {
assert( objsize() ); assert( objsize() );
b.append(reinterpret_cast<const void *>( objdata() ), objsize() ); b.append(reinterpret_cast<const void *>( objdata() ), objsize() );
} }
/** Readable representation of a BSON object in an extended JSON-st yle notation. /** Readable representation of a BSON object in an extended JSON-st yle notation.
This is an abbreviated representation which might be used for l ogging. This is an abbreviated representation which might be used for l ogging.
*/ */
string toString() const; string toString( bool isArray = false ) const;
operator string() const { return toString(); } operator string() const { return toString(); }
/** Properly formatted JSON string. */ /** Properly formatted JSON string. */
string jsonString( JsonStringFormat format = Strict ) const; string jsonString( JsonStringFormat format = Strict ) const;
/** note: addFields always adds _id even if not specified */ /** note: addFields always adds _id even if not specified */
int addFields(BSONObj& from, set<string>& fields); /* returns n add ed */ int addFields(BSONObj& from, set<string>& fields); /* returns n add ed */
/** returns # of top level fields in the object /** returns # of top level fields in the object
note: iterates to count the fields note: iterates to count the fields
skipping to change at line 998 skipping to change at line 988
opALL = 0x0B, opALL = 0x0B,
NIN = 0x0C, NIN = 0x0C,
opEXISTS = 0x0D, opEXISTS = 0x0D,
opMOD = 0x0E, opMOD = 0x0E,
opTYPE = 0x0F, opTYPE = 0x0F,
opREGEX = 0x10, opREGEX = 0x10,
opOPTIONS = 0x11, opOPTIONS = 0x11,
opELEM_MATCH = 0x12, opELEM_MATCH = 0x12,
opNEAR = 0x13, opNEAR = 0x13,
opWITHIN = 0x14, opWITHIN = 0x14,
opMAX_DISTANCE=0x15
}; };
}; };
ostream& operator<<( ostream &s, const BSONObj &o ); ostream& operator<<( ostream &s, const BSONObj &o );
ostream& operator<<( ostream &s, const BSONElement &e ); ostream& operator<<( ostream &s, const BSONElement &e );
struct BSONArray: BSONObj { struct BSONArray: BSONObj {
// Don't add anything other than forwarding constructors!!! // Don't add anything other than forwarding constructors!!!
BSONArray(): BSONObj() {} BSONArray(): BSONObj() {}
explicit BSONArray(const BSONObj& obj): BSONObj(obj) {} explicit BSONArray(const BSONObj& obj): BSONObj(obj) {}
}; };
skipping to change at line 1661 skipping to change at line 1652
BSONArrayBuilder() : _i(0), _b() {} BSONArrayBuilder() : _i(0), _b() {}
BSONArrayBuilder( BufBuilder &b ) : _i(0), _b(b) {} BSONArrayBuilder( BufBuilder &b ) : _i(0), _b(b) {}
template <typename T> template <typename T>
BSONArrayBuilder& append(const T& x){ BSONArrayBuilder& append(const T& x){
_b.append(num().c_str(), x); _b.append(num().c_str(), x);
return *this; return *this;
} }
BSONArrayBuilder& append(const BSONElement& e){ BSONArrayBuilder& append(const BSONElement& e){
_b.appendAs(e, num().c_str()); _b.appendAs(e, num());
return *this; return *this;
} }
template <typename T> template <typename T>
BSONArrayBuilder& operator<<(const T& x){ BSONArrayBuilder& operator<<(const T& x){
return append(x); return append(x);
} }
void appendNull() { void appendNull() {
_b.appendNull(num().c_str()); _b.appendNull(num().c_str());
skipping to change at line 1899 skipping to change at line 1890
BSONObjIterator it(x); BSONObjIterator it(x);
while ( it.moreWithEOO() ) { while ( it.moreWithEOO() ) {
BSONElement e = it.next(); BSONElement e = it.next();
if ( e.eoo() ) break; if ( e.eoo() ) break;
append(e); append(e);
} }
return *this; return *this;
} }
inline bool BSONObj::isValid(){ inline bool BSONObj::isValid(){
return objsize() > 0 && objsize() <= 1024 * 1024 * 8; int x = objsize();
return x > 0 && x <= 1024 * 1024 * 8;
} }
inline bool BSONObj::getObjectID(BSONElement& e) const { inline bool BSONObj::getObjectID(BSONElement& e) const {
BSONElement f = getField("_id"); BSONElement f = getField("_id");
if( !f.eoo() ) { if( !f.eoo() ) {
e = f; e = f;
return true; return true;
} }
return false; return false;
} }
 End of changes. 7 change blocks. 
19 lines changed or deleted 12 lines changed or added


 matcher.h   matcher.h 
skipping to change at line 28 skipping to change at line 28
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "jsobj.h" #include "jsobj.h"
#include <pcrecpp.h> #include <pcrecpp.h>
namespace mongo { namespace mongo {
class Cursor;
class CoveredIndexMatcher; class CoveredIndexMatcher;
class Matcher; class Matcher;
class RegexMatcher { class RegexMatcher {
public: public:
const char *fieldName; const char *fieldName;
const char *regex; const char *regex;
const char *flags; const char *flags;
string prefix; string prefix;
shared_ptr< pcrecpp::RE > re; shared_ptr< pcrecpp::RE > re;
skipping to change at line 192 skipping to change at line 193
friend class CoveredIndexMatcher; friend class CoveredIndexMatcher;
}; };
// If match succeeds on index key, then attempt to match full document. // If match succeeds on index key, then attempt to match full document.
class CoveredIndexMatcher : boost::noncopyable { class CoveredIndexMatcher : boost::noncopyable {
public: public:
CoveredIndexMatcher(const BSONObj &pattern, const BSONObj &indexKey Pattern); CoveredIndexMatcher(const BSONObj &pattern, const BSONObj &indexKey Pattern);
bool matches(const BSONObj &o){ return _docMatcher.matches( o ); } bool matches(const BSONObj &o){ return _docMatcher.matches( o ); }
bool matches(const BSONObj &key, const DiskLoc &recLoc , MatchDetai ls * details = 0 ); bool matches(const BSONObj &key, const DiskLoc &recLoc , MatchDetai ls * details = 0 );
bool matchesCurrent( Cursor * cursor , MatchDetails * details = 0 ) ;
bool needRecord(){ return _needRecord; } bool needRecord(){ return _needRecord; }
Matcher& docMatcher() { return _docMatcher; } Matcher& docMatcher() { return _docMatcher; }
private: private:
Matcher _keyMatcher; Matcher _keyMatcher;
Matcher _docMatcher; Matcher _docMatcher;
bool _needRecord; bool _needRecord;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 2 change blocks. 
0 lines changed or deleted 2 lines changed or added


 message.h   message.h 
skipping to change at line 25 skipping to change at line 25
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "../util/sock.h" #include "../util/sock.h"
#include "../util/atomic_int.h" #include "../util/atomic_int.h"
namespace mongo { namespace mongo {
extern bool noUnixSocket;
class Message; class Message;
class MessagingPort; class MessagingPort;
class PiggyBackData; class PiggyBackData;
typedef AtomicUInt MSGID; typedef AtomicUInt MSGID;
class Listener { class Listener {
public: public:
Listener(const string &_ip, int p) : ip(_ip), port(p) { } Listener(const string &ip, int p, bool logConnect=true ) : _ip(ip), _port(p), _logConnect(logConnect) { }
virtual ~Listener() {} virtual ~Listener() {}
bool init(); // set up socket void initAndListen(); // never returns unless error (start a thread
int socket() const { return sock; } )
void listen(); // never returns (start a thread)
/* spawn a thread, etc., then return */ /* spawn a thread, etc., then return */
virtual void accepted(MessagingPort *mp) = 0; virtual void accepted(int sock, const SockAddr& from);
virtual void accepted(MessagingPort *mp){
assert(!"You must overwrite one of the accepted methods");
}
private: private:
string ip; string _ip;
int port; int _port;
int sock; bool _logConnect;
}; };
class AbstractMessagingPort { class AbstractMessagingPort {
public: public:
virtual ~AbstractMessagingPort() { } virtual ~AbstractMessagingPort() { }
virtual void reply(Message& received, Message& response, MSGID resp onseTo) = 0; // like the reply below, but doesn't rely on received.data sti ll being available virtual void reply(Message& received, Message& response, MSGID resp onseTo) = 0; // like the reply below, but doesn't rely on received.data sti ll being available
virtual void reply(Message& received, Message& response) = 0; virtual void reply(Message& received, Message& response) = 0;
virtual unsigned remotePort() = 0 ; virtual unsigned remotePort() = 0 ;
}; };
class MessagingPort : public AbstractMessagingPort { class MessagingPort : public AbstractMessagingPort {
public: public:
MessagingPort(int sock, SockAddr& farEnd); MessagingPort(int sock, const SockAddr& farEnd);
MessagingPort();
// in some cases the timeout will actually be 2x this value - eg we
do a partial send,
// then the timeout fires, then we try to send again, then the time
out fires again with
// no data sent, then we detect that the other side is down
MessagingPort(int timeout = 0);
virtual ~MessagingPort(); virtual ~MessagingPort();
void shutdown(); void shutdown();
bool connect(SockAddr& farEnd); bool connect(SockAddr& farEnd);
/* it's assumed if you reuse a message object, that it doesn't cros s MessagingPort's. /* it's assumed if you reuse a message object, that it doesn't cros s MessagingPort's.
also, the Message data will go out of scope on the subsequent re cv call. also, the Message data will go out of scope on the subsequent re cv call.
*/ */
bool recv(Message& m); bool recv(Message& m);
void reply(Message& received, Message& response, MSGID responseTo); void reply(Message& received, Message& response, MSGID responseTo);
void reply(Message& received, Message& response); void reply(Message& received, Message& response);
bool call(Message& toSend, Message& response); bool call(Message& toSend, Message& response);
void say(Message& toSend, int responseTo = -1); void say(Message& toSend, int responseTo = -1);
void piggyBack( Message& toSend , int responseTo = -1 ); void piggyBack( Message& toSend , int responseTo = -1 );
virtual unsigned remotePort(); virtual unsigned remotePort();
int send( const char * data , const int len ); // send len or throw SocketException
int recv( char * data , int max ); void send( const char * data , int len, const char *context );
// recv len or throw SocketException
void recv( char * data , int len );
int unsafe_recv( char *buf, int max );
private: private:
int sock; int sock;
PiggyBackData * piggyBackData; PiggyBackData * piggyBackData;
public: public:
SockAddr farEnd; SockAddr farEnd;
int _timeout;
friend class PiggyBackData; friend class PiggyBackData;
}; };
//#pragma pack() //#pragma pack()
#pragma pack(1) #pragma pack(1)
enum Operations { enum Operations {
opReply = 1, /* reply. responseTo is set. */ opReply = 1, /* reply. responseTo is set. */
dbMsg = 1000, /* generic msg command followed by a string */ dbMsg = 1000, /* generic msg command followed by a string */
 End of changes. 8 change blocks. 
12 lines changed or deleted 29 lines changed or added


 miniwebserver.h   miniwebserver.h 
skipping to change at line 26 skipping to change at line 26
*/ */
#pragma once #pragma once
#include "../stdafx.h" #include "../stdafx.h"
#include "message.h" #include "message.h"
#include "../db/jsobj.h" #include "../db/jsobj.h"
namespace mongo { namespace mongo {
class MiniWebServer { class MiniWebServer : public Listener {
public: public:
MiniWebServer(); MiniWebServer(const string &ip, int _port);
virtual ~MiniWebServer() {} virtual ~MiniWebServer() {}
bool init(const string &ip, int _port);
void run();
virtual void doRequest( virtual void doRequest(
const char *rq, // the full request const char *rq, // the full request
string url, string url,
// set these and return them: // set these and return them:
string& responseMsg, string& responseMsg,
int& responseCode, int& responseCode,
vector<string>& headers, // if completely empty, content-type: text/html will be added vector<string>& headers, // if completely empty, content-type: text/html will be added
const SockAddr &from const SockAddr &from
) = 0; ) = 0;
int socket() const { return sock; }
protected: protected:
string parseURL( const char * buf ); string parseURL( const char * buf );
string parseMethod( const char * headers ); string parseMethod( const char * headers );
string getHeader( const char * headers , string name ); string getHeader( const char * headers , string name );
void parseParams( BSONObj & params , string query ); void parseParams( BSONObj & params , string query );
static const char *body( const char *buf ); static const char *body( const char *buf );
static string urlDecode(const char* s); static string urlDecode(const char* s);
static string urlDecode(string s) {return urlDecode(s.c_str());} static string urlDecode(string s) {return urlDecode(s.c_str());}
private: private:
void accepted(int s, const SockAddr &from); void accepted(int s, const SockAddr &from);
static bool fullReceive( const char *buf ); static bool fullReceive( const char *buf );
int port;
int sock;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 5 change blocks. 
10 lines changed or deleted 2 lines changed or added


 mmap.h   mmap.h 
skipping to change at line 22 skipping to change at line 22
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
namespace mongo { namespace mongo {
class MemoryMappedFile { /* the administrative-ish stuff here */
class MongoFile {
protected:
virtual void close() = 0;
virtual void flush(bool sync) = 0;
void created(); /* subclass must call after create */
void destroyed(); /* subclass must call in destructor */
public: public:
virtual long length() = 0;
enum Options { enum Options {
SEQUENTIAL = 1 SEQUENTIAL = 1 // hint - e.g. FILE_FLAG_SEQUENTIAL_SCAN on wind
ows
};
virtual ~MongoFile() {}
static int flushAll( bool sync ); // returns n flushed
static long long totalMappedLength();
static void closeAllFiles( stringstream &message );
/* can be "overriden" if necessary */
static bool exists(boost::filesystem::path p) {
return boost::filesystem::exists(p);
}
};
class MFTemplate : public MongoFile {
protected:
virtual void close();
virtual void flush(bool sync);
public:
virtual long length();
class Pointer {
public:
void* at(int offset, int len);
void grow(int offset, int len);
bool isNull() const;
};
Pointer map( const char *filename );
Pointer map(const char *_filename, long &length, int options=0);
};
class MemoryMappedFile : public MongoFile {
public:
class Pointer {
char *_base;
public:
Pointer() : _base(0) { }
Pointer(void *p) : _base((char*) p) { }
void* at(int offset, int maxLen) { return _base + offset; }
void grow(int offset, int len) { /* no action requir
ed with mem mapped file */ }
bool isNull() const { return _base == 0; }
}; };
MemoryMappedFile(); MemoryMappedFile();
~MemoryMappedFile(); /* closes the file if open */ ~MemoryMappedFile() {
destroyed();
close();
}
void close(); void close();
// Throws exception if file doesn't exist. // Throws exception if file doesn't exist. (dm may2010: not sure if this is always true?)
void* map( const char *filename ); void* map( const char *filename );
/*Pointer pmap( const char *filename ) {
void *p = map(filename);
uassert(13077, "couldn't open/map file", p);
return Pointer(p);
}*/
/* Creates with length if DNE, otherwise uses existing file length, /* Creates with length if DNE, otherwise uses existing file length,
passed length. passed length.
*/ */
void* map(const char *filename, long &length, int options = 0 ); void* map(const char *filename, long &length, int options = 0 );
void flush(bool sync); void flush(bool sync);
void* viewOfs() { /*void* viewOfs() {
return view; return view;
} }*/
long length() { long length() {
return len; return len;
} }
static void updateLength( const char *filename, long &length );
static long long totalMappedLength();
static void closeAllFiles( stringstream &message );
static int flushAll( bool sync );
private: private:
void created(); static void updateLength( const char *filename, long &length );
HANDLE fd; HANDLE fd;
HANDLE maphandle; HANDLE maphandle;
void *view; void *view;
long len; long len;
string _filename;
}; };
void printMemInfo( const char * where ); void printMemInfo( const char * where );
#include "ramstore.h"
//#define _RAMSTORE
#if defined(_RAMSTORE)
typedef RamStoreFile MMF;
#else
typedef MemoryMappedFile MMF;
#endif
} // namespace mongo } // namespace mongo
 End of changes. 12 change blocks. 
14 lines changed or deleted 76 lines changed or added


 namespace.h   namespace.h 
skipping to change at line 604 skipping to change at line 605
add_ns( ns, details ); add_ns( ns, details );
} }
void add_ns( const char *ns, const NamespaceDetails &details ) { void add_ns( const char *ns, const NamespaceDetails &details ) {
init(); init();
Namespace n(ns); Namespace n(ns);
uassert( 10081 , "too many namespaces/collections", ht->put(n, details)); uassert( 10081 , "too many namespaces/collections", ht->put(n, details));
} }
/* just for diagnostics */ /* just for diagnostics */
size_t detailsOffset(NamespaceDetails *d) { /*size_t detailsOffset(NamespaceDetails *d) {
if ( !ht ) if ( !ht )
return -1; return -1;
return ((char *) d) - (char *) ht->nodes; return ((char *) d) - (char *) ht->nodes;
} }*/
/* extra space for indexes when more than 10 */ /* extra space for indexes when more than 10 */
NamespaceDetails::Extra* allocExtra(const char *ns) { NamespaceDetails::Extra* allocExtra(const char *ns) {
Namespace n(ns); Namespace n(ns);
Namespace extra(n.extraName().c_str()); // throws userexception if ns name too long Namespace extra(n.extraName().c_str()); // throws userexception if ns name too long
NamespaceDetails *d = details(ns); NamespaceDetails *d = details(ns);
massert( 10350 , "allocExtra: base ns missing?", d ); massert( 10350 , "allocExtra: base ns missing?", d );
assert( d->extraOffset == 0 ); assert( d->extraOffset == 0 );
massert( 10351 , "allocExtra: extra already exists", ht->get(e xtra) == 0 ); massert( 10351 , "allocExtra: extra already exists", ht->get(e xtra) == 0 );
NamespaceDetails::Extra temp; NamespaceDetails::Extra temp;
skipping to change at line 667 skipping to change at line 668
} }
bool allocated() const { bool allocated() const {
return ht != 0; return ht != 0;
} }
private: private:
boost::filesystem::path path() const; boost::filesystem::path path() const;
void maybeMkdir() const; void maybeMkdir() const;
MemoryMappedFile f; MMF f;
HashTable<Namespace,NamespaceDetails> *ht; HashTable<Namespace,NamespaceDetails,MMF::Pointer> *ht;
string dir_; string dir_;
string database_; string database_;
}; };
extern string dbpath; // --dbpath parm extern string dbpath; // --dbpath parm
extern bool directoryperdb; extern bool directoryperdb;
extern string lockfilepath; // --lockfilepath param
// Rename a namespace within current 'client' db. // Rename a namespace within current 'client' db.
// (Arguments should include db name) // (Arguments should include db name)
void renameNamespace( const char *from, const char *to ); void renameNamespace( const char *from, const char *to );
} // namespace mongo } // namespace mongo
 End of changes. 4 change blocks. 
4 lines changed or deleted 5 lines changed or added


 pdfile.h   pdfile.h 
skipping to change at line 37 skipping to change at line 37
#include "../stdafx.h" #include "../stdafx.h"
#include "../util/mmap.h" #include "../util/mmap.h"
#include "diskloc.h" #include "diskloc.h"
#include "jsobjmanipulator.h" #include "jsobjmanipulator.h"
#include "namespace.h" #include "namespace.h"
#include "client.h" #include "client.h"
namespace mongo { namespace mongo {
class MDFHeader; class DataFileHeader;
class Extent; class Extent;
class Record; class Record;
class Cursor; class Cursor;
class OpDebug; class OpDebug;
void dropDatabase(const char *ns); void dropDatabase(const char *ns);
bool repairDatabase(const char *ns, string &errmsg, bool preserveCloned FilesOnFailure = false, bool backupOriginalFiles = false); bool repairDatabase(const char *ns, string &errmsg, bool preserveCloned FilesOnFailure = false, bool backupOriginalFiles = false);
/* low level - only drops this ns */ /* low level - only drops this ns */
void dropNS(const string& dropNs); void dropNS(const string& dropNs);
skipping to change at line 59 skipping to change at line 59
/* deletes this ns, indexes and cursors */ /* deletes this ns, indexes and cursors */
void dropCollection( const string &name, string &errmsg, BSONObjBuilder &result ); void dropCollection( const string &name, string &errmsg, BSONObjBuilder &result );
bool userCreateNS(const char *ns, BSONObj j, string& err, bool logForRe plication); bool userCreateNS(const char *ns, BSONObj j, string& err, bool logForRe plication);
auto_ptr<Cursor> findTableScan(const char *ns, const BSONObj& order, co nst DiskLoc &startLoc=DiskLoc()); auto_ptr<Cursor> findTableScan(const char *ns, const BSONObj& order, co nst DiskLoc &startLoc=DiskLoc());
// -1 if library unavailable. // -1 if library unavailable.
boost::intmax_t freeSpace(); boost::intmax_t freeSpace();
/*--------------------------------------------------------------------- */ /*--------------------------------------------------------------------- */
class MDFHeader;
class MongoDataFile { class MongoDataFile {
friend class DataFileMgr; friend class DataFileMgr;
friend class BasicCursor; friend class BasicCursor;
public: public:
MongoDataFile(int fn) : fileNo(fn) { } MongoDataFile(int fn) : fileNo(fn) { }
void open(const char *filename, int requestedDataSize = 0, bool pre allocateOnly = false); void open(const char *filename, int requestedDataSize = 0, bool pre allocateOnly = false);
/* allocate a new extent from this datafile. /* allocate a new extent from this datafile.
@param capped - true if capped collection @param capped - true if capped collection
@param loops is our recursion check variable - you want to pass in zero @param loops is our recursion check variable - you want to pass in zero
*/ */
Extent* createExtent(const char *ns, int approxSize, bool capped = false, int loops = 0); Extent* createExtent(const char *ns, int approxSize, bool capped = false, int loops = 0);
MDFHeader *getHeader() { DataFileHeader *getHeader() {
return header; return header;
} }
/* return max size an extent may be */ /* return max size an extent may be */
static int maxSize(); static int maxSize();
private: private:
int defaultSize( const char *filename ) const; int defaultSize( const char *filename ) const;
Extent* getExtent(DiskLoc loc); Extent* getExtent(DiskLoc loc);
Extent* _getExtent(DiskLoc loc); Extent* _getExtent(DiskLoc loc);
Record* recordAt(DiskLoc dl); Record* recordAt(DiskLoc dl);
Record* makeRecord(DiskLoc dl, int size);
void grow(DiskLoc dl, int size);
MemoryMappedFile mmf; MMF mmf;
MDFHeader *header; MMF::Pointer _p;
DataFileHeader *header;
int fileNo; int fileNo;
}; };
class DataFileMgr { class DataFileMgr {
friend class BasicCursor; friend class BasicCursor;
public: public:
void init(const string& path ); void init(const string& path );
/* see if we can find an extent of the right size in the freelist. */ /* see if we can find an extent of the right size in the freelist. */
static Extent* allocFromFreeList(const char *ns, int approxSize, bo ol capped = false); static Extent* allocFromFreeList(const char *ns, int approxSize, bo ol capped = false);
skipping to change at line 122 skipping to change at line 124
static auto_ptr<Cursor> findAll(const char *ns, const DiskLoc &star tLoc = DiskLoc()); static auto_ptr<Cursor> findAll(const char *ns, const DiskLoc &star tLoc = DiskLoc());
/* special version of insert for transaction logging -- streamlined a bit. /* special version of insert for transaction logging -- streamlined a bit.
assumes ns is capped and no indexes assumes ns is capped and no indexes
no _id field check no _id field check
*/ */
Record* fast_oplog_insert(NamespaceDetails *d, const char *ns, int len); Record* fast_oplog_insert(NamespaceDetails *d, const char *ns, int len);
static Extent* getExtent(const DiskLoc& dl); static Extent* getExtent(const DiskLoc& dl);
static Record* getRecord(const DiskLoc& dl); static Record* getRecord(const DiskLoc& dl);
static DeletedRecord* makeDeletedRecord(const DiskLoc& dl, int len)
;
static void grow(const DiskLoc& dl, int len);
/* does not clean up indexes, etc. : just deletes the record in the pdfile. */ /* does not clean up indexes, etc. : just deletes the record in the pdfile. */
void _deleteRecord(NamespaceDetails *d, const char *ns, Record *tod elete, const DiskLoc& dl); void _deleteRecord(NamespaceDetails *d, const char *ns, Record *tod elete, const DiskLoc& dl);
private: private:
vector<MongoDataFile *> files; vector<MongoDataFile *> files;
}; };
extern DataFileMgr theDataFileMgr; extern DataFileMgr theDataFileMgr;
skipping to change at line 200 skipping to change at line 204
DiskLoc myLoc; DiskLoc myLoc;
DiskLoc xnext, xprev; /* next/prev extent for this namespace */ DiskLoc xnext, xprev; /* next/prev extent for this namespace */
/* which namespace this extent is for. this is just for troublesho oting really /* which namespace this extent is for. this is just for troublesho oting really
and won't even be correct if the collection were renamed! and won't even be correct if the collection were renamed!
*/ */
Namespace nsDiagnostic; Namespace nsDiagnostic;
int length; /* size of the extent, including these fields */ int length; /* size of the extent, including these fields */
DiskLoc firstRecord, lastRecord; DiskLoc firstRecord, lastRecord;
char extentData[4]; char _extentData[4];
static int HeaderSize() { return sizeof(Extent)-4; }
bool validates() { bool validates() {
return !(firstRecord.isNull() ^ lastRecord.isNull()) && return !(firstRecord.isNull() ^ lastRecord.isNull()) &&
length >= 0 && !myLoc.isNull(); length >= 0 && !myLoc.isNull();
} }
void dump(iostream& s) { void dump(iostream& s) {
s << " loc:" << myLoc.toString() << " xnext:" << xnext.toStr ing() << " xprev:" << xprev.toString() << '\n'; s << " loc:" << myLoc.toString() << " xnext:" << xnext.toStr ing() << " xprev:" << xprev.toString() << '\n';
s << " nsdiag:" << nsDiagnostic.buf << '\n'; s << " nsdiag:" << nsDiagnostic.buf << '\n';
s << " size:" << length << " firstRecord:" << firstRecord.to String() << " lastRecord:" << lastRecord.toString() << '\n'; s << " size:" << length << " firstRecord:" << firstRecord.to String() << " lastRecord:" << lastRecord.toString() << '\n';
skipping to change at line 257 skipping to change at line 263
---------------------- ----------------------
Extent (for a particular namespace) Extent (for a particular namespace)
Record Record
... ...
Record (some chained for unused space) Record (some chained for unused space)
---------------------- ----------------------
more Extents... more Extents...
---------------------- ----------------------
*/ */
/* data file header */ class DataFileHeader {
class MDFHeader {
public: public:
int version; int version;
int versionMinor; int versionMinor;
int fileLength; int fileLength;
DiskLoc unused; /* unused is the portion of the file that doesn't b elong to any allocated extents. -1 = no more */ DiskLoc unused; /* unused is the portion of the file that doesn't b elong to any allocated extents. -1 = no more */
int unusedLength; int unusedLength;
char reserved[8192 - 4*4 - 8]; char reserved[8192 - 4*4 - 8];
char data[4]; char data[4];
static int headerSize() { enum { HeaderSize = 8192 };
return sizeof(MDFHeader) - 4;
}
bool currentVersion() const { bool currentVersion() const {
return ( version == VERSION ) && ( versionMinor == VERSION_MINO R ); return ( version == VERSION ) && ( versionMinor == VERSION_MINO R );
} }
bool uninitialized() const { bool uninitialized() const {
if ( version == 0 ) return true; if ( version == 0 ) return true;
return false; return false;
} }
Record* getRecord(DiskLoc dl) { /*Record* __getRecord(DiskLoc dl) {
int ofs = dl.getOfs(); int ofs = dl.getOfs();
assert( ofs >= headerSize() ); assert( ofs >= HeaderSize );
return (Record*) (((char *) this) + ofs); return (Record*) (((char *) this) + ofs);
} }*/
void init(int fileno, int filelength) { void init(int fileno, int filelength) {
if ( uninitialized() ) { if ( uninitialized() ) {
assert(filelength > 32768 ); assert(filelength > 32768 );
assert( headerSize() == 8192 ); assert( HeaderSize == 8192 );
fileLength = filelength; fileLength = filelength;
version = VERSION; version = VERSION;
versionMinor = VERSION_MINOR; versionMinor = VERSION_MINOR;
unused.setOfs( fileno, headerSize() ); unused.setOfs( fileno, HeaderSize );
assert( (data-(char*)this) == headerSize() ); assert( (data-(char*)this) == HeaderSize );
unusedLength = fileLength - headerSize() - 16; unusedLength = fileLength - HeaderSize - 16;
memcpy(data+unusedLength, " \nthe end\n", 16); //memcpy(data+unusedLength, " \nthe end\n", 16);
} }
} }
bool isEmpty() const { bool isEmpty() const {
return uninitialized() || ( unusedLength == fileLength - header Size() - 16 ); return uninitialized() || ( unusedLength == fileLength - Header Size - 16 );
} }
}; };
#pragma pack() #pragma pack()
inline Extent* MongoDataFile::_getExtent(DiskLoc loc) { inline Extent* MongoDataFile::_getExtent(DiskLoc loc) {
loc.assertOk(); loc.assertOk();
Extent *e = (Extent *) (((char *)header) + loc.getOfs()); Extent *e = (Extent *) _p.at(loc.getOfs(), Extent::HeaderSize());
return e; return e;
} }
inline Extent* MongoDataFile::getExtent(DiskLoc loc) { inline Extent* MongoDataFile::getExtent(DiskLoc loc) {
Extent *e = _getExtent(loc); Extent *e = _getExtent(loc);
e->assertOk(); e->assertOk();
return e; return e;
} }
} // namespace mongo } // namespace mongo
#include "cursor.h" #include "cursor.h"
namespace mongo { namespace mongo {
inline Record* MongoDataFile::recordAt(DiskLoc dl) { inline Record* MongoDataFile::recordAt(DiskLoc dl) {
return header->getRecord(dl); int ofs = dl.getOfs();
assert( ofs >= DataFileHeader::HeaderSize );
return (Record*) _p.at(ofs, -1);
}
inline void MongoDataFile::grow(DiskLoc dl, int size) {
int ofs = dl.getOfs();
_p.grow(ofs, size);
}
inline Record* MongoDataFile::makeRecord(DiskLoc dl, int size) {
int ofs = dl.getOfs();
assert( ofs >= DataFileHeader::HeaderSize );
return (Record*) _p.at(ofs, size);
} }
inline DiskLoc Record::getNext(const DiskLoc& myLoc) { inline DiskLoc Record::getNext(const DiskLoc& myLoc) {
if ( nextOfs != DiskLoc::NullOfs ) { if ( nextOfs != DiskLoc::NullOfs ) {
/* defensive */ /* defensive */
if ( nextOfs >= 0 && nextOfs < 10 ) { if ( nextOfs >= 0 && nextOfs < 10 ) {
sayDbContext("Assertion failure - Record::getNext() referen cing a deleted record?"); sayDbContext("Assertion failure - Record::getNext() referen cing a deleted record?");
return DiskLoc(); return DiskLoc();
} }
skipping to change at line 450 skipping to change at line 466
inline Extent* DataFileMgr::getExtent(const DiskLoc& dl) { inline Extent* DataFileMgr::getExtent(const DiskLoc& dl) {
assert( dl.a() != -1 ); assert( dl.a() != -1 );
return cc().database()->getFile(dl.a())->getExtent(dl); return cc().database()->getFile(dl.a())->getExtent(dl);
} }
inline Record* DataFileMgr::getRecord(const DiskLoc& dl) { inline Record* DataFileMgr::getRecord(const DiskLoc& dl) {
assert( dl.a() != -1 ); assert( dl.a() != -1 );
return cc().database()->getFile(dl.a())->recordAt(dl); return cc().database()->getFile(dl.a())->recordAt(dl);
} }
BOOST_STATIC_ASSERT( 16 == sizeof(DeletedRecord) );
inline void DataFileMgr::grow(const DiskLoc& dl, int len) {
assert( dl.a() != -1 );
cc().database()->getFile(dl.a())->grow(dl, len);
}
inline DeletedRecord* DataFileMgr::makeDeletedRecord(const DiskLoc& dl,
int len) {
assert( dl.a() != -1 );
return (DeletedRecord*) cc().database()->getFile(dl.a())->makeRecor
d(dl, sizeof(DeletedRecord));
}
void ensureHaveIdIndex(const char *ns); void ensureHaveIdIndex(const char *ns);
bool dropIndexes( NamespaceDetails *d, const char *ns, const char *name , string &errmsg, BSONObjBuilder &anObjBuilder, bool maydeleteIdIndex ); bool dropIndexes( NamespaceDetails *d, const char *ns, const char *name , string &errmsg, BSONObjBuilder &anObjBuilder, bool maydeleteIdIndex );
} // namespace mongo } // namespace mongo
 End of changes. 18 change blocks. 
22 lines changed or deleted 53 lines changed or added


 query.h   query.h 
skipping to change at line 77 skipping to change at line 77
*/ */
// struct QueryOptions, QueryResult, QueryResultFlags in: // struct QueryOptions, QueryResult, QueryResultFlags in:
#include "../client/dbclient.h" #include "../client/dbclient.h"
namespace mongo { namespace mongo {
extern const int MaxBytesToReturnToClientAtOnce; extern const int MaxBytesToReturnToClientAtOnce;
// for an existing query (ie a ClientCursor), send back additional info rmation. // for an existing query (ie a ClientCursor), send back additional info rmation.
QueryResult* getMore(const char *ns, int ntoreturn, long long cursorid struct GetMoreWaitException { };
, CurOp& op);
QueryResult* processGetMore(const char *ns, int ntoreturn, long long cu
rsorid , CurOp& op, int pass );
struct UpdateResult { struct UpdateResult {
bool existing; bool existing;
bool mod; bool mod;
long long num; long long num;
UpdateResult( bool e, bool m, unsigned long long n ) UpdateResult( bool e, bool m, unsigned long long n )
: existing(e) , mod(m), num(n ){} : existing(e) , mod(m), num(n ){}
int oldCode(){ int oldCode(){
 End of changes. 1 change blocks. 
2 lines changed or deleted 4 lines changed or added


 queryoptimizer.h   queryoptimizer.h 
skipping to change at line 120 skipping to change at line 120
bool complete_; bool complete_;
string exceptionMessage_; string exceptionMessage_;
const QueryPlan *qp_; const QueryPlan *qp_;
bool error_; bool error_;
}; };
// Set of candidate query plans for a particular query. Used for runni ng // Set of candidate query plans for a particular query. Used for runni ng
// a QueryOp on these plans. // a QueryOp on these plans.
class QueryPlanSet { class QueryPlanSet {
public: public:
typedef boost::shared_ptr< QueryPlan > PlanPtr;
typedef vector< PlanPtr > PlanSet;
QueryPlanSet( const char *ns, QueryPlanSet( const char *ns,
const BSONObj &query, const BSONObj &query,
const BSONObj &order, const BSONObj &order,
const BSONElement *hint = 0, const BSONElement *hint = 0,
bool honorRecordedPlan = true, bool honorRecordedPlan = true,
const BSONObj &min = BSONObj(), const BSONObj &min = BSONObj(),
const BSONObj &max = BSONObj() ); const BSONObj &max = BSONObj() );
int nPlans() const { return plans_.size(); } int nPlans() const { return plans_.size(); }
shared_ptr< QueryOp > runOp( QueryOp &op ); shared_ptr< QueryOp > runOp( QueryOp &op );
template< class T > template< class T >
shared_ptr< T > runOp( T &op ) { shared_ptr< T > runOp( T &op ) {
return dynamic_pointer_cast< T >( runOp( static_cast< QueryOp& >( op ) ) ); return dynamic_pointer_cast< T >( runOp( static_cast< QueryOp& >( op ) ) );
} }
const FieldRangeSet &fbs() const { return fbs_; } const FieldRangeSet &fbs() const { return fbs_; }
BSONObj explain() const; BSONObj explain() const;
bool usingPrerecordedPlan() const { return usingPrerecordedPlan_; } bool usingPrerecordedPlan() const { return usingPrerecordedPlan_; }
PlanPtr getBestGuess() const;
private: private:
void addOtherPlans( bool checkFirst ); void addOtherPlans( bool checkFirst );
typedef boost::shared_ptr< QueryPlan > PlanPtr;
typedef vector< PlanPtr > PlanSet;
void addPlan( PlanPtr plan, bool checkFirst ) { void addPlan( PlanPtr plan, bool checkFirst ) {
if ( checkFirst && plan->indexKey().woCompare( plans_[ 0 ]->ind exKey() ) == 0 ) if ( checkFirst && plan->indexKey().woCompare( plans_[ 0 ]->ind exKey() ) == 0 )
return; return;
plans_.push_back( plan ); plans_.push_back( plan );
} }
void init(); void init();
void addHint( IndexDetails &id ); void addHint( IndexDetails &id );
struct Runner { struct Runner {
Runner( QueryPlanSet &plans, QueryOp &op ); Runner( QueryPlanSet &plans, QueryOp &op );
shared_ptr< QueryOp > run(); shared_ptr< QueryOp > run();
 End of changes. 3 change blocks. 
2 lines changed or deleted 5 lines changed or added


 repl.h   repl.h 
skipping to change at line 68 skipping to change at line 68
bool master; bool master;
int opIdMem; int opIdMem;
bool fastsync; bool fastsync;
bool autoresync; bool autoresync;
int slavedelay; int slavedelay;
bool pretouch;
ReplSettings() ReplSettings()
: slave(NotSlave) , master(false) , opIdMem(100000000) , fastsy nc() , autoresync(false), slavedelay(), pretouch(false) { : slave(NotSlave) , master(false) , opIdMem(100000000) , fastsy nc() , autoresync(false), slavedelay() {
} }
}; };
extern ReplSettings replSettings; extern ReplSettings replSettings;
bool cloneFrom(const char *masterHost, string& errmsg, const string& fr omdb, bool logForReplication, bool cloneFrom(const char *masterHost, string& errmsg, const string& fr omdb, bool logForReplication,
bool slaveOk, bool useReplAuth, bool snap shot); bool slaveOk, bool useReplAuth, bool snap shot);
/* A replication exception */ /* A replication exception */
skipping to change at line 102 skipping to change at line 100
{ host: ..., source: ..., only: ..., syncedTo: ..., localLogTs: . .., dbsNextPass: { ... }, incompleteCloneDbs: { ... } } { host: ..., source: ..., only: ..., syncedTo: ..., localLogTs: . .., dbsNextPass: { ... }, incompleteCloneDbs: { ... } }
'source' defaults to 'main'; support for multiple source names is 'source' defaults to 'main'; support for multiple source names is
not done (always use main for now). not done (always use main for now).
*/ */
class ReplSource { class ReplSource {
bool resync(string db); bool resync(string db);
/* pull some operations from the master's oplog, and apply them. */ /* pull some operations from the master's oplog, and apply them. */
bool sync_pullOpLog(int& nApplied); int sync_pullOpLog(int& nApplied);
void sync_pullOpLog_applyOperation(BSONObj& op, OpTime *localLogTai l); void sync_pullOpLog_applyOperation(BSONObj& op, OpTime *localLogTai l);
auto_ptr<DBClientConnection> conn; auto_ptr<DBClientConnection> conn;
auto_ptr<DBClientCursor> cursor; auto_ptr<DBClientCursor> cursor;
/* we only clone one database per pass, even if a lot need done. T his helps us /* we only clone one database per pass, even if a lot need done. T his helps us
avoid overflowing the master's transaction log by doing too much work before going avoid overflowing the master's transaction log by doing too much work before going
back to read more transactions. (Imagine a scenario of slave sta rtup where we try to back to read more transactions. (Imagine a scenario of slave sta rtup where we try to
clone 100 databases in one pass.) clone 100 databases in one pass.)
skipping to change at line 135 skipping to change at line 133
static BSONObj idForOp( const BSONObj &op, bool &mod ); static BSONObj idForOp( const BSONObj &op, bool &mod );
static void updateSetsWithOp( const BSONObj &op, bool mayUpdateStor age ); static void updateSetsWithOp( const BSONObj &op, bool mayUpdateStor age );
// call without the db mutex // call without the db mutex
void syncToTailOfRemoteLog(); void syncToTailOfRemoteLog();
// call with the db mutex // call with the db mutex
OpTime nextLastSavedLocalTs() const; OpTime nextLastSavedLocalTs() const;
void setLastSavedLocalTs( const OpTime &nextLocalTs ); void setLastSavedLocalTs( const OpTime &nextLocalTs );
// call without the db mutex // call without the db mutex
void resetSlave(); void resetSlave();
// call with the db mutex // call with the db mutex
int updateSetsWithLocalOps( OpTime &localLogTail, bool mayUnlock ); // returns false if the slave has been reset
bool updateSetsWithLocalOps( OpTime &localLogTail, bool mayUnlock )
;
string ns() const { return string( "local.oplog.$" ) + sourceName() ; } string ns() const { return string( "local.oplog.$" ) + sourceName() ; }
unsigned _sleepAdviceTime; unsigned _sleepAdviceTime;
public: public:
static void applyOperation(const BSONObj& op); static void applyOperation(const BSONObj& op);
bool replacing; // in "replace mode" -- see CmdReplacePeer bool replacing; // in "replace mode" -- see CmdReplacePeer
bool paired; // --pair in use bool paired; // --pair in use
string hostName; // ip addr or hostname plus optionally, ":<port >" string hostName; // ip addr or hostname plus optionally, ":<port >"
string _sourceName; // a logical source name. string _sourceName; // a logical source name.
string sourceName() const { string sourceName() const {
skipping to change at line 166 skipping to change at line 165
has ABCXY, then _lastSavedLocalTs won't be greater than C until we have reconciled has ABCXY, then _lastSavedLocalTs won't be greater than C until we have reconciled
the DE-XY difference.) the DE-XY difference.)
*/ */
OpTime _lastSavedLocalTs; OpTime _lastSavedLocalTs;
int nClonedThisPass; int nClonedThisPass;
typedef vector< shared_ptr< ReplSource > > SourceVector; typedef vector< shared_ptr< ReplSource > > SourceVector;
static void loadAll(SourceVector&); static void loadAll(SourceVector&);
explicit ReplSource(BSONObj); explicit ReplSource(BSONObj);
bool sync(int& nApplied);
/* -1 = error */
int sync(int& nApplied);
void save(); // write ourself to local.sources void save(); // write ourself to local.sources
void resetConnection() { void resetConnection() {
cursor = auto_ptr<DBClientCursor>(0); cursor = auto_ptr<DBClientCursor>(0);
conn = auto_ptr<DBClientConnection>(0); conn = auto_ptr<DBClientConnection>(0);
} }
// make a jsobj from our member fields of the form // make a jsobj from our member fields of the form
// { host: ..., source: ..., syncedTo: ... } // { host: ..., source: ..., syncedTo: ... }
BSONObj jsobj(); BSONObj jsobj();
skipping to change at line 209 skipping to change at line 211
"c" db cmd "c" db cmd
"db" declares presence of a database (ns is set to the db name + '.' ) "db" declares presence of a database (ns is set to the db name + '.' )
*/ */
void logOp(const char *opstr, const char *ns, const BSONObj& obj, BSONO bj *patt = 0, bool *b = 0); void logOp(const char *opstr, const char *ns, const BSONObj& obj, BSONO bj *patt = 0, bool *b = 0);
// class for managing a set of ids in memory // class for managing a set of ids in memory
class MemIds { class MemIds {
public: public:
MemIds() : size_() {} MemIds() : size_() {}
friend class IdTracker; friend class IdTracker;
void reset() { void reset() { imp_.clear(); }
imp_.clear();
size_ = 0;
}
bool get( const char *ns, const BSONObj &id ) { return imp_[ ns ].c ount( id ); } bool get( const char *ns, const BSONObj &id ) { return imp_[ ns ].c ount( id ); }
void set( const char *ns, const BSONObj &id, bool val ) { void set( const char *ns, const BSONObj &id, bool val ) {
if ( val ) { if ( val ) {
if ( imp_[ ns ].insert( id.getOwned() ).second ) { if ( imp_[ ns ].insert( id.getOwned() ).second ) {
size_ += id.objsize() + sizeof( BSONObj ); size_ += id.objsize() + sizeof( BSONObj );
} }
} else { } else {
if ( imp_[ ns ].erase( id ) == 1 ) { if ( imp_[ ns ].erase( id ) == 1 ) {
size_ -= id.objsize() + sizeof( BSONObj ); size_ -= id.objsize() + sizeof( BSONObj );
} }
skipping to change at line 431 skipping to change at line 430
enum FindingStartMode { Initial, FindExtent, InExtent }; enum FindingStartMode { Initial, FindExtent, InExtent };
const QueryPlan &_qp; const QueryPlan &_qp;
bool _findingStart; bool _findingStart;
FindingStartMode _findingStartMode; FindingStartMode _findingStartMode;
auto_ptr< CoveredIndexMatcher > _matcher; auto_ptr< CoveredIndexMatcher > _matcher;
Timer _findingStartTimer; Timer _findingStartTimer;
ClientCursor * _findingStartCursor; ClientCursor * _findingStartCursor;
auto_ptr< Cursor > _c; auto_ptr< Cursor > _c;
DiskLoc startLoc( const DiskLoc &rec ) { DiskLoc startLoc( const DiskLoc &rec ) {
Extent *e = rec.rec()->myExtent( rec ); Extent *e = rec.rec()->myExtent( rec );
if ( !_qp.nsd()->capLooped() || ( e->myLoc != _qp.nsd()->capExt ent ) ) if ( e->myLoc != _qp.nsd()->capExtent )
return e->firstRecord; return e->firstRecord;
// Likely we are on the fresh side of capExtent, so return firs t fresh record. // Likely we are on the fresh side of capExtent, so return firs t fresh record.
// If we are on the stale side of capExtent, then the collectio n is small and it // If we are on the stale side of capExtent, then the collectio n is small and it
// doesn't matter if we start the extent scan with capFirstNewR ecord. // doesn't matter if we start the extent scan with capFirstNewR ecord.
return _qp.nsd()->capFirstNewRecord; return _qp.nsd()->capFirstNewRecord;
} }
// should never have an empty extent in the oplog, so don't worry a bout that case
DiskLoc prevLoc( const DiskLoc &rec ) { DiskLoc prevLoc( const DiskLoc &rec ) {
Extent *e = rec.rec()->myExtent( rec ); Extent *e = rec.rec()->myExtent( rec );
if ( _qp.nsd()->capLooped() ) { if ( e->xprev.isNull() )
if ( e->xprev.isNull() ) e = _qp.nsd()->lastExtent.ext();
e = _qp.nsd()->lastExtent.ext(); else
else e = e->xprev.ext();
e = e->xprev.ext(); if ( e->myLoc != _qp.nsd()->capExtent )
if ( e->myLoc != _qp.nsd()->capExtent ) return e->firstRecord;
return e->firstRecord;
} else {
if ( !e->xprev.isNull() ) {
e = e->xprev.ext();
return e->firstRecord;
}
}
return DiskLoc(); // reached beginning of collection return DiskLoc(); // reached beginning of collection
} }
void createClientCursor( const DiskLoc &startLoc = DiskLoc() ) { void createClientCursor( const DiskLoc &startLoc = DiskLoc() ) {
auto_ptr<Cursor> c = _qp.newCursor( startLoc ); auto_ptr<Cursor> c = _qp.newCursor( startLoc );
_findingStartCursor = new ClientCursor(c, _qp.ns(), false); _findingStartCursor = new ClientCursor(QueryOption_NoCursorTime out, c, _qp.ns());
} }
void destroyClientCursor() { void destroyClientCursor() {
if ( _findingStartCursor ) { if ( _findingStartCursor ) {
ClientCursor::erase( _findingStartCursor->cursorid ); ClientCursor::erase( _findingStartCursor->cursorid );
_findingStartCursor = 0; _findingStartCursor = 0;
} }
} }
void maybeRelease() { void maybeRelease() {
RARELY { RARELY {
CursorId id = _findingStartCursor->cursorid; CursorId id = _findingStartCursor->cursorid;
skipping to change at line 481 skipping to change at line 472
{ {
dbtemprelease t; dbtemprelease t;
} }
_findingStartCursor = ClientCursor::find( id, false ); _findingStartCursor = ClientCursor::find( id, false );
} }
} }
void init() { void init() {
// Use a ClientCursor here so we can release db mutex while sca nning // Use a ClientCursor here so we can release db mutex while sca nning
// oplog (can take quite a while with large oplogs). // oplog (can take quite a while with large oplogs).
auto_ptr<Cursor> c = _qp.newReverseCursor(); auto_ptr<Cursor> c = _qp.newReverseCursor();
_findingStartCursor = new ClientCursor(c, _qp.ns(), false); _findingStartCursor = new ClientCursor(QueryOption_NoCursorTime out, c, _qp.ns());
_findingStartTimer.reset(); _findingStartTimer.reset();
_findingStartMode = Initial; _findingStartMode = Initial;
BSONElement tsElt = _qp.query()[ "ts" ]; BSONElement tsElt = _qp.query()[ "ts" ];
massert( 13044, "no ts field in query", !tsElt.eoo() ); massert( 13044, "no ts field in query", !tsElt.eoo() );
BSONObjBuilder b; BSONObjBuilder b;
b.append( tsElt ); b.append( tsElt );
BSONObj tsQuery = b.obj(); BSONObj tsQuery = b.obj();
_matcher.reset(new CoveredIndexMatcher(tsQuery, _qp.indexKey()) ); _matcher.reset(new CoveredIndexMatcher(tsQuery, _qp.indexKey()) );
} }
}; };
void updateSlaveLocation( CurOp& curop, const char * ns , OpTime lastOp
);
bool opReplicatedEnough( OpTime op , int w );
} // namespace mongo } // namespace mongo
 End of changes. 12 change blocks. 
27 lines changed or deleted 23 lines changed or added


 replset.h   replset.h 
skipping to change at line 194 skipping to change at line 194
} }
bool initialSyncCompleted() { bool initialSyncCompleted() {
return initialsynccomplete != 0; return initialsynccomplete != 0;
} }
void setInitialSyncCompleted() { void setInitialSyncCompleted() {
BSONObj o = fromjson("{\"initialsynccomplete\":1}"); BSONObj o = fromjson("{\"initialsynccomplete\":1}");
Helpers::putSingleton("local.pair.sync", o); Helpers::putSingleton("local.pair.sync", o);
initialsynccomplete = 1; initialsynccomplete = 1;
log() << "pair: initial sync complete" << endl;
} }
void setInitialSyncCompletedLocking() { void setInitialSyncCompletedLocking() {
if ( initialsynccomplete == 1 ) if ( initialsynccomplete == 1 )
return; return;
dblock lk; dblock lk;
BSONObj o = fromjson("{\"initialsynccomplete\":1}"); setInitialSyncCompleted();
Helpers::putSingleton("local.pair.sync", o);
initialsynccomplete = 1;
} }
}; };
} // namespace mongo } // namespace mongo
 End of changes. 2 change blocks. 
3 lines changed or deleted 2 lines changed or added


 scanandorder.h   scanandorder.h 
skipping to change at line 110 skipping to change at line 110
startFrom(_startFrom), order(_order) { startFrom(_startFrom), order(_order) {
limit = _limit > 0 ? _limit + startFrom : 0x7fffffff; limit = _limit > 0 ? _limit + startFrom : 0x7fffffff;
approxSize = 0; approxSize = 0;
} }
int size() const { int size() const {
return best.size(); return best.size();
} }
void add(BSONObj o) { void add(BSONObj o) {
assert( o.isValid() );
BSONObj k = order.getKeyFromObject(o); BSONObj k = order.getKeyFromObject(o);
if ( (int) best.size() < limit ) { if ( (int) best.size() < limit ) {
approxSize += k.objsize(); approxSize += k.objsize();
uassert( 10128 , "too much key data for sort() with no ind ex. add an index or specify a smaller limit", approxSize < 1 * 1024 * 1024 ); uassert( 10128 , "too much key data for sort() with no ind ex. add an index or specify a smaller limit", approxSize < 1 * 1024 * 1024 );
_add(k, o); _add(k, o);
return; return;
} }
BestMap::iterator i; BestMap::iterator i;
assert( best.end() != best.begin() ); assert( best.end() != best.begin() );
i = best.end(); i = best.end();
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 sock.h   sock.h 
skipping to change at line 25 skipping to change at line 25
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "../stdafx.h" #include "../stdafx.h"
#include <stdio.h> #include <stdio.h>
#include <sstream> #include <sstream>
#include "goodies.h" #include "goodies.h"
#include "../db/jsobj.h"
#ifdef _WIN32 #define SOCK_FAMILY_UNKNOWN_ERROR 13078
#include <windows.h>
#include <winsock.h>
#endif
namespace mongo { namespace mongo {
#if defined(_WIN32) #if defined(_WIN32)
typedef short sa_family_t;
typedef int socklen_t; typedef int socklen_t;
inline int getLastError() { inline int getLastError() {
return WSAGetLastError(); return WSAGetLastError();
} }
inline const char* gai_strerror(int code) {
return ::gai_strerrorA(code);
}
inline void disableNagle(int sock) { inline void disableNagle(int sock) {
int x = 1; int x = 1;
if ( setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &x, sizeof (x)) ) if ( setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &x, sizeof (x)) )
out() << "ERROR: disableNagle failed" << endl; out() << "ERROR: disableNagle failed" << endl;
} }
inline void prebindOptions( int sock ) { inline void prebindOptions( int sock ) {
} }
// This won't actually be used on windows
struct sockaddr_un {
short sun_family;
char sun_path[108]; // length from unix header
};
#else #else
} // namespace mongo } // namespace mongo
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h> #include <errno.h>
#include <netdb.h> #include <netdb.h>
namespace mongo { namespace mongo {
inline void closesocket(int s) { inline void closesocket(int s) {
close(s); close(s);
skipping to change at line 89 skipping to change at line 99
} }
inline void prebindOptions( int sock ) { inline void prebindOptions( int sock ) {
DEV log() << "doing prebind option" << endl; DEV log() << "doing prebind option" << endl;
int x = 1; int x = 1;
if ( setsockopt( sock , SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)) < 0 ) if ( setsockopt( sock , SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)) < 0 )
out() << "Failed to set socket opt, SO_REUSEADDR" << endl; out() << "Failed to set socket opt, SO_REUSEADDR" << endl;
} }
#endif #endif
inline void setSockReceiveTimeout(int sock, int secs) { inline string makeUnixSockPath(int port){
// todo - finish - works? return "/tmp/mongodb-" + BSONObjBuilder::numStr(port) + ".sock";
}
inline void setSockTimeouts(int sock, int secs) {
struct timeval tv; struct timeval tv;
tv.tv_sec = 0;//secs; tv.tv_sec = secs;
tv.tv_usec = 1000; tv.tv_usec = 0;
int rc = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, si massert( 13083, "unable to set SO_RCVTIMEO",
zeof(tv)); setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, siz
if ( rc ) { eof(tv) ) == 0 );
out() << "ERROR: setsockopt RCVTIMEO failed rc:" << rc << " " < massert( 13084, "unable to set SO_SNDTIMEO",
< OUTPUT_ERRNO << " secs:" << secs << " sock:" << sock << endl; setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &tv, siz
} eof(tv) ) == 0 );
} }
// If an ip address is passed in, just return that. If a hostname is p assed // If an ip address is passed in, just return that. If a hostname is p assed
// in, look up its ip and return that. Returns "" on failure. // in, look up its ip and return that. Returns "" on failure.
string hostbyname(const char *hostname); string hostbyname(const char *hostname);
void enableIPv6(bool state=true);
bool IPv6Enabled();
struct SockAddr { struct SockAddr {
SockAddr() { SockAddr() {
addressSize = sizeof(sockaddr_in); addressSize = sizeof(sa);
memset(&sa, 0, sizeof(sa)); memset(&sa, 0, sizeof(sa));
sa.ss_family = AF_UNSPEC;
} }
SockAddr(int sourcePort); /* listener side */ SockAddr(int sourcePort); /* listener side */
SockAddr(const char *ip, int port); /* EndPoint (remote) side, or i f you want to specify which interface locally */ SockAddr(const char *ip, int port); /* EndPoint (remote) side, or i f you want to specify which interface locally */
struct sockaddr_in sa; template <typename T>
socklen_t addressSize; T& as() { return *(T*)(&sa); }
template <typename T>
bool isLocalHost() const { const T& as() const { return *(const T*)(&sa); }
#if defined(_WIN32)
return sa.sin_addr.S_un.S_addr == 0x100007f;
#else
return sa.sin_addr.s_addr == 0x100007f;
#endif
}
string toString() const{ string toString(bool includePort=true) const{
stringstream out; string out = getAddr();
out << inet_ntoa(sa.sin_addr) << ':' if (includePort && getType() != AF_UNIX && getType() != AF_UNSP
<< ntohs(sa.sin_port); EC)
return out.str(); out += ':' + BSONObjBuilder::numStr(getPort());
return out;
} }
operator string() const{ operator string() const{
return toString(); return toString();
} }
unsigned getPort() { // returns one of AF_INET, AF_INET6, or AF_UNIX
return sa.sin_port; sa_family_t getType() const {
return sa.ss_family;
} }
bool localhost() const { return inet_addr( "127.0.0.1" ) == sa.sin_ unsigned getPort() const {
addr.s_addr; } switch (getType()){
case AF_INET: return ntohs(as<sockaddr_in>().sin_port);
case AF_INET6: return ntohs(as<sockaddr_in6>().sin6_port);
case AF_UNIX: return 0;
case AF_UNSPEC: return 0;
default: massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported ad
dress family", false); return 0;
}
}
string getAddr() const {
switch (getType()){
case AF_INET:
case AF_INET6: {
const int buflen=128;
char buffer[buflen];
int ret = getnameinfo(raw(), addressSize, buffer, bufle
n, NULL, 0, NI_NUMERICHOST);
massert(13082, gai_strerror(ret), ret == 0);
return buffer;
}
case AF_UNIX: return (addressSize > 2 ? as<sockaddr_un>().
sun_path : "anonymous unix socket");
case AF_UNSPEC: return "(NONE)";
default: massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported ad
dress family", false); return "";
}
}
bool isLocalHost() const;
bool operator==(const SockAddr& r) const { bool operator==(const SockAddr& r) const {
return sa.sin_addr.s_addr == r.sa.sin_addr.s_addr && if (getType() != r.getType())
sa.sin_port == r.sa.sin_port; return false;
if (getPort() != r.getPort())
return false;
switch (getType()){
case AF_INET: return as<sockaddr_in>().sin_addr.s_addr ==
r.as<sockaddr_in>().sin_addr.s_addr;
case AF_INET6: return memcmp(as<sockaddr_in6>().sin6_addr.s
6_addr, r.as<sockaddr_in6>().sin6_addr.s6_addr, sizeof(in6_addr)) == 0;
case AF_UNIX: return strcmp(as<sockaddr_un>().sun_path, r.
as<sockaddr_un>().sun_path) == 0;
case AF_UNSPEC: return true; // assume all unspecified addr
esses are the same
default: massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported ad
dress family", false);
}
} }
bool operator!=(const SockAddr& r) const { bool operator!=(const SockAddr& r) const {
return !(*this == r); return !(*this == r);
} }
bool operator<(const SockAddr& r) const { bool operator<(const SockAddr& r) const {
if ( sa.sin_port >= r.sa.sin_port ) if (getType() < r.getType())
return true;
else if (getType() > r.getType())
return false; return false;
return sa.sin_addr.s_addr < r.sa.sin_addr.s_addr;
}
};
const int MaxMTU = 16384; if (getPort() < r.getPort())
return true;
else if (getPort() > r.getPort())
return false;
class UDPConnection { switch (getType()){
public: case AF_INET: return as<sockaddr_in>().sin_addr.s_addr < r
UDPConnection() { .as<sockaddr_in>().sin_addr.s_addr;
sock = 0; case AF_INET6: return memcmp(as<sockaddr_in6>().sin6_addr.s
} 6_addr, r.as<sockaddr_in6>().sin6_addr.s6_addr, sizeof(in6_addr)) < 0;
~UDPConnection() { case AF_UNIX: return strcmp(as<sockaddr_un>().sun_path, r.
if ( sock ) { as<sockaddr_un>().sun_path) < 0;
closesocket(sock); case AF_UNSPEC: return false;
sock = 0; default: massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported ad
dress family", false);
} }
} }
bool init(const SockAddr& myAddr);
int recvfrom(char *buf, int len, SockAddr& sender);
int sendto(char *buf, int len, const SockAddr& EndPoint);
int mtu(const SockAddr& sa) {
return sa.isLocalHost() ? 16384 : 1480;
}
SOCKET sock;
};
inline int UDPConnection::recvfrom(char *buf, int len, SockAddr& sender const sockaddr* raw() const {return (sockaddr*)&sa;}
) { sockaddr* raw() {return (sockaddr*)&sa;}
return ::recvfrom(sock, buf, len, 0, (sockaddr *) &sender.sa, &send
er.addressSize);
}
inline int UDPConnection::sendto(char *buf, int len, const SockAddr& En
dPoint) {
if ( 0 && rand() < (RAND_MAX>>4) ) {
out() << " NOTSENT ";
// out() << curTimeMillis() << " .TEST: NOT SENDING PAC
KET" << endl;
return 0;
}
return ::sendto(sock, buf, len, 0, (sockaddr *) &EndPoint.sa, EndPo
int.addressSize);
}
inline bool UDPConnection::init(const SockAddr& myAddr) { socklen_t addressSize;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); private:
if ( sock == INVALID_SOCKET ) { struct sockaddr_storage sa;
out() << "invalid socket? " << OUTPUT_ERRNO << endl; };
return false;
}
//out() << sizeof(sockaddr_in) << ' ' << myAddr.addressSize << endl
;
if ( ::bind(sock, (sockaddr *) &myAddr.sa, myAddr.addressSize) != 0
) {
out() << "udp init failed" << endl;
closesocket(sock);
sock = 0;
return false;
}
socklen_t optLen;
int rcvbuf;
if (getsockopt(sock,
SOL_SOCKET,
SO_RCVBUF,
(char*)&rcvbuf,
&optLen) != -1)
out() << "SO_RCVBUF:" << rcvbuf << endl;
return true;
}
inline SockAddr::SockAddr(int sourcePort) { extern SockAddr unknownAddress; // ( "0.0.0.0", 0 )
memset(sa.sin_zero, 0, sizeof(sa.sin_zero));
sa.sin_family = AF_INET;
sa.sin_port = htons(sourcePort);
sa.sin_addr.s_addr = htonl(INADDR_ANY);
addressSize = sizeof(sa);
}
inline SockAddr::SockAddr(const char * iporhost , int port) { const int MaxMTU = 16384;
string ip = hostbyname( iporhost );
memset(sa.sin_zero, 0, sizeof(sa.sin_zero));
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
sa.sin_addr.s_addr = inet_addr(ip.c_str());
addressSize = sizeof(sa);
}
inline string getHostName() { inline string getHostName() {
char buf[256]; char buf[256];
int ec = gethostname(buf, 127); int ec = gethostname(buf, 127);
if ( ec || *buf == 0 ) { if ( ec || *buf == 0 ) {
log() << "can't get this server's hostname " << OUTPUT_ERRNO << endl; log() << "can't get this server's hostname " << OUTPUT_ERRNO << endl;
return ""; return "";
} }
return buf; return buf;
} }
 End of changes. 25 change blocks. 
116 lines changed or deleted 120 lines changed or added


 stdafx.h   stdafx.h 
skipping to change at line 23 skipping to change at line 23
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#if defined(_WIN32)
# define NOMINMAX
# include <winsock2.h> //this must be included before the first windows.h
include
# include <ws2tcpip.h>
# include <windows.h>
#endif
#include <string> #include <string>
namespace mongo { namespace mongo {
using namespace std; using namespace std;
#define NOMINMAX
#if defined(_WIN32) #if defined(_WIN32)
const bool debug=true; const bool debug=true;
#else #else
const bool debug=false; const bool debug=false;
#endif #endif
// pdfile versions // pdfile versions
const int VERSION = 4; const int VERSION = 4;
const int VERSION_MINOR = 5; const int VERSION_MINOR = 5;
 End of changes. 2 change blocks. 
2 lines changed or deleted 8 lines changed or added


 update.h   update.h 
skipping to change at line 103 skipping to change at line 103
switch (op){ switch (op){
case PUSH: case PUSH:
case PUSH_ALL: case PUSH_ALL:
case POP: case POP:
return true; return true;
default: default:
return false; return false;
} }
} }
static bool isIndexed( const string& fullName , const set<string>& bool isIndexed( const set<string>& idxKeys ) const {
idxKeys ){
const char * fieldName = fullName.c_str();
// check if there is an index key that is a parent of mod // check if there is an index key that is a parent of mod
for( const char *dot = strchr( fieldName, '.' ); dot; dot = str chr( dot + 1, '.' ) ) for( const char *dot = strchr( fieldName, '.' ); dot; dot = str chr( dot + 1, '.' ) )
if ( idxKeys.count( string( fieldName, dot - fieldName ) ) ) if ( idxKeys.count( string( fieldName, dot - fieldName ) ) )
return true; return true;
string fullName = fieldName;
// check if there is an index key equal to mod // check if there is an index key equal to mod
if ( idxKeys.count(fullName) ) if ( idxKeys.count(fullName) )
return true; return true;
// check if there is an index key that is a child of mod // check if there is an index key that is a child of mod
set< string >::const_iterator j = idxKeys.upper_bound( fullName ); set< string >::const_iterator j = idxKeys.upper_bound( fullName );
if ( j != idxKeys.end() && j->find( fullName ) == 0 && (*j)[ful lName.size()] == '.' ) if ( j != idxKeys.end() && j->find( fullName ) == 0 && (*j)[ful lName.size()] == '.' )
return true; return true;
return false;
}
bool isIndexed( const set<string>& idxKeys ) const {
string fullName = fieldName;
if ( isIndexed( fullName , idxKeys ) )
return true;
if ( strstr( fieldName , "." ) ){
// check for a.0.1
StringBuilder buf( fullName.size() + 1 );
for ( size_t i=0; i<fullName.size(); i++ ){
char c = fullName[i];
buf << c;
if ( c != '.' )
continue;
if ( ! isdigit( fullName[i+1] ) )
continue;
bool possible = true;
size_t j=i+2;
for ( ; j<fullName.size(); j++ ){
char d = fullName[j];
if ( d == '.' )
break;
if ( isdigit( d ) )
continue;
possible = false;
break;
}
if ( possible )
i = j;
}
string x = buf.str();
if ( isIndexed( x , idxKeys ) )
return true;
}
return false; return false;
} }
template< class Builder > template< class Builder >
void apply( Builder& b , BSONElement in , ModState& ms ) const; void apply( Builder& b , BSONElement in , ModState& ms ) const;
/** /**
* @return true iff toMatch should be removed from the array * @return true iff toMatch should be removed from the array
*/ */
bool _pullElementMatch( BSONElement& toMatch ) const; bool _pullElementMatch( BSONElement& toMatch ) const;
skipping to change at line 373 skipping to change at line 329
}; };
/** /**
* stores any information about a single Mod operating on a single Obje ct * stores any information about a single Mod operating on a single Obje ct
*/ */
class ModState { class ModState {
public: public:
const Mod * m; const Mod * m;
BSONElement old; BSONElement old;
const char * fixedOpName; const char * fixedName;
BSONElement * fixed; BSONElement * fixed;
int pushStartSize; int pushStartSize;
BSONType incType; BSONType incType;
int incint; int incint;
double incdouble; double incdouble;
long long inclong; long long inclong;
ModState(){ ModState(){
fixedOpName = 0; fixedName = 0;
fixed = 0; fixed = 0;
pushStartSize = -1; pushStartSize = -1;
incType = EOO; incType = EOO;
} }
Mod::Op op() const { Mod::Op op() const {
return m->op; return m->op;
} }
const char * fieldName() const { const char * fieldName() const {
return m->fieldName; return m->fieldName;
} }
bool needOpLogRewrite() const { bool needOpLogRewrite() const {
if ( fixed || fixedOpName || incType ) if ( fixed || fixedName || incType )
return true; return true;
switch( op() ){ switch( op() ){
case Mod::BIT: case Mod::BIT:
case Mod::BITAND: case Mod::BITAND:
case Mod::BITOR: case Mod::BITOR:
// TODO: should we convert this to $set? // TODO: should we convert this to $set?
return false; return false;
default: default:
return false; return false;
} }
} }
void appendForOpLog( BSONObjBuilder& b ) const { void appendForOpLog( BSONObjBuilder& b ) const {
if ( incType ){ if ( incType ){
BSONObjBuilder bb( b.subobjStart( "$set" ) ); BSONObjBuilder bb( b.subobjStart( "$set" ) );
appendIncValue( bb , true ); appendIncValue( bb );
bb.done(); bb.done();
return; return;
} }
const char * name = fixedOpName ? fixedOpName : Mod::modNames[o p()]; const char * name = fixedName ? fixedName : Mod::modNames[op()] ;
BSONObjBuilder bb( b.subobjStart( name ) ); BSONObjBuilder bb( b.subobjStart( name ) );
if ( fixed ) if ( fixed )
bb.appendAs( *fixed , m->fieldName ); bb.appendAs( *fixed , m->fieldName );
else else
bb.appendAs( m->elt , m->fieldName ); bb.append( m->elt );
bb.done(); bb.done();
} }
template< class Builder > template< class Builder >
void apply( Builder& b , BSONElement in ){ void apply( Builder& b , BSONElement in ){
m->apply( b , in , *this ); m->apply( b , in , *this );
} }
template< class Builder > template< class Builder >
void appendIncValue( Builder& b , bool useFullName ) const { void appendIncValue( Builder& b ) const {
const char * n = useFullName ? m->fieldName : m->shortFieldName
;
switch ( incType ){ switch ( incType ){
case NumberDouble: case NumberDouble:
b.append( n , incdouble ); break; b.append( m->shortFieldName , incdouble ); break;
case NumberLong: case NumberLong:
b.append( n , inclong ); break; b.append( m->shortFieldName , inclong ); break;
case NumberInt: case NumberInt:
b.append( n , incint ); break; b.append( m->shortFieldName , incint ); break;
default: default:
assert(0); assert(0);
} }
} }
}; };
/** /**
* this is used to hold state, meta data while applying a ModSet to a B SONObj * this is used to hold state, meta data while applying a ModSet to a B SONObj
* the goal is to make ModSet const so its re-usable * the goal is to make ModSet const so its re-usable
*/ */
skipping to change at line 518 skipping to change at line 472
break; break;
} }
case Mod::UNSET: case Mod::UNSET:
case Mod::PULL: case Mod::PULL:
case Mod::PULL_ALL: case Mod::PULL_ALL:
// no-op b/c unset/pull of nothing does nothing // no-op b/c unset/pull of nothing does nothing
break; break;
case Mod::INC: case Mod::INC:
ms.fixedOpName = "$set"; ms.fixedName = "$set";
case Mod::SET: { case Mod::SET: {
m._checkForAppending( m.elt ); m._checkForAppending( m.elt );
b.appendAs( m.elt, m.shortFieldName ); b.appendAs( m.elt, m.shortFieldName );
break; break;
} }
default: default:
stringstream ss; stringstream ss;
ss << "unknown mod in appendNewFromMod: " << m.op; ss << "unknown mod in appendNewFromMod: " << m.op;
throw UserException( 9015, ss.str() ); throw UserException( 9015, ss.str() );
} }
 End of changes. 14 change blocks. 
61 lines changed or deleted 13 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/