assert_util.h   assert_util.h 
skipping to change at line 33 skipping to change at line 33
/* 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:
static boost::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:
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 ) {
/* asserted during global variable initialization */
return;
}
boostlock 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;
} }
skipping to change at line 67 skipping to change at line 75
/* last assert of diff types: regular, wassert, msgassert, uassert: */ /* last assert of diff types: regular, wassert, msgassert, uassert: */
extern Assertion lastAssert[4]; extern Assertion lastAssert[4];
class DBException : public std::exception { class DBException : public std::exception {
public: public:
virtual const char* what() const throw() = 0; virtual const char* what() const throw() = 0;
virtual string toString() const { virtual string toString() const {
return what(); return what();
} }
virtual int getCode() = 0;
operator string() const { return toString(); } operator string() const { return toString(); }
}; };
class AssertionException : public DBException { class AssertionException : public DBException {
public: public:
int code;
string msg; string msg;
AssertionException() { } AssertionException() { code = 0; }
virtual ~AssertionException() throw() { } virtual ~AssertionException() throw() { }
virtual bool severe() { virtual bool severe() {
return true; return true;
} }
virtual bool isUserAssertion() { virtual bool isUserAssertion() {
return false; return false;
} }
virtual int getCode(){ return code; }
virtual const char* what() const throw() { return msg.c_str(); } virtual const char* what() const throw() { return msg.c_str(); }
}; };
/* UserExceptions are valid errors that a user can cause, like out of d isk space or duplicate key */ /* UserExceptions are valid errors that a user can cause, like out of d isk space or duplicate key */
class UserException : public AssertionException { class UserException : public AssertionException {
public: public:
UserException(const char *_msg) { UserException(int c , const string& m) {
msg = _msg; code = c;
} msg = m;
UserException(string _msg) {
msg = _msg;
} }
virtual bool severe() { virtual bool severe() {
return false; return false;
} }
virtual bool isUserAssertion() { virtual bool isUserAssertion() {
return true; return true;
} }
virtual string toString() const { virtual string toString() const {
return "userassert:" + msg; return "userassert:" + msg;
} }
}; };
class MsgAssertionException : public AssertionException { class MsgAssertionException : public AssertionException {
public: public:
MsgAssertionException(const char *_msg) { MsgAssertionException(int c, const char *m) {
msg = _msg; code = c;
msg = m;
} }
virtual bool severe() { virtual bool severe() {
return false; return false;
} }
virtual string toString() const { virtual string toString() const {
return "massert:" + msg; return "massert:" + msg;
} }
}; };
void asserted(const char *msg, const char *file, unsigned line); void asserted(const char *msg, const char *file, unsigned line);
void wasserted(const char *msg, const char *file, unsigned line); void wasserted(const char *msg, const char *file, unsigned line);
void uasserted(const char *msg); void uasserted(int msgid, const char *msg);
inline void uasserted(string msg) { uasserted(msg.c_str()); } inline void uasserted(int msgid , string msg) { uasserted(msgid, msg.c_
str()); }
void uassert_nothrow(const char *msg); // reported via lasterror, but d on't throw exception void uassert_nothrow(const char *msg); // reported via lasterror, but d on't throw exception
void msgasserted(const char *msg); void msgasserted(int msgid, const char *msg);
inline void msgasserted(string msg) { msgasserted(msg.c_str()); } inline void msgasserted(int msgid, string msg) { msgasserted(msgid, msg
.c_str()); }
#ifdef assert #ifdef assert
#undef assert #undef assert
#endif #endif
#define assert(_Expression) (void)( (!!(_Expression)) || (mongo::asserted(# _Expression, __FILE__, __LINE__), 0) ) #define assert(_Expression) (void)( (!!(_Expression)) || (mongo::asserted(# _Expression, __FILE__, __LINE__), 0) )
/* "user assert". if asserts, user did something wrong, not our code * / /* "user assert". if asserts, user did something wrong, not our code * /
//#define uassert(_Expression) (void)( (!!(_Expression)) || (uasserted(#_Ex //#define uassert( 10269 , _Expression) (void)( (!!(_Expression)) || (uasse
pression, __FILE__, __LINE__), 0) ) rted(#_Expression, __FILE__, __LINE__), 0) )
#define uassert(msg,_Expression) (void)( (!!(_Expression)) || (mongo::uasse #define uassert(msgid, msg,_Expression) (void)( (!!(_Expression)) || (mongo
rted(msg), 0) ) ::uasserted(msgid, msg), 0) )
#define xassert(_Expression) (void)( (!!(_Expression)) || (mongo::asserted( #_Expression, __FILE__, __LINE__), 0) ) #define xassert(_Expression) (void)( (!!(_Expression)) || (mongo::asserted( #_Expression, __FILE__, __LINE__), 0) )
#define yassert 1 #define yassert 1
/* warning only - keeps going */ /* warning only - keeps going */
#define wassert(_Expression) (void)( (!!(_Expression)) || (mongo::wasserted (#_Expression, __FILE__, __LINE__), 0) ) #define wassert(_Expression) (void)( (!!(_Expression)) || (mongo::wasserted (#_Expression, __FILE__, __LINE__), 0) )
/* display a message, no context, and throw assertionexception /* display a message, no context, and throw assertionexception
easy way to throw an exception and log something without our stack t race easy way to throw an exception and log something without our stack t race
display happening. display happening.
*/ */
#define massert(msg,_Expression) (void)( (!!(_Expression)) || (mongo::msgas serted(msg), 0) ) #define massert(msgid, msg,_Expression) (void)( (!!(_Expression)) || (mongo ::msgasserted(msgid, msg), 0) )
/* dassert is 'debug assert' -- might want to turn off for production a s these /* dassert is 'debug assert' -- might want to turn off for production a s these
could be slow. could be slow.
*/ */
#if defined(_DEBUG) #if defined(_DEBUG)
#define dassert assert #define dassert assert
#else #else
#define dassert(x) #define dassert(x)
#endif #endif
// some special ids that we want to duplicate
// > 10000 asserts
// < 10000 UserException
#define ASSERT_ID_DUPKEY 11000
} // namespace mongo } // namespace mongo
#define BOOST_CHECK_EXCEPTION( expression ) \ #define BOOST_CHECK_EXCEPTION( expression ) \
try { \ try { \
expression; \ expression; \
} catch ( const std::exception &e ) { \ } catch ( const std::exception &e ) { \
problem() << "caught boost exception: " << e.what() << endl; \ problem() << "caught boost exception: " << e.what() << endl; \
assert( false ); \ assert( false ); \
} catch ( ... ) { \ } catch ( ... ) { \
massert( "unknown boost failed" , false ); \ massert( 10437 , "unknown boost failed" , false ); \
} }
 End of changes. 15 change blocks. 
18 lines changed or deleted 37 lines changed or added


 btree.h   btree.h 
skipping to change at line 91 skipping to change at line 91
friend class BtreeBuilder; friend class BtreeBuilder;
friend class KeyNode; friend class KeyNode;
public: public:
void dumpTree(DiskLoc thisLoc, const BSONObj &order); void dumpTree(DiskLoc thisLoc, const BSONObj &order);
bool isHead() { return parent.isNull(); } bool isHead() { return parent.isNull(); }
void assertValid(const BSONObj &order, bool force = false); void assertValid(const BSONObj &order, bool force = false);
int fullValidate(const DiskLoc& thisLoc, const BSONObj &order); /* traverses everything */ int fullValidate(const DiskLoc& thisLoc, const BSONObj &order); /* traverses everything */
protected: protected:
void modified(const DiskLoc& thisLoc); void modified(const DiskLoc& thisLoc);
KeyNode keyNode(int i) const { KeyNode keyNode(int i) const {
if ( i >= n ){ assert( i < n );
massert( (string)"invalid keyNode: " + BSON( "i" << i << "
n" << n ).jsonString() , i < n );
}
return KeyNode(*this, k(i)); return KeyNode(*this, k(i));
} }
char * dataAt(short ofs) { char * dataAt(short ofs) {
return data + ofs; return data + ofs;
} }
void init(); // initialize a new node void init(); // initialize a new node
/* returns false if node is full and must be split /* returns false if node is full and must be split
skipping to change at line 190 skipping to change at line 188
/* @return true if key exists in index /* @return true if key exists in index
order - indicates order of keys in the index. this is basically the index's key pattern, e.g.: order - indicates order of keys in the index. this is basically the index's key pattern, e.g.:
BSONObj order = ((IndexDetails&)idx).keyPattern(); BSONObj order = ((IndexDetails&)idx).keyPattern();
likewise below in bt_insert() etc. likewise below in bt_insert() etc.
*/ */
bool exists(const IndexDetails& idx, DiskLoc thisLoc, const BSONObj & key, BSONObj order); bool exists(const IndexDetails& idx, DiskLoc thisLoc, const BSONObj & key, BSONObj order);
static DiskLoc addBucket(IndexDetails&); /* start a new index off, empty */ static DiskLoc addBucket(IndexDetails&); /* start a new index off, empty */
void deallocBucket(const DiskLoc &thisLoc); // clear bucket memory, placeholder for deallocation
static void renameIndexNamespace(const char *oldNs, const char *new Ns); static void renameIndexNamespace(const char *oldNs, const char *new Ns);
int bt_insert(DiskLoc thisLoc, DiskLoc recordLoc, int bt_insert(DiskLoc thisLoc, DiskLoc recordLoc,
const BSONObj& key, const BSONObj &order, bool dupsAllow ed, const BSONObj& key, const BSONObj &order, bool dupsAllow ed,
IndexDetails& idx, bool toplevel = true); IndexDetails& idx, bool toplevel = true);
bool unindex(const DiskLoc& thisLoc, IndexDetails& id, BSONObj& key , const DiskLoc& recordLoc); bool unindex(const DiskLoc& thisLoc, IndexDetails& id, BSONObj& key , const DiskLoc& recordLoc);
/* locate may return an "unused" key that is just a marker. so be careful. /* locate may return an "unused" key that is just a marker. so be careful.
 End of changes. 2 change blocks. 
5 lines changed or deleted 1 lines changed or added


 builder.h   builder.h 
skipping to change at line 21 skipping to change at line 21
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "../stdafx.h" #include "../stdafx.h"
#include <string.h>
namespace mongo { namespace mongo {
class StringBuilder;
class BufBuilder { class BufBuilder {
public: public:
BufBuilder(int initsize = 512) : size(initsize) { BufBuilder(int initsize = 512) : size(initsize) {
if ( size > 0 ) { if ( size > 0 ) {
data = (char *) malloc(size); data = (char *) malloc(size);
assert(data); assert(data);
} else { } else {
data = 0; data = 0;
} }
l = 0; l = 0;
skipping to change at line 46 skipping to change at line 49
kill(); kill();
} }
void kill() { void kill() {
if ( data ) { if ( data ) {
free(data); free(data);
data = 0; data = 0;
} }
} }
void reset( int maxSize = 0 ){
l = 0;
if ( maxSize && size > maxSize ){
free(data);
data = (char*)malloc(maxSize);
size = maxSize;
}
}
/* leave room for some stuff later */ /* leave room for some stuff later */
void skip(int n) { void skip(int n) {
grow(n); grow(n);
} }
/* note this may be deallocated (realloced) if you keep writing. */ /* note this may be deallocated (realloced) if you keep writing. */
char* buf() { char* buf() {
return data; return data;
} }
skipping to change at line 121 skipping to change at line 134
assert( a < 64 * 1024 * 1024 ); assert( a < 64 * 1024 * 1024 );
data = (char *) realloc(data, a); data = (char *) realloc(data, a);
size= a; size= a;
} }
return data + oldlen; return data + oldlen;
} }
char *data; char *data;
int l; int l;
int size; int size;
friend class StringBuilder;
};
class StringBuilder {
public:
StringBuilder( int initsize=256 )
: _buf( initsize ){
}
#define SBNUM(val,maxSize,macro) \
int prev = _buf.l; \
int z = sprintf( _buf.grow(maxSize) , macro , (val) ); \
_buf.l = prev + z; \
return *this;
StringBuilder& operator<<( double x ){
SBNUM( x , 25 , "%g" );
}
StringBuilder& operator<<( int x ){
SBNUM( x , 11 , "%d" );
}
StringBuilder& operator<<( unsigned x ){
SBNUM( x , 11 , "%u" );
}
StringBuilder& operator<<( long x ){
SBNUM( x , 22 , "%ld" );
}
StringBuilder& operator<<( unsigned long x ){
SBNUM( x , 22 , "%lu" );
}
StringBuilder& operator<<( long long x ){
SBNUM( x , 22 , "%lld" );
}
StringBuilder& operator<<( unsigned long long x ){
SBNUM( x , 22 , "%llu" );
}
StringBuilder& operator<<( short x ){
SBNUM( x , 8 , "%hd" );
}
void append( const char * str ){
int x = strlen( str );
memcpy( _buf.grow( x ) , str , x );
}
StringBuilder& operator<<( const char * str ){
append( str );
return *this;
}
StringBuilder& operator<<( const string& s ){
append( s.c_str() );
return *this;
}
// access
void reset( int maxSize = 0 ){
_buf.reset( maxSize );
}
string str(){
return string(_buf.data,0,_buf.l);
}
private:
BufBuilder _buf;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 4 change blocks. 
0 lines changed or deleted 79 lines changed or added


 chunk.h   chunk.h 
skipping to change at line 55 skipping to change at line 55
x is in a shard iff x is in a shard iff
min <= x < max min <= x < max
*/ */
class Chunk : public Model , boost::noncopyable { class Chunk : public Model , boost::noncopyable {
public: public:
Chunk( ChunkManager * info ); Chunk( ChunkManager * info );
const BSONObj& getMin() const { return _min; } const BSONObj& getMin() const { return _min; }
const BSONObj& getMinDotted() const { return _minDotted; }
const BSONObj& getMax() const { return _max; } const BSONObj& getMax() const { return _max; }
const BSONObj& getMaxDotted() const { return _maxDotted; }
void setMin(const BSONObj& o){ void setMin(const BSONObj& o){
_min = o; _min = o;
_minDotted = nested2dotted(o);
} }
void setMax(const BSONObj& o){ void setMax(const BSONObj& o){
_max = o; _max = o;
_maxDotted = nested2dotted(o);
} }
string getShard(){ string getShard(){
return _shard; return _shard;
} }
void setShard( string shard ); void setShard( string shard );
bool contains( const BSONObj& obj ); bool contains( const BSONObj& obj );
string toString() const; string toString() const;
skipping to change at line 134 skipping to change at line 130
static long MaxChunkSize; static long MaxChunkSize;
private: private:
// main shard info // main shard info
ChunkManager * _manager; ChunkManager * _manager;
ShardKeyPattern skey(); ShardKeyPattern skey();
string _ns; string _ns;
BSONObj _min; //nested BSONObj _min;
BSONObj _minDotted; BSONObj _max;
BSONObj _max; //nested
BSONObj _maxDotted;
string _shard; string _shard;
ShardChunkVersion _lastmod; ShardChunkVersion _lastmod;
bool _modified; bool _modified;
// transient stuff // transient stuff
long _dataWritten; long _dataWritten;
// methods, etc.. // methods, etc..
 End of changes. 5 change blocks. 
8 lines changed or deleted 2 lines changed or added


 client.h   client.h 
skipping to change at line 27 skipping to change at line 27
*/ */
/* Client represents a connection to the database (the server-side) and cor responds /* Client represents a connection to the database (the server-side) and cor responds
to an open socket (or logical connection if pooling on sockets) from a c lient. to an open socket (or logical connection if pooling on sockets) from a c lient.
todo: switch to asio...this will fit nicely with that. todo: switch to asio...this will fit nicely with that.
*/ */
#pragma once #pragma once
#include "../stdafx.h"
#include "namespace.h"
#include "lasterror.h" #include "lasterror.h"
#include "../util/top.h" #include "../util/top.h"
namespace mongo { namespace mongo {
class AuthenticationInfo; class AuthenticationInfo;
class Database; class Database;
struct CurOp; class CurOp;
class Client : boost::noncopyable { class Client : boost::noncopyable {
public: public:
static boost::mutex clientsMutex; static boost::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();
}; };
private: private:
CurOp *_op; CurOp * const _curOp;
Database *_database; Database *_database;
Namespace _ns; Namespace _ns;
//NamespaceString _nsstr; //NamespaceString _nsstr;
bool _shutdown; bool _shutdown;
list<string> _tempCollections; list<string> _tempCollections;
const char *_desc; const char *_desc;
bool _god; bool _god;
public: public:
AuthenticationInfo *ai; AuthenticationInfo *ai;
Top top; Top top;
CurOp* curop() { return _op; } CurOp* curop() { return _curOp; }
Database* database() { return _database; } Database* database() {
return _database;
}
const char *ns() { return _ns.buf; } const char *ns() { return _ns.buf; }
void setns(const char *ns, Database *db) { void setns(const char *ns, Database *db) {
_database = db; _database = db;
_ns = ns; _ns = ns;
//_nsstr = ns; //_nsstr = ns;
} }
void clearns() { setns("", 0); } void clearns() { setns("", 0); }
Client(const char *desc); Client(const char *desc);
~Client(); ~Client();
const char *desc() const { return _desc; }
void addTempCollection( const string& ns ){ void addTempCollection( const string& ns ){
_tempCollections.push_back( ns ); _tempCollections.push_back( ns );
} }
/* each thread which does db operations has a Client object in TLS. /* each thread which does db operations has a Client object in TLS.
call this when your thread starts. call this when your thread starts.
*/ */
static void initThread(const char *desc); static void initThread(const char *desc);
/* /*
skipping to change at line 100 skipping to change at line 106
bool isGod() const { return _god; } bool isGod() const { return _god; }
}; };
/* defined in security.cpp - one day add client.cpp? */ /* defined in security.cpp - one day add client.cpp? */
extern boost::thread_specific_ptr<Client> currentClient; extern boost::thread_specific_ptr<Client> currentClient;
inline Client& cc() { inline Client& cc() {
return *currentClient.get(); return *currentClient.get();
} }
/* each thread which does db operations has a Client object in TLS.
call this when your thread starts.
*/
inline void Client::initThread(const char *desc) { inline void Client::initThread(const char *desc) {
assert( currentClient.get() == 0 ); assert( currentClient.get() == 0 );
currentClient.reset( new Client(desc) ); currentClient.reset( new Client(desc) );
} }
inline Client::GodScope::GodScope(){ inline Client::GodScope::GodScope(){
_prev = cc()._god; _prev = cc()._god;
cc()._god = true; cc()._god = true;
} }
inline Client::GodScope::~GodScope(){ inline Client::GodScope::~GodScope(){
cc()._god = _prev; cc()._god = _prev;
} }
/* this unlocks, does NOT upgrade. that works for our current usage
*/
inline void mongolock::releaseAndWriteLock() {
if( !_writelock ) {
#if BOOST_VERSION >= 103500
int s = dbMutex.getState();
if( s != -1 ) {
log() << "error: releaseAndWriteLock() s == " << s << endl;
msgasserted( 12600, "releaseAndWriteLock: unlock_shared fai
led, probably recursive" );
}
#endif
_writelock = true;
dbMutex.unlock_shared();
dbMutex.lock();
/* this is defensive; as we were unlocked for a moment above,
the Database object we reference could have been deleted:
*/
cc().clearns();
}
}
}; };
 End of changes. 7 change blocks. 
4 lines changed or deleted 38 lines changed or added


 clientcursor.h   clientcursor.h 
skipping to change at line 53 skipping to change at line 53
typedef map<CursorId, ClientCursor*> CCById; typedef map<CursorId, ClientCursor*> CCById;
typedef multimap<DiskLoc, ClientCursor*> CCByLoc; typedef multimap<DiskLoc, ClientCursor*> CCByLoc;
extern BSONObj id_obj; extern BSONObj id_obj;
class ClientCursor { class ClientCursor {
friend class CmdCursorInfo; friend class CmdCursorInfo;
DiskLoc _lastLoc; // use getter and setter n ot this (important) DiskLoc _lastLoc; // use getter and setter n ot this (important)
unsigned _idleAgeMillis; // how long has the cursor been around, relative to server idle time unsigned _idleAgeMillis; // how long has the cursor been around, relative to server idle time
bool _liveForever; // if true, never time out bool _noTimeout; // if true, never time out c
cursor ursor
bool _doingDeletes;
static CCById clientCursorsById; static CCById clientCursorsById;
static CCByLoc byLoc; static CCByLoc byLoc;
static boost::recursive_mutex ccmutex; // must use this for all s tatics above! static boost::recursive_mutex ccmutex; // must use this for all s tatics above!
static CursorId allocCursorId_inlock(); static CursorId allocCursorId_inlock();
public: public:
/*const*/ CursorId cursorid; /*const*/ CursorId cursorid;
string ns; string ns;
auto_ptr<KeyValJSMatcher> matcher; auto_ptr<CoveredIndexMatcher> matcher;
auto_ptr<Cursor> c; auto_ptr<Cursor> c;
int pos; // # objects into the curs or so far int pos; // # objects into the curs or so far
BSONObj query; BSONObj query;
ClientCursor() : _idleAgeMillis(0), _liveForever(false), pos(0) { ClientCursor() : _idleAgeMillis(0), _noTimeout(false), _doingDelete s(false), pos(0) {
recursive_boostlock lock(ccmutex); recursive_boostlock 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;
} }
auto_ptr< FieldMatcher > filter; // which fields query wants return ed auto_ptr< FieldMatcher > filter; // which fields query wants return ed
Message originalMessage; // this is effectively an auto ptr for dat a the matcher points to Message originalMessage; // this is effectively an auto ptr for dat a the matcher points to
/* Get rid of cursors for namespaces that begin with nsprefix. /* Get rid of cursors for namespaces that begin with nsprefix.
Used by drop, deleteIndexes, dropDatabase. Used by drop, deleteIndexes, dropDatabase.
*/ */
static void invalidate(const char *nsPrefix); static void invalidate(const char *nsPrefix);
/**
* do a dbtemprelease
* note: caller should check matcher.docMatcher().atomic() first an
d not yield if atomic -
* we don't do herein as this->matcher (above) is only initia
lized for true queries/getmore.
* (ie not set for remote/update)
* @return if the cursor is still valid.
* if false is returned, then this ClientCursor should be c
onsidered deleted
*/
bool yield();
private: private:
void setLastLoc_inlock(DiskLoc); void setLastLoc_inlock(DiskLoc);
static ClientCursor* find_inlock(CursorId id, bool warn = true) { static ClientCursor* find_inlock(CursorId id, bool warn = true) {
CCById::iterator it = clientCursorsById.find(id); CCById::iterator it = clientCursorsById.find(id);
if ( it == clientCursorsById.end() ) { if ( it == clientCursorsById.end() ) {
if ( warn ) if ( warn )
OCCASIONALLY out() << "ClientCursor::find(): cursor not found in map " << id << " (ok after a drop)\n"; OCCASIONALLY out() << "ClientCursor::find(): cursor not found in map " << id << " (ok after a drop)\n";
return 0; return 0;
} }
skipping to change at line 137 skipping to change at line 147
stringstream ss; stringstream ss;
ss << ns << "." << cursorid; ss << ns << "." << cursorid;
ids_->mayUpgradeStorage( ss.str() );*/ ids_->mayUpgradeStorage( ss.str() );*/
} }
/** /**
* @param millis amount of idle passed time since last call * @param millis amount of idle passed time since last call
*/ */
bool shouldTimeout( unsigned millis ){ bool shouldTimeout( unsigned millis ){
_idleAgeMillis += millis; _idleAgeMillis += millis;
return ! _liveForever && _idleAgeMillis > 600000; return ! _noTimeout && _idleAgeMillis > 600000;
} }
unsigned idleTime(){ unsigned idleTime(){
return _idleAgeMillis; return _idleAgeMillis;
} }
static void idleTimeReport(unsigned millis); static void idleTimeReport(unsigned millis);
void liveForever() { void noTimeout() {
_liveForever = true; _noTimeout = true;
}
void setDoingDeletes( bool doingDeletes ){
_doingDeletes = doingDeletes;
} }
static unsigned byLocSize(); // just for diagnostics static unsigned byLocSize(); // just for diagnostics
// static void idleTimeReport(unsigned millis); // static void idleTimeReport(unsigned millis);
static void informAboutToDeleteBucket(const DiskLoc& b); static void informAboutToDeleteBucket(const DiskLoc& b);
static void aboutToDelete(const DiskLoc& dl); static void aboutToDelete(const DiskLoc& dl);
}; };
} // namespace mongo } // namespace mongo
 End of changes. 6 change blocks. 
7 lines changed or deleted 24 lines changed or added


