assert_util.h   assert_util.h 
skipping to change at line 34 skipping to change at line 34
/* these are manipulated outside of mutexes, so be careful */ /* these are manipulated outside of mutexes, so be careful */
struct Assertion { struct Assertion {
Assertion() { Assertion() {
msg[0] = msg[127] = 0; msg[0] = msg[127] = 0;
context[0] = context[127] = 0; context[0] = context[127] = 0;
file = ""; file = "";
line = 0; line = 0;
when = 0; when = 0;
} }
private: private:
static boost::mutex *_mutex; static mongo::mutex *_mutex;
char msg[128]; char msg[128];
char context[128]; char context[128];
const char *file; const char *file;
unsigned line; unsigned line;
time_t when; time_t when;
public: public:
void set(const char *m, const char *ctxt, const char *f, unsigned l ) { void set(const char *m, const char *ctxt, const char *f, unsigned l ) {
if( _mutex == 0 ) { if( _mutex == 0 ) {
/* asserted during global variable initialization */ /* asserted during global variable initialization */
return; return;
} }
boostlock lk(*_mutex); scoped_lock lk(*_mutex);
strncpy(msg, m, 127); strncpy(msg, m, 127);
strncpy(context, ctxt, 127); strncpy(context, ctxt, 127);
file = f; file = f;
line = l; line = l;
when = time(0); when = time(0);
} }
std::string toString(); std::string toString();
bool isSet() { bool isSet() {
return when != 0; return when != 0;
} }
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 base64.h   base64.h 
skipping to change at line 18 skipping to change at line 18
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* 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
namespace mongo { namespace mongo {
namespace base64 { namespace base64 {
class Alphabet {
public:
Alphabet()
: encode((unsigned char*)
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"+/")
, decode(new unsigned char[257])
{
memset( decode.get() , 0 , 256 );
for ( int i=0; i<64; i++ ){
decode[ encode[i] ] = i;
}
test();
}
void test(){
assert( strlen( (char*)encode ) == 64 );
for ( int i=0; i<26; i++ )
assert( encode[i] == toupper( encode[i+26] ) );
}
char e( int x ){
return encode[x&0x3f];
}
private:
const unsigned char * encode;
public:
boost::scoped_array<unsigned char> decode;
};
extern Alphabet alphabet;
void encode( stringstream& ss , const char * data , int size ); void encode( stringstream& ss , const char * data , int size );
string encode( const char * data , int size ); string encode( const char * data , int size );
string encode( const string& s ); string encode( const string& s );
void decode( stringstream& ss , const string& s ); void decode( stringstream& ss , const string& s );
string decode( const string& s ); string decode( const string& s );
void testAlphabet(); void testAlphabet();
} }
} }
 End of changes. 2 change blocks. 
0 lines changed or deleted 37 lines changed or added


 btree.h   btree.h 
skipping to change at line 274 skipping to change at line 274
virtual bool ok() { virtual bool ok() {
return !bucket.isNull(); return !bucket.isNull();
} }
bool eof() { bool eof() {
return !ok(); return !ok();
} }
virtual bool advance(); virtual bool advance();
virtual void noteLocation(); // updates keyAtKeyOfs... virtual void noteLocation(); // updates keyAtKeyOfs...
virtual void checkLocation(); virtual void checkLocation();
virtual bool supportGetMore() { return true; }
/* used for multikey index traversal to avoid sending back dups. se e Matcher::matches(). /* used for multikey index traversal to avoid sending back dups. se e Matcher::matches().
if a multikey index traversal: if a multikey index traversal:
if loc has already been sent, returns true. if loc has already been sent, returns true.
otherwise, marks loc as sent. otherwise, marks loc as sent.
@return true if the loc has not been seen @return true if the loc has not been seen
*/ */
set<DiskLoc> dups; set<DiskLoc> dups;
virtual bool getsetdup(DiskLoc loc) { virtual bool getsetdup(DiskLoc loc) {
if( multikey ) { if( multikey ) {
skipping to change at line 336 skipping to change at line 337
string s = string("BtreeCursor ") + indexDetails.indexName(); string s = string("BtreeCursor ") + indexDetails.indexName();
if ( direction < 0 ) s += " reverse"; if ( direction < 0 ) s += " reverse";
if ( bounds_.size() > 1 ) s += " multi"; if ( bounds_.size() > 1 ) s += " multi";
return s; return s;
} }
BSONObj prettyKey( const BSONObj &key ) const { BSONObj prettyKey( const BSONObj &key ) const {
return key.replaceFieldNames( indexDetails.keyPattern() ).clien tReadable(); return key.replaceFieldNames( indexDetails.keyPattern() ).clien tReadable();
} }
virtual BSONObj prettyStartKey() const { virtual BSONObj prettyIndexBounds() const {
return prettyKey( startKey ); BSONArrayBuilder ba;
} if ( bounds_.size() == 0 ) {
virtual BSONObj prettyEndKey() const { ba << BSON_ARRAY( prettyKey( startKey ) << prettyKey( endKe
return prettyKey( endKey ); y ) );
} else {
for( BoundList::const_iterator i = bounds_.begin(); i != bo
unds_.end(); ++i ) {
ba << BSON_ARRAY( prettyKey( i->first ) << prettyKey( i
->second ) );
}
}
return ba.arr();
} }
void forgetEndKey() { endKey = BSONObj(); } void forgetEndKey() { endKey = BSONObj(); }
private: private:
/* Our btrees may (rarely) have "unused" keys when items are delete d. /* Our btrees may (rarely) have "unused" keys when items are delete d.
Skip past them. Skip past them.
*/ */
void skipUnusedKeys(); void skipUnusedKeys();
 End of changes. 2 change blocks. 
5 lines changed or deleted 14 lines changed or added


 builder.h   builder.h 
skipping to change at line 105 skipping to change at line 105
} }
void append(const char *str) { void append(const char *str) {
append((void*) str, strlen(str)+1); append((void*) str, strlen(str)+1);
} }
void append(const string &str) { void append(const string &str) {
append( (void *)str.c_str(), str.length() + 1 ); append( (void *)str.c_str(), str.length() + 1 );
} }
void append( int val , int padding ){
}
int len() const { int len() const {
return l; return l;
} }
void setlen( int newLen ){ void setlen( int newLen ){
l = newLen; l = newLen;
} }
private: private:
/* returns the pre-grow write position */ /* returns the pre-grow write position */
 End of changes. 1 change blocks. 
0 lines changed or deleted 4 lines changed or added


 client.h   client.h 
skipping to change at line 45 skipping to change at line 45
class AuthenticationInfo; class AuthenticationInfo;
class Database; class Database;
class CurOp; class CurOp;
class Command; class Command;
class Client; class Client;
extern boost::thread_specific_ptr<Client> currentClient; extern boost::thread_specific_ptr<Client> currentClient;
class Client : boost::noncopyable { class Client : boost::noncopyable {
public: public:
static boost::mutex clientsMutex; static mongo::mutex clientsMutex;
static set<Client*> clients; // always be in clientsMutex when mani pulating this static set<Client*> clients; // always be in clientsMutex when mani pulating this
class GodScope { class GodScope {
bool _prev; bool _prev;
public: public:
GodScope(); GodScope();
~GodScope(); ~GodScope();
}; };
/* Set database we want to use, then, restores when we finish (are out of scope) /* Set database we want to use, then, restores when we finish (are out of scope)
skipping to change at line 248 skipping to change at line 248
dbMutex.unlock_shared(); dbMutex.unlock_shared();
dbMutex.lock(); dbMutex.lock();
if ( cc().getContext() ) if ( cc().getContext() )
cc().getContext()->unlocked(); cc().getContext()->unlocked();
} }
} }
string sayClientState(); string sayClientState();
inline bool haveClient(){
return currentClient.get() > 0;
}
}; };
 End of changes. 2 change blocks. 
1 lines changed or deleted 4 lines changed or added


 clientcursor.h   clientcursor.h 
skipping to change at line 86 skipping to change at line 86
public: public:
ClientCursor *_c; ClientCursor *_c;
void release() { void release() {
if( _c ) { if( _c ) {
assert( _c->_pinValue >= 100 ); assert( _c->_pinValue >= 100 );
_c->_pinValue -= 100; _c->_pinValue -= 100;
} }
_c = 0; _c = 0;
} }
Pointer(long long cursorid) { Pointer(long long cursorid) {
recursive_boostlock lock(ccmutex); recursive_scoped_lock lock(ccmutex);
_c = ClientCursor::find_inlock(cursorid, true); _c = ClientCursor::find_inlock(cursorid, true);
if( _c ) { if( _c ) {
if( _c->_pinValue >= 100 ) { if( _c->_pinValue >= 100 ) {
_c = 0; _c = 0;
uassert(12051, "clientcursor already in use? driver problem?", false); uassert(12051, "clientcursor already in use? driver problem?", false);
} }
_c->_pinValue += 100; _c->_pinValue += 100;
} }
} }
~Pointer() { ~Pointer() {
skipping to change at line 116 skipping to change at line 116
BSONObj query; BSONObj query;
ClientCursor(auto_ptr<Cursor>& _c, const char *_ns, bool okToTimeou t) : ClientCursor(auto_ptr<Cursor>& _c, const char *_ns, bool okToTimeou t) :
_idleAgeMillis(0), _pinValue(0), _idleAgeMillis(0), _pinValue(0),
_doingDeletes(false), _doingDeletes(false),
ns(_ns), c(_c), ns(_ns), c(_c),
pos(0) pos(0)
{ {
if( !okToTimeout ) if( !okToTimeout )
noTimeout(); noTimeout();
recursive_boostlock 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;
} }
shared_ptr< FieldMatcher > fields; // which fields query wants retu rned shared_ptr< FieldMatcher > fields; // which fields query wants retu rned
skipping to change at line 158 skipping to change at line 158
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;
} }
return it->second; return it->second;
} }
public: public:
static ClientCursor* find(CursorId id, bool warn = true) { static ClientCursor* find(CursorId id, bool warn = true) {
recursive_boostlock lock(ccmutex); recursive_scoped_lock lock(ccmutex);
ClientCursor *c = find_inlock(id, warn); ClientCursor *c = find_inlock(id, warn);
// if this asserts, your code was not thread safe - you either need to set no timeout // if this asserts, your code was not thread safe - you either need to set no timeout
// for the cursor or keep a ClientCursor::Pointer in scope for it. // for the cursor or keep a ClientCursor::Pointer in scope for it.
massert( 12521, "internal error: use of an unlocked ClientCurso r", c == 0 || c->_pinValue ); massert( 12521, "internal error: use of an unlocked ClientCurso r", c == 0 || c->_pinValue );
return c; return c;
} }
static bool erase(CursorId id) { static bool erase(CursorId id) {
recursive_boostlock lock(ccmutex); recursive_scoped_lock lock(ccmutex);
ClientCursor *cc = find_inlock(id); ClientCursor *cc = find_inlock(id);
if ( cc ) { if ( cc ) {
assert( cc->_pinValue < 100 ); // you can't still have an a ctive ClientCursor::Pointer assert( cc->_pinValue < 100 ); // you can't still have an a ctive ClientCursor::Pointer
delete cc; delete cc;
return true; return true;
} }
return false; return false;
} }
/* call when cursor's location changes so that we can update the /* call when cursor's location changes so that we can update the
 End of changes. 4 change blocks. 
4 lines changed or deleted 4 lines changed or added


 cmdline.h   cmdline.h 
skipping to change at line 19 skipping to change at line 19
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* 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 "../stdafx.h"
namespace mongo { namespace mongo {
/* command line options /* command line options
*/ */
/* concurrency: OK/READ */ /* concurrency: OK/READ */
struct CmdLine { struct CmdLine {
int port; // --port int port; // --port
bool rest; // --rest
string source; // --source string source; // --source
string only; // --only string only; // --only
bool quiet; // --quiet bool quiet; // --quiet
bool notablescan; // --notablescan bool notablescan; // --notablescan
bool prealloc; // --noprealloc bool prealloc; // --noprealloc
bool smallfiles; // --smallfiles bool smallfiles; // --smallfiles
bool quota; // --quota bool quota; // --quota
skipping to change at line 50 skipping to change at line 53
int defaultProfile; // --profile int defaultProfile; // --profile
int slowMS; // --time in ms that is "slow" int slowMS; // --time in ms that is "slow"
enum { enum {
DefaultDBPort = 27017, DefaultDBPort = 27017,
ConfigServerPort = 27019, ConfigServerPort = 27019,
ShardServerPort = 27018 ShardServerPort = 27018
}; };
CmdLine() : CmdLine() :
port(DefaultDBPort), quiet(false), notablescan(false), prealloc (true), smallfiles(false), port(DefaultDBPort), rest(false), quiet(false), notablescan(fal se), prealloc(true), smallfiles(false),
quota(false), quotaFiles(8), cpu(false), oplogSize(0), defaultP rofile(0), slowMS(100) quota(false), quotaFiles(8), cpu(false), oplogSize(0), defaultP rofile(0), slowMS(100)
{ } { }
void addGlobalOptions( boost::program_options::options_description&
general ,
boost::program_options::options_description&
hidden );
}; };
extern CmdLine cmdLine; extern CmdLine cmdLine;
} }
 End of changes. 5 change blocks. 
1 lines changed or deleted 9 lines changed or added


 concurrency.h   concurrency.h 
skipping to change at line 52 skipping to change at line 52
inline bool readLockSupported(){ inline bool readLockSupported(){
#ifdef HAVE_READLOCK #ifdef HAVE_READLOCK
return true; return true;
#else #else
return false; return false;
#endif #endif
} }
string sayClientState(); string sayClientState();
bool haveClient();
void curopWaitingForLock( int type ); void curopWaitingForLock( int type );
void curopGotLock(); void curopGotLock();
/* mutex time stats */ /* mutex time stats */
class MutexInfo { class MutexInfo {
unsigned long long start, enter, timeLocked; // all in microseconds unsigned long long start, enter, timeLocked; // all in microseconds
int locked; int locked;
public: public:
skipping to change at line 117 skipping to change at line 118
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()); }
void lock() { void lock() {
//DEV cout << "LOCK" << endl; //DEV cout << "LOCK" << endl;
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; 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 );
_state.set(1); _state.set(1);
curopWaitingForLock( 1 ); curopWaitingForLock( 1 );
_m.lock(); _m.lock();
 End of changes. 2 change blocks. 
0 lines changed or deleted 3 lines changed or added


 connpool.h   connpool.h 
skipping to change at line 54 skipping to change at line 54
request... request...
Usage: Usage:
{ {
ScopedDbConnection c("myserver"); ScopedDbConnection c("myserver");
c.conn()... c.conn()...
} }
*/ */
class DBConnectionPool { class DBConnectionPool {
boost::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() )
return; return;
boostlock 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. 
2 lines changed or deleted 2 lines changed or added


 counters.h   counters.h 
skipping to change at line 104 skipping to change at line 104
int _resets; int _resets;
long long _maxAllowed; long long _maxAllowed;
long long _btreeMemMisses; long long _btreeMemMisses;
long long _btreeMemHits; long long _btreeMemHits;
long long _btreeAccesses; long long _btreeAccesses;
}; };
extern IndexCounters globalIndexCounters; extern IndexCounters globalIndexCounters;
class FlushCounters {
public:
FlushCounters();
void flushed(int ms);
void append( BSONObjBuilder& b );
private:
long long _total_time;
long long _flushes;
int _last_time;
Date_t _last;
};
extern FlushCounters globalFlushCounters;
} }
 End of changes. 1 change blocks. 