 cmdline.h   cmdline.h 
skipping to change at line 40 skipping to change at line 40
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
int quotaFiles; // --quotaFiles int quotaFiles; // --quotaFiles
bool cpu; // --cpu show cpu time periodically bool cpu; // --cpu show cpu time periodically
long long oplogSize; // --oplogSize long long oplogSize; // --oplogSize
int defaultProfile; // --profile
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), quiet(false), notablescan(false), prealloc (true), smallfiles(false),
quota(false), quotaFiles(8), cpu(false), oplogSize(0) quota(false), quotaFiles(8), cpu(false), oplogSize(0), defaultP rofile(0), slowMS(100)
{ } { }
}; };
extern CmdLine cmdLine; extern CmdLine cmdLine;
} }
 End of changes. 2 change blocks. 
1 lines changed or deleted 3 lines changed or added


 commands.h   commands.h 
skipping to change at line 45 skipping to change at line 45
/* run the given command /* run the given command
implement this... implement this...
fromRepl - command is being invoked as part of replication synci ng. In this situation you fromRepl - command is being invoked as part of replication synci ng. In this situation you
normally do not want to log the command to the local oplog. normally do not want to log the command to the local oplog.
return value is true if succeeded. if false, set errmsg text. return value is true if succeeded. if false, set errmsg text.
*/ */
virtual bool run(const char *ns, BSONObj& cmdObj, string& errmsg, B SONObjBuilder& result, bool fromRepl) = 0; virtual bool run(const char *ns, BSONObj& cmdObj, string& errmsg, B SONObjBuilder& result, bool fromRepl) = 0;
/* true if a read lock is sufficient
note: logTheTop() MUST be false if readOnly
*/
virtual bool readOnly() {
return false;
}
/* Return true if only the admin ns has privileges to run this comm and. */ /* Return true if only the admin ns has privileges to run this comm and. */
virtual bool adminOnly() { virtual bool adminOnly() {
return false; return false;
} }
/* Like adminOnly, but even stricter: we must either be authenticat
ed for admin db,
or, if running without auth, on the local interface.
When localHostOnlyIfNoAuth() is true, adminOnly() must also be t
rue.
*/
virtual bool localHostOnlyIfNoAuth(const BSONObj& cmdObj) { return
false; }
/* Return true if slaves of a replication pair are allowed to execu te the command /* Return true if slaves of a replication pair are allowed to execu te the command
(the command directly from a client -- if fromRepl, always allow ed). (the command directly from a client -- if fromRepl, always allow ed).
*/ */
virtual bool slaveOk() = 0; virtual bool slaveOk() = 0;
/* Return true if the client force a command to be run on a slave b y /* Return true if the client force a command to be run on a slave b y
turning on the 'slaveok' option in the command query. turning on the 'slaveok' option in the command query.
*/ */
virtual bool slaveOverrideOk() { virtual bool slaveOverrideOk() {
return false; return false;
skipping to change at line 93 skipping to change at line 107
if ( cmdObj["query"].type() == Object ) if ( cmdObj["query"].type() == Object )
return cmdObj["query"].embeddedObject(); return cmdObj["query"].embeddedObject();
if ( cmdObj["q"].type() == Object ) if ( cmdObj["q"].type() == Object )
return cmdObj["q"].embeddedObject(); return cmdObj["q"].embeddedObject();
return BSONObj(); return BSONObj();
} }
}; };
bool runCommandAgainstRegistered(const char *ns, BSONObj& jsobj, BSONOb jBuilder& anObjBuilder); bool runCommandAgainstRegistered(const char *ns, BSONObj& jsobj, BSONOb jBuilder& anObjBuilder);
bool _runCommands(const char *ns, BSONObj& jsobj, stringstream& ss, Buf Builder &b, BSONObjBuilder& anObjBuilder, bool fromRepl, int queryOptions); bool _runCommands(const char *ns, BSONObj& jsobj, BufBuilder &b, BSONOb jBuilder& anObjBuilder, bool fromRepl, int queryOptions);
} // namespace mongo } // namespace mongo
 End of changes. 3 change blocks. 
1 lines changed or deleted 18 lines changed or added


 concurrency.h   concurrency.h 
skipping to change at line 20 skipping to change at line 20
End func name with _inlock to indicate "caller must lock before callin g". End func name with _inlock to indicate "caller must lock before callin g".
*/ */
#pragma once #pragma once
#if BOOST_VERSION >= 103500 #if BOOST_VERSION >= 103500
#include <boost/thread/shared_mutex.hpp> #include <boost/thread/shared_mutex.hpp>
#undef assert #undef assert
#define assert xassert #define assert xassert
#endif
namespace mongo {
#if 0
//#if BOOST_VERSION >= 103500
//typedef boost::shared_mutex MongoMutex;
class MongoMutex {
boost::shared_mutex m;
public:
void lock() {
m.lock();
}
void unlock() { m.unlock(); }
void lock_shared() { m.lock_shared(); }
void unlock_shared() { m.unlock_shared(); }
};
#else
/* this will be for old versions of boost */
class MongoMutex {
boost::recursive_mutex m;
int x;
public:
MongoMutex() { x=0; }
void lock() {
#if BOOST_VERSION >= 103500
m.lock();
#else #else
boost::detail::thread::lock_ops<boost::recursive_mutex>::lock(m #warning built with boost version 1.34 or older limited concurrency
);
#endif
}
void unlock() {
#if BOOST_VERSION >= 103500
m.unlock();
#else
boost::detail::thread::lock_ops<boost::recursive_mutex>::unlock
(m);
#endif #endif
}
void lock_shared() { lock(); } namespace mongo {
void unlock_shared() { unlock(); }
};
#endif
/* 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:
MutexInfo() : locked(0) { MutexInfo() : locked(0) {
start = curTimeMicros64(); start = curTimeMicros64();
} }
skipping to change at line 89 skipping to change at line 50
} }
void leaving() { void leaving() {
locked--; locked--;
assert( locked >= 0 ); assert( locked >= 0 );
if ( locked == 0 ) if ( locked == 0 )
timeLocked += curTimeMicros64() - enter; timeLocked += curTimeMicros64() - enter;
} }
int isLocked() const { int isLocked() const {
return locked; return locked;
} }
void timingInfo(unsigned long long &s, unsigned long long &tl) { void getTimingInfo(unsigned long long &s, unsigned long long &tl) c onst {
s = start; s = start;
tl = timeLocked; tl = timeLocked;
} }
}; };
extern MongoMutex &dbMutex; #if BOOST_VERSION >= 103500
extern MutexInfo dbMutexInfo; //#if 0
class MongoMutex {
MutexInfo _minfo;
boost::shared_mutex _m;
ThreadLocalValue<int> _state;
public:
/**
* @return
* > 0 write lock
* = 0 no lock
* < 0 read lock
*/
int getState(){ return _state.get(); }
void assertWriteLocked() { assert( _state.get() > 0 ); }
bool atLeastReadLocked() { return _state.get() != 0; }
void assertAtLeastReadLocked() { assert(atLeastReadLocked()); }
void lock() {
DEV cout << "LOCK" << endl;
int s = _state.get();
if( s > 0 ) {
_state.set(s+1);
return;
}
massert( 10293 , "internal error: locks are not upgradeable", s
== 0 );
_state.set(1);
_m.lock();
_minfo.entered();
}
void unlock() {
DEV cout << "UNLOCK" << endl;
int s = _state.get();
if( s > 1 ) {
_state.set(s-1);
return;
}
assert( s == 1 );
_state.set(0);
_minfo.leaving();
_m.unlock();
}
void lock_shared() {
DEV cout << " LOCKSHARED" << endl;
int s = _state.get();
if( s ) {
if( s > 0 ) {
// already in write lock - just be recursive and stay w
rite locked
_state.set(s+1);
return;
}
else {
// already in read lock - recurse
_state.set(s-1);
return;
}
}
_state.set(-1);
_m.lock_shared();
}
void unlock_shared() {
DEV cout << " UNLOCKSHARED" << endl;
int s = _state.get();
if( s > 0 ) {
assert( s > 1 ); /* we must have done a lock write first to
have s > 1 */
_state.set(s-1);
return;
}
if( s < -1 ) {
_state.set(s+1);
return;
}
assert( s == -1 );
_state.set(0);
_m.unlock_shared();
}
MutexInfo& info() { return _minfo; }
};
#else
/* this will be for old versions of boost */
class MongoMutex {
MutexInfo _minfo;
boost::recursive_mutex m;
public:
MongoMutex() { }
void lock() {
#if BOOST_VERSION >= 103500
m.lock();
#else
boost::detail::thread::lock_ops<boost::recursive_mutex>::lock(m
);
#endif
_minfo.entered();
}
/* void unlock() {
struct lock { _minfo.leaving();
recursive_boostlock bl_; #if BOOST_VERSION >= 103500
MutexInfo& info_; m.unlock();
lock( boost::recursive_mutex &mutex, MutexInfo &info ) : #else
bl_( mutex ), boost::detail::thread::lock_ops<boost::recursive_mutex>::unlock
info_( info ) { (m);
info_.entered(); #endif
} }
~lock() {
info_.leaving(); void lock_shared() { lock(); }
void unlock_shared() { unlock(); }
MutexInfo& info() { return _minfo; }
void assertWriteLocked() {
assert( info().isLocked() );
} }
void assertAtLeastReadLocked() {
assert( info().isLocked() );
}
bool atLeastReadLocked() { return info().isLocked(); }
int getState(){ return info().isLocked() ? 1 : 0; }
}; };
*/ #endif
extern MongoMutex &dbMutex;
void dbunlocking_write(); void dbunlocking_write();
void dbunlocking_read(); void dbunlocking_read();
struct writelock { struct writelock {
writelock(const string& ns) { writelock(const string& ns) {
dbMutex.lock(); dbMutex.lock();
dbMutexInfo.entered();
} }
~writelock() { ~writelock() {
dbunlocking_write(); dbunlocking_write();
dbMutexInfo.leaving();
dbMutex.unlock(); dbMutex.unlock();
} }
}; };
struct readlock { struct readlock {
readlock(const string& ns) { readlock(const string& ns) {
dbMutex.lock_shared(); dbMutex.lock_shared();
} }
~readlock() { ~readlock() {
dbunlocking_read(); dbunlocking_read();
dbMutex.unlock_shared(); dbMutex.unlock_shared();
} }
}; };
class mongolock { class mongolock {
bool _writelock; bool _writelock;
public: public:
mongolock(bool write) : _writelock(write) { mongolock(bool write) : _writelock(write) {
if( _writelock ) { if( _writelock ) {
dbMutex.lock(); dbMutex.lock();
dbMutexInfo.entered();
} }
else else
dbMutex.lock_shared(); dbMutex.lock_shared();
} }
~mongolock() { ~mongolock() {
if( _writelock ) { if( _writelock ) {
dbunlocking_write(); dbunlocking_write();
dbMutexInfo.leaving();
dbMutex.unlock(); dbMutex.unlock();
} }
else { else {
dbunlocking_read(); dbunlocking_read();
dbMutex.unlock_shared(); dbMutex.unlock_shared();
} }
} }
/* this unlocks, does NOT upgrade. that works for our current usage */ /* this unlocks, does NOT upgrade. that works for our current usage */
void releaseAndWriteLock() { void releaseAndWriteLock();
if( !_writelock ) {
_writelock = true;
dbMutex.unlock_shared();
dbMutex.lock();
dbMutexInfo.entered();
}
}
}; };
/* use writelock and readlock instead */ /* use writelock and readlock instead */
struct dblock : public writelock { struct dblock : public writelock {
dblock() : writelock("") { } dblock() : writelock("") { }
~dblock() { ~dblock() {
} }
}; };
/* a scoped release of a mutex temporarily -- like a scopedlock but rev // eliminate
ersed. inline void assertInWriteLock() { dbMutex.assertWriteLocked(); }
*/
/*
struct temprelease {
boost::mutex& m;
temprelease(boost::mutex& _m) : m(_m) {
#if BOOST_VERSION >= 103500
m.unlock();
#else
boost::detail::thread::lock_ops<boost::mutex>::unlock(m);
#endif
}
~temprelease() {
#if BOOST_VERSION >= 103500
m.lock();
#else
boost::detail::thread::lock_ops<boost::mutex>::lock(m);
#endif
}
};
*/
inline void assertInWriteLock() {
/* TEMP assert( dbMutexInfo.isLocked() );
*/
}
} }
 End of changes. 16 change blocks. 
96 lines changed or deleted 124 lines changed or added


 connpool.h   connpool.h 
skipping to change at line 83 skipping to change at line 83
/** 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.
*/ */
class ScopedDbConnection { class ScopedDbConnection {
const string host; const string host;
DBClientBase *_conn; DBClientBase *_conn;
public: public:
/** get the associated connection object */ /** get the associated connection object */
DBClientBase* operator->(){ DBClientBase* operator->(){
uassert( "did you call done already" , _conn ); uassert( 11004 , "did you call done already" , _conn );
return _conn; return _conn;
} }
/** get the associated connection object */ /** get the associated connection object */
DBClientBase& conn() { DBClientBase& conn() {
uassert( "did you call done already" , _conn ); uassert( 11005 , "did you call done already" , _conn );
return *_conn; return *_conn;
} }
/** throws UserException if can't connect */ /** throws UserException if can't connect */
ScopedDbConnection(const string& _host) : ScopedDbConnection(const string& _host) :
host(_host), _conn( pool.get(_host) ) { host(_host), _conn( pool.get(_host) ) {
//cout << " for: " << _host << " got conn: " << _conn << endl; //cout << " for: " << _host << " got conn: " << _conn << endl;
} }
/** Force closure of the connection. You should call this if you l eave it in /** Force closure of the connection. You should call this if you l eave it in
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 curop.h   curop.h 
// curop.h // curop.h
#pragma once #pragma once
#include "namespace.h" #include "namespace.h"
#include "security.h" #include "security.h"
#include "client.h" #include "client.h"
namespace mongo { namespace mongo {
struct CurOp { class OpDebug {
void reset(time_t now, const sockaddr_in &_client) { public:
active = true; StringBuilder str;
opNum++;
startTime = now; void reset(){
ns[0] = '?'; // just in case not set later str.reset();
*query = 0;
killCurrentOp = 0;
client = _client;
} }
};
bool active; /* Current operation (for the current Client).
unsigned opNum; an embedded member of Client class, and typically used from within t
time_t startTime; he mutex there. */
int op; class CurOp : boost::noncopyable {
char ns[Namespace::MaxNsLen+2]; static WrappingInt _nextOpNum;
char query[128]; static BSONObj _tooBig; // { $msg : "query not recording (too large
char zero; )" }
bool _active;
Timer _timer;
int _op;
WrappingInt _opNum;
char _ns[Namespace::MaxNsLen+2];
struct sockaddr_in client; struct sockaddr_in client;
char _queryBuf[256];
bool haveQuery() const { return *((int *) _queryBuf) != 0; }
void resetQuery(int x=0) { *((int *)_queryBuf) = x; }
BSONObj query() {
if( *((int *) _queryBuf) == 1 ) {
return _tooBig;
}
BSONObj o(_queryBuf);
return o;
}
OpDebug _debug;
public:
void reset( const sockaddr_in &_client) {
_active = true;
_opNum = _nextOpNum.atomicIncrement();
_timer.reset();
_ns[0] = '?'; // just in case not set later
_debug.reset();
resetQuery();
client = _client;
}
OpDebug& debug(){
return _debug;
}
WrappingInt opNum() const { return _opNum; }
bool active() const { return _active; }
int elapsedMillis(){ return _timer.millis(); }
/** micros */
unsigned long long startTime(){
return _timer.startTime();
}
void setActive(bool active) { _active = active; }
void setNS(const char *ns) {
strncpy(_ns, ns, Namespace::MaxNsLen);
}
void setOp(int op) { _op = op; }
void setQuery(const BSONObj& query) {
if( query.objsize() > (int) sizeof(_queryBuf) ) {
resetQuery(1); // flag as too big and return
return;
}
memcpy(_queryBuf, query.objdata(), query.objsize());
}
CurOp() { CurOp() {
active = false; _active = false;
opNum = 0; // opNum = 0;
_op = 0;
// These addresses should never be written to again. The zeroe s are // These addresses should never be written to again. The zeroe s are
// placed here as a precaution because currentOp may be accesse d // placed here as a precaution because currentOp may be accesse d
// without the db mutex. // without the db mutex.
ns[sizeof(ns)-1] = 0; memset(_ns, 0, sizeof(_ns));
query[sizeof(query)-1] = 0; memset(_queryBuf, 0, sizeof(_queryBuf));
} }
BSONObj info() { BSONObj info() {
AuthenticationInfo *ai = currentClient.get()->ai; AuthenticationInfo *ai = currentClient.get()->ai;
if( !ai->isAuthorized("admin") ) { if( !ai->isAuthorized("admin") ) {
BSONObjBuilder b; BSONObjBuilder b;
b.append("err", "unauthorized"); b.append("err", "unauthorized");
return b.obj(); return b.obj();
} }
return infoNoauth(); return infoNoauth();
} }
BSONObj infoNoauth() { BSONObj infoNoauth() {
BSONObjBuilder b; BSONObjBuilder b;
b.append("opid", opNum); b.append("opid", _opNum);
b.append("active", active); b.append("active", _active);
if( active ) if( _active )
b.append("secs_running", (int) (time(0)-startTime)); b.append("secs_running", _timer.seconds() );
if( op == 2004 ) if( _op == 2004 )
b.append("op", "query"); b.append("op", "query");
else if( op == 2005 ) else if( _op == 2005 )
b.append("op", "getMore"); b.append("op", "getMore");
else if( op == 2001 ) else if( _op == 2001 )
b.append("op", "update"); b.append("op", "update");
else if( op == 2002 ) else if( _op == 2002 )
b.append("op", "insert"); b.append("op", "insert");
else if( op == 2006 ) else if( _op == 2006 )
b.append("op", "delete"); b.append("op", "delete");
else else
b.append("op", op); b.append("op", _op);
b.append("ns", ns); b.append("ns", _ns);
b.append("query", query);
b.append("inLock", dbMutexInfo.isLocked()); if( haveQuery() ) {
b.append("query", query());
}
// b.append("inLock", ??
stringstream clientStr; stringstream clientStr;
clientStr << inet_ntoa( client.sin_addr ) << ":" << ntohs( clie nt.sin_port ); clientStr << inet_ntoa( client.sin_addr ) << ":" << ntohs( clie nt.sin_port );
b.append("client", clientStr.str()); b.append("client", clientStr.str());
return b.obj(); return b.obj();
} }
}; };
/* 0 = ok
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
*/
extern class KillCurrentOp {
enum { Off, On, All } state;
WrappingInt toKill;
public:
void killAll() { state = All; }
void kill(WrappingInt i) { toKill = i; state = On; }
void checkForInterrupt() {
if( state != Off ) {
if( state == All )
uasserted(11600,"interrupted at shutdown");
if( cc().curop()->opNum() == toKill ) {
state = Off;
uasserted(11601,"interrupted");
}
}
}
} killCurrentOp;
} }
 End of changes. 13 change blocks. 
33 lines changed or deleted 114 lines changed or added


 cursor.h   cursor.h 
skipping to change at line 28 skipping to change at line 28
#include "../stdafx.h" #include "../stdafx.h"
#include "jsobj.h" #include "jsobj.h"
#include "storage.h" #include "storage.h"
namespace mongo { namespace mongo {
class Record; class Record;
/* 0 = ok
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
*/
extern int killCurrentOp;
inline void checkForInterrupt() {
if( killCurrentOp ) {
if( !goingAway ) {
// if we are shutting down, we leave this on so potentially
we can stop multiple operations
killCurrentOp = 0;
}
uasserted("interrupted");
}
}
/* Query cursors, base class. This is for our internal cursors. "Clie ntCursor" is a separate /* Query cursors, base class. This is for our internal cursors. "Clie ntCursor" is a separate
concept and is for the user's cursor. concept and is for the user's cursor.
WARNING concurrency: the vfunctions below are called back from withi n a WARNING concurrency: the vfunctions below are called back from withi n a
ClientCursor::ccmutex. Don't cause a deadlock, you've been warned. ClientCursor::ccmutex. Don't cause a deadlock, you've been warned.
*/ */
class Cursor { class Cursor {
public: public:
virtual ~Cursor() {} virtual ~Cursor() {}
virtual bool ok() = 0; virtual bool ok() = 0;
skipping to change at line 156 skipping to change at line 141
BSONObj j(r); BSONObj j(r);
return j; return j;
} }
virtual DiskLoc currLoc() { virtual DiskLoc currLoc() {
return curr; return curr;
} }
virtual DiskLoc refLoc() { virtual DiskLoc refLoc() {
return curr.isNull() ? last : curr; return curr.isNull() ? last : curr;
} }
bool advance() { bool advance();
checkForInterrupt();
if ( eof() ) {
if ( tailable_ && !last.isNull() ) {
curr = s->next( last );
} else {
return false;
}
} else {
last = curr;
curr = s->next( curr );
}
return ok();
}
BasicCursor(DiskLoc dl, const AdvanceStrategy *_s = forward()) : cu rr(dl), s( _s ) { BasicCursor(DiskLoc dl, const AdvanceStrategy *_s = forward()) : cu rr(dl), s( _s ) {
init(); init();
} }
BasicCursor(const AdvanceStrategy *_s = forward()) : s( _s ) { BasicCursor(const AdvanceStrategy *_s = forward()) : s( _s ) {
init(); init();
} }
virtual string toString() { virtual string toString() {
return "BasicCursor"; return "BasicCursor";
} }
 End of changes. 2 change blocks. 
32 lines changed or deleted 1 lines changed or added