0 lines changed or deleted 16 lines changed or added


 curop.h   curop.h 
skipping to change at line 65 skipping to change at line 65
AtomicUInt _opNum; AtomicUInt _opNum;
char _ns[Namespace::MaxNsLen+2]; char _ns[Namespace::MaxNsLen+2];
struct sockaddr_in _remote; struct sockaddr_in _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;
ProgressMeter _progressMeter;
void _reset(){ void _reset(){
_command = false; _command = false;
_lockType = 0; _lockType = 0;
_dbprofile = 0; _dbprofile = 0;
_end = 0; _end = 0;
_waitingForLock = false; _waitingForLock = false;
_message = "";
_progressMeter.finished();
} }
void setNS(const char *ns) { void setNS(const char *ns) {
strncpy(_ns, ns, Namespace::MaxNsLen); strncpy(_ns, ns, Namespace::MaxNsLen);
} }
public: public:
bool haveQuery() const { return *((int *) _queryBuf) != 0; } bool haveQuery() const { return *((int *) _queryBuf) != 0; }
skipping to change at line 237 skipping to change at line 242
} }
BSONObj infoNoauth(); BSONObj infoNoauth();
string getRemoteString(){ string getRemoteString(){
stringstream ss; stringstream ss;
ss << inet_ntoa( _remote.sin_addr ) << ":" << ntohs( _remote.si n_port ); ss << inet_ntoa( _remote.sin_addr ) << ":" << ntohs( _remote.si n_port );
return ss.str(); return ss.str();
} }
ProgressMeter& setMessage( const char * msg , long long progressMet
erTotal = 0 , int secondsBetween = 3 ){
_message = msg;
if ( progressMeterTotal ){
assert( ! _progressMeter.isActive() );
_progressMeter.reset( progressMeterTotal , secondsBetween )
;
}
else {
_progressMeter.finished();
}
return _progressMeter;
}
string getMessage() const { return _message; }
ProgressMeter getProgressMeter() { return _progressMeter; }
friend class Client; friend class Client;
}; };
/* 0 = ok /* 0 = ok
1 = kill current operation and reset this to 0 1 = kill current operation and reset this to 0
future: maybe use this as a "going away" thing on process terminatio n with a higher flag value future: maybe use this as a "going away" thing on process terminatio n with a higher flag value
*/ */
extern class KillCurrentOp { extern class KillCurrentOp {
enum { Off, On, All } state; enum { Off, On, All } state;
AtomicUInt toKill; AtomicUInt toKill;
public: public:
void killAll() { state = All; } void killAll() { state = All; }
void kill(AtomicUInt i) { toKill = i; state = On; } void kill(AtomicUInt i) { toKill = i; state = On; }
void checkForInterrupt() { void checkForInterrupt() {
if( state != Off ) { if( state != Off ) {
if( state == All ) if( state == All )
uasserted(11600,"interrupted at shutdown"); uasserted(11600,"interrupted at shutdown");
if( cc().curop()->opNum() == toKill ) { if( cc().curop()->opNum() == toKill ) {
 End of changes. 4 change blocks. 
1 lines changed or deleted 23 lines changed or added


 cursor.h   cursor.h 
skipping to change at line 80 skipping to change at line 80
} }
/* called after every query block is iterated -- i.e. between getMo re() blocks /* called after every query block is iterated -- i.e. between getMo re() blocks
so you can note where we are, if necessary. so you can note where we are, if necessary.
*/ */
virtual void noteLocation() { } virtual void noteLocation() { }
/* called before query getmore block is iterated */ /* called before query getmore block is iterated */
virtual void checkLocation() { } virtual void checkLocation() { }
virtual bool supportGetMore() = 0;
virtual string toString() { virtual string toString() {
return "abstract?"; return "abstract?";
} }
/* used for multikey index traversal to avoid sending back dups. se e Matcher::matches(). /* used for multikey index traversal to avoid sending back dups. se e Matcher::matches().
if a multikey index traversal: if a multikey index traversal:
if loc has already been sent, returns true. if loc has already been sent, returns true.
otherwise, marks loc as sent. otherwise, marks loc as sent.
@param deep - match was against an array, so we know it is multi key. this is legacy and kept @param deep - match was against an array, so we know it is multi key. this is legacy and kept
for backwards datafile compatibility. 'deep' can be eliminated next time we for backwards datafile compatibility. 'deep' can be eliminated next time we
force a data file conversion. 7Jul09 force a data file conversion. 7Jul09
*/ */
virtual bool getsetdup(DiskLoc loc) = 0; virtual bool getsetdup(DiskLoc loc) = 0;
virtual BSONObj prettyStartKey() const { return BSONObj(); } virtual BSONObj prettyIndexBounds() const { return BSONObj(); }
virtual BSONObj prettyEndKey() const { return BSONObj(); }
virtual bool capped() const { return false; } virtual bool capped() const { return false; }
}; };
// strategy object implementing direction of traversal. // strategy object implementing direction of traversal.
class AdvanceStrategy { class AdvanceStrategy {
public: public:
virtual ~AdvanceStrategy() { } virtual ~AdvanceStrategy() { }
virtual DiskLoc next( const DiskLoc &prev ) const = 0; virtual DiskLoc next( const DiskLoc &prev ) const = 0;
skipping to change at line 161 skipping to change at line 162
return "BasicCursor"; return "BasicCursor";
} }
virtual void setTailable() { virtual void setTailable() {
if ( !curr.isNull() || !last.isNull() ) if ( !curr.isNull() || !last.isNull() )
tailable_ = true; tailable_ = true;
} }
virtual bool tailable() { virtual bool tailable() {
return tailable_; return tailable_;
} }
virtual bool getsetdup(DiskLoc loc) { return false; } virtual bool getsetdup(DiskLoc loc) { return false; }
virtual bool supportGetMore() { return true; }
}; };
/* used for order { $natural: -1 } */ /* used for order { $natural: -1 } */
class ReverseCursor : public BasicCursor { class ReverseCursor : public BasicCursor {
public: public:
ReverseCursor(DiskLoc dl) : BasicCursor( dl, reverse() ) { } ReverseCursor(DiskLoc dl) : BasicCursor( dl, reverse() ) { }
ReverseCursor() : BasicCursor( reverse() ) { } ReverseCursor() : BasicCursor( reverse() ) { }
virtual string toString() { virtual string toString() {
return "ReverseCursor"; return "ReverseCursor";
} }
 End of changes. 3 change blocks. 
2 lines changed or deleted 5 lines changed or added


 dbclient.h   dbclient.h 
skipping to change at line 371 skipping to change at line 371
*/ */
virtual BSONObj findOne(const string &ns, Query query, const BSONOb j *fieldsToReturn = 0, int queryOptions = 0); virtual BSONObj findOne(const string &ns, Query query, const BSONOb j *fieldsToReturn = 0, int queryOptions = 0);
}; };
/** /**
DB "commands" DB "commands"
Basically just invocations of connection.$cmd.findOne({...}); Basically just invocations of connection.$cmd.findOne({...});
*/ */
class DBClientWithCommands : public DBClientInterface { class DBClientWithCommands : public DBClientInterface {
bool isOk(const BSONObj&);
set<string> _seenIndexes; set<string> _seenIndexes;
public: public:
/** helper function. run a simple command where the command expression is simply /** helper function. run a simple command where the command expression is simply
{ command : 1 } { command : 1 }
@param info -- where to put result object. may be null if call er doesn't need that info @param info -- where to put result object. may be null if call er doesn't need that info
@param command -- command name @param command -- command name
@return true if the command returned "ok". @return true if the command returned "ok".
*/ */
bool simpleCommand(const string &dbname, BSONObj *info, const strin g &command); bool simpleCommand(const string &dbname, BSONObj *info, const strin g &command);
skipping to change at line 393 skipping to change at line 392
/** Run a database command. Database commands are represented as B SON objects. Common database /** Run a database command. Database commands are represented as B SON objects. Common database
commands have prebuilt helper functions -- see below. If a hel per is not available you can commands have prebuilt helper functions -- see below. If a hel per is not available you can
directly call runCommand. directly call runCommand.
@param dbname database name. Use "admin" for global administra tive commands. @param dbname database name. Use "admin" for global administra tive commands.
@param cmd the command object to execute. For exam ple, { ismaster : 1 } @param cmd the command object to execute. For exam ple, { ismaster : 1 }
@param info the result object the database returns. Typically has { ok : ..., errmsg : ... } fields @param info the result object the database returns. Typically has { ok : ..., errmsg : ... } fields
set. set.
@return true if the command returned "ok". @return true if the command returned "ok".
*/ */
bool runCommand(const string &dbname, const BSONObj& cmd, BSONObj & info, int options=0); virtual bool runCommand(const string &dbname, const BSONObj& cmd, B SONObj &info, int options=0);
/** Authorize access to a particular database. /** Authorize access to a particular database.
Authentication is separate for each database on the server -- you may authenticate for any Authentication is separate for each database on the server -- you may authenticate for any
number of databases on a single connection. number of databases on a single connection.
The "admin" database is special and once authenticat ed provides access to all databases on the The "admin" database is special and once authenticat ed provides access to all databases on the
server. server.
@param digestPassword if password is plain text, set this to true. otherwise assumed to be pre-digested @param digestPassword if password is plain text, set this to true. otherwise assumed to be pre-digested
@return true if successful @return true if successful
*/ */
virtual bool auth(const string &dbname, const string &username, con st string &pwd, string& errmsg, bool digestPassword = true); virtual bool auth(const string &dbname, const string &username, con st string &pwd, string& errmsg, bool digestPassword = true);
skipping to change at line 665 skipping to change at line 665
/** @return the collection name portion of an ns string */ /** @return the collection name portion of an ns string */
string nsGetCollection( const string &ns ){ string nsGetCollection( const string &ns ){
string::size_type pos = ns.find( "." ); string::size_type pos = ns.find( "." );
if ( pos == string::npos ) if ( pos == string::npos )
return ""; return "";
return ns.substr( pos + 1 ); return ns.substr( pos + 1 );
} }
protected:
bool isOk(const BSONObj&);
}; };
/** /**
abstract class that implements the core db operations abstract class that implements the core db operations
*/ */
class DBClientBase : public DBClientWithCommands, public DBConnector { class DBClientBase : public DBClientWithCommands, public DBConnector {
public: public:
/** send a query to the database. /** send a query to the database.
ns: namespace to query, format is <dbname>.<collectname >[.<collectname>]* ns: namespace to query, format is <dbname>.<collectname >[.<collectname>]*
query: query to perform on the collection. this is a BSON Obj (binary JSON) query: query to perform on the collection. this is a BSON Obj (binary JSON)
 End of changes. 3 change blocks. 
2 lines changed or deleted 4 lines changed or added


 file_allocator.h   file_allocator.h 
skipping to change at line 57 skipping to change at line 57
#endif #endif
} }
// May be called if file exists. If file exists, or its allocation has // May be called if file exists. If file exists, or its allocation has
// been requested, size is updated to match existing file size. // been requested, size is updated to match existing file size.
void requestAllocation( const string &name, long &size ) { void requestAllocation( const string &name, long &size ) {
/* Some of the system calls in the file allocator don't work in win, /* Some of the system calls in the file allocator don't work in win,
so no win support - 32 or 64 bit. Plus we don't seem to nee d preallocation so no win support - 32 or 64 bit. Plus we don't seem to nee d preallocation
on windows anyway as we don't have to pre-zero the file ther e. on windows anyway as we don't have to pre-zero the file ther e.
*/ */
#if !defined(_WIN32) #if !defined(_WIN32)
boostlock lk( pendingMutex_ ); scoped_lock lk( pendingMutex_ );
if ( failed_ ) if ( failed_ )
return; return;
long oldSize = prevSize( name ); long oldSize = prevSize( name );
if ( oldSize != -1 ) { if ( oldSize != -1 ) {
size = oldSize; size = oldSize;
return; return;
} }
pending_.push_back( name ); pending_.push_back( name );
pendingSize_[ name ] = size; pendingSize_[ name ] = size;
pendingUpdated_.notify_all(); pendingUpdated_.notify_all();
#endif #endif
} }
// Returns when file has been allocated. If file exists, size is // Returns when file has been allocated. If file exists, size is
// updated to match existing file size. // updated to match existing file size.
void allocateAsap( const string &name, long &size ) { void allocateAsap( const string &name, long &size ) {
#if !defined(_WIN32) #if !defined(_WIN32)
boostlock lk( pendingMutex_ ); scoped_lock lk( pendingMutex_ );
long oldSize = prevSize( name ); long oldSize = prevSize( name );
if ( oldSize != -1 ) { if ( oldSize != -1 ) {
size = oldSize; size = oldSize;
if ( !inProgress( name ) ) if ( !inProgress( name ) )
return; return;
} }
checkFailure(); checkFailure();
pendingSize_[ name ] = size; pendingSize_[ name ] = size;
if ( pending_.size() == 0 ) if ( pending_.size() == 0 )
pending_.push_back( name ); pending_.push_back( name );
else if ( pending_.front() != name ) { else if ( pending_.front() != name ) {
pending_.remove( name ); pending_.remove( name );
list< string >::iterator i = pending_.begin(); list< string >::iterator i = pending_.begin();
++i; ++i;
pending_.insert( i, name ); pending_.insert( i, name );
} }
pendingUpdated_.notify_all(); pendingUpdated_.notify_all();
while( inProgress( name ) ) { while( inProgress( name ) ) {
checkFailure(); checkFailure();
pendingUpdated_.wait( lk ); pendingUpdated_.wait( lk.boost() );
} }
#endif #endif
} }
void waitUntilFinished() const { void waitUntilFinished() const {
#if !defined(_WIN32) #if !defined(_WIN32)
if ( failed_ ) if ( failed_ )
return; return;
boostlock lk( pendingMutex_ ); scoped_lock lk( pendingMutex_ );
while( pending_.size() != 0 ) while( pending_.size() != 0 )
pendingUpdated_.wait( lk ); pendingUpdated_.wait( lk.boost() );
#endif #endif
} }
private: private:
#if !defined(_WIN32) #if !defined(_WIN32)
void checkFailure() { void checkFailure() {
massert( 12520, "file allocation failure", !failed_ ); massert( 12520, "file allocation failure", !failed_ );
} }
// caller must hold pendingMutex_ lock. Returns size if allocated or // caller must hold pendingMutex_ lock. Returns size if allocated or
skipping to change at line 133 skipping to change at line 133
} }
// caller must hold pendingMutex_ lock. // caller must hold pendingMutex_ lock.
bool inProgress( const string &name ) const { bool inProgress( const string &name ) const {
for( list< string >::const_iterator i = pending_.begin(); i != pending_.end(); ++i ) for( list< string >::const_iterator i = pending_.begin(); i != pending_.end(); ++i )
if ( *i == name ) if ( *i == name )
return true; return true;
return false; return false;
} }
mutable boost::mutex pendingMutex_; mutable mongo::mutex pendingMutex_;
mutable boost::condition pendingUpdated_; mutable boost::condition pendingUpdated_;
list< string > pending_; list< string > pending_;
mutable map< string, long > pendingSize_; mutable map< string, long > pendingSize_;
bool failed_; bool failed_;
struct Runner { struct Runner {
Runner( FileAllocator &allocator ) : a_( allocator ) {} Runner( FileAllocator &allocator ) : a_( allocator ) {}
FileAllocator &a_; FileAllocator &a_;
void operator()() { void operator()() {
while( 1 ) { while( 1 ) {
{ {
boostlock lk( a_.pendingMutex_ ); scoped_lock lk( a_.pendingMutex_ );
if ( a_.pending_.size() == 0 ) if ( a_.pending_.size() == 0 )
a_.pendingUpdated_.wait( lk ); a_.pendingUpdated_.wait( lk.boost() );
} }
while( 1 ) { while( 1 ) {
string name; string name;
long size; long size;
{ {
boostlock lk( a_.pendingMutex_ ); scoped_lock lk( a_.pendingMutex_ );
if ( a_.pending_.size() == 0 ) if ( a_.pending_.size() == 0 )
break; break;
name = a_.pending_.front(); name = a_.pending_.front();
size = a_.pendingSize_[ name ]; size = a_.pendingSize_[ name ];
} }
try { try {
log() << "allocating new datafile " << name << ", filling with zeroes..." << endl; log() << "allocating new datafile " << name << ", filling with zeroes..." << endl;
long fd = open(name.c_str(), O_CREAT | O_RDWR | O_NOATIME, S_IRUSR | S_IWUSR); long fd = open(name.c_str(), O_CREAT | O_RDWR | O_NOATIME, S_IRUSR | S_IWUSR);
if ( fd <= 0 ) { if ( fd <= 0 ) {
stringstream ss; stringstream ss;
skipping to change at line 209 skipping to change at line 209
} }
close( fd ); close( fd );
} catch ( ... ) { } catch ( ... ) {
problem() << "Failed to allocate new file: " << name problem() << "Failed to allocate new file: " << name
<< ", size: " << size << ", aborting. " << endl; << ", size: " << size << ", aborting. " << endl;
try { try {
BOOST_CHECK_EXCEPTION( boost::filesystem::r emove( name ) ); BOOST_CHECK_EXCEPTION( boost::filesystem::r emove( name ) );
} catch ( ... ) { } catch ( ... ) {
} }
boostlock lk( a_.pendingMutex_ ); scoped_lock lk( a_.pendingMutex_ );
a_.failed_ = true; a_.failed_ = true;
// not erasing from pending // not erasing from pending
a_.pendingUpdated_.notify_all(); a_.pendingUpdated_.notify_all();
return; // no more allocation return; // no more allocation
} }
{ {
boostlock lk( a_.pendingMutex_ ); scoped_lock lk( a_.pendingMutex_ );
a_.pendingSize_.erase( name ); a_.pendingSize_.erase( name );
a_.pending_.pop_front(); a_.pending_.pop_front();
a_.pendingUpdated_.notify_all(); a_.pendingUpdated_.notify_all();
} }
} }
} }
} }
}; };
#endif #endif
}; };
 End of changes. 11 change blocks. 