 database.h   database.h 
skipping to change at line 21 skipping to change at line 21
* 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 "cmdline.h"
/* Database represents a database database /* Database represents a database database
Each database database has its own set of files -- dbname.ns, dbname.0, dbname.1, ... Each database database has its own set of files -- dbname.ns, dbname.0, dbname.1, ...
*/ */
namespace mongo { namespace mongo {
class Database { class Database {
public: public:
static bool _openAllFiles;
Database(const char *nm, bool& newDb, const string& _path = dbpath) : Database(const char *nm, bool& newDb, const string& _path = dbpath) :
name(nm), name(nm),
path(_path), path(_path),
namespaceIndex( path, name ) namespaceIndex( path, name )
{ {
{ {
int L = strlen(nm); int L = strlen(nm);
uassert( "db name is empty", L > 0 ); uassert( 10028 , "db name is empty", L > 0 );
uassert( "bad db name [1]", *nm != '.' ); uassert( 10029 , "bad db name [1]", *nm != '.' );
uassert( "bad db name [2]", nm[L-1] != '.' ); uassert( 10030 , "bad db name [2]", nm[L-1] != '.' );
uassert( "bad char(s) in db name", strchr(nm, ' ') == 0 ); uassert( 10031 , "bad char(s) in db name", strchr(nm, ' ')
uassert( "db name too long", L < 64 ); == 0 );
uassert( 10032 , "db name too long", L < 64 );
} }
newDb = namespaceIndex.exists(); newDb = namespaceIndex.exists();
profile = 0;
profileName = name + ".system.profile";
// If already exists, open. Otherwise behave as if empty until // If already exists, open. Otherwise behave as if empty until
// there's a write, then open. // there's a write, then open.
if ( !newDb ) if ( ! newDb || cmdLine.defaultProfile ) {
namespaceIndex.init(); namespaceIndex.init();
profile = 0; if( _openAllFiles )
profileName = name + ".system.profile"; openAllFiles();
}
} }
~Database() { ~Database() {
btreeStore->closeFiles(name, path); btreeStore->closeFiles(name, path);
int n = files.size(); int n = files.size();
for ( int i = 0; i < n; i++ ) for ( int i = 0; i < n; i++ )
delete files[i]; delete files[i];
} }
bool exists(int n) {
stringstream ss;
ss << name << '.' << n;
boost::filesystem::path fullName;
fullName = boost::filesystem::path(path) / ss.str();
return boost::filesystem::exists(fullName);
}
void openAllFiles() {
int n = 0;
while( exists(n) ) {
getFile(n);
n++;
}
}
MongoDataFile* getFile( int n, int sizeNeeded = 0, bool preallocate Only = false ) { MongoDataFile* getFile( int n, int sizeNeeded = 0, bool preallocate Only = false ) {
assert(this); assert(this);
namespaceIndex.init(); namespaceIndex.init();
if ( n < 0 || n >= DiskLoc::MaxFiles ) { if ( n < 0 || n >= DiskLoc::MaxFiles ) {
out() << "getFile(): n=" << n << endl; out() << "getFile(): n=" << n << endl;
#if !defined(_RECSTORE) #if !defined(_RECSTORE)
if( n >= RecCache::Base && n <= RecCache::Base+1000 ) if( n >= RecCache::Base && n <= RecCache::Base+1000 )
massert("getFile(): bad file number - using recstore db w/nonrecstore db build?", false); massert( 10294 , "getFile(): bad file number - using re cstore db w/nonrecstore db build?", false);
#endif #endif
massert("getFile(): bad file number value (corrupt db?): ru n repair", false); massert( 10295 , "getFile(): bad file number value (corrupt db?): run repair", false);
} }
DEV { DEV {
if ( n > 100 ) if ( n > 100 )
out() << "getFile(): n=" << n << "?" << endl; out() << "getFile(): n=" << n << "?" << endl;
} }
MongoDataFile* p = 0; MongoDataFile* p = 0;
if ( !preallocateOnly ) { if ( !preallocateOnly ) {
while ( n >= (int) files.size() ) while ( n >= (int) files.size() )
files.push_back(0); files.push_back(0);
p = files[n]; p = files[n];
skipping to change at line 115 skipping to change at line 142
} }
MongoDataFile* addAFile( int sizeNeeded = 0, bool preallocateNextFi le = false ) { MongoDataFile* addAFile( int sizeNeeded = 0, bool preallocateNextFi le = false ) {
int n = (int) files.size(); int n = (int) files.size();
MongoDataFile *ret = getFile( n, sizeNeeded ); MongoDataFile *ret = getFile( n, sizeNeeded );
if ( preallocateNextFile ) if ( preallocateNextFile )
preallocateAFile(); preallocateAFile();
return ret; return ret;
} }
// ok to call multiple times // safe to call this multiple times - the implementation will only preallocate one file
void preallocateAFile() { void preallocateAFile() {
int n = (int) files.size(); int n = (int) files.size();
getFile( n, 0, true ); getFile( n, 0, true );
} }
MongoDataFile* suitableFile( int sizeNeeded ) { MongoDataFile* suitableFile( int sizeNeeded ) {
MongoDataFile* f = newestFile(); MongoDataFile* f = newestFile();
for ( int i = 0; i < 8; i++ ) { for ( int i = 0; i < 8; i++ ) {
if ( f->getHeader()->unusedLength >= sizeNeeded ) if ( f->getHeader()->unusedLength >= sizeNeeded )
break; break;
f = addAFile( sizeNeeded ); f = addAFile( sizeNeeded );
if ( f->getHeader()->fileLength >= MongoDataFile::maxSize() ) // this is as big as they get so might as well stop if ( f->getHeader()->fileLength >= MongoDataFile::maxSize() ) // this is as big as they get so might as well stop
break; break;
} }
return f; return f;
} }
Extent* allocExtent( const char *ns, int size, bool capped ) {
Extent *e = DataFileMgr::allocFromFreeList( ns, size, capped );
if( e ) return e;
return suitableFile( size )->createExtent( ns, size, capped );
}
MongoDataFile* newestFile() { MongoDataFile* newestFile() {
int n = (int) files.size(); int n = (int) files.size();
if ( n > 0 ) n--; if ( n > 0 ) n--;
return getFile(n); return getFile(n);
} }
void finishInit(); // ugly... /**
* @return true if success, false otherwise
*/
bool setProfilingLevel( int newLevel , string& errmsg );
void finishInit();
vector<MongoDataFile*> files; vector<MongoDataFile*> files;
string name; // "alleyinsider" string name; // "alleyinsider"
string path; string path;
NamespaceIndex namespaceIndex; NamespaceIndex namespaceIndex;
int profile; // 0=off. int profile; // 0=off.
string profileName; // "alleyinsider.system.profile" string profileName; // "alleyinsider.system.profile"
}; };
 End of changes. 13 change blocks. 
12 lines changed or deleted 51 lines changed or added


 db.h   db.h 
skipping to change at line 55 skipping to change at line 55
extern map<string,Database*> databases; extern map<string,Database*> databases;
extern bool master; extern bool master;
/* sometimes we deal with databases with the same name in different dir ectories - thus this */ /* sometimes we deal with databases with the same name in different dir ectories - thus this */
inline string makeDbKeyStr( const char *ns, const string& path ) { inline string makeDbKeyStr( const char *ns, const string& path ) {
char cl[256]; char cl[256];
nsToClient(ns, cl); nsToClient(ns, cl);
return string( cl ) + ":" + path; return string( cl ) + ":" + path;
} }
inline void resetClient(const char *ns, const string& path=dbpath) {
dbMutex.assertAtLeastReadLocked();
string key = makeDbKeyStr( ns, path );
map<string,Database*>::iterator it = databases.find(key);
if ( it != databases.end() ) {
cc().setns(ns, it->second);
return;
}
assert(false);
}
/* returns true if the database ("database") did not exist, and it was created on this call /* returns true if the database ("database") did not exist, and it was created on this call
path - datafiles directory, if not the default, so we can differenti ate between db's of the same path - datafiles directory, if not the default, so we can differenti ate between db's of the same
name in different places (for example temp ones on repair). name in different places (for example temp ones on repair).
*/ */
inline bool setClient(const char *ns, const string& path=dbpath) { inline bool setClient(const char *ns, const string& path=dbpath, mongol ock *lock = 0) {
if( logLevel > 5 ) if( logLevel > 5 )
log() << "setClient: " << ns << endl; log() << "setClient: " << ns << endl;
dbMutex.assertAtLeastReadLocked();
cc().top.clientStart( ns ); cc().top.clientStart( ns );
string key = makeDbKeyStr( ns, path ); string key = makeDbKeyStr( ns, path );
map<string,Database*>::iterator it = databases.find(key); map<string,Database*>::iterator it = databases.find(key);
if ( it != databases.end() ) { if ( it != databases.end() ) {
cc().setns(ns, it->second); cc().setns(ns, it->second);
return false; return false;
} }
if( lock )
lock->releaseAndWriteLock();
// when master for replication, we advertise all the db's, and that // when master for replication, we advertise all the db's, and that
// looks like a 'first operation'. so that breaks this log message' s // looks like a 'first operation'. so that breaks this log message' s
// meaningfulness. instead of fixing (which would be better), we j ust // meaningfulness. instead of fixing (which would be better), we j ust
// stop showing for now. // stop showing for now.
// 2008-12-22 We now open every database on startup, so this log is // 2008-12-22 We now open every database on startup, so this log is
// no longer helpful. Commenting. // no longer helpful. Commenting.
// if( !master ) // if( !master )
// log() << "first operation for database " << key << endl; // log() << "first operation for database " << key << endl;
assertInWriteLock(); assertInWriteLock();
char cl[256]; char cl[256];
nsToClient(ns, cl); nsToClient(ns, cl);
bool justCreated; bool justCreated;
Database *newdb = new Database(cl, justCreated, path); Database *newdb = new Database(cl, justCreated, path);
databases[key] = newdb; databases[key] = newdb;
newdb->finishInit();
cc().setns(ns, newdb); cc().setns(ns, newdb);
newdb->finishInit();
return justCreated; return justCreated;
} }
// shared functionality for removing references to a database from this pro gram instance // shared functionality for removing references to a database from this pro gram instance
// does not delete the files on disk // does not delete the files on disk
void closeClient( const char *cl, const string& path = dbpath ); void closeDatabase( const char *cl, const string& path = dbpath );
/* remove database from the databases map */ /* remove database from the databases map */
inline void eraseDatabase( const char *ns, const string& path=dbpath ) { inline void eraseDatabase( const char *ns, const string& path=dbpath ) {
string key = makeDbKeyStr( ns, path ); string key = makeDbKeyStr( ns, path );
databases.erase( key ); databases.erase( key );
} }
inline bool clientIsEmpty() { inline bool clientIsEmpty() {
return !cc().database()->namespaceIndex.allocated(); return !cc().database()->namespaceIndex.allocated();
} }
struct dbtemprelease { struct dbtemprelease {
string clientname; string clientname;
string clientpath; string clientpath;
int locktype;
dbtemprelease() { dbtemprelease() {
Client& client = cc(); Client& client = cc();
Database *database = client.database(); Database *database = client.database();
if ( database ) { if ( database ) {
clientname = database->name; clientname = database->name;
clientpath = database->path; clientpath = database->path;
} }
client.top.clientStop(); client.top.clientStop();
dbMutexInfo.leaving(); locktype = dbMutex.getState();
dbMutex.unlock(); assert( locktype );
if ( locktype > 0 ) {
massert( 10298 , "can't temprelease nested w
rite lock", locktype == 1);
dbMutex.unlock();
}
else {
massert( 10299 , "can't temprelease nested r
ead lock", locktype == -1);
dbMutex.unlock_shared();
}
} }
~dbtemprelease() { ~dbtemprelease() {
dbMutex.lock(); if ( locktype > 0 )
dbMutexInfo.entered(); dbMutex.lock();
else
dbMutex.lock_shared();
if ( clientname.empty() ) if ( clientname.empty() )
cc().setns("", 0); cc().setns("", 0);
else else
setClient(clientname.c_str(), clientpath.c_str()); setClient(clientname.c_str(), clientpath.c_str());
} }
}; };
/**
only does a temp release if we're not nested and have a lock
*/
struct dbtempreleasecond {
dbtemprelease * real;
int locktype;
dbtempreleasecond(){
real = 0;
locktype = dbMutex.getState();
if ( locktype == 1 || locktype == -1 )
real = new dbtemprelease();
}
~dbtempreleasecond(){
if ( real ){
delete real;
real = 0;
}
}
};
extern TicketHolder connTicketHolder;
} // namespace mongo } // namespace mongo
#include "dbinfo.h" //#include "dbinfo.h"
#include "concurrency.h" #include "concurrency.h"
 End of changes. 13 change blocks. 
10 lines changed or deleted 65 lines changed or added


 dbclient.h   dbclient.h 
skipping to change at line 300 skipping to change at line 300
/** /**
The interface that any db connection should implement The interface that any db connection should implement
*/ */
class DBClientInterface : boost::noncopyable { class DBClientInterface : boost::noncopyable {
public: public:
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0, virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0,
const BSONObj *fieldsToRetur n = 0, int queryOptions = 0) = 0; const BSONObj *fieldsToRetur n = 0, int queryOptions = 0) = 0;
virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo ng cursorId, int nToReturn = 0, int options = 0 ) = 0; virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo ng cursorId, int nToReturn = 0, int options = 0 ) = 0;
virtual BSONObj findOne(const string &ns, Query query, const BSONOb
j *fieldsToReturn = 0, int queryOptions = 0) = 0;
virtual void insert( const string &ns, BSONObj obj ) = 0; virtual void insert( const string &ns, BSONObj obj ) = 0;
virtual void insert( const string &ns, const vector< BSONObj >& v ) = 0; virtual void insert( const string &ns, const vector< BSONObj >& v ) = 0;
virtual void remove( const string &ns , Query query, bool justOne = 0 ) = 0; virtual void remove( const string &ns , Query query, bool justOne = 0 ) = 0;
virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = 0 , bool multi = 0 ) = 0; virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = 0 , bool multi = 0 ) = 0;
virtual ~DBClientInterface() { } virtual ~DBClientInterface() { }
/**
@return a single object that matches the query. if none do, the
n the object is empty
@throws AssertionException
*/
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&); bool isOk(const BSONObj&);
set<string> _seenIndexes; set<string> _seenIndexes;
public: public:
skipping to change at line 414 skipping to change at line 419
/** Reset the previous error state for this connection (accessed vi a getLastError and /** Reset the previous error state for this connection (accessed vi a getLastError and
getPrevError). Useful when performing several operations at on ce and then checking getPrevError). Useful when performing several operations at on ce and then checking
for an error after attempting all operations. for an error after attempting all operations.
*/ */
bool resetError() { return simpleCommand("admin", 0, "reseterror"); } bool resetError() { return simpleCommand("admin", 0, "reseterror"); }
/** Delete the specified collection. */ /** Delete the specified collection. */
virtual bool dropCollection( const string &ns ){ virtual bool dropCollection( const string &ns ){
string db = nsGetDB( ns ); string db = nsGetDB( ns );
string coll = nsGetCollection( ns ); string coll = nsGetCollection( ns );
uassert( "no collection name", coll.size() ); uassert( 10011 , "no collection name", coll.size() );
BSONObj info; BSONObj info;
bool res = runCommand( db.c_str() , BSON( "drop" << coll ) , in fo ); bool res = runCommand( db.c_str() , BSON( "drop" << coll ) , in fo );
resetIndexCache(); resetIndexCache();
return res; return res;
} }
/** Perform a repair and compaction of the specified database. May take a long time to run. Disk space /** Perform a repair and compaction of the specified database. May take a long time to run. Disk space
must be available equal to the size of the database while repair ing. must be available equal to the size of the database while repair ing.
skipping to change at line 644 skipping to change at line 649
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0, virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0,
const BSONObj *fieldsToRetur n = 0, int queryOptions = 0); const BSONObj *fieldsToRetur n = 0, int queryOptions = 0);
/** @param cursorId id of cursor to retrieve /** @param cursorId id of cursor to retrieve
@return an handle to a previously allocated cursor @return an handle to a previously allocated cursor
@throws AssertionException @throws AssertionException
*/ */
virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo ng cursorId, int nToReturn = 0, int options = 0 ); virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo ng cursorId, int nToReturn = 0, int options = 0 );
/** /**
@return a single object that matches the query. if none do, the
n the object is empty
@throws AssertionException
*/
virtual BSONObj findOne(const string &ns, Query query, const BSONOb
j *fieldsToReturn = 0, int queryOptions = 0);
/**
insert an object into the database insert an object into the database
*/ */
virtual void insert( const string &ns , BSONObj obj ); virtual void insert( const string &ns , BSONObj obj );
/** /**
insert a vector of objects into the database insert a vector of objects into the database
*/ */
virtual void insert( const string &ns, const vector< BSONObj >& v ) ; virtual void insert( const string &ns, const vector< BSONObj >& v ) ;
/** /**
skipping to change at line 680 skipping to change at line 679
virtual string getServerAddress() const = 0; virtual string getServerAddress() const = 0;
virtual bool isFailed() const = 0; virtual bool isFailed() const = 0;
}; };
class DBClientPaired; class DBClientPaired;
class ConnectException : public UserException { class ConnectException : public UserException {
public: public:
ConnectException(string msg) : UserException(msg) { } ConnectException(string msg) : UserException(9000,msg) { }
}; };
/** /**
A basic connection to the database. A basic connection to the database.
This is the main entry point for talking to a simple Mongo setup This is the main entry point for talking to a simple Mongo setup
*/ */
class DBClientConnection : public DBClientBase { class DBClientConnection : public DBClientBase {
DBClientPaired *clientPaired; DBClientPaired *clientPaired;
auto_ptr<MessagingPort> p; auto_ptr<MessagingPort> p;
auto_ptr<SockAddr> server; auto_ptr<SockAddr> server;
 End of changes. 5 change blocks. 
13 lines changed or deleted 11 lines changed or added


 dbhelpers.h   dbhelpers.h 
skipping to change at line 25 skipping to change at line 25
* 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/>.
*/ */
/* db helpers are helper functions and classes that let us easily manipulat e the local /* db helpers are helper functions and classes that let us easily manipulat e the local
database instance. database instance.
*/ */
#pragma once #pragma once
#include "../stdafx.h"
#include "client.h"
#include "db.h"
namespace mongo { namespace mongo {
class Cursor;
class CoveredIndexMatcher;
class CursorIterator {
public:
CursorIterator( auto_ptr<Cursor> c , BSONObj filter = BSONObj() );
BSONObj next();
bool hasNext();
private:
void _advance();
auto_ptr<Cursor> _cursor;
auto_ptr<CoveredIndexMatcher> _matcher;
BSONObj _o;
};
/**
all helpers assume locking is handled above them
*/
struct Helpers { struct Helpers {
/* ensure the specified index exists. /* ensure the specified index exists.
@param keyPattern key pattern, e.g., { ts : 1 } @param keyPattern key pattern, e.g., { ts : 1 }
@param name index name, e.g., "name_1" @param name index name, e.g., "name_1"
This method can be a little (not much) cpu-slow, so you may wish to use This method can be a little (not much) cpu-slow, so you may wish to use
OCCASIONALLY ensureIndex(...); OCCASIONALLY ensureIndex(...);
skipping to change at line 52 skipping to change at line 76
/* fetch a single object from collection ns that matches query. /* fetch a single object from collection ns that matches query.
set your db SavedContext first. set your db SavedContext first.
@param requireIndex if true, complain if no index for the query. a way to guard against @param requireIndex if true, complain if no index for the query. a way to guard against
writing a slow query. writing a slow query.
@return true if object found @return true if object found
*/ */
static bool findOne(const char *ns, BSONObj query, BSONObj& result, bool requireIndex = false); static bool findOne(const char *ns, BSONObj query, BSONObj& result, bool requireIndex = false);
/** static bool findById(const char *ns, BSONObj query, BSONObj& result
-1 no index );
0 not found
1 found static auto_ptr<CursorIterator> find( const char *ns , BSONObj quer
*/ y = BSONObj() , bool requireIndex = false );
static int findById(const char *ns, BSONObj query, BSONObj& result
);
/* Get/put the first object from a collection. Generally only usef ul if the collection /* Get/put the first object from a collection. Generally only usef ul if the collection
only ever has a single object -- which is a "singleton collectio n". only ever has a single object -- which is a "singleton collectio n".
You do not need to set the database before calling. You do not need to set the database before calling.
Returns: true if object exists. Returns: true if object exists.
*/ */
static bool getSingleton(const char *ns, BSONObj& result); static bool getSingleton(const char *ns, BSONObj& result);
static void putSingleton(const char *ns, BSONObj obj); static void putSingleton(const char *ns, BSONObj obj);
skipping to change at line 110 skipping to change at line 131
~DBContext() { ~DBContext() {
cc().setns(oldns.c_str(), olddb); cc().setns(oldns.c_str(), olddb);
} }
}; };
// manage a set using collection backed storage // manage a set using collection backed storage
class DbSet { class DbSet {
public: public:
DbSet( const string &name = "", const BSONObj &key = BSONObj() ) : DbSet( const string &name = "", const BSONObj &key = BSONObj() ) :
name_( name ), name_( name ),
key_( key.getOwned() ) { key_( key.getOwned() ) {
} }
~DbSet(); ~DbSet();
void reset( const string &name = "", const BSONObj &key = BSONObj() ); void reset( const string &name = "", const BSONObj &key = BSONObj() );
bool get( const BSONObj &obj ) const; bool get( const BSONObj &obj ) const;
void set( const BSONObj &obj, bool val ); void set( const BSONObj &obj, bool val );
private: private:
string name_; string name_;
BSONObj key_; BSONObj key_;
}; };
 End of changes. 4 change blocks. 
9 lines changed or deleted 31 lines changed or added


 dbmessage.h   dbmessage.h 
skipping to change at line 119 skipping to change at line 119
query = (const char *) i; query = (const char *) i;
} }
/* for insert and update msgs */ /* for insert and update msgs */
bool moreJSObjs() { bool moreJSObjs() {
return nextjsobj != 0; return nextjsobj != 0;
} }
BSONObj nextJsObj() { BSONObj nextJsObj() {
if ( nextjsobj == data ) if ( nextjsobj == data )
nextjsobj += strlen(data) + 1; // skip namespace nextjsobj += strlen(data) + 1; // skip namespace
massert( "Remaining data too small for BSON object", theEnd - n extjsobj > 3 ); massert( 10304 , "Remaining data too small for BSON object", t heEnd - nextjsobj > 3 );
BSONObj js(nextjsobj); BSONObj js(nextjsobj);
massert( "Invalid object size", js.objsize() > 3 ); massert( 10305 , "Invalid object size", js.objsize() > 3 );
massert( "Next object larger than available space", massert( 10306 , "Next object larger than available space",
js.objsize() < ( theEnd - data ) ); js.objsize() < ( theEnd - data ) );
if ( objcheck && !js.valid() ) { if ( objcheck && !js.valid() ) {
massert("bad object in message", false); massert( 10307 , "bad object in message", false);
} }
nextjsobj += js.objsize(); nextjsobj += js.objsize();
if ( nextjsobj >= theEnd ) if ( nextjsobj >= theEnd )
nextjsobj = 0; nextjsobj = 0;
return js; return js;
} }
const Message& msg() { const Message& msg() {
return m; return m;
} }
 End of changes. 3 change blocks. 
4 lines changed or deleted 4 lines changed or added


 engine.h   engine.h 
skipping to change at line 73 skipping to change at line 73
virtual ScriptingFunction createFunction( const char * code ); virtual ScriptingFunction createFunction( const char * code );
/** /**
* @return 0 on success * @return 0 on success
*/ */
virtual int invoke( ScriptingFunction func , const BSONObj& args, i nt timeoutMs = 0 , bool ignoreReturn = false ) = 0; virtual int invoke( ScriptingFunction func , const BSONObj& args, i nt timeoutMs = 0 , bool ignoreReturn = false ) = 0;
void invokeSafe( ScriptingFunction func , const BSONObj& args, int timeoutMs = 0 ){ void invokeSafe( ScriptingFunction func , const BSONObj& args, int timeoutMs = 0 ){
int res = invoke( func , args , timeoutMs ); int res = invoke( func , args , timeoutMs );
if ( res == 0 ) if ( res == 0 )
return; return;
throw UserException( (string)"invoke failed: " + getError() ); throw UserException( 9004 , (string)"invoke failed: " + getErro r() );
} }
virtual string getError() = 0; virtual string getError() = 0;
int invoke( const char* code , const BSONObj& args, int timeoutMs = 0 ); int invoke( const char* code , const BSONObj& args, int timeoutMs = 0 );
void invokeSafe( const char* code , const BSONObj& args, int timeou tMs = 0 ){ void invokeSafe( const char* code , const BSONObj& args, int timeou tMs = 0 ){
if ( invoke( code , args , timeoutMs ) == 0 ) if ( invoke( code , args , timeoutMs ) == 0 )
return; return;
throw UserException( (string)"invoke failed: " + getError() ); throw UserException( 9005 , (string)"invoke failed: " + getErro r() );
} }
virtual bool exec( const string& code , const string& name , bool p rintResult , bool reportError , bool assertOnError, int timeoutMs = 0 ) = 0 ; virtual bool exec( const string& code , const string& name , bool p rintResult , bool reportError , bool assertOnError, int timeoutMs = 0 ) = 0 ;
virtual void execSetup( const string& code , const string& name = " setup" ){ virtual void execSetup( const string& code , const string& name = " setup" ){
exec( code , name , false , true , true , 0 ); exec( code , name , false , true , true , 0 );
} }
virtual bool execFile( const string& filename , bool printResult , bool reportError , bool assertOnError, int timeoutMs = 0 ); virtual bool execFile( const string& filename , bool printResult , bool reportError , bool assertOnError, int timeoutMs = 0 );
virtual void injectNative( const char *field, NativeFunction func ) = 0; virtual void injectNative( const char *field, NativeFunction func ) = 0;
skipping to change at line 106 skipping to change at line 106
/** /**
if any changes are made to .system.js, call this if any changes are made to .system.js, call this
right now its just global - slightly inefficient, but a lot simple r right now its just global - slightly inefficient, but a lot simple r
*/ */
static void storedFuncMod(); static void storedFuncMod();
static int getNumScopes(){ static int getNumScopes(){
return _numScopes; return _numScopes;
} }
static void validateObjectIdString( const string &str );
protected: protected:
virtual ScriptingFunction _createFunction( const char * code ) = 0; virtual ScriptingFunction _createFunction( const char * code ) = 0;
string _localDBName; string _localDBName;
long long _loadedVersion; long long _loadedVersion;
static long long _lastVersion; static long long _lastVersion;
map<string,ScriptingFunction> _cachedFunctions; map<string,ScriptingFunction> _cachedFunctions;
static int _numScopes; static int _numScopes;
}; };
class ScriptEngine : boost::noncopyable { class ScriptEngine : boost::noncopyable {
public: public:
ScriptEngine(); ScriptEngine();
virtual ~ScriptEngine(); virtual ~ScriptEngine();
virtual Scope * createScope() = 0; virtual Scope * newScope() {
Scope *s = createScope();
if ( s && _scopeInitCallback )
_scopeInitCallback( *s );
return s;
}
virtual void runTest() = 0; virtual void runTest() = 0;
virtual bool utf8Ok() const = 0; virtual bool utf8Ok() const = 0;
static void setup(); static void setup();
auto_ptr<Scope> getPooledScope( const string& pool ); auto_ptr<Scope> getPooledScope( const string& pool );
void threadDone(); void threadDone();
struct Unlocker { virtual ~Unlocker() {} };
virtual auto_ptr<Unlocker> newThreadUnlocker() { return auto_ptr< U
nlocker >( new Unlocker ); }
void setScopeInitCallback( void ( *func )( Scope & ) ) { _scopeInit
Callback = func; }
protected:
virtual Scope * createScope() = 0;
private:
void ( *_scopeInitCallback )( Scope & );
}; };
extern ScriptEngine * globalScriptEngine; extern ScriptEngine * globalScriptEngine;
} }
 End of changes. 5 change blocks. 
3 lines changed or deleted 23 lines changed or added


 engine_java.h   engine_java.h 
skipping to change at line 197 skipping to change at line 197
JavaJS->scopeSetThis( s , obj ); JavaJS->scopeSetThis( s , obj );
} }
void setNumber(const char *field, double val ) { void setNumber(const char *field, double val ) {
JavaJS->scopeSetNumber(s,field,val); JavaJS->scopeSetNumber(s,field,val);
} }
void setString(const char *field, const char * val ) { void setString(const char *field, const char * val ) {
JavaJS->scopeSetString(s,field,val); JavaJS->scopeSetString(s,field,val);
} }
void setObject(const char *field, const BSONObj& obj , bool readOnl y ) { void setObject(const char *field, const BSONObj& obj , bool readOnl y ) {
uassert( "only readOnly setObject supported in java" , readOnly ); uassert( 10211 , "only readOnly setObject supported in java" , readOnly );
JavaJS->scopeSetObject(s,field,&obj); JavaJS->scopeSetObject(s,field,&obj);
} }
void setBoolean(const char *field, bool val ) { void setBoolean(const char *field, bool val ) {
JavaJS->scopeSetBoolean(s,field,val); JavaJS->scopeSetBoolean(s,field,val);
} }
ScriptingFunction createFunction( const char * code ){ ScriptingFunction createFunction( const char * code ){
return JavaJS->functionCreate( code ); return JavaJS->functionCreate( code );
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 engine_v8.h   engine_v8.h 
skipping to change at line 42 skipping to change at line 42
V8Scope( V8ScriptEngine * engine ); V8Scope( V8ScriptEngine * engine );
~V8Scope(); ~V8Scope();
virtual void reset(); virtual void reset();
virtual void init( BSONObj * data ); virtual void init( BSONObj * data );
virtual void localConnect( const char * dbName ); virtual void localConnect( const char * dbName );
virtual void externalSetup(); virtual void externalSetup();
v8::Handle<v8::Value> get( const char * field ); v8::Handle<v8::Value> get( const char * field ); // caller must cre ate context and handle scopes
virtual double getNumber( const char *field ); virtual double getNumber( const char *field );
virtual int getNumberInt( const char *field ); virtual int getNumberInt( const char *field );
virtual long long getNumberLongLong( const char *field ); virtual long long getNumberLongLong( const char *field );
virtual string getString( const char *field ); virtual string getString( const char *field );
virtual bool getBoolean( const char *field ); virtual bool getBoolean( const char *field );
virtual BSONObj getObject( const char *field ); virtual BSONObj getObject( const char *field );
virtual int type( const char *field ); virtual int type( const char *field );
virtual void setNumber( const char *field , double val ); virtual void setNumber( const char *field , double val );
virtual void setString( const char *field , const char * val ); virtual void setString( const char *field , const char * val );
virtual void setBoolean( const char *field , bool val ); virtual void setBoolean( const char *field , bool val );
virtual void setElement( const char *field , const BSONElement& e ) ; virtual void setElement( const char *field , const BSONElement& e ) ;
virtual void setObject( const char *field , const BSONObj& obj , bo ol readOnly); virtual void setObject( const char *field , const BSONObj& obj , bo ol readOnly);
virtual void setThis( const BSONObj * obj ); virtual void setThis( const BSONObj * obj );
virtual ScriptingFunction _createFunction( const char * code ); virtual ScriptingFunction _createFunction( const char * code );
Local< v8::Function > __createFunction( const char * code );
virtual int invoke( ScriptingFunction func , const BSONObj& args, i nt timeoutMs = 0 , bool ignoreReturn = false ); virtual int invoke( ScriptingFunction func , const BSONObj& args, i nt timeoutMs = 0 , bool ignoreReturn = false );
virtual bool exec( const string& code , const string& name , bool p rintResult , bool reportError , bool assertOnError, int timeoutMs ); virtual bool exec( const string& code , const string& name , bool p rintResult , bool reportError , bool assertOnError, int timeoutMs );
virtual string getError(){ return _error; } virtual string getError(){ return _error; }
virtual void injectNative( const char *field, NativeFunction func ) virtual void injectNative( const char *field, NativeFunction func )
{ ;
Handle< FunctionTemplate > f( v8::FunctionTemplate::New( native
Callback ) );
f->Set( v8::String::New( "_native_function" ), External::New( (
void*)func ) );
_global->Set( v8::String::New( field ), f->GetFunction() );
}
void gc(){} // no-op in v8 void gc();
Handle< Context > context() const { return _context; }
private: private:
void _startCall(); void _startCall();
static Handle< Value > nativeCallback( const Arguments &args ); static Handle< Value > nativeCallback( const Arguments &args );
static Handle< Value > loadCallback( const Arguments &args ); static Handle< Value > loadCallback( const Arguments &args );
V8ScriptEngine * _engine; V8ScriptEngine * _engine;
HandleScope _handleScope; Persistent<Context> _context;
Handle<Context> _context; Persistent<v8::Object> _global;
Context::Scope _scope;
Handle<v8::Object> _global;
string _error; string _error;
vector< v8::Handle<Value> > _funcs; vector< Persistent<Value> > _funcs;
v8::Handle<v8::Object> _this; v8::Persistent<v8::Object> _this;
v8::Handle<v8::Function> _wrapper; v8::Persistent<v8::Function> _wrapper;
enum ConnectState { NOT , LOCAL , EXTERNAL }; enum ConnectState { NOT , LOCAL , EXTERNAL };
ConnectState _connectState; ConnectState _connectState;
string _localDBName;
}; };
class V8ScriptEngine : public ScriptEngine { class V8ScriptEngine : public ScriptEngine {
public: public:
V8ScriptEngine(); V8ScriptEngine();
virtual ~V8ScriptEngine(); virtual ~V8ScriptEngine();
virtual Scope * createScope(){ return new V8Scope( this ); } virtual Scope * createScope(){ return new V8Scope( this ); }
virtual void runTest(){} virtual void runTest(){}
bool utf8Ok() const { return true; } bool utf8Ok() const { return true; }
private: class V8Unlocker : public Unlocker {
//HandleScope _handleScope; v8::Unlocker u_;
//Handle<ObjectTemplate> _globalTemplate; };
//Handle<FunctionTemplate> _externalTemplate; virtual auto_ptr<Unlocker> newThreadUnlocker() { return auto_ptr< U
//Handle<FunctionTemplate> _localTemplate; nlocker >( new V8Unlocker ); }
private:
friend class V8Scope; friend class V8Scope;
}; };
extern ScriptEngine * globalScriptEngine; extern ScriptEngine * globalScriptEngine;
} }
 End of changes. 10 change blocks. 
23 lines changed or deleted 19 lines changed or added


 extsort.h   extsort.h 
skipping to change at line 99 skipping to change at line 99
void add( const BSONObj& o , const DiskLoc & loc ); void add( const BSONObj& o , const DiskLoc & loc );
void add( const BSONObj& o , int a , int b ){ void add( const BSONObj& o , int a , int b ){
add( o , DiskLoc( a , b ) ); add( o , DiskLoc( a , b ) );
} }
/* call after adding values, and before fetching the iterator */ /* call after adding values, and before fetching the iterator */
void sort(); void sort();
auto_ptr<Iterator> iterator(){ auto_ptr<Iterator> iterator(){
uassert( "not sorted" , _sorted ); uassert( 10052 , "not sorted" , _sorted );
return auto_ptr<Iterator>( new Iterator( this ) ); return auto_ptr<Iterator>( new Iterator( this ) );
} }
int numFiles(){ int numFiles(){
return _files.size(); return _files.size();
} }
private: private:
void sort( string file ); void sort( string file );
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 file.h   file.h 
skipping to change at line 70 skipping to change at line 70
} }
public: public:
File() { File() {
fd = INVALID_HANDLE_VALUE; fd = INVALID_HANDLE_VALUE;
_bad = true; _bad = true;
} }
~File() { ~File() {
if( is_open() ) CloseHandle(fd); if( is_open() ) CloseHandle(fd);
fd = INVALID_HANDLE_VALUE; fd = INVALID_HANDLE_VALUE;
} }
void open(const char *filename) { void open(const char *filename, bool readOnly=false ) {
std::wstring filenamew = toWideString(filename); std::wstring filenamew = toWideString(filename);
fd = CreateFile( fd = CreateFile(
filenamew.c_str(), GENERIC_WRITE | GENERIC_READ, FILE_SHAR E_READ, filenamew.c_str(), ( readOnly ? 0 : GENERIC_WRITE ) | GENE RIC_READ, FILE_SHARE_READ,
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if( !is_open() ) { if( !is_open() ) {
out() << "CreateFile failed " << filename << endl; out() << "CreateFile failed " << filename << endl;
} }
else else
_bad = false; _bad = false;
} }
void write(fileofs o, const char *data, unsigned len) { void write(fileofs o, const char *data, unsigned len) {
LARGE_INTEGER li; LARGE_INTEGER li;
li.QuadPart = o; li.QuadPart = o;
skipping to change at line 97 skipping to change at line 97
} }
void read(fileofs o, char *data, unsigned len) { void read(fileofs o, char *data, unsigned len) {
DWORD read; DWORD read;
LARGE_INTEGER li; LARGE_INTEGER li;
li.QuadPart = o; li.QuadPart = o;
SetFilePointerEx(fd, li, NULL, FILE_BEGIN); SetFilePointerEx(fd, li, NULL, FILE_BEGIN);
int ok = ReadFile(fd, data, len, &read, 0); int ok = ReadFile(fd, data, len, &read, 0);
if( !ok ) if( !ok )
err(ok); err(ok);
else else
massert("ReadFile error - truncated file?", read == len); massert( 10438 , "ReadFile error - truncated file?", read == le n);
} }
bool bad() { return _bad; } bool bad() { return _bad; }
bool is_open() { return fd != INVALID_HANDLE_VALUE; } bool is_open() { return fd != INVALID_HANDLE_VALUE; }
fileofs len() { fileofs len() {
LARGE_INTEGER li; LARGE_INTEGER li;
li.LowPart = GetFileSize(fd, (DWORD *) &li.HighPart); li.LowPart = GetFileSize(fd, (DWORD *) &li.HighPart);
if( li.HighPart == 0 && li.LowPart == INVALID_FILE_SIZE ) { if( li.HighPart == 0 && li.LowPart == INVALID_FILE_SIZE ) {
err( false ); err( false );
return 0; return 0;
} }
skipping to change at line 121 skipping to change at line 121
}; };
#else #else
class File : public FileInterface { class File : public FileInterface {
int fd; int fd;
bool _bad; bool _bad;
void err(bool ok) { void err(bool ok) {
if( !ok && !_bad ) { if( !ok && !_bad ) {
_bad = true; _bad = true;
log() << "File I/O error " << errno << '\n'; log() << "File I/O " << OUTPUT_ERRNO << '\n';
} }
} }
public: public:
File() { File() {
fd = -1; fd = -1;
_bad = true; _bad = true;
} }
~File() { ~File() {
if( is_open() ) ::close(fd); if( is_open() ) ::close(fd);
fd = -1; fd = -1;
} }
#ifndef O_NOATIME #ifndef O_NOATIME
#define O_NOATIME 0 #define O_NOATIME 0
#define lseek64 lseek #define lseek64 lseek
#endif #endif
void open(const char *filename) { void open(const char *filename, bool readOnly=false ) {
fd = ::open(filename, O_CREAT | O_RDWR | O_NOATIME, S_IRUSR | S_IWU fd = ::open(filename, O_CREAT | ( readOnly ? 0 : O_RDWR ) | O_NOATI
SR); ME, S_IRUSR | S_IWUSR);
if ( fd <= 0 ) { if ( fd <= 0 ) {
out() << "couldn't open " << filename << ' ' << errno << endl; out() << "couldn't open " << filename << ' ' << OUTPUT_ERRNO << endl;
return; return;
} }
_bad = false; _bad = false;
} }
void write(fileofs o, const char *data, unsigned len) { void write(fileofs o, const char *data, unsigned len) {
lseek64(fd, o, SEEK_SET); lseek64(fd, o, SEEK_SET);
err( ::write(fd, data, len) == (int) len ); err( ::write(fd, data, len) == (int) len );
} }
void read(fileofs o, char *data, unsigned len) { void read(fileofs o, char *data, unsigned len) {
lseek(fd, o, SEEK_SET); lseek(fd, o, SEEK_SET);
 End of changes. 6 change blocks. 
8 lines changed or deleted 8 lines changed or added


 file_allocator.h   file_allocator.h 
skipping to change at line 52 skipping to change at line 52
#endif #endif
void start() { void start() {
#if !defined(_WIN32) #if !defined(_WIN32)
Runner r( *this ); Runner r( *this );
boost::thread t( r ); boost::thread t( r );
#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,
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.
*/
#if !defined(_WIN32) #if !defined(_WIN32)
boostlock lk( pendingMutex_ ); boostlock lk( pendingMutex_ );
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();
skipping to change at line 150 skipping to change at line 154
boostlock lk( a_.pendingMutex_ ); boostlock 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 {
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;
ss << "couldn't open " << name << ' ' << er ss << "couldn't open " << name << ' ' << OU
rno; TPUT_ERRNO;
massert( ss.str(), fd <= 0 ); massert( 10439 , ss.str(), fd <= 0 );
} }
#if defined(POSIX_FADV_DONTNEED) #if defined(POSIX_FADV_DONTNEED)
if( posix_fadvise(fd, 0, size, POSIX_FADV_DONTN EED) ) { if( posix_fadvise(fd, 0, size, POSIX_FADV_DONTN EED) ) {
log() << "warning: posix_fadvise fails " << name << ' ' << errno << endl; log() << "warning: posix_fadvise fails " << name << ' ' << OUTPUT_ERRNO << endl;
} }
#endif #endif
/* make sure the file is the full desired lengt h */ /* make sure the file is the full desired lengt h */
off_t filelen = lseek(fd, 0, SEEK_END); off_t filelen = lseek(fd, 0, SEEK_END);
if ( filelen < size ) { if ( filelen < size ) {
massert( "failure creating new datafile", f ilelen == 0 ); massert( 10440 , "failure creating new dat afile", filelen == 0 );
// Check for end of disk. // Check for end of disk.
massert( "Unable to allocate file of desire d size", massert( 10441 , "Unable to allocate file of desired size",
size - 1 == lseek(fd, size - 1, SEE K_SET) ); size - 1 == lseek(fd, size - 1, SEE K_SET) );
massert( "Unable to allocate file of desire d size", massert( 10442 , "Unable to allocate file of desired size",
1 == write(fd, "", 1) ); 1 == write(fd, "", 1) );
lseek(fd, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);
log() << "allocating new datafile " << name << ", filling with zeroes..." << endl; log() << "allocating new datafile " << name << ", filling with zeroes..." << endl;
Timer t; Timer t;
long z = 256 * 1024; long z = 256 * 1024;
char buf[z]; char buf[z];
memset(buf, 0, z); memset(buf, 0, z);
long left = size; long left = size;
while ( 1 ) { while ( 1 ) {
if ( left <= z ) { if ( left <= z ) {
massert( "write failed", left == wr ite(fd, buf, left) ); massert( 10443 , "write failed", l eft == write(fd, buf, left) );
break; break;
} }
massert( "write failed", z == write(fd, buf, z) ); massert( 10444 , "write failed", z == write(fd, buf, z) );
left -= z; left -= z;
} }
log() << "done allocating datafile " << nam e << ", size: " << size/1024/1024 << "MB, took " << ((double)t.millis())/10 00.0 << " secs" << endl; log() << "done allocating datafile " << nam e << ", size: " << size/1024/1024 << "MB, took " << ((double)t.millis())/10 00.0 << " secs" << endl;
} }
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 {
 End of changes. 8 change blocks. 
9 lines changed or deleted 16 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)
} // 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 107 skipping to change at line 107
p -= 16; p -= 16;
for ( int i = 0; i < 16; i++ ) for ( int i = 0; i < 16; i++ )
cout << (unsigned) ((unsigned char)*p++) << ' '; cout << (unsigned) ((unsigned char)*p++) << ' ';
cout << endl; cout << endl;
len -= 16; len -= 16;
} }
} catch (...) { } catch (...) {
} }
} }
// PRINT(2+2); prints "2+2: 4"
#define PRINT(x) cout << #x ": " << (x) << endl
// PRINTFL; prints file:line
#define PRINTFL cout << __FILE__ ":" << __LINE__ << endl
#undef yassert #undef yassert
#undef assert #undef assert
#define assert xassert #define assert xassert
#define yassert 1 #define yassert 1
struct WrappingInt { struct WrappingInt {
WrappingInt() { WrappingInt() {
x = 0; x = 0;
} }
skipping to change at line 182 skipping to change at line 187
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
} }
#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__)
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;
boost::thread::sleep(xt); boost::thread::sleep(xt);
} }
inline void sleepmillis(int s) { inline void sleepmillis(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 / 1000 ); xt.sec += ( s / 1000 );
skipping to change at line 211 skipping to change at line 215
boost::xtime xt; boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC); boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += ( s / 1000000 ); xt.sec += ( s / 1000000 );
xt.nsec += ( s % 1000000 ) * 1000; xt.nsec += ( s % 1000000 ) * 1000;
if ( xt.nsec >= 1000000000 ) { if ( xt.nsec >= 1000000000 ) {
xt.nsec -= 1000000000; xt.nsec -= 1000000000;
xt.sec++; xt.sec++;
} }
boost::thread::sleep(xt); boost::thread::sleep(xt);
} }
#else
inline void sleepsecs(int s) {
struct timespec t;
t.tv_sec = s;
t.tv_nsec = 0;
if ( nanosleep( &t , 0 ) ){
cout << "nanosleep failed" << endl;
}
}
inline void sleepmicros(int s) {
struct timespec t;
t.tv_sec = (int)(s / 1000000);
t.tv_nsec = s % 1000000;
if ( nanosleep( &t , 0 ) ){
cout << "nanosleep failed" << endl;
}
}
inline void sleepmillis(int s) {
sleepmicros( s * 1000 );
}
#endif
// note this wraps // note this wraps
inline int tdiff(unsigned told, unsigned tnew) { inline int tdiff(unsigned told, unsigned tnew) {
return WrappingInt::diff(tnew, told); return WrappingInt::diff(tnew, told);
} }
inline unsigned curTimeMillis() { inline unsigned curTimeMillis() {
boost::xtime xt; boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC); boost::xtime_get(&xt, boost::TIME_UTC);
unsigned t = xt.nsec / 1000000; unsigned t = xt.nsec / 1000000;
return (xt.sec & 0xfffff) * 1000 + t; return (xt.sec & 0xfffff) * 1000 + t;
} }
struct Date_t { struct Date_t {
// TODO: make signed (and look for related TODO's) // TODO: make signed (and look for related TODO's)
unsigned long long millis; unsigned long long millis;
Date_t(): millis(0) {} Date_t(): millis(0) {}
Date_t(unsigned long long m): millis(m) {} Date_t(unsigned long long m): millis(m) {}
operator unsigned long long&() { return millis; } operator unsigned long long&() { return millis; }
operator const unsigned long long&() const { return millis; } operator const unsigned long long&() const { return millis; }
}; };
inline unsigned long long jsTime() { inline Date_t jsTime() {
boost::xtime xt; boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC); boost::xtime_get(&xt, boost::TIME_UTC);
unsigned long long t = xt.nsec / 1000000; unsigned long long t = xt.nsec / 1000000;
return ((unsigned long long) xt.sec * 1000) + t; return ((unsigned long long) xt.sec * 1000) + t;
} }
inline unsigned long long curTimeMicros64() { inline unsigned long long curTimeMicros64() {
boost::xtime xt; boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC); boost::xtime_get(&xt, boost::TIME_UTC);
unsigned long long t = xt.nsec / 1000; unsigned long long t = xt.nsec / 1000;
skipping to change at line 285 skipping to change at line 267
using namespace boost; using namespace boost;
typedef boost::mutex::scoped_lock boostlock; typedef boost::mutex::scoped_lock boostlock;
typedef boost::recursive_mutex::scoped_lock recursive_boostlock; typedef boost::recursive_mutex::scoped_lock recursive_boostlock;
// simple scoped timer // simple scoped timer
class Timer { class Timer {
public: public:
Timer() { Timer() {
reset(); reset();
} }
Timer( unsigned long long start ) {
old = start;
}
int seconds(){ int seconds(){
return (int)(micros() / 1000000); return (int)(micros() / 1000000);
} }
int millis() { int millis() {
return (long)(micros() / 1000); return (long)(micros() / 1000);
} }
unsigned long long micros() { unsigned long long micros() {
unsigned long long n = curTimeMicros64(); unsigned long long n = curTimeMicros64();
return n - old; return n - old;
} }
unsigned long long micros(unsigned long long & n) { // returns cur time in addition to timer result unsigned long long micros(unsigned long long & n) { // returns cur time in addition to timer result
n = curTimeMicros64(); n = curTimeMicros64();
return n - old; return n - old;
} }
unsigned long long startTime(){
return old;
}
void reset() { void reset() {
old = curTimeMicros64(); old = curTimeMicros64();
} }
private: private:
unsigned long long old; unsigned long long old;
}; };
/* /*
class DebugMutex : boost::noncopyable { class DebugMutex : boost::noncopyable {
skipping to change at line 386 skipping to change at line 374
/* thread local "value" rather than a pointer /* thread local "value" rather than a pointer
good for things which have copy constructors (and the copy construct or is fast enough) good for things which have copy constructors (and the copy construct or is fast enough)
e.g. e.g.
ThreadLocalValue<int> myint; ThreadLocalValue<int> myint;
*/ */
template<class T> template<class T>
class ThreadLocalValue { class ThreadLocalValue {
public: public:
ThreadLocalValue( T def = 0 ) : _default( def ) { } ThreadLocalValue( T def = 0 ) : _default( def ) { }
int get() { T get() {
T * val = _val.get(); T * val = _val.get();
if ( val ) if ( val )
return *val; return *val;
return _default; return _default;
} }
void set( const T& i ) { void set( const T& i ) {
T *v = _val.get(); T *v = _val.get();
if( v ) { if( v ) {
*v = i; *v = i;
return; return;
} }
v = new T(i); v = new T(i);
_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 Interval = 100 ) ProgressMeter( long long total , int secondsBetween = 3 , int check Interval = 100 )
: _total( total ) , _secondsBetween( secondsBetween ) , _checkI nterval( checkInterval ) , : _total( total ) , _secondsBetween( secondsBetween ) , _checkI nterval( checkInterval ) ,
_done(0) , _hits(0) , _lastTime( (int) time(0) ){ _done(0) , _hits(0) , _lastTime( (int) time(0) ){
skipping to change at line 450 skipping to change at line 440
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 {
public:
TicketHolder( int num ){
_outof = num;
_num = num;
}
bool tryAcquire(){
boostlock lk( _mutex );
if ( _num <= 0 ){
if ( _num < 0 ){
cerr << "DISASTER! in TicketHolder" << endl;
}
return false;
}
_num--;
return true;
}
void release(){
boostlock lk( _mutex );
_num++;
}
void resize( int newSize ){
boostlock lk( _mutex );
int used = _outof - _num;
if ( used > newSize ){
cout << "ERROR: can't resize since we're using (" << used <
< ") more than newSize(" << newSize << ")" << endl;
return;
}
_outof = newSize;
_num = _outof - used;
}
int available(){
return _num;
}
int used(){
return _outof - _num;
}
private:
int _outof;
int _num;
boost::mutex _mutex;
};
class TicketHolderReleaser {
public:
TicketHolderReleaser( TicketHolder * holder ){
_holder = holder;
}
~TicketHolderReleaser(){
_holder->release();
}
private:
TicketHolder * _holder;
};
} // namespace mongo } // namespace mongo
 End of changes. 11 change blocks. 
26 lines changed or deleted 80 lines changed or added


 gridfs.h   gridfs.h 
skipping to change at line 160 skipping to change at line 160
} }
gridfs_offset getContentLength(){ gridfs_offset getContentLength(){
return (gridfs_offset)(_obj["length"].number()); return (gridfs_offset)(_obj["length"].number());
} }
string getContentType(){ string getContentType(){
return _obj["contentType"].valuestr(); return _obj["contentType"].valuestr();
} }
unsigned long long getUploadDate(){ Date_t getUploadDate(){
return _obj["uploadDate"].date(); return _obj["uploadDate"].date();
} }
string getMD5(){ string getMD5(){
return _obj["md5"].str(); return _obj["md5"].str();
} }
BSONElement getFileField( const string& name ){ BSONElement getFileField( const string& name ){
return _obj[name]; return _obj[name];
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 instance.h   instance.h 
skipping to change at line 46 skipping to change at line 46
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;
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 << "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() ) {
problem() << "couldn't open log stream" << endl; problem() << "couldn't open log stream" << endl;
throw 1717; throw 1717;
} }
} }
} }
/** /**
* @return old * @return old
skipping to change at line 102 skipping to change at line 102
} }
~DbResponse() { ~DbResponse() {
delete response; delete response;
} }
}; };
static SockAddr unknownAddress( "0.0.0.0", 0 ); static SockAddr unknownAddress( "0.0.0.0", 0 );
bool assembleResponse( Message &m, DbResponse &dbresponse, const sockad dr_in &client = unknownAddress.sa ); bool assembleResponse( Message &m, DbResponse &dbresponse, const sockad dr_in &client = unknownAddress.sa );
void receivedKillCursors(Message& m);
void receivedUpdate(Message& m, stringstream& ss);
void receivedDelete(Message& m, stringstream& ss);
void receivedInsert(Message& m, stringstream& ss);
bool receivedGetMore(DbResponse& dbresponse, Message& m, stringstream&
ss);
bool receivedQuery(DbResponse& dbresponse, Message& m, stringstream& ss
, bool logit);
void getDatabaseNames( vector< string > &names ); void getDatabaseNames( vector< string > &names );
// must call with db lock // must call with db lock
void registerListenerSocket( int socket ); void registerListenerSocket( int socket );
// --- local client --- // --- local client ---
class DBDirectClient : public DBClientBase { class DBDirectClient : public DBClientBase {
public:
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer
y, int nToReturn = 0, int nToSkip = 0,
const BSONObj *fieldsToRetur
n = 0, int queryOptions = 0);
virtual bool isFailed() const { virtual bool isFailed() const {
return false; return false;
} }
virtual string toString() { virtual string toString() {
return "DBDirectClient"; return "DBDirectClient";
} }
virtual string getServerAddress() const{ virtual string getServerAddress() const{
return "localhost"; // TODO: should this have the port? return "localhost"; // TODO: should this have the port?
} }
virtual bool call( Message &toSend, Message &response, bool assertO k=true ); virtual bool call( Message &toSend, Message &response, bool assertO k=true );
skipping to change at line 136 skipping to change at line 135
virtual void say( Message &toSend ); virtual void say( Message &toSend );
virtual void sayPiggyBack( Message &toSend ) { virtual void sayPiggyBack( Message &toSend ) {
// don't need to piggy back when connected locally // don't need to piggy back when connected locally
return say( toSend ); return say( toSend );
} }
class AlwaysAuthorized : public AuthenticationInfo { class AlwaysAuthorized : public AuthenticationInfo {
virtual bool isAuthorized( const char *dbname ) { virtual bool isAuthorized( const char *dbname ) {
return true; return true;
} }
}; };
/* TODO: this looks bad that auth is set to always. is that really always safe? */ /* TODO: this looks bad that auth is set to always. is that really always safe? */
class SavedContext { class SavedContext {
public: public:
SavedContext() { SavedContext() {
dblock lk; _save = dbMutex.atLeastReadLocked();
Client *c = currentClient.get(); Client *c = currentClient.get();
if ( c->database() )
oldName = c->database()->name;
oldAuth = c->ai; oldAuth = c->ai;
// careful, don't want to free this: // careful, don't want to free this:
c->ai = &always; c->ai = &always;
/* it only makes sense to manipulate a pointer - c->databas
e() - if locked.
thus the _saved flag.
*/
if( _save ) {
if ( c->database() ) {
dbMutex.assertAtLeastReadLocked();
_oldName = c->database()->name;
}
}
} }
~SavedContext() { ~SavedContext() {
Client *c = currentClient.get(); Client *c = currentClient.get();
c->ai = oldAuth; c->ai = oldAuth;
if ( !oldName.empty() ) { if( _save ) {
dblock lk; if ( !_oldName.empty() ) {
setClient( oldName.c_str() ); dbMutex.assertAtLeastReadLocked();
setClient( _oldName.c_str() );
}
}
else {
// defensive
cc().clearns();
} }
} }
private: private:
bool _save;
static AlwaysAuthorized always; static AlwaysAuthorized always;
AuthenticationInfo *oldAuth; AuthenticationInfo *oldAuth;
string oldName; string _oldName;
}; };
}; };
extern int lockFile; extern int lockFile;
void acquirePathLock(); void acquirePathLock();
} // namespace mongo } // namespace mongo
 End of changes. 10 change blocks. 