11 lines changed or deleted 11 lines changed or added


 goodies.h   goodies.h 
skipping to change at line 27 skipping to change at line 27
*/ */
#pragma once #pragma once
#if defined(_WIN32) #if defined(_WIN32)
# include <windows.h> # include <windows.h>
#endif #endif
namespace mongo { namespace mongo {
#if !defined(_WIN32) && !defined(NOEXECINFO) && !defined(__freebsd__) #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 {
inline pthread_t GetCurrentThreadId() { inline pthread_t GetCurrentThreadId() {
return pthread_self(); return pthread_self();
skipping to change at line 156 skipping to change at line 156
inline void time_t_to_String(time_t t, char *buf) { inline void time_t_to_String(time_t t, char *buf) {
#if defined(_WIN32) #if defined(_WIN32)
ctime_s(buf, 64, &t); ctime_s(buf, 64, &t);
#else #else
ctime_r(&t, buf); ctime_r(&t, buf);
#endif #endif
buf[24] = 0; // don't want the \n buf[24] = 0; // don't want the \n
} }
inline void time_t_to_Struct(time_t t, struct tm * buf , bool local = f
alse ) {
#if defined(_WIN32)
if ( local )
localtime_s( buf , &t );
else
gmtime_s(buf, &t);
#else
if ( local )
localtime_r(&t, buf);
else
gmtime_r(&t, buf);
#endif
}
#define asctime _asctime_not_threadsafe_ #define asctime _asctime_not_threadsafe_
#define gmtime _gmtime_not_threadsafe_ #define gmtime _gmtime_not_threadsafe_
#define localtime _localtime_not_threadsafe_ #define localtime _localtime_not_threadsafe_
#define ctime _ctime_is_not_threadsafe_ #define ctime _ctime_is_not_threadsafe_
#if defined(_WIN32) || defined(__sunos__) #if defined(_WIN32) || defined(__sunos__)
inline void sleepsecs(int s) { inline void sleepsecs(int s) {
boost::xtime xt; boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC); boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += s; xt.sec += s;
skipping to change at line 255 skipping to change at line 269
// measures up to 1024 seconds. or, 512 seconds with tdiff that is... // measures up to 1024 seconds. or, 512 seconds with tdiff that is...
inline unsigned curTimeMicros() { inline unsigned curTimeMicros() {
boost::xtime xt; boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC); boost::xtime_get(&xt, boost::TIME_UTC);
unsigned t = xt.nsec / 1000; unsigned t = xt.nsec / 1000;
unsigned secs = xt.sec % 1024; unsigned secs = xt.sec % 1024;
return secs*1000000 + t; return secs*1000000 + t;
} }
using namespace boost; using namespace boost;
typedef boost::mutex::scoped_lock boostlock;
typedef boost::recursive_mutex::scoped_lock recursive_boostlock; extern bool __destroyingStatics;
// If you create a local static instance of this class, that instance w
ill be destroyed
// before all global static objects are destroyed, so __destroyingStati
cs will be set
// to true before the global static variables are destroyed.
class StaticObserver : boost::noncopyable {
public:
~StaticObserver() { __destroyingStatics = true; }
};
// 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
// destroying them.
class mutex : boost::noncopyable {
public:
mutex() { new (_buf) boost::mutex(); }
~mutex() {
if( !__destroyingStatics ) {
boost().boost::mutex::~mutex();
}
}
class scoped_lock : boost::noncopyable {
public:
scoped_lock( mongo::mutex &m ) : _l( m.boost() ) {}
boost::mutex::scoped_lock &boost() { return _l; }
private:
boost::mutex::scoped_lock _l;
};
private:
boost::mutex &boost() { return *( boost::mutex * )( _buf ); }
char _buf[ sizeof( boost::mutex ) ];
};
typedef mongo::mutex::scoped_lock 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();
} }
Timer( unsigned long long start ) { Timer( unsigned long long start ) {
old = start; old = start;
} }
skipping to change at line 295 skipping to change at line 343
old = curTimeMicros64(); old = curTimeMicros64();
} }
private: private:
unsigned long long old; unsigned long long old;
}; };
/* /*
class DebugMutex : boost::noncopyable { class DebugMutex : boost::noncopyable {
friend class lock; friend class lock;
boost::mutex m; mongo::mutex m;
int locked; int locked;
public: public:
DebugMutex() : locked(0); { } DebugMutex() : locked(0); { }
bool isLocked() { return locked; } bool isLocked() { return locked; }
}; };
*/ */
//typedef boostlock lock; //typedef scoped_lock lock;
inline bool startsWith(const char *str, const char *prefix) { inline bool startsWith(const char *str, const char *prefix) {
size_t l = strlen(prefix); size_t l = strlen(prefix);
if ( strlen(str) < l ) return false; if ( strlen(str) < l ) return false;
return strncmp(str, prefix, l) == 0; return strncmp(str, prefix, l) == 0;
} }
inline bool endsWith(const char *p, const char *suffix) { inline bool endsWith(const char *p, const char *suffix) {
size_t a = strlen(p); size_t a = strlen(p);
size_t b = strlen(suffix); size_t b = strlen(suffix);
skipping to change at line 395 skipping to change at line 443
_val.reset( v ); _val.reset( v );
} }
private: private:
T _default; T _default;
boost::thread_specific_ptr<T> _val; boost::thread_specific_ptr<T> _val;
}; };
class ProgressMeter { class ProgressMeter {
public: public:
ProgressMeter( long long total , int secondsBetween = 3 , int check ProgressMeter( long long total , int secondsBetween = 3 , int check
Interval = 100 ) Interval = 100 ){
: _total( total ) , _secondsBetween( secondsBetween ) , _checkI reset( total , secondsBetween , checkInterval );
nterval( checkInterval ) , }
_done(0) , _hits(0) , _lastTime( (int) time(0) ){
ProgressMeter(){
_active = 0;
}
void reset( long long total , int secondsBetween = 3 , int checkInt
erval = 100 ){
_total = total;
_secondsBetween = secondsBetween;
_checkInterval = checkInterval;
_done = 0;
_hits = 0;
_lastTime = (int)time(0);
_active = 1;
}
void finished(){
_active = 0;
}
bool isActive(){
return _active;
} }
bool hit( int n = 1 ){ bool hit( int n = 1 ){
if ( ! _active ){
cout << "warning: hit on in-active ProgressMeter" << endl;
}
_done += n; _done += n;
_hits++; _hits++;
if ( _hits % _checkInterval ) if ( _hits % _checkInterval )
return false; return false;
int t = (int) time(0); int t = (int) time(0);
if ( t - _lastTime < _secondsBetween ) if ( t - _lastTime < _secondsBetween )
return false; return false;
if ( _total > 0 ){ if ( _total > 0 ){
skipping to change at line 426 skipping to change at line 501
} }
long long done(){ long long done(){
return _done; return _done;
} }
long long hits(){ long long hits(){
return _hits; return _hits;
} }
string toString() const {
if ( ! _active )
return "";
stringstream buf;
buf << _done << "/" << _total << " " << (_done*100)/_total << "
%";
return buf.str();
}
private: private:
bool _active;
long long _total; long long _total;
int _secondsBetween; int _secondsBetween;
int _checkInterval; int _checkInterval;
long long _done; long long _done;
long long _hits; long long _hits;
int _lastTime; int _lastTime;
}; };
class TicketHolder { class TicketHolder {
public: public:
TicketHolder( int num ){ TicketHolder( int num ){
_outof = num; _outof = num;
_num = num; _num = num;
} }
bool tryAcquire(){ bool tryAcquire(){
boostlock lk( _mutex ); scoped_lock lk( _mutex );
if ( _num <= 0 ){ if ( _num <= 0 ){
if ( _num < 0 ){ if ( _num < 0 ){
cerr << "DISASTER! in TicketHolder" << endl; cerr << "DISASTER! in TicketHolder" << endl;
} }
return false; return false;
} }
_num--; _num--;
return true; return true;
} }
void release(){ void release(){
boostlock lk( _mutex ); scoped_lock lk( _mutex );
_num++; _num++;
} }
void resize( int newSize ){ void resize( int newSize ){
boostlock lk( _mutex ); scoped_lock lk( _mutex );
int used = _outof - _num; int used = _outof - _num;
if ( used > newSize ){ if ( used > newSize ){
cout << "ERROR: can't resize since we're using (" << used < < ") more than newSize(" << newSize << ")" << endl; cout << "ERROR: can't resize since we're using (" << used < < ") more than newSize(" << newSize << ")" << endl;
return; return;
} }
_outof = newSize; _outof = newSize;
_num = _outof - used; _num = _outof - used;
} }
skipping to change at line 484 skipping to change at line 568
return _num; return _num;
} }
int used(){ int used(){
return _outof - _num; return _outof - _num;
} }
private: private:
int _outof; int _outof;
int _num; int _num;
boost::mutex _mutex; mongo::mutex _mutex;
}; };
class TicketHolderReleaser { class TicketHolderReleaser {
public: public:
TicketHolderReleaser( TicketHolder * holder ){ TicketHolderReleaser( TicketHolder * holder ){
_holder = holder; _holder = holder;
} }
~TicketHolderReleaser(){ ~TicketHolderReleaser(){
_holder->release(); _holder->release();
skipping to change at line 558 skipping to change at line 642
return _buf[0] == 0; return _buf[0] == 0;
} }
private: private:
size_t _size; size_t _size;
char * _buf; char * _buf;
}; };
ostream& operator<<( ostream &s, const ThreadSafeString &o ); ostream& operator<<( ostream &s, const ThreadSafeString &o );
inline bool isNumber( char c ) {
return c >= '0' && c <= '9';
}
// for convenience, '{' is greater than anything and stops number parsi
ng
inline int lexNumCmp( const char *s1, const char *s2 ) {
int nret = 0;
while( *s1 && *s2 ) {
bool p1 = ( *s1 == '{' );
bool p2 = ( *s2 == '{' );
if ( p1 && !p2 )
return 1;
if ( p2 && !p1 )
return -1;
bool n1 = isNumber( *s1 );
bool n2 = isNumber( *s2 );
if ( n1 && n2 ) {
if ( nret == 0 ) {
nret = *s1 > *s2 ? 1 : ( *s1 == *s2 ? 0 : -1 );
}
} else if ( n1 ) {
return 1;
} else if ( n2 ) {
return -1;
} else {
if ( nret ) {
return nret;
}
if ( *s1 > *s2 ) {
return 1;
} else if ( *s2 > *s1 ) {
return -1;
}
nret = 0;
}
++s1; ++s2;
}
if ( *s1 ) {
return 1;
} else if ( *s2 ) {
return -1;
}
return nret;
}
} // namespace mongo } // namespace mongo
 End of changes. 14 change blocks. 
14 lines changed or deleted 150 lines changed or added


 index.h   index.h 