16 lines changed or deleted 33 lines changed or added


 jsobj.h   jsobj.h 
skipping to change at line 323 skipping to change at line 323
/** @return value of a boolean element. /** @return value of a boolean element.
You must assure element is a boolean before You must assure element is a boolean before
calling. */ calling. */
bool boolean() const { bool boolean() const {
return *value() ? true : false; return *value() ? true : false;
} }
/** Retrieve a java style date value from the element. /** Retrieve a java style date value from the element.
Ensure element is of type Date before calling. Ensure element is of type Date before calling.
*/ */
unsigned long long date() const { Date_t date() const {
return *reinterpret_cast< const unsigned long long* >( value() return *reinterpret_cast< const Date_t* >( value() );
);
} }
/** Convert the value to boolean, regardless of its type, in a java script-like fashion /** Convert the value to boolean, regardless of its type, in a java script-like fashion
(i.e., treat zero and null as false). (i.e., treat zero and null as false).
*/ */
bool trueValue() const { bool trueValue() const {
switch( type() ) { switch( type() ) {
case NumberLong: case NumberLong:
return *reinterpret_cast< const long long* >( value() ) != 0; return *reinterpret_cast< const long long* >( value() ) != 0;
case NumberDouble: case NumberDouble:
return *reinterpret_cast< const double* >( value() ) != 0; return *reinterpret_cast< const double* >( value() ) != 0;
case NumberInt: case NumberInt:
return *reinterpret_cast< const int* >( value() ) != 0; return *reinterpret_cast< const int* >( value() ) != 0;
case Bool: case Bool:
return boolean(); return boolean();
case EOO: case EOO:
case jstNULL: case jstNULL:
case Undefined:
return false; return false;
default: default:
; ;
} }
return true; return true;
} }
/** True if element is of a numeric type. */ /** True if element is of a numeric type. */
bool isNumber() const { bool isNumber() const {
skipping to change at line 496 skipping to change at line 497
string ascode() const { string ascode() const {
switch( type() ){ switch( type() ){
case String: case String:
case Code: case Code:
return valuestr(); return valuestr();
case CodeWScope: case CodeWScope:
return codeWScopeCode(); return codeWScopeCode();
default: default:
log() << "can't convert type: " << (int)(type()) << " to co de" << endl; log() << "can't convert type: " << (int)(type()) << " to co de" << endl;
} }
uassert( "not code" , 0 ); uassert( 10062 , "not code" , 0 );
return ""; return "";
} }
/** Get binary data. Element must be of type BinData */ /** Get binary data. Element must be of type BinData */
const char *binData(int& len) const { const char *binData(int& len) const {
// BinData: <int len> <byte subtype> <byte[len] data> // BinData: <int len> <byte subtype> <byte[len] data>
assert( type() == BinData ); assert( type() == BinData );
len = valuestrsize(); len = valuestrsize();
return value() + 5; return value() + 5;
} }
skipping to change at line 586 skipping to change at line 587
/** Check that data is internally consistent. */ /** Check that data is internally consistent. */
void validate() const; void validate() const;
/** True if this element may contain subobjects. */ /** True if this element may contain subobjects. */
bool mayEncapsulate() const { bool mayEncapsulate() const {
return type() == Object || return type() == Object ||
type() == Array || type() == Array ||
type() == CodeWScope; type() == CodeWScope;
} }
unsigned long long timestampTime() const{ Date_t timestampTime() const{
unsigned long long t = ((unsigned int*)(value() + 4 ))[0]; unsigned long long t = ((unsigned int*)(value() + 4 ))[0];
return t * 1000; return t * 1000;
} }
unsigned int timestampInc() const{ unsigned int timestampInc() const{
return ((unsigned int*)(value() ))[0]; return ((unsigned int*)(value() ))[0];
} }
const char * dbrefNS() const { const char * dbrefNS() const {
uassert( "not a dbref" , type() == DBRef ); uassert( 10063 , "not a dbref" , type() == DBRef );
return value() + 4; return value() + 4;
} }
const OID& dbrefOID() const { const OID& dbrefOID() const {
uassert( "not a dbref" , type() == DBRef ); uassert( 10064 , "not a dbref" , type() == DBRef );
const char * start = value(); const char * start = value();
start += 4 + *reinterpret_cast< const int* >( start ); start += 4 + *reinterpret_cast< const int* >( start );
return *reinterpret_cast< const OID* >( start ); return *reinterpret_cast< const OID* >( start );
} }
bool operator<( const BSONElement& other ) const { bool operator<( const BSONElement& other ) const {
int x = (int)canonicalType() - (int)other.canonicalType(); int x = (int)canonicalType() - (int)other.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(*this,other) < 0; return compareElementValues(*this,other) < 0;
} }
protected:
// If maxLen is specified, don't scan more than maxLen bytes. // If maxLen is specified, don't scan more than maxLen bytes.
BSONElement(const char *d, int maxLen = -1) : data(d) { BSONElement(const char *d, int maxLen = -1) : data(d) {
fieldNameSize_ = -1; fieldNameSize_ = -1;
if ( eoo() ) if ( eoo() )
fieldNameSize_ = 0; fieldNameSize_ = 0;
else { else {
if ( maxLen != -1 ) { if ( maxLen != -1 ) {
int size = strnlen( fieldName(), maxLen - 1 ); int size = strnlen( fieldName(), maxLen - 1 );
massert( "Invalid field name", size != -1 ); massert( 10333 , "Invalid field name", size != -1 );
fieldNameSize_ = size + 1; fieldNameSize_ = size + 1;
} }
} }
totalSize = -1; totalSize = -1;
} }
private: private:
const char *data; const char *data;
mutable int fieldNameSize_; // cached value mutable int fieldNameSize_; // cached value
int fieldNameSize() const { int fieldNameSize() const {
if ( fieldNameSize_ == -1 ) if ( fieldNameSize_ == -1 )
fieldNameSize_ = strlen( fieldName() ) + 1; fieldNameSize_ = strlen( fieldName() ) + 1;
return fieldNameSize_; return fieldNameSize_;
} }
mutable int totalSize; /* caches the computed size */ mutable int totalSize; /* caches the computed size */
}; };
int getGtLtOp(const BSONElement& e); int getGtLtOp(const BSONElement& e);
/* compare values with type check.
note: as is now, not smart about int/double comingling. TODO
*/
inline int compareValues(const BSONElement& l, const BSONElement& r)
{
int x = (int) l.type() - (int) r.type();
if( x ) return x;
return compareElementValues(l,r);
}
struct BSONElementCmpWithoutField { struct BSONElementCmpWithoutField {
bool operator()( const BSONElement &l, const BSONElement &r ) const { bool operator()( const BSONElement &l, const BSONElement &r ) const {
return l.woCompare( r, false ); return l.woCompare( r, false );
} }
}; };
typedef set< BSONElement, BSONElementCmpWithoutField > BSONElementSet; typedef set< BSONElement, BSONElementCmpWithoutField > BSONElementSet;
/** /**
C++ representation of a "BSON" object -- that is, an extended JSO N-style C++ representation of a "BSON" object -- that is, an extended JSO N-style
skipping to change at line 718 skipping to change at line 708
}; };
const char *_objdata; const char *_objdata;
boost::shared_ptr< Holder > _holder; boost::shared_ptr< Holder > _holder;
void init(const char *data, bool ifree) { void init(const char *data, bool ifree) {
if ( ifree ) if ( ifree )
_holder.reset( new Holder( data ) ); _holder.reset( new Holder( data ) );
_objdata = data; _objdata = data;
if ( ! isValid() ){ if ( ! isValid() ){
stringstream ss; stringstream ss;
ss << "Invalid BSONObj spec size: " << objsize(); ss << "Invalid BSONObj spec size: " << objsize();
try {
BSONElement e = firstElement();
ss << " first element:" << e.toString() << " ";
}
catch ( ... ){}
string s = ss.str(); string s = ss.str();
massert( s , 0 ); massert( 10334 , s , 0 );
} }
} }
#pragma pack(1) #pragma pack(1)
static struct EmptyObject { static struct EmptyObject {
EmptyObject() { EmptyObject() {
len = 5; len = 5;
jstype = EOO; jstype = EOO;
} }
int len; int len;
char jstype; char jstype;
skipping to change at line 829 skipping to change at line 814
bool hasField( const char * name )const { bool hasField( const char * name )const {
return ! getField( name ).eoo(); return ! getField( name ).eoo();
} }
/** @return "" if DNE or wrong type */ /** @return "" if DNE or wrong type */
const char * getStringField(const char *name) const; const char * getStringField(const char *name) const;
/** @return subobject of the given name */ /** @return subobject of the given name */
BSONObj getObjectField(const char *name) const; BSONObj getObjectField(const char *name) const;
/** @return INT_MIN if not present */ /** @return INT_MIN if not present - does some type conversions */
int getIntField(const char *name) const; int getIntField(const char *name) const;
/** @return false if not present */ /** @return false if not present */
bool getBoolField(const char *name) const; bool getBoolField(const char *name) const;
/** makes a new BSONObj with the fields specified in pattern. /** makes a new BSONObj with the fields specified in pattern.
fields returned in the order they appear in pattern. fields returned in the order they appear in pattern.
if any field is missing from the object, that field in the if any field is missing or undefined in the object, that field i
key will be null. n the
output will be null.
sets element field names to empty string sets output field names to match pattern field names.
If an array is encountered while scanning the dotted names in pa ttern, If an array is encountered while scanning the dotted names in pa ttern,
that array is added to the returned obj, rather than any subobje that field is treated as missing.
cts
referenced within the array. The variable nameWithinArray is se
t to the
name of the requested field within the returned array.
*/ */
BSONObj extractFieldsDotted(BSONObj pattern, BSONObjBuilder& b, con st char *&nameWithinArray) const; // this version, builder owns the returne d obj buffer BSONObj extractFieldsDotted(BSONObj pattern) const;
/** /**
sets element field names to empty string sets element field names to empty string
If a field in pattern is missing, it is omitted from the returne d If a field in pattern is missing, it is omitted from the returne d
object. object.
*/ */
BSONObj extractFieldsUnDotted(BSONObj pattern) const; BSONObj extractFieldsUnDotted(BSONObj pattern) const;
/** extract items from object which match a pattern object. /** extract items from object which match a pattern object.
e.g., if pattern is { x : 1, y : 1 }, builds an obje ct with e.g., if pattern is { x : 1, y : 1 }, builds an obje ct with
skipping to change at line 938 skipping to change at line 921
} }
/** @return true if field exists in the object */ /** @return true if field exists in the object */
bool hasElement(const char *name) const; bool hasElement(const char *name) const;
/** Get the _id field from the object. For good performance drivers should /** Get the _id field from the object. For good performance drivers should
assure that _id is the first element of the object; however, co rrect operation assure that _id is the first element of the object; however, co rrect operation
is assured regardless. is assured regardless.
@return true if found @return true if found
*/ */
bool getObjectID(BSONElement& e); bool getObjectID(BSONElement& e) const;
/** makes a copy of the object. /** makes a copy of the object.
*/ */
BSONObj copy() const; BSONObj copy() const;
/* make sure the data buffer is under the control of BSONObj's and not a remote buffer */ /* make sure the data buffer is under the control of BSONObj's and not a remote buffer */
BSONObj getOwned() const{ BSONObj getOwned() const{
if ( !isOwned() ) if ( !isOwned() )
return copy(); return copy();
return *this; return *this;
skipping to change at line 1157 skipping to change at line 1140
} }
/** append an element but with a new name */ /** append an element but with a new name */
void appendAs(const BSONElement& e, const char *as) { void appendAs(const BSONElement& e, const char *as) {
assert( !e.eoo() ); // do not append eoo, that would corrupt us . the builder auto appends when done() is called. assert( !e.eoo() ); // do not append eoo, that would corrupt us . the builder auto appends when done() is called.
b.append((char) e.type()); b.append((char) e.type());
b.append(as); b.append(as);
b.append((void *) e.value(), e.valuesize()); b.append((void *) e.value(), e.valuesize());
} }
void appendAs(const BSONElement& e, const string& as) {
appendAs( e , as.c_str() );
}
/** add a subobject as a member */ /** add a subobject as a member */
void append(const char *fieldName, BSONObj subObj) { void append(const char *fieldName, BSONObj subObj) {
b.append((char) Object); b.append((char) Object);
b.append(fieldName); b.append(fieldName);
b.append((void *) subObj.objdata(), subObj.objsize()); b.append((void *) subObj.objdata(), subObj.objsize());
} }
void append(const string& fieldName , BSONObj subObj) { void append(const string& fieldName , BSONObj subObj) {
append( fieldName.c_str() , subObj ); append( fieldName.c_str() , subObj );
} }
skipping to change at line 1271 skipping to change at line 1258
*/ */
void appendTimeT(const char *fieldName, time_t dt) { void appendTimeT(const char *fieldName, time_t dt) {
b.append((char) Date); b.append((char) Date);
b.append(fieldName); b.append(fieldName);
b.append(static_cast<unsigned long long>(dt) * 1000); b.append(static_cast<unsigned long long>(dt) * 1000);
} }
/** Append a date. /** Append a date.
@param dt a Java-style 64 bit date value, that is @param dt a Java-style 64 bit date value, that is
the number of milliseconds since January 1, 1970, 00: 00:00 GMT the number of milliseconds since January 1, 1970, 00: 00:00 GMT
*/ */
void appendDate(const char *fieldName, unsigned long long dt) { void appendDate(const char *fieldName, Date_t dt) {
b.append((char) Date); b.append((char) Date);
b.append(fieldName); b.append(fieldName);
b.append(dt); b.append(dt);
} }
void append(const char *fieldName, Date_t dt) {
appendDate(fieldName, dt);
}
/** Append a regular expression value /** Append a regular expression value
@param regex the regular expression pattern @param regex the regular expression pattern
@param regex options such as "i" or "g" @param regex options such as "i" or "g"
*/ */
void appendRegex(const char *fieldName, const char *regex, const ch ar *options = "") { void appendRegex(const char *fieldName, const char *regex, const ch ar *options = "") {
b.append((char) RegEx); b.append((char) RegEx);
b.append(fieldName); b.append(fieldName);
b.append(regex); b.append(regex);
b.append(options); b.append(options);
} }
skipping to change at line 1442 skipping to change at line 1433
/* Append an array of ints /* Append an array of ints
void appendArray( const char *fieldName, const vector< int >& vals ) { void appendArray( const char *fieldName, const vector< int >& vals ) {
BSONObjBuilder arrBuilder; BSONObjBuilder arrBuilder;
for ( unsigned i = 0; i < vals.size(); ++i ) for ( unsigned i = 0; i < vals.size(); ++i )
arrBuilder.append( numStr( i ).c_str(), vals[ i ] ); arrBuilder.append( numStr( i ).c_str(), vals[ i ] );
marshalArray( fieldName, arrBuilder.done() ); marshalArray( fieldName, arrBuilder.done() );
}*/ }*/
/** The returned BSONObj will free the buffer when it is finished. */ /** The returned BSONObj will free the buffer when it is finished. */
BSONObj obj() { BSONObj obj() {
massert( "builder does not own memory", owned() ); massert( 10335 , "builder does not own memory", owned() );
int l; int l;
return BSONObj(decouple(l), true); return BSONObj(decouple(l), true);
} }
/** Fetch the object we have built. /** Fetch the object we have built.
BSONObjBuilder still frees the object when the build er goes out of BSONObjBuilder still frees the object when the build er goes out of
scope -- very important to keep in mind. Use obj() if you scope -- very important to keep in mind. Use obj() if you
would like the BSONObj to last longer than the build er. would like the BSONObj to last longer than the build er.
*/ */
BSONObj done() { BSONObj done() {
skipping to change at line 1498 skipping to change at line 1489
ForceExplicitString( const string &str ) : str_( str ) {} ForceExplicitString( const string &str ) : str_( str ) {}
string str_; string str_;
}; };
/** Stream oriented way to add field names and values. */ /** Stream oriented way to add field names and values. */
BSONObjBuilderValueStream &operator<<( const ForceExplicitString& n ame ) { BSONObjBuilderValueStream &operator<<( const ForceExplicitString& n ame ) {
return operator<<( name.str_.c_str() ); return operator<<( name.str_.c_str() );
} }
Labeler operator<<( const Labeler::Label &l ) { Labeler operator<<( const Labeler::Label &l ) {
massert( "No subobject started", s_.subobjStarted() ); massert( 10336 , "No subobject started", s_.subobjStarted() );
return s_ << l; return s_ << l;
} }
bool owned() const { bool owned() const {
return &b == &buf_; return &b == &buf_;
} }
private: private:
// Append the provided arr object as an array. // Append the provided arr object as an array.
void marshalArray( const char *fieldName, const BSONObj &arr ) { void marshalArray( const char *fieldName, const BSONObj &arr ) {
skipping to change at line 1651 skipping to change at line 1642
char sname[7]; char sname[7];
unsigned slen; unsigned slen;
char sval[10]; char sval[10];
char eoo; char eoo;
}; };
#pragma pack() #pragma pack()
extern JSObj1 js1; extern JSObj1 js1;
#ifdef _DEBUG #ifdef _DEBUG
#define CHECK_OBJECT( o , msg ) massert( (string)"object not valid" + (msg) , (o).isValid() ) #define CHECK_OBJECT( o , msg ) massert( 10337 , (string)"object not valid " + (msg) , (o).isValid() )
#else #else
#define CHECK_OBJECT( o , msg ) #define CHECK_OBJECT( o , msg )
#endif #endif
inline BSONObj BSONElement::embeddedObjectUserCheck() { inline BSONObj BSONElement::embeddedObjectUserCheck() {
uassert( "invalid parameter: expected an object", type()==Object || type()==Array ); uassert( 10065 , "invalid parameter: expected an object", type()== Object || type()==Array );
return BSONObj(value()); return BSONObj(value());
} }
inline BSONObj BSONElement::embeddedObject() const { inline BSONObj BSONElement::embeddedObject() const {
assert( type()==Object || type()==Array ); assert( type()==Object || type()==Array );
return BSONObj(value()); return BSONObj(value());
} }
inline BSONObj BSONElement::codeWScopeObject() const { inline BSONObj BSONElement::codeWScopeObject() const {
assert( type() == CodeWScope ); assert( type() == CodeWScope );
skipping to change at line 1730 skipping to change at line 1721
if ( e.eoo() ) break; if ( e.eoo() ) break;
append(e); append(e);
} }
return *this; return *this;
} }
inline bool BSONObj::isValid(){ inline bool BSONObj::isValid(){
return objsize() > 0 && objsize() <= 1024 * 1024 * 8; return objsize() > 0 && objsize() <= 1024 * 1024 * 8;
} }
inline bool BSONObj::getObjectID(BSONElement& e) { inline bool BSONObj::getObjectID(BSONElement& e) const {
BSONElement f = findElement("_id"); BSONElement f = findElement("_id");
if( !f.eoo() ) { if( !f.eoo() ) {
e = f; e = f;
return true; return true;
} }
return false; return false;
} }
inline BSONObjBuilderValueStream::BSONObjBuilderValueStream( BSONObjBui lder * builder ) { inline BSONObjBuilderValueStream::BSONObjBuilderValueStream( BSONObjBui lder * builder ) {
_fieldName = 0; _fieldName = 0;
skipping to change at line 1825 skipping to change at line 1816
inline BSONMap bson2map(const BSONObj& obj){ inline BSONMap bson2map(const BSONObj& obj){
BSONMap m; BSONMap m;
BSONObjIterator it(obj); BSONObjIterator it(obj);
while (it.more()){ while (it.more()){
BSONElement e = it.next(); BSONElement e = it.next();
m[e.fieldName()] = e; m[e.fieldName()] = e;
} }
return m; return m;
} }
struct BSONElementFieldNameCmp {
bool operator()( const BSONElement &l, const BSONElement &r ) const
{
return strcmp( l.fieldName() , r.fieldName() ) <= 0;
}
};
typedef set<BSONElement, BSONElementFieldNameCmp> BSONSortedElements;
inline BSONSortedElements bson2set( const BSONObj& obj ){
BSONSortedElements s;
BSONObjIterator it(obj);
while ( it.more() )
s.insert( it.next() );
return s;
}
class BSONObjIteratorSorted {
public:
BSONObjIteratorSorted( const BSONObj& o );
~BSONObjIteratorSorted(){
assert( _fields );
delete _fields;
_fields = 0;
}
bool more(){
return _cur < _nfields;
}
BSONElement next(){
assert( _fields );
if ( _cur < _nfields )
return BSONElement( _fields[_cur++] );
return BSONElement();
}
private:
const char ** _fields;
int _nfields;
int _cur;
};
} // namespace mongo } // namespace mongo
 End of changes. 26 change blocks. 
42 lines changed or deleted 74 lines changed or added


 lasterror.h   lasterror.h 
skipping to change at line 29 skipping to change at line 29
#include <boost/thread/tss.hpp> #include <boost/thread/tss.hpp>
#undef assert #undef assert
#define assert xassert #define assert xassert
namespace mongo { namespace mongo {
class BSONObjBuilder; class BSONObjBuilder;
class Message; class Message;
struct LastError { struct LastError {
int code;
string msg; string msg;
enum UpdatedExistingType { NotUpdate, True, False } updatedExisting ; enum UpdatedExistingType { NotUpdate, True, False } updatedExisting ;
/* todo: nObjects should be 64 bit */ /* todo: nObjects should be 64 bit */
int nObjects; int nObjects;
int nPrev; int nPrev;
bool valid; bool valid;
bool overridenById; bool overridenById;
void raiseError(const char *_msg) { void raiseError(int _code , const char *_msg) {
reset( true ); reset( true );
code = _code;
msg = _msg; msg = _msg;
} }
void recordUpdate( bool _updatedExisting, int nChanged ) { void recordUpdate( bool _updatedExisting, int nChanged ) {
reset( true ); reset( true );
nObjects = nChanged; nObjects = nChanged;
updatedExisting = _updatedExisting ? True : False; updatedExisting = _updatedExisting ? True : False;
} }
void recordDelete( int nDeleted ) { void recordDelete( int nDeleted ) {
reset( true ); reset( true );
nObjects = nDeleted; nObjects = nDeleted;
} }
LastError() { LastError() {
overridenById = false; overridenById = false;
reset(); reset();
} }
void reset( bool _valid = false ) { void reset( bool _valid = false ) {
code = 0;
msg.clear(); msg.clear();
updatedExisting = NotUpdate; updatedExisting = NotUpdate;
nObjects = 0; nObjects = 0;
nPrev = 1; nPrev = 1;
valid = _valid; valid = _valid;
} }
void appendSelf( BSONObjBuilder &b ); void appendSelf( BSONObjBuilder &b );
static LastError noError; static LastError noError;
}; };
skipping to change at line 96 skipping to change at line 99
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 boost::mutex _idsmutex;
map<int,Status> _ids; map<int,Status> _ids;
} lastError; } lastError;
inline void raiseError(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';
return; return;
} }
le->raiseError(msg); le->raiseError(code, msg);
} }
inline void recordUpdate( bool updatedExisting, int nChanged ) { inline void recordUpdate( bool updatedExisting, int nChanged ) {
LastError *le = lastError.get(); LastError *le = lastError.get();
if ( le ) if ( le )
le->recordUpdate( updatedExisting, nChanged ); le->recordUpdate( updatedExisting, nChanged );
} }
inline void recordDelete( int nDeleted ) { inline void recordDelete( int nDeleted ) {
LastError *le = lastError.get(); LastError *le = lastError.get();
 End of changes. 6 change blocks. 
3 lines changed or deleted 6 lines changed or added


 log.h   log.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 <string.h>
namespace mongo { namespace mongo {
using boost::shared_ptr; using boost::shared_ptr;
// Utility interface for stringifying object only when val() called. // Utility interface for stringifying object only when val() called.
class LazyString { class LazyString {
public: public:
virtual ~LazyString() {} virtual ~LazyString() {}
virtual string val() const = 0; virtual string val() const = 0;
}; };
skipping to change at line 242 skipping to change at line 244
return l; return l;
} }
/** /**
log to a file rather than stdout log to a file rather than stdout
defined in assert_util.cpp defined in assert_util.cpp
*/ */
void initLogging( const string& logpath , bool append ); void initLogging( const string& logpath , bool append );
void rotateLogs( int signal = 0 ); void rotateLogs( int signal = 0 );
#define OUTPUT_ERRNOX(x) "errno:" << x << " " << strerror(x)
#define OUTPUT_ERRNO OUTPUT_ERRNOX(errno)
} // namespace mongo } // namespace mongo
 End of changes. 2 change blocks. 
0 lines changed or deleted 5 lines changed or added


 matcher.h   matcher.h 
skipping to change at line 28 skipping to change at line 28
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "jsobj.h" #include "jsobj.h"
#include <pcrecpp.h> #include <pcrecpp.h>
namespace mongo { namespace mongo {
class KeyValJSMatcher; class CoveredIndexMatcher;
class RegexMatcher { class RegexMatcher {
public: public:
const char *fieldName; const char *fieldName;
pcrecpp::RE *re; pcrecpp::RE *re;
RegexMatcher() { RegexMatcher() {
re = 0; re = 0;
} }
~RegexMatcher() { ~RegexMatcher() {
delete re; delete re;
skipping to change at line 65 skipping to change at line 65
BasicMatcher(){ BasicMatcher(){
} }
BasicMatcher( BSONElement _e , int _op ) : toMatch( _e ) , compareO p( _op ){ BasicMatcher( BSONElement _e , int _op ) : toMatch( _e ) , compareO p( _op ){
if ( _op == BSONObj::opMOD ){ if ( _op == BSONObj::opMOD ){
BSONObj o = _e.embeddedObject().firstElement().embeddedObje ct(); BSONObj o = _e.embeddedObject().firstElement().embeddedObje ct();
mod = o["0"].numberInt(); mod = o["0"].numberInt();
modm = o["1"].numberInt(); modm = o["1"].numberInt();
uassert( "mod can't be 0" , mod ); uassert( 10073 , "mod can't be 0" , mod );
} }
else if ( _op == BSONObj::opTYPE ){ else if ( _op == BSONObj::opTYPE ){
type = (BSONType)(_e.embeddedObject().firstElement().number Int()); type = (BSONType)(_e.embeddedObject().firstElement().number Int());
} }
} }
BasicMatcher( BSONElement _e , int _op , const BSONObj& array ) : t oMatch( _e ) , compareOp( _op ){ BasicMatcher( BSONElement _e , int _op , const BSONObj& array ) : t oMatch( _e ) , compareOp( _op ){
myset.reset( new set<BSONElement,element_lt>() ); myset.reset( new set<BSONElement,element_lt>() );
skipping to change at line 102 skipping to change at line 102
// SQL where clause equivalent // SQL where clause equivalent
class Where; class Where;
class DiskLoc; class DiskLoc;
/* 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. { 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 JSMatcher : boost::noncopyable { class JSMatcher : 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 BasicMatcher& bm, bool isArr = false); int compareOp, const BasicMatcher& bm, bool isArr = false);
int matchesNe( int matchesNe(
skipping to change at line 137 skipping to change at line 136
// 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.
JSMatcher(const BSONObj &pattern, const BSONObj &constrainIndexKey = BSONObj()); JSMatcher(const BSONObj &pattern, const BSONObj &constrainIndexKey = BSONObj());
~JSMatcher(); ~JSMatcher();
bool matches(const BSONObj& j); bool matches(const BSONObj& j);
bool keyMatch() const { return !all && !haveSize && !hasArray; } bool keyMatch() const { return !all && !haveSize && !hasArray; }
bool atomic() const { return _atomic; }
private: private:
void addBasic(const BSONElement &e, int c) { void addBasic(const BSONElement &e, int c) {
// 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( BasicMatcher( e , c ) ); basics.push_back( BasicMatcher( e , c ) );
} }
int valuesMatch(const BSONElement& l, const BSONElement& r, int op, const BasicMatcher& bm); int valuesMatch(const BSONElement& l, const BSONElement& r, int op, const BasicMatcher& bm);
skipping to change at line 150 skipping to change at line 152
if ( e.type() == MinKey || e.type() == MaxKey ) if ( e.type() == MinKey || e.type() == MaxKey )
return; return;
basics.push_back( BasicMatcher( e , c ) ); basics.push_back( BasicMatcher( e , c ) );
} }
int valuesMatch(const BSONElement& l, const BSONElement& r, int op, const BasicMatcher& bm); int valuesMatch(const BSONElement& l, const BSONElement& r, int op, const BasicMatcher& 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<BasicMatcher> basics; vector<BasicMatcher> basics;
// int n; // # of basicmatcher items // int n; // # of basicmatcher items
bool haveSize; bool haveSize;
bool all; bool all;
bool hasArray; bool hasArray;
/* $atomic - if true, a multi document operation (some removes, upd
ates)
should be done atomically. in that case, we do not yi
eld -
i.e. we stay locked the whole time.
*/
bool _atomic;
RegexMatcher regexs[4]; RegexMatcher regexs[4];
int nRegex; int nRegex;
// so we delete the mem when we're done: // so we delete the mem when we're done:
vector< shared_ptr< BSONObjBuilder > > builders_; vector< shared_ptr< BSONObjBuilder > > _builders;
friend class KeyValJSMatcher; friend class CoveredIndexMatcher;
}; };
// If match succeeds on index key, then attempt to match full record. // If match succeeds on index key, then attempt to match full document.
class KeyValJSMatcher : boost::noncopyable { class CoveredIndexMatcher : boost::noncopyable {
public: public:
KeyValJSMatcher(const BSONObj &pattern, const BSONObj &indexKeyPatt CoveredIndexMatcher(const BSONObj &pattern, const BSONObj &indexKey
ern); Pattern);
bool matches(const BSONObj &j); bool matches(const BSONObj &o){ return _docMatcher.matches( o ); }
bool matches(const BSONObj &key, const DiskLoc &recLoc); bool matches(const BSONObj &key, const DiskLoc &recLoc);
bool needRecord(){ return _needRecord; } bool needRecord(){ return _needRecord; }
JSMatcher& docMatcher() { return _docMatcher; }
private: private:
JSMatcher _keyMatcher; JSMatcher _keyMatcher;
JSMatcher _recordMatcher; JSMatcher _docMatcher;
bool _needRecord; bool _needRecord;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 14 change blocks. 
15 lines changed or deleted 26 lines changed or added


 message.h   message.h 
skipping to change at line 200 skipping to change at line 200
return freeIt; return freeIt;
} }
private: private:
bool freeIt; bool freeIt;
}; };
class SocketException : public DBException { class SocketException : public DBException {
public: public:
virtual const char* what() const throw() { return "socket exception "; } virtual const char* what() const throw() { return "socket exception "; }
virtual int getCode(){ return 9001; }
}; };
MSGID nextMessageId(); MSGID nextMessageId();
void setClientId( int id ); void setClientId( int id );
int getClientId(); int getClientId();
} // namespace mongo } // namespace mongo
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 mmap.h   mmap.h 
skipping to change at line 25 skipping to change at line 25
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
namespace mongo { namespace mongo {
class MemoryMappedFile { class MemoryMappedFile {
public: public:
enum Options {
SEQUENTIAL = 1
};
MemoryMappedFile(); MemoryMappedFile();
~MemoryMappedFile(); /* closes the file if open */ ~MemoryMappedFile(); /* closes the file if open */
void close(); void close();
// Throws exception if file doesn't exist. // Throws exception if file doesn't exist.
void* map( const char *filename ); void* map( const char *filename );
/* Creates with length if DNE, otherwise uses existing file length, /* Creates with length if DNE, otherwise uses existing file length,
passed length. passed length.
*/ */
void* map(const char *filename, long &length, int options = 0 ); void* map(const char *filename, long &length);
void flush(bool sync); void flush(bool sync);
void* viewOfs() { void* viewOfs() {
return view; return view;
} }
long length() { long length() {
return len; return len;
} }
 End of changes. 2 change blocks. 
5 lines changed or deleted 1 lines changed or added


 namespace.h   namespace.h 
skipping to change at line 91 skipping to change at line 91
}; };
/* This helper class is used to make the HashMap below in NamespaceD etails */ /* This helper class is used to make the HashMap below in NamespaceD etails */
class Namespace { class Namespace {
public: public:
enum MaxNsLenValue { MaxNsLen = 128 }; enum MaxNsLenValue { MaxNsLen = 128 };
Namespace(const char *ns) { Namespace(const char *ns) {
*this = ns; *this = ns;
} }
Namespace& operator=(const char *ns) { Namespace& operator=(const char *ns) {
uassert("ns name too long, max size is 128", strlen(ns) < MaxNs Len); uassert( 10080 , "ns name too long, max size is 128", strlen(ns ) < MaxNsLen);
//memset(buf, 0, MaxNsLen); /* this is just to keep stuff clean in the files for easy dumping and reading */ //memset(buf, 0, MaxNsLen); /* this is just to keep stuff clean in the files for easy dumping and reading */
strcpy_s(buf, MaxNsLen, ns); strcpy_s(buf, MaxNsLen, ns);
return *this; return *this;
} }
/* for more than 10 indexes -- see NamespaceDetails::Extra */ /* for more than 10 indexes -- see NamespaceDetails::Extra */
string extraName() { string extraName() {
string s = string(buf) + "$extra"; string s = string(buf) + "$extra";
massert("ns name too long", s.size() < MaxNsLen); massert( 10348 , "ns name too long", s.size() < MaxNsLen);
return s; return s;
} }
void kill() { void kill() {
buf[0] = 0x7f; buf[0] = 0x7f;
} }
bool operator==(const char *r) { bool operator==(const char *r) {
return strcmp(buf, r) == 0; return strcmp(buf, r) == 0;
} }
skipping to change at line 313 skipping to change at line 313
assert( sizeof(dataFileVersion) == 2 ); assert( sizeof(dataFileVersion) == 2 );
dataFileVersion = 0; dataFileVersion = 0;
indexFileVersion = 0; indexFileVersion = 0;
multiKeyIndexBits = 0; multiKeyIndexBits = 0;
reservedA = 0; reservedA = 0;
extraOffset = 0; extraOffset = 0;
memset(reserved, 0, sizeof(reserved)); memset(reserved, 0, sizeof(reserved));
} }
DiskLoc firstExtent; DiskLoc firstExtent;
DiskLoc lastExtent; DiskLoc lastExtent;
/* NOTE: capped collections override the meaning of deleted list.
deletedList[0] points to a list of free records (DeletedRe
cord's) for all extents in
the namespace.
deletedList[1] points to the last record in the prev exten
t. When the "current extent"
changes, this value is updated. !deletedList[1].isValid()
when this value is not
yet computed.
*/
DiskLoc deletedList[Buckets]; DiskLoc deletedList[Buckets];
long long datasize; long long datasize;
long long nrecords; long long nrecords;
int lastExtentSize; int lastExtentSize;
int nIndexes; int nIndexes;
private: private:
IndexDetails _indexes[NIndexesBase]; IndexDetails _indexes[NIndexesBase];
public: public:
int capped; int capped;
int max; // max # of objects for a capped table. int max; // max # of objects for a capped table.
double paddingFactor; // 1.0 = no padding. double paddingFactor; // 1.0 = no padding.
skipping to change at line 388 skipping to change at line 397
} }
/* hackish - find our index # in the indexes array /* hackish - find our index # in the indexes array
*/ */
int idxNo(IndexDetails& idx) { int idxNo(IndexDetails& idx) {
IndexIterator i = ii(); IndexIterator i = ii();
while( i.more() ) { while( i.more() ) {
if( &i.next() == &idx ) if( &i.next() == &idx )
return i.pos()-1; return i.pos()-1;
} }
massert("E12000 idxNo fails", false); massert( 10349 , "E12000 idxNo fails", false);
return -1; return -1;
} }
/* multikey indexes are indexes where there are more than one key i n the index /* multikey indexes are indexes where there are more than one key i n the index
for a single document. see multikey in wiki. for a single document. see multikey in wiki.
for these, we have to do some dedup object on queries. for these, we have to do some dedup object on queries.
*/ */
bool isMultikey(int i) { bool isMultikey(int i) {
return (multiKeyIndexBits & (((unsigned long long) 1) << i)) != 0; return (multiKeyIndexBits & (((unsigned long long) 1) << i)) != 0;
} }
skipping to change at line 516 skipping to change at line 525
#pragma pack() #pragma pack()
/* these are things we know / compute about a namespace that are transi ent -- things /* these are things we know / compute about a namespace that are transi ent -- things
we don't actually store in the .ns file. so mainly caching of frequ ently used we don't actually store in the .ns file. so mainly caching of frequ ently used
information. information.
CAUTION: Are you maintaining this properly on a collection drop()? A dropdatabase()? Be careful. CAUTION: Are you maintaining this properly on a collection drop()? A dropdatabase()? Be careful.
The current field "allIndexKeys" may have too many keys in it on such an occurrence; The current field "allIndexKeys" may have too many keys in it on such an occurrence;
as currently used that does not cause anything terrible to happen. as currently used that does not cause anything terrible to happen.
todo: cleanup code, need abstractions and separation
*/ */
class NamespaceDetailsTransient : boost::noncopyable { class NamespaceDetailsTransient : boost::noncopyable {
string ns; /* general --------------------------------------------------------
bool haveIndexKeys; ----- */
set<string> allIndexKeys; private:
void computeIndexKeys(); string _ns;
int writeCount_; void reset();
map< QueryPattern, pair< BSONObj, long long > > queryCache_; static std::map< string, shared_ptr< NamespaceDetailsTransient > >
string logNS_; _map;
bool logValid_;
public: public:
NamespaceDetailsTransient(const char *_ns) : ns(_ns), haveIndexKeys NamespaceDetailsTransient(const char *ns) : _ns(ns), _keysComputed(
(), writeCount_(), logValid_() { false), _qcWriteCount(), _cll_enabled() { }
haveIndexKeys=false; /*lazy load them*/ /* _get() is not threadsafe */
static NamespaceDetailsTransient& _get(const char *ns);
/* use get_w() when doing write operations */
static NamespaceDetailsTransient& get_w(const char *ns) {
DEV assertInWriteLock();
return _get(ns);
} }
void addedIndex() { reset(); }
void deletedIndex() { reset(); }
/* Drop cached information on all namespaces beginning with the spe
cified prefix.
Can be useful as index namespaces share the same start as the re
gular collection.
SLOW - sequential scan of all NamespaceDetailsTransient objects
*/
static void clearForPrefix(const char *prefix);
/* indexKeys() cache ----------------------------------------------
------ */
/* assumed to be in write lock for this */
private:
bool _keysComputed;
set<string> _indexKeys;
void computeIndexKeys();
public:
/* get set of index keys for this namespace. handy to quickly chec k if a given /* get set of index keys for this namespace. handy to quickly chec k if a given
field is indexed (Note it might be a seconary component of a com pound index.) field is indexed (Note it might be a secondary component of a co mpound index.)
*/ */
set<string>& indexKeys() { set<string>& indexKeys() {
if ( !haveIndexKeys ) { DEV assertInWriteLock();
haveIndexKeys=true; if ( !_keysComputed )
computeIndexKeys(); computeIndexKeys();
} return _indexKeys;
return allIndexKeys;
} }
void addedIndex() { reset(); } /* query cache (for query optimizer) ------------------------------
void deletedIndex() { reset(); } ------- */
void registerWriteOp() { private:
if ( queryCache_.empty() ) int _qcWriteCount;
map< QueryPattern, pair< BSONObj, long long > > _qcCache;
public:
static boost::mutex _qcMutex;
/* you must be in the qcMutex when calling this (and using the retu
rned val): */
static NamespaceDetailsTransient& get_inlock(const char *ns) {
return _get(ns);
}
void clearQueryCache() { // public for unit tests
_qcCache.clear();
_qcWriteCount = 0;
}
/* you must notify the cache if you are doing writes, as query plan
optimality will change */
void notifyOfWriteOp() {
if ( _qcCache.empty() )
return; return;
if ( ++writeCount_ >= 100 ) if ( ++_qcWriteCount >= 100 )
clearQueryCache(); clearQueryCache();
} }
void clearQueryCache() {
queryCache_.clear();
writeCount_ = 0;
}
BSONObj indexForPattern( const QueryPattern &pattern ) { BSONObj indexForPattern( const QueryPattern &pattern ) {
return queryCache_[ pattern ].first; return _qcCache[ pattern ].first;
} }
long long nScannedForPattern( const QueryPattern &pattern ) { long long nScannedForPattern( const QueryPattern &pattern ) {
return queryCache_[ pattern ].second; return _qcCache[ pattern ].second;
} }
void registerIndexForPattern( const QueryPattern &pattern, const BS ONObj &indexKey, long long nScanned ) { void registerIndexForPattern( const QueryPattern &pattern, const BS ONObj &indexKey, long long nScanned ) {
queryCache_[ pattern ] = make_pair( indexKey, nScanned ); _qcCache[ pattern ] = make_pair( indexKey, nScanned );
} }
void startLog( int logSizeMb = 128 ); /* for collection-level logging -- see CmdLogCollection -----------
void invalidateLog(); ------ */
bool validateCompleteLog(); /* assumed to be in write lock for this */
string logNS() const { return logNS_; }
bool logValid() const { return logValid_; }
private: private:
void reset(); string _cll_ns; // "local.temp.oplog." + _ns;
void dropLog(); bool _cll_enabled;
static std::map< string, shared_ptr< NamespaceDetailsTransient > > void cllDrop(); // drop _cll_ns
map_;
public: public:
static NamespaceDetailsTransient& get(const char *ns); string cllNS() const { return _cll_ns; }
// Drop cached information on all namespaces beginning with the spe bool cllEnabled() const { return _cll_enabled; }
cified prefix. void cllStart( int logSizeMb = 256 ); // begin collection level log
static void drop(const char *prefix); ging
}; void cllInvalidate();
bool cllValidateComplete();
}; /* NamespaceDetailsTransient */
inline NamespaceDetailsTransient& NamespaceDetailsTransient::_get(const
char *ns) {
shared_ptr< NamespaceDetailsTransient > &t = _map[ ns ];
if ( t.get() == 0 )
t.reset( new NamespaceDetailsTransient(ns) );
return *t;
}
/* NamespaceIndex is the ".ns" file you see in the data directory. It is the "system catalog" /* NamespaceIndex is the ".ns" file you see in the data directory. It is the "system catalog"
if you will: at least the core parts. (Additional info in system.* collections.) if you will: at least the core parts. (Additional info in system.* collections.)
*/ */
class NamespaceIndex { class NamespaceIndex {
friend class NamespaceCursor; friend class NamespaceCursor;
BOOST_STATIC_ASSERT( sizeof(NamespaceDetails::Extra) <= sizeof(Name spaceDetails) ); BOOST_STATIC_ASSERT( sizeof(NamespaceDetails::Extra) <= sizeof(Name spaceDetails) );
public: public:
NamespaceIndex(const string &dir, const string &database) : NamespaceIndex(const string &dir, const string &database) :
ht( 0 ), ht( 0 ),
skipping to change at line 605 skipping to change at line 645
void init(); void init();
void add_ns(const char *ns, DiskLoc& loc, bool capped) { void add_ns(const char *ns, DiskLoc& loc, bool capped) {
NamespaceDetails details( loc, capped ); NamespaceDetails details( loc, capped );
add_ns( ns, details ); add_ns( ns, details );
} }
void add_ns( const char *ns, const NamespaceDetails &details ) { void add_ns( const char *ns, const NamespaceDetails &details ) {
init(); init();
Namespace n(ns); Namespace n(ns);
uassert("too many namespaces/collections", ht->put(n, details)) ; uassert( 10081 , "too many namespaces/collections", ht->put(n, details));
} }
/* just for diagnostics */ /* just for diagnostics */
size_t detailsOffset(NamespaceDetails *d) { size_t detailsOffset(NamespaceDetails *d) {
if ( !ht ) if ( !ht )
return -1; return -1;
return ((char *) d) - (char *) ht->nodes; return ((char *) d) - (char *) ht->nodes;
} }
/* extra space for indexes when more than 10 */ /* extra space for indexes when more than 10 */
NamespaceDetails::Extra* allocExtra(const char *ns) { NamespaceDetails::Extra* allocExtra(const char *ns) {
Namespace n(ns); Namespace n(ns);
Namespace extra(n.extraName().c_str()); // throws userexception if ns name too long Namespace extra(n.extraName().c_str()); // throws userexception if ns name too long
NamespaceDetails *d = details(ns); NamespaceDetails *d = details(ns);
massert( "allocExtra: base ns missing?", d ); massert( 10350 , "allocExtra: base ns missing?", d );
assert( d->extraOffset == 0 ); assert( d->extraOffset == 0 );
massert( "allocExtra: extra already exists", ht->get(extra) == 0 ); massert( 10351 , "allocExtra: extra already exists", ht->get(e xtra) == 0 );
NamespaceDetails::Extra temp; NamespaceDetails::Extra temp;
memset(&temp, 0, sizeof(temp)); memset(&temp, 0, sizeof(temp));
uassert( "allocExtra: too many namespaces/collections", ht->put (extra, (NamespaceDetails&) temp)); uassert( 10082 , "allocExtra: too many namespaces/collections" , ht->put(extra, (NamespaceDetails&) temp));
NamespaceDetails::Extra *e = (NamespaceDetails::Extra *) ht->ge t(extra); NamespaceDetails::Extra *e = (NamespaceDetails::Extra *) ht->ge t(extra);
d->extraOffset = ((char *) e) - ((char *) d); d->extraOffset = ((char *) e) - ((char *) d);
assert( d->extra() == e ); assert( d->extra() == e );
return e; return e;
} }
NamespaceDetails* details(const char *ns) { NamespaceDetails* details(const char *ns) {
if ( !ht ) if ( !ht )
return 0; return 0;
Namespace n(ns); Namespace n(ns);
 End of changes. 26 change blocks. 
50 lines changed or deleted 103 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) {
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. 5 change blocks. 
26 lines changed or deleted 3 lines changed or added


 pdfile.h   pdfile.h 
skipping to change at line 41 skipping to change at line 41
#include "jsobjmanipulator.h" #include "jsobjmanipulator.h"
#include "namespace.h" #include "namespace.h"
#include "client.h" #include "client.h"
namespace mongo { namespace mongo {
class MDFHeader; class MDFHeader;
class Extent; class Extent;
class Record; class Record;
class Cursor; class Cursor;
class OpDebug;
void dropDatabase(const char *ns); void dropDatabase(const char *ns);
bool repairDatabase(const char *ns, string &errmsg, bool preserveCloned FilesOnFailure = false, bool backupOriginalFiles = false); bool repairDatabase(const char *ns, string &errmsg, bool preserveCloned FilesOnFailure = false, bool backupOriginalFiles = false);
/* low level - only drops this ns */ /* low level - only drops this ns */
void dropNS(const string& dropNs); void dropNS(const string& dropNs);
/* deletes this ns, indexes and cursors */ /* deletes this ns, indexes and cursors */
void dropCollection( const string &name, string &errmsg, BSONObjBuilder &result ); void dropCollection( const string &name, string &errmsg, BSONObjBuilder &result );
bool userCreateNS(const char *ns, BSONObj j, string& err, bool logForRe plication); bool userCreateNS(const char *ns, BSONObj j, string& err, bool logForRe plication);
skipping to change at line 73 skipping to change at line 74
public: public:
MongoDataFile(int fn) : fileNo(fn) { } MongoDataFile(int fn) : fileNo(fn) { }
void open(const char *filename, int requestedDataSize = 0, bool pre allocateOnly = false); void open(const char *filename, int requestedDataSize = 0, bool pre allocateOnly = false);
/* allocate a new extent from this datafile. /* allocate a new extent from this datafile.
@param capped - true if capped collection @param capped - true if capped collection
@param loops is our recursion check variable - you want to pass in zero @param loops is our recursion check variable - you want to pass in zero
*/ */
Extent* createExtent(const char *ns, int approxSize, bool capped = false, int loops = 0); Extent* createExtent(const char *ns, int approxSize, bool capped = false, int loops = 0);
/* see if we can find an extent of the right size in the freelist.
if not,
createExtent.
*/
Extent* allocExtent(const char *ns, int approxSize, bool capped = f
alse);
MDFHeader *getHeader() { MDFHeader *getHeader() {
return header; return header;
} }
/* return max size an extent may be */ /* return max size an extent may be */
static int maxSize(); static int maxSize();
private: private:
int defaultSize( const char *filename ) const; int defaultSize( const char *filename ) const;
skipping to change at line 102 skipping to change at line 98
MemoryMappedFile mmf; MemoryMappedFile mmf;
MDFHeader *header; MDFHeader *header;
int fileNo; int fileNo;
}; };
class DataFileMgr { class DataFileMgr {
friend class BasicCursor; friend class BasicCursor;
public: public:
void init(const string& path ); void init(const string& path );
/* see if we can find an extent of the right size in the freelist.
*/
static Extent* allocFromFreeList(const char *ns, int approxSize, bo
ol capped = false);
/** @return DiskLoc where item ends up */ /** @return DiskLoc where item ends up */
const DiskLoc update( const DiskLoc update(
const char *ns, const char *ns,
Record *toupdate, const DiskLoc& dl, Record *toupdate, const DiskLoc& dl,
const char *buf, int len, stringstream& profiling); const char *buf, int len, OpDebug& debug);
// The object o may be updated if modified on insert. // The object o may be updated if modified on insert.
void insertAndLog( const char *ns, const BSONObj &o, bool god = fal se ); void insertAndLog( const char *ns, const BSONObj &o, bool god = fal se );
DiskLoc insert(const char *ns, BSONObj &o, bool god = false); DiskLoc insert(const char *ns, BSONObj &o, bool god = false);
DiskLoc insert(const char *ns, const void *buf, int len, bool god = false, const BSONElement &writeId = BSONElement(), bool mayAddIndex = true ); DiskLoc insert(const char *ns, const void *buf, int len, bool god = false, const BSONElement &writeId = BSONElement(), bool mayAddIndex = true );
void deleteRecord(const char *ns, Record *todelete, const DiskLoc& dl, bool cappedOK = false, bool noWarn = false); void deleteRecord(const char *ns, Record *todelete, const DiskLoc& dl, bool cappedOK = false, bool noWarn = false);
static auto_ptr<Cursor> findAll(const char *ns, const DiskLoc &star tLoc = DiskLoc()); static auto_ptr<Cursor> findAll(const char *ns, const DiskLoc &star tLoc = DiskLoc());
/* special version of insert for transaction logging -- streamlined a bit. /* special version of insert for transaction logging -- streamlined a bit.
assumes ns is capped and no indexes assumes ns is capped and no indexes
no _id field check no _id field check
 End of changes. 4 change blocks. 
8 lines changed or deleted 7 lines changed or added


 query.h   query.h 
skipping to change at line 75 skipping to change at line 75
from insert where you can pass a list of objects to insert in the db. from insert where you can pass a list of objects to insert in the db.
Note that the update field layout is very similar layout to Query. Note that the update field layout is very similar layout to Query.
*/ */
// struct QueryOptions, QueryResult, QueryResultFlags in: // struct QueryOptions, QueryResult, QueryResultFlags in:
#include "../client/dbclient.h" #include "../client/dbclient.h"
namespace mongo { namespace mongo {
// for an existing query (ie a ClientCursor), send back additional info rmation. // for an existing query (ie a ClientCursor), send back additional info rmation.
QueryResult* getMore(const char *ns, int ntoreturn, long long cursorid , stringstream& ss); QueryResult* getMore(const char *ns, int ntoreturn, long long cursorid , CurOp& op);
struct UpdateResult { struct UpdateResult {
bool existing; bool existing;
bool mod; bool mod;
unsigned long long num; unsigned long long num;
UpdateResult( bool e, bool m, unsigned long long n ) UpdateResult( bool e, bool m, unsigned long long n )
: existing(e) , mod(m), num(n ){} : existing(e) , mod(m), num(n ){}
int oldCode(){ int oldCode(){
skipping to change at line 104 skipping to change at line 104
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
*/ */
UpdateResult updateObjects(const char *ns, BSONObj updateobj, BSONObj p attern, bool upsert, bool multi , stringstream& ss, bool logop ); UpdateResult updateObjects(const char *ns, BSONObj updateobj, BSONObj p attern, 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 .
int deleteObjects(const char *ns, BSONObj pattern, bool justOne, bool l ogop = false, bool god=false); int deleteObjects(const char *ns, BSONObj pattern, bool justOne, bool l ogop = 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, stringstream& ss ); auto_ptr< QueryResult > runQuery(Message& m, QueryMessage& q, CurOp& cu rop );
} // namespace mongo } // namespace mongo
#include "clientcursor.h" #include "clientcursor.h"
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 queryoptimizer.h   queryoptimizer.h 
skipping to change at line 75 skipping to change at line 75
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_;
}; };
// 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
// each clone its own query plan.
class QueryOp { class QueryOp {
public: public:
QueryOp() : complete_(), qp_(), error_() {} QueryOp() : complete_(), qp_(), error_() {}
virtual ~QueryOp() {} virtual ~QueryOp() {}
virtual void init() = 0; virtual void init() = 0;
virtual void next() = 0; virtual void next() = 0;
virtual bool mayRecordPlan() const = 0; virtual bool mayRecordPlan() const = 0;
// Return a copy of the inheriting class, which will be run with it s own // Return a copy of the inheriting class, which will be run with it s own
// query plan. // query plan.
virtual QueryOp *clone() const = 0; virtual QueryOp *clone() const = 0;
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 quorum.h   quorum.h 
skipping to change at line 14 skipping to change at line 14
#include "dbclient.h" #include "dbclient.h"
namespace mongo { namespace mongo {
/** /**
* this is a connection to a cluster of servers that operate as one * this is a connection to a cluster of servers that operate as one
* for super high durability * for super high durability
*/ */
class QuorumConnection : public DBClientWithCommands { class QuorumConnection : public DBClientWithCommands {
public: public:
/**
* @param commaSeperated should be 3 hosts comma seperated
*/
QuorumConnection( string commaSeperated );
QuorumConnection( string a , string b , string c ); QuorumConnection( string a , string b , string c );
~QuorumConnection(); ~QuorumConnection();
/** /**
* @return true if all servers are up and ready for writes * @return true if all servers are up and ready for writes
*/ */
bool prepare( string& errmsg ); bool prepare( string& errmsg );
/** /**
* runs fsync on all servers * runs fsync on all servers
*/ */
bool fsync( string& errmsg ); bool fsync( string& errmsg );
// --- from DBClientInterface
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer
y, int nToReturn, int nToSkip,
const BSONObj *fieldsToRetur
n, int queryOptions);
virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo
ng cursorId, int nToReturn, int options );
virtual void insert( const string &ns, BSONObj obj );
virtual void insert( const string &ns, const vector< BSONObj >& v )
;
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 string toString();
private: private:
void _checkLast();
void _connect( string host ); void _connect( string host );
vector<DBClientConnection*> _conns; vector<DBClientConnection*> _conns;
}; };
}; };
 End of changes. 3 change blocks. 
0 lines changed or deleted 28 lines changed or added


 rec.h   rec.h 
skipping to change at line 68 skipping to change at line 68
/* An in memory RecStoreInterface implementation -------------------------- -- /* An in memory RecStoreInterface implementation -------------------------- --
*/ */
#if 0 #if 0
class InMem_RecStore : public RecStoreInterface { class InMem_RecStore : public RecStoreInterface {
enum InmemfileValue { INMEMFILE = 0x70000000 }; enum InmemfileValue { INMEMFILE = 0x70000000 };
public: public:
static char* get(DiskLoc d, unsigned len) { static char* get(DiskLoc d, unsigned len) {
assert( d.a() == INMEMFILE ); assert( d.a() == INMEMFILE );
#ifdef __LP64__ #ifdef __LP64__
massert("64 bit not done", false); massert( 10372 , "64 bit not done", false);
return 0; return 0;
#else #else
return (char *) d.getOfs(); return (char *) d.getOfs();
#endif #endif
} }
static DiskLoc insert(const char *ns, const void *obuf, int len, bool g od) { static DiskLoc insert(const char *ns, const void *obuf, int len, bool g od) {
#ifdef __LP64__ #ifdef __LP64__
assert( 0 ); assert( 0 );
throw -1; throw -1;
skipping to change at line 96 skipping to change at line 96
#endif #endif
} }
static void modified(DiskLoc d) { } static void modified(DiskLoc d) { }
static void drop(const char *ns) { static void drop(const char *ns) {
log() << "warning: drop() not yet implemented for InMem_RecStore" < < endl; log() << "warning: drop() not yet implemented for InMem_RecStore" < < endl;
} }
virtual void rename(const char *fromNs, const char *toNs) { virtual void rename(const char *fromNs, const char *toNs) {
massert( "rename not yet implemented for InMem_RecStore", false ); massert( 10373 , "rename not yet implemented for InMem_RecStore", fa lse );
} }
}; };
#endif #endif
/* Glue btree to RecStoreInterface: ---------------------------- */ /* Glue btree to RecStoreInterface: ---------------------------- */
extern RecStoreInterface *btreeStore; extern RecStoreInterface *btreeStore;
const int BucketSize = 8192; const int BucketSize = 8192;
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 reccache.h   reccache.h 
skipping to change at line 180 skipping to change at line 180
} }
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); boostlock 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( "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;
return d; return d;
} }
void closeFiles(string dbname, string path); void closeFiles(string dbname, string path);
skipping to change at line 217 skipping to change at line 217
virtual void modified(DiskLoc d) { virtual void modified(DiskLoc d) {
theRecCache.dirty(d); theRecCache.dirty(d);
} }
/* drop collection */ /* drop collection */
virtual void drop(const char *ns) { virtual void drop(const char *ns) {
theRecCache.drop(ns); theRecCache.drop(ns);
} }
virtual void rename(const char *fromNs, const char *toNs) { virtual void rename(const char *fromNs, const char *toNs) {
massert( "rename not yet implemented for CachedBasicRecStore", false ); massert( 10378 , "rename not yet implemented for CachedBasicRecStore ", false );
} }
/* close datafiles associated with the db specified. */ /* close datafiles associated with the db specified. */
virtual void closeFiles(string dbname, string path) { virtual void closeFiles(string dbname, string path) {
theRecCache.closeFiles(dbname, dbpath); theRecCache.closeFiles(dbname, dbpath);
} }
}; };
/* see concurrency.h - note on a lock reset from read->write we don't /* see concurrency.h - note on a lock reset from read->write we don't
call dbunlocking_read, we just wait for the final dbunlocking_write call dbunlocking_read, we just wait for the final dbunlocking_write
call call
*/ */
inline void dbunlocking_read() { inline void dbunlocking_read() {
Client *c = currentClient.get(); Client *c = currentClient.get();
c->top.clientStop(); if ( c )
c->top.clientStop();
} }
inline void dbunlocking_write() { inline void dbunlocking_write() {
theRecCache.ejectOld(); theRecCache.ejectOld();
dbunlocking_read(); dbunlocking_read();
} }
} /*namespace*/ } /*namespace*/
 End of changes. 3 change blocks. 
3 lines changed or deleted 4 lines changed or added


 reci.h   reci.h 
skipping to change at line 14 skipping to change at line 14
#include "storage.h" #include "storage.h"
namespace mongo { namespace mongo {
/* Subclass this and implement your real storage interface. /* Subclass this and implement your real storage interface.
*/ */
class RecStoreInterface { class RecStoreInterface {
public: public:
virtual ~RecStoreInterface() {} virtual ~RecStoreInterface() {}
/* Get a pointer to the data at diskloc d. Pointer guaranteed to stay in /* Get a pointer to the data at diskloc d. Pointer guaranteed to stay in
scope through the current database operation's life. scope through the current database operation's life.
*/ */
virtual char* get(DiskLoc d, unsigned len) = 0; virtual char* get(DiskLoc d, unsigned len) = 0;
/* indicate that the diskloc specified has been updated. note that as-i s today,tl he modification may come AFTER this /* indicate that the diskloc specified has been updated. note that as-i s today, the modification may come AFTER this
call -- we handle that currently -- until the dblock finishes. call -- we handle that currently -- until the dblock finishes.
*/ */
virtual void modified(DiskLoc d) = 0; virtual void modified(DiskLoc d) = 0;
/* insert specified data as a record */ /* insert specified data as a record */
virtual DiskLoc insert(const char *ns, const void *obuf, int len, bool god) = 0; virtual DiskLoc insert(const char *ns, const void *obuf, int len, bool god) = 0;
virtual void deleteRecord(const char *ns, DiskLoc d) { massert("not imp lemented RecStoreInterface::deleteRecord", false); } virtual void deleteRecord(const char *ns, DiskLoc d) { massert( 10379 , "not implemented RecStoreInterface::deleteRecord", false); }
/* drop the collection */ /* drop the collection */
virtual void drop(const char *ns) = 0; virtual void drop(const char *ns) = 0;
/* rename collection */ /* rename collection */
virtual void rename(const char *fromNs, const char *toNs) = 0; virtual void rename(const char *fromNs, const char *toNs) = 0;
/* close datafiles associated with the db specified. */ /* close datafiles associated with the db specified. */
virtual void closeFiles(string dbname, string path) = 0; virtual void closeFiles(string dbname, string path) = 0;
 End of changes. 3 change blocks. 
2 lines changed or deleted 3 lines changed or added


 recstore.h   recstore.h 
skipping to change at line 53 skipping to change at line 53
string filename; string filename;
private: private:
void writeHeader(); void writeHeader();
File f; File f;
fileofs len; fileofs len;
RecStoreHeader h; // h.reserved is wasteful here; fix later. RecStoreHeader h; // h.reserved is wasteful here; fix later.
void write(fileofs ofs, const char *data, unsigned len) { void write(fileofs ofs, const char *data, unsigned len) {
f.write(ofs, data, len); f.write(ofs, data, len);
massert("basicrecstore write io error", !f.bad()); massert( 10380 , "basicrecstore write io error", !f.bad());
} }
}; };
/* --- implementation --- */ /* --- implementation --- */
inline BasicRecStore::~BasicRecStore() { inline BasicRecStore::~BasicRecStore() {
h.cleanShutdown = 0; h.cleanShutdown = 0;
if( f.is_open() ) { if( f.is_open() ) {
writeHeader(); writeHeader();
f.fsync(); f.fsync();
} }
} }
inline void BasicRecStore::writeHeader() { inline void BasicRecStore::writeHeader() {
write(0, (const char *) &h, 28); // update header in file for new leof write(0, (const char *) &h, 28); // update header in file for new leof
uassert("file io error in BasicRecStore [1]", !f.bad()); uassert( 10115 , "file io error in BasicRecStore [1]", !f.bad());
} }
inline fileofs BasicRecStore::insert(const char *buf, unsigned reclen) { inline fileofs BasicRecStore::insert(const char *buf, unsigned reclen) {
if( h.firstDeleted ) { if( h.firstDeleted ) {
uasserted("deleted not yet implemented recstoreinsert"); uasserted(11500, "deleted not yet implemented recstoreinsert");
} }
massert("bad len", reclen == h.recsize); massert( 10381 , "bad len", reclen == h.recsize);
fileofs ofs = h.leof; fileofs ofs = h.leof;
h.leof += reclen; h.leof += reclen;
if( h.leof > len ) { if( h.leof > len ) {
// grow the file. we grow quite a bit to avoid excessive file syst em fragmentations // grow the file. we grow quite a bit to avoid excessive file syst em fragmentations
len += (len / 8) + h.recsize; len += (len / 8) + h.recsize;
uassert( "recstore file too big for 32 bit", len <= 0x7fffffff || s izeof(std::streamoff) > 4 ); uassert( 10116 , "recstore file too big for 32 bit", len <= 0x7fff ffff || sizeof(std::streamoff) > 4 );
write(len, "", 0); write(len, "", 0);
} }
writeHeader(); writeHeader();
write(ofs, buf, reclen); write(ofs, buf, reclen);
uassert("file io error in BasicRecStore [2]", !f.bad()); uassert( 10117 , "file io error in BasicRecStore [2]", !f.bad());
return ofs; return ofs;
} }
/* so far, it's ok to read or update a subset of a record */ /* so far, it's ok to read or update a subset of a record */
inline void BasicRecStore::update(fileofs o, const char *buf, unsigned len) { inline void BasicRecStore::update(fileofs o, const char *buf, unsigned len) {
assert(o <= h.leof && o >= sizeof(RecStoreHeader)); assert(o <= h.leof && o >= sizeof(RecStoreHeader));
write(o, buf, len); write(o, buf, len);
} }
inline void BasicRecStore::get(fileofs o, char *buf, unsigned len) { inline void BasicRecStore::get(fileofs o, char *buf, unsigned len) {
assert(o <= h.leof && o >= sizeof(RecStoreHeader)); assert(o <= h.leof && o >= sizeof(RecStoreHeader));
f.read(o, buf, len); f.read(o, buf, len);
massert("basicrestore::get I/O error", !f.bad()); massert( 10382 , "basicrestore::get I/O error", !f.bad());
} }
inline void BasicRecStore::remove(fileofs o, unsigned len) { inline void BasicRecStore::remove(fileofs o, unsigned len) {
uasserted("not yet implemented recstoreremove"); uasserted(11501, "not yet implemented recstoreremove");
} }
} }
 End of changes. 8 change blocks. 
8 lines changed or deleted 8 lines changed or added


 repl.h   repl.h 
skipping to change at line 65 skipping to change at line 65
extern int opIdMem; extern int opIdMem;
bool cloneFrom(const char *masterHost, string& errmsg, const string& fr omdb, bool logForReplication, bool cloneFrom(const char *masterHost, string& errmsg, const string& fr omdb, bool logForReplication,
bool slaveOk, bool useReplAuth, bool snap shot); bool slaveOk, bool useReplAuth, bool snap shot);
/* A replication exception */ /* A replication exception */
class SyncException : public DBException { class SyncException : public DBException {
public: public:
virtual const char* what() const throw() { return "sync exception"; } virtual const char* what() const throw() { return "sync exception"; }
virtual int getCode(){ return 10001; }
}; };
/* A Source is a source from which we can pull (replicate) data. /* A Source is a source from which we can pull (replicate) data.
stored in collection local.sources. stored in collection local.sources.
Can be a group of things to replicate for several databases. Can be a group of things to replicate for several databases.
{ host: ..., source: ..., only: ..., syncedTo: ..., localLogTs: . .., dbsNextPass: { ... }, incompleteCloneDbs: { ... } } { host: ..., source: ..., only: ..., syncedTo: ..., localLogTs: . .., dbsNextPass: { ... }, incompleteCloneDbs: { ... } }
'source' defaults to 'main'; support for multiple source names is 'source' defaults to 'main'; support for multiple source names is
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 replset.h   replset.h 
skipping to change at line 158 skipping to change at line 158
inline ReplPair::ReplPair(const char *remoteEnd, const char *arb) { inline ReplPair::ReplPair(const char *remoteEnd, const char *arb) {
state = -1; state = -1;
remote = remoteEnd; remote = remoteEnd;
remotePort = CmdLine::DefaultDBPort; remotePort = CmdLine::DefaultDBPort;
remoteHost = remoteEnd; remoteHost = remoteEnd;
const char *p = strchr(remoteEnd, ':'); const char *p = strchr(remoteEnd, ':');
if ( p ) { if ( p ) {
remoteHost = string(remoteEnd, p-remoteEnd); remoteHost = string(remoteEnd, p-remoteEnd);
remotePort = atoi(p+1); remotePort = atoi(p+1);
uassert("bad port #", remotePort > 0 && remotePort < 0x10000 ); uassert( 10125 , "bad port #", remotePort > 0 && remotePort < 0 x10000 );
if ( remotePort == CmdLine::DefaultDBPort ) if ( remotePort == CmdLine::DefaultDBPort )
remote = remoteHost; // don't include ":27017" as it is def ault; in case ran in diff ways over time to normalizke the hostname format in sources collection remote = remoteHost; // don't include ":27017" as it is def ault; in case ran in diff ways over time to normalizke the hostname format in sources collection
} }
uassert("arbiter parm is missing, use '-' for none", arb); uassert( 10126 , "arbiter parm is missing, use '-' for none", arb);
arbHost = arb; arbHost = arb;
uassert("arbiter parm is empty", !arbHost.empty()); uassert( 10127 , "arbiter parm is empty", !arbHost.empty());
} }
/* This is set to true if we have EVER been up to date -- this way a ne w pair member /* This is set to true if we have EVER been up to date -- this way a ne w pair member
which is a replacement won't go online as master until we have initial ly fully synced. which is a replacement won't go online as master until we have initial ly fully synced.
*/ */
class PairSync { class PairSync {
int initialsynccomplete; int initialsynccomplete;
public: public:
PairSync() { PairSync() {
initialsynccomplete = -1; initialsynccomplete = -1;
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 scanandorder.h   scanandorder.h 
skipping to change at line 113 skipping to change at line 113
} }
int size() const { int size() const {
return best.size(); return best.size();
} }
void add(BSONObj o) { void add(BSONObj o) {
BSONObj k = order.getKeyFromObject(o); BSONObj k = order.getKeyFromObject(o);
if ( (int) best.size() < limit ) { if ( (int) best.size() < limit ) {
approxSize += k.objsize(); approxSize += k.objsize();
uassert( "too much key data for sort() with no index. add an index or specify a smaller limit", approxSize < 1 * 1024 * 1024 ); uassert( 10128 , "too much key data for sort() with no ind ex. add an index or specify a smaller limit", approxSize < 1 * 1024 * 1024 );
_add(k, o); _add(k, o);
return; return;
} }
BestMap::iterator i; BestMap::iterator i;
assert( best.end() != best.begin() ); assert( best.end() != best.begin() );
i = best.end(); i = best.end();
i--; i--;
_addIfBetter(k, o, i); _addIfBetter(k, o, i);
} }
skipping to change at line 136 skipping to change at line 136
int nFilled = 0; int nFilled = 0;
for ( BestMap::iterator i = begin; i != end; i++ ) { for ( BestMap::iterator i = begin; i != end; i++ ) {
n++; n++;
if ( n <= startFrom ) if ( n <= startFrom )
continue; continue;
BSONObj& o = i->second; BSONObj& o = i->second;
fillQueryResultFromObj(b, filter, o); fillQueryResultFromObj(b, filter, o);
nFilled++; nFilled++;
if ( nFilled >= limit ) if ( nFilled >= limit )
break; break;
uassert( "too much data for sort() with no index", b.len() < 4000000 ); // appserver limit uassert( 10129 , "too much data for sort() with no index", b.len() < 4000000 ); // appserver limit
} }
nout = nFilled; nout = nFilled;
} }
/* scanning complete. stick the query result in b for n objects. */ /* scanning complete. stick the query result in b for n objects. */
void fill(BufBuilder& b, FieldMatcher *filter, int& nout) { void fill(BufBuilder& b, FieldMatcher *filter, int& nout) {
_fill(b, filter, nout, best.begin(), best.end()); _fill(b, filter, nout, best.begin(), best.end());
} }
}; };
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 security.h   security.h 
skipping to change at line 62 skipping to change at line 62
void authorize(const char *dbname) { void authorize(const char *dbname) {
assertInWriteLock(); assertInWriteLock();
m[dbname].level = 2; m[dbname].level = 2;
} }
virtual bool isAuthorized(const char *dbname) { virtual bool isAuthorized(const char *dbname) {
if( m[dbname].level == 2 ) return true; if( m[dbname].level == 2 ) return true;
if( noauth ) return true; if( noauth ) return true;
if( m["admin"].level == 2 ) return true; if( m["admin"].level == 2 ) return true;
if( m["local"].level == 2 ) return true; if( m["local"].level == 2 ) return true;
if( isLocalHost ) { if( isLocalHost ) {
dblock l; // TODO: this is bad, since we want to be able to check this even if outside global lock. probably goes away with concurren cy readlock l("");
DBContext c("admin.system.users"); DBContext c("admin.system.users");
BSONObj result; BSONObj result;
if( Helpers::getSingleton("admin.system.user s", result) ) if( Helpers::getSingleton("admin.system.user s", result) )
return false; return false;
if( warned == 0 ) { if( warned == 0 ) {
warned++; warned++;
log() << "warning: no users configur ed in admin.system.users, allowing localhost access" << endl; log() << "warning: no users configur ed in admin.system.users, allowing localhost access" << endl;
} }
return true; return true;
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 shardkey.h   shardkey.h 
skipping to change at line 39 skipping to change at line 39
*/ */
class ShardKeyPattern { class ShardKeyPattern {
public: public:
ShardKeyPattern( BSONObj p = BSONObj() ); ShardKeyPattern( BSONObj p = BSONObj() );
/** /**
global min is the lowest possible value for this key global min is the lowest possible value for this key
e.g. { num : MinKey } e.g. { num : MinKey }
*/ */
BSONObj globalMin() const { return gMin; } BSONObj globalMin() const { return gMin; }
BSONObj globalMinDotted() const { return gMinDotted; }
/** /**
global max is the highest possible value for this key global max is the highest possible value for this key
*/ */
BSONObj globalMax() const { return gMax; } BSONObj globalMax() const { return gMax; }
BSONObj globalMaxDotted() const { return gMax; }
bool isGlobalMin( const BSONObj& k ){ bool isGlobalMin( const BSONObj& k ){
return k.woCompare( globalMin() ) == 0; return k.woCompare( globalMin() ) == 0;
} }
bool isGlobalMax( const BSONObj& k ){ bool isGlobalMax( const BSONObj& k ){
return k.woCompare( globalMax() ) == 0; return k.woCompare( globalMax() ) == 0;
} }
bool isGlobal( const BSONObj& k ){ bool isGlobal( const BSONObj& k ){
skipping to change at line 104 skipping to change at line 102
-> -1 -> -1
@return @return
0 if sort either doesn't have all the fields or has extra fie lds 0 if sort either doesn't have all the fields or has extra fie lds
< 0 if sort is descending < 0 if sort is descending
> 1 if sort is ascending > 1 if sort is ascending
*/ */
int canOrder( const BSONObj& sort ); int canOrder( const BSONObj& sort );
BSONObj key() { return pattern; } BSONObj key() { return pattern; }
BSONObj keyDotted() { return patternDotted; }
string toString() const; string toString() const;
BSONObj extractKey(const BSONObj& from) const; BSONObj extractKey(const BSONObj& from) const;
bool partOfShardKey(const string& key ) const { bool partOfShardKey(const string& key ) const {
return patternfields.count( key ) > 0; return patternfields.count( key ) > 0;
} }
operator string() const {
return pattern.toString();
}
private: private:
// all BSONObj stored with both nested and dotted form
BSONObj pattern; BSONObj pattern;
BSONObj patternDotted;
BSONObj gMin; BSONObj gMin;
BSONObj gMinDotted;
BSONObj gMax; BSONObj gMax;
BSONObj gMaxDotted;
/* question: better to have patternfields precomputed or not? depe nds on if we use copy contructor often. */ /* question: better to have patternfields precomputed or not? depe nds on if we use copy contructor often. */
set<string> patternfields; set<string> patternfields;
bool relevant(const BSONObj& query, const BSONObj& L, const BSONObj & R); bool relevant(const BSONObj& query, const BSONObj& L, const BSONObj & R);
}; };
inline BSONObj ShardKeyPattern::extractKey(const BSONObj& from) const { inline BSONObj ShardKeyPattern::extractKey(const BSONObj& from) const {
return from.extractFields(pattern); return from.extractFields(pattern);
} }
 End of changes. 8 change blocks. 
9 lines changed or deleted 3 lines changed or added


 sock.h   sock.h 
skipping to change at line 66 skipping to change at line 66
#include <errno.h> #include <errno.h>
#include <netdb.h> #include <netdb.h>
namespace mongo { namespace mongo {
inline void closesocket(int s) { inline void closesocket(int s) {
close(s); close(s);
} }
const int INVALID_SOCKET = -1; const int INVALID_SOCKET = -1;
typedef int SOCKET; typedef int SOCKET;
//#define h_errno errno
inline int getLastError() {
return errno;
}
inline void disableNagle(int sock) { inline void disableNagle(int sock) {
int x = 1; int x = 1;
#ifdef SOL_TCP #ifdef SOL_TCP
int level = SOL_TCP; int level = SOL_TCP;
#else #else
int level = SOL_SOCKET; int level = SOL_SOCKET;
#endif #endif
if ( setsockopt(sock, level, TCP_NODELAY, (char *) &x, sizeof(x)) ) if ( setsockopt(sock, level, TCP_NODELAY, (char *) &x, sizeof(x)) )
skipping to change at line 99 skipping to change at line 96
#endif #endif
inline void setSockReceiveTimeout(int sock, int secs) { inline void setSockReceiveTimeout(int sock, int secs) {
// todo - finish - works? // todo - finish - works?
struct timeval tv; struct timeval tv;
tv.tv_sec = 0;//secs; tv.tv_sec = 0;//secs;
tv.tv_usec = 1000; tv.tv_usec = 1000;
int rc = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, si zeof(tv)); int rc = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, si zeof(tv));
if ( rc ) { if ( rc ) {
out() << "ERROR: setsockopt RCVTIMEO failed rc:" << rc << " err no:" << getLastError() << " secs:" << secs << " sock:" << sock << endl; out() << "ERROR: setsockopt RCVTIMEO failed rc:" << rc << " " < < OUTPUT_ERRNO << " secs:" << secs << " sock:" << sock << endl;
} }
} }
// If an ip address is passed in, just return that. If a hostname is p assed // If an ip address is passed in, just return that. If a hostname is p assed
// in, look up its ip and return that. Returns "" on failure. // in, look up its ip and return that. Returns "" on failure.
string hostbyname(const char *hostname); string hostbyname(const char *hostname);
struct SockAddr { struct SockAddr {
SockAddr() { SockAddr() {
addressSize = sizeof(sockaddr_in); addressSize = sizeof(sockaddr_in);
skipping to change at line 196 skipping to change at line 193
out() << " NOTSENT "; out() << " NOTSENT ";
// out() << curTimeMillis() << " .TEST: NOT SENDING PAC KET" << endl; // out() << curTimeMillis() << " .TEST: NOT SENDING PAC KET" << endl;
return 0; return 0;
} }
return ::sendto(sock, buf, len, 0, (sockaddr *) &EndPoint.sa, EndPo int.addressSize); return ::sendto(sock, buf, len, 0, (sockaddr *) &EndPoint.sa, EndPo int.addressSize);
} }
inline bool UDPConnection::init(const SockAddr& myAddr) { inline bool UDPConnection::init(const SockAddr& myAddr) {
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if ( sock == INVALID_SOCKET ) { if ( sock == INVALID_SOCKET ) {
out() << "invalid socket? " << errno << endl; out() << "invalid socket? " << OUTPUT_ERRNO << endl;
return false; return false;
} }
//out() << sizeof(sockaddr_in) << ' ' << myAddr.addressSize << endl ; //out() << sizeof(sockaddr_in) << ' ' << myAddr.addressSize << endl ;
if ( ::bind(sock, (sockaddr *) &myAddr.sa, myAddr.addressSize) != 0 ) { if ( ::bind(sock, (sockaddr *) &myAddr.sa, myAddr.addressSize) != 0 ) {
out() << "udp init failed" << endl; out() << "udp init failed" << endl;
closesocket(sock); closesocket(sock);
sock = 0; sock = 0;
return false; return false;
} }
socklen_t optLen; socklen_t optLen;
skipping to change at line 238 skipping to change at line 235
sa.sin_family = AF_INET; sa.sin_family = AF_INET;
sa.sin_port = htons(port); sa.sin_port = htons(port);
sa.sin_addr.s_addr = inet_addr(ip.c_str()); sa.sin_addr.s_addr = inet_addr(ip.c_str());
addressSize = sizeof(sa); addressSize = sizeof(sa);
} }
inline string getHostName() { inline string getHostName() {
char buf[256]; char buf[256];
int ec = gethostname(buf, 127); int ec = gethostname(buf, 127);
if ( ec || *buf == 0 ) { if ( ec || *buf == 0 ) {
log() << "can't get this server's hostname errno:" << ec << end l; log() << "can't get this server's hostname " << OUTPUT_ERRNO << endl;
return ""; return "";
} }
return buf; return buf;
} }
} // namespace mongo } // namespace mongo
 End of changes. 4 change blocks. 
7 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. 
1 lines changed or deleted 0 lines changed or added


 top.h   top.h 
skipping to change at line 26 skipping to change at line 26
*/ */
#pragma once #pragma once
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#undef assert #undef assert
#define assert xassert #define assert xassert
namespace mongo { namespace mongo {
/* 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 Top { class Top {
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;
public: typedef boost::tuple< D, int, int, int > UsageData;
Top() : read_(false), write_(false) { } public:
Top() : _read(false), _write(false) { }
/* these are used to record activity: */ /* these are used to record activity: */
void clientStart( const char *client ) { void clientStart( const char *client ) {
clientStop(); clientStop();
currentStart_ = currentTime(); _currentStart = currentTime();
current_ = client; _current = client;
} }
/* indicate current request is a read operation. */ /* indicate current request is a read operation. */
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); boostlock 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); boostlock 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(); for( UsageMap::iterator i = snapshot.begin(); i != snapshot.end
++i ) (); ++i )
sorted.insert( make_pair( i->second.get<0>(), i->first ) ); sorted.insert( make_pair( i->second.get<0>(), i->first ) );
for( multimap< D, string, more >::iterator i = sorted.begin(); i != for( multimap< D, string, more >::iterator i = sorted.begin();
sorted.end(); ++i ) { i != sorted.end(); ++i ) {
if ( trivialNs( i->second.c_str() ) ) if ( trivialNs( i->second.c_str() ) )
continue; continue;
Usage u; Usage u;
u.ns = i->second; u.ns = i->second;
u.time = totalUsage[ u.ns ].get<0>(); u.time = totalUsage[ u.ns ].get<0>();
u.pct = snapshotDuration_ != D() ? 100.0 * i->first.ticks() / s u.pct = _snapshotDuration != D() ? 100.0 * i->first.ticks()
napshotDuration_.ticks() : 0; / _snapshotDuration.ticks() : 0;
u.reads = snapshot[ u.ns ].get<1>(); u.reads = snapshot[ u.ns ].get<1>();
u.writes = snapshot[ u.ns ].get<2>(); u.writes = snapshot[ u.ns ].get<2>();
u.calls = snapshot[ u.ns ].get<3>(); u.calls = snapshot[ u.ns ].get<3>();
res.push_back( u ); res.push_back( u );
} }
for( UsageMap::iterator i = totalUsage.begin(); i != totalUsage.end for( UsageMap::iterator i = totalUsage.begin(); i != totalUsage
(); ++i ) { .end(); ++i ) {
if ( snapshot.count( i->first ) != 0 || trivialNs( i->first.c_s if ( snapshot.count( i->first ) != 0 || trivialNs( i->first
tr() ) ) .c_str() ) )
continue; continue;
Usage u; Usage u;
u.ns = i->first; u.ns = i->first;
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); boostlock 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;
_snapshotStart = currentTime();
_nextSnapshot.clear();
} }
snapshotDuration_ = currentTime() - snapshotStart_;
snapshotStart_ = currentTime();
nextSnapshot_.clear();
}
private: private:
static boost::mutex topMutex; static boost::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, boost::tuple< D, int, int, int > > UsageMap; // du typedef map<string,UsageData> UsageMap; // duration, # reads, # wri
ration, # reads, # writes, # total calls 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 );
recordUsageForMap( nextSnapshot_, client, duration ); recordUsageForMap( _nextSnapshot, client, duration );
} }
void recordUsageForMap( UsageMap &map, const string &client, D duration void recordUsageForMap( UsageMap &map, const string &client, D dura
) { tion ) {
map[ client ].get< 0 >() += duration; UsageData& g = map[client];
if ( read_ && !write_ ) g.get< 0 >() += duration;
map[ client ].get< 1 >()++; if ( _read && !_write )
else if ( !read_ && write_ ) g.get< 1 >()++;
map[ client ].get< 2 >()++; else if ( !_read && _write )
map[ client ].get< 3 >()++; g.get< 2 >()++;
} g.get< 3 >()++;
static void fillParentNamespaces( UsageMap &to, const UsageMap &from ) }
{ static void fillParentNamespaces( UsageMap &to, const UsageMap &fro
for( UsageMap::const_iterator i = from.begin(); i != from.end(); ++ m ) {
i ) { for( UsageMap::const_iterator i = from.begin(); i != from.end()
string current = i->first; ; ++i ) {
size_t dot = current.rfind( "." ); string current = i->first;
if ( dot == string::npos || dot != current.length() - 1 ) { size_t dot = current.rfind( "." );
inc( to[ current ], i->second ); if ( dot == string::npos || dot != current.length() - 1 ) {
} inc( to[ current ], i->second );
while( dot != string::npos ) { }
current = current.substr( 0, dot ); while( dot != string::npos ) {
inc( to[ current ], i->second ); current = current.substr( 0, dot );
dot = current.rfind( "." ); inc( to[ current ], i->second );
dot = current.rfind( "." );
}
} }
} }
} static void inc( UsageData &to, const UsageData &from ) {
static void inc( boost::tuple< D, int, int, int > &to, const boost::tup to.get<0>() += from.get<0>();
le< D, int, int, int > &from ) { to.get<1>() += from.get<1>();
to.get<0>() += from.get<0>(); to.get<2>() += from.get<2>();
to.get<1>() += from.get<1>(); to.get<3>() += from.get<3>();
to.get<2>() += from.get<2>(); }
to.get<3>() += from.get<3>(); struct more { bool operator()( const D &a, const D &b ) { return a
} > b; } };
struct more { bool operator()( const D &a, const D &b ) { return a > b; string _current;
} }; T _currentStart;
string current_; static T _snapshotStart;
T currentStart_; static D _snapshotDuration;
static T snapshotStart_; static UsageMap _totalUsage;
static D snapshotDuration_; static UsageMap _snapshotA;
static UsageMap totalUsage_; static UsageMap _snapshotB;
static UsageMap snapshotA_; static UsageMap &_snapshot;
static UsageMap snapshotB_; static UsageMap &_nextSnapshot;
static UsageMap &snapshot_; bool _read;
static UsageMap &nextSnapshot_; bool _write;
bool read_; };
bool write_;
};
} // namespace mongo } // namespace mongo
 End of changes. 19 change blocks. 
146 lines changed or deleted 147 lines changed or added


 utils.h   utils.h 
// utils.h // utils.h
#pragma once #pragma once
#include "../scripting/engine.h" #include "../scripting/engine.h"
namespace mongo { namespace mongo {
namespace shellUtils { namespace shellUtils {
extern std::string _dbConnect;
extern std::string _dbAuth;
void RecordMyLocation( const char *_argv0 ); void RecordMyLocation( const char *_argv0 );
void installShellUtils( Scope& scope ); void installShellUtils( Scope& scope );
// Scoped management of mongo program instances. Simple implementa tion: // Scoped management of mongo program instances. Simple implementa tion:
// destructor kills all mongod instances created by the shell. // destructor kills all mongod instances created by the shell.
struct MongoProgramScope { struct MongoProgramScope {
MongoProgramScope() {} // Avoid 'unused variable' warning. MongoProgramScope() {} // Avoid 'unused variable' warning.
~MongoProgramScope(); ~MongoProgramScope();
}; };
void KillMongoProgramInstances(); void KillMongoProgramInstances();
void initScope( Scope &scope );
} }
} }
 End of changes. 2 change blocks. 
0 lines changed or deleted 4 lines changed or added


 v8_db.h   v8_db.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 "../client/dbclient.h" #include "../client/dbclient.h"
namespace mongo { namespace mongo {
// These functions may depend on the caller creating a handle scope and
context scope.
v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate( bool local ) ; v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate( bool local ) ;
void installDBTypes( v8::Handle<v8::ObjectTemplate>& global ); void installDBTypes( v8::Handle<v8::ObjectTemplate>& global );
void installDBTypes( v8::Handle<v8::Object>& global ); void installDBTypes( v8::Handle<v8::Object>& global );
// the actual globals // the actual globals
mongo::DBClientBase * getConnection( const v8::Arguments& args ); mongo::DBClientBase * getConnection( const v8::Arguments& args );
// Mongo members // Mongo members
v8::Handle<v8::Value> mongoConsLocal(const v8::Arguments& args); v8::Handle<v8::Value> mongoConsLocal(const v8::Arguments& args);
skipping to change at line 57 skipping to change at line 59
v8::Handle<v8::Value> internalCursorNext(const v8::Arguments& args); v8::Handle<v8::Value> internalCursorNext(const v8::Arguments& args);
v8::Handle<v8::Value> internalCursorHasNext(const v8::Arguments& args); v8::Handle<v8::Value> internalCursorHasNext(const v8::Arguments& args);
// DB members // DB members
v8::Handle<v8::Value> dbInit(const v8::Arguments& args); v8::Handle<v8::Value> dbInit(const v8::Arguments& args);
v8::Handle<v8::Value> collectionInit( const v8::Arguments& args ); v8::Handle<v8::Value> collectionInit( const v8::Arguments& args );
v8::Handle<v8::Value> objectIdInit( const v8::Arguments& args ); v8::Handle<v8::Value> objectIdInit( const v8::Arguments& args );
v8::Handle<v8::Value> dbRefInit( const v8::Arguments& args ); v8::Handle<v8::Value> dbRefInit( const v8::Arguments& args );
v8::Handle<v8::Value> dbPointerInit( const v8::Arguments& args );
v8::Handle<v8::Value> binDataInit( const v8::Arguments& args );
v8::Handle<v8::Value> dbQueryInit( const v8::Arguments& args ); v8::Handle<v8::Value> dbQueryInit( const v8::Arguments& args );
v8::Handle<v8::Value> dbQueryIndexAccess( uint32_t index , const v8::Ac cessorInfo& info ); v8::Handle<v8::Value> dbQueryIndexAccess( uint32_t index , const v8::Ac cessorInfo& info );
v8::Handle<v8::Value> collectionFallback( v8::Local<v8::String> name, c onst v8::AccessorInfo &info); v8::Handle<v8::Value> collectionFallback( v8::Local<v8::String> name, c onst v8::AccessorInfo &info);
v8::Handle<v8::Value> bsonsize( const v8::Arguments& args );
} }
 End of changes. 3 change blocks. 
0 lines changed or deleted 8 lines changed or added


 v8_utils.h   v8_utils.h 
skipping to change at line 43 skipping to change at line 43
void ReportException(v8::TryCatch* handler); void ReportException(v8::TryCatch* handler);
#define jsassert(x,msg) assert(x) #define jsassert(x,msg) assert(x)
std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::Value> & o ); std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::Value> & o );
std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::TryCatc h> * try_catch ); std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::TryCatc h> * try_catch );
std::string toSTLString( const v8::Handle<v8::Value> & o ); std::string toSTLString( const v8::Handle<v8::Value> & o );
std::string toSTLString( const v8::TryCatch * try_catch ); std::string toSTLString( const v8::TryCatch * try_catch );
class V8Scope;
void installFork( v8::Handle< v8::Object > &global, v8::Handle< v8::Con
text > &context );
} }
 End of changes. 1 change blocks. 
0 lines changed or deleted 3 lines changed or added


 v8_wrapper.h   v8_wrapper.h 
skipping to change at line 28 skipping to change at line 28
#pragma once #pragma once
#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 ); 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 );
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 );
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();
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 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/