skipping to change at line 62 skipping to change at line 62
/** optional op : compare 2 objects with regards to this index */ /** optional op : compare 2 objects with regards to this index */
virtual int compare( const BSONObj& l , const BSONObj& r ) const; virtual int compare( const BSONObj& l , const BSONObj& r ) const;
/** @return plugin */ /** @return plugin */
const IndexPlugin * getPlugin() const { return _plugin; } const IndexPlugin * getPlugin() const { return _plugin; }
const BSONObj& keyPattern() const; const BSONObj& keyPattern() const;
virtual IndexSuitability suitability( const BSONObj& query , const BSONObj& order ) const ; virtual IndexSuitability suitability( const BSONObj& query , const BSONObj& order ) const ;
virtual bool scanAndOrderRequired( const BSONObj& query , const BSO
NObj& order ) const ;
protected: protected:
const IndexPlugin * _plugin; const IndexPlugin * _plugin;
const IndexSpec * _spec; const IndexSpec * _spec;
}; };
/** /**
* this represents a plugin * this represents a plugin
* a plugin could be something like full text search, sparse index, etc ... * a plugin could be something like full text search, sparse index, etc ...
* 1 of these exists per type of index per server * 1 of these exists per type of index per server
* 1 IndexType is created per index using this plugin * 1 IndexType is created per index using this plugin
 End of changes. 1 change blocks. 
0 lines changed or deleted 3 lines changed or added


 instance.h   instance.h 
skipping to change at line 41 skipping to change at line 41
#define OPWRITE if( _diaglog.level & 1 ) _diaglog.write((char *) m.data, m. data->len); #define OPWRITE if( _diaglog.level & 1 ) _diaglog.write((char *) m.data, m. data->len);
#define OPREAD if( _diaglog.level & 2 ) _diaglog.readop((char *) m.data, m. data->len); #define OPREAD if( _diaglog.level & 2 ) _diaglog.readop((char *) m.data, m. data->len);
struct DiagLog { struct DiagLog {
ofstream *f; ofstream *f;
/* 0 = off; 1 = writes, 2 = reads, 3 = both /* 0 = off; 1 = writes, 2 = reads, 3 = both
7 = log a few reads, and all writes. 7 = log a few reads, and all writes.
*/ */
int level; int level;
boost::mutex mutex; mongo::mutex mutex;
DiagLog() : f(0) , level(0) { } DiagLog() : f(0) , level(0) { }
void init() { void init() {
if ( ! f && level ){ if ( ! f && level ){
log() << "diagLogging = " << level << endl; log() << "diagLogging = " << level << endl;
stringstream ss; stringstream ss;
ss << dbpath << "/diaglog." << hex << time(0); ss << dbpath << "/diaglog." << hex << time(0);
string name = ss.str(); string name = ss.str();
f = new ofstream(name.c_str(), ios::out | ios::binary); f = new ofstream(name.c_str(), ios::out | ios::binary);
if ( ! f->good() ) { if ( ! f->good() ) {
skipping to change at line 68 skipping to change at line 68
* @return old * @return old
*/ */
int setLevel( int newLevel ){ int setLevel( int newLevel ){
int old = level; int old = level;
level = newLevel; level = newLevel;
init(); init();
return old; return old;
} }
void flush() { void flush() {
if ( level ){ if ( level ){
boostlock lk(mutex); scoped_lock lk(mutex);
f->flush(); f->flush();
} }
} }
void write(char *data,int len) { void write(char *data,int len) {
if ( level & 1 ){ if ( level & 1 ){
boostlock lk(mutex); scoped_lock lk(mutex);
f->write(data,len); f->write(data,len);
} }
} }
void readop(char *data, int len) { void readop(char *data, int len) {
if ( level & 2 ) { if ( level & 2 ) {
bool log = (level & 4) == 0; bool log = (level & 4) == 0;
OCCASIONALLY log = true; OCCASIONALLY log = true;
if ( log ){ if ( log ){
boostlock lk(mutex); scoped_lock lk(mutex);
assert( f );
f->write(data,len); f->write(data,len);
} }
} }
} }
}; };
extern DiagLog _diaglog; extern DiagLog _diaglog;
/* we defer response until we unlock. don't want a blocked socket to /* we defer response until we unlock. don't want a blocked socket to
keep things locked. keep things locked.
 End of changes. 4 change blocks. 
4 lines changed or deleted 5 lines changed or added


 jsobj.h   jsobj.h 
skipping to change at line 996 skipping to change at line 996
NE = 0x9, NE = 0x9,
opSIZE = 0x0A, opSIZE = 0x0A,
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,
}; };
}; };
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 1312 skipping to change at line 1313
} }
void appendNumber( const string& fieldName , long long l ){ void appendNumber( const string& fieldName , long long l ){
static long long maxInt = (int)pow( 2.0 , 30.0 ); static long long maxInt = (int)pow( 2.0 , 30.0 );
static long long maxDouble = (long long)pow( 2.0 , 40.0 ); static long long maxDouble = (long long)pow( 2.0 , 40.0 );
if ( l < maxInt ) if ( l < maxInt )
append( fieldName.c_str() , (int)l ); append( fieldName.c_str() , (int)l );
else if ( l < maxDouble ) else if ( l < maxDouble )
append( fieldName.c_str() , (double)l ); append( fieldName.c_str() , (double)l );
append( fieldName.c_str() , l ); else
append( fieldName.c_str() , l );
} }
/** Append a double element */ /** Append a double element */
BSONObjBuilder& append(const char *fieldName, double n) { BSONObjBuilder& append(const char *fieldName, double n) {
b.append((char) NumberDouble); b.append((char) NumberDouble);
b.append(fieldName); b.append(fieldName);
b.append(n); b.append(n);
return *this; return *this;
} }
skipping to change at line 1649 skipping to change at line 1651
BufBuilder &b; BufBuilder &b;
BufBuilder buf_; BufBuilder buf_;
int offset_; int offset_;
BSONObjBuilderValueStream s_; BSONObjBuilderValueStream s_;
BSONSizeTracker * _tracker; BSONSizeTracker * _tracker;
}; };
class BSONArrayBuilder : boost::noncopyable{ class BSONArrayBuilder : boost::noncopyable{
public: public:
BSONArrayBuilder() :i(0), b() {} BSONArrayBuilder() : _i(0), _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().c_str());
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);
} }
BSONArray arr(){ return BSONArray(b.obj()); } void appendNull() {
_b.appendNull(num().c_str());
}
BSONArray arr(){ return BSONArray(_b.obj()); }
BSONObj done() { return _b.done(); }
template <typename T>
BSONArrayBuilder& append(const char *name, const T& x){
fill( name );
append( x );
return *this;
}
BufBuilder &subobjStart( const char *name ) {
fill( name );
return _b.subobjStart( num().c_str() );
}
BufBuilder &subarrayStart( const char *name ) {
fill( name );
return _b.subarrayStart( num().c_str() );
}
void appendArray( const char *name, BSONObj subObj ) {
fill( name );
_b.appendArray( num().c_str(), subObj );
}
void appendAs( const BSONElement &e, const char *name ) {
fill( name );
append( e );
}
private: private:
string num(){ return b.numStr(i++); } void fill( const char *name ) {
int i; char *r;
BSONObjBuilder b; int n = strtol( name, &r, 10 );
uassert( 13048, "can't append to array using string field name"
, !*r );
while( _i < n )
append( nullElt() );
}
static BSONElement nullElt() {
static BSONObj n = nullObj();
return n.firstElement();
}
static BSONObj nullObj() {
BSONObjBuilder b;
b.appendNull( "" );
return b.obj();
}
string num(){ return _b.numStr(_i++); }
int _i;
BSONObjBuilder _b;
}; };
/** iterator for a BSONObj /** iterator for a BSONObj
Note each BSONObj ends with an EOO element: so you will get more() o n an empty Note each BSONObj ends with an EOO element: so you will get more() o n an empty
object, although next().eoo() will be true. object, although next().eoo() will be true.
todo: we may want to make a more stl-like iterator interface for thi s todo: we may want to make a more stl-like iterator interface for thi s
with things like begin() and end() with things like begin() and end()
*/ */
skipping to change at line 1963 skipping to change at line 2018
s.insert( it.next() ); s.insert( it.next() );
return s; return s;
} }
class BSONObjIteratorSorted { class BSONObjIteratorSorted {
public: public:
BSONObjIteratorSorted( const BSONObj& o ); BSONObjIteratorSorted( const BSONObj& o );
~BSONObjIteratorSorted(){ ~BSONObjIteratorSorted(){
assert( _fields ); assert( _fields );
delete _fields; delete[] _fields;
_fields = 0; _fields = 0;
} }
bool more(){ bool more(){
return _cur < _nfields; return _cur < _nfields;
} }
BSONElement next(){ BSONElement next(){
assert( _fields ); assert( _fields );
if ( _cur < _nfields ) if ( _cur < _nfields )
 End of changes. 8 change blocks. 
10 lines changed or deleted 66 lines changed or added


 lasterror.h   lasterror.h 
skipping to change at line 103 skipping to change at line 103
// disable causes get() to return 0. // disable causes get() to return 0.
LastError *disableForCommand(); // only call once per command invoc ation! LastError *disableForCommand(); // only call once per command invoc ation!
private: private:
ThreadLocalValue<int> _id; ThreadLocalValue<int> _id;
boost::thread_specific_ptr<LastError> _tl; boost::thread_specific_ptr<LastError> _tl;
struct Status { struct Status {
time_t time; time_t time;
LastError *lerr; LastError *lerr;
}; };
static boost::mutex _idsmutex; static mongo::mutex _idsmutex;
map<int,Status> _ids; map<int,Status> _ids;
} lastError; } lastError;
inline void raiseError(int code , const char *msg) { inline void raiseError(int code , const char *msg) {
LastError *le = lastError.get(); LastError *le = lastError.get();
if ( le == 0 ) { if ( le == 0 ) {
DEV log() << "warning: lastError==0 can't report:" << msg << '\ n'; DEV log() << "warning: lastError==0 can't report:" << msg << '\ n';
} else if ( le->disabled ) { } else if ( le->disabled ) {
log() << "lastError disabled, can't report: " << msg << endl; log() << "lastError disabled, can't report: " << msg << endl;
} else { } else {
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 log.h   log.h 
skipping to change at line 121 skipping to change at line 121
virtual Nullstream& operator<< (ios_base& (*hex)(ios_base&)) { virtual Nullstream& operator<< (ios_base& (*hex)(ios_base&)) {
return *this; return *this;
} }
virtual void flush(){} virtual void flush(){}
}; };
extern Nullstream nullstream; extern Nullstream nullstream;
#define LOGIT { ss << x; return *this; } #define LOGIT { ss << x; return *this; }
class Logstream : public Nullstream { class Logstream : public Nullstream {
static boost::mutex &mutex; static mongo::mutex mutex;
static int doneSetup; static int doneSetup;
stringstream ss; stringstream ss;
public: public:
static int magicNumber(){ static int magicNumber(){
return 1717; return 1717;
} }
void flush() { void flush() {
// this ensures things are sane // this ensures things are sane
if ( doneSetup == 1717 ){ if ( doneSetup == 1717 ){
boostlock lk(mutex); scoped_lock lk(mutex);
cout << ss.str(); cout << ss.str();
cout.flush(); cout.flush();
} }
ss.str(""); ss.str("");
} }
Logstream& operator<<(const char *x) LOGIT Logstream& operator<<(const char *x) LOGIT
Logstream& operator<<(char *x) LOGIT Logstream& operator<<(char *x) LOGIT
Logstream& operator<<(char x) LOGIT Logstream& operator<<(char x) LOGIT
Logstream& operator<<(int x) LOGIT Logstream& operator<<(int x) LOGIT
Logstream& operator<<(ExitCode x) LOGIT Logstream& operator<<(ExitCode x) LOGIT
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 matcher.h   matcher.h 
skipping to change at line 37 skipping to change at line 37
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;
pcrecpp::RE *re; shared_ptr< pcrecpp::RE > re;
bool isNot; bool isNot;
RegexMatcher() : re( 0 ), isNot() {} RegexMatcher() : isNot() {}
~RegexMatcher() {
delete re;
}
}; };
struct element_lt struct element_lt
{ {
bool operator()(const BSONElement& l, const BSONElement& r) const bool operator()(const BSONElement& l, const BSONElement& r) const
{ {
int x = (int) l.canonicalType() - (int) r.canonicalType(); int x = (int) l.canonicalType() - (int) r.canonicalType();
if ( x < 0 ) return true; if ( x < 0 ) return true;
else if ( x > 0 ) return false; else if ( x > 0 ) return false;
return compareElementValues(l,r) < 0; return compareElementValues(l,r) < 0;
skipping to change at line 72 skipping to change at line 69
ElementMatcher( BSONElement _e , int _op, bool _isNot ); ElementMatcher( BSONElement _e , int _op, bool _isNot );
ElementMatcher( BSONElement _e , int _op , const BSONObj& array, bo ol _isNot ); ElementMatcher( BSONElement _e , int _op , const BSONObj& array, bo ol _isNot );
~ElementMatcher() { } ~ElementMatcher() { }
BSONElement toMatch; BSONElement toMatch;
int compareOp; int compareOp;
bool isNot; bool isNot;
shared_ptr< set<BSONElement,element_lt> > myset; shared_ptr< set<BSONElement,element_lt> > myset;
shared_ptr< vector<RegexMatcher> > myregex;
// these are for specific operators // these are for specific operators
int mod; int mod;
int modm; int modm;
BSONType type; BSONType type;
shared_ptr<Matcher> subMatcher; shared_ptr<Matcher> subMatcher;
vector< shared_ptr<Matcher> > allMatchers; vector< shared_ptr<Matcher> > allMatchers;
}; };
class Where; // used for $where javascript eval class Where; // used for $where javascript eval
class DiskLoc; class DiskLoc;
struct MatchDetails {
MatchDetails(){
reset();
}
void reset(){
loadedObject = false;
elemMatchKey = 0;
}
string toString() const {
stringstream ss;
ss << "loadedObject: " << loadedObject << " ";
ss << "elemMatchKey: " << ( elemMatchKey ? elemMatchKey : "NULL
" ) << " ";
return ss.str();
}
bool loadedObject;
const char * elemMatchKey; // warning, this may go out of scope if
matched object does
};
/* Match BSON objects against a query pattern. /* Match BSON objects against a query pattern.
e.g. e.g.
db.foo.find( { a : 3 } ); db.foo.find( { a : 3 } );
{ a : 3 } is the pattern object. See wiki documentation for full in fo. { a : 3 } is the pattern object. See wiki documentation for full in fo.
GT/LT: GT/LT:
{ a : { $gt : 3 } } { a : { $gt : 3 } }
Not equal: Not equal:
{ a : { $ne : 3 } } { a : { $ne : 3 } }
TODO: we should rewrite the matcher to be more an AST style. TODO: we should rewrite the matcher to be more an AST style.
*/ */
class Matcher : boost::noncopyable { class Matcher : boost::noncopyable {
int matchesDotted( int matchesDotted(
const char *fieldName, const char *fieldName,
const BSONElement& toMatch, const BSONObj& obj, const BSONElement& toMatch, const BSONObj& obj,
int compareOp, const ElementMatcher& bm, bool isArr = false); int compareOp, const ElementMatcher& bm, bool isArr , MatchDeta ils * details );
int matchesNe( int matchesNe(
const char *fieldName, const char *fieldName,
const BSONElement &toMatch, const BSONObj &obj, const BSONElement &toMatch, const BSONObj &obj,
const ElementMatcher&bm); const ElementMatcher&bm, MatchDetails * details );
public: public:
static int opDirection(int op) { static int opDirection(int op) {
return op <= BSONObj::LTE ? -1 : 1; return op <= BSONObj::LTE ? -1 : 1;
} }
// Only specify constrainIndexKey if matches() will be called with // Only specify constrainIndexKey if matches() will be called with
// index keys having empty string field names. // index keys having empty string field names.
Matcher(const BSONObj &pattern, const BSONObj &constrainIndexKey = BSONObj()); Matcher(const BSONObj &pattern, const BSONObj &constrainIndexKey = BSONObj());
~Matcher(); ~Matcher();
bool matches(const BSONObj& j); bool matches(const BSONObj& j, MatchDetails * details = 0 );
bool keyMatch() const { return !all && !haveSize && !hasArray && !h aveNot; } bool keyMatch() const { return !all && !haveSize && !hasArray && !h aveNeg; }
bool atomic() const { return _atomic; } bool atomic() const { return _atomic; }
bool hasType( BSONObj::MatchType type ) const;
private: private:
void addBasic(const BSONElement &e, int c, bool isNot) { void addBasic(const BSONElement &e, int c, bool isNot) {
// TODO May want to selectively ignore these element types base d on op type. // TODO May want to selectively ignore these element types base d on op type.
if ( e.type() == MinKey || e.type() == MaxKey ) if ( e.type() == MinKey || e.type() == MaxKey )
return; return;
basics.push_back( ElementMatcher( e , c, isNot ) ); basics.push_back( ElementMatcher( e , c, isNot ) );
} }
void addRegex(const char *fieldName, const char *regex, const char *flags, bool isNot = false); void addRegex(const char *fieldName, const char *regex, const char *flags, bool isNot = false);
bool addOp( const BSONElement &e, const BSONElement &fe, bool isNot , const char *& regex, const char *&flags ); bool addOp( const BSONElement &e, const BSONElement &fe, bool isNot , const char *& regex, const char *&flags );
int valuesMatch(const BSONElement& l, const BSONElement& r, int op, const ElementMatcher& bm); int valuesMatch(const BSONElement& l, const BSONElement& r, int op, const ElementMatcher& bm);
Where *where; // set if query uses $where Where *where; // set if query uses $where
BSONObj jsobj; // the query pattern. e.g., { name : "joe" } BSONObj jsobj; // the query pattern. e.g., { name : "joe" }
BSONObj constrainIndexKey_; BSONObj constrainIndexKey_;
vector<ElementMatcher> basics; vector<ElementMatcher> basics;
bool haveSize; bool haveSize;
bool all; bool all;
bool hasArray; bool hasArray;
bool haveNot; bool haveNeg;
/* $atomic - if true, a multi document operation (some removes, upd ates) /* $atomic - if true, a multi document operation (some removes, upd ates)
should be done atomically. in that case, we do not yi eld - should be done atomically. in that case, we do not yi eld -
i.e. we stay locked the whole time. i.e. we stay locked the whole time.
http://www.mongodb.org/display/DOCS/Removing[ http://www.mongodb.org/display/DOCS/Removing[
*/ */
bool _atomic; bool _atomic;
RegexMatcher regexs[4]; RegexMatcher regexs[4];
int nRegex; int nRegex;
skipping to change at line 171 skipping to change at line 191
vector< shared_ptr< BSONObjBuilder > > _builders; vector< shared_ptr< BSONObjBuilder > > _builders;
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 , bool * loa ded = 0 ); bool matches(const BSONObj &key, const DiskLoc &recLoc , MatchDetai ls * 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. 11 change blocks. 
11 lines changed or deleted 33 lines changed or added


 miniwebserver.h   miniwebserver.h 
skipping to change at line 20 skipping to change at line 20
* *
* 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
#include "../stdafx.h"
#include "message.h" #include "message.h"
#include "../db/jsobj.h"
namespace mongo { namespace mongo {
class MiniWebServer { class MiniWebServer {
public: public:
MiniWebServer(); MiniWebServer();
virtual ~MiniWebServer() {} virtual ~MiniWebServer() {}
bool init(const string &ip, int _port); bool init(const string &ip, int _port);
void run(); void run();
skipping to change at line 48 skipping to change at line 50
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; } 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( map<string,string> & 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(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 port;
int sock; int sock;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 4 change blocks. 
1 lines changed or deleted 6 lines changed or added


 namespace.h   namespace.h 
skipping to change at line 348 skipping to change at line 348
multiKeyIndexBits |= (((unsigned long long) 1) << i); multiKeyIndexBits |= (((unsigned long long) 1) << i);
} }
void clearIndexIsMultikey(int i) { void clearIndexIsMultikey(int i) {
dassert( i < NIndexesMax ); dassert( i < NIndexesMax );
multiKeyIndexBits &= ~(((unsigned long long) 1) << i); multiKeyIndexBits &= ~(((unsigned long long) 1) << i);
} }
/* add a new index. does not add to system.indexes etc. - just to NamespaceDetails. /* add a new index. does not add to system.indexes etc. - just to NamespaceDetails.
caller must populate returned object. caller must populate returned object.
*/ */
IndexDetails& addIndex(const char *thisns); IndexDetails& addIndex(const char *thisns, bool resetTransient=true );
void aboutToDeleteAnIndex() { void aboutToDeleteAnIndex() {
flags &= ~Flag_HaveIdIndex; flags &= ~Flag_HaveIdIndex;
} }
void cappedDisallowDelete() { void cappedDisallowDelete() {
flags |= Flag_CappedDisallowDelete; flags |= Flag_CappedDisallowDelete;
} }
/* returns index of the first index in which the field is present. -1 if not present. */ /* returns index of the first index in which the field is present. -1 if not present. */
skipping to change at line 508 skipping to change at line 508
set<string>& indexKeys() { set<string>& indexKeys() {
DEV assertInWriteLock(); DEV assertInWriteLock();
if ( !_keysComputed ) if ( !_keysComputed )
computeIndexKeys(); computeIndexKeys();
return _indexKeys; return _indexKeys;
} }
/* IndexSpec caching */ /* IndexSpec caching */
private: private:
map<const IndexDetails*,IndexSpec> _indexSpecs; map<const IndexDetails*,IndexSpec> _indexSpecs;
static boost::mutex _isMutex; static mongo::mutex _isMutex;
public: public:
const IndexSpec& getIndexSpec( const IndexDetails * details ){ const IndexSpec& getIndexSpec( const IndexDetails * details ){
IndexSpec& spec = _indexSpecs[details]; IndexSpec& spec = _indexSpecs[details];
if ( ! spec._finishedInit ){ if ( ! spec._finishedInit ){
boostlock lk(_isMutex); scoped_lock lk(_isMutex);
if ( ! spec._finishedInit ){ if ( ! spec._finishedInit ){
spec.reset( details ); spec.reset( details );
assert( spec._finishedInit ); assert( spec._finishedInit );
} }
} }
return spec; return spec;
} }
/* query cache (for query optimizer) ------------------------------ ------- */ /* query cache (for query optimizer) ------------------------------ ------- */
private: private:
int _qcWriteCount; int _qcWriteCount;
map< QueryPattern, pair< BSONObj, long long > > _qcCache; map< QueryPattern, pair< BSONObj, long long > > _qcCache;
public: public:
static boost::mutex _qcMutex; static mongo::mutex _qcMutex;
/* you must be in the qcMutex when calling this (and using the retu rned val): */ /* you must be in the qcMutex when calling this (and using the retu rned val): */
static NamespaceDetailsTransient& get_inlock(const char *ns) { static NamespaceDetailsTransient& get_inlock(const char *ns) {
return _get(ns); return _get(ns);
} }
void clearQueryCache() { // public for unit tests void clearQueryCache() { // public for unit tests
_qcCache.clear(); _qcCache.clear();
_qcWriteCount = 0; _qcWriteCount = 0;
} }
/* you must notify the cache if you are doing writes, as query plan optimality will change */ /* you must notify the cache if you are doing writes, as query plan optimality will change */
void notifyOfWriteOp() { void notifyOfWriteOp() {
 End of changes. 4 change blocks. 
4 lines changed or deleted 4 lines changed or added


 optime.h   optime.h 
skipping to change at line 23 skipping to change at line 23
* 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
#include "../db/concurrency.h" #include "../db/concurrency.h"
namespace mongo { namespace mongo {
void exitCleanly( int code );
/* Operation sequence #. A combination of current second plus an ordin al value. /* Operation sequence #. A combination of current second plus an ordin al value.
*/ */
struct ClockSkewException : public DBException {
virtual const char* what() const throw() { return "clock skew excep
tion"; }
virtual int getCode(){ return 20001; }
};
#pragma pack(4) #pragma pack(4)
class OpTime { class OpTime {
unsigned i; unsigned i;
unsigned secs; unsigned secs;
static OpTime last; static OpTime last;
public: public:
static void setLast(const Date_t &date) {
last = OpTime(date);
}
unsigned getSecs() const { unsigned getSecs() const {
return secs; return secs;
} }
OpTime(Date_t date) { OpTime(Date_t date) {
reinterpret_cast<unsigned long long&>(*this) = date.millis; reinterpret_cast<unsigned long long&>(*this) = date.millis;
} }
OpTime(unsigned long long date) { OpTime(unsigned long long date) {
reinterpret_cast<unsigned long long&>(*this) = date; reinterpret_cast<unsigned long long&>(*this) = date;
} }
OpTime(unsigned a, unsigned b) { OpTime(unsigned a, unsigned b) {
secs = a; secs = a;
i = b; i = b;
} }
OpTime() { OpTime() {
secs = 0; secs = 0;
i = 0; i = 0;
} }
static OpTime now() { static OpTime now() {
unsigned t = (unsigned) time(0); unsigned t = (unsigned) time(0);
// DEV assertInWriteLock(); // DEV assertInWriteLock();
if ( t < last.secs ){
bool toLog = false;
ONCE toLog = true;
RARELY toLog = true;
if ( last.i & 0x80000000 )
toLog = true;
if ( toLog )
log() << "clock skew detected prev: " << last.secs <<
" now: " << t << " trying to handle..." << endl;
if ( last.i & 0x80000000 ) {
log() << "ERROR Large clock skew detected, shutting dow
n" << endl;
throw ClockSkewException();
}
t = last.secs;
}
if ( last.secs == t ) { if ( last.secs == t ) {
last.i++; last.i++;
return last; return last;
} }
last = OpTime(t, 1); last = OpTime(t, 1);
return last; return last;
} }
/* We store OpTime's in the database as BSON Date datatype -- we ne eded some sort of /* We store OpTime's in the database as BSON Date datatype -- we ne eded some sort of
64 bit "container" for these values. While these are not really " Dates", that seems a 64 bit "container" for these values. While these are not really " Dates", that seems a
 End of changes. 4 change blocks. 
0 lines changed or deleted 26 lines changed or added


 query.h   query.h 
skipping to change at line 105 skipping to change at line 105
} }
if ( mod ) if ( mod )
return 3; return 3;
return 4; return 4;
} }
}; };
/* returns true if an existing object was updated, false if no existing object was found. /* returns true if an existing object was updated, false if no existing object was found.
multi - update multiple objects - mostly useful with things like $se t multi - update multiple objects - mostly useful with things like $se t
god - allow access to system namespaces and don't yield
*/ */
UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BS ONObj pattern, bool upsert, bool multi , bool logop , OpDebug& debug ); UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BS ONObj pattern, bool upsert, bool multi , bool logop , OpDebug& debug );
// If justOne is true, deletedId is set to the id of the deleted object . // If justOne is true, deletedId is set to the id of the deleted object .
long long deleteObjects(const char *ns, BSONObj pattern, bool justOne, bool logop = false, bool god=false); long long deleteObjects(const char *ns, BSONObj pattern, bool justOne, bool logop = false, bool god=false);
long long runCount(const char *ns, const BSONObj& cmd, string& err); long long runCount(const char *ns, const BSONObj& cmd, string& err);
auto_ptr< QueryResult > runQuery(Message& m, QueryMessage& q, CurOp& cu rop ); auto_ptr< QueryResult > runQuery(Message& m, QueryMessage& q, CurOp& cu rop );
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 queryoptimizer.h   queryoptimizer.h 
skipping to change at line 28 skipping to change at line 28
#pragma once #pragma once
#include "cursor.h" #include "cursor.h"
#include "jsobj.h" #include "jsobj.h"
#include "queryutil.h" #include "queryutil.h"
namespace mongo { namespace mongo {
class IndexDetails; class IndexDetails;
class IndexType;
class QueryPlan : boost::noncopyable { class QueryPlan : boost::noncopyable {
public: public:
QueryPlan(NamespaceDetails *_d, QueryPlan(NamespaceDetails *_d,
int _idxNo, // -1 = no index int _idxNo, // -1 = no index
const FieldRangeSet &fbs, const FieldRangeSet &fbs,
const BSONObj &order, const BSONObj &order,
const BSONObj &startKey = BSONObj(), const BSONObj &startKey = BSONObj(),
const BSONObj &endKey = BSONObj() , const BSONObj &endKey = BSONObj() ,
string special="" ); string special="" );
skipping to change at line 75 skipping to change at line 77
const BSONObj &order_; const BSONObj &order_;
const IndexDetails *index_; const IndexDetails *index_;
bool optimal_; bool optimal_;
bool scanAndOrderRequired_; bool scanAndOrderRequired_;
bool exactKeyMatch_; bool exactKeyMatch_;
int direction_; int direction_;
BoundList indexBounds_; BoundList indexBounds_;
bool endKeyInclusive_; bool endKeyInclusive_;
bool unhelpful_; bool unhelpful_;
string _special; string _special;
IndexType * _type;
}; };
// Inherit from this interface to implement a new query operation. // Inherit from this interface to implement a new query operation.
// The query optimizer will clone the QueryOp that is provided, giving // The query optimizer will clone the QueryOp that is provided, giving
// each clone its own query plan. // each clone its own query plan.
class QueryOp { class QueryOp {
public: public:
QueryOp() : complete_(), qp_(), error_() {} QueryOp() : complete_(), qp_(), error_() {}
virtual ~QueryOp() {} virtual ~QueryOp() {}
 End of changes. 2 change blocks. 
0 lines changed or deleted 3 lines changed or added


 queryutil.h   queryutil.h 
skipping to change at line 53 skipping to change at line 53
return ( cmp < 0 || ( cmp == 0 && lower_.inclusive_ && upper_.i nclusive_ ) ); return ( cmp < 0 || ( cmp == 0 && lower_.inclusive_ && upper_.i nclusive_ ) );
} }
}; };
// range of a field's value that may be determined from query -- used t o // range of a field's value that may be determined from query -- used t o
// determine index limits // determine index limits
class FieldRange { class FieldRange {
public: public:
FieldRange( const BSONElement &e = BSONObj().firstElement() , bool isNot=false , bool optimize=true ); FieldRange( const BSONElement &e = BSONObj().firstElement() , bool isNot=false , bool optimize=true );
const FieldRange &operator&=( const FieldRange &other ); const FieldRange &operator&=( const FieldRange &other );
const FieldRange &operator|=( const FieldRange &other );
BSONElement min() const { assert( !empty() ); return intervals_[ 0 ].lower_.bound_; } BSONElement min() const { assert( !empty() ); return intervals_[ 0 ].lower_.bound_; }
BSONElement max() const { assert( !empty() ); return intervals_[ in tervals_.size() - 1 ].upper_.bound_; } BSONElement max() const { assert( !empty() ); return intervals_[ in tervals_.size() - 1 ].upper_.bound_; }
bool minInclusive() const { assert( !empty() ); return intervals_[ 0 ].lower_.inclusive_; } bool minInclusive() const { assert( !empty() ); return intervals_[ 0 ].lower_.inclusive_; }
bool maxInclusive() const { assert( !empty() ); return intervals_[ intervals_.size() - 1 ].upper_.inclusive_; } bool maxInclusive() const { assert( !empty() ); return intervals_[ intervals_.size() - 1 ].upper_.inclusive_; }
bool equality() const { bool equality() const {
return return
!empty() && !empty() &&
min().woCompare( max(), false ) == 0 && min().woCompare( max(), false ) == 0 &&
maxInclusive() && maxInclusive() &&
minInclusive(); minInclusive();
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 queue.h   queue.h 
skipping to change at line 33 skipping to change at line 33
#include <queue> #include <queue>
namespace mongo { namespace mongo {
/** /**
* simple blocking queue * simple blocking queue
*/ */
template<typename T> class BlockingQueue : boost::noncopyable { template<typename T> class BlockingQueue : boost::noncopyable {
public: public:
void push(T const& t){ void push(T const& t){
boostlock l( _lock ); scoped_lock l( _lock );
_queue.push( t ); _queue.push( t );
_condition.notify_one(); _condition.notify_one();
} }
bool empty() const { bool empty() const {
boostlock l( _lock ); scoped_lock l( _lock );
return _queue.empty(); return _queue.empty();
} }
bool tryPop( T & t ){ bool tryPop( T & t ){
boostlock l( _lock ); scoped_lock l( _lock );
if ( _queue.empty() ) if ( _queue.empty() )
return false; return false;
t = _queue.front(); t = _queue.front();
_queue.pop(); _queue.pop();
return true; return true;
} }
T blockingPop(){ T blockingPop(){
boostlock l( _lock ); scoped_lock l( _lock );
while( _queue.empty() ) while( _queue.empty() )
_condition.wait( l ); _condition.wait( l.boost() );
T t = _queue.front(); T t = _queue.front();
_queue.pop(); _queue.pop();
return t; return t;
} }
private: private:
std::queue<T> _queue; std::queue<T> _queue;
mutable boost::mutex _lock; mutable mongo::mutex _lock;
boost::condition _condition; boost::condition _condition;
}; };
} }
 End of changes. 6 change blocks. 
6 lines changed or deleted 6 lines changed or added


 reccache.h   reccache.h 
skipping to change at line 51 skipping to change at line 51
Node(void* _data) : data((char *) _data) { dirty = false; newer = 0 ; } Node(void* _data) : data((char *) _data) { dirty = false; newer = 0 ; }
~Node() { ~Node() {
free(data); free(data);
data = 0; data = 0;
} }
char *data; char *data;
DiskLoc loc; DiskLoc loc;
bool dirty; bool dirty;
Node *older, *newer; // lru Node *older, *newer; // lru
}; };
boost::mutex &rcmutex; // mainly to coordinate with the lazy writer thr ead mongo::mutex rcmutex; // mainly to coordinate with the lazy writer thre ad
unsigned recsize; unsigned recsize;
map<DiskLoc, Node*> m; // the cache map<DiskLoc, Node*> m; // the cache
Node *newest, *oldest; Node *newest, *oldest;
unsigned nnodes; unsigned nnodes;
set<DiskLoc> dirtyl; set<DiskLoc> dirtyl;
vector<BasicRecStore*> stores; // DiskLoc::a() indicates the index into this vector vector<BasicRecStore*> stores; // DiskLoc::a() indicates the index into this vector
map<string, BasicRecStore*> storesByNsKey; // nskey -> BasicRecStore* map<string, BasicRecStore*> storesByNsKey; // nskey -> BasicRecStore*
public: public:
static unsigned MAXNODES; static unsigned MAXNODES;
enum BaseValue { Base = 10000 }; enum BaseValue { Base = 10000 };
skipping to change at line 136 skipping to change at line 136
fileofs fileOfs(DiskLoc d) { fileofs fileOfs(DiskLoc d) {
return ((fileofs) d.getOfs()) * recsize; return ((fileofs) d.getOfs()) * recsize;
} }
void dump(); void dump();
void _ejectOld(); void _ejectOld();
public: public:
/* all public functions (except constructor) should use the mutex */ /* all public functions (except constructor) should use the mutex */
RecCache(unsigned recsz) : rcmutex( *( new boost::mutex() ) ), recsize( recsz) { RecCache(unsigned recsz) : recsize(recsz) {
nnodes = 0; nnodes = 0;
newest = oldest = 0; newest = oldest = 0;
} }
/* call this after doing some work, after you are sure you are done wit h modifications. /* call this after doing some work, after you are sure you are done wit h modifications.
we call it from dbunlocking(). we call it from dbunlocking().
*/ */
void ejectOld() { void ejectOld() {
if( nnodes > MAXNODES ) // just enough here to be inlineable for sp eed reasons. _ejectOld does the real work if( nnodes > MAXNODES ) // just enough here to be inlineable for sp eed reasons. _ejectOld does the real work
_ejectOld(); _ejectOld();
skipping to change at line 158 skipping to change at line 158
/* bg writer thread invokes this */ /* bg writer thread invokes this */
void writeLazily(); void writeLazily();
/* Note that this may be called BEFORE the actual writing to the node /* Note that this may be called BEFORE the actual writing to the node
takes place. We do flushing later on a dbunlocking() call, which ha ppens takes place. We do flushing later on a dbunlocking() call, which ha ppens
after the writing. after the writing.
*/ */
void dirty(DiskLoc d) { void dirty(DiskLoc d) {
assert( d.a() >= Base ); assert( d.a() >= Base );
boostlock lk(rcmutex); scoped_lock lk(rcmutex);
map<DiskLoc, Node*>::iterator i = m.find(d); map<DiskLoc, Node*>::iterator i = m.find(d);
if( i != m.end() ) { if( i != m.end() ) {
Node *n = i->second; Node *n = i->second;
if( !n->dirty ) { if( !n->dirty ) {
n->dirty = true; n->dirty = true;
dirtyl.insert(n->loc); dirtyl.insert(n->loc);
} }
} }
} }
char* get(DiskLoc d, unsigned len) { char* get(DiskLoc d, unsigned len) {
assert( d.a() >= Base ); assert( d.a() >= Base );
assert( len == recsize ); assert( len == recsize );
boostlock lk(rcmutex); scoped_lock lk(rcmutex);
map<DiskLoc, Node*>::iterator i = m.find(d); map<DiskLoc, Node*>::iterator i = m.find(d);
if( i != m.end() ) { if( i != m.end() ) {
touch(i->second); touch(i->second);
return i->second->data; return i->second->data;
} }
Node *n = mkNode(); Node *n = mkNode();
n->loc = d; n->loc = d;
store(d).get(fileOfs(d), n->data, recsize); // could throw exceptio n store(d).get(fileOfs(d), n->data, recsize); // could throw exceptio n
m.insert( pair<DiskLoc, Node*>(d, n) ); m.insert( pair<DiskLoc, Node*>(d, n) );
return n->data; return n->data;
} }
void drop(const char *ns); void drop(const char *ns);
DiskLoc insert(const char *ns, const void *obuf, int len, bool god) { DiskLoc insert(const char *ns, const void *obuf, int len, bool god) {
boostlock lk(rcmutex); scoped_lock lk(rcmutex);
BasicRecStore& rs = store(ns); BasicRecStore& rs = store(ns);
fileofs o = rs.insert((const char *) obuf, len); fileofs o = rs.insert((const char *) obuf, len);
assert( o % recsize == 0 ); assert( o % recsize == 0 );
fileofs recnum = o / recsize; fileofs recnum = o / recsize;
massert( 10377 , "RecCache file too large?", recnum <= 0x7fffffff ); massert( 10377 , "RecCache file too large?", recnum <= 0x7fffffff );
Node *n = mkNode(); Node *n = mkNode();
memcpy(n->data, obuf, len); memcpy(n->data, obuf, len);
DiskLoc d(rs.fileNumber + Base, (int) recnum); DiskLoc d(rs.fileNumber + Base, (int) recnum);
n->loc = d; n->loc = d;
m[d] = n; m[d] = n;
 End of changes. 5 change blocks. 
5 lines changed or deleted 5 lines changed or added


 repl.h   repl.h 
skipping to change at line 35 skipping to change at line 35
local.oplog.$<source> local.oplog.$<source>
local.oplog.$main is the default local.oplog.$main is the default
*/ */
#pragma once #pragma once
#include "pdfile.h" #include "pdfile.h"
#include "db.h" #include "db.h"
#include "dbhelpers.h" #include "dbhelpers.h"
#include "query.h" #include "query.h"
#include "queryoptimizer.h"
#include "../client/dbclient.h" #include "../client/dbclient.h"
#include "../util/optime.h" #include "../util/optime.h"
namespace mongo { namespace mongo {
class DBClientConnection; class DBClientConnection;
class DBClientCursor; class DBClientCursor;
skipping to change at line 200 skipping to change at line 201
void forceResync( const char *requester ); void forceResync( const char *requester );
}; };
/* Write operation to the log (local.oplog.$main) /* Write operation to the log (local.oplog.$main)
"i" insert "i" insert
"u" update "u" update
"d" delete "d" delete
"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 char *logNs, const BSONObj& obj, BSONObj *patt, bool *b, const OpTime &ts);
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() { imp_.clear(); } void reset() { imp_.clear(); }
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 ) {
skipping to change at line 342 skipping to change at line 342
MemIds memModIds_; MemIds memModIds_;
DbIds dbIds_; DbIds dbIds_;
DbIds dbModIds_; DbIds dbModIds_;
bool inMem_; bool inMem_;
int maxMem_; int maxMem_;
}; };
bool anyReplEnabled(); bool anyReplEnabled();
void appendReplicationInfo( BSONObjBuilder& result , bool authed , int level = 0 ); void appendReplicationInfo( BSONObjBuilder& result , bool authed , int level = 0 );
void replCheckCloseDatabase( Database * db );
extern int __findingStartInitialTimeout; // configurable for testing
class FindingStartCursor {
public:
FindingStartCursor( const QueryPlan & qp ) :
_qp( qp ),
_findingStart( true ),
_findingStartMode(),
_findingStartTimer( 0 ),
_findingStartCursor( 0 )
{ init(); }
bool done() const { return !_findingStart; }
auto_ptr< Cursor > cRelease() { return _c; }
void next() {
if ( !_findingStartCursor || !_findingStartCursor->c->ok() ) {
_findingStart = false;
_c = _qp.newCursor(); // on error, start from beginning
destroyClientCursor();
return;
}
switch( _findingStartMode ) {
case Initial: {
if ( !_matcher->matches( _findingStartCursor->c->currKe
y(), _findingStartCursor->c->currLoc() ) ) {
_findingStart = false; // found first record out of
query range, so scan normally
_c = _qp.newCursor( _findingStartCursor->c->currLoc
() );
destroyClientCursor();
return;
}
_findingStartCursor->c->advance();
RARELY {
if ( _findingStartTimer.seconds() >= __findingStart
InitialTimeout ) {
createClientCursor( startLoc( _findingStartCurs
or->c->currLoc() ) );
_findingStartMode = FindExtent;
return;
}
}
maybeRelease();
return;
}
case FindExtent: {
if ( !_matcher->matches( _findingStartCursor->c->currKe
y(), _findingStartCursor->c->currLoc() ) ) {
_findingStartMode = InExtent;
return;
}
DiskLoc prev = prevLoc( _findingStartCursor->c->currLoc
() );
if ( prev.isNull() ) { // hit beginning, so start scann
ing from here
createClientCursor();
_findingStartMode = InExtent;
return;
}
// There might be a more efficient implementation than
creating new cursor & client cursor each time,
// not worrying about that for now
createClientCursor( prev );
maybeRelease();
return;
}
case InExtent: {
if ( _matcher->matches( _findingStartCursor->c->currKey
(), _findingStartCursor->c->currLoc() ) ) {
_findingStart = false; // found first record in que
ry range, so scan normally
_c = _qp.newCursor( _findingStartCursor->c->currLoc
() );
destroyClientCursor();
return;
}
_findingStartCursor->c->advance();
maybeRelease();
return;
}
default: {
massert( 12600, "invalid _findingStartMode", false );
}
}
}
private:
enum FindingStartMode { Initial, FindExtent, InExtent };
const QueryPlan &_qp;
bool _findingStart;
FindingStartMode _findingStartMode;
auto_ptr< CoveredIndexMatcher > _matcher;
Timer _findingStartTimer;
ClientCursor * _findingStartCursor;
auto_ptr< Cursor > _c;
DiskLoc startLoc( const DiskLoc &rec ) {
Extent *e = rec.rec()->myExtent( rec );
if ( e->myLoc != _qp.nsd()->capExtent )
return e->firstRecord;
// 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
// doesn't matter if we start the extent scan with capFirstNewR
ecord.
return _qp.nsd()->capFirstNewRecord;
}
DiskLoc prevLoc( const DiskLoc &rec ) {
Extent *e = rec.rec()->myExtent( rec );
if ( e->xprev.isNull() )
e = _qp.nsd()->lastExtent.ext();
else
e = e->xprev.ext();
if ( e->myLoc != _qp.nsd()->capExtent )
return e->firstRecord;
return DiskLoc(); // reached beginning of collection
}
void createClientCursor( const DiskLoc &startLoc = DiskLoc() ) {
auto_ptr<Cursor> c = _qp.newCursor( startLoc );
_findingStartCursor = new ClientCursor(c, _qp.ns(), false);
}
void destroyClientCursor() {
if ( _findingStartCursor ) {
ClientCursor::erase( _findingStartCursor->cursorid );
_findingStartCursor = 0;
}
}
void maybeRelease() {
RARELY {
CursorId id = _findingStartCursor->cursorid;
_findingStartCursor->updateLocation();
{
dbtemprelease t;
}
_findingStartCursor = ClientCursor::find( id, false );
}
}
void init() {
// Use a ClientCursor here so we can release db mutex while sca
nning
// oplog (can take quite a while with large oplogs).
auto_ptr<Cursor> c = _qp.newReverseCursor();
_findingStartCursor = new ClientCursor(c, _qp.ns(), false);
_findingStartTimer.reset();
_findingStartMode = Initial;
BSONElement tsElt = _qp.query()[ "ts" ];
massert( 13044, "no ts field in query", !tsElt.eoo() );
BSONObjBuilder b;
b.append( tsElt );
BSONObj tsQuery = b.obj();
_matcher.reset(new CoveredIndexMatcher(tsQuery, _qp.indexKey())
);
}
};
} // namespace mongo } // namespace mongo
 End of changes. 3 change blocks. 
1 lines changed or deleted 157 lines changed or added


 request.h   request.h 
skipping to change at line 127 skipping to change at line 127
static ClientInfo * get( int clientId = 0 , bool create = true ); static ClientInfo * get( int clientId = 0 , bool create = true );
private: private:
int _id; int _id;
set<string> _a; set<string> _a;
set<string> _b; set<string> _b;
set<string> * _cur; set<string> * _cur;
set<string> * _prev; set<string> * _prev;
int _lastAccess; int _lastAccess;
static boost::mutex _clientsLock; static mongo::mutex _clientsLock;
static ClientCache _clients; static ClientCache _clients;
static boost::thread_specific_ptr<ClientInfo> _tlInfo; static boost::thread_specific_ptr<ClientInfo> _tlInfo;
}; };
} }
#include "strategy.h" #include "strategy.h"
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 security.h   security.h 
skipping to change at line 40 skipping to change at line 40
// --noauth cmd line option // --noauth cmd line option
extern bool noauth; extern bool noauth;
/* for a particular db */ /* for a particular db */
struct Auth { struct Auth {
Auth() { level = 0; } Auth() { level = 0; }
int level; int level;
}; };
class AuthenticationInfo : boost::noncopyable { class AuthenticationInfo : boost::noncopyable {
mongo::mutex _lock;
map<string, Auth> m; // dbname -> auth map<string, Auth> m; // dbname -> auth
static int warned; static int warned;
public: public:
bool isLocalHost; bool isLocalHost;
AuthenticationInfo() { isLocalHost = false; } AuthenticationInfo() { isLocalHost = false; }
~AuthenticationInfo() { ~AuthenticationInfo() {
} }
void logout(const string& dbname ) { void logout(const string& dbname ) {
assertInWriteLock(); // TODO: can we get rid of this ? only 1 thread should be looking at an AuthenticationInfo scoped_lock lk(_lock);
m.erase(dbname); m.erase(dbname);
} }
void authorize(const string& dbname ) { void authorize(const string& dbname ) {
assertInWriteLock(); scoped_lock lk(_lock);
m[dbname].level = 2; m[dbname].level = 2;
} }
void authorizeReadOnly(const string& dbname) { void authorizeReadOnly(const string& dbname) {
assertInWriteLock(); scoped_lock lk(_lock);
m[dbname].level = 1; m[dbname].level = 1;
} }
bool isAuthorized(const string& dbname) { return _isAuthorized( dbn ame, 2 ); } bool isAuthorized(const string& dbname) { return _isAuthorized( dbn ame, 2 ); }
bool isAuthorizedReads(const string& dbname) { return _isAuthorized ( dbname, 1 ); } bool isAuthorizedReads(const string& dbname) { return _isAuthorized ( dbname, 1 ); }
bool isAuthorizedForLock(const string& dbname, int lockType ) { ret urn _isAuthorized( dbname , lockType > 0 ? 2 : 1 ); } bool isAuthorizedForLock(const string& dbname, int lockType ) { ret urn _isAuthorized( dbname , lockType > 0 ? 2 : 1 ); }
void print(); void print();
protected: protected:
bool _isAuthorized(const string& dbname, int level) { bool _isAuthorized(const string& dbname, int level) {
 End of changes. 4 change blocks. 
3 lines changed or deleted 4 lines changed or added


 snapshots.h   snapshots.h 
skipping to change at line 37 skipping to change at line 37
*/ */
namespace mongo { namespace mongo {
class SnapshotThread; class SnapshotThread;
/** /**
* stores a point in time snapshot * stores a point in time snapshot
* i.e. all counters at a given time * i.e. all counters at a given time
*/ */
class SnapshotData { class SnapshotData {
SnapshotData(); void takeSnapshot();
unsigned long long _created; unsigned long long _created;
Top::CollectionData _globalUsage; Top::CollectionData _globalUsage;
unsigned long long _totalWriteLockedTime; // micros of total time l ocked unsigned long long _totalWriteLockedTime; // micros of total time l ocked
Top::UsageMap _usage; Top::UsageMap _usage;
friend class SnapshotThread; friend class SnapshotThread;
friend class SnapshotDelta; friend class SnapshotDelta;
friend class Snapshots;
}; };
/** /**
* contains performance information for a time period * contains performance information for a time period
*/ */
class SnapshotDelta { class SnapshotDelta {
public: public:
SnapshotDelta( SnapshotData * older , SnapshotData * newer ); SnapshotDelta( const SnapshotData& older , const SnapshotData& newe r );
unsigned long long start() const { unsigned long long start() const {
return _older->_created; return _older._created;
} }
unsigned long long elapsed() const { unsigned long long elapsed() const {
return _elapsed; return _elapsed;
} }
unsigned long long timeInWriteLock() const { unsigned long long timeInWriteLock() const {
return _newer->_totalWriteLockedTime - _older->_totalWriteLocke dTime; return _newer._totalWriteLockedTime - _older._totalWriteLockedT ime;
} }
double percentWriteLocked() const { double percentWriteLocked() const {
double e = (double) elapsed(); double e = (double) elapsed();
double w = (double) timeInWriteLock(); double w = (double) timeInWriteLock();
return w/e; return w/e;
} }
Top::CollectionData globalUsageDiff(); Top::CollectionData globalUsageDiff();
Top::UsageMap collectionUsageDiff(); Top::UsageMap collectionUsageDiff();
private: private:
SnapshotData * _older; const SnapshotData& _older;
SnapshotData * _newer; const SnapshotData& _newer;
unsigned long long _elapsed; unsigned long long _elapsed;
}; };
class Snapshots { class Snapshots {
public: public:
Snapshots(); Snapshots(int n=100);
void add( SnapshotData * s ); const SnapshotData* takeSnapshot();
int numDeltas() const { return _stored-1; } int numDeltas() const { return _stored-1; }
SnapshotData* getPrev( int numBack = 0 ); const SnapshotData& getPrev( int numBack = 0 );
auto_ptr<SnapshotDelta> computeDelta( int numBack = 0 ); auto_ptr<SnapshotDelta> computeDelta( int numBack = 0 );
void outputLockInfoHTML( stringstream& ss ); void outputLockInfoHTML( stringstream& ss );
private: private:
boost::mutex _lock; mongo::mutex _lock;
int _n; int _n;
SnapshotData** _snapshots; boost::scoped_array<SnapshotData> _snapshots;
int _loc; int _loc;
int _stored; int _stored;
}; };
class SnapshotThread : public BackgroundJob { class SnapshotThread : public BackgroundJob {
public: public:
void run(); void run();
}; };
extern Snapshots statsSnapshots; extern Snapshots statsSnapshots;
 End of changes. 11 change blocks. 
11 lines changed or deleted 12 lines changed or added


 sock.h   sock.h 
skipping to change at line 247 skipping to change at line 247
} }
return buf; return buf;
} }
class ListeningSockets { class ListeningSockets {
public: public:
ListeningSockets() : _sockets( new set<int>() ){ ListeningSockets() : _sockets( new set<int>() ){
} }
void add( int sock ){ void add( int sock ){
boostlock lk( _mutex ); scoped_lock lk( _mutex );
_sockets->insert( sock ); _sockets->insert( sock );
} }
void remove( int sock ){ void remove( int sock ){
boostlock lk( _mutex ); scoped_lock lk( _mutex );
_sockets->erase( sock ); _sockets->erase( sock );
} }
void closeAll(){ void closeAll(){
set<int>* s; set<int>* s;
{ {
boostlock lk( _mutex ); scoped_lock lk( _mutex );
s = _sockets; s = _sockets;
_sockets = new set<int>(); _sockets = new set<int>();
} }
for ( set<int>::iterator i=s->begin(); i!=s->end(); i++ ){ for ( set<int>::iterator i=s->begin(); i!=s->end(); i++ ){
int sock = *i; int sock = *i;
log() << "\t going to close listening socket: " << sock << endl; log() << "\t going to close listening socket: " << sock << endl;
closesocket( sock ); closesocket( sock );
} }
} }
static ListeningSockets* get(); static ListeningSockets* get();
private: private:
boost::mutex _mutex; mongo::mutex _mutex;
set<int>* _sockets; set<int>* _sockets;
static ListeningSockets* _instance; static ListeningSockets* _instance;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 4 change blocks. 
4 lines changed or deleted 4 lines changed or added


 stdafx.h   stdafx.h 
skipping to change at line 56 skipping to change at line 56
EXIT_BADOPTIONS = 2 , EXIT_BADOPTIONS = 2 ,
EXIT_REPLICATION_ERROR = 3 , EXIT_REPLICATION_ERROR = 3 ,
EXIT_NEED_UPGRADE = 4 , EXIT_NEED_UPGRADE = 4 ,
EXIT_KILL = 12 , EXIT_KILL = 12 ,
EXIT_ABRUBT = 14 , EXIT_ABRUBT = 14 ,
EXIT_NTSERVICE_ERROR = 20 , EXIT_NTSERVICE_ERROR = 20 ,
EXIT_JAVA = 21 , EXIT_JAVA = 21 ,
EXIT_OOM_MALLOC = 42 , EXIT_OOM_MALLOC = 42 ,
EXIT_OOM_REALLOC = 43 , EXIT_OOM_REALLOC = 43 ,
EXIT_FS = 45 , EXIT_FS = 45 ,
EXIT_CLOCK_SKEW = 47 ,
EXIT_POSSIBLE_CORRUPTION = 60 , // this means we detected a possibl e corruption situation, like a buf overflow EXIT_POSSIBLE_CORRUPTION = 60 , // this means we detected a possibl e corruption situation, like a buf overflow
EXIT_UNCAUGHT = 100 , // top level exception that wasn't caught EXIT_UNCAUGHT = 100 , // top level exception that wasn't caught
EXIT_TEST = 101 , EXIT_TEST = 101 ,
}; };
void dbexit( ExitCode returnCode, const char *whyMsg = ""); void dbexit( ExitCode returnCode, const char *whyMsg = "");
/** /**
this is here so you can't just type exit() to quit the program this is here so you can't just type exit() to quit the program
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 syncclusterconnection.h   syncclusterconnection.h 
skipping to change at line 64 skipping to change at line 64
virtual void insert( const string &ns, const vector< BSONObj >& v ) ; virtual void insert( const string &ns, const vector< BSONObj >& v ) ;
virtual void remove( const string &ns , Query query, bool justOne ) ; virtual void remove( const string &ns , Query query, bool justOne ) ;
virtual void update( const string &ns , Query query , BSONObj obj , bool upsert , bool multi ); virtual void update( const string &ns , Query query , BSONObj obj , bool upsert , bool multi );
virtual string toString(); virtual string toString();
private: private:
bool _commandOnActive(const string &dbname, const BSONObj& cmd, BSO
NObj &info, int options=0);
auto_ptr<DBClientCursor> _queryOnActive(const string &ns, Query que
ry, int nToReturn, int nToSkip,
const BSONObj *fieldsToRetu
rn, int queryOptions, int batchSize );
bool _isReadOnly( const string& name );
void _checkLast(); void _checkLast();
void _connect( string host ); void _connect( string host );
vector<DBClientConnection*> _conns; vector<DBClientConnection*> _conns;
map<string,int> _lockTypes;
}; };
}; };
 End of changes. 2 change blocks. 
0 lines changed or deleted 12 lines changed or added


 thread_pool.h   thread_pool.h 
skipping to change at line 63 skipping to change at line 63
template<typename F, typename A, typename B, typename C> template<typename F, typename A, typename B, typename C>
void schedule(F f, A a, B b, C c){ schedule(boost::bind(f,a,b,c)); } void schedule(F f, A a, B b, C c){ schedule(boost::bind(f,a,b,c)); }
template<typename F, typename A, typename B, typename C, typename D > template<typename F, typename A, typename B, typename C, typename D >
void schedule(F f, A a, B b, C c, D d){ schedule(boost::bind(f,a,b, c,d)); } void schedule(F f, A a, B b, C c, D d){ schedule(boost::bind(f,a,b, c,d)); }
template<typename F, typename A, typename B, typename C, typename D , typename E> template<typename F, typename A, typename B, typename C, typename D , typename E>
void schedule(F f, A a, B b, C c, D d, E e){ schedule(boost::bind(f ,a,b,c,d,e)); } void schedule(F f, A a, B b, C c, D d, E e){ schedule(boost::bind(f ,a,b,c,d,e)); }
int tasks_remaining() { return _tasksRemaining; } int tasks_remaining() { return _tasksRemaining; }
private: private:
boost::mutex _mutex; mongo::mutex _mutex;
boost::condition _condition; boost::condition _condition;
list<Worker*> _freeWorkers; //used as LIFO stack (always front) list<Worker*> _freeWorkers; //used as LIFO stack (always front)
list<Task> _tasks; //used as FIFO queue (push_back, pop_front) list<Task> _tasks; //used as FIFO queue (push_back, pop_front)
int _tasksRemaining; // in queue + currently processing int _tasksRemaining; // in queue + currently processing
int _nThreads; // only used for sanity checking. could be removed i n the future. int _nThreads; // only used for sanity checking. could be removed i n the future.
// should only be called by a worker from the worker's thread // should only be called by a worker from the worker's thread
void task_done(Worker* worker); void task_done(Worker* worker);
friend class Worker; friend class Worker;
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 top.h   top.h 
skipping to change at line 35 skipping to change at line 35
/** /**
* tracks usage by collection * tracks usage by collection
*/ */
class Top { class Top {
public: public:
class UsageData { class UsageData {
public: public:
UsageData() : time(0) , count(0){} UsageData() : time(0) , count(0){}
UsageData( UsageData& older , UsageData& newer ); UsageData( const UsageData& older , const UsageData& newer );
long long time; long long time;
long long count; long long count;
void inc( long long micros ){ void inc( long long micros ){
count++; count++;
time += micros; time += micros;
} }
}; };
class CollectionData { class CollectionData {
public: public:
/** /**
* constructs a diff * constructs a diff
*/ */
CollectionData(){} CollectionData(){}
CollectionData( CollectionData& older , CollectionData& newer ) ; CollectionData( const CollectionData& older , const CollectionD ata& newer );
UsageData total; UsageData total;
UsageData readLock; UsageData readLock;
UsageData writeLock; UsageData writeLock;
UsageData queries; UsageData queries;
UsageData getmore; UsageData getmore;
UsageData insert; UsageData insert;
UsageData update; UsageData update;
UsageData remove; UsageData remove;
UsageData commands; UsageData commands;
}; };
typedef map<string,CollectionData> UsageMap; typedef map<string,CollectionData> UsageMap;
public: public:
void record( const string& ns , int op , int lockType , long long m icros , bool command ); void record( const string& ns , int op , int lockType , long long m icros , bool command );
void append( BSONObjBuilder& b ); void append( BSONObjBuilder& b );
UsageMap cloneMap(); void cloneMap(UsageMap& out);
CollectionData getGlobalData(){ return _global; } CollectionData getGlobalData(){ return _global; }
void collectionDropped( const string& ns );
public: // static stuff public: // static stuff
static Top global; static Top global;
void append( BSONObjBuilder& b , const char * name , const UsageDat a& map ); void append( BSONObjBuilder& b , const char * name , const UsageDat a& map );
void append( BSONObjBuilder& b , const UsageMap& map ); void append( BSONObjBuilder& b , const UsageMap& map );
private: private:
void _record( CollectionData& c , int op , int lockType , long long micros , bool command ); void _record( CollectionData& c , int op , int lockType , long long micros , bool command );
boost::mutex _lock; mongo::mutex _lock;
CollectionData _global; CollectionData _global;
UsageMap _usage; UsageMap _usage;
string _lastDropped;
}; };
/* Records per namespace utilization of the mongod process. /* Records per namespace utilization of the mongod process.
No two functions of this class may be called concurrently. No two functions of this class may be called concurrently.
*/ */
class TopOld { class TopOld {
typedef boost::posix_time::ptime T; typedef boost::posix_time::ptime T;
typedef boost::posix_time::time_duration D; typedef boost::posix_time::time_duration D;
typedef boost::tuple< D, int, int, int > UsageData; typedef boost::tuple< D, int, int, int > UsageData;
public: public:
skipping to change at line 118 skipping to change at line 120
void setRead() { _read = true; } void setRead() { _read = true; }
void setWrite() { _write = true; } void setWrite() { _write = true; }
void clientStop() { void clientStop() {
if ( _currentStart == T() ) if ( _currentStart == T() )
return; return;
D d = currentTime() - _currentStart; D d = currentTime() - _currentStart;
{ {
boostlock L(topMutex); scoped_lock L(topMutex);
recordUsage( _current, d ); recordUsage( _current, d );
} }
_currentStart = T(); _currentStart = T();
_read = false; _read = false;
_write = false; _write = false;
} }
/* these are used to fetch the stats: */ /* these are used to fetch the stats: */
struct Usage { struct Usage {
string ns; string ns;
D time; D time;
double pct; double pct;
int reads, writes, calls; int reads, writes, calls;
}; };
static void usage( vector< Usage > &res ) { static void usage( vector< Usage > &res ) {
boostlock L(topMutex); scoped_lock L(topMutex);
// Populate parent namespaces // Populate parent namespaces
UsageMap snapshot; UsageMap snapshot;
UsageMap totalUsage; UsageMap totalUsage;
fillParentNamespaces( snapshot, _snapshot ); fillParentNamespaces( snapshot, _snapshot );
fillParentNamespaces( totalUsage, _totalUsage ); fillParentNamespaces( totalUsage, _totalUsage );
multimap< D, string, more > sorted; multimap< D, string, more > sorted;
for( UsageMap::iterator i = snapshot.begin(); i != snapshot.end (); ++i ) for( UsageMap::iterator i = snapshot.begin(); i != snapshot.end (); ++i )
sorted.insert( make_pair( i->second.get<0>(), i->first ) ); sorted.insert( make_pair( i->second.get<0>(), i->first ) );
skipping to change at line 175 skipping to change at line 177
u.time = i->second.get<0>(); u.time = i->second.get<0>();
u.pct = 0; u.pct = 0;
u.reads = 0; u.reads = 0;
u.writes = 0; u.writes = 0;
u.calls = 0; u.calls = 0;
res.push_back( u ); res.push_back( u );
} }
} }
static void completeSnapshot() { static void completeSnapshot() {
boostlock L(topMutex); scoped_lock L(topMutex);
if ( &_snapshot == &_snapshotA ) { if ( &_snapshot == &_snapshotA ) {
_snapshot = _snapshotB; _snapshot = _snapshotB;
_nextSnapshot = _snapshotA; _nextSnapshot = _snapshotA;
} else { } else {
_snapshot = _snapshotA; _snapshot = _snapshotA;
_nextSnapshot = _snapshotB; _nextSnapshot = _snapshotB;
} }
_snapshotDuration = currentTime() - _snapshotStart; _snapshotDuration = currentTime() - _snapshotStart;
_snapshotStart = currentTime(); _snapshotStart = currentTime();
_nextSnapshot.clear(); _nextSnapshot.clear();
} }
private: private:
static boost::mutex topMutex; static mongo::mutex topMutex;
static bool trivialNs( const char *ns ) { static bool trivialNs( const char *ns ) {
const char *ret = strrchr( ns, '.' ); const char *ret = strrchr( ns, '.' );
return ret && ret[ 1 ] == '\0'; return ret && ret[ 1 ] == '\0';
} }
typedef map<string,UsageData> UsageMap; // duration, # reads, # wri tes, # total calls typedef map<string,UsageData> UsageMap; // duration, # reads, # wri tes, # total calls
static T currentTime() { static T currentTime() {
return boost::posix_time::microsec_clock::universal_time(); return boost::posix_time::microsec_clock::universal_time();
} }
void recordUsage( const string &client, D duration ) { void recordUsage( const string &client, D duration ) {
recordUsageForMap( _totalUsage, client, duration ); recordUsageForMap( _totalUsage, client, duration );
 End of changes. 10 change blocks. 
8 lines changed or deleted 10 lines changed or added


 update.h   update.h 
skipping to change at line 85 skipping to change at line 85
break; break;
case NumberInt: case NumberInt:
manip.setInt( elt.numberInt() + in.numberInt() ); manip.setInt( elt.numberInt() + in.numberInt() );
break; break;
default: default:
assert(0); assert(0);
} }
} }
void appendIncremented( BSONObjBuilder& bb , const BSONElement& in, template< class Builder >
ModState& ms ) const; void appendIncremented( Builder& bb , const BSONElement& in, ModSta
te& ms ) const;
bool operator<( const Mod &other ) const { bool operator<( const Mod &other ) const {
return strcmp( fieldName, other.fieldName ) < 0; return strcmp( fieldName, other.fieldName ) < 0;
} }
bool arrayDep() const { bool arrayDep() const {
switch (op){ switch (op){
case PUSH: case PUSH:
case PUSH_ALL: case PUSH_ALL:
case POP: case POP:
skipping to change at line 118 skipping to change at line 119
// 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; return false;
} }
void apply( BSONObjBuilder& b , BSONElement in , ModState& ms ) con template< class Builder >
st; 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;
void _checkForAppending( const BSONElement& e ) const { void _checkForAppending( const BSONElement& e ) const {
if ( e.type() == Object ){ if ( e.type() == Object ){
// this is a tiny bit slow, but rare and important // this is a tiny bit slow, but rare and important
// only when setting something TO an object, not setting so mething in an object // only when setting something TO an object, not setting so mething in an object
skipping to change at line 164 skipping to change at line 167
}; };
/** /**
* stores a set of Mods * stores a set of Mods
* once created, should never be changed * once created, should never be changed
*/ */
class ModSet : boost::noncopyable { class ModSet : boost::noncopyable {
typedef map<string,Mod> ModHolder; typedef map<string,Mod> ModHolder;
ModHolder _mods; ModHolder _mods;
int _isIndexed; int _isIndexed;
bool _hasDynamicArray;
static void extractFields( map< string, BSONElement > &fields, cons t BSONElement &top, const string &base ); static void extractFields( map< string, BSONElement > &fields, cons t BSONElement &top, const string &base );
FieldCompareResult compare( const ModHolder::iterator &m, map< stri ng, BSONElement >::iterator &p, const map< string, BSONElement >::iterator &pEnd ) const { FieldCompareResult compare( const ModHolder::iterator &m, map< stri ng, BSONElement >::iterator &p, const map< string, BSONElement >::iterator &pEnd ) const {
bool mDone = ( m == _mods.end() ); bool mDone = ( m == _mods.end() );
bool pDone = ( p == pEnd ); bool pDone = ( p == pEnd );
assert( ! mDone ); assert( ! mDone );
assert( ! pDone ); assert( ! pDone );
if ( mDone && pDone ) if ( mDone && pDone )
return SAME; return SAME;
skipping to change at line 256 skipping to change at line 260
return Mod::ADDTOSET; return Mod::ADDTOSET;
} }
} }
default: break; default: break;
} }
uassert( 10161 , "Invalid modifier specified " + string( fn ), false ); uassert( 10161 , "Invalid modifier specified " + string( fn ), false );
return Mod::INC; return Mod::INC;
} }
ModSet(){}
public: public:
ModSet( const BSONObj &from , ModSet( const BSONObj &from ,
const set<string>& idxKeys = set<string>(), const set<string>& idxKeys = set<string>(),
const set<string>* backgroundKeys = 0 const set<string>* backgroundKeys = 0
); );
// TODO: this is inefficient - should probably just handle when ite
rating
ModSet * fixDynamicArray( const char * elemMatchKey ) const;
bool hasDynamicArray() const { return _hasDynamicArray; }
/** /**
* creates a ModSetState suitable for operation on obj * creates a ModSetState suitable for operation on obj
* doesn't change or modify this ModSet or any underying Mod * doesn't change or modify this ModSet or any underying Mod
*/ */
auto_ptr<ModSetState> prepare( const BSONObj& obj ) const; auto_ptr<ModSetState> prepare( const BSONObj& obj ) const;
/** /**
* given a query pattern, builds an object suitable for an upsert * given a query pattern, builds an object suitable for an upsert
* will take the query spec and combine all $ operators * will take the query spec and combine all $ operators
*/ */
skipping to change at line 343 skipping to change at line 354
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 || 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;
skipping to change at line 369 skipping to change at line 380
BSONObjBuilder bb( b.subobjStart( "$set" ) ); BSONObjBuilder bb( b.subobjStart( "$set" ) );
appendIncValue( bb ); appendIncValue( bb );
bb.done(); bb.done();
return; return;
} }
const char * name = fixedName ? fixedName : Mod::modNames[op()] ; const char * name = fixedName ? fixedName : Mod::modNames[op()] ;
BSONObjBuilder bb( b.subobjStart( name ) ); BSONObjBuilder bb( b.subobjStart( name ) );
if ( fixed ) if ( fixed )
bb.append( *fixed ); bb.appendAs( *fixed , m->fieldName );
else else
bb.append( m->elt ); bb.append( m->elt );
bb.done(); bb.done();
} }
void apply( BSONObjBuilder& b , BSONElement in ){ template< class Builder >
void apply( Builder& b , BSONElement in ){
m->apply( b , in , *this ); m->apply( b , in , *this );
} }
void appendIncValue( BSONObjBuilder& b ) const { template< class Builder >
void appendIncValue( Builder& b ) const {
switch ( incType ){ switch ( incType ){
case NumberDouble: case NumberDouble:
b.append( m->shortFieldName , incdouble ); break; b.append( m->shortFieldName , incdouble ); break;
case NumberLong: case NumberLong:
b.append( m->shortFieldName , inclong ); break; b.append( m->shortFieldName , inclong ); break;
case NumberInt: case NumberInt:
b.append( m->shortFieldName , 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
*/ */
class ModSetState : boost::noncopyable { class ModSetState : boost::noncopyable {
typedef map<string,ModState> ModStateHolder; struct FieldCmp {
bool operator()( const string &l, const string &r ) const {
return lexNumCmp( l.c_str(), r.c_str() ) < 0;
}
};
typedef map<string,ModState,FieldCmp> ModStateHolder;
const BSONObj& _obj; const BSONObj& _obj;
ModStateHolder _mods; ModStateHolder _mods;
bool _inPlacePossible; bool _inPlacePossible;
ModSetState( const BSONObj& obj ) ModSetState( const BSONObj& obj )
: _obj( obj ) , _inPlacePossible(true){ : _obj( obj ) , _inPlacePossible(true){
} }
/** /**
* @return if in place is still possible * @return if in place is still possible
*/ */
bool amIInPlacePossible( bool inPlacePossible ){ bool amIInPlacePossible( bool inPlacePossible ){
if ( ! inPlacePossible ) if ( ! inPlacePossible )
_inPlacePossible = false; _inPlacePossible = false;
return _inPlacePossible; return _inPlacePossible;
} }
void createNewFromMods( const string& root , BSONObjBuilder& b , co template< class Builder >
nst BSONObj &obj ); void createNewFromMods( const string& root , Builder& b , const BSO
NObj &obj );
void _appendNewFromMods( const string& root , ModState& m , BSONObj template< class Builder >
Builder& b , set<string>& onedownseen ); void _appendNewFromMods( const string& root , ModState& m , Builder
& b , set<string>& onedownseen );
void appendNewFromMod( ModState& ms , BSONObjBuilder& b ){ template< class Builder >
void appendNewFromMod( ModState& ms , Builder& b ){
//const Mod& m = *(ms.m); // HACK //const Mod& m = *(ms.m); // HACK
Mod& m = *((Mod*)(ms.m)); // HACK Mod& m = *((Mod*)(ms.m)); // HACK
switch ( m.op ){ switch ( m.op ){
case Mod::PUSH: case Mod::PUSH:
case Mod::ADDTOSET: { case Mod::ADDTOSET: {
if ( m.isEach() ){ if ( m.isEach() ){
b.appendArray( m.shortFieldName , m.getEach() ); b.appendArray( m.shortFieldName , m.getEach() );
} }
skipping to change at line 451 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.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. 
14 lines changed or deleted 35 lines changed or added


 v8_wrapper.h   v8_wrapper.h 
skipping to change at line 29 skipping to change at line 29
#include <v8.h> #include <v8.h>
#include <cstring> #include <cstring>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include "../db/jsobj.h" #include "../db/jsobj.h"
namespace mongo { namespace mongo {
v8::Local<v8::Object> mongoToV8( const mongo::BSONObj & m , bool array = 0 , bool readOnly = false ); v8::Local<v8::Object> mongoToV8( const mongo::BSONObj & m , bool array = 0 , bool readOnly = false );
mongo::BSONObj v8ToMongo( v8::Handle<v8::Object> o ); mongo::BSONObj v8ToMongo( v8::Handle<v8::Object> o , int depth = 0 );
void v8ToMongoElement( BSONObjBuilder & b , v8::Handle<v8::String> name , void v8ToMongoElement( BSONObjBuilder & b , v8::Handle<v8::String> name ,
const string sname , v8::Handle<v8::Value> value ); const string sname , v8::Handle<v8::Value> value , int depth = 0 );
v8::Handle<v8::Value> mongoToV8Element( const BSONElement &f ); v8::Handle<v8::Value> mongoToV8Element( const BSONElement &f );
v8::Function * getNamedCons( const char * name ); v8::Function * getNamedCons( const char * name );
v8::Function * getObjectIdCons(); v8::Function * getObjectIdCons();
v8::Handle<v8::FunctionTemplate> getObjectWrapperTemplate(); v8::Handle<v8::FunctionTemplate> getObjectWrapperTemplate();
class WrapperHolder; class WrapperHolder;
WrapperHolder * createWrapperHolder( const BSONObj * o , bool readOnly , bool iDelete ); WrapperHolder * createWrapperHolder( const BSONObj * o , bool readOnly , bool iDelete );
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 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/