allocator.h   allocator.h 
skipping to change at line 35 skipping to change at line 35
return x; return x;
} }
inline void * ourrealloc(void *ptr, size_t size) { inline void * ourrealloc(void *ptr, size_t size) {
void *x = realloc(ptr, size); void *x = realloc(ptr, size);
if ( x == 0 ) dbexit( EXIT_OOM_REALLOC , "realloc fails"); if ( x == 0 ) dbexit( EXIT_OOM_REALLOC , "realloc fails");
return x; return x;
} }
#define MONGO_malloc mongo::ourmalloc #define MONGO_malloc mongo::ourmalloc
#define malloc MONGO_malloc
#define MONGO_realloc mongo::ourrealloc #define MONGO_realloc mongo::ourrealloc
#define realloc MONGO_realloc
} // namespace mongo } // namespace mongo
 End of changes. 2 change blocks. 
0 lines changed or deleted 2 lines changed or added


 assert_util.h   assert_util.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 "../db/lasterror.h" #include "../bson/inline_decls.h"
// MONGO_NORETURN undefed at end of file // MONGO_NORETURN undefed at end of file
#ifdef __GNUC__ #ifdef __GNUC__
# define MONGO_NORETURN __attribute__((__noreturn__)) # define MONGO_NORETURN __attribute__((__noreturn__))
#else #else
# define MONGO_NORETURN # define MONGO_NORETURN
#endif #endif
namespace mongo { namespace mongo {
enum CommonErrorCodes { enum CommonErrorCodes {
DatabaseDifferCaseCode = 13297 , DatabaseDifferCaseCode = 13297 ,
StaleConfigInContextCode = 13388 SendStaleConfigCode = 13388 ,
RecvStaleConfigCode = 9996
}; };
class AssertionCount { class AssertionCount {
public: public:
AssertionCount(); AssertionCount();
void rollover(); void rollover();
void condrollover( int newValue ); void condrollover( int newValue );
int regular; int regular;
int warning; int warning;
int msg; int msg;
int user; int user;
int rollovers; int rollovers;
}; };
extern AssertionCount assertionCount; extern AssertionCount assertionCount;
class BSONObjBuilder;
struct ExceptionInfo { struct ExceptionInfo {
ExceptionInfo() : msg(""),code(-1) {} ExceptionInfo() : msg(""),code(-1) {}
ExceptionInfo( const char * m , int c ) ExceptionInfo( const char * m , int c )
: msg( m ) , code( c ) { : msg( m ) , code( c ) {
} }
ExceptionInfo( const string& m , int c ) ExceptionInfo( const std::string& m , int c )
: msg( m ) , code( c ) { : msg( m ) , code( c ) {
} }
void append( BSONObjBuilder& b , const char * m = "$err" , const ch ar * c = "code" ) const ; void append( BSONObjBuilder& b , const char * m = "$err" , const ch ar * c = "code" ) const ;
string toString() const { stringstream ss; ss << "exception: " << c ode << " " << msg; return ss.str(); } std::string toString() const;
bool empty() const { return msg.empty(); } bool empty() const { return msg.empty(); }
void reset(){ msg = ""; code=-1; } void reset(){ msg = ""; code=-1; }
std::string msg;
string msg;
int code; int code;
}; };
/** helper class that builds error strings. lighter weight than a Stri ngBuilder, albeit less flexible. /** helper class that builds error strings. lighter weight than a Stri ngBuilder, albeit less flexible.
NOINLINE_DECL used in the constructor implementations as we are ass uming this is a cold code path when used. NOINLINE_DECL used in the constructor implementations as we are ass uming this is a cold code path when used.
example: example:
throw UserException(123, ErrorMsg("blah", num_val)); throw UserException(123, ErrorMsg("blah", num_val));
*/ */
class ErrorMsg { class ErrorMsg {
public: public:
ErrorMsg(const char *msg, char ch); ErrorMsg(const char *msg, char ch);
ErrorMsg(const char *msg, unsigned val); ErrorMsg(const char *msg, unsigned val);
operator string() const { return buf; } operator std::string() const { return buf; }
private: private:
char buf[256]; char buf[256];
}; };
class DBException;
std::string causedBy( const DBException& e );
std::string causedBy( const std::string& e );
bool inShutdown();
/** Most mongo exceptions inherit from this; this is commonly caught in
most threads */
class DBException : public std::exception { class DBException : public std::exception {
public: public:
DBException( const ExceptionInfo& ei ) : _ei(ei) {} DBException( const ExceptionInfo& ei ) : _ei(ei) { traceIfNeeded(*t
DBException( const char * msg , int code ) : _ei(msg,code) {} his); }
DBException( const string& msg , int code ) : _ei(msg,code) {} DBException( const char * msg , int code ) : _ei(msg,code) { traceI
fNeeded(*this); }
DBException( const std::string& msg , int code ) : _ei(msg,code) {
traceIfNeeded(*this); }
virtual ~DBException() throw() { } virtual ~DBException() throw() { }
virtual const char* what() const throw() { return _ei.msg.c_str(); } virtual const char* what() const throw() { return _ei.msg.c_str(); }
virtual int getCode() const { return _ei.code; } virtual int getCode() const { return _ei.code; }
virtual void appendPrefix( stringstream& ss ) const { } virtual void appendPrefix( std::stringstream& ss ) const { }
virtual void addContext( const std::string& str ) {
virtual string toString() const { _ei.msg = str + causedBy( _ei.msg );
stringstream ss; ss << getCode() << " " << what(); return ss.st
r();
return ss.str();
} }
virtual std::string toString() const;
const ExceptionInfo& getInfo() const { return _ei; } const ExceptionInfo& getInfo() const { return _ei; }
private:
static void traceIfNeeded( const DBException& e );
public:
static bool traceExceptions;
protected: protected:
ExceptionInfo _ei; ExceptionInfo _ei;
}; };
class AssertionException : public DBException { class AssertionException : public DBException {
public: public:
AssertionException( const ExceptionInfo& ei ) : DBException(ei) {} AssertionException( const ExceptionInfo& ei ) : DBException(ei) {}
AssertionException( const char * msg , int code ) : DBException(msg ,code) {} AssertionException( const char * msg , int code ) : DBException(msg ,code) {}
AssertionException( const string& msg , int code ) : DBException(ms g,code) {} AssertionException( const std::string& msg , int code ) : DBExcepti on(msg,code) {}
virtual ~AssertionException() throw() { } virtual ~AssertionException() throw() { }
virtual bool severe() { return true; } virtual bool severe() { return true; }
virtual bool isUserAssertion() { return false; } virtual bool isUserAssertion() { return false; }
/* true if an interrupted exception - see KillCurrentOp */ /* true if an interrupted exception - see KillCurrentOp */
bool interrupted() { bool interrupted() {
return _ei.code == 11600 || _ei.code == 11601; return _ei.code == 11600 || _ei.code == 11601;
} }
}; };
/* 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(int c , const string& m) : AssertionException( m , c UserException(int c , const std::string& m) : AssertionException( m
) {} , c ) {}
virtual bool severe() { return false; } virtual bool severe() { return false; }
virtual bool isUserAssertion() { return true; } virtual bool isUserAssertion() { return true; }
virtual void appendPrefix( stringstream& ss ) const { ss << "useras sert:"; } virtual void appendPrefix( std::stringstream& ss ) const;
}; };
class MsgAssertionException : public AssertionException { class MsgAssertionException : public AssertionException {
public: public:
MsgAssertionException( const ExceptionInfo& ei ) : AssertionExcepti on( ei ) {} MsgAssertionException( const ExceptionInfo& ei ) : AssertionExcepti on( ei ) {}
MsgAssertionException(int c, const string& m) : AssertionException( m , c ) {} MsgAssertionException(int c, const std::string& m) : AssertionExcep tion( m , c ) {}
virtual bool severe() { return false; } virtual bool severe() { return false; }
virtual void appendPrefix( stringstream& ss ) const { ss << "masser t:"; } virtual void appendPrefix( std::stringstream& ss ) const;
}; };
void asserted(const char *msg, const char *file, unsigned line) MONGO_N ORETURN; void asserted(const char *msg, const char *file, unsigned line) MONGO_N ORETURN;
void wasserted(const char *msg, const char *file, unsigned line); void wasserted(const char *msg, const char *file, unsigned line);
void verifyFailed( int msgid ); void verifyFailed( int msgid );
void fassertFailed( int msgid );
/** a "user assertion". throws UserAssertion. logs. typically used f or errors that a user /** a "user assertion". throws UserAssertion. logs. typically used f or errors that a user
could cause, such as duplicate key, disk full, etc. could cause, such as duplicate key, disk full, etc.
*/ */
void uasserted(int msgid, const char *msg) MONGO_NORETURN; void uasserted(int msgid, const char *msg) MONGO_NORETURN;
inline void uasserted(int msgid , string msg) { uasserted(msgid, msg.c_ str()); } void uasserted(int msgid , const std::string &msg);
/** reported via lasterror, but don't throw exception */ /** reported via lasterror, but don't throw exception */
void uassert_nothrow(const char *msg); void uassert_nothrow(const char *msg);
/** msgassert and massert are for errors that are internal but have a w ell defined error text string. /** msgassert and massert are for errors that are internal but have a w ell defined error text std::string.
a stack trace is logged. a stack trace is logged.
*/ */
void msgassertedNoTrace(int msgid, const char *msg) MONGO_NORETURN; void msgassertedNoTrace(int msgid, const char *msg) MONGO_NORETURN;
inline void msgassertedNoTrace(int msgid, const string& msg) { msgasser tedNoTrace( msgid , msg.c_str() ); } inline void msgassertedNoTrace(int msgid, const std::string& msg) { msg assertedNoTrace( msgid , msg.c_str() ); }
void msgasserted(int msgid, const char *msg) MONGO_NORETURN; void msgasserted(int msgid, const char *msg) MONGO_NORETURN;
inline void msgasserted(int msgid, string msg) { msgasserted(msgid, msg .c_str()); } void msgasserted(int msgid, const std::string &msg);
/* convert various types of exceptions to strings */ /* convert various types of exceptions to strings */
inline string causedBy( const char* e ){ return (string)" :: caused by inline std::string causedBy( const char* e ){ return (std::string)" ::
:: " + e; } caused by :: " + e; }
inline string causedBy( const DBException& e ){ return causedBy( e.toSt inline std::string causedBy( const DBException& e ){ return causedBy( e
ring().c_str() ); } .toString().c_str() ); }
inline string causedBy( const std::exception& e ){ return causedBy( e.w inline std::string causedBy( const std::exception& e ){ return causedBy
hat() ); } ( e.what() ); }
inline string causedBy( const string& e ){ return causedBy( e.c_str() ) inline std::string causedBy( const std::string& e ){ return causedBy( e
; } .c_str() ); }
/** in the mongodb source, use verify() instead of assert(). verify is always evaluated even in release builds. */ /** in the mongodb source, use verify() instead of assert(). verify is always evaluated even in release builds. */
inline void verify( int msgid , bool testOK ) { if ( ! testOK ) verifyF ailed( msgid ); } inline void verify( int msgid , bool testOK ) { if ( ! testOK ) verifyF ailed( msgid ); }
/** abends on condition failure */
inline void fassert( int msgid , bool testOK ) { if ( ! testOK ) fasser
tFailed( msgid ); }
#ifdef assert
#undef assert
#endif
#define MONGO_assert(_Expression) (void)( MONGO_likely(!!(_Expression)) || (mongo::asserted(#_Expression, __FILE__, __LINE__), 0) ) #define MONGO_assert(_Expression) (void)( MONGO_likely(!!(_Expression)) || (mongo::asserted(#_Expression, __FILE__, __LINE__), 0) )
#define assert MONGO_assert
/* "user assert". if asserts, user did something wrong, not our code * / /* "user assert". if asserts, user did something wrong, not our code * /
#define MONGO_uassert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || ( mongo::uasserted(msgid, msg), 0) ) #define MONGO_uassert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || ( mongo::uasserted(msgid, msg), 0) )
#define uassert MONGO_uassert
/* warning only - keeps going */ /* warning only - keeps going */
#define MONGO_wassert(_Expression) (void)( MONGO_likely(!!(_Expression)) || (mongo::wasserted(#_Expression, __FILE__, __LINE__), 0) ) #define MONGO_wassert(_Expression) (void)( MONGO_likely(!!(_Expression)) || (mongo::wasserted(#_Expression, __FILE__, __LINE__), 0) )
#define wassert MONGO_wassert
/* 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 MONGO_massert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || ( mongo::msgasserted(msgid, msg), 0) ) #define MONGO_massert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || ( mongo::msgasserted(msgid, msg), 0) )
#define massert MONGO_massert
/* 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 MONGO_dassert assert # define MONGO_dassert assert
#else #else
# define MONGO_dassert(x) # define MONGO_dassert(x)
#endif #endif
#define dassert MONGO_dassert
// some special ids that we want to duplicate // some special ids that we want to duplicate
// > 10000 asserts // > 10000 asserts
// < 10000 UserException // < 10000 UserException
enum { ASSERT_ID_DUPKEY = 11000 }; enum { ASSERT_ID_DUPKEY = 11000 };
/* throws a uassertion with an appropriate msg */ /* throws a uassertion with an appropriate msg */
void streamNotGood( int code , string msg , std::ios& myios ) MONGO_NOR ETURN; void streamNotGood( int code , std::string msg , std::ios& myios ) MONG O_NORETURN;
inline void assertStreamGood(unsigned msgid, string msg, std::ios& myio s) { inline void assertStreamGood(unsigned msgid, std::string msg, std::ios& myios) {
if( !myios.good() ) streamNotGood(msgid, msg, myios); if( !myios.good() ) streamNotGood(msgid, msg, myios);
} }
string demangleName( const type_info& typeinfo ); std::string demangleName( const type_info& typeinfo );
} // namespace mongo } // namespace mongo
#define BOOST_CHECK_EXCEPTION MONGO_BOOST_CHECK_EXCEPTION #define BOOST_CHECK_EXCEPTION MONGO_BOOST_CHECK_EXCEPTION
#define MONGO_BOOST_CHECK_EXCEPTION( expression ) \ #define MONGO_BOOST_CHECK_EXCEPTION( expression ) \
try { \ try { \
expression; \ expression; \
} catch ( const std::exception &e ) { \ } catch ( const std::exception &e ) { \
stringstream ss; \ stringstream ss; \
ss << "caught boost exception: " << e.what() << ' ' << __FILE__ << ' ' << __LINE__; \ ss << "caught boost exception: " << e.what() << ' ' << __FILE__ << ' ' << __LINE__; \
skipping to change at line 235 skipping to change at line 258
} }
#define MONGO_BOOST_CHECK_EXCEPTION_WITH_MSG( expression, msg ) \ #define MONGO_BOOST_CHECK_EXCEPTION_WITH_MSG( expression, msg ) \
try { \ try { \
expression; \ expression; \
} catch ( const std::exception &e ) { \ } catch ( const std::exception &e ) { \
stringstream ss; \ stringstream ss; \
ss << msg << " caught boost exception: " << e.what(); \ ss << msg << " caught boost exception: " << e.what(); \
msgasserted( 14043 , ss.str() ); \ msgasserted( 14043 , ss.str() ); \
} catch ( ... ) { \ } catch ( ... ) { \
msgasserted( 14044 , string("unknown boost failed ") + msg ); \ msgasserted( 14044 , std::string("unknown boost failed ") + msg ); \
} }
#define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD #define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD
#define MONGO_DESTRUCTOR_GUARD( expression ) \ #define MONGO_DESTRUCTOR_GUARD( expression ) \
try { \ try { \
expression; \ expression; \
} catch ( const std::exception &e ) { \ } catch ( const std::exception &e ) { \
problem() << "caught exception (" << e.what() << ") in destructor ( " << __FUNCTION__ << ")" << endl; \ problem() << "caught exception (" << e.what() << ") in destructor ( " << __FUNCTION__ << ")" << endl; \
} catch ( ... ) { \ } catch ( ... ) { \
problem() << "caught unknown exception in destructor (" << __FUNCTI ON__ << ")" << endl; \ problem() << "caught unknown exception in destructor (" << __FUNCTI ON__ << ")" << endl; \
 End of changes. 34 change blocks. 
40 lines changed or deleted 67 lines changed or added


 balance.h   balance.h 
skipping to change at line 95 skipping to change at line 95
* @param candidateChunks possible chunks to move * @param candidateChunks possible chunks to move
* @return number of chunks effectively moved * @return number of chunks effectively moved
*/ */
int _moveChunks( const vector<CandidateChunkPtr>* candidateChunks ) ; int _moveChunks( const vector<CandidateChunkPtr>* candidateChunks ) ;
/** /**
* Marks this balancer as being live on the config server(s). * Marks this balancer as being live on the config server(s).
* *
* @param conn is the connection with the config server(s) * @param conn is the connection with the config server(s)
*/ */
void _ping( DBClientBase& conn ); void _ping( DBClientBase& conn, bool waiting = false );
/** /**
* @return true if all the servers listed in configdb as being shar ds are reachable and are distinct processes * @return true if all the servers listed in configdb as being shar ds are reachable and are distinct processes
*/ */
bool _checkOIDs(); bool _checkOIDs();
}; };
extern Balancer balancer; extern Balancer balancer;
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 bson-inl.h   bson-inl.h 
skipping to change at line 37 skipping to change at line 37
#undef max #undef max
#undef min #undef min
#endif #endif
namespace mongo { namespace mongo {
inline bool isNaN(double d) { inline bool isNaN(double d) {
return d != d; return d != d;
} }
inline bool isInf(double d, int* sign = 0) {
volatile double tmp = d;
if ((tmp == d) && ((tmp - d) != 0.0)) {
if ( sign ) {
*sign = (d < 0.0 ? -1 : 1);
}
return true;
}
if ( sign ) {
*sign = 0;
}
return false;
}
/* must be same type when called, unless both sides are #s /* must be same type when called, unless both sides are #s
this large function is in header to facilitate inline-only use of bs on this large function is in header to facilitate inline-only use of bs on
*/ */
inline int compareElementValues(const BSONElement& l, const BSONElement & r) { inline int compareElementValues(const BSONElement& l, const BSONElement & r) {
int f; int f;
switch ( l.type() ) { switch ( l.type() ) {
case EOO: case EOO:
case Undefined: // EOO and Undefined are same canonicalType case Undefined: // EOO and Undefined are same canonicalType
case jstNULL: case jstNULL:
skipping to change at line 127 skipping to change at line 144
case DBRef: { case DBRef: {
int lsz = l.valuesize(); int lsz = l.valuesize();
int rsz = r.valuesize(); int rsz = r.valuesize();
if ( lsz - rsz != 0 ) return lsz - rsz; if ( lsz - rsz != 0 ) return lsz - rsz;
return memcmp(l.value(), r.value(), lsz); return memcmp(l.value(), r.value(), lsz);
} }
case BinData: { case BinData: {
int lsz = l.objsize(); // our bin data size in bytes, not inclu ding the subtype byte int lsz = l.objsize(); // our bin data size in bytes, not inclu ding the subtype byte
int rsz = r.objsize(); int rsz = r.objsize();
if ( lsz - rsz != 0 ) return lsz - rsz; if ( lsz - rsz != 0 ) return lsz - rsz;
return memcmp(l.value()+4, r.value()+4, lsz+1); return memcmp(l.value()+4, r.value()+4, lsz+1 /*+1 for subtype byte*/);
} }
case RegEx: { case RegEx: {
int c = strcmp(l.regex(), r.regex()); int c = strcmp(l.regex(), r.regex());
if ( c ) if ( c )
return c; return c;
return strcmp(l.regexFlags(), r.regexFlags()); return strcmp(l.regexFlags(), r.regexFlags());
} }
case CodeWScope : { case CodeWScope : {
f = l.canonicalType() - r.canonicalType(); f = l.canonicalType() - r.canonicalType();
if ( f ) if ( f )
skipping to change at line 153 skipping to change at line 170
if ( f ) if ( f )
return f; return f;
return 0; return 0;
} }
default: default:
assert( false); assert( false);
} }
return -1; return -1;
} }
/* wo = "well ordered" */ /* wo = "well ordered"
note: (mongodb related) : this can only change in behavior when inde
x version # changes
*/
inline int BSONElement::woCompare( const BSONElement &e, inline int BSONElement::woCompare( const BSONElement &e,
bool considerFieldName ) const { bool considerFieldName ) const {
int lt = (int) canonicalType(); int lt = (int) canonicalType();
int rt = (int) e.canonicalType(); int rt = (int) e.canonicalType();
int x = lt - rt; int x = lt - rt;
if( x != 0 && (!isNumber() || !e.isNumber()) ) if( x != 0 && (!isNumber() || !e.isNumber()) )
return x; return x;
if ( considerFieldName ) { if ( considerFieldName ) {
x = strcmp(fieldName(), e.fieldName()); x = strcmp(fieldName(), e.fieldName());
if ( x != 0 ) if ( x != 0 )
 End of changes. 3 change blocks. 
2 lines changed or deleted 22 lines changed or added


 bson.h   bson.h 
skipping to change at line 47 skipping to change at line 47
#error this header is for client programs, not the mongo database itself. i nclude jsobj.h instead. #error this header is for client programs, not the mongo database itself. i nclude jsobj.h instead.
/* because we define simplistic assert helpers here that don't pull in a bu nch of util -- so that /* because we define simplistic assert helpers here that don't pull in a bu nch of util -- so that
BSON can be used header only. BSON can be used header only.
*/ */
#endif #endif
#include <cstdlib> #include <cstdlib>
#include <memory> #include <memory>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <boost/utility.hpp> //#include <boost/utility.hpp>
namespace bson { namespace bson {
using std::string; using std::string;
using std::stringstream; using std::stringstream;
class assertion : public std::exception { class assertion : public std::exception {
public: public:
assertion( unsigned u , const string& s ) assertion( unsigned u , const string& s )
: id( u ) , msg( s ) { : id( u ) , msg( s ) {
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 bson_db.h   bson_db.h 
skipping to change at line 70 skipping to change at line 70
uassert( 10062 , "not code" , 0 ); uassert( 10062 , "not code" , 0 );
return ""; return "";
} }
inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(DateNowLab eler& id) { inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(DateNowLab eler& id) {
_builder->appendDate(_fieldName, jsTime()); _builder->appendDate(_fieldName, jsTime());
_fieldName = 0; _fieldName = 0;
return *_builder; return *_builder;
} }
inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(NullLabele
r& id) {
_builder->appendNull(_fieldName);
_fieldName = 0;
return *_builder;
}
inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(MinKeyLabe ler& id) { inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(MinKeyLabe ler& id) {
_builder->appendMinKey(_fieldName); _builder->appendMinKey(_fieldName);
_fieldName = 0; _fieldName = 0;
return *_builder; return *_builder;
} }
inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(MaxKeyLabe ler& id) { inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(MaxKeyLabe ler& id) {
_builder->appendMaxKey(_fieldName); _builder->appendMaxKey(_fieldName);
_fieldName = 0; _fieldName = 0;
return *_builder; return *_builder;
 End of changes. 1 change blocks. 
0 lines changed or deleted 7 lines changed or added


 bsonelement.h   bsonelement.h 
skipping to change at line 24 skipping to change at line 24
* 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 <vector> #include <vector>
#include <string.h> #include <string.h>
#include "util/builder.h" #include "util/builder.h"
#include "bsontypes.h" #include "bsontypes.h"
#include "oid.h"
namespace mongo { namespace mongo {
class OpTime; class OpTime;
class BSONObj; class BSONObj;
class BSONElement; class BSONElement;
class BSONObjBuilder; class BSONObjBuilder;
} }
namespace bson { namespace bson {
typedef mongo::BSONElement be; typedef mongo::BSONElement be;
skipping to change at line 186 skipping to change at line 187
bool trueValue() const; bool trueValue() const;
/** True if number, string, bool, date, OID */ /** True if number, string, bool, date, OID */
bool isSimpleType() const; bool isSimpleType() const;
/** True if element is of a numeric type. */ /** True if element is of a numeric type. */
bool isNumber() const; bool isNumber() const;
/** Return double value for this field. MUST be NumberDouble type. */ /** Return double value for this field. MUST be NumberDouble type. */
double _numberDouble() const {return *reinterpret_cast< const doubl e* >( value() ); } double _numberDouble() const {return *reinterpret_cast< const doubl e* >( value() ); }
/** Return double value for this field. MUST be NumberInt type. */ /** Return int value for this field. MUST be NumberInt type. */
int _numberInt() const {return *reinterpret_cast< const int* >( val ue() ); } int _numberInt() const {return *reinterpret_cast< const int* >( val ue() ); }
/** Return double value for this field. MUST be NumberLong type. */ /** Return long long value for this field. MUST be NumberLong type. */
long long _numberLong() const {return *reinterpret_cast< const long long* >( value() ); } long long _numberLong() const {return *reinterpret_cast< const long long* >( value() ); }
/** Retrieve int value for the element safely. Zero returned if no t a number. */ /** Retrieve int value for the element safely. Zero returned if no t a number. */
int numberInt() const; int numberInt() const;
/** Retrieve long value for the element safely. Zero returned if n ot a number. */ /** Retrieve long value for the element safely. Zero returned if n ot a number. */
long long numberLong() const; long long numberLong() const;
/** Retrieve the numeric value of the element. If not of a numeric type, returns 0. /** Retrieve the numeric value of the element. If not of a numeric type, returns 0.
Note: casts to double, data loss may occur with large (>52 bit) NumberLong values. Note: casts to double, data loss may occur with large (>52 bit) NumberLong values.
*/ */
double numberDouble() const; double numberDouble() const;
skipping to change at line 393 skipping to change at line 394
explicit BSONElement(const char *d, int maxLen) : data(d) { explicit BSONElement(const char *d, int maxLen) : data(d) {
if ( eoo() ) { if ( eoo() ) {
totalSize = 1; totalSize = 1;
fieldNameSize_ = 0; fieldNameSize_ = 0;
} }
else { else {
totalSize = -1; totalSize = -1;
fieldNameSize_ = -1; fieldNameSize_ = -1;
if ( maxLen != -1 ) { if ( maxLen != -1 ) {
int size = (int) strnlen( fieldName(), maxLen - 1 ); int size = (int) strnlen( fieldName(), maxLen - 1 );
massert( 10333 , "Invalid field name", size != -1 ); uassert( 10333 , "Invalid field name", size != -1 );
fieldNameSize_ = size + 1; fieldNameSize_ = size + 1;
} }
} }
} }
explicit BSONElement(const char *d) : data(d) { explicit BSONElement(const char *d) : data(d) {
fieldNameSize_ = -1; fieldNameSize_ = -1;
totalSize = -1; totalSize = -1;
if ( eoo() ) { if ( eoo() ) {
fieldNameSize_ = 0; fieldNameSize_ = 0;
skipping to change at line 430 skipping to change at line 431
friend class BSONObjIterator; friend class BSONObjIterator;
friend class BSONObj; friend class BSONObj;
const BSONElement& chk(int t) const { const BSONElement& chk(int t) const {
if ( t != type() ) { if ( t != type() ) {
StringBuilder ss; StringBuilder ss;
if( eoo() ) if( eoo() )
ss << "field not found, expected type " << t; ss << "field not found, expected type " << t;
else else
ss << "wrong type for field (" << fieldName() << ") " < < type() << " != " << t; ss << "wrong type for field (" << fieldName() << ") " < < type() << " != " << t;
uasserted(13111, ss.str() ); msgasserted(13111, ss.str() );
} }
return *this; return *this;
} }
const BSONElement& chk(bool expr) const { const BSONElement& chk(bool expr) const {
uassert(13118, "unexpected or missing type value in BSON object ", expr); massert(13118, "unexpected or missing type value in BSON object ", expr);
return *this; return *this;
} }
}; };
inline int BSONElement::canonicalType() const { inline int BSONElement::canonicalType() const {
BSONType t = type(); BSONType t = type();
switch ( t ) { switch ( t ) {
case MinKey: case MinKey:
case MaxKey: case MaxKey:
return t; return t;
 End of changes. 6 change blocks. 
5 lines changed or deleted 6 lines changed or added


 bsonmisc.h   bsonmisc.h 
skipping to change at line 87 skipping to change at line 87
cout << BSON( GENOID << "z" << 3 ); // { _id : ..., z : 3 } cout << BSON( GENOID << "z" << 3 ); // { _id : ..., z : 3 }
*/ */
extern struct GENOIDLabeler { } GENOID; extern struct GENOIDLabeler { } GENOID;
/* Utility class to add a Date element with the current time /* Utility class to add a Date element with the current time
Example: Example:
cout << BSON( "created" << DATENOW ); // { created : "2009-10-09 1 1:41:42" } cout << BSON( "created" << DATENOW ); // { created : "2009-10-09 1 1:41:42" }
*/ */
extern struct DateNowLabeler { } DATENOW; extern struct DateNowLabeler { } DATENOW;
/* Utility class to assign a NULL value to a given attribute
Example:
cout << BSON( "a" << BSONNULL ); // { a : null }
*/
extern struct NullLabeler { } BSONNULL;
/* Utility class to add the minKey (minus infinity) to a given attribut e /* Utility class to add the minKey (minus infinity) to a given attribut e
Example: Example:
cout << BSON( "a" << MINKEY ); // { "a" : { "$minKey" : 1 } } cout << BSON( "a" << MINKEY ); // { "a" : { "$minKey" : 1 } }
*/ */
extern struct MinKeyLabeler { } MINKEY; extern struct MinKeyLabeler { } MINKEY;
extern struct MaxKeyLabeler { } MAXKEY; extern struct MaxKeyLabeler { } MAXKEY;
// Utility class to implement GT, GTE, etc as described above. // Utility class to implement GT, GTE, etc as described above.
class Labeler { class Labeler {
public: public:
skipping to change at line 145 skipping to change at line 151
friend class Labeler; friend class Labeler;
BSONObjBuilderValueStream( BSONObjBuilder * builder ); BSONObjBuilderValueStream( BSONObjBuilder * builder );
BSONObjBuilder& operator<<( const BSONElement& e ); BSONObjBuilder& operator<<( const BSONElement& e );
template<class T> template<class T>
BSONObjBuilder& operator<<( T value ); BSONObjBuilder& operator<<( T value );
BSONObjBuilder& operator<<(DateNowLabeler& id); BSONObjBuilder& operator<<(DateNowLabeler& id);
BSONObjBuilder& operator<<(NullLabeler& id);
BSONObjBuilder& operator<<(MinKeyLabeler& id); BSONObjBuilder& operator<<(MinKeyLabeler& id);
BSONObjBuilder& operator<<(MaxKeyLabeler& id); BSONObjBuilder& operator<<(MaxKeyLabeler& id);
Labeler operator<<( const Labeler::Label &l ); Labeler operator<<( const Labeler::Label &l );
void endField( const char *nextFieldName = 0 ); void endField( const char *nextFieldName = 0 );
bool subobjStarted() const { return _fieldName != 0; } bool subobjStarted() const { return _fieldName != 0; }
private: private:
const char * _fieldName; const char * _fieldName;
 End of changes. 2 change blocks. 
0 lines changed or deleted 8 lines changed or added


 bsonobj.h   bsonobj.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 <boost/noncopyable.hpp>
#include <boost/intrusive_ptr.hpp> #include <boost/intrusive_ptr.hpp>
#include <set> #include <set>
#include <list> #include <list>
#include <vector> #include <vector>
#include "util/atomic_int.h" #include "util/atomic_int.h"
#include "util/builder.h" #include "util/builder.h"
#include "stringdata.h" #include "stringdata.h"
namespace mongo { namespace mongo {
skipping to change at line 335 skipping to change at line 336
BSONElement firstElement() const { return BSONElement(objdata() + 4 ); } BSONElement firstElement() const { return BSONElement(objdata() + 4 ); }
/** faster than firstElement().fieldName() - for the first element we can easily find the fieldname without /** faster than firstElement().fieldName() - for the first element we can easily find the fieldname without
computing the element size. computing the element size.
*/ */
const char * firstElementFieldName() const { const char * firstElementFieldName() const {
const char *p = objdata() + 4; const char *p = objdata() + 4;
return *p == EOO ? "" : p+1; return *p == EOO ? "" : p+1;
} }
BSONType firstElementType() const {
const char *p = objdata() + 4;
return (BSONType) *p;
}
/** Get the _id field from the object. For good performance driver s should /** Get the _id field from the object. For good performance driver s 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) const; bool getObjectID(BSONElement& e) const;
/** @return A hash code for the object */ /** @return A hash code for the object */
int hash() const { int hash() const {
unsigned x = 0; unsigned x = 0;
 End of changes. 2 change blocks. 
0 lines changed or deleted 6 lines changed or added


 bsonobjbuilder.h   bsonobjbuilder.h 
skipping to change at line 28 skipping to change at line 28
* 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 <limits> #include <limits>
#include <cmath> #include <cmath>
#include <boost/static_assert.hpp> #include <boost/static_assert.hpp>
#if defined(MONGO_EXPOSE_MACROS)
// boost changed it
#undef assert
#define assert MONGO_assert
#endif
#include "bsonelement.h" #include "bsonelement.h"
#include "bsonobj.h" #include "bsonobj.h"
#include "bsonmisc.h" #include "bsonmisc.h"
#if defined(_DEBUG) && defined(MONGO_EXPOSE_MACROS)
#include "../util/log.h"
#endif
namespace mongo { namespace mongo {
using namespace std; using namespace std;
#if defined(_WIN32) #if defined(_WIN32)
// warning: 'this' : used in base member initializer list // warning: 'this' : used in base member initializer list
#pragma warning( disable : 4355 ) #pragma warning( disable : 4355 )
#endif #endif
skipping to change at line 635 skipping to change at line 643
_s.endField( f.name().c_str() ); _s.endField( f.name().c_str() );
return _s; return _s;
} }
template<typename T> template<typename T>
BSONObjBuilder& operator<<( const BSONFieldValue<T>& v ) { BSONObjBuilder& operator<<( const BSONFieldValue<T>& v ) {
append( v.name().c_str() , v.value() ); append( v.name().c_str() , v.value() );
return *this; return *this;
} }
BSONObjBuilder& operator<<( const BSONElement& e ){
append( e );
return *this;
}
/** @return true if we are using our own bufbuilder, and not an alt ernate that was given to us in our constructor */ /** @return true if we are using our own bufbuilder, and not an alt ernate that was given to us in our constructor */
bool owned() const { return &_b == &_buf; } bool owned() const { return &_b == &_buf; }
BSONObjIterator iterator() const ; BSONObjIterator iterator() const ;
bool hasField( const StringData& name ) const ; bool hasField( const StringData& name ) const ;
int len() const { return _b.len(); } int len() const { return _b.len(); }
BufBuilder& bb() { return _b; } BufBuilder& bb() { return _b; }
skipping to change at line 753 skipping to change at line 766
fill( name ); fill( name );
_b.appendArray( num(), subObj ); _b.appendArray( num(), subObj );
} }
void appendAs( const BSONElement &e, const char *name) { void appendAs( const BSONElement &e, const char *name) {
fill( name ); fill( name );
append( e ); append( e );
} }
int len() const { return _b.len(); } int len() const { return _b.len(); }
int arrSize() const { return _i; }
private: private:
// These two are undefined privates to prevent their accidental
// use as we don't support unsigned ints in BSON
BSONObjBuilder& append(const StringData& fieldName, unsigned int va
l);
BSONObjBuilder& append(const StringData& fieldName, unsigned long l
ong val);
void fill( const StringData& name ) { void fill( const StringData& name ) {
char *r; char *r;
long int n = strtol( name.data(), &r, 10 ); long int n = strtol( name.data(), &r, 10 );
if ( *r ) if ( *r )
uasserted( 13048, (string)"can't append to array using stri ng field name [" + name.data() + "]" ); uasserted( 13048, (string)"can't append to array using stri ng field name [" + name.data() + "]" );
fill(n); fill(n);
} }
void fill (int upTo){ void fill (int upTo){
// if this is changed make sure to update error message and jst ests/set7.js // if this is changed make sure to update error message and jst ests/set7.js
 End of changes. 5 change blocks. 
0 lines changed or deleted 21 lines changed or added


 bsontypes.h   bsontypes.h 
skipping to change at line 101 skipping to change at line 101
}; };
/* subtypes of BinData. /* subtypes of BinData.
bdtCustom and above are ones that the JS compiler understands, but a re bdtCustom and above are ones that the JS compiler understands, but a re
opaque to the database. opaque to the database.
*/ */
enum BinDataType { enum BinDataType {
BinDataGeneral=0, BinDataGeneral=0,
Function=1, Function=1,
ByteArrayDeprecated=2, /* use BinGeneral instead */ ByteArrayDeprecated=2, /* use BinGeneral instead */
bdtUUID = 3, bdtUUID = 3, /* deprecated */
newUUID=4, /* language-independent UUID format across all drivers */
MD5Type=5, MD5Type=5,
bdtCustom=128 bdtCustom=128
}; };
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 2 lines changed or added


 btree.h   btree.h 
skipping to change at line 206 skipping to change at line 206
}; };
public: public:
template< class V > template< class V >
const BtreeBucket<V> * btree() const { const BtreeBucket<V> * btree() const {
return DiskLoc(*this).btree<V>(); return DiskLoc(*this).btree<V>();
} }
template< class V > template< class V >
BtreeBucket<V> * btreemod() const { BtreeBucket<V> * btreemod() const {
return DiskLoc(*this).btreemod<V>(); return DiskLoc(*this).btreemod<V>();
} }
operator DiskLoc() const { operator const DiskLoc() const {
// endian // endian
if( isNull() ) return DiskLoc(); if( isNull() ) return DiskLoc();
unsigned a = *((unsigned *) (_a-1)); unsigned a = *((unsigned *) (_a-1));
return DiskLoc(a >> 8, ofs); return DiskLoc(a >> 8, ofs);
} }
int& GETOFS() { return ofs; } int& GETOFS() { return ofs; }
int getOfs() const { return ofs; } int getOfs() const { return ofs; }
bool operator<(const DiskLoc56Bit& rhs) const { bool operator<(const DiskLoc56Bit& rhs) const {
// the orderering of dup keys in btrees isn't too critical, but we'd like to put items that are // the orderering of dup keys in btrees isn't too critical, but we'd like to put items that are
// close together on disk close together in the tree, so we do want the file # to be the most significant // close together on disk close together in the tree, so we do want the file # to be the most significant
skipping to change at line 575 skipping to change at line 575
* - The bson 'key' must fit in the bucket without packing. * - The bson 'key' must fit in the bucket without packing.
* - If 'key' and 'prevChildBucket' are set at index i, the btree * - If 'key' and 'prevChildBucket' are set at index i, the btree
* ordering properties will be maintained. * ordering properties will be maintained.
* Postconditions: * Postconditions:
* - The specified key is set at index i, replacing the existing * - The specified key is set at index i, replacing the existing
* _KeyNode data and without shifting any other _KeyNode objects . * _KeyNode data and without shifting any other _KeyNode objects .
*/ */
void setKey( int i, const DiskLoc recordLoc, const Key& key, const DiskLoc prevChildBucket ); void setKey( int i, const DiskLoc recordLoc, const Key& key, const DiskLoc prevChildBucket );
}; };
template< class V>
struct Continuation;
/** /**
* This class adds functionality for manipulating buckets that are asse mbled * This class adds functionality for manipulating buckets that are asse mbled
* in a tree. The requirements for const and non const functions and * in a tree. The requirements for const and non const functions and
* arguments are generally the same as in BtreeBucket. Because this cl ass * arguments are generally the same as in BtreeBucket. Because this cl ass
* deals with tree structure, some functions that are marked const may * deals with tree structure, some functions that are marked const may
* trigger modification of another node in the btree or potentially of the * trigger modification of another node in the btree or potentially of the
* current node. In such cases, the function's implementation explicit ly * current node. In such cases, the function's implementation explicit ly
* casts away const when indicating an intent to write to the durabilit y * casts away const when indicating an intent to write to the durabilit y
* layer. The DiskLocs provided to such functions should be passed by * layer. The DiskLocs provided to such functions should be passed by
* value if they shadow pointers within the btree. * value if they shadow pointers within the btree.
skipping to change at line 606 skipping to change at line 609
* *
* TODO There are several cases in which the 'this' pointer is invalida ted * TODO There are several cases in which the 'this' pointer is invalida ted
* as a result of deallocation. A seperate class representing a btree would * as a result of deallocation. A seperate class representing a btree would
* alleviate some fragile cases where the implementation must currently * alleviate some fragile cases where the implementation must currently
* behave correctly if the 'this' pointer is suddenly invalidated by a * behave correctly if the 'this' pointer is suddenly invalidated by a
* callee. * callee.
*/ */
template< class V > template< class V >
class BtreeBucket : public BucketBasics<V> { class BtreeBucket : public BucketBasics<V> {
friend class BtreeCursor; friend class BtreeCursor;
friend struct Continuation<V>;
public: public:
// make compiler happy: // make compiler happy:
typedef typename V::Key Key; typedef typename V::Key Key;
typedef typename V::KeyOwned KeyOwned; typedef typename V::KeyOwned KeyOwned;
typedef typename BucketBasics<V>::KeyNode KeyNode; typedef typename BucketBasics<V>::KeyNode KeyNode;
typedef typename BucketBasics<V>::_KeyNode _KeyNode; typedef typename BucketBasics<V>::_KeyNode _KeyNode;
typedef typename BucketBasics<V>::Loc Loc; typedef typename BucketBasics<V>::Loc Loc;
const _KeyNode& k(int i) const { return static_cast< const Buck etBasics<V> * >(this)->k(i); } const _KeyNode& k(int i) const { return static_cast< const Buck etBasics<V> * >(this)->k(i); }
protected: protected:
_KeyNode& k(int i) { return static_cast< BucketBasi cs<V> * >(this)->_k(i); } _KeyNode& k(int i) { return static_cast< BucketBasi cs<V> * >(this)->_k(i); }
skipping to change at line 682 skipping to change at line 686
* - If key / recordLoc exist in the btree as a used key, @throw * - If key / recordLoc exist in the btree as a used key, @throw
* exception 10287 and no change. * exception 10287 and no change.
* - If key / recordLoc do not exist in the btree, they are insert ed * - If key / recordLoc do not exist in the btree, they are insert ed
* and @return 0. The root of the btree may be changed, so * and @return 0. The root of the btree may be changed, so
* 'this'/thisLoc may no longer be the root upon return. * 'this'/thisLoc may no longer be the root upon return.
*/ */
int bt_insert(const DiskLoc thisLoc, const DiskLoc recordLoc, int bt_insert(const DiskLoc thisLoc, const DiskLoc recordLoc,
const BSONObj& key, const Ordering &order, bool dupsA llowed, const BSONObj& key, const Ordering &order, bool dupsA llowed,
IndexDetails& idx, bool toplevel = true) const; IndexDetails& idx, bool toplevel = true) const;
/** does the insert in two steps - can then use an upgradable lock
for step 1, which
is the part which may have page faults. also that step is most
of the computational work.
*/
void twoStepInsert(DiskLoc thisLoc, Continuation<V> &c, bool dupsAl
lowed) const;
/** /**
* Preconditions: * Preconditions:
* - 'key' has a valid schema for this index, and may have objsize () > KeyMax. * - 'key' has a valid schema for this index, and may have objsize () > KeyMax.
* Postconditions: * Postconditions:
* - If key / recordLoc are in the btree, they are removed (possib ly * - If key / recordLoc are in the btree, they are removed (possib ly
* by being marked as an unused key), @return true, and potentia lly * by being marked as an unused key), @return true, and potentia lly
* invalidate 'this' / thisLoc and change the head. * invalidate 'this' / thisLoc and change the head.
* - If key / recordLoc are not in the btree, @return false and do nothing. * - If key / recordLoc are not in the btree, @return false and do nothing.
*/ */
bool unindex(const DiskLoc thisLoc, IndexDetails& id, const BSONObj & key, const DiskLoc recordLoc) const; bool unindex(const DiskLoc thisLoc, IndexDetails& id, const BSONObj & key, const DiskLoc recordLoc) const;
skipping to change at line 724 skipping to change at line 733
/** /**
* Advance to next or previous key in the index. * Advance to next or previous key in the index.
* @param direction to advance. * @param direction to advance.
*/ */
DiskLoc advance(const DiskLoc& thisLoc, int& keyOfs, int direction, const char *caller) const; DiskLoc advance(const DiskLoc& thisLoc, int& keyOfs, int direction, const char *caller) const;
/** Advance in specified direction to the specified key */ /** Advance in specified direction to the specified key */
void advanceTo(DiskLoc &thisLoc, int &keyOfs, const BSONObj &keyBeg in, int keyBeginLen, bool afterKey, const vector< const BSONElement * > &ke yEnd, const vector< bool > &keyEndInclusive, const Ordering &order, int dir ection ) const; void advanceTo(DiskLoc &thisLoc, int &keyOfs, const BSONObj &keyBeg in, int keyBeginLen, bool afterKey, const vector< const BSONElement * > &ke yEnd, const vector< bool > &keyEndInclusive, const Ordering &order, int dir ection ) const;
/** Locate a key with fields comprised of a combination of keyBegin fields and keyEnd fields. */ /** Locate a key with fields comprised of a combination of keyBegin fields and keyEnd fields. */
void customLocate(DiskLoc &thisLoc, int &keyOfs, const BSONObj &key Begin, int keyBeginLen, bool afterKey, const vector< const BSONElement * > &keyEnd, const vector< bool > &keyEndInclusive, const Ordering &order, int direction, pair< DiskLoc, int > &bestParent ) const; static void customLocate(DiskLoc &locInOut, int &keyOfs, const BSON Obj &keyBegin, int keyBeginLen, bool afterKey, const vector< const BSONElem ent * > &keyEnd, const vector< bool > &keyEndInclusive, const Ordering &ord er, int direction, pair< DiskLoc, int > &bestParent ) ;
/** @return head of the btree by traversing from current bucket. */ /** @return head of the btree by traversing from current bucket. */
const DiskLoc getHead(const DiskLoc& thisLoc) const; const DiskLoc getHead(const DiskLoc& thisLoc) const;
/** get tree shape */ /** get tree shape */
void shape(stringstream&) const; void shape(stringstream&) const;
static void a_test(IndexDetails&); static void a_test(IndexDetails&);
static int getKeyMax(); static int getKeyMax();
skipping to change at line 893 skipping to change at line 902
public: public:
Key keyAt(int i) const { Key keyAt(int i) const {
if( i >= this->n ) if( i >= this->n )
return Key(); return Key();
return Key(this->data + k(i).keyDataOfs()); return Key(this->data + k(i).keyDataOfs());
} }
protected: protected:
/** /**
* Allocate a temporary btree bucket in ram rather than in memory m
apped
* storage. The caller must release this bucket with free().
*/
static BtreeBucket<V> * allocTemp();
/**
* Preconditions: * Preconditions:
* - This bucket is packed. * - This bucket is packed.
* - Cannot add a key of size KeyMax to this bucket. * - Cannot add a key of size KeyMax to this bucket.
* - 0 <= keypos <= n is the position of a new key that will be in serted * - 0 <= keypos <= n is the position of a new key that will be in serted
* - lchild is equal to the existing child at index keypos. * - lchild is equal to the existing child at index keypos.
* Postconditions: * Postconditions:
* - The thisLoc bucket is split into two packed buckets, possibly * - The thisLoc bucket is split into two packed buckets, possibly
* invalidating the initial position of keypos, with a split key * invalidating the initial position of keypos, with a split key
* promoted to the parent. The new key key/recordLoc will be in serted * promoted to the parent. The new key key/recordLoc will be in serted
* into one of the split buckets, and lchild/rchild set appropri ately. * into one of the split buckets, and lchild/rchild set appropri ately.
skipping to change at line 929 skipping to change at line 932
* lchild and rchild, the btree ordering requirements will be * lchild and rchild, the btree ordering requirements will be
* maintained. * maintained.
* - lchild is equal to the existing child at index keypos. * - lchild is equal to the existing child at index keypos.
* - n == 0 is ok. * - n == 0 is ok.
* Postconditions: * Postconditions:
* - The key / recordLoc are inserted at position keypos, and the * - The key / recordLoc are inserted at position keypos, and the
* bucket is split if necessary, which may change the tree head. * bucket is split if necessary, which may change the tree head.
* - The bucket may be packed or split, invalidating the specified value * - The bucket may be packed or split, invalidating the specified value
* of keypos. * of keypos.
* This function will always modify thisLoc, but it's marked const because * This function will always modify thisLoc, but it's marked const because
* it commonly relies on the specialized write intent mechanism of basicInsert(). * it commonly relies on the specialized writ]e intent mechanism of basicInsert().
*/ */
void insertHere(const DiskLoc thisLoc, int keypos, void insertHere(const DiskLoc thisLoc, int keypos,
const DiskLoc recordLoc, const Key& key, const Orde ring &order, const DiskLoc recordLoc, const Key& key, const Orde ring &order,
const DiskLoc lchild, const DiskLoc rchild, IndexDe tails &idx) const; const DiskLoc lchild, const DiskLoc rchild, IndexDe tails &idx) const;
/** bt_insert() is basically just a wrapper around this. */ /** bt_insert() is basically just a wrapper around this. */
int _insert(const DiskLoc thisLoc, const DiskLoc recordLoc, int _insert(const DiskLoc thisLoc, const DiskLoc recordLoc,
const Key& key, const Ordering &order, bool dupsAllowed , const Key& key, const Ordering &order, bool dupsAllowed ,
const DiskLoc lChild, const DiskLoc rChild, IndexDetail s &idx) const; const DiskLoc lChild, const DiskLoc rChild, IndexDetail s &idx) const;
void insertStepOne(DiskLoc thisLoc, Continuation<V>& c, bool dupsAl
lowed) const;
bool find(const IndexDetails& idx, const Key& key, const DiskLoc &r ecordLoc, const Ordering &order, int& pos, bool assertIfDup) const; bool find(const IndexDetails& idx, const Key& key, const DiskLoc &r ecordLoc, const Ordering &order, int& pos, bool assertIfDup) const;
bool customFind( int l, int h, const BSONObj &keyBegin, int keyBegi nLen, bool afterKey, const vector< const BSONElement * > &keyEnd, const vec tor< bool > &keyEndInclusive, const Ordering &order, int direction, DiskLoc &thisLoc, int &keyOfs, pair< DiskLoc, int > &bestParent ) const; static bool customFind( int l, int h, const BSONObj &keyBegin, int keyBeginLen, bool afterKey, const vector< const BSONElement * > &keyEnd, co nst vector< bool > &keyEndInclusive, const Ordering &order, int direction, DiskLoc &thisLoc, int &keyOfs, pair< DiskLoc, int > &bestParent ) ;
static void findLargestKey(const DiskLoc& thisLoc, DiskLoc& largest Loc, int& largestKey); static void findLargestKey(const DiskLoc& thisLoc, DiskLoc& largest Loc, int& largestKey);
static int customBSONCmp( const BSONObj &l, const BSONObj &rBegin, int rBeginLen, bool rSup, const vector< const BSONElement * > &rEnd, const vector< bool > &rEndInclusive, const Ordering &o, int direction ); static int customBSONCmp( const BSONObj &l, const BSONObj &rBegin, int rBeginLen, bool rSup, const vector< const BSONElement * > &rEnd, const vector< bool > &rEndInclusive, const Ordering &o, int direction );
/** If child is non null, set its parent to thisLoc */ /** If child is non null, set its parent to thisLoc */
static void fix(const DiskLoc thisLoc, const DiskLoc child); static void fix(const DiskLoc thisLoc, const DiskLoc child);
/** /**
* Preconditions: * Preconditions:
* - 0 <= keypos < n * - 0 <= keypos < n
* - If the specified key and recordLoc are placed in keypos of th isLoc, * - If the specified key and recordLoc are placed in keypos of th isLoc,
skipping to change at line 996 skipping to change at line 1001
class FieldRangeVector; class FieldRangeVector;
class FieldRangeVectorIterator; class FieldRangeVectorIterator;
class BtreeCursor : public Cursor { class BtreeCursor : public Cursor {
protected: protected:
BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int direction ); BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int direction );
BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails& _id, const shared_ptr< FieldRangeVector > &_bounds, int _direction ); BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails& _id, const shared_ptr< FieldRangeVector > &_bounds, int _direction );
public: public:
virtual ~BtreeCursor(); virtual ~BtreeCursor();
/** makes an appropriate subclass depending on the index version */ /** makes an appropriate subclass depending on the index version */
static BtreeCursor* make( NamespaceDetails *_d, const IndexDetails&
, const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int
direction );
static BtreeCursor* make( NamespaceDetails *_d, const IndexDetails&
_id, const shared_ptr< FieldRangeVector > &_bounds, int _direction );
static BtreeCursor* make( NamespaceDetails *_d, int _idxNo, const I ndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyIn clusive, int direction ); static BtreeCursor* make( NamespaceDetails *_d, int _idxNo, const I ndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyIn clusive, int direction );
static BtreeCursor* make( NamespaceDetails *_d, int _idxNo, const I ndexDetails& _id, const shared_ptr< FieldRangeVector > &_bounds, int _direc tion ); static BtreeCursor* make( NamespaceDetails *_d, int _idxNo, const I ndexDetails& _id, const shared_ptr< FieldRangeVector > &_bounds, int _direc tion );
virtual bool ok() { return !bucket.isNull(); } virtual bool ok() { return !bucket.isNull(); }
virtual bool advance(); virtual bool advance();
virtual void noteLocation(); // updates keyAtKeyOfs... virtual void noteLocation(); // updates keyAtKeyOfs...
virtual void checkLocation() = 0; virtual void checkLocation() = 0;
virtual bool supportGetMore() { return true; } virtual bool supportGetMore() { return true; }
virtual bool supportYields() { return true; } virtual bool supportYields() { return true; }
skipping to change at line 1054 skipping to change at line 1061
virtual Record* _current() { return currLoc().rec(); } virtual Record* _current() { return currLoc().rec(); }
virtual BSONObj current() { return BSONObj(_current()); } virtual BSONObj current() { return BSONObj(_current()); }
virtual string toString(); virtual string toString();
BSONObj prettyKey( const BSONObj &key ) const { BSONObj prettyKey( const BSONObj &key ) const {
return key.replaceFieldNames( indexDetails.keyPattern() ).clien tReadable(); return key.replaceFieldNames( indexDetails.keyPattern() ).clien tReadable();
} }
virtual BSONObj prettyIndexBounds() const; virtual BSONObj prettyIndexBounds() const;
void forgetEndKey() { endKey = BSONObj(); }
virtual CoveredIndexMatcher *matcher() const { return _matcher.get( ); } virtual CoveredIndexMatcher *matcher() const { return _matcher.get( ); }
virtual shared_ptr< CoveredIndexMatcher > matcherPtr() const { retu rn _matcher; } virtual shared_ptr< CoveredIndexMatcher > matcherPtr() const { retu rn _matcher; }
virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) { _matcher = matcher; } virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) { _matcher = matcher; }
virtual long long nscanned() { return _nscanned; } virtual long long nscanned() { return _nscanned; }
/** for debugging only */ /** for debugging only */
const DiskLoc getBucket() const { return bucket; } const DiskLoc getBucket() const { return bucket; }
int getKeyOfs() const { return keyOfs; }
// just for unit tests // just for unit tests
virtual bool curKeyHasChild() = 0; virtual bool curKeyHasChild() = 0;
protected: protected:
/** /**
* Our btrees may (rarely) have "unused" keys when items are delete d. * Our btrees may (rarely) have "unused" keys when items are delete d.
* Skip past them. * Skip past them.
*/ */
virtual bool skipUnusedKeys() = 0; virtual bool skipUnusedKeys() = 0;
skipping to change at line 1089 skipping to change at line 1095
/** selective audits on construction */ /** selective audits on construction */
void audit(); void audit();
virtual void _audit() = 0; virtual void _audit() = 0;
virtual DiskLoc _locate(const BSONObj& key, const DiskLoc& loc) = 0 ; virtual DiskLoc _locate(const BSONObj& key, const DiskLoc& loc) = 0 ;
virtual DiskLoc _advance(const DiskLoc& thisLoc, int& keyOfs, int d irection, const char *caller) = 0; virtual DiskLoc _advance(const DiskLoc& thisLoc, int& keyOfs, int d irection, const char *caller) = 0;
virtual void _advanceTo(DiskLoc &thisLoc, int &keyOfs, const BSONOb j &keyBegin, int keyBeginLen, bool afterKey, const vector< const BSONElemen t * > &keyEnd, const vector< bool > &keyEndInclusive, const Ordering &order , int direction ) = 0; virtual void _advanceTo(DiskLoc &thisLoc, int &keyOfs, const BSONOb j &keyBegin, int keyBeginLen, bool afterKey, const vector< const BSONElemen t * > &keyEnd, const vector< bool > &keyEndInclusive, const Ordering &order , int direction ) = 0;
/** set initial bucket */ /** set initial bucket */
void init(); void initWithoutIndependentFieldRanges();
/** if afterKey is true, we want the first key with values of the k eyBegin fields greater than keyBegin */ /** if afterKey is true, we want the first key with values of the k eyBegin fields greater than keyBegin */
void advanceTo( const BSONObj &keyBegin, int keyBeginLen, bool afte rKey, const vector< const BSONElement * > &keyEnd, const vector< bool > &ke yEndInclusive ); void advanceTo( const BSONObj &keyBegin, int keyBeginLen, bool afte rKey, const vector< const BSONElement * > &keyEnd, const vector< bool > &ke yEndInclusive );
set<DiskLoc> _dups; set<DiskLoc> _dups;
NamespaceDetails * const d; NamespaceDetails * const d;
const int idxNo; const int idxNo;
BSONObj startKey; BSONObj startKey;
BSONObj endKey; BSONObj endKey;
bool _endKeyInclusive; bool _endKeyInclusive;
skipping to change at line 1111 skipping to change at line 1117
const IndexDetails& indexDetails; const IndexDetails& indexDetails;
const BSONObj _order; const BSONObj _order;
const Ordering _ordering; const Ordering _ordering;
DiskLoc bucket; DiskLoc bucket;
int keyOfs; int keyOfs;
const int _direction; // 1=fwd,-1=reverse const int _direction; // 1=fwd,-1=reverse
BSONObj keyAtKeyOfs; // so we can tell if things moved around on us between the query and the getMore call BSONObj keyAtKeyOfs; // so we can tell if things moved around on us between the query and the getMore call
DiskLoc locAtKeyOfs; DiskLoc locAtKeyOfs;
const shared_ptr< FieldRangeVector > _bounds; const shared_ptr< FieldRangeVector > _bounds;
auto_ptr< FieldRangeVectorIterator > _boundsIterator; auto_ptr< FieldRangeVectorIterator > _boundsIterator;
const IndexSpec& _spec;
shared_ptr< CoveredIndexMatcher > _matcher; shared_ptr< CoveredIndexMatcher > _matcher;
bool _independentFieldRanges; bool _independentFieldRanges;
long long _nscanned; long long _nscanned;
}; };
template< class V >
struct Continuation {
//Continuation(const typename V::Key & k);
Continuation(DiskLoc thisLoc, DiskLoc _recordLoc, const BSONObj &_k
ey,
Ordering _order, IndexDetails& _idx) :
bLoc(thisLoc), recordLoc(_recordLoc), key(_key), order(_order),
idx(_idx) {
op = Nothing;
}
DiskLoc bLoc;
DiskLoc recordLoc;
typename V::KeyOwned key;
const Ordering order;
IndexDetails& idx;
enum Op { Nothing, SetUsed, InsertHere } op;
int pos;
const BtreeBucket<V> *b;
void stepTwo() {
if( op == Nothing )
return;
else if( op == SetUsed ) {
const typename V::_KeyNode& kn = b->k(pos);
kn.writing().setUsed();
}
else {
b->insertHere(bLoc, pos, recordLoc, key, order, DiskLoc(),
DiskLoc(), idx);
}
}
};
/** Renames the index namespace for this btree's index. */ /** Renames the index namespace for this btree's index. */
void renameIndexNamespace(const char *oldNs, const char *newNs); void renameIndexNamespace(const char *oldNs, const char *newNs);
/** /**
* give us a writable version of the btree bucket (declares write inten t). * give us a writable version of the btree bucket (declares write inten t).
* note it is likely more efficient to declare write intent on somethin g smaller when you can. * note it is likely more efficient to declare write intent on somethin g smaller when you can.
*/ */
template< class V > template< class V >
BtreeBucket<V> * DiskLoc::btreemod() const { BtreeBucket<V> * DiskLoc::btreemod() const {
assert( _a != -1 ); assert( _a != -1 );
 End of changes. 15 change blocks. 
15 lines changed or deleted 61 lines changed or added


 bufreader.h   bufreader.h 
skipping to change at line 32 skipping to change at line 32
/** helper to read and parse a block of memory /** helper to read and parse a block of memory
methods throw the eof exception if the operation would pass the end of the methods throw the eof exception if the operation would pass the end of the
buffer with which we are working. buffer with which we are working.
*/ */
class BufReader : boost::noncopyable { class BufReader : boost::noncopyable {
public: public:
class eof : public std::exception { class eof : public std::exception {
public: public:
eof() { } eof() { }
virtual const char * what() { return "BufReader eof"; } virtual const char * what() const throw() { return "BufReader e of"; }
}; };
BufReader(const void *p, unsigned len) : _start(p), _pos(p), _end(( (char *)_pos)+len) { } BufReader(const void *p, unsigned len) : _start(p), _pos(p), _end(( (char *)_pos)+len) { }
bool atEof() const { return _pos == _end; } bool atEof() const { return _pos == _end; }
/** read in the object specified, and advance buffer pointer */ /** read in the object specified, and advance buffer pointer */
template <typename T> template <typename T>
void read(T &t) { void read(T &t) {
T* cur = (T*) _pos; T* cur = (T*) _pos;
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 builder.h   builder.h 
skipping to change at line 22 skipping to change at line 22
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include <cfloat> #include <cfloat>
#include <string> #include <string>
#include <sstream>
#include <iostream>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include "../inline_decls.h" #include "../inline_decls.h"
#include "../stringdata.h" #include "../stringdata.h"
namespace mongo { namespace mongo {
/* Note the limit here is rather arbitrary and is simply a standard. ge nerally the code works /* Note the limit here is rather arbitrary and is simply a standard. ge nerally the code works
with any object that fits in ram. with any object that fits in ram.
skipping to change at line 201 skipping to change at line 203
l += by; l += by;
if ( l > size ) { if ( l > size ) {
grow_reallocate(); grow_reallocate();
} }
return data + oldlen; return data + oldlen;
} }
private: private:
/* "slow" portion of 'grow()' */ /* "slow" portion of 'grow()' */
void NOINLINE_DECL grow_reallocate() { void NOINLINE_DECL grow_reallocate() {
int a = size * 2; int a = 64;
if ( a == 0 ) while( a < l )
a = 512; a = a * 2;
if ( l > a ) if ( a > BufferMaxSize ) {
a = l + 16 * 1024; std::stringstream ss;
if ( a > BufferMaxSize ) ss << "BufBuilder attempted to grow() to " << a << " bytes,
msgasserted(13548, "BufBuilder grow() > 64MB"); past the 64MB limit.";
msgasserted(13548, ss.str().c_str());
}
data = (char *) al.Realloc(data, a); data = (char *) al.Realloc(data, a);
size= a; size= a;
} }
char *data; char *data;
int l; int l;
int size; int size;
friend class StringBuilder; friend class StringBuilder;
}; };
skipping to change at line 252 skipping to change at line 255
/** stringstream deals with locale so this is a lot faster than std::st ringstream for UTF8 */ /** stringstream deals with locale so this is a lot faster than std::st ringstream for UTF8 */
class StringBuilder { class StringBuilder {
public: public:
static const size_t MONGO_DBL_SIZE = 3 + DBL_MANT_DIG - DBL_MIN_EXP ; static const size_t MONGO_DBL_SIZE = 3 + DBL_MANT_DIG - DBL_MIN_EXP ;
static const size_t MONGO_S32_SIZE = 12; static const size_t MONGO_S32_SIZE = 12;
static const size_t MONGO_U32_SIZE = 11; static const size_t MONGO_U32_SIZE = 11;
static const size_t MONGO_S64_SIZE = 23; static const size_t MONGO_S64_SIZE = 23;
static const size_t MONGO_U64_SIZE = 22; static const size_t MONGO_U64_SIZE = 22;
static const size_t MONGO_S16_SIZE = 7; static const size_t MONGO_S16_SIZE = 7;
StringBuilder( int initsize=256 ) StringBuilder() { }
: _buf( initsize ) {
}
StringBuilder& operator<<( double x ) { StringBuilder& operator<<( double x ) {
return SBNUM( x , MONGO_DBL_SIZE , "%g" ); return SBNUM( x , MONGO_DBL_SIZE , "%g" );
} }
StringBuilder& operator<<( int x ) { StringBuilder& operator<<( int x ) {
return SBNUM( x , MONGO_S32_SIZE , "%d" ); return SBNUM( x , MONGO_S32_SIZE , "%d" );
} }
StringBuilder& operator<<( unsigned x ) { StringBuilder& operator<<( unsigned x ) {
return SBNUM( x , MONGO_U32_SIZE , "%u" ); return SBNUM( x , MONGO_U32_SIZE , "%u" );
} }
skipping to change at line 314 skipping to change at line 315
return *this; return *this;
} }
void reset( int maxSize = 0 ) { _buf.reset( maxSize ); } void reset( int maxSize = 0 ) { _buf.reset( maxSize ); }
std::string str() const { return std::string(_buf.data, _buf.l); } std::string str() const { return std::string(_buf.data, _buf.l); }
int len() const { return _buf.l; } int len() const { return _buf.l; }
private: private:
BufBuilder _buf; StackBufBuilder _buf;
// non-copyable, non-assignable // non-copyable, non-assignable
StringBuilder( const StringBuilder& ); StringBuilder( const StringBuilder& );
StringBuilder& operator=( const StringBuilder& ); StringBuilder& operator=( const StringBuilder& );
template <typename T> template <typename T>
StringBuilder& SBNUM(T val,int maxSize,const char *macro) { StringBuilder& SBNUM(T val,int maxSize,const char *macro) {
int prev = _buf.l; int prev = _buf.l;
int z = mongo_snprintf( _buf.grow(maxSize) , maxSize , macro , (val) ); int z = mongo_snprintf( _buf.grow(maxSize) , maxSize , macro , (val) );
assert( z >= 0 ); assert( z >= 0 );
 End of changes. 4 change blocks. 
11 lines changed or deleted 13 lines changed or added


 chunk.h   chunk.h 
skipping to change at line 37 skipping to change at line 37
#include "shardkey.h" #include "shardkey.h"
#include "shard.h" #include "shard.h"
#include "util.h" #include "util.h"
namespace mongo { namespace mongo {
class DBConfig; class DBConfig;
class Chunk; class Chunk;
class ChunkRange; class ChunkRange;
class ChunkManager; class ChunkManager;
class ChunkRangeMangager;
class ChunkObjUnitTest; class ChunkObjUnitTest;
typedef shared_ptr<const Chunk> ChunkPtr; typedef shared_ptr<const Chunk> ChunkPtr;
// key is max for each Chunk or ChunkRange // key is max for each Chunk or ChunkRange
typedef map<BSONObj,ChunkPtr,BSONObjCmp> ChunkMap; typedef map<BSONObj,ChunkPtr,BSONObjCmp> ChunkMap;
typedef map<BSONObj,shared_ptr<ChunkRange>,BSONObjCmp> ChunkRangeMap; typedef map<BSONObj,shared_ptr<ChunkRange>,BSONObjCmp> ChunkRangeMap;
typedef shared_ptr<const ChunkManager> ChunkManagerPtr; typedef shared_ptr<const ChunkManager> ChunkManagerPtr;
skipping to change at line 156 skipping to change at line 155
* @return true if move was successful * @return true if move was successful
*/ */
bool moveAndCommit( const Shard& to , long long chunkSize , BSONObj & res ) const; bool moveAndCommit( const Shard& to , long long chunkSize , BSONObj & res ) const;
/** /**
* @return size of shard in bytes * @return size of shard in bytes
* talks to mongod to do this * talks to mongod to do this
*/ */
long getPhysicalSize() const; long getPhysicalSize() const;
/**
* marks this chunk as a jumbo chunk
* that means the chunk will be inelligble for migrates
*/
void markAsJumbo() const;
bool isJumbo() const { return _jumbo; }
/**
* Attempt to refresh maximum chunk size from config.
*/
static void refreshChunkSize();
// //
// public constants // public constants
// //
static string chunkMetadataNS; static string chunkMetadataNS;
static int MaxChunkSize; static int MaxChunkSize;
static int MaxObjectPerChunk; static int MaxObjectPerChunk;
static bool ShouldAutoSplit;
// //
// accessors and helpers // accessors and helpers
// //
string toString() const; string toString() const;
friend ostream& operator << (ostream& out, const Chunk& c) { return (out << c.toString()); } friend ostream& operator << (ostream& out, const Chunk& c) { return (out << c.toString()); }
bool operator==(const Chunk& s) const; bool operator==(const Chunk& s) const;
bool operator!=(const Chunk& s) const { return ! ( *this == s ); } bool operator!=(const Chunk& s) const { return ! ( *this == s ); }
skipping to change at line 190 skipping to change at line 200
private: private:
// main shard info // main shard info
const ChunkManager * _manager; const ChunkManager * _manager;
BSONObj _min; BSONObj _min;
BSONObj _max; BSONObj _max;
Shard _shard; Shard _shard;
ShardChunkVersion _lastmod; ShardChunkVersion _lastmod;
mutable bool _jumbo;
// transient stuff // transient stuff
mutable long _dataWritten; mutable long _dataWritten;
// methods, etc.. // methods, etc..
/** /**
* if sort 1, return lowest key * if sort 1, return lowest key
* if sort -1, return highest key * if sort -1, return highest key
skipping to change at line 225 skipping to change at line 236
const BSONObj& getMin() const { return _min; } const BSONObj& getMin() const { return _min; }
const BSONObj& getMax() const { return _max; } const BSONObj& getMax() const { return _max; }
// clones of Chunk methods // clones of Chunk methods
bool contains(const BSONObj& obj) const; bool contains(const BSONObj& obj) const;
ChunkRange(ChunkMap::const_iterator begin, const ChunkMap::const_it erator end) ChunkRange(ChunkMap::const_iterator begin, const ChunkMap::const_it erator end)
: _manager(begin->second->getManager()) : _manager(begin->second->getManager())
, _shard(begin->second->getShard()) , _shard(begin->second->getShard())
, _min(begin->second->getMin()) , _min(begin->second->getMin())
, _max(prior(end)->second->getMax()) { , _max(boost::prior(end)->second->getMax()) {
assert( begin != end ); assert( begin != end );
DEV while (begin != end) { DEV while (begin != end) {
assert(begin->second->getManager() == _manager); assert(begin->second->getManager() == _manager);
assert(begin->second->getShard() == _shard); assert(begin->second->getShard() == _shard);
++begin; ++begin;
} }
} }
// Merge min and max (must be adjacent ranges) // Merge min and max (must be adjacent ranges)
skipping to change at line 295 skipping to change at line 306
public: public:
typedef map<Shard,ShardChunkVersion> ShardVersionMap; typedef map<Shard,ShardChunkVersion> ShardVersionMap;
ChunkManager( string ns , ShardKeyPattern pattern , bool unique ); ChunkManager( string ns , ShardKeyPattern pattern , bool unique );
string getns() const { return _ns; } string getns() const { return _ns; }
int numChunks() const { return _chunkMap.size(); } int numChunks() const { return _chunkMap.size(); }
bool hasShardKey( const BSONObj& obj ) const; bool hasShardKey( const BSONObj& obj ) const;
void createFirstChunks( const Shard& shard ) const; // only call fr om DBConfig::shardCollection void createFirstChunks( const Shard& primary , vector<BSONObj>* ini tPoints , vector<Shard>* initShards ) const; // only call from DBConfig::sh ardCollection
ChunkPtr findChunk( const BSONObj& obj ) const; ChunkPtr findChunk( const BSONObj& obj ) const;
ChunkPtr findChunkOnServer( const Shard& shard ) const; ChunkPtr findChunkOnServer( const Shard& shard ) const;
const ShardKeyPattern& getShardKey() const { return _key; } const ShardKeyPattern& getShardKey() const { return _key; }
bool isUnique() const { return _unique; } bool isUnique() const { return _unique; }
void getShardsForQuery( set<Shard>& shards , const BSONObj& query ) const; void getShardsForQuery( set<Shard>& shards , const BSONObj& query ) const;
void getAllShards( set<Shard>& all ) const; void getAllShards( set<Shard>& all ) const;
void getShardsForRange(set<Shard>& shards, const BSONObj& min, cons t BSONObj& max, bool fullKeyReq = true) const; // [min, max) void getShardsForRange(set<Shard>& shards, const BSONObj& min, cons t BSONObj& max, bool fullKeyReq = true) const; // [min, max)
ChunkMap getChunkMap() const { return _chunkMap; }
/**
* Returns true if, for this shard, the chunks are identical in bot
h chunk managers
*/
bool compatibleWith( const ChunkManager& other, const Shard& shard
) const;
bool compatibleWith( ChunkManagerPtr other, const Shard& shard ) co
nst { if( ! other ) return false; return compatibleWith( *other, shard ); }
bool compatibleWith( const Chunk& other ) const;
bool compatibleWith( ChunkPtr other ) const { if( ! other ) return
false; return compatibleWith( *other ); }
string toString() const; string toString() const;
ShardChunkVersion getVersion( const Shard& shard ) const; ShardChunkVersion getVersion( const Shard& shard ) const;
ShardChunkVersion getVersion() const; ShardChunkVersion getVersion() const;
/** /**
* this is just an increasing number of how many ChunkManagers we h ave so we know if something has been updated * this is just an increasing number of how many ChunkManagers we h ave so we know if something has been updated
*/ */
unsigned long long getSequenceNumber() const { return _sequenceNumb er; } unsigned long long getSequenceNumber() const { return _sequenceNumb er; }
 End of changes. 7 change blocks. 
5 lines changed or deleted 31 lines changed or added


 client.h   client.h 
// client.h // @file s/client.h
/* /*
* Copyright (C) 2010 10gen Inc. * Copyright (C) 2010 10gen Inc.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3, * it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation. * as published by the Free Software Foundation.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* 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 Lice nse * You should have received a copy of the GNU Affero General Public Lice nse
* 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
#include "../pch.h" #include "../pch.h"
#include "chunk.h"
#include "writeback_listener.h" #include "writeback_listener.h"
#include "../db/security.h" #include "../db/security.h"
#include "../db/client_common.h"
namespace mongo { namespace mongo {
/** /**
* holds information about a client connected to a mongos * holds information about a client connected to a mongos
* 1 per client socket * 1 per client socket
* currently implemented with a thread local * currently implemented with a thread local
*/ */
class ClientInfo { class ClientInfo : public ClientBasic {
public: public:
ClientInfo(); ClientInfo();
~ClientInfo(); ~ClientInfo();
/** new request from client, adjusts internal state */ /** new request from client, adjusts internal state */
void newRequest( AbstractMessagingPort* p = 0 ); void newRequest( AbstractMessagingPort* p = 0 );
/** client disconnected */ /** client disconnected */
void disconnect(); void disconnect();
bool hasRemote() const { return true; }
/** /**
* @return remote socket address of the client * @return remote socket address of the client
*/ */
HostAndPort getRemote() const { return _remote; } HostAndPort getRemote() const { return _remote; }
/** /**
* notes that this client use this shard * notes that this client use this shard
* keeps track of all shards accessed this request * keeps track of all shards accessed this request
*/ */
void addShard( const string& shard ); void addShard( const string& shard );
skipping to change at line 81 skipping to change at line 84
void clearCurrentShards(){ _cur->clear(); } void clearCurrentShards(){ _cur->clear(); }
/** /**
* calls getLastError * calls getLastError
* resets shards since get last error * resets shards since get last error
* @return if the command was ok or if there was an error * @return if the command was ok or if there was an error
*/ */
bool getLastError( const BSONObj& options , BSONObjBuilder& result , bool fromWriteBackListener = false ); bool getLastError( const BSONObj& options , BSONObjBuilder& result , bool fromWriteBackListener = false );
/** @return if its ok to auto split from this client */ /** @return if its ok to auto split from this client */
bool autoSplitOk() const { return _autoSplitOk && Chunk::ShouldAuto Split; } bool autoSplitOk() const { return _autoSplitOk; }
void noAutoSplit() { _autoSplitOk = false; } void noAutoSplit() { _autoSplitOk = false; }
static ClientInfo * get(); static ClientInfo * get();
AuthenticationInfo* getAuthenticationInfo() const { return (Authent const AuthenticationInfo* getAuthenticationInfo() const { return (A
icationInfo*)&_ai; } uthenticationInfo*)&_ai; }
AuthenticationInfo* getAuthenticationInfo() { return (Authenticatio
nInfo*)&_ai; }
bool isAdmin() { return _ai.isAuthorized( "admin" ); } bool isAdmin() { return _ai.isAuthorized( "admin" ); }
private: private:
AuthenticationInfo _ai; AuthenticationInfo _ai;
struct WBInfo { struct WBInfo {
WBInfo( const WriteBackListener::ConnectionIdent& c , OID o ) : ident( c ) , id( o ) {} WBInfo( const WriteBackListener::ConnectionIdent& c , OID o ) : ident( c ) , id( o ) {}
WriteBackListener::ConnectionIdent ident; WriteBackListener::ConnectionIdent ident;
OID id; OID id;
}; };
// for getLastError // for getLastError
 End of changes. 8 change blocks. 
6 lines changed or deleted 11 lines changed or added


 clientcursor.h   clientcursor.h 
skipping to change at line 117 skipping to change at line 117
if( _c ) { if( _c ) {
if( _c->_pinValue >= 100 ) { if( _c->_pinValue >= 100 ) {
_c = 0; _c = 0;
uasserted(12051, "clientcursor already in use? driv er problem?"); uasserted(12051, "clientcursor already in use? driv er problem?");
} }
_c->_pinValue += 100; _c->_pinValue += 100;
} }
} }
}; };
// This object assures safe and reliable cleanup of the ClientCurso // This object assures safe and reliable cleanup of a ClientCursor.
r.
// The implementation assumes that there will be no duplicate ids a
mong cursors
// (which is assured if cursors must last longer than 1 second).
class CleanupPointer : boost::noncopyable { class CleanupPointer : boost::noncopyable {
public: public:
CleanupPointer() : _c( 0 ), _id( -1 ) {} CleanupPointer() : _c( 0 ), _id( -1 ) {}
void reset( ClientCursor *c = 0 ) { void reset( ClientCursor *c = 0 ) {
if ( c == _c ) if ( c == _c )
return; return;
if ( _c ) { if ( _c ) {
// be careful in case cursor was deleted by someone els e // be careful in case cursor was deleted by someone els e
ClientCursor::erase( _id ); ClientCursor::erase( _id );
} }
skipping to change at line 149 skipping to change at line 147
~CleanupPointer() { ~CleanupPointer() {
DESTRUCTOR_GUARD ( reset(); ); DESTRUCTOR_GUARD ( reset(); );
} }
operator bool() { return _c; } operator bool() { return _c; }
ClientCursor * operator-> () { return _c; } ClientCursor * operator-> () { return _c; }
private: private:
ClientCursor *_c; ClientCursor *_c;
CursorId _id; CursorId _id;
}; };
/**
* Iterates through all ClientCursors, under its own ccmutex lock.
* Also supports deletion on the fly.
*/
class LockedIterator : boost::noncopyable {
public:
LockedIterator() : _lock( ccmutex ), _i( clientCursorsById.begi
n() ) {}
bool ok() const { return _i != clientCursorsById.end(); }
ClientCursor *current() const { return _i->second; }
void advance() { ++_i; }
/**
* Delete 'current' and advance. Properly handles cascading del
etions that may occur
* when one ClientCursor is directly deleted.
*/
void deleteAndAdvance();
private:
recursive_scoped_lock _lock;
CCById::const_iterator _i;
};
ClientCursor(int queryOptions, const shared_ptr<Cursor>& c, const s tring& ns, BSONObj query = BSONObj() ); ClientCursor(int queryOptions, const shared_ptr<Cursor>& c, const s tring& ns, BSONObj query = BSONObj() );
~ClientCursor(); ~ClientCursor();
// *************** basic accessors ******************* // *************** basic accessors *******************
CursorId cursorid() const { return _cursorid; } CursorId cursorid() const { return _cursorid; }
string ns() const { return _ns; } string ns() const { return _ns; }
Database * db() const { return _db; } Database * db() const { return _db; }
const BSONObj& query() const { return _query; } const BSONObj& query() const { return _query; }
skipping to change at line 194 skipping to change at line 212
}; };
/** /**
* @param needRecord whether or not the next record has to be read from disk for sure * @param needRecord whether or not the next record has to be read from disk for sure
* if this is true, will yield of next record isn 't in memory * if this is true, will yield of next record isn 't in memory
* @param yielded true if a yield occurred, and potentially if a yi eld did not occur * @param yielded true if a yield occurred, and potentially if a yi eld did not occur
* @return same as yield() * @return same as yield()
*/ */
bool yieldSometimes( RecordNeeds need, bool *yielded = 0 ); bool yieldSometimes( RecordNeeds need, bool *yielded = 0 );
static int yieldSuggest(); static int suggestYieldMicros();
static void staticYield( int micros , const StringData& ns , Record * rec ); static void staticYield( int micros , const StringData& ns , Record * rec );
struct YieldData { CursorId _id; bool _doingDeletes; }; struct YieldData { CursorId _id; bool _doingDeletes; };
bool prepareToYield( YieldData &data ); bool prepareToYield( YieldData &data );
static bool recoverFromYield( const YieldData &data ); static bool recoverFromYield( const YieldData &data );
struct YieldLock : boost::noncopyable { struct YieldLock : boost::noncopyable {
explicit YieldLock( ptr<ClientCursor> cc ) explicit YieldLock( ptr<ClientCursor> cc )
: _canYield(cc->_c->supportYields()) { : _canYield(cc->_c->supportYields()) {
if ( _canYield ) { if ( _canYield ) {
skipping to change at line 305 skipping to change at line 323
public: public:
static ClientCursor* find(CursorId id, bool warn = true) { static ClientCursor* find(CursorId id, bool warn = true) {
recursive_scoped_lock lock(ccmutex); recursive_scoped_lock lock(ccmutex);
ClientCursor *c = find_inlock(id, warn); ClientCursor *c = find_inlock(id, warn);
// if this asserts, your code was not thread safe - you either need to set no timeout // if this asserts, your code was not thread safe - you either need to set no timeout
// for the cursor or keep a ClientCursor::Pointer in scope for it. // for the cursor or keep a ClientCursor::Pointer in scope for it.
massert( 12521, "internal error: use of an unlocked ClientCurso r", c == 0 || c->_pinValue ); massert( 12521, "internal error: use of an unlocked ClientCurso r", c == 0 || c->_pinValue );
return c; return c;
} }
/**
* Deletes the cursor with the provided @param 'id' if one exists.
* @throw if the cursor with the provided id is pinned.
*/
static bool erase(CursorId id) { static bool erase(CursorId id) {
recursive_scoped_lock lock(ccmutex); recursive_scoped_lock lock(ccmutex);
ClientCursor *cc = find_inlock(id); ClientCursor *cc = find_inlock(id);
if ( cc ) { if ( cc ) {
assert( cc->_pinValue < 100 ); // you can't still have an a ctive ClientCursor::Pointer assert( cc->_pinValue < 100 ); // you can't still have an a ctive ClientCursor::Pointer
delete cc; delete cc;
return true; return true;
} }
return false; return false;
} }
skipping to change at line 394 skipping to change at line 416
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
/* 0 = normal /* 0 = normal
1 = no timeout allowed 1 = no timeout allowed
100 = in use (pinned) -- see Pointer class 100 = in use (pinned) -- see Pointer class
*/ */
unsigned _pinValue; unsigned _pinValue;
bool _doingDeletes; bool _doingDeletes; // when true we are the delete and aboutToDelet e shouldn't manipulate us
ElapsedTracker _yieldSometimesTracker; ElapsedTracker _yieldSometimesTracker;
ShardChunkManagerPtr _chunkManager; ShardChunkManagerPtr _chunkManager;
public: public:
shared_ptr<ParsedQuery> pq; shared_ptr<ParsedQuery> pq;
shared_ptr<Projection> fields; // which fields query wants returned shared_ptr<Projection> fields; // which fields query wants returned
// TODO Maybe helper objects should manage their own memory rather
than rely on the
// original message being valid.
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
private: // static members private: // static members
static CCById clientCursorsById; static CCById clientCursorsById;
static long long numberTimedOut; static long long numberTimedOut;
static boost::recursive_mutex& ccmutex; // must use this for all statics above! static boost::recursive_mutex& ccmutex; // must use this for all statics above!
static CursorId allocCursorId_inlock(); static CursorId allocCursorId_inlock();
}; };
class ClientCursorMonitor : public BackgroundJob { class ClientCursorMonitor : public BackgroundJob {
public: public:
string name() const { return "ClientCursorMonitor"; } string name() const { return "ClientCursorMonitor"; }
void run(); void run();
}; };
extern ClientCursorMonitor clientCursorMonitor;
} // namespace mongo } // namespace mongo
// ClientCursor should only be used with auto_ptr because it needs to be // ClientCursor should only be used with auto_ptr because it needs to be
// release()ed after a yield if stillOk() returns false and these pointer t ypes // release()ed after a yield if stillOk() returns false and these pointer t ypes
// do not support releasing. This will prevent them from being used acciden tally // do not support releasing. This will prevent them from being used acciden tally
namespace boost{ namespace boost{
template<> class scoped_ptr<mongo::ClientCursor> {}; template<> class scoped_ptr<mongo::ClientCursor> {};
template<> class shared_ptr<mongo::ClientCursor> {}; template<> class shared_ptr<mongo::ClientCursor> {};
} }
 End of changes. 7 change blocks. 
9 lines changed or deleted 32 lines changed or added


 cmdline.h   cmdline.h 
skipping to change at line 22 skipping to change at line 22
* *
* 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 "../pch.h" #include "../pch.h"
#include "jsobj.h" #include "jsobj.h"
namespace boost {
namespace program_options {
class options_description;
class positional_options_description;
class variables_map;
}
}
namespace mongo { namespace mongo {
#ifdef MONGO_SSL #ifdef MONGO_SSL
class SSLManager; class SSLManager;
#endif #endif
/* command line options /* command line options
*/ */
/* concurrency: OK/READ */ /* concurrency: OK/READ */
struct CmdLine { struct CmdLine {
skipping to change at line 91 skipping to change at line 99
/** --durOptions 7 dump journal and terminate without doing an ything further /** --durOptions 7 dump journal and terminate without doing an ything further
--durOptions 4 recover and terminate without listening --durOptions 4 recover and terminate without listening
*/ */
enum { // bits to be ORed enum { // bits to be ORed
DurDumpJournal = 1, // dump diagnostics on the journal during recovery DurDumpJournal = 1, // dump diagnostics on the journal during recovery
DurScanOnly = 2, // don't do any real work, just scan and dump if dump specified DurScanOnly = 2, // don't do any real work, just scan and dump if dump specified
DurRecoverOnly = 4, // terminate after recovery step DurRecoverOnly = 4, // terminate after recovery step
DurParanoid = 8, // paranoid mode enables extra checks DurParanoid = 8, // paranoid mode enables extra checks
DurAlwaysCommit = 16, // do a group commit every time the write lock is released DurAlwaysCommit = 16, // do a group commit every time the write lock is released
DurAlwaysRemap = 32 // remap the private view after every gro DurAlwaysRemap = 32, // remap the private view after every gro
up commit (may lag to the next write lock acquisition, but will do all file up commit (may lag to the next write lock acquisition, but will do all file
s then) s then)
DurNoCheckSpace = 64 // don't check that there is enough room
for journal files before startup (for diskfull tests)
}; };
int durOptions; // --durOptions <n> for debugging int durOptions; // --durOptions <n> for debugging
bool objcheck; // --objcheck bool objcheck; // --objcheck
long long oplogSize; // --oplogSize long long oplogSize; // --oplogSize
int defaultProfile; // --profile int defaultProfile; // --profile
int slowMS; // --time in ms that is "slow" int slowMS; // --time in ms that is "slow"
int pretouch; // --pretouch for replication application (e xperimental) int pretouch; // --pretouch for replication application (e xperimental)
bool moveParanoia; // for move chunk paranoia bool moveParanoia; // for move chunk paranoia
double syncdelay; // seconds between fsyncs double syncdelay; // seconds between fsyncs
bool noUnixSocket; // --nounixsocket bool noUnixSocket; // --nounixsocket
bool doFork; // --fork
string socket; // UNIX domain socket directory string socket; // UNIX domain socket directory
bool keyFile; bool keyFile;
#ifndef _WIN32
pid_t parentProc; // --fork pid of initial process
pid_t leaderProc; // --fork pid of leader process
#endif
#ifdef MONGO_SSL #ifdef MONGO_SSL
bool sslOnNormalPorts; // --sslOnNormalPorts bool sslOnNormalPorts; // --sslOnNormalPorts
string sslPEMKeyFile; // --sslPEMKeyFile string sslPEMKeyFile; // --sslPEMKeyFile
string sslPEMKeyPassword; // --sslPEMKeyPassword string sslPEMKeyPassword; // --sslPEMKeyPassword
SSLManager* sslServerManager; // currently leaks on close SSLManager* sslServerManager; // currently leaks on close
#endif #endif
static void launchOk();
static void addGlobalOptions( boost::program_options::options_descr iption& general , static void addGlobalOptions( boost::program_options::options_descr iption& general ,
boost::program_options::options_descr iption& hidden ); boost::program_options::options_descr iption& hidden );
static void addWindowsOptions( boost::program_options::options_desc ription& windows , static void addWindowsOptions( boost::program_options::options_desc ription& windows ,
boost::program_options::options_desc ription& hidden ); boost::program_options::options_desc ription& hidden );
static void parseConfigFile( istream &f, stringstream &ss); static void parseConfigFile( istream &f, stringstream &ss);
/** /**
* @return true if should run program, false if should exit * @return true if should run program, false if should exit
*/ */
static bool store( int argc , char ** argv , static bool store( int argc , char ** argv ,
boost::program_options::options_description& vis ible, boost::program_options::options_description& vis ible,
boost::program_options::options_description& hid den, boost::program_options::options_description& hid den,
boost::program_options::positional_options_descr iption& positional, boost::program_options::positional_options_descr iption& positional,
boost::program_options::variables_map &output ); boost::program_options::variables_map &output );
time_t started;
}; };
// todo move to cmdline.cpp? // todo move to cmdline.cpp?
inline CmdLine::CmdLine() : inline CmdLine::CmdLine() :
port(DefaultDBPort), rest(false), jsonp(false), quiet(false), noTab leScan(false), prealloc(true), preallocj(true), smallfiles(sizeof(int*) == 4), port(DefaultDBPort), rest(false), jsonp(false), quiet(false), noTab leScan(false), prealloc(true), preallocj(true), smallfiles(sizeof(int*) == 4),
configsvr(false), configsvr(false),
quota(false), quotaFiles(8), cpu(false), durOptions(0), objcheck(fa lse), oplogSize(0), defaultProfile(0), slowMS(100), pretouch(0), moveParano ia( true ), quota(false), quotaFiles(8), cpu(false), durOptions(0), objcheck(fa lse), oplogSize(0), defaultProfile(0), slowMS(100), pretouch(0), moveParano ia( true ),
syncdelay(60), noUnixSocket(false), socket("/tmp") syncdelay(60), noUnixSocket(false), doFork(0), socket("/tmp")
{ {
started = time(0);
journalCommitInterval = 0; // 0 means use default journalCommitInterval = 0; // 0 means use default
dur = false; dur = false;
#if defined(_DURABLEDEFAULTON) #if defined(_DURABLEDEFAULTON)
dur = true; dur = true;
#endif #endif
if( sizeof(void*) == 8 ) if( sizeof(void*) == 8 )
dur = true; dur = true;
#if defined(_DURABLEDEFAULTOFF) #if defined(_DURABLEDEFAULTOFF)
dur = false; dur = false;
#endif #endif
#ifdef MONGO_SSL #ifdef MONGO_SSL
sslOnNormalPorts = false; sslOnNormalPorts = false;
sslServerManager = 0; sslServerManager = 0;
#endif #endif
} }
extern CmdLine cmdLine; extern CmdLine cmdLine;
void setupLaunchSignals();
void setupCoreSignals(); void setupCoreSignals();
string prettyHostName(); string prettyHostName();
void printCommandLineOpts(); void printCommandLineOpts();
/** /**
* used for setParameter * used for setParameter command
* so you can write validation code that lives with code using it * so you can write validation code that lives with code using it
* rather than all in the command place * rather than all in the command place
* also lets you have mongos or mongod specific code * also lets you have mongos or mongod specific code
* without pulling it all sorts of things * without pulling it all sorts of things
*/ */
class ParameterValidator { class ParameterValidator {
public: public:
ParameterValidator( const string& name ); ParameterValidator( const string& name );
virtual ~ParameterValidator() {} virtual ~ParameterValidator() {}
virtual bool isValid( BSONElement e , string& errmsg ) = 0; virtual bool isValid( BSONElement e , string& errmsg ) const = 0;
static ParameterValidator * get( const string& name ); static ParameterValidator * get( const string& name );
private: private:
string _name; const string _name;
// don't need to lock since this is all done in static init
static map<string,ParameterValidator*> * _all;
}; };
} }
 End of changes. 12 change blocks. 
10 lines changed or deleted 30 lines changed or added


 commands.h   commands.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 "../pch.h"
#include "jsobj.h" #include "jsobj.h"
#include "../util/timer.h" #include "../util/mongoutils/str.h"
#include "../client/dbclient.h"
namespace mongo { namespace mongo {
class BSONObj; class BSONObj;
class BSONObjBuilder; class BSONObjBuilder;
class Client; class Client;
class Timer;
/** mongodb "commands" (sent via db.$cmd.findOne(...)) /** mongodb "commands" (sent via db.$cmd.findOne(...))
subclass to make a command. define a singleton object for it. subclass to make a command. define a singleton object for it.
*/ */
class Command { class Command {
protected:
string parseNsFullyQualified(const string& dbname, const BSONObj& c
mdObj) const;
public: public:
// only makes sense for commands where 1st parm is the collection.
virtual string parseNs(const string& dbname, const BSONObj& cmdObj)
const;
enum LockType { READ = -1 , NONE = 0 , WRITE = 1 }; enum LockType { READ = -1 , NONE = 0 , WRITE = 1 };
const string name; const string name;
/* 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.
skipping to change at line 66 skipping to change at line 69
virtual LockType locktype() const = 0; virtual LockType locktype() const = 0;
/* 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() const { virtual bool adminOnly() const {
return false; return false;
} }
void htmlHelp(stringstream&) const; void htmlHelp(stringstream&) const;
/* Like adminOnly, but even stricter: we must either be authenticat ed for admin db, /* Like adminOnly, but even stricter: we must either be authenticat ed for admin db,
or, if running without auth, on the local interface. or, if running without auth, on the local interface. Used for t
hings which
are so major that remote invocation may not make sense (e.g., sh
utdownServer).
When localHostOnlyIfNoAuth() is true, adminOnly() must also be t rue. When localHostOnlyIfNoAuth() is true, adminOnly() must also be t rue.
*/ */
virtual bool localHostOnlyIfNoAuth(const BSONObj& cmdObj) { return false; } virtual bool localHostOnlyIfNoAuth(const BSONObj& cmdObj) { return false; }
/* Return true if slaves are allowed to execute the command /* Return true if slaves are allowed to execute 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() const = 0; virtual bool slaveOk() const = 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() const {
return false; return false;
} }
/* Override and return true to if true,log the operation (logOp()) to the replication log. /* Override and return true to if true,log the operation (logOp()) to the replication log.
(not done if fromRepl of course) (not done if fromRepl of course)
Note if run() returns false, we do NOT log. Note if run() returns false, we do NOT log.
*/ */
virtual bool logTheOp() { return false; } virtual bool logTheOp() { return false; }
skipping to change at line 103 skipping to change at line 107
/* Return true if authentication and security applies to the comman ds. Some commands /* Return true if authentication and security applies to the comman ds. Some commands
(e.g., getnonce, authenticate) can be done by anyone even unauth orized. (e.g., getnonce, authenticate) can be done by anyone even unauth orized.
*/ */
virtual bool requiresAuth() { return true; } virtual bool requiresAuth() { return true; }
/* Return true if a replica set secondary should go into "recoverin g" /* Return true if a replica set secondary should go into "recoverin g"
(unreadable) state while running this command. (unreadable) state while running this command.
*/ */
virtual bool maintenanceMode() const { return false; } virtual bool maintenanceMode() const { return false; }
/* Return true if command should be permitted when a replica set se
condary is in "recovering"
(unreadable) state.
*/
virtual bool maintenanceOk() const { return true; /* assumed true p
rior to commit */ }
/** @param webUI expose the command in the web ui as localhost:2801 7/<name> /** @param webUI expose the command in the web ui as localhost:2801 7/<name>
@param oldName an optional old, deprecated name for the command @param oldName an optional old, deprecated name for the command
*/ */
Command(const char *_name, bool webUI = false, const char *oldName = 0); Command(const char *_name, bool webUI = false, const char *oldName = 0);
virtual ~Command() {} virtual ~Command() {}
protected: protected:
BSONObj getQuery( const BSONObj& cmdObj ) { BSONObj getQuery( const BSONObj& cmdObj ) {
if ( cmdObj["query"].type() == Object ) if ( cmdObj["query"].type() == Object )
 End of changes. 9 change blocks. 
6 lines changed or deleted 21 lines changed or added


 concurrency.h   concurrency.h 
skipping to change at line 19 skipping to change at line 19
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* 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 Lice nse * You should have received a copy of the GNU Affero General Public Lice nse
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/*mongod concurrency rules & notes will be placed here.
Mutex heirarchy (1 = "leaf")
name level
Logstream::mutex 1
ClientCursor::ccmutex 2
dblock 3
End func name with _inlock to indicate "caller must lock before callin
g".
*/
#pragma once #pragma once
#include "../util/concurrency/rwlock.h"
#include "../util/mmap.h"
#include "../util/time_support.h"
namespace mongo {
string sayClientState();
bool haveClient();
class Client;
Client* curopWaitingForLock( int type );
void curopGotLock(Client*);
/* mutex time stats */
class MutexInfo {
unsigned long long enter, timeLocked; // microseconds
int locked;
unsigned long long start; // last as we touch this least often
public:
MutexInfo() : timeLocked(0) , locked(0) {
start = curTimeMicros64();
}
void entered() {
if ( locked == 0 )
enter = curTimeMicros64();
locked++;
assert( locked >= 1 );
}
void leaving() {
locked--;
assert( locked >= 0 );
if ( locked == 0 )
timeLocked += curTimeMicros64() - enter;
}
int isLocked() const { return locked; }
void getTimingInfo(unsigned long long &s, unsigned long long &tl) c
onst {
s = start;
tl = timeLocked;
}
unsigned long long getTimeLocked() const { return timeLocked; }
};
}
#include "mongomutex.h" #include "mongomutex.h"
namespace mongo {
struct writelock {
writelock() { dbMutex.lock(); }
writelock(const string& ns) { dbMutex.lock(); }
~writelock() {
DESTRUCTOR_GUARD(
dbMutex.unlock();
);
}
};
struct readlock {
readlock(const string& ns) {
dbMutex.lock_shared();
}
readlock() { dbMutex.lock_shared(); }
~readlock() {
DESTRUCTOR_GUARD(
dbMutex.unlock_shared();
);
}
};
struct readlocktry {
readlocktry( const string&ns , int tryms ) {
_got = dbMutex.lock_shared_try( tryms );
}
~readlocktry() {
if ( _got ) {
dbMutex.unlock_shared();
}
}
bool got() const { return _got; }
private:
bool _got;
};
struct writelocktry {
writelocktry( const string&ns , int tryms ) {
_got = dbMutex.lock_try( tryms );
}
~writelocktry() {
if ( _got ) {
dbMutex.unlock();
}
}
bool got() const { return _got; }
private:
bool _got;
};
struct readlocktryassert : public readlocktry {
readlocktryassert(const string& ns, int tryms) :
readlocktry(ns,tryms) {
uassert(13142, "timeout getting readlock", got());
}
};
/** assure we have at least a read lock - they key with this being
if you have a write lock, that's ok too.
*/
struct atleastreadlock {
atleastreadlock( const string& ns ) {
_prev = dbMutex.getState();
if ( _prev == 0 )
dbMutex.lock_shared();
}
~atleastreadlock() {
if ( _prev == 0 )
dbMutex.unlock_shared();
}
private:
int _prev;
};
/* parameterized choice of read or write locking
use readlock and writelock instead of this when statically known whi
ch you want
*/
class mongolock {
bool _writelock;
public:
mongolock(bool write) : _writelock(write) {
if( _writelock ) {
dbMutex.lock();
}
else
dbMutex.lock_shared();
}
~mongolock() {
DESTRUCTOR_GUARD(
if( _writelock ) {
dbMutex.unlock();
}
else {
dbMutex.unlock_shared();
}
);
}
/* this unlocks, does NOT upgrade. that works for our current usage
*/
void releaseAndWriteLock();
};
/* deprecated - use writelock and readlock instead */
struct dblock : public writelock {
dblock() : writelock("") { }
};
// eliminate this - we should just type "dbMutex.assertWriteLocked();"
instead
inline void assertInWriteLock() { dbMutex.assertWriteLocked(); }
}
 End of changes. 3 change blocks. 
58 lines changed or deleted 0 lines changed or added


 config.h   config.h 
skipping to change at line 59 skipping to change at line 59
*/ */
struct ShardFields { struct ShardFields {
static BSONField<bool> draining; // is it draining chunks? static BSONField<bool> draining; // is it draining chunks?
static BSONField<long long> maxSize; // max allowed disk space usa ge static BSONField<long long> maxSize; // max allowed disk space usa ge
}; };
class ConfigServer; class ConfigServer;
class DBConfig; class DBConfig;
typedef boost::shared_ptr<DBConfig> DBConfigPtr; typedef boost::shared_ptr<DBConfig> DBConfigPtr;
typedef shared_ptr<Shard> ShardPtr;
extern DBConfigPtr configServerPtr; extern DBConfigPtr configServerPtr;
extern ConfigServer& configServer; extern ConfigServer& configServer;
/** /**
* top level configuration for a database * top level configuration for a database
*/ */
class DBConfig { class DBConfig {
struct CollectionInfo { struct CollectionInfo {
skipping to change at line 133 skipping to change at line 134
string getName() { return _name; }; string getName() { return _name; };
/** /**
* @return if anything in this db is partitioned or not * @return if anything in this db is partitioned or not
*/ */
bool isShardingEnabled() { bool isShardingEnabled() {
return _shardingEnabled; return _shardingEnabled;
} }
void enableSharding(); void enableSharding();
ChunkManagerPtr shardCollection( const string& ns , ShardKeyPattern fieldsAndOrder , bool unique ); ChunkManagerPtr shardCollection( const string& ns , ShardKeyPattern fieldsAndOrder , bool unique , vector<BSONObj>* initPoints=0, vector<Shard >* initShards=0 );
/** /**
@return true if there was sharding info to remove @return true if there was sharding info to remove
*/ */
bool removeSharding( const string& ns ); bool removeSharding( const string& ns );
/** /**
* @return whether or not the 'ns' collection is partitioned * @return whether or not the 'ns' collection is partitioned
*/ */
bool isSharded( const string& ns ); bool isSharded( const string& ns );
ChunkManagerPtr getChunkManager( const string& ns , bool reload = f alse, bool forceReload = false ); ChunkManagerPtr getChunkManager( const string& ns , bool reload = f alse, bool forceReload = false );
ChunkManagerPtr getChunkManagerIfExists( const string& ns , bool re load = false, bool forceReload = false ); ChunkManagerPtr getChunkManagerIfExists( const string& ns , bool re load = false, bool forceReload = false );
const Shard& getShard( const string& ns );
/** /**
* @return the correct for shard for the ns * @return the correct for shard for the ns
* if the namespace is sharded, will return NULL * if the namespace is sharded, will return NULL
*/ */
const Shard& getShard( const string& ns ); ShardPtr getShardIfExists( const string& ns );
const Shard& getPrimary() const { const Shard& getPrimary() const {
uassert( 8041 , (string)"no primary shard configured for db: " + _name , _primary.ok() ); uassert( 8041 , (string)"no primary shard configured for db: " + _name , _primary.ok() );
return _primary; return _primary;
} }
void setPrimary( string s ); void setPrimary( string s );
bool load(); bool load();
bool reload(); bool reload();
 End of changes. 4 change blocks. 
2 lines changed or deleted 4 lines changed or added


 connections.h   connections.h 
skipping to change at line 51 skipping to change at line 51
scopedconn object for same host). scopedconn object for same host).
*/ */
class ScopedConn { class ScopedConn {
public: public:
/** throws assertions if connect failure etc. */ /** throws assertions if connect failure etc. */
ScopedConn(string hostport); ScopedConn(string hostport);
~ScopedConn() { ~ScopedConn() {
// conLock releases... // conLock releases...
} }
void reconnect() { void reconnect() {
conn()->port().shutdown(); conn().reset(new DBClientConnection(true, 0, 10));
connect(); x->connected = false;
connect();
} }
/* If we were to run a query and not exhaust the cursor, future use of the connection would be problematic. /* If we were to run a query and not exhaust the cursor, future use of the connection would be problematic.
So here what we do is wrapper known safe methods and not allow c ursor-style queries at all. This makes So here what we do is wrapper known safe methods and not allow c ursor-style queries at all. This makes
ScopedConn limited in functionality but very safe. More non-cur sor wrappers can be added here if needed. ScopedConn limited in functionality but very safe. More non-cur sor wrappers can be added here if needed.
*/ */
bool runCommand(const string &dbname, const BSONObj& cmd, BSONObj & info, int options=0) { bool runCommand(const string &dbname, const BSONObj& cmd, BSONObj & info, int options=0) {
return conn()->runCommand(dbname, cmd, info, options); return conn()->runCommand(dbname, cmd, info, options);
} }
unsigned long long count(const string &ns) { unsigned long long count(const string &ns) {
skipping to change at line 74 skipping to change at line 75
} }
BSONObj findOne(const string &ns, const Query& q, const BSONObj *fi eldsToReturn = 0, int queryOptions = 0) { BSONObj findOne(const string &ns, const Query& q, const BSONObj *fi eldsToReturn = 0, int queryOptions = 0) {
return conn()->findOne(ns, q, fieldsToReturn, queryOptions); return conn()->findOne(ns, q, fieldsToReturn, queryOptions);
} }
private: private:
auto_ptr<scoped_lock> connLock; auto_ptr<scoped_lock> connLock;
static mongo::mutex mapMutex; static mongo::mutex mapMutex;
struct X { struct X {
mongo::mutex z; mongo::mutex z;
DBClientConnection cc; scoped_ptr<DBClientConnection> cc;
bool connected; bool connected;
X() : z("X"), cc(/*reconnect*/ true, 0, /*timeout*/ 10.0), conn X() : z("X"), cc(new DBClientConnection(/*reconnect*/ true, 0,
ected(false) { /*timeout*/ 10.0)), connected(false) {
cc._logLevel = 2; cc->_logLevel = 2;
} }
} *x; } *x;
typedef map<string,ScopedConn::X*> M; typedef map<string,ScopedConn::X*> M;
static M& _map; static M& _map;
DBClientConnection* conn() { return &x->cc; } scoped_ptr<DBClientConnection>& conn() { return x->cc; }
const string _hostport; const string _hostport;
// we should already be locked... // we should already be locked...
bool connect() { bool connect() {
string err; string err;
if (!x->cc.connect(_hostport, err)) { if (!x->cc->connect(_hostport, err)) {
log() << "couldn't connect to " << _hostport << ": " << err << rsLog; log() << "couldn't connect to " << _hostport << ": " << err << rsLog;
return false; return false;
} }
x->connected = true; x->connected = true;
// if we cannot authenticate against a member, then either its ke y file // if we cannot authenticate against a member, then either its ke y file
// or our key file has to change. if our key file has to change, we'll // or our key file has to change. if our key file has to change, we'll
// be rebooting. if their file has to change, they'll be rebooted so the // be rebooting. if their file has to change, they'll be rebooted so the
// connection created above will go dead, reconnect, and reauth. // connection created above will go dead, reconnect, and reauth.
if (!noauth && !x->cc.auth("local", internalSecurity.user, intern alSecurity.pwd, err, false)) { if (!noauth && !x->cc->auth("local", internalSecurity.user, inter nalSecurity.pwd, err, false)) {
log() << "could not authenticate against " << _hostport << ", " << err << rsLog; log() << "could not authenticate against " << _hostport << ", " << err << rsLog;
return false; return false;
} }
return true; return true;
} }
}; };
inline ScopedConn::ScopedConn(string hostport) : _hostport(hostport) { inline ScopedConn::ScopedConn(string hostport) : _hostport(hostport) {
bool first = false; bool first = false;
 End of changes. 6 change blocks. 
9 lines changed or deleted 10 lines changed or added


 core.h   core.h 
skipping to change at line 51 skipping to change at line 51
for ( unsigned i=0; i<16; i++ ) { for ( unsigned i=0; i<16; i++ ) {
unsigned fixed = 0; unsigned fixed = 0;
for ( int j=0; j<4; j++ ) { for ( int j=0; j<4; j++ ) {
if ( i & ( 1 << j ) ) if ( i & ( 1 << j ) )
fixed |= ( 1 << ( j * 2 ) ); fixed |= ( 1 << ( j * 2 ) );
} }
hashedToNormal[fixed] = i; hashedToNormal[fixed] = i;
} }
long long currAllX = 0, currAllY = 0;
for ( int i = 0; i < 64; i++ ){
if( i % 2 == 0 ){
allX[ i / 2 ] = currAllX;
currAllX = currAllX + ( 1LL << ( 63 - i ) );
}
else{
allY[ i / 2 ] = currAllY;
currAllY = currAllY + ( 1LL << ( 63 - i ) );
}
}
} }
int masks32[32]; int masks32[32];
long long masks64[64]; long long masks64[64];
long long allX[32];
long long allY[32];
unsigned hashedToNormal[256]; unsigned hashedToNormal[256];
}; };
extern GeoBitSets geoBitSets; extern GeoBitSets geoBitSets;
class GeoHash { class GeoHash {
public: public:
GeoHash() GeoHash()
skipping to change at line 171 skipping to change at line 184
bool hasPrefix( const GeoHash& other ) const { bool hasPrefix( const GeoHash& other ) const {
assert( other._bits <= _bits ); assert( other._bits <= _bits );
if ( other._bits == 0 ) if ( other._bits == 0 )
return true; return true;
long long x = other._hash ^ _hash; long long x = other._hash ^ _hash;
x = x >> (64-(other._bits*2)); x = x >> (64-(other._bits*2));
return x == 0; return x == 0;
} }
string toString() const { string toString() const {
StringBuilder buf( _bits * 2 ); StringBuilder buf;
for ( unsigned x=0; x<_bits*2; x++ ) for ( unsigned x=0; x<_bits*2; x++ )
buf.append( _hash & geoBitSets.masks64[x] ? "1" : "0" ); buf.append( _hash & geoBitSets.masks64[x] ? "1" : "0" );
return buf.str(); return buf.str();
} }
string toStringHex1() const { string toStringHex1() const {
stringstream ss; stringstream ss;
ss << hex << _hash; ss << hex << _hash;
return ss.str(); return ss.str();
} }
skipping to change at line 213 skipping to change at line 226
bool getBitX( unsigned pos ) const { bool getBitX( unsigned pos ) const {
assert( pos < 32 ); assert( pos < 32 );
return getBit( pos * 2 ); return getBit( pos * 2 );
} }
bool getBitY( unsigned pos ) const { bool getBitY( unsigned pos ) const {
assert( pos < 32 ); assert( pos < 32 );
return getBit( ( pos * 2 ) + 1 ); return getBit( ( pos * 2 ) + 1 );
} }
BSONObj wrap() const { BSONObj wrap( const char* name = "" ) const {
BSONObjBuilder b(20); BSONObjBuilder b(20);
append( b , "" ); append( b , name );
BSONObj o = b.obj(); BSONObj o = b.obj();
assert( o.objsize() == 20 ); if( ! strlen( name ) ) assert( o.objsize() == 20 );
return o; return o;
} }
bool constrains() const { bool constrains() const {
return _bits > 0; return _bits > 0;
} }
bool canRefine() const { bool canRefine() const {
return _bits < 32; return _bits < 32;
} }
bool atMinX() const {
return ( _hash & geoBitSets.allX[ _bits ] ) == 0;
}
bool atMinY() const {
//log() << " MinY : " << hex << (unsigned long long) _hash << "
" << _bits << " " << hex << (unsigned long long) geoBitSets.allY[ _bits ]
<< endl;
return ( _hash & geoBitSets.allY[ _bits ] ) == 0;
}
bool atMaxX() const {
return ( _hash & geoBitSets.allX[ _bits ] ) == geoBitSets.allX[
_bits ];
}
bool atMaxY() const {
return ( _hash & geoBitSets.allY[ _bits ] ) == geoBitSets.allY[
_bits ];
}
void move( int x , int y ) { void move( int x , int y ) {
assert( _bits ); assert( _bits );
_move( 0 , x ); _move( 0 , x );
_move( 1 , y ); _move( 1 , y );
} }
void _move( unsigned offset , int d ) { void _move( unsigned offset , int d ) {
if ( d == 0 ) if ( d == 0 )
return; return;
assert( d <= 1 && d>= -1 ); // TEMP assert( d <= 1 && d>= -1 ); // TEMP
skipping to change at line 462 skipping to change at line 492
} }
else { else {
return _x > p._x ? p._x + radius >= _x : _x + radius >= p._x; return _x > p._x ? p._x + radius >= _x : _x + radius >= p._x;
} }
} }
return sqrt( ( a * a ) + ( b * b ) ) <= radius; return sqrt( ( a * a ) + ( b * b ) ) <= radius;
} }
string toString() const { string toString() const {
StringBuilder buf(32); StringBuilder buf;
buf << "(" << _x << "," << _y << ")"; buf << "(" << _x << "," << _y << ")";
return buf.str(); return buf.str();
} }
double _x; double _x;
double _y; double _y;
}; };
extern const double EARTH_RADIUS_KM; extern const double EARTH_RADIUS_KM;
 End of changes. 8 change blocks. 
5 lines changed or deleted 39 lines changed or added


 counters.h   counters.h 
skipping to change at line 76 skipping to change at line 76
AtomicUInt * _command; AtomicUInt * _command;
}; };
extern OpCounters globalOpCounters; extern OpCounters globalOpCounters;
extern OpCounters replOpCounters; extern OpCounters replOpCounters;
class IndexCounters { class IndexCounters {
public: public:
IndexCounters(); IndexCounters();
// used without a mutex intentionally (can race)
void btree( char * node ) { void btree( char * node ) {
if ( ! _memSupported ) if ( ! _memSupported )
return; return;
if ( _sampling++ % _samplingrate ) if ( _sampling++ % _samplingrate )
return; return;
btree( _pi.blockInMemory( node ) ); btree( _pi.blockInMemory( node ) );
} }
void btree( bool memHit ) { void btree( bool memHit ) {
if ( memHit ) if ( memHit )
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 curop-inl.h   curop-inl.h 
// @file curop-inl.h
/**
* Copyright (C) 2009 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3
,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* 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/>.
*/
#pragma once
#include "curop.h" #include "curop.h"
namespace mongo {
// todo : move more here
inline CurOp::CurOp( Client * client , CurOp * wrapped ) {
_client = client;
_wrapped = wrapped;
if ( _wrapped )
_client->_curOp = this;
_start = _checkpoint = 0;
_active = false;
_reset();
_op = 0;
// These addresses should never be written to again. The zeroes ar
e
// placed here as a precaution because currentOp may be accessed
// without the db mutex.
memset(_ns, 0, sizeof(_ns));
}
}
 End of changes. 2 change blocks. 
22 lines changed or deleted 0 lines changed or added


 curop.h   curop.h 
skipping to change at line 61 skipping to change at line 61
BSONObj updateobj; BSONObj updateobj;
// detailed options // detailed options
long long cursorid; long long cursorid;
int ntoreturn; int ntoreturn;
int ntoskip; int ntoskip;
bool exhaust; bool exhaust;
// debugging/profile info // debugging/profile info
int nscanned; int nscanned;
bool idhack; bool idhack; // indicates short circuited code path on an u
bool scanAndOrder; pdate to make the update faster
bool moved; bool scanAndOrder; // scanandorder query plan aspect was used
bool moved; // update resulted in a move (moves are expens
ive)
bool fastmod; bool fastmod;
bool fastmodinsert; bool fastmodinsert; // upsert of an $operation. builds a default o
bool upsert; bject
unsigned keyUpdates; bool upsert; // true if the update actually did an insert
int keyUpdates;
// error handling // error handling
ExceptionInfo exceptionInfo; ExceptionInfo exceptionInfo;
// response info // response info
int executionTime; int executionTime;
int nreturned; int nreturned;
int responseLength; int responseLength;
}; };
skipping to change at line 100 skipping to change at line 100
reset(); reset();
} }
void reset( int sz = 0 ) { void reset( int sz = 0 ) {
_lock.lock(); _lock.lock();
_reset( sz ); _reset( sz );
_lock.unlock(); _lock.unlock();
} }
void set( const BSONObj& o ) { void set( const BSONObj& o ) {
_lock.lock(); scoped_spinlock lk(_lock);
try { int sz = o.objsize();
int sz = o.objsize(); if ( sz > (int) sizeof(_buf) ) {
_reset(TOO_BIG_SENTINEL);
if ( sz > (int) sizeof(_buf) ) {
_reset(TOO_BIG_SENTINEL);
}
else {
memcpy(_buf, o.objdata(), sz );
}
_lock.unlock();
} }
catch ( ... ) { else {
_lock.unlock(); memcpy(_buf, o.objdata(), sz );
throw;
} }
} }
int size() const { return *_size; } int size() const { return *_size; }
bool have() const { return size() > 0; } bool have() const { return size() > 0; }
BSONObj get() const { BSONObj get() const {
_lock.lock(); scoped_spinlock lk(_lock);
BSONObj o; return _get();
try {
o = _get();
_lock.unlock();
}
catch ( ... ) {
_lock.unlock();
throw;
}
return o;
} }
void append( BSONObjBuilder& b , const StringData& name ) const { void append( BSONObjBuilder& b , const StringData& name ) const {
scoped_spinlock lk(_lock); scoped_spinlock lk(_lock);
BSONObj temp = _get(); BSONObj temp = _get();
b.append( name , temp ); b.append( name , temp );
} }
private: private:
/** you have to be locked when you call this */ /** you have to be locked when you call this */
skipping to change at line 179 skipping to change at line 160
bool haveQuery() const { return _query.have(); } bool haveQuery() const { return _query.have(); }
BSONObj query() { return _query.get(); } BSONObj query() { return _query.get(); }
void appendQuery( BSONObjBuilder& b , const StringData& name ) cons t { _query.append( b , name ); } void appendQuery( BSONObjBuilder& b , const StringData& name ) cons t { _query.append( b , name ); }
void ensureStarted() { void ensureStarted() {
if ( _start == 0 ) if ( _start == 0 )
_start = _checkpoint = curTimeMicros64(); _start = _checkpoint = curTimeMicros64();
} }
bool isStarted() const { return _start > 0; } bool isStarted() const { return _start > 0; }
void enter( Client::Context * context ); void enter( Client::Context * context );
void leave( Client::Context * context ); void leave( Client::Context * context );
void reset();
void reset() { void reset( const HostAndPort& remote, int op );
_reset();
_start = _checkpoint = 0;
_opNum = _nextOpNum++;
_ns[0] = 0;
_debug.reset();
_query.reset();
_active = true; // this should be last for ui clarity
}
void reset( const HostAndPort& remote, int op ) {
reset();
_remote = remote;
_op = op;
}
void markCommand() { _command = true; } void markCommand() { _command = true; }
void waitingForLock( int type ) { void waitingForLock( int type ) {
_waitingForLock = true; _waitingForLock = true;
if ( type > 0 ) if ( type > 0 )
_lockType = 1; _lockType = 1;
else else
_lockType = -1; _lockType = -1;
} }
void gotLock() { _waitingForLock = false; } void gotLock() { _waitingForLock = false; }
skipping to change at line 229 skipping to change at line 193
} }
AtomicUInt opNum() const { return _opNum; } AtomicUInt opNum() const { return _opNum; }
/** if this op is running */ /** if this op is running */
bool active() const { return _active; } bool active() const { return _active; }
int getLockType() const { return _lockType; } int getLockType() const { return _lockType; }
bool isWaitingForLock() const { return _waitingForLock; } bool isWaitingForLock() const { return _waitingForLock; }
int getOp() const { return _op; } int getOp() const { return _op; }
unsigned long long startTime() { // micros
/** micros */
unsigned long long startTime() {
ensureStarted(); ensureStarted();
return _start; return _start;
} }
void done() { void done() {
_active = false; _active = false;
_end = curTimeMicros64(); _end = curTimeMicros64();
} }
unsigned long long totalTimeMicros() { unsigned long long totalTimeMicros() {
massert( 12601 , "CurOp not marked done yet" , ! _active ); massert( 12601 , "CurOp not marked done yet" , ! _active );
return _end - startTime(); return _end - startTime();
} }
int totalTimeMillis() { return (int) (totalTimeMicros() / 1000); } int totalTimeMillis() { return (int) (totalTimeMicros() / 1000); }
int elapsedMillis() { int elapsedMillis() {
unsigned long long total = curTimeMicros64() - startTime(); unsigned long long total = curTimeMicros64() - startTime();
return (int) (total / 1000); return (int) (total / 1000);
} }
int elapsedSeconds() { return elapsedMillis() / 1000; } int elapsedSeconds() { return elapsedMillis() / 1000; }
void setQuery(const BSONObj& query) { _query.set( query ); } void setQuery(const BSONObj& query) { _query.set( query ); }
Client * getClient() const { return _client; } Client * getClient() const { return _client; }
BSONObj info();
BSONObj info() {
if( ! cc().getAuthenticationInfo()->isAuthorized("admin") ) {
BSONObjBuilder b;
b.append("err", "unauthorized");
return b.obj();
}
return infoNoauth();
}
BSONObj infoNoauth(); BSONObj infoNoauth();
string getRemoteString( bool includePort = true ) { return _remote. toString(includePort); } string getRemoteString( bool includePort = true ) { return _remote. toString(includePort); }
ProgressMeter& setMessage( const char * msg , unsigned long long pr
ProgressMeter& setMessage( const char * msg , unsigned long long pr ogressMeterTotal = 0 , int secondsBetween = 3 );
ogressMeterTotal = 0 , int secondsBetween = 3 ) {
if ( progressMeterTotal ) {
if ( _progressMeter.isActive() ) {
cout << "about to assert, old _message: " << _message <
< " new message:" << msg << endl;
assert( ! _progressMeter.isActive() );
}
_progressMeter.reset( progressMeterTotal , secondsBetween )
;
}
else {
_progressMeter.finished();
}
_message = msg;
return _progressMeter;
}
string getMessage() const { return _message.toString(); } string getMessage() const { return _message.toString(); }
ProgressMeter& getProgressMeter() { return _progressMeter; } ProgressMeter& getProgressMeter() { return _progressMeter; }
CurOp *parent() const { return _wrapped; } CurOp *parent() const { return _wrapped; }
void kill() { _killed = true; } void kill() { _killed = true; }
bool killed() const { return _killed; } bool killed() const { return _killed; }
void yielded() { _numYields++; } void yielded() { _numYields++; }
void setNS(const char *ns) { void setNS(const char *ns) {
strncpy(_ns, ns, Namespace::MaxNsLen); strncpy(_ns, ns, Namespace::MaxNsLen);
_ns[Namespace::MaxNsLen] = 0; _ns[Namespace::MaxNsLen] = 0;
} }
friend class Client;
private: private:
friend class Client;
void _reset();
static AtomicUInt _nextOpNum; static AtomicUInt _nextOpNum;
Client * _client; Client * _client;
CurOp * _wrapped; CurOp * _wrapped;
unsigned long long _start; unsigned long long _start;
unsigned long long _checkpoint; unsigned long long _checkpoint;
unsigned long long _end; unsigned long long _end;
bool _active; bool _active;
int _op; int _op;
bool _command; bool _command;
int _lockType; // see concurrency.h for values int _lockType; // see concurrency.h for values
bool _waitingForLock; bool _waitingForLock;
int _dbprofile; // 0=off, 1=slow, 2=all int _dbprofile; // 0=off, 1=slow, 2=all
AtomicUInt _opNum; AtomicUInt _opNum; // todo: simple being "unsigned" m
ay make more sense here
char _ns[Namespace::MaxNsLen+2]; char _ns[Namespace::MaxNsLen+2];
HostAndPort _remote; HostAndPort _remote; // CAREFUL here with thread safety
CachedBSONObj _query; CachedBSONObj _query; // CachedBSONObj is thread safe
OpDebug _debug; OpDebug _debug;
ThreadSafeString _message; ThreadSafeString _message;
ProgressMeter _progressMeter; ProgressMeter _progressMeter;
volatile bool _killed; volatile bool _killed;
int _numYields; int _numYields;
void _reset() {
_command = false;
_lockType = 0;
_dbprofile = 0;
_end = 0;
_waitingForLock = false;
_message = "";
_progressMeter.finished();
_killed = false;
_numYields = 0;
}
}; };
/* _globalKill: we are shutting down /* _globalKill: we are shutting down
otherwise kill attribute set on specified CurOp otherwise kill attribute set on specified CurOp
this class does not handle races between interruptJs and the checkFo rInterrupt functions - those must be this class does not handle races between interruptJs and the checkFo rInterrupt functions - those must be
handled by the client of this class handled by the client of this class
*/ */
extern class KillCurrentOp { extern class KillCurrentOp {
public: public:
void killAll(); void killAll();
void kill(AtomicUInt i); void kill(AtomicUInt i);
/** @return true if global interrupt and should terminate the opera tion */ /** @return true if global interrupt and should terminate the opera tion */
bool globalInterruptCheck() const { return _globalKill; } bool globalInterruptCheck() const { return _globalKill; }
void checkForInterrupt( bool heedMutex = true ) { void checkForInterrupt( bool heedMutex = true ) {
if ( heedMutex && dbMutex.isWriteLocked() ) Client& c = cc();
if ( heedMutex && d.dbMutex.isWriteLocked() )
return; return;
if( _globalKill ) if( _globalKill )
uasserted(11600,"interrupted at shutdown"); uasserted(11600,"interrupted at shutdown");
if( cc().curop()->killed() ) if( c.curop()->killed() )
uasserted(11601,"interrupted"); uasserted(11601,"interrupted");
if( c.sometimes(1024) ) {
AbstractMessagingPort *p = cc().port();
if( p )
p->assertStillConnected();
}
} }
/** @return "" if not interrupted. otherwise, you should stop. */ /** @return "" if not interrupted. otherwise, you should stop. */
const char *checkForInterruptNoAssert( bool heedMutex = true ) { const char *checkForInterruptNoAssert( /*bool heedMutex = true*/ )
if ( heedMutex && dbMutex.isWriteLocked() ) {
return ""; Client& c = cc();
// always called withi false so commented out:
/*if ( heedMutex && d.dbMutex.isWriteLocked() )
return "";*/
if( _globalKill ) if( _globalKill )
return "interrupted at shutdown"; return "interrupted at shutdown";
if( cc().curop()->killed() ) if( c.curop()->killed() )
return "interrupted"; return "interrupted";
if( c.sometimes(1024) ) {
try {
AbstractMessagingPort *p = cc().port();
if( p )
p->assertStillConnected();
}
catch(...) {
log() << "no longer connected to client";
return "no longer connected to client";
}
}
return ""; return "";
} }
private: private:
void interruptJs( AtomicUInt *op ); void interruptJs( AtomicUInt *op );
volatile bool _globalKill; volatile bool _globalKill;
} killCurrentOp; } killCurrentOp;
} }
 End of changes. 32 change blocks. 
118 lines changed or deleted 58 lines changed or added


 cursor.h   cursor.h 
skipping to change at line 83 skipping to change at line 83
virtual bool supportGetMore() = 0; virtual bool supportGetMore() = 0;
/* called after every query block is iterated -- i.e. between getMo re() blocks /* called after every query block is iterated -- i.e. between getMo re() blocks
so you can note where we are, if necessary. so you can note where we are, if necessary.
*/ */
virtual void noteLocation() { } virtual void noteLocation() { }
/* called before query getmore block is iterated */ /* called before query getmore block is iterated */
virtual void checkLocation() { } virtual void checkLocation() { }
/**
* Called before a document pointed at by an earlier iterate of thi
s cursor is to be
* modified. It is ok if the current iterate also points to the do
cument to be modified.
*/
virtual void prepareToTouchEarlierIterate() { noteLocation(); }
/** Recover from a previous call to prepareToTouchEarlierIterate().
*/
virtual void recoverFromTouchingEarlierIterate() { checkLocation();
}
virtual bool supportYields() = 0; virtual bool supportYields() = 0;
/** Called before a ClientCursor yield. */ /** Called before a ClientCursor yield. */
virtual bool prepareToYield() { noteLocation(); return supportYield s(); } virtual bool prepareToYield() { noteLocation(); return supportYield s(); }
/** Called after a ClientCursor yield. */ /** Called after a ClientCursor yield. Recovers from a previous ca ll to prepareToYield(). */
virtual void recoverFromYield() { checkLocation(); } virtual void recoverFromYield() { checkLocation(); }
virtual string toString() { return "abstract?"; } virtual string toString() { return "abstract?"; }
/* used for multikey index traversal to avoid sending back dups. se e Matcher::matches(). /* used for multikey index traversal to avoid sending back dups. se e Matcher::matches().
if a multikey index traversal: if a multikey index traversal:
if loc has already been sent, returns true. if loc has already been sent, returns true.
otherwise, marks loc as sent. otherwise, marks loc as sent.
*/ */
virtual bool getsetdup(DiskLoc loc) = 0; virtual bool getsetdup(DiskLoc loc) = 0;
virtual bool isMultiKey() const = 0; virtual bool isMultiKey() const = 0;
virtual bool autoDedup() const { return true; }
/** /**
* return true if the keys in the index have been modified from the main doc * return true if the keys in the index have been modified from the main doc
* if you have { a : 1 , b : [ 1 , 2 ] } * if you have { a : 1 , b : [ 1 , 2 ] }
* an index on { a : 1 } would not be modified * an index on { a : 1 } would not be modified
* an index on { b : 1 } would be since the values of the array are put in the index * an index on { b : 1 } would be since the values of the array are put in the index
* not the array * not the array
*/ */
virtual bool modifiedKeys() const = 0; virtual bool modifiedKeys() const = 0;
virtual BSONObj prettyIndexBounds() const { return BSONArray(); } virtual BSONObj prettyIndexBounds() const { return BSONArray(); }
/**
* If true, this is an unindexed cursor over a capped collection.
Currently such cursors must
* not own a delegate ClientCursor, due to the implementation of Cl
ientCursor::aboutToDelete(). - SERVER-4563
*/
virtual bool capped() const { return false; } virtual bool capped() const { return false; }
virtual long long nscanned() = 0; virtual long long nscanned() = 0;
// The implementation may return different matchers depending on th e // The implementation may return different matchers depending on th e
// position of the cursor. If matcher() is nonzero at the start, // position of the cursor. If matcher() is nonzero at the start,
// matcher() should be checked each time advance() is called. // matcher() should be checked each time advance() is called.
// Implementations which generate their own matcher should return t his // Implementations which generate their own matcher should return t his
// to avoid a matcher being set manually. // to avoid a matcher being set manually.
// Note that the return values differ subtly here // Note that the return values differ subtly here
// Used when we want fast matcher lookup // Used when we want fast matcher lookup
virtual CoveredIndexMatcher *matcher() const { return 0; } virtual CoveredIndexMatcher *matcher() const { return 0; }
// Used when we need to share this matcher with someone else // Used when we need to share this matcher with someone else
virtual shared_ptr< CoveredIndexMatcher > matcherPtr() const { retu rn shared_ptr< CoveredIndexMatcher >(); } virtual shared_ptr< CoveredIndexMatcher > matcherPtr() const { retu rn shared_ptr< CoveredIndexMatcher >(); }
virtual bool currentMatches( MatchDetails *details = 0 ) {
return !matcher() || matcher()->matchesCurrent( this, details )
;
}
// A convenience function for setting the value of matcher() manual ly // A convenience function for setting the value of matcher() manual ly
// so it may accessed later. Implementations which must generate // so it may accessed later. Implementations which must generate
// their own matcher() should assert here. // their own matcher() should assert here.
virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) { virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) {
massert( 13285, "manual matcher config not allowed", false ); massert( 13285, "manual matcher config not allowed", false );
} }
virtual void explainDetails( BSONObjBuilder& b ) { return; } virtual void explainDetails( BSONObjBuilder& b ) { return; }
}; };
 End of changes. 5 change blocks. 
1 lines changed or deleted 27 lines changed or added


 cursors.h   cursors.h 
skipping to change at line 101 skipping to change at line 101
void doTimeouts(); void doTimeouts();
void startTimeoutThread(); void startTimeoutThread();
private: private:
mutable mongo::mutex _mutex; mutable mongo::mutex _mutex;
MapSharded _cursors; MapSharded _cursors;
MapNormal _refs; MapNormal _refs;
long long _shardedTotal; long long _shardedTotal;
static int _myLogLevel; static const int _myLogLevel;
}; };
extern CursorCache cursorCache; extern CursorCache cursorCache;
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 d_logic.h   d_logic.h 
skipping to change at line 33 skipping to change at line 33
#include "d_chunk_manager.h" #include "d_chunk_manager.h"
#include "util.h" #include "util.h"
namespace mongo { namespace mongo {
class Database; class Database;
class DiskLoc; class DiskLoc;
typedef ShardChunkVersion ConfigVersion; typedef ShardChunkVersion ConfigVersion;
typedef map<string,ConfigVersion> NSVersionMap;
// -------------- // --------------
// --- global state --- // --- global state ---
// -------------- // --------------
class ShardingState { class ShardingState {
public: public:
ShardingState(); ShardingState();
bool enabled() const { return _enabled; } bool enabled() const { return _enabled; }
const string& getConfigServer() const { return _configServer; } const string& getConfigServer() const { return _configServer; }
void enable( const string& server ); void enable( const string& server );
void gotShardName( const string& name ); void gotShardName( const string& name );
void gotShardHost( string host ); void gotShardHost( string host );
string getShardName() { return _shardName; }
string getShardHost() { return _shardHost; }
/** Reverts back to a state where this mongod is not sharded. */ /** Reverts back to a state where this mongod is not sharded. */
void resetShardingState(); void resetShardingState();
// versioning support // versioning support
bool hasVersion( const string& ns ); bool hasVersion( const string& ns );
bool hasVersion( const string& ns , ConfigVersion& version ); bool hasVersion( const string& ns , ConfigVersion& version );
const ConfigVersion getVersion( const string& ns ) const; const ConfigVersion getVersion( const string& ns ) const;
/** /**
skipping to change at line 149 skipping to change at line 151
private: private:
bool _enabled; bool _enabled;
string _configServer; string _configServer;
string _shardName; string _shardName;
string _shardHost; string _shardHost;
// protects state below // protects state below
mutable mongo::mutex _mutex; mutable mongo::mutex _mutex;
// protects accessing the config server
// Using a ticket holder so we can have multiple redundant tries at
any given time
mutable TicketHolder _configServerTickets;
// map from a namespace into the ensemble of chunk ranges that are stored in this mongod // map from a namespace into the ensemble of chunk ranges that are stored in this mongod
// a ShardChunkManager carries all state we need for a collection a t this shard, including its version information // a ShardChunkManager carries all state we need for a collection a t this shard, including its version information
typedef map<string,ShardChunkManagerPtr> ChunkManagersMap; typedef map<string,ShardChunkManagerPtr> ChunkManagersMap;
ChunkManagersMap _chunks; ChunkManagersMap _chunks;
}; };
extern ShardingState shardingState; extern ShardingState shardingState;
/** /**
skipping to change at line 190 skipping to change at line 189
bool inForceVersionOkMode() const { bool inForceVersionOkMode() const {
return _forceVersionOk; return _forceVersionOk;
} }
void enterForceVersionOkMode() { _forceVersionOk = true; } void enterForceVersionOkMode() { _forceVersionOk = true; }
void leaveForceVersionOkMode() { _forceVersionOk = false; } void leaveForceVersionOkMode() { _forceVersionOk = false; }
private: private:
OID _id; OID _id;
NSVersionMap _versions;
bool _forceVersionOk; // if this is true, then chunk version #s are n't check, and all ops are allowed bool _forceVersionOk; // if this is true, then chunk version #s are n't check, and all ops are allowed
typedef map<string,ConfigVersion> NSVersionMap;
NSVersionMap _versions;
static boost::thread_specific_ptr<ShardedConnectionInfo> _tl; static boost::thread_specific_ptr<ShardedConnectionInfo> _tl;
}; };
struct ShardForceVersionOkModeBlock { struct ShardForceVersionOkModeBlock {
ShardForceVersionOkModeBlock() { ShardForceVersionOkModeBlock() {
info = ShardedConnectionInfo::get( false ); info = ShardedConnectionInfo::get( false );
if ( info ) if ( info )
info->enterForceVersionOkMode(); info->enterForceVersionOkMode();
} }
~ShardForceVersionOkModeBlock() { ~ShardForceVersionOkModeBlock() {
 End of changes. 5 change blocks. 
6 lines changed or deleted 6 lines changed or added


 database.h   database.h 
skipping to change at line 22 skipping to change at line 22
* 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" #include "cmdline.h"
#include "namespace.h"
namespace mongo { namespace mongo {
class Extent;
class MongoDataFile;
class ClientCursor; class ClientCursor;
struct ByLocKey; struct ByLocKey;
typedef map<ByLocKey, ClientCursor*> CCByLoc; typedef map<ByLocKey, ClientCursor*> CCByLoc;
/** /**
* 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, ...
* NOT memory mapped * NOT memory mapped
*/ */
class Database { class Database {
public: public:
static bool _openAllFiles; static bool _openAllFiles;
// you probably need to be in dbHolderMutex when constructing this
Database(const char *nm, /*out*/ bool& newDb, const string& _path = dbpath); Database(const char *nm, /*out*/ bool& newDb, const string& _path = dbpath);
private: private:
~Database(); ~Database(); // closes files and other cleanup see below.
public: public:
/* you must use this to close - there is essential code in this met hod that is not in the ~Database destructor. /* you must use this to close - there is essential code in this met hod that is not in the ~Database destructor.
thus the destructor is private. this could be cleaned up one da y... thus the destructor is private. this could be cleaned up one da y...
*/ */
static void closeDatabase( const char *db, const string& path ); static void closeDatabase( const char *db, const string& path );
void openAllFiles(); void openAllFiles();
/** /**
* tries to make sure that this hasn't been deleted * tries to make sure that this hasn't been deleted
*/ */
bool isOk() const { return magic == 781231; } bool isOk() const { return magic == 781231; }
bool isEmpty() { return ! namespaceIndex.allocated(); } bool isEmpty() { return ! namespaceIndex.allocated(); }
/** /**
* total file size of Database in bytes * total file size of Database in bytes
*/ */
long long fileSize() const; long long fileSize() const;
int numFiles() const { return (int)files.size(); } int numFiles() const;
/** /**
* returns file valid for file number n * returns file valid for file number n
*/ */
boost::filesystem::path fileName( int n ) const; boost::filesystem::path fileName( int n ) const;
bool exists(int n) const { return boost::filesystem::exists( fileNa private:
me( n ) ); } bool exists(int n) const;
bool openExistingFile( int n );
public:
/** /**
* return file n. if it doesn't exist, create it * return file n. if it doesn't exist, create it
*/ */
MongoDataFile* getFile( int n, int sizeNeeded = 0, bool preallocate Only = false ); MongoDataFile* getFile( int n, int sizeNeeded = 0, bool preallocate Only = false );
MongoDataFile* addAFile( int sizeNeeded, bool preallocateNextFile ) ; MongoDataFile* addAFile( int sizeNeeded, bool preallocateNextFile ) ;
/** /**
* makes sure we have an extra file at the end that is empty * makes sure we have an extra file at the end that is empty
* safe to call this multiple times - the implementation will only preallocate one file * safe to call this multiple times - the implementation will only preallocate one file
skipping to change at line 94 skipping to change at line 101
Extent* allocExtent( const char *ns, int size, bool capped, bool en forceQuota ); Extent* allocExtent( const char *ns, int size, bool capped, bool en forceQuota );
MongoDataFile* newestFile(); MongoDataFile* newestFile();
/** /**
* @return true if success. false if bad level or error creating p rofile ns * @return true if success. false if bad level or error creating p rofile ns
*/ */
bool setProfilingLevel( int newLevel , string& errmsg ); bool setProfilingLevel( int newLevel , string& errmsg );
void flushFiles( bool sync ) const; void flushFiles( bool sync );
/** /**
* @return true if ns is part of the database * @return true if ns is part of the database
* ns=foo.bar, db=foo returns true * ns=foo.bar, db=foo returns true
*/ */
bool ownsNS( const string& ns ) const { bool ownsNS( const string& ns ) const {
if ( ! startsWith( ns , name ) ) if ( ! startsWith( ns , name ) )
return false; return false;
return ns[name.size()] == '.'; return ns[name.size()] == '.';
} }
private:
static bool validDBName( const string& ns );
/** /**
* @throws DatabaseDifferCaseCode if the name is a duplicate based on * @throws DatabaseDifferCaseCode if the name is a duplicate based on
* case insensitive matching. * case insensitive matching.
*/ */
void checkDuplicateUncasedNames() const; void checkDuplicateUncasedNames(bool inholderlockalready) const;
public:
/** /**
* @return name of an existing database with same text name but dif ferent * @return name of an existing database with same text name but dif ferent
* casing, if one exists. Otherwise the empty string is returned. If * casing, if one exists. Otherwise the empty string is returned. If
* 'duplicates' is specified, it is filled with all duplicate names . * 'duplicates' is specified, it is filled with all duplicate names .
*/ */
static string duplicateUncasedName( const string &name, const strin g &path, set< string > *duplicates = 0 ); static string duplicateUncasedName( bool inholderlockalready, const string &name, const string &path, set< string > *duplicates = 0 );
public: // this should be private later
vector<MongoDataFile*> files;
const string name; // "alleyinsider" const string name; // "alleyinsider"
const string path; const string path;
private:
// must be in the dbLock when touching this (and write locked when
writing to of course)
// however during Database object construction we aren't, which is
ok as it isn't yet visible
// to others and we are in the dbholder lock then.
vector<MongoDataFile*> _files;
public: // this should be private later
NamespaceIndex namespaceIndex; NamespaceIndex namespaceIndex;
int profile; // 0=off. int profile; // 0=off.
const string profileName; // "alleyinsider.system.profile" const string profileName; // "alleyinsider.system.profile"
CCByLoc ccByLoc; CCByLoc ccByLoc;
int magic; // used for making sure the object is still loaded in me mory int magic; // used for making sure the object is still loaded in me mory
}; };
} // namespace mongo } // namespace mongo
 End of changes. 13 change blocks. 
14 lines changed or deleted 27 lines changed or added


 db.h   db.h 
skipping to change at line 21 skipping to change at line 21
* 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 "../pch.h" #include "../pch.h"
#include "../util/net/message.h" #include "../util/net/message.h"
#include "concurrency.h" #include "mongomutex.h"
#include "pdfile.h" #include "pdfile.h"
#include "curop.h" #include "curop.h"
#include "client.h" #include "client.h"
#include "databaseholder.h"
namespace mongo { namespace mongo {
// void jniCallback(Message& m, Message& out);
/**
* class to hold path + dbname -> Database
* might be able to optimizer further
*/
class DatabaseHolder {
public:
typedef map<string,Database*> DBs;
typedef map<string,DBs> Paths;
DatabaseHolder() : _size(0) { }
bool isLoaded( const string& ns , const string& path ) const {
dbMutex.assertAtLeastReadLocked();
Paths::const_iterator x = _paths.find( path );
if ( x == _paths.end() )
return false;
const DBs& m = x->second;
string db = _todb( ns );
DBs::const_iterator it = m.find(db);
return it != m.end();
}
Database * get( const string& ns , const string& path ) const {
dbMutex.assertAtLeastReadLocked();
Paths::const_iterator x = _paths.find( path );
if ( x == _paths.end() )
return 0;
const DBs& m = x->second;
string db = _todb( ns );
DBs::const_iterator it = m.find(db);
if ( it != m.end() )
return it->second;
return 0;
}
void put( const string& ns , const string& path , Database * db ) {
dbMutex.assertWriteLocked();
DBs& m = _paths[path];
Database*& d = m[_todb(ns)];
if ( ! d )
_size++;
d = db;
}
Database* getOrCreate( const string& ns , const string& path , bool
& justCreated );
void erase( const string& ns , const string& path ) {
dbMutex.assertWriteLocked();
DBs& m = _paths[path];
_size -= (int)m.erase( _todb( ns ) );
}
/* force - force close even if something underway - use at shutdown
*/
bool closeAll( const string& path , BSONObjBuilder& result, bool fo
rce );
int size() {
return _size;
}
void forEach(boost::function<void(Database *)> f) const {
dbMutex.assertAtLeastReadLocked();
for ( Paths::const_iterator i=_paths.begin(); i!=_paths.end();
i++ ) {
DBs m = i->second;
for( DBs::const_iterator j=m.begin(); j!=m.end(); j++ ) {
f(j->second);
}
}
}
/**
* gets all unique db names, ignoring paths
*/
void getAllShortNames( set<string>& all ) const {
dbMutex.assertAtLeastReadLocked();
for ( Paths::const_iterator i=_paths.begin(); i!=_paths.end();
i++ ) {
DBs m = i->second;
for( DBs::const_iterator j=m.begin(); j!=m.end(); j++ ) {
all.insert( j->first );
}
}
}
private:
string _todb( const string& ns ) const {
string d = __todb( ns );
uassert( 13280 , (string)"invalid db name: " + ns , Database::v
alidDBName( d ) );
return d;
}
string __todb( const string& ns ) const {
size_t i = ns.find( '.' );
if ( i == string::npos ) {
uassert( 13074 , "db name can't be empty" , ns.size() );
return ns;
}
uassert( 13075 , "db name can't be empty" , i > 0 );
return ns.substr( 0 , i );
}
Paths _paths;
int _size;
};
extern DatabaseHolder dbHolder;
struct dbtemprelease { struct dbtemprelease {
Client::Context * _context; Client::Context * _context;
int _locktype; int _locktype;
dbtemprelease() { dbtemprelease() {
const Client& c = cc(); const Client& c = cc();
_context = c.getContext(); _context = c.getContext();
_locktype = dbMutex.getState(); _locktype = d.dbMutex.getState();
assert( _locktype ); assert( _locktype );
if ( _locktype > 0 ) { if ( _locktype > 0 ) {
massert( 10298 , "can't temprelease nested write lock", _lo cktype == 1); massert( 10298 , "can't temprelease nested write lock", _lo cktype == 1);
if ( _context ) _context->unlocked(); if ( _context ) _context->unlocked();
dbMutex.unlock(); d.dbMutex.unlock();
} }
else { else {
massert( 10299 , "can't temprelease nested read lock", _loc ktype == -1); massert( 10299 , "can't temprelease nested read lock", _loc ktype == -1);
if ( _context ) _context->unlocked(); if ( _context ) _context->unlocked();
dbMutex.unlock_shared(); d.dbMutex.unlock_shared();
} }
verify( 14814 , c.curop() ); verify( 14814 , c.curop() );
c.curop()->yielded(); c.curop()->yielded();
} }
~dbtemprelease() { ~dbtemprelease() {
if ( _locktype > 0 ) if ( _locktype > 0 )
dbMutex.lock(); d.dbMutex.lock();
else else
dbMutex.lock_shared(); d.dbMutex.lock_shared();
if ( _context ) _context->relocked(); if ( _context ) _context->relocked();
} }
}; };
/** must be write locked /** must be write locked
no assert (and no release) if nested write lock no assert (and no release) if nested write lock
a lot like dbtempreleasecond but no malloc so should be a tiny bit faster a lot like dbtempreleasecond but no malloc so should be a tiny bit faster
*/ */
struct dbtempreleasewritelock { struct dbtempreleasewritelock {
Client::Context * _context; Client::Context * _context;
int _locktype; int _locktype;
dbtempreleasewritelock() { dbtempreleasewritelock() {
const Client& c = cc(); const Client& c = cc();
_context = c.getContext(); _context = c.getContext();
_locktype = dbMutex.getState(); _locktype = d.dbMutex.getState();
assert( _locktype >= 1 ); assert( _locktype >= 1 );
if( _locktype > 1 ) if( _locktype > 1 )
return; // nested return; // nested
if ( _context ) if ( _context )
_context->unlocked(); _context->unlocked();
dbMutex.unlock(); d.dbMutex.unlock();
verify( 14845 , c.curop() ); verify( 14845 , c.curop() );
c.curop()->yielded(); c.curop()->yielded();
} }
~dbtempreleasewritelock() { ~dbtempreleasewritelock() {
if ( _locktype == 1 ) if ( _locktype == 1 )
dbMutex.lock(); d.dbMutex.lock();
if ( _context ) if ( _context )
_context->relocked(); _context->relocked();
} }
}; };
/** /**
only does a temp release if we're not nested and have a lock only does a temp release if we're not nested and have a lock
*/ */
struct dbtempreleasecond { struct dbtempreleasecond {
dbtemprelease * real; dbtemprelease * real;
int locktype; int locktype;
dbtempreleasecond() { dbtempreleasecond() {
real = 0; real = 0;
locktype = dbMutex.getState(); locktype = d.dbMutex.getState();
if ( locktype == 1 || locktype == -1 ) if ( locktype == 1 || locktype == -1 )
real = new dbtemprelease(); real = new dbtemprelease();
} }
~dbtempreleasecond() { ~dbtempreleasecond() {
if ( real ) { if ( real ) {
delete real; delete real;
real = 0; real = 0;
} }
} }
bool unlocked() { bool unlocked() {
return real > 0; return real != 0;
} }
}; };
} // namespace mongo } // namespace mongo
//#include "dbinfo.h"
#include "concurrency.h"
 End of changes. 14 change blocks. 
130 lines changed or deleted 12 lines changed or added


 dbclient.h   dbclient.h 
skipping to change at line 28 skipping to change at line 28
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "../util/net/message.h" #include "../util/net/message.h"
#include "../util/net/message_port.h" #include "../util/net/message_port.h"
#include "../db/jsobj.h" #include "../db/jsobj.h"
#include "../db/json.h" #include "../db/json.h"
#include "../db/security.h"
#include <stack> #include <stack>
namespace mongo { namespace mongo {
/** the query field 'options' can have these bits set: */ /** the query field 'options' can have these bits set: */
enum QueryOptions { enum QueryOptions {
/** Tailable means cursor is not closed when the last data is retri eved. rather, the cursor marks /** Tailable means cursor is not closed when the last data is retri eved. rather, the cursor marks
the final object's position. you can resume using the cursor la ter, from where it was located, the final object's position. you can resume using the cursor la ter, from where it was located,
if more data were received. Set on dbQuery and dbGetMore. if more data were received. Set on dbQuery and dbGetMore.
skipping to change at line 334 skipping to change at line 335
template< class T > template< class T >
void appendComplex( const char *fieldName, const T& val ) { void appendComplex( const char *fieldName, const T& val ) {
makeComplex(); makeComplex();
BSONObjBuilder b; BSONObjBuilder b;
b.appendElements(obj); b.appendElements(obj);
b.append(fieldName, val); b.append(fieldName, val);
obj = b.obj(); obj = b.obj();
} }
}; };
/**
* Represents a full query description, including all options required
for the query to be passed on
* to other hosts
*/
class QuerySpec {
string _ns;
int _ntoskip;
int _ntoreturn;
int _options;
BSONObj _query;
BSONObj _fields;
Query _queryObj;
public:
QuerySpec( const string& ns,
const BSONObj& query, const BSONObj& fields,
int ntoskip, int ntoreturn, int options )
: _ns( ns ), _ntoskip( ntoskip ), _ntoreturn( ntoreturn ), _opt
ions( options ),
_query( query.getOwned() ), _fields( fields.getOwned() ) , _q
ueryObj( _query ) {
}
QuerySpec() {}
bool isEmpty() const { return _ns.size() == 0; }
bool isExplain() const { return _queryObj.isExplain(); }
BSONObj filter() const { return _queryObj.getFilter(); }
BSONObj hint() const { return _queryObj.getHint(); }
BSONObj sort() const { return _queryObj.getSort(); }
BSONObj query() const { return _query; }
BSONObj fields() const { return _fields; }
BSONObj* fieldsData() { return &_fields; }
// don't love this, but needed downstrem
const BSONObj* fieldsPtr() const { return &_fields; }
string ns() const { return _ns; }
int ntoskip() const { return _ntoskip; }
int ntoreturn() const { return _ntoreturn; }
int options() const { return _options; }
void setFields( BSONObj& o ) { _fields = o.getOwned(); }
string toString() const {
return str::stream() << "QSpec " <<
BSON( "ns" << _ns << "n2skip" << _ntoskip << "n2return" <<
_ntoreturn << "options" << _options
<< "query" << _query << "fields" << _fields );
}
};
/** Typically one uses the QUERY(...) macro to construct a Query object . /** Typically one uses the QUERY(...) macro to construct a Query object .
Example: QUERY( "age" << 33 << "school" << "UCLA" ) Example: QUERY( "age" << 33 << "school" << "UCLA" )
*/ */
#define QUERY(x) mongo::Query( BSON(x) ) #define QUERY(x) mongo::Query( BSON(x) )
// Useful utilities for namespaces
/** @return the database name portion of an ns string */
string nsGetDB( const string &ns );
/** @return the collection name portion of an ns string */
string nsGetCollection( const string &ns );
/** /**
interface that handles communication with the db interface that handles communication with the db
*/ */
class DBConnector { class DBConnector {
public: public:
virtual ~DBConnector() {} virtual ~DBConnector() {}
/** actualServer is set to the actual server where they call went i f there was a choice (SlaveOk) */ /** actualServer is set to the actual server where they call went i f there was a choice (SlaveOk) */
virtual bool call( Message &toSend, Message &response, bool assertO k=true , string * actualServer = 0 ) = 0; virtual bool call( Message &toSend, Message &response, bool assertO k=true , string * actualServer = 0 ) = 0;
virtual void say( Message &toSend, bool isRetry = false ) = 0; virtual void say( Message &toSend, bool isRetry = false , string * actualServer = 0 ) = 0;
virtual void sayPiggyBack( Message &toSend ) = 0; virtual void sayPiggyBack( Message &toSend ) = 0;
/* used by QueryOption_Exhaust. To use that your subclass must imp lement this. */ /* used by QueryOption_Exhaust. To use that your subclass must imp lement this. */
virtual bool recv( Message& m ) { assert(false); return false; } virtual bool recv( Message& m ) { assert(false); return false; }
// In general, for lazy queries, we'll need to say, recv, then chec kResponse // In general, for lazy queries, we'll need to say, recv, then chec kResponse
virtual void checkResponse( const char* data, int nReturned, bool* retry = NULL, string* targetHost = NULL ) { virtual void checkResponse( const char* data, int nReturned, bool* retry = NULL, string* targetHost = NULL ) {
if( retry ) *retry = false; if( targetHost ) *targetHost = ""; if( retry ) *retry = false; if( targetHost ) *targetHost = "";
} }
virtual bool lazySupported() const = 0; virtual bool lazySupported() const = 0;
}; };
skipping to change at line 431 skipping to change at line 493
@param options see enum QueryOptions - normally not needed to r un a command @param options see enum QueryOptions - normally not needed to r un a command
@return true if the command returned "ok". @return true if the command returned "ok".
*/ */
virtual bool runCommand(const string &dbname, const BSONObj& cmd, B SONObj &info, int options=0); virtual bool runCommand(const string &dbname, const BSONObj& cmd, B SONObj &info, int options=0);
/** Authorize access to a particular database. /** Authorize access to a particular database.
Authentication is separate for each database on the server -- y ou may authenticate for any Authentication is separate for each database on the server -- y ou may authenticate for any
number of databases on a single connection. number of databases on a single connection.
The "admin" database is special and once authenticated provides access to all databases on the The "admin" database is special and once authenticated provides access to all databases on the
server. server.
@param digestPassword if password is plain text, set this to tr @param digestPassword if password is plain text, set this
ue. otherwise assumed to be pre-digested to true. otherwise assumed to be pre-digested
@param[out] authLevel level of authentication for the giv
en user
@return true if successful @return true if successful
*/ */
virtual bool auth(const string &dbname, const string &username, con st string &pwd, string& errmsg, bool digestPassword = true); virtual bool auth(const string &dbname, const string &username, con st string &pwd, string& errmsg, bool digestPassword = true, Auth::Level * l evel = NULL);
/** count number of objects in collection ns that match the query c riteria specified /** count number of objects in collection ns that match the query c riteria specified
throws UserAssertion if database returns an error throws UserAssertion if database returns an error
*/ */
virtual unsigned long long count(const string &ns, const BSONObj& q uery = BSONObj(), int options=0, int limit=0, int skip=0 ); virtual unsigned long long count(const string &ns, const BSONObj& q uery = BSONObj(), int options=0, int limit=0, int skip=0 );
string createPasswordDigest( const string &username , const string &clearTextPassword ); string createPasswordDigest( const string &username , const string &clearTextPassword );
/** returns true in isMaster parm if this db is the current master /** returns true in isMaster parm if this db is the current master
of a replica pair. of a replica pair.
skipping to change at line 474 skipping to change at line 537
@param capped if true, this is a fixed size collection (where ol d data rolls out). @param capped if true, this is a fixed size collection (where ol d data rolls out).
@param max maximum number of objects if capped (optional). @param max maximum number of objects if capped (optional).
returns true if successful. returns true if successful.
*/ */
bool createCollection(const string &ns, long long size = 0, bool ca pped = false, int max = 0, BSONObj *info = 0); bool createCollection(const string &ns, long long size = 0, bool ca pped = false, int max = 0, BSONObj *info = 0);
/** Get error result from the last write operation (insert/update/d elete) on this connection. /** Get error result from the last write operation (insert/update/d elete) on this connection.
@return error message text, or empty string if no error. @return error message text, or empty string if no error.
*/ */
string getLastError(); string getLastError(bool fsync = false, bool j = false, int w = 0, int wtimeout = 0);
/** Get error result from the last write operation (insert/update/d elete) on this connection. /** Get error result from the last write operation (insert/update/d elete) on this connection.
@return full error object. @return full error object.
If "w" is -1, wait for propagation to majority of nodes.
If "wtimeout" is 0, the operation will block indefinitely if ne
eded.
*/ */
virtual BSONObj getLastErrorDetailed(); virtual BSONObj getLastErrorDetailed(bool fsync = false, bool j = f alse, int w = 0, int wtimeout = 0);
/** Can be called with the returned value from getLastErrorDetailed to extract an error string. /** Can be called with the returned value from getLastErrorDetailed to extract an error string.
If all you need is the string, just call getLastError() instead . If all you need is the string, just call getLastError() instead .
*/ */
static string getLastErrorString( const BSONObj& res ); static string getLastErrorString( const BSONObj& res );
/** Return the last error which has occurred, even if not the very last operation. /** Return the last error which has occurred, even if not the very last operation.
@return { err : <error message>, nPrev : <how_many_ops_back_occu rred>, ok : 1 } @return { err : <error message>, nPrev : <how_many_ops_back_occu rred>, ok : 1 }
skipping to change at line 703 skipping to change at line 769
/** Erase / drop an entire database */ /** Erase / drop an entire database */
virtual bool dropDatabase(const string &dbname, BSONObj *info = 0) { virtual bool dropDatabase(const string &dbname, BSONObj *info = 0) {
bool ret = simpleCommand(dbname, info, "dropDatabase"); bool ret = simpleCommand(dbname, info, "dropDatabase");
resetIndexCache(); resetIndexCache();
return ret; return ret;
} }
virtual string toString() = 0; virtual string toString() = 0;
/** @return the database name portion of an ns string */
string nsGetDB( const string &ns ) {
string::size_type pos = ns.find( "." );
if ( pos == string::npos )
return ns;
return ns.substr( 0 , pos );
}
/** @return the collection name portion of an ns string */
string nsGetCollection( const string &ns ) {
string::size_type pos = ns.find( "." );
if ( pos == string::npos )
return "";
return ns.substr( pos + 1 );
}
protected: protected:
/** if the result of a command is ok*/ /** if the result of a command is ok*/
bool isOk(const BSONObj&); bool isOk(const BSONObj&);
/** if the element contains a not master error */ /** if the element contains a not master error */
bool isNotMasterErrorString( const BSONElement& e ); bool isNotMasterErrorString( const BSONElement& e );
BSONObj _countCmd(const string &ns, const BSONObj& query, int optio ns, int limit, int skip ); BSONObj _countCmd(const string &ns, const BSONObj& query, int optio ns, int limit, int skip );
enum QueryOptions availableOptions(); enum QueryOptions availableOptions();
skipping to change at line 880 skipping to change at line 928
false was returned -- it will try to connect again. false was returned -- it will try to connect again.
@param serverHostname host to connect to. can include port numb er ( 127.0.0.1 , 127.0.0.1:5555 ) @param serverHostname host to connect to. can include port numb er ( 127.0.0.1 , 127.0.0.1:5555 )
*/ */
void connect(const string& serverHostname) { void connect(const string& serverHostname) {
string errmsg; string errmsg;
if( !connect(HostAndPort(serverHostname), errmsg) ) if( !connect(HostAndPort(serverHostname), errmsg) )
throw ConnectException(string("can't connect ") + errmsg); throw ConnectException(string("can't connect ") + errmsg);
} }
virtual bool auth(const string &dbname, const string &username, con st string &pwd, string& errmsg, bool digestPassword = true); virtual bool auth(const string &dbname, const string &username, con st string &pwd, string& errmsg, bool digestPassword = true, Auth::Level* le vel=NULL);
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y=Query(), int nToReturn = 0, int nToSkip = 0, virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y=Query(), int nToReturn = 0, int nToSkip = 0,
const BSONObj *fieldsToRetur n = 0, int queryOptions = 0 , int batchSize = 0 ) { const BSONObj *fieldsToRetur n = 0, int queryOptions = 0 , int batchSize = 0 ) {
checkConnection(); checkConnection();
return DBClientBase::query( ns, query, nToReturn, nToSkip, fiel dsToReturn, queryOptions , batchSize ); return DBClientBase::query( ns, query, nToReturn, nToSkip, fiel dsToReturn, queryOptions , batchSize );
} }
/** Uses QueryOption_Exhaust /** Uses QueryOption_Exhaust
Exhaust mode sends back all data queries as fast as possible, w ith no back-and-for for OP_GETMORE. If you are certain Exhaust mode sends back all data queries as fast as possible, w ith no back-and-for for OP_GETMORE. If you are certain
you will exhaust the query, it could be useful. you will exhaust the query, it could be useful.
skipping to change at line 921 skipping to change at line 969
return ss.str(); return ss.str();
} }
/** Returns the address of the server */ /** Returns the address of the server */
string toString() { return _serverString; } string toString() { return _serverString; }
string getServerAddress() const { return _serverString; } string getServerAddress() const { return _serverString; }
virtual void killCursor( long long cursorID ); virtual void killCursor( long long cursorID );
virtual bool callRead( Message& toSend , Message& response ) { retu rn call( toSend , response ); } virtual bool callRead( Message& toSend , Message& response ) { retu rn call( toSend , response ); }
virtual void say( Message &toSend, bool isRetry = false ); virtual void say( Message &toSend, bool isRetry = false , string * actualServer = 0 );
virtual bool recv( Message& m ); virtual bool recv( Message& m );
virtual void checkResponse( const char *data, int nReturned, bool* retry = NULL, string* host = NULL ); virtual void checkResponse( const char *data, int nReturned, bool* retry = NULL, string* host = NULL );
virtual bool call( Message &toSend, Message &response, bool assertO k = true , string * actualServer = 0 ); virtual bool call( Message &toSend, Message &response, bool assertO k = true , string * actualServer = 0 );
virtual ConnectionString::ConnectionType type() const { return Conn ectionString::MASTER; } virtual ConnectionString::ConnectionType type() const { return Conn ectionString::MASTER; }
void setSoTimeout(double to) { _so_timeout = to; } void setSoTimeout(double to) { _so_timeout = to; }
double getSoTimeout() const { return _so_timeout; } double getSoTimeout() const { return _so_timeout; }
virtual bool lazySupported() const { return true; } virtual bool lazySupported() const { return true; }
static int getNumConnections() { static int getNumConnections() {
skipping to change at line 977 skipping to change at line 1025
/** pings server to check if it's up /** pings server to check if it's up
*/ */
bool serverAlive( const string &uri ); bool serverAlive( const string &uri );
DBClientBase * createDirectClient(); DBClientBase * createDirectClient();
BSONElement getErrField( const BSONObj& result ); BSONElement getErrField( const BSONObj& result );
bool hasErrField( const BSONObj& result ); bool hasErrField( const BSONObj& result );
inline std::ostream& operator<<( std::ostream &s, const Query &q ) {
return s << q.toString();
}
} // namespace mongo } // namespace mongo
#include "dbclientcursor.h" #include "dbclientcursor.h"
#include "dbclient_rs.h" #include "dbclient_rs.h"
#include "undef_macros.h" #include "undef_macros.h"
 End of changes. 13 change blocks. 
26 lines changed or deleted 84 lines changed or added


 dbclient_rs.h   dbclient_rs.h 
skipping to change at line 108 skipping to change at line 108
private: private:
/** /**
* This populates a list of hosts from the list of seeds (discardin g the * This populates a list of hosts from the list of seeds (discardin g the
* seed list). * seed list).
* @param name set name * @param name set name
* @param servers seeds * @param servers seeds
*/ */
ReplicaSetMonitor( const string& name , const vector<HostAndPort>& servers ); ReplicaSetMonitor( const string& name , const vector<HostAndPort>& servers );
/**
* Checks all connections from the host list and sets the current
* master.
*
* @param checkAllSecondaries if set to false, stop immediately whe
n
* the master is found or when _master is not -1.
*/
void _check( bool checkAllSecondaries ); void _check( bool checkAllSecondaries );
/** /**
* Use replSetGetStatus command to make sure hosts in host list are up * Use replSetGetStatus command to make sure hosts in host list are up
* and readable. Sets Node::ok appropriately. * and readable. Sets Node::ok appropriately.
*/ */
void _checkStatus( const string& hostAddr ); void _checkStatus(DBClientConnection *conn);
/** /**
* Add array of hosts to host list. Doesn't do anything if hosts ar e * Add array of hosts to host list. Doesn't do anything if hosts ar e
* already in host list. * already in host list.
* @param hostList the list of hosts to add * @param hostList the list of hosts to add
* @param changed if new hosts were added * @param changed if new hosts were added
*/ */
void _checkHosts(const BSONObj& hostList, bool& changed); void _checkHosts(const BSONObj& hostList, bool& changed);
/** /**
* Updates host list. * Updates host list.
* Invariant: if nodesOffset is >= 0, _nodes[nodesOffset].conn shou * @param c the connection to check
ld be
* equal to conn.
*
* @param conn the connection to check
* @param maybePrimary OUT * @param maybePrimary OUT
* @param verbose * @param verbose
* @param nodesOffset - offset into _nodes array, -1 for not in it * @param nodesOffset - offset into _nodes array, -1 for not in it
* * @return if the connection is good
* @return true if the connection is good or false if invariant
* is broken
*/ */
bool _checkConnection( DBClientConnection* conn, string& maybePrima bool _checkConnection( DBClientConnection * c , string& maybePrimar
ry, y , bool verbose , int nodesOffset );
bool verbose, int nodesOffset );
string _getServerAddress_inlock() const; string _getServerAddress_inlock() const;
NodeDiff _getHostDiff_inlock( const BSONObj& hostList ); NodeDiff _getHostDiff_inlock( const BSONObj& hostList );
bool _shouldChangeHosts( const BSONObj& hostList, bool inlock ); bool _shouldChangeHosts( const BSONObj& hostList, bool inlock );
/**
* @return the index to _nodes corresponding to the server address.
*/
int _find( const string& server ) const ; int _find( const string& server ) const ;
int _find_inlock( const string& server ) const ; int _find_inlock( const string& server ) const ;
int _find( const HostAndPort& server ) const ;
/** mutable mongo::mutex _lock; // protects _nodes
* Checks whether the given connection matches the connection store
d in _nodes.
* Mainly used for sanity checking to confirm that nodeOffset still
* refers to the right connection after releasing and reacquiring
* a mutex.
*/
bool _checkConnMatch_inlock( DBClientConnection* conn, size_t nodeO
ffset ) const;
// protects _nodes and indices pointing to it (_master & _nextSlave
)
mutable mongo::mutex _lock;
/**
* "Synchronizes" the _checkConnection method. Should ideally be on
e mutex per
* connection object being used. The purpose of this lock is to mak
e sure that
* the reply from the connection the lock holder got is the actual
response
* to what it sent.
*
* Deadlock WARNING: never acquire this while holding _lock
*/
mutable mongo::mutex _checkConnectionLock; mutable mongo::mutex _checkConnectionLock;
string _name; string _name;
// note these get copied around in the nodes vector so be sure to m
aintain copyable semantics here
struct Node { struct Node {
Node( const HostAndPort& a , DBClientConnection* c ) Node( const HostAndPort& a , DBClientConnection* c )
: addr( a ) , conn(c) , ok( c != NULL ), : addr( a ) , conn(c) , ok(true) ,
ismaster(false), secondary( false ) , hidden( false ) , p ingTimeMillis(0) { ismaster(false), secondary( false ) , hidden( false ) , p ingTimeMillis(0) {
ok = conn.get() == NULL;
} }
bool okForSecondaryQueries() const { bool okForSecondaryQueries() const {
return ok && secondary && ! hidden; return ok && secondary && ! hidden;
} }
BSONObj toBSON() const { BSONObj toBSON() const {
return BSON( "addr" << addr.toString() << return BSON( "addr" << addr.toString() <<
"isMaster" << ismaster << "isMaster" << ismaster <<
"secondary" << secondary << "secondary" << secondary <<
skipping to change at line 259 skipping to change at line 229
/** Returns false if nomember of the set were reachable, or neither is /** Returns false if nomember of the set were reachable, or neither is
* master, although, * master, although,
* when false returned, you can still try to use this connection ob ject, it will * when false returned, you can still try to use this connection ob ject, it will
* try reconnects. * try reconnects.
*/ */
bool connect(); bool connect();
/** Authorize. Authorizes all nodes as needed /** Authorize. Authorizes all nodes as needed
*/ */
virtual bool auth(const string &dbname, const string &username, con st string &pwd, string& errmsg, bool digestPassword = true ); virtual bool auth(const string &dbname, const string &username, con st string &pwd, string& errmsg, bool digestPassword = true, Auth::Level * l evel = NULL);
// ----------- simple functions -------------- // ----------- simple functions --------------
/** throws userassertion "no master found" */ /** throws userassertion "no master found" */
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 , int batchSize = 0 ); const BSONObj *fieldsToRetur n = 0, int queryOptions = 0 , int batchSize = 0 );
/** throws userassertion "no master found" */ /** throws userassertion "no master found" */
virtual BSONObj findOne(const string &ns, const Query& query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0); virtual BSONObj findOne(const string &ns, const Query& query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0);
skipping to change at line 289 skipping to change at line 259
virtual void killCursor( long long cursorID ); virtual void killCursor( long long cursorID );
// ---- access raw connections ---- // ---- access raw connections ----
DBClientConnection& masterConn(); DBClientConnection& masterConn();
DBClientConnection& slaveConn(); DBClientConnection& slaveConn();
// ---- callback pieces ------- // ---- callback pieces -------
virtual void say( Message &toSend, bool isRetry = false ); virtual void say( Message &toSend, bool isRetry = false , string* a ctualServer = 0);
virtual bool recv( Message &toRecv ); virtual bool recv( Message &toRecv );
virtual void checkResponse( const char* data, int nReturned, bool* retry = NULL, string* targetHost = NULL ); virtual void checkResponse( const char* data, int nReturned, bool* retry = NULL, string* targetHost = NULL );
/* this is the callback from our underlying connections to notify u s that we got a "not master" error. /* this is the callback from our underlying connections to notify u s that we got a "not master" error.
*/ */
void isntMaster(); void isntMaster();
/* this is used to indicate we got a "not master or secondary" erro r from a secondary. /* this is used to indicate we got a "not master or secondary" erro r from a secondary.
*/ */
void isntSecondary(); void isntSecondary();
 End of changes. 13 change blocks. 
51 lines changed or deleted 14 lines changed or added


 dbclientcursor.h   dbclientcursor.h 
skipping to change at line 30 skipping to change at line 30
#include "../pch.h" #include "../pch.h"
#include "../util/net/message.h" #include "../util/net/message.h"
#include "../db/jsobj.h" #include "../db/jsobj.h"
#include "../db/json.h" #include "../db/json.h"
#include <stack> #include <stack>
namespace mongo { namespace mongo {
class AScopedConnection; class AScopedConnection;
/** for mock purposes only -- do not create variants of DBClientCursor, /** for mock purposes only -- do not create variants of DBClientCursor,
nor hang code here */ nor hang code here
class DBClientCursorInterface { @see DBClientMockCursor
*/
class DBClientCursorInterface : boost::noncopyable {
public: public:
virtual ~DBClientCursorInterface() {} virtual ~DBClientCursorInterface() {}
virtual bool more() = 0; virtual bool more() = 0;
virtual BSONObj next() = 0; virtual BSONObj next() = 0;
// TODO bring more of the DBClientCursor interface to here // TODO bring more of the DBClientCursor interface to here
protected: protected:
DBClientCursorInterface() {} DBClientCursorInterface() {}
}; };
/** Queries return a cursor object */ /** Queries return a cursor object */
class DBClientCursor : public DBClientCursorInterface { class DBClientCursor : public DBClientCursorInterface {
public: public:
/** If true, safe to call next(). Requests more from server if nec essary. */ /** If true, safe to call next(). Requests more from server if nec essary. */
bool more(); bool more();
/** If true, there is more in our local buffers to be fetched via n ext(). Returns /** If true, there is more in our local buffers to be fetched via n ext(). Returns
false when a getMore request back to server would be required. You can use this false when a getMore request back to server would be required. You can use this
if you want to exhaust whatever data has been fetched to the cl ient already but if you want to exhaust whatever data has been fetched to the cl ient already but
then perhaps stop. then perhaps stop.
*/ */
int objsLeftInBatch() const { _assertIfNull(); return _putBack.size () + b.nReturned - b.pos; } int objsLeftInBatch() const { _assertIfNull(); return _putBack.size () + batch.nReturned - batch.pos; }
bool moreInCurrentBatch() { return objsLeftInBatch() > 0; } bool moreInCurrentBatch() { return objsLeftInBatch() > 0; }
/** next /** next
@return next object in the result cursor. @return next object in the result cursor.
on an error at the remote server, you will get back: on an error at the remote server, you will get back:
{ $err: <string> } { $err: <string> }
if you do not want to handle that yourself, call nextSafe(). if you do not want to handle that yourself, call nextSafe().
*/ */
BSONObj next(); BSONObj next();
skipping to change at line 90 skipping to change at line 89
return o; return o;
} }
/** peek ahead at items buffered for future next() calls. /** peek ahead at items buffered for future next() calls.
never requests new data from the server. so peek only effectiv e never requests new data from the server. so peek only effectiv e
with what is already buffered. with what is already buffered.
WARNING: no support for _putBack yet! WARNING: no support for _putBack yet!
*/ */
void peek(vector<BSONObj>&, int atMost); void peek(vector<BSONObj>&, int atMost);
// Peeks at first element, if exists
BSONObj peekFirst();
/** /**
* peek ahead and see if an error occurred, and get the error if so . * peek ahead and see if an error occurred, and get the error if so .
*/ */
bool peekError(BSONObj* error = NULL); bool peekError(BSONObj* error = NULL);
/** /**
iterate the rest of the cursor and return the number if items iterate the rest of the cursor and return the number if items
*/ */
int itcount() { int itcount() {
int c = 0; int c = 0;
skipping to change at line 139 skipping to change at line 141
query(_query), query(_query),
nToReturn(_nToReturn), nToReturn(_nToReturn),
haveLimit( _nToReturn > 0 && !(queryOptions & QueryOption_Curso rTailable)), haveLimit( _nToReturn > 0 && !(queryOptions & QueryOption_Curso rTailable)),
nToSkip(_nToSkip), nToSkip(_nToSkip),
fieldsToReturn(_fieldsToReturn), fieldsToReturn(_fieldsToReturn),
opts(queryOptions), opts(queryOptions),
batchSize(bs==1?2:bs), batchSize(bs==1?2:bs),
cursorId(), cursorId(),
_ownCursor( true ), _ownCursor( true ),
wasError( false ) { wasError( false ) {
_finishConsInit();
} }
DBClientCursor( DBClientBase* client, const string &_ns, long long _cursorId, int _nToReturn, int options ) : DBClientCursor( DBClientBase* client, const string &_ns, long long _cursorId, int _nToReturn, int options ) :
_client(client), _client(client),
ns(_ns), ns(_ns),
nToReturn( _nToReturn ), nToReturn( _nToReturn ),
haveLimit( _nToReturn > 0 && !(options & QueryOption_CursorTail able)), haveLimit( _nToReturn > 0 && !(options & QueryOption_CursorTail able)),
opts( options ), opts( options ),
cursorId(_cursorId), cursorId(_cursorId),
_ownCursor( true ) { _ownCursor( true ) {
_finishConsInit();
} }
virtual ~DBClientCursor(); virtual ~DBClientCursor();
long long getCursorId() const { return cursorId; } long long getCursorId() const { return cursorId; }
/** by default we "own" the cursor and will send the server a KillC ursor /** by default we "own" the cursor and will send the server a KillC ursor
message when ~DBClientCursor() is called. This function overrid es that. message when ~DBClientCursor() is called. This function overrid es that.
*/ */
void decouple() { _ownCursor = false; } void decouple() { _ownCursor = false; }
void attach( AScopedConnection * conn ); void attach( AScopedConnection * conn );
string originalHost() const { return _originalHost; }
Message* getMessage(){ return batch.m.get(); }
/** /**
* actually does the query * actually does the query
*/ */
bool init(); bool init();
void initLazy( bool isRetry = false ); void initLazy( bool isRetry = false );
bool initLazyFinish( bool& retry ); bool initLazyFinish( bool& retry );
class Batch : boost::noncopyable { class Batch : boost::noncopyable {
friend class DBClientCursor; friend class DBClientCursor;
skipping to change at line 185 skipping to change at line 193
const char *data; const char *data;
public: public:
Batch() : m( new Message() ), nReturned(), pos(), data() { } Batch() : m( new Message() ), nReturned(), pos(), data() { }
}; };
private: private:
friend class DBClientBase; friend class DBClientBase;
friend class DBClientConnection; friend class DBClientConnection;
int nextBatchSize(); int nextBatchSize();
void _finishConsInit();
Batch b; Batch batch;
DBClientBase* _client; DBClientBase* _client;
string _originalHost;
string ns; string ns;
BSONObj query; BSONObj query;
int nToReturn; int nToReturn;
bool haveLimit; bool haveLimit;
int nToSkip; int nToSkip;
const BSONObj *fieldsToReturn; const BSONObj *fieldsToReturn;
int opts; int opts;
int batchSize; int batchSize;
stack< BSONObj > _putBack; stack< BSONObj > _putBack;
int resultFlags; int resultFlags;
 End of changes. 12 change blocks. 
8 lines changed or deleted 18 lines changed or added


 dbhelpers.h   dbhelpers.h 
skipping to change at line 60 skipping to change at line 60
Note: does nothing if collection does not yet exist. Note: does nothing if collection does not yet exist.
*/ */
static void ensureIndex(const char *ns, BSONObj keyPattern, bool un ique, const char *name); static void ensureIndex(const char *ns, BSONObj keyPattern, bool un ique, const char *name);
/* 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 query - the query to perform. note this is the low level portion of query so "orderby : ..." @param query - the query to perform. note this is the low level portion of query so "orderby : ..."
won't work. won't work.
@param requireIndex if true, complain if no index for the query. a way to guard against @param requireIndex if true, assert 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, const BSONObj &query, BSONObj& result, bool requireIndex = false); static bool findOne(const char *ns, const BSONObj &query, BSONObj& result, bool requireIndex = false);
static DiskLoc findOne(const char *ns, const BSONObj &query, bool r equireIndex); static DiskLoc findOne(const char *ns, const BSONObj &query, bool r equireIndex);
/** /**
* @param foundIndex if passed in will be set to 1 if ns and index found * @param foundIndex if passed in will be set to 1 if ns and index found
* @return true if object found * @return true if object found
skipping to change at line 141 skipping to change at line 141
~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_;
}; };
/** /**
* user for saving deletd bson objects to a flat file * user for saving deleted bson objects to a flat file
*/ */
class RemoveSaver : public Helpers::RemoveCallback , boost::noncopyable { class RemoveSaver : public Helpers::RemoveCallback , boost::noncopyable {
public: public:
RemoveSaver( const string& type , const string& ns , const string& why); RemoveSaver( const string& type , const string& ns , const string& why);
~RemoveSaver(); ~RemoveSaver();
void goingToDelete( const BSONObj& o ); void goingToDelete( const BSONObj& o );
private: private:
path _root; boost::filesystem::path _root;
path _file; boost::filesystem::path _file;
ofstream* _out; ofstream* _out;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 3 change blocks. 
4 lines changed or deleted 4 lines changed or added


 diskloc.h   diskloc.h 
skipping to change at line 33 skipping to change at line 33
#pragma once #pragma once
#include "jsobj.h" #include "jsobj.h"
namespace mongo { namespace mongo {
class Record; class Record;
class DeletedRecord; class DeletedRecord;
class Extent; class Extent;
class MongoDataFile; class MongoDataFile;
class DiskLoc;
template< class Version > class BtreeBucket; template< class Version > class BtreeBucket;
#pragma pack(1) #pragma pack(1)
/** represents a disk location/offset on disk in a database. 64 bits. /** represents a disk location/offset on disk in a database. 64 bits.
it is assumed these will be passed around by value a lot so don't d o anything to make them large it is assumed these will be passed around by value a lot so don't d o anything to make them large
(such as adding a virtual function) (such as adding a virtual function)
*/ */
class DiskLoc { class DiskLoc {
int _a; // this will be volume, file #, etsc. but is a logical value could be anything depending on storage engine int _a; // this will be volume, file #, etsc. but is a logical value could be anything depending on storage engine
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 distlock.h   distlock.h 
skipping to change at line 74 skipping to change at line 74
* collection with that name. * collection with that name.
* *
* To be maintained, each taken lock needs to be revalidaded ("pinged") within a pre-established amount of time. This * To be maintained, each taken lock needs to be revalidaded ("pinged") within a pre-established amount of time. This
* class does this maintenance automatically once a DistributedLock obj ect was constructed. * class does this maintenance automatically once a DistributedLock obj ect was constructed.
*/ */
class DistributedLock { class DistributedLock {
public: public:
static LabeledLevel logLvl; static LabeledLevel logLvl;
typedef boost::tuple<string, Date_t, Date_t, OID> PingData; struct PingData {
PingData( const string& _id , Date_t _lastPing , Date_t _remote
, OID _ts )
: id(_id), lastPing(_lastPing), remote(_remote), ts(_ts){
}
PingData()
: id(""), lastPing(0), remote(0), ts(){
}
string id;
Date_t lastPing;
Date_t remote;
OID ts;
};
class LastPings { class LastPings {
public: public:
LastPings() : _mutex( "DistributedLock::LastPings" ) {} LastPings() : _mutex( "DistributedLock::LastPings" ) {}
~LastPings(){} ~LastPings(){}
PingData getLastPing( const ConnectionString& conn, const string & lockName ); PingData getLastPing( const ConnectionString& conn, const string & lockName );
void setLastPing( const ConnectionString& conn, const string& lo ckName, const PingData& pd ); void setLastPing( const ConnectionString& conn, const string& lo ckName, const PingData& pd );
mongo::mutex _mutex; mongo::mutex _mutex;
 End of changes. 1 change blocks. 
1 lines changed or deleted 16 lines changed or added


 dur.h   dur.h 
skipping to change at line 175 skipping to change at line 175
static DurableInterface* _impl; // NonDurableImpl at startup() static DurableInterface* _impl; // NonDurableImpl at startup()
static void enableDurability(); // makes _impl a DurableImpl static void enableDurability(); // makes _impl a DurableImpl
static void disableDurability(); // makes _impl a NonDurableImp l static void disableDurability(); // makes _impl a NonDurableImp l
// these need to be able to enable/disable Durability // these need to be able to enable/disable Durability
friend void startup(); friend void startup();
friend class TempDisableDurability; friend class TempDisableDurability;
}; // class DurableInterface }; // class DurableInterface
class NonDurableImpl : public DurableInterface { class NonDurableImpl : public DurableInterface {
void* writingPtr(void *x, unsigned len) { return x; } void* writingPtr(void *x, unsigned len);
void* writingAtOffset(void *buf, unsigned ofs, unsigned len) { return buf; } void* writingAtOffset(void *buf, unsigned ofs, unsigned len) { return buf; }
void* writingRangesAtOffsets(void *buf, const vector< pair< lon g long, unsigned > > &ranges) { return buf; } void* writingRangesAtOffsets(void *buf, const vector< pair< lon g long, unsigned > > &ranges) { return buf; }
void declareWriteIntent(void *, unsigned) { } void declareWriteIntent(void *, unsigned);
void createdFile(string filename, unsigned long long len) { } void createdFile(string filename, unsigned long long len) { }
bool awaitCommit() { return false; } bool awaitCommit() { return false; }
bool commitNow() { return false; } bool commitNow() { return false; }
bool commitIfNeeded() { return false; } bool commitIfNeeded() { return false; }
bool aCommitIsNeeded() const { return false; } bool aCommitIsNeeded() const { return false; }
void setNoJournal(void *dst, void *src, unsigned len); void setNoJournal(void *dst, void *src, unsigned len);
void syncDataAndTruncateJournal() {} void syncDataAndTruncateJournal() {}
}; };
class DurableImpl : public DurableInterface { class DurableImpl : public DurableInterface {
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 dur_commitjob.h   dur_commitjob.h 
skipping to change at line 92 skipping to change at line 92
public: public:
Already() { clear(); } Already() { clear(); }
void clear() { memset(this, 0, sizeof(*this)); } void clear() { memset(this, 0, sizeof(*this)); }
/* see if we have Already recorded/indicated our write intent f or this region of memory. /* see if we have Already recorded/indicated our write intent f or this region of memory.
automatically upgrades the length if the length was shorter previously. automatically upgrades the length if the length was shorter previously.
@return true if already indicated. @return true if already indicated.
*/ */
bool checkAndSet(void* p, int len) { bool checkAndSet(void* p, int len) {
unsigned x = mongoutils::hashPointer(p); unsigned x = mongoutils::hashPointer(p);
pair<void*, int> nd = nodes[x % N]; pair<void*, int>& nd = nodes[x % N];
if( nd.first == p ) { if( nd.first == p ) {
if( nd.second < len ) { if( nd.second < len ) {
nd.second = len; nd.second = len;
return false; // haven't indicated this len yet return false; // haven't indicated this len yet
} }
return true; // already indicated return true; // already indicated
} }
nd.first = p; nd.first = p;
nd.second = len; nd.second = len;
return false; // a new set return false; // a new set
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 dur_journalimpl.h   dur_journalimpl.h 
skipping to change at line 56 skipping to change at line 56
void journal(const JSectHeader& h, const AlignedBuilder& b); void journal(const JSectHeader& h, const AlignedBuilder& b);
boost::filesystem::path getFilePathFor(int filenumber) const; boost::filesystem::path getFilePathFor(int filenumber) const;
unsigned long long lastFlushTime() const { return _lastFlushTim e; } unsigned long long lastFlushTime() const { return _lastFlushTim e; }
void cleanup(bool log); // closes and removes journal files void cleanup(bool log); // closes and removes journal files
unsigned long long curFileId() const { return _curFileId; } unsigned long long curFileId() const { return _curFileId; }
void assureLogFileOpen() { void assureLogFileOpen() {
mutex::scoped_lock lk(_curLogFileMutex); SimpleMutex::scoped_lock lk(_curLogFileMutex);
if( _curLogFile == 0 ) if( _curLogFile == 0 )
_open(); _open();
} }
/** open a journal file to journal operations to. */ /** open a journal file to journal operations to. */
void open(); void open();
private: private:
/** check if time to rotate files. assure a file is open. /** check if time to rotate files. assure a file is open.
* internally called with every commit * internally called with every commit
*/ */
void _rotate(); void _rotate();
void _open(); void _open();
void closeCurrentJournalFile(); void closeCurrentJournalFile();
void removeUnneededJournalFiles(); void removeUnneededJournalFiles();
unsigned long long _written; // bytes written so far to the cur rent journal (log) file unsigned long long _written; // bytes written so far to the cur rent journal (log) file
unsigned _nextFileNumber; unsigned _nextFileNumber;
public: public:
mutex _curLogFileMutex; SimpleMutex _curLogFileMutex;
bool _ageOut; bool _ageOut;
private: private:
LogFile *_curLogFile; // use _curLogFileMutex LogFile *_curLogFile; // use _curLogFileMutex
unsigned long long _curFileId; // current file id see JHeader:: fileId unsigned long long _curFileId; // current file id see JHeader:: fileId
struct JFile { struct JFile {
string filename; string filename;
unsigned long long lastEventTimeMs; unsigned long long lastEventTimeMs;
}; };
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 dur_recover.h   dur_recover.h 
skipping to change at line 21 skipping to change at line 21
namespace dur { namespace dur {
struct ParsedJournalEntry; struct ParsedJournalEntry;
/** call go() to execute a recovery from existing journal files. /** call go() to execute a recovery from existing journal files.
*/ */
class RecoveryJob : boost::noncopyable { class RecoveryJob : boost::noncopyable {
public: public:
RecoveryJob() : _lastDataSyncedFromLastRun(0), RecoveryJob() : _lastDataSyncedFromLastRun(0),
_mx("recovery"), _recovering(false) { _lastSeqMentionedInCo nsoleLog = 1; } _mx("recovery"), _recovering(false) { _lastSeqMentionedInCo nsoleLog = 1; }
void go(vector<path>& files); void go(vector<boost::filesystem::path>& files);
~RecoveryJob(); ~RecoveryJob();
/** @param data data between header and footer. compressed if r ecovering. */ /** @param data data between header and footer. compressed if r ecovering. */
void processSection(const JSectHeader *h, const void *data, uns igned len, const JSectFooter *f); void processSection(const JSectHeader *h, const void *data, uns igned len, const JSectFooter *f);
void close(); // locks and calls _close() void close(); // locks and calls _close()
static RecoveryJob & get() { return _instance; } static RecoveryJob & get() { return _instance; }
private: private:
void write(const ParsedJournalEntry& entry); // actually writes to the file void write(const ParsedJournalEntry& entry); // actually writes to the file
void applyEntry(const ParsedJournalEntry& entry, bool apply, bo ol dump); void applyEntry(const ParsedJournalEntry& entry, bool apply, bo ol dump);
void applyEntries(const vector<ParsedJournalEntry> &entries); void applyEntries(const vector<ParsedJournalEntry> &entries);
bool processFileBuffer(const void *, unsigned len); bool processFileBuffer(const void *, unsigned len);
bool processFile(path journalfile); bool processFile(boost::filesystem::path journalfile);
void _close(); // doesn't lock void _close(); // doesn't lock
list<boost::shared_ptr<MongoMMF> > _mmfs; list<boost::shared_ptr<MongoMMF> > _mmfs;
unsigned long long _lastDataSyncedFromLastRun; unsigned long long _lastDataSyncedFromLastRun;
unsigned long long _lastSeqMentionedInConsoleLog; unsigned long long _lastSeqMentionedInConsoleLog;
public: public:
mongo::mutex _mx; // protects _mmfs; see setNoJournal() too mongo::mutex _mx; // protects _mmfs; see setNoJournal() too
private: private:
bool _recovering; // are we in recovery or WRITETODATAFILES bool _recovering; // are we in recovery or WRITETODATAFILES
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 engine.h   engine.h 
skipping to change at line 89 skipping to change at line 89
virtual void setFunction( const char *field , const char * code ) = 0; virtual void setFunction( const char *field , const char * code ) = 0;
// virtual void setThis( const BSONObj * obj ) = 0; // virtual void setThis( const BSONObj * obj ) = 0;
virtual ScriptingFunction createFunction( const char * code ); virtual ScriptingFunction createFunction( const char * code );
virtual void rename( const char * from , const char * to ) = 0; virtual void rename( const char * from , const char * to ) = 0;
/** /**
* @return 0 on success * @return 0 on success
*/ */
virtual int invoke( ScriptingFunction func , const BSONObj* args, c onst BSONObj* recv, int timeoutMs = 0 , bool ignoreReturn = false, bool rea dOnlyArgs = false, bool readOnlyRecv = false ) = 0; virtual int invoke( ScriptingFunction func , const BSONObj* args, c onst BSONObj* recv, int timeoutMs = 0 , bool ignoreReturn = false, bool rea dOnlyArgs = false, bool readOnlyRecv = false ) = 0;
void invokeSafe( ScriptingFunction func , const BSONObj* args, cons void invokeSafe( ScriptingFunction func , const BSONObj* args, cons
t BSONObj* recv, int timeoutMs = 0, bool readOnlyArgs = false, bool readOnl t BSONObj* recv, int timeoutMs = 0 , bool ignoreReturn = false, bool readOn
yRecv = false ) { lyArgs = false, bool readOnlyRecv = false ) {
int res = invoke( func , args , recv, timeoutMs, readOnlyArgs, int res = invoke( func , args , recv, timeoutMs, ignoreReturn,
readOnlyRecv ); readOnlyArgs, readOnlyRecv );
if ( res == 0 ) if ( res == 0 )
return; return;
throw UserException( 9004 , (string)"invoke failed: " + getErro r() ); throw UserException( 9004 , (string)"invoke failed: " + getErro r() );
} }
virtual string getError() = 0; virtual string getError() = 0;
virtual bool hasOutOfMemoryException() = 0;
int invoke( const char* code , const BSONObj* args, const BSONObj* recv, int timeoutMs = 0 ); int invoke( const char* code , const BSONObj* args, const BSONObj* recv, int timeoutMs = 0 );
void invokeSafe( const char* code , const BSONObj* args, const BSON Obj* recv, int timeoutMs = 0 ) { void invokeSafe( const char* code , const BSONObj* args, const BSON Obj* recv, int timeoutMs = 0 ) {
if ( invoke( code , args , recv, timeoutMs ) == 0 ) if ( invoke( code , args , recv, timeoutMs ) == 0 )
return; return;
throw UserException( 9005 , (string)"invoke failed: " + getErro r() ); throw UserException( 9005 , (string)"invoke failed: " + getErro r() );
} }
virtual bool exec( const StringData& code , const string& name , bo ol printResult , bool reportError , bool assertOnError, int timeoutMs = 0 ) = 0; virtual bool exec( const StringData& code , const string& name , bo ol printResult , bool reportError , bool assertOnError, int timeoutMs = 0 ) = 0;
virtual void execSetup( const StringData& code , const string& name = "setup" ) { virtual void execSetup( const StringData& code , const string& name = "setup" ) {
 End of changes. 2 change blocks. 
5 lines changed or deleted 6 lines changed or added


 engine_v8.h   engine_v8.h 
skipping to change at line 38 skipping to change at line 38
class V8ScriptEngine; class V8ScriptEngine;
class V8Scope; class V8Scope;
typedef Handle< Value > (*v8Function) ( V8Scope* scope, const v8::Argum ents& args ); typedef Handle< Value > (*v8Function) ( V8Scope* scope, const v8::Argum ents& args );
// Preemption is going to be allowed for the v8 mutex, and some of our v8 // Preemption is going to be allowed for the v8 mutex, and some of our v8
// usage is not preemption safe. So we are using an additional mutex t hat // usage is not preemption safe. So we are using an additional mutex t hat
// will not be preempted. The V8Lock should be used in place of v8::Lo cker // will not be preempted. The V8Lock should be used in place of v8::Lo cker
// except in certain special cases involving interrupts. // except in certain special cases involving interrupts.
namespace v8Locks { namespace v8Locks {
struct InterruptLock {
InterruptLock();
~InterruptLock();
};
// the implementations are quite simple - objects must be destroyed in // the implementations are quite simple - objects must be destroyed in
// reverse of the order created, and should not be shared between t hreads // reverse of the order created, and should not be shared between t hreads
struct RecursiveLock { struct RecursiveLock {
RecursiveLock(); RecursiveLock();
~RecursiveLock(); ~RecursiveLock();
bool _unlock; bool _unlock;
}; };
struct RecursiveUnlock { struct RecursiveUnlock {
RecursiveUnlock(); RecursiveUnlock();
~RecursiveUnlock(); ~RecursiveUnlock();
bool _lock; bool _lock;
}; };
} // namespace v8Locks } // namespace v8Locks
class V8Lock { class V8Lock {
public:
V8Lock() : _preemptionLock(Isolate::GetCurrent()){}
private:
v8Locks::RecursiveLock _noPreemptionLock; v8Locks::RecursiveLock _noPreemptionLock;
v8::Locker _preemptionLock; v8::Locker _preemptionLock;
}; };
struct V8Unlock { struct V8Unlock {
public:
V8Unlock() : _preemptionUnlock(Isolate::GetCurrent()){}
private:
v8::Unlocker _preemptionUnlock; v8::Unlocker _preemptionUnlock;
v8Locks::RecursiveUnlock _noPreemptionUnlock; v8Locks::RecursiveUnlock _noPreemptionUnlock;
}; };
class BSONHolder {
public:
BSONHolder( BSONObj obj ) {
_obj = obj.getOwned();
_modified = false;
}
~BSONHolder() {
}
BSONObj _obj;
bool _modified;
};
class V8Scope : public Scope { class V8Scope : public Scope {
public: public:
V8Scope( V8ScriptEngine * engine ); V8Scope( V8ScriptEngine * engine );
~V8Scope(); ~V8Scope();
virtual void reset(); virtual void reset();
virtual void init( const BSONObj * data ); virtual void init( const BSONObj * data );
virtual void localConnect( const char * dbName ); virtual void localConnect( const char * dbName );
skipping to change at line 98 skipping to change at line 128
virtual void setFunction( const char *field , const char * code ); virtual void setFunction( const char *field , const char * code );
// virtual void setThis( const BSONObj * obj ); // virtual void setThis( const BSONObj * obj );
virtual void rename( const char * from , const char * to ); virtual void rename( const char * from , const char * to );
virtual ScriptingFunction _createFunction( const char * code ); virtual ScriptingFunction _createFunction( const char * code );
Local< v8::Function > __createFunction( const char * code ); Local< v8::Function > __createFunction( const char * code );
virtual int invoke( ScriptingFunction func , const BSONObj* args, c onst BSONObj* recv, int timeoutMs = 0 , bool ignoreReturn = false, bool rea dOnlyArgs = false, bool readOnlyRecv = false ); virtual int invoke( ScriptingFunction func , const BSONObj* args, c onst BSONObj* recv, int timeoutMs = 0 , bool ignoreReturn = false, bool rea dOnlyArgs = false, bool readOnlyRecv = false );
virtual bool exec( const StringData& code , const string& name , bo ol printResult , bool reportError , bool assertOnError, int timeoutMs ); virtual bool exec( const StringData& code , const string& name , bo ol printResult , bool reportError , bool assertOnError, int timeoutMs );
virtual string getError() { return _error; } virtual string getError() { return _error; }
virtual bool hasOutOfMemoryException();
virtual void injectNative( const char *field, NativeFunction func, void* data = 0 ); virtual void injectNative( const char *field, NativeFunction func, void* data = 0 );
void injectNative( const char *field, NativeFunction func, Handle<v 8::Object>& obj, void* data = 0 ); void injectNative( const char *field, NativeFunction func, Handle<v 8::Object>& obj, void* data = 0 );
void injectV8Function( const char *field, v8Function func ); void injectV8Function( const char *field, v8Function func );
void injectV8Function( const char *field, v8Function func, Handle<v 8::Object>& obj ); void injectV8Function( const char *field, v8Function func, Handle<v 8::Object>& obj );
void injectV8Function( const char *field, v8Function func, Handle<v 8::Template>& t ); void injectV8Function( const char *field, v8Function func, Handle<v 8::Template>& t );
Handle<v8::FunctionTemplate> createV8Function( v8Function func ); Handle<v8::FunctionTemplate> createV8Function( v8Function func );
void gc(); void gc();
Handle< Context > context() const { return _context; } Handle< Context > context() const { return _context; }
v8::Local<v8::Object> mongoToV8( const mongo::BSONObj & m , bool ar ray = 0 , bool readOnly = false ); v8::Local<v8::Object> mongoToV8( const mongo::BSONObj & m , bool ar ray = 0 , bool readOnly = false );
v8::Handle<v8::Object> mongoToLZV8( const mongo::BSONObj & m , bool array = 0 , bool readOnly = false ); v8::Handle<v8::Object> mongoToLZV8( const mongo::BSONObj & m , bool array = 0 , bool readOnly = false );
mongo::BSONObj v8ToMongo( v8::Handle<v8::Object> o , int depth = 0 ); mongo::BSONObj v8ToMongo( v8::Handle<v8::Object> o , int depth = 0 );
void v8ToMongoElement( BSONObjBuilder & b , v8::Handle<v8::String> void v8ToMongoElement( BSONObjBuilder & b , const string sname , v8
name , ::Handle<v8::Value> value , int depth = 0, BSONObj* originalParent=0 );
const string sname , v8::Handle<v8::Value> v
alue , int depth = 0, BSONObj* originalParent=0 );
v8::Handle<v8::Value> mongoToV8Element( const BSONElement &f, bool readOnly = false ); v8::Handle<v8::Value> mongoToV8Element( const BSONElement &f, bool readOnly = false );
virtual void append( BSONObjBuilder & builder , const char * fieldN ame , const char * scopeName ); virtual void append( BSONObjBuilder & builder , const char * fieldN ame , const char * scopeName );
v8::Function * getNamedCons( const char * name ); v8::Function * getNamedCons( const char * name );
v8::Function * getObjectIdCons(); v8::Function * getObjectIdCons();
Local< v8::Value > newId( const OID &id ); Local< v8::Value > newId( const OID &id );
Persistent<v8::Object> wrapBSONObject(Local<v8::Object> obj, BSONOb j* data); Persistent<v8::Object> wrapBSONObject(Local<v8::Object> obj, BSONHo lder* data);
Persistent<v8::Object> wrapArrayObject(Local<v8::Object> obj, char* data); Persistent<v8::Object> wrapArrayObject(Local<v8::Object> obj, char* data);
v8::Handle<v8::String> getV8Str(string str); v8::Handle<v8::String> getV8Str(string str);
// inline v8::Handle<v8::String> getV8Str(string str) { return v8::S tring::New(str.c_str()); } // inline v8::Handle<v8::String> getV8Str(string str) { return v8::S tring::New(str.c_str()); }
inline v8::Handle<v8::String> getLocalV8Str(string str) { return v8 ::String::New(str.c_str()); } inline v8::Handle<v8::String> getLocalV8Str(string str) { return v8 ::String::New(str.c_str()); }
v8::Isolate* getIsolate() { return _isolate; }
Persistent<Context> getContext() { return _context; }
// call with v8 mutex:
void enableV8Interrupt();
void disableV8Interrupt();
bool pauseV8Interrupt();
bool resumeV8Interrupt();
Handle<v8::String> V8STR_CONN; Handle<v8::String> V8STR_CONN;
Handle<v8::String> V8STR_ID; Handle<v8::String> V8STR_ID;
Handle<v8::String> V8STR_LENGTH; Handle<v8::String> V8STR_LENGTH;
Handle<v8::String> V8STR_LEN; Handle<v8::String> V8STR_LEN;
Handle<v8::String> V8STR_TYPE; Handle<v8::String> V8STR_TYPE;
Handle<v8::String> V8STR_ISOBJECTID; Handle<v8::String> V8STR_ISOBJECTID;
Handle<v8::String> V8STR_NATIVE_FUNC; Handle<v8::String> V8STR_NATIVE_FUNC;
Handle<v8::String> V8STR_NATIVE_DATA; Handle<v8::String> V8STR_NATIVE_DATA;
Handle<v8::String> V8STR_V8_FUNC; Handle<v8::String> V8STR_V8_FUNC;
Handle<v8::String> V8STR_RETURN; Handle<v8::String> V8STR_RETURN;
skipping to change at line 152 skipping to change at line 191
Handle<v8::String> V8STR_I; Handle<v8::String> V8STR_I;
Handle<v8::String> V8STR_EMPTY; Handle<v8::String> V8STR_EMPTY;
Handle<v8::String> V8STR_MINKEY; Handle<v8::String> V8STR_MINKEY;
Handle<v8::String> V8STR_MAXKEY; Handle<v8::String> V8STR_MAXKEY;
Handle<v8::String> V8STR_NUMBERLONG; Handle<v8::String> V8STR_NUMBERLONG;
Handle<v8::String> V8STR_NUMBERINT; Handle<v8::String> V8STR_NUMBERINT;
Handle<v8::String> V8STR_DBPTR; Handle<v8::String> V8STR_DBPTR;
Handle<v8::String> V8STR_BINDATA; Handle<v8::String> V8STR_BINDATA;
Handle<v8::String> V8STR_WRAPPER; Handle<v8::String> V8STR_WRAPPER;
Handle<v8::String> V8STR_RO; Handle<v8::String> V8STR_RO;
Handle<v8::String> V8STR_MODIFIED; Handle<v8::String> V8STR_FULLNAME;
Handle<v8::String> V8STR_BSON;
private: private:
void _startCall(); void _startCall();
static Handle< Value > nativeCallback( V8Scope* scope, const Argume nts &args ); static Handle< Value > nativeCallback( V8Scope* scope, const Argume nts &args );
static v8::Handle< v8::Value > v8Callback( const v8::Arguments &arg s ); static v8::Handle< v8::Value > v8Callback( const v8::Arguments &arg s );
static Handle< Value > load( V8Scope* scope, const Arguments &args ); static Handle< Value > load( V8Scope* scope, const Arguments &args );
static Handle< Value > Print(V8Scope* scope, const v8::Arguments& a rgs); static Handle< Value > Print(V8Scope* scope, const v8::Arguments& a rgs);
static Handle< Value > Version(V8Scope* scope, const v8::Arguments& args); static Handle< Value > Version(V8Scope* scope, const v8::Arguments& args);
static Handle< Value > GCV8(V8Scope* scope, const v8::Arguments& ar gs); static Handle< Value > GCV8(V8Scope* scope, const v8::Arguments& ar gs);
skipping to change at line 180 skipping to change at line 220
vector< Persistent<Value> > _funcs; vector< Persistent<Value> > _funcs;
v8::Persistent<v8::Object> _emptyObj; v8::Persistent<v8::Object> _emptyObj;
v8::Persistent<v8::Function> _wrapper; v8::Persistent<v8::Function> _wrapper;
enum ConnectState { NOT , LOCAL , EXTERNAL }; enum ConnectState { NOT , LOCAL , EXTERNAL };
ConnectState _connectState; ConnectState _connectState;
std::map <string, v8::Persistent <v8::String> > _strCache; std::map <string, v8::Persistent <v8::String> > _strCache;
Persistent<v8::FunctionTemplate> lzFunctionTemplate;
Persistent<v8::ObjectTemplate> lzObjectTemplate; Persistent<v8::ObjectTemplate> lzObjectTemplate;
Persistent<v8::ObjectTemplate> roObjectTemplate; Persistent<v8::ObjectTemplate> roObjectTemplate;
Persistent<v8::ObjectTemplate> lzArrayTemplate; Persistent<v8::ObjectTemplate> lzArrayTemplate;
Persistent<v8::ObjectTemplate> internalFieldObjects; Persistent<v8::ObjectTemplate> internalFieldObjects;
v8::Isolate* _isolate;
}; };
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; }
class V8UnlockForClient : public Unlocker { class V8UnlockForClient : public Unlocker {
V8Unlock u_; // V8Unlock u_;
}; };
virtual auto_ptr<Unlocker> newThreadUnlocker() { return auto_ptr< U nlocker >( new V8UnlockForClient ); } virtual auto_ptr<Unlocker> newThreadUnlocker() { return auto_ptr< U nlocker >( new V8UnlockForClient ); }
virtual void interrupt( unsigned opSpec ); virtual void interrupt( unsigned opSpec );
virtual void interruptAll(); virtual void interruptAll();
private: private:
friend class V8Scope; friend class V8Scope;
}; };
skipping to change at line 228 skipping to change at line 270
const char* data () const { return _data.c_str(); } const char* data () const { return _data.c_str(); }
size_t length () const { return _data.length(); } size_t length () const { return _data.length(); }
private: private:
// string _str; // string _str;
// const char* _data; // const char* _data;
std::string _data; std::string _data;
// size_t _len; // size_t _len;
}; };
extern ScriptEngine * globalScriptEngine; extern ScriptEngine * globalScriptEngine;
extern map< unsigned, int > __interruptSpecToThreadId;
} }
 End of changes. 15 change blocks. 
8 lines changed or deleted 48 lines changed or added


 extsort.h   extsort.h 
skipping to change at line 65 skipping to change at line 65
}; };
private: private:
IndexInterface& _i; IndexInterface& _i;
const Ordering _order; const Ordering _order;
}; };
static IndexInterface *extSortIdxInterface; static IndexInterface *extSortIdxInterface;
static Ordering extSortOrder; static Ordering extSortOrder;
static int extSortComp( const void *lv, const void *rv ) { static int extSortComp( const void *lv, const void *rv ) {
DEV RARELY { DEV RARELY {
dbMutex.assertWriteLocked(); // must be as we use a global var d.dbMutex.assertWriteLocked(); // must be as we use a globa l var
} }
Data * l = (Data*)lv; Data * l = (Data*)lv;
Data * r = (Data*)rv; Data * r = (Data*)rv;
return _compare(*extSortIdxInterface, *l, *r, extSortOrder); return _compare(*extSortIdxInterface, *l, *r, extSortOrder);
}; };
class FileIterator : boost::noncopyable { class FileIterator : boost::noncopyable {
public: public:
FileIterator( string file ); FileIterator( string file );
~FileIterator(); ~FileIterator();
bool more(); bool more();
Data next(); Data next();
private: private:
bool _read( char* buf, long long count ); MemoryMappedFile _file;
char * _buf;
int _file; char * _end;
unsigned long long _length;
unsigned long long _readSoFar;
}; };
public: public:
typedef FastArray<Data> InMemory; typedef FastArray<Data> InMemory;
class Iterator : boost::noncopyable { class Iterator : boost::noncopyable {
public: public:
Iterator( BSONObjExternalSorter * sorter ); Iterator( BSONObjExternalSorter * sorter );
skipping to change at line 141 skipping to change at line 139
private: private:
void _sortInMem(); void _sortInMem();
void sort( string file ); void sort( string file );
void finishMap(); void finishMap();
BSONObj _order; BSONObj _order;
long _maxFilesize; long _maxFilesize;
path _root; boost::filesystem::path _root;
int _arraySize; int _arraySize;
InMemory * _cur; InMemory * _cur;
long _curSizeSoFar; long _curSizeSoFar;
list<string> _files; list<string> _files;
bool _sorted; bool _sorted;
static unsigned long long _compares; static unsigned long long _compares;
}; };
 End of changes. 3 change blocks. 
7 lines changed or deleted 5 lines changed or added


 file_allocator.h   file_allocator.h 
skipping to change at line 87 skipping to change at line 87
list< string > _pending; list< string > _pending;
mutable map< string, long > _pendingSize; mutable map< string, long > _pendingSize;
bool _failed; bool _failed;
#endif #endif
static FileAllocator* _instance; static FileAllocator* _instance;
}; };
/** like "mkdir -p" but on parent dir of p rather than p itself */
boost::filesystem::path ensureParentDirCreated(const boost::filesystem:
:path& p);
} // namespace mongo } // namespace mongo
 End of changes. 1 change blocks. 
4 lines changed or deleted 0 lines changed or added


 framework.h   framework.h 
skipping to change at line 26 skipping to change at line 26
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* /*
simple portable regression system simple portable regression system
*/ */
#include "../pch.h" #include "../pch.h"
#define ASSERT_EXCEPTION(a,b) \ #define ASSERT_THROWS(a,b) \
try { \ try { \
a; \ a; \
mongo::regression::assert_fail( #a , __FILE__ , __LINE__ ); \ mongo::regression::assert_fail( #a , __FILE__ , __LINE__ ); \
} catch ( b& ){ \ } catch ( b& ){ \
mongo::regression::assert_pass(); \ mongo::regression::assert_pass(); \
} }
#define ASSERT_EQUALS(a,b) (mongo::regression::MyAsserts( #a , #b , __FILE_ _ , __LINE__ ) ).ae( (a) , (b) ) #define ASSERT_EQUALS(a,b) (mongo::regression::MyAsserts( #a , #b , __FILE_ _ , __LINE__ ) ).ae( (a) , (b) )
#define ASSERT_NOT_EQUALS(a,b) (mongo::regression::MyAsserts( #a , #b , __F ILE__ , __LINE__ ) ).nae( (a) , (b) ) #define ASSERT_NOT_EQUALS(a,b) (mongo::regression::MyAsserts( #a , #b , __F ILE__ , __LINE__ ) ).nae( (a) , (b) )
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 goodies.h   goodies.h 
skipping to change at line 57 skipping to change at line 57
#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();
} }
/* use "addr2line -CFe <exe>" to parse. */ /* use "addr2line -CFe <exe>" to parse. */
inline void printStackTrace( ostream &o = cout ) { inline void printStackTrace(ostream &o = cout) {
void *b[20]; void *b[20];
int size = backtrace(b, 20); int size = backtrace(b, 20);
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
o << hex << b[i] << dec << ' '; o << hex << b[i] << dec << ' ';
o << endl; o << endl;
char **strings; char **strings;
strings = backtrace_symbols(b, size); strings = backtrace_symbols(b, size);
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
o << ' ' << strings[i] << '\n'; o << ' ' << strings[i] << '\n';
o.flush(); o.flush();
free (strings); free (strings);
} }
#else #else
inline void printStackTrace( ostream &o = cout ) { } inline void printStackTrace(ostream &o = cout) { }
#endif #endif
bool isPrime(int n); bool isPrime(int n);
int nextPrime(int n); int nextPrime(int n);
inline void dumpmemory(const char *data, int len) { inline void dumpmemory(const char *data, int len) {
if ( len > 1024 ) if ( len > 1024 )
len = 1024; len = 1024;
try { try {
const char *q = data; const char *q = data;
skipping to change at line 160 skipping to change at line 160
#if !defined(_WIN32) #if !defined(_WIN32)
typedef int HANDLE; typedef int HANDLE;
inline void strcpy_s(char *dst, unsigned len, const char *src) { inline void strcpy_s(char *dst, unsigned len, const char *src) {
assert( strlen(src) < len ); assert( strlen(src) < len );
strcpy(dst, src); strcpy(dst, src);
} }
#else #else
typedef void *HANDLE; typedef void *HANDLE;
#endif #endif
/* thread local "value" rather than a pointer
good for things which have copy constructors (and the copy construct
or is fast enough)
e.g.
ThreadLocalValue<int> myint;
*/
template<class T>
class ThreadLocalValue {
public:
ThreadLocalValue( T def = 0 ) : _default( def ) { }
T get() const {
T * val = _val.get();
if ( val )
return *val;
return _default;
}
void set( const T& i ) {
T *v = _val.get();
if( v ) {
*v = i;
return;
}
v = new T(i);
_val.reset( v );
}
private:
boost::thread_specific_ptr<T> _val;
const T _default;
};
class ProgressMeter : boost::noncopyable { class ProgressMeter : boost::noncopyable {
public: public:
ProgressMeter( unsigned long long total , int secondsBetween = 3 , int checkInterval = 100 ) { ProgressMeter( unsigned long long total , int secondsBetween = 3 , int checkInterval = 100 , string units = "" ) : _units(units) {
reset( total , secondsBetween , checkInterval ); reset( total , secondsBetween , checkInterval );
} }
ProgressMeter() { ProgressMeter() {
_active = 0; _active = 0;
_units = "";
} }
// typically you do ProgressMeterHolder // typically you do ProgressMeterHolder
void reset( unsigned long long total , int secondsBetween = 3 , int checkInterval = 100 ) { void reset( unsigned long long total , int secondsBetween = 3 , int checkInterval = 100 ) {
_total = total; _total = total;
_secondsBetween = secondsBetween; _secondsBetween = secondsBetween;
_checkInterval = checkInterval; _checkInterval = checkInterval;
_done = 0; _done = 0;
_hits = 0; _hits = 0;
skipping to change at line 229 skipping to change at line 198
bool isActive() { bool isActive() {
return _active; return _active;
} }
/** /**
* @param n how far along we are relative to the total # we set in CurOp::setMessage * @param n how far along we are relative to the total # we set in CurOp::setMessage
* @return if row was printed * @return if row was printed
*/ */
bool hit( int n = 1 ) { bool hit( int n = 1 ) {
if ( ! _active ) { if ( ! _active ) {
cout << "warning: hit on in-active ProgressMeter" << endl; cout << "warning: hit an inactive ProgressMeter" << endl;
return false; return false;
} }
_done += n; _done += n;
_hits++; _hits++;
if ( _hits % _checkInterval ) if ( _hits % _checkInterval )
return false; return false;
int t = (int) time(0); int t = (int) time(0);
if ( t - _lastTime < _secondsBetween ) if ( t - _lastTime < _secondsBetween )
return false; return false;
if ( _total > 0 ) { if ( _total > 0 ) {
int per = (int)( ( (double)_done * 100.0 ) / (double)_total ); int per = (int)( ( (double)_done * 100.0 ) / (double)_total );
cout << "\t\t" << _done << "/" << _total << "\t" << per << cout << "\t\t" << _done << "/" << _total << "\t" << per <<
"%" << endl; "%";
if ( ! _units.empty() ) {
cout << "\t(" << _units << ")" << endl;
}
else {
cout << endl;
}
} }
_lastTime = t; _lastTime = t;
return true; return true;
} }
void setUnits( string units ) {
_units = units;
}
void setTotalWhileRunning( unsigned long long total ) { void setTotalWhileRunning( unsigned long long total ) {
_total = total; _total = total;
} }
unsigned long long done() const { return _done; } unsigned long long done() const { return _done; }
unsigned long long hits() const { return _hits; } unsigned long long hits() const { return _hits; }
unsigned long long total() const { return _total; } unsigned long long total() const { return _total; }
string toString() const { string toString() const {
if ( ! _active ) if ( ! _active )
return ""; return "";
stringstream buf; stringstream buf;
buf << _done << "/" << _total << " " << (_done*100)/_total << " %"; buf << _done << "/" << _total << " " << (_done*100)/_total << " %";
if ( ! _units.empty() ) {
buf << "\t(" << _units << ")" << endl;
}
return buf.str(); return buf.str();
} }
bool operator==( const ProgressMeter& other ) const { bool operator==( const ProgressMeter& other ) const {
return this == &other; return this == &other;
} }
private: private:
bool _active; bool _active;
unsigned long long _total; unsigned long long _total;
int _secondsBetween; int _secondsBetween;
int _checkInterval; int _checkInterval;
unsigned long long _done; unsigned long long _done;
unsigned long long _hits; unsigned long long _hits;
int _lastTime; int _lastTime;
string _units;
}; };
// e.g.: // e.g.:
// CurOp * op = cc().curop(); // CurOp * op = cc().curop();
// ProgressMeterHolder pm( op->setMessage( "index: (1/3) external sort" , d->stats.nrecords , 10 ) ); // ProgressMeterHolder pm( op->setMessage( "index: (1/3) external sort" , d->stats.nrecords , 10 ) );
// loop { pm.hit(); } // loop { pm.hit(); }
class ProgressMeterHolder : boost::noncopyable { class ProgressMeterHolder : boost::noncopyable {
public: public:
ProgressMeterHolder( ProgressMeter& pm ) ProgressMeterHolder( ProgressMeter& pm )
: _pm( pm ) { : _pm( pm ) {
skipping to change at line 327 skipping to change at line 314
class TicketHolder { class TicketHolder {
public: public:
TicketHolder( int num ) : _mutex("TicketHolder") { TicketHolder( int num ) : _mutex("TicketHolder") {
_outof = num; _outof = num;
_num = num; _num = num;
} }
bool tryAcquire() { bool tryAcquire() {
scoped_lock lk( _mutex ); scoped_lock lk( _mutex );
return _tryAcquire(); if ( _num <= 0 ) {
} if ( _num < 0 ) {
cerr << "DISASTER! in TicketHolder" << endl;
void waitForTicket() { }
scoped_lock lk( _mutex ); return false;
while( ! _tryAcquire() ) {
_newTicket.wait( lk.boost() );
} }
_num--;
return true;
} }
void release() { void release() {
{ scoped_lock lk( _mutex );
scoped_lock lk( _mutex ); _num++;
_num++;
}
_newTicket.notify_one();
} }
void resize( int newSize ) { void resize( int newSize ) {
{ scoped_lock lk( _mutex );
scoped_lock lk( _mutex ); int used = _outof - _num;
if ( used > newSize ) {
int used = _outof - _num; cout << "ERROR: can't resize since we're using (" << used <
if ( used > newSize ) { < ") more than newSize(" << newSize << ")" << endl;
cout << "ERROR: can't resize since we're using (" << us return;
ed << ") more than newSize(" << newSize << ")" << endl;
return;
}
_outof = newSize;
_num = _outof - used;
} }
// Potentially wasteful, but easier to see is correct _outof = newSize;
_newTicket.notify_all(); _num = _outof - used;
} }
int available() const { int available() const {
return _num; return _num;
} }
int used() const { int used() const {
return _outof - _num; return _outof - _num;
} }
int outof() const { return _outof; } int outof() const { return _outof; }
private: private:
bool _tryAcquire(){
if ( _num <= 0 ) {
if ( _num < 0 ) {
cerr << "DISASTER! in TicketHolder" << endl;
}
return false;
}
_num--;
return true;
}
int _outof; int _outof;
int _num; int _num;
mongo::mutex _mutex; mongo::mutex _mutex;
boost::condition_variable_any _newTicket;
}; };
class TicketHolderReleaser { class TicketHolderReleaser {
public: public:
TicketHolderReleaser( TicketHolder * holder ) { TicketHolderReleaser( TicketHolder * holder ) {
_holder = holder; _holder = holder;
} }
~TicketHolderReleaser() { ~TicketHolderReleaser() {
_holder->release(); _holder->release();
} }
private: private:
TicketHolder * _holder; TicketHolder * _holder;
}; };
/** /**
* this is a thread safe string * this is a thread safe string
* you will never get a bad pointer, though data may be mungedd * you will never get a bad pointer, though data may be mungedd
*/ */
class ThreadSafeString { class ThreadSafeString : boost::noncopyable {
public: public:
ThreadSafeString( size_t size=256 ) ThreadSafeString( size_t size=256 )
: _size( size ) , _buf( new char[size] ) { : _size( size ) , _buf( new char[size] ) {
memset( _buf , 0 , _size ); memset( _buf , 0 , _size );
} }
ThreadSafeString( const ThreadSafeString& other ) ThreadSafeString( const ThreadSafeString& other )
: _size( other._size ) , _buf( new char[_size] ) { : _size( other._size ) , _buf( new char[_size] ) {
strncpy( _buf , other._buf , _size ); strncpy( _buf , other._buf , _size );
} }
skipping to change at line 502 skipping to change at line 466
T* operator->() const { return _p; } T* operator->() const { return _p; }
T& operator*() const { return *_p; } T& operator*() const { return *_p; }
// convert from ptr<T> // convert from ptr<T>
operator T* () const { return _p; } operator T* () const { return _p; }
private: private:
T* _p; T* _p;
}; };
/** Hmmmm */ using boost::shared_ptr;
using namespace boost; using boost::scoped_ptr;
using boost::scoped_array;
using boost::intrusive_ptr;
using boost::bad_lexical_cast;
using boost::dynamic_pointer_cast;
} // namespace mongo } // namespace mongo
 End of changes. 19 change blocks. 
83 lines changed or deleted 49 lines changed or added


 grid.h   grid.h 
skipping to change at line 85 skipping to change at line 85
/** /**
* @return true if the config database knows about a host 'name' * @return true if the config database knows about a host 'name'
*/ */
bool knowAboutShard( const string& name ) const; bool knowAboutShard( const string& name ) const;
/** /**
* @return true if the chunk balancing functionality is enabled * @return true if the chunk balancing functionality is enabled
*/ */
bool shouldBalance() const; bool shouldBalance() const;
/**
*
* Obtain grid configuration and settings data.
*
* @param name identifies a particular type of configuration data.
* @return a BSON object containing the requested data.
*/
BSONObj getConfigSetting( string name ) const;
unsigned long long getNextOpTime() const; unsigned long long getNextOpTime() const;
void flushConfig(); void flushConfig();
// exposed methods below are for testing only // exposed methods below are for testing only
/** /**
* @param balancerDoc bson that may contain a window of time for th e balancer to work * @param balancerDoc bson that may contain a window of time for th e balancer to work
* format { ... , activeWindow: { start: "8:30" , stop: "19: 00" } , ... } * format { ... , activeWindow: { start: "8:30" , stop: "19: 00" } , ... }
* @return true if there is no window of time specified for the bal ancer or it we're currently in it * @return true if there is no window of time specified for the bal ancer or it we're currently in it
 End of changes. 1 change blocks. 
0 lines changed or deleted 9 lines changed or added


 gridfs.h   gridfs.h 
skipping to change at line 35 skipping to change at line 35
typedef unsigned long long gridfs_offset; typedef unsigned long long gridfs_offset;
class GridFS; class GridFS;
class GridFile; class GridFile;
class GridFSChunk { class GridFSChunk {
public: public:
GridFSChunk( BSONObj data ); GridFSChunk( BSONObj data );
GridFSChunk( BSONObj fileId , int chunkNumber , const char * data , int len ); GridFSChunk( BSONObj fileId , int chunkNumber , const char * data , int len );
int len() { int len() const {
int len; int len;
_data["data"].binDataClean( len ); _data["data"].binDataClean( len );
return len; return len;
} }
const char * data( int & len ) { const char * data( int & len ) const {
return _data["data"].binDataClean( len ); return _data["data"].binDataClean( len );
} }
private: private:
BSONObj _data; BSONObj _data;
friend class GridFS; friend class GridFS;
}; };
/** /**
GridFS is for storing large file-style objects in MongoDB. GridFS is for storing large file-style objects in MongoDB.
skipping to change at line 102 skipping to change at line 102
/** /**
* removes file referenced by fileName from the db * removes file referenced by fileName from the db
* @param fileName filename (in GridFS) of the file to remove * @param fileName filename (in GridFS) of the file to remove
* @return the file object * @return the file object
*/ */
void removeFile( const string& fileName ); void removeFile( const string& fileName );
/** /**
* returns a file object matching the query * returns a file object matching the query
*/ */
GridFile findFile( BSONObj query ); GridFile findFile( BSONObj query ) const;
/** /**
* equiv to findFile( { filename : filename } ) * equiv to findFile( { filename : filename } )
*/ */
GridFile findFile( const string& fileName ); GridFile findFile( const string& fileName ) const;
/** /**
* convenience method to get all the files * convenience method to get all the files
*/ */
auto_ptr<DBClientCursor> list(); auto_ptr<DBClientCursor> list() const;
/** /**
* convenience method to get all the files with a filter * convenience method to get all the files with a filter
*/ */
auto_ptr<DBClientCursor> list( BSONObj query ); auto_ptr<DBClientCursor> list( BSONObj query ) const;
private: private:
DBClientBase& _client; DBClientBase& _client;
string _dbName; string _dbName;
string _prefix; string _prefix;
string _filesNS; string _filesNS;
string _chunksNS; string _chunksNS;
unsigned int _chunkSize; unsigned int _chunkSize;
// insert fileobject. All chunks must be in DB. // insert fileobject. All chunks must be in DB.
skipping to change at line 142 skipping to change at line 142
/** /**
wrapper for a file stored in the Mongo database wrapper for a file stored in the Mongo database
*/ */
class GridFile { class GridFile {
public: public:
/** /**
* @return whether or not this file exists * @return whether or not this file exists
* findFile will always return a GriFile, so need to check this * findFile will always return a GriFile, so need to check this
*/ */
bool exists() { bool exists() const {
return ! _obj.isEmpty(); return ! _obj.isEmpty();
} }
string getFilename() { string getFilename() const {
return _obj["filename"].str(); return _obj["filename"].str();
} }
int getChunkSize() { int getChunkSize() const {
return (int)(_obj["chunkSize"].number()); return (int)(_obj["chunkSize"].number());
} }
gridfs_offset getContentLength() { gridfs_offset getContentLength() const {
return (gridfs_offset)(_obj["length"].number()); return (gridfs_offset)(_obj["length"].number());
} }
string getContentType() { string getContentType() const {
return _obj["contentType"].valuestr(); return _obj["contentType"].valuestr();
} }
Date_t getUploadDate() { Date_t getUploadDate() const {
return _obj["uploadDate"].date(); return _obj["uploadDate"].date();
} }
string getMD5() { string getMD5() const {
return _obj["md5"].str(); return _obj["md5"].str();
} }
BSONElement getFileField( const string& name ) { BSONElement getFileField( const string& name ) const {
return _obj[name]; return _obj[name];
} }
BSONObj getMetadata(); BSONObj getMetadata() const;
int getNumChunks() { int getNumChunks() const {
return (int) ceil( (double)getContentLength() / (double)getChun kSize() ); return (int) ceil( (double)getContentLength() / (double)getChun kSize() );
} }
GridFSChunk getChunk( int n ); GridFSChunk getChunk( int n ) const;
/** /**
write the file to the output stream write the file to the output stream
*/ */
gridfs_offset write( ostream & out ); gridfs_offset write( ostream & out ) const;
/** /**
write the file to this filename write the file to this filename
*/ */
gridfs_offset write( const string& where ); gridfs_offset write( const string& where ) const;
private: private:
GridFile( GridFS * grid , BSONObj obj ); GridFile(const GridFS * grid , BSONObj obj );
void _exists(); void _exists() const;
GridFS * _grid; const GridFS * _grid;
BSONObj _obj; BSONObj _obj;
friend class GridFS; friend class GridFS;
}; };
} }
#include "undef_macros.h" #include "undef_macros.h"
 End of changes. 22 change blocks. 
23 lines changed or deleted 23 lines changed or added


 hostandport.h   hostandport.h 
skipping to change at line 28 skipping to change at line 28
#pragma once #pragma once
#include "sock.h" #include "sock.h"
#include "../../db/cmdline.h" #include "../../db/cmdline.h"
#include "../mongoutils/str.h" #include "../mongoutils/str.h"
namespace mongo { namespace mongo {
using namespace mongoutils; using namespace mongoutils;
void dynHostResolve(string& name, int& port);
string dynHostMyName();
/** helper for manipulating host:port connection endpoints. /** helper for manipulating host:port connection endpoints.
*/ */
struct HostAndPort { struct HostAndPort {
HostAndPort() : _port(-1) { } HostAndPort() : _port(-1) { }
/** From a string hostname[:portnumber] /** From a string hostname[:portnumber] or a #dynname
Throws user assertion if bad config string or bad port #. Throws user assertion if bad config string or bad port #.
*/ */
HostAndPort(string s); HostAndPort(string s);
/** @param p port number. -1 is ok to use default. */ /** @param p port number. -1 is ok to use default. */
HostAndPort(string h, int p /*= -1*/) : _host(h), _port(p) { } HostAndPort(string h, int p /*= -1*/) : _host(h), _port(p) {
assert( !str::startsWith(h, '#') );
HostAndPort(const SockAddr& sock )
: _host( sock.getAddr() ) , _port( sock.getPort() ) {
} }
static HostAndPort me() { HostAndPort(const SockAddr& sock ) : _host( sock.getAddr() ) , _por
return HostAndPort("localhost", cmdLine.port); t( sock.getPort() ) { }
}
static HostAndPort me() { return HostAndPort("localhost", cmdLine.p
ort); }
/* uses real hostname instead of localhost */ /* uses real hostname instead of localhost */
static HostAndPort Me(); static HostAndPort Me();
bool operator<(const HostAndPort& r) const { bool operator<(const HostAndPort& r) const {
if( _host < r._host ) string h = host();
string rh = r.host();
if( h < rh )
return true; return true;
if( _host == r._host ) if( h == rh )
return port() < r.port(); return port() < r.port();
return false; return false;
} }
bool operator==(const HostAndPort& r) const { bool operator==(const HostAndPort& r) const {
return _host == r._host && port() == r.port(); return host() == r.host() && port() == r.port();
} }
bool operator!=(const HostAndPort& r) const { bool operator!=(const HostAndPort& r) const { return !(*this == r);
return _host != r._host || port() != r.port(); }
}
/* returns true if the host/port combo identifies this process inst ance. */ /* returns true if the host/port combo identifies this process inst ance. */
bool isSelf() const; // defined in message.cpp bool isSelf() const; // defined in isself.cpp
bool isLocalHost() const; bool isLocalHost() const;
/** /**
* @param includePort host:port if true, host otherwise * @param includePort host:port if true, host otherwise
*/ */
string toString( bool includePort=true ) const; string toString( bool includePort=true ) const;
operator string() const { return toString(); } // get the logical name if using a #dynhostname instead of resolvin
g to current actual name
string dynString() const;
string toStringLong() const;
string host() const { return _host; } operator string() const { return toString(); }
int port() const { return _port >= 0 ? _port : CmdLine::DefaultDBPo bool empty() const {
rt; } return _dynName.empty() && _host.empty() && _port < 0;
bool hasPort() const { return _port >= 0; } }
void setPort( int port ) { _port = port; } string host() const {
if( !dyn() )
return _host;
string h = _dynName;
int p;
dynHostResolve(h, p);
return h;
}
int port() const {
int p = -2;
if( dyn() ) {
string h = _dynName;
dynHostResolve(h,p);
}
else {
p = _port;
}
return p >= 0 ? p : CmdLine::DefaultDBPort;
}
bool hasPort() const {
int p = -2;
if( dyn() ) {
string h = _dynName;
dynHostResolve(h,p);
}
else {
p = _port;
}
return p >= 0;
}
void setPort( int port ) {
if( dyn() ) {
log() << "INFO skipping setPort() HostAndPort dyn()=true" <
< endl;
return;
}
_port = port;
}
private: private:
bool dyn() const { return !_dynName.empty(); }
void init(const char *);
// invariant (except full obj assignment): // invariant (except full obj assignment):
string _dynName; // when this is set, _host and _port aren't used, rather, we look up the dyn info every time.
string _host; string _host;
int _port; // -1 indicates unspecified int _port; // -1 indicates unspecified
}; };
inline HostAndPort HostAndPort::Me() { inline HostAndPort HostAndPort::Me() {
{
string s = dynHostMyName();
if( !s.empty() )
return HostAndPort(s);
}
const char* ips = cmdLine.bind_ip.c_str(); const char* ips = cmdLine.bind_ip.c_str();
while(*ips) { while(*ips) {
string ip; string ip;
const char * comma = strchr(ips, ','); const char * comma = strchr(ips, ',');
if (comma) { if (comma) {
ip = string(ips, comma - ips); ip = string(ips, comma - ips);
ips = comma + 1; ips = comma + 1;
} }
else { else {
ip = string(ips); ip = string(ips);
skipping to change at line 117 skipping to change at line 166
return h; return h;
} }
} }
string h = getHostName(); string h = getHostName();
assert( !h.empty() ); assert( !h.empty() );
assert( h != "localhost" ); assert( h != "localhost" );
return HostAndPort(h, cmdLine.port); return HostAndPort(h, cmdLine.port);
} }
inline string HostAndPort::dynString() const {
return dyn() ? _dynName : toString();
}
inline string HostAndPort::toStringLong() const {
return _dynName + ':' + toString();
}
inline string HostAndPort::toString( bool includePort ) const { inline string HostAndPort::toString( bool includePort ) const {
string h = host();
int p = port();
if ( ! includePort ) if ( ! includePort )
return _host; return h;
stringstream ss; stringstream ss;
ss << _host; ss << h;
if ( _port != -1 ) { if ( p != -1 ) {
ss << ':'; ss << ':';
#if defined(_DEBUG) #if defined(_DEBUG)
if( _port >= 44000 && _port < 44100 ) { if( p >= 44000 && p < 44100 ) {
log() << "warning: special debug port 44xxx used" << endl; log() << "warning: special debug port 44xxx used" << endl;
ss << _port+1; ss << p+1;
} }
else else
ss << _port; ss << p;
#else #else
ss << _port; ss << p;
#endif #endif
} }
return ss.str(); return ss.str();
} }
inline bool HostAndPort::isLocalHost() const { inline bool HostAndPort::isLocalHost() const {
string _host = host();
return ( _host == "localhost" return ( _host == "localhost"
|| startsWith(_host.c_str(), "127.") || startsWith(_host.c_str(), "127.")
|| _host == "::1" || _host == "::1"
|| _host == "anonymous unix socket" || _host == "anonymous unix socket"
|| _host.c_str()[0] == '/' // unix socket || _host.c_str()[0] == '/' // unix socket
); );
} }
inline HostAndPort::HostAndPort(string s) { inline void HostAndPort::init(const char *p) {
const char *p = s.c_str(); uassert(13110, "HostAndPort: bad host:port config string", *p);
uassert(13110, "HostAndPort: bad config string", *p); assert( *p != '#' );
assert( _dynName.empty() );
const char *colon = strrchr(p, ':'); const char *colon = strrchr(p, ':');
if( colon ) { if( colon ) {
int port = atoi(colon+1); int port = atoi(colon+1);
uassert(13095, "HostAndPort: bad port #", port > 0); uassert(13095, "HostAndPort: bad port #", port > 0);
_host = string(p,colon-p); _host = string(p,colon-p);
_port = port; _port = port;
} }
else { else {
// no port specified. // no port specified.
_host = p; _host = p;
_port = -1; _port = -1;
} }
} }
inline HostAndPort::HostAndPort(string s) {
const char *p = s.c_str();
if( *p == '#' ) {
_dynName = s;
_port = -2;
_host = "invalid_hostname_dyn_in_use";
}
else {
init(p);
}
}
} }
 End of changes. 27 change blocks. 
32 lines changed or deleted 110 lines changed or added


 index.h   index.h 
skipping to change at line 33 skipping to change at line 33
#include "jsobj.h" #include "jsobj.h"
#include "indexkey.h" #include "indexkey.h"
#include "key.h" #include "key.h"
namespace mongo { namespace mongo {
class IndexInterface { class IndexInterface {
protected: protected:
virtual ~IndexInterface() { } virtual ~IndexInterface() { }
public: public:
static void phasedBegin();
virtual void phasedQueueItemToInsert(
int idxNo,
DiskLoc thisLoc, DiskLoc _recordLoc, const BSONObj &_key,
const Ordering& _order, IndexDetails& _idx, bool dupsAllowed) =
0;
static void phasedFinish();
virtual int keyCompare(const BSONObj& l,const BSONObj& r, const Ord ering &ordering) = 0; virtual int keyCompare(const BSONObj& l,const BSONObj& r, const Ord ering &ordering) = 0;
virtual long long fullValidate(const DiskLoc& thisLoc, const BSONOb j &order) = 0; virtual long long fullValidate(const DiskLoc& thisLoc, const BSONOb j &order) = 0;
virtual DiskLoc findSingle(const IndexDetails &indexdetails , const DiskLoc& thisLoc, const BSONObj& key) const = 0; virtual DiskLoc findSingle(const IndexDetails &indexdetails , const DiskLoc& thisLoc, const BSONObj& key) const = 0;
virtual bool unindex(const DiskLoc thisLoc, IndexDetails& id, const BSONObj& key, const DiskLoc recordLoc) const = 0; virtual bool unindex(const DiskLoc thisLoc, IndexDetails& id, const BSONObj& key, const DiskLoc recordLoc) const = 0;
virtual int bt_insert(const DiskLoc thisLoc, const DiskLoc recordLo c, virtual int bt_insert(const DiskLoc thisLoc, const DiskLoc recordLo c,
const BSONObj& key, const Ordering &order, bool dupsAllowed, const BSONObj& key, const Ordering &order, bool dupsAllowed,
IndexDetails& idx, bool toplevel = true) const = 0; IndexDetails& idx, bool toplevel = true) const = 0;
virtual DiskLoc addBucket(const IndexDetails&) = 0; virtual DiskLoc addBucket(const IndexDetails&) = 0;
virtual void uassertIfDups(IndexDetails& idx, vector<BSONObj*>& add edKeys, DiskLoc head, virtual void uassertIfDups(IndexDetails& idx, vector<BSONObj*>& add edKeys, DiskLoc head,
DiskLoc self, const Ordering& ordering) = 0; DiskLoc self, const Ordering& ordering) = 0;
 End of changes. 1 change blocks. 
0 lines changed or deleted 8 lines changed or added


 indexkey.h   indexkey.h 
skipping to change at line 30 skipping to change at line 30
#include "../pch.h" #include "../pch.h"
#include "diskloc.h" #include "diskloc.h"
#include "jsobj.h" #include "jsobj.h"
#include <map> #include <map>
namespace mongo { namespace mongo {
extern const int DefaultIndexVersionNumber; extern const int DefaultIndexVersionNumber;
const int ParallelArraysCode = 10088;
class Cursor; class Cursor;
class IndexSpec; class IndexSpec;
class IndexType; // TODO: this name sucks class IndexType; // TODO: this name sucks
class IndexPlugin; class IndexPlugin;
class IndexDetails; class IndexDetails;
enum IndexSuitability { USELESS = 0 , HELPFUL = 1 , OPTIMAL = 2 }; enum IndexSuitability { USELESS = 0 , HELPFUL = 1 , OPTIMAL = 2 };
/** /**
* this represents an instance of a index plugin * this represents an instance of a index plugin
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 instance.h   instance.h 
skipping to change at line 32 skipping to change at line 32
#include "../client/dbclient.h" #include "../client/dbclient.h"
#include "curop-inl.h" #include "curop-inl.h"
#include "security.h" #include "security.h"
#include "cmdline.h" #include "cmdline.h"
#include "client.h" #include "client.h"
namespace mongo { namespace mongo {
extern string dbExecCommand; extern string dbExecCommand;
struct DiagLog { /** a high level recording of operations to the database - sometimes us
ofstream *f; ed for diagnostics
and debugging.
*/
class DiagLog {
ofstream *f; // note this is never freed
/* 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;
mongo::mutex mutex; mongo::mutex mutex;
void openFile();
DiagLog() : f(0) , level(0), mutex("DiagLog") { } public:
void init() { DiagLog();
if ( ! f && level ) { int getLevel() const { return level; }
log() << "diagLogging = " << level << endl;
stringstream ss;
ss << dbpath << "/diaglog." << hex << time(0);
string name = ss.str();
f = new ofstream(name.c_str(), ios::out | ios::binary);
if ( ! f->good() ) {
problem() << "couldn't open log stream" << endl;
throw 1717;
}
}
}
/** /**
* @return old * @return old
*/ */
int setLevel( int newLevel ) { int setLevel( int newLevel );
int old = level; void flush();
level = newLevel; void writeop(char *data,int len);
init(); void readop(char *data, int len);
return old;
}
void flush() {
if ( level ) {
scoped_lock lk(mutex);
f->flush();
}
}
void write(char *data,int len) {
if ( level & 1 ) {
scoped_lock lk(mutex);
f->write(data,len);
}
}
void readop(char *data, int len) {
if ( level & 2 ) {
bool log = (level & 4) == 0;
OCCASIONALLY log = true;
if ( log ) {
scoped_lock lk(mutex);
assert( f );
f->write(data,len);
}
}
}
}; };
extern DiagLog _diaglog; extern DiagLog _diaglog;
/* we defer response until we unlock. don't want a blocked socket to /* we defer response until we unlock. don't want a blocked socket to
keep things locked. keep things locked.
*/ */
struct DbResponse { struct DbResponse {
Message *response; Message *response;
MSGID responseTo; MSGID responseTo;
skipping to change at line 120 skipping to change at line 88
local database does NOT count. local database does NOT count.
*/ */
bool replHasDatabases(); bool replHasDatabases();
/** "embedded" calls to the local server directly. /** "embedded" calls to the local server directly.
Caller does not need to lock, that is handled within. Caller does not need to lock, that is handled within.
*/ */
class DBDirectClient : public DBClientBase { class DBDirectClient : public DBClientBase {
public: public:
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0, virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0,
const BSONObj *fieldsToRetur n = 0, int queryOptions = 0); const BSONObj *fieldsToRetur n = 0, int queryOptions = 0, int batchSize = 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 , string * actualServer = 0 ); virtual bool call( Message &toSend, Message &response, bool assertO k=true , string * actualServer = 0 );
virtual void say( Message &toSend, bool isRetry = false ); virtual void say( Message &toSend, bool isRetry = false , string * actualServer = 0 );
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 );
} }
virtual void killCursor( long long cursorID ); virtual void killCursor( long long cursorID );
virtual bool callRead( Message& toSend , Message& response ) { virtual bool callRead( Message& toSend , Message& response ) {
return call( toSend , response ); return call( toSend , response );
} }
 End of changes. 6 change blocks. 
47 lines changed or deleted 16 lines changed or added


 jsobj.h   jsobj.h 
skipping to change at line 34 skipping to change at line 34
represented in JSON (plus a few extensions useful for databases & other languages). represented in JSON (plus a few extensions useful for databases & other languages).
http://www.bsonspec.org/ http://www.bsonspec.org/
*/ */
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "../bson/util/builder.h" #include "../bson/util/builder.h"
#include "../util/optime.h" #include "../util/optime.h"
#include "boost/utility.hpp" //#include "boost/utility.hpp"
#include <set> //#include <set>
#include "../bson/bsontypes.h" #include "../bson/bsontypes.h"
#include "../bson/oid.h" #include "../bson/oid.h"
#include "../bson/bsonelement.h" #include "../bson/bsonelement.h"
#include "../bson/bsonobj.h" #include "../bson/bsonobj.h"
#include "../bson/bsonmisc.h" #include "../bson/bsonmisc.h"
#include "../bson/bsonobjbuilder.h" #include "../bson/bsonobjbuilder.h"
#include "../bson/bsonobjiterator.h" #include "../bson/bsonobjiterator.h"
#include "../bson/bson-inl.h" #include "../bson/bson-inl.h"
#include "../bson/ordering.h" #include "../bson/ordering.h"
#include "../bson/stringdata.h" #include "../bson/stringdata.h"
#include "../bson/bson_db.h" #include "../bson/bson_db.h"
 End of changes. 2 change blocks. 
3 lines changed or deleted 2 lines changed or added


 jsobjmanipulator.h   jsobjmanipulator.h 
skipping to change at line 22 skipping to change at line 22
* 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 Lice nse * You should have received a copy of the GNU Affero General Public Lice nse
* 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 "dur.h" //#include "dur.h"
namespace mongo { namespace mongo {
/** Manipulate the binary representation of a BSONElement in-place. /** Manipulate the binary representation of a BSONElement in-place.
Careful, this casts away const. Careful, this casts away const.
*/ */
class BSONElementManipulator { class BSONElementManipulator {
public: public:
BSONElementManipulator( const BSONElement &element ) : BSONElementManipulator( const BSONElement &element ) :
_element( element ) { _element( element ) {
assert( !_element.eoo() ); assert( !_element.eoo() );
} }
/** Replace a Timestamp type with a Date type initialized to /** Replace a Timestamp type with a Date type initialized to
OpTime::now().asDate() OpTime::now().asDate()
*/ */
void initTimestamp(); void initTimestamp();
// Note the ones with a capital letter call getDur().writing and jo
urnal
/** Change the value, in place, of the number. */ /** Change the value, in place, of the number. */
void setNumber(double d) { void setNumber(double d) {
if ( _element.type() == NumberDouble ) *reinterpret_cast< doubl e * >( value() ) = d; if ( _element.type() == NumberDouble ) *reinterpret_cast< doubl e * >( value() ) = d;
else if ( _element.type() == NumberInt ) *reinterpret_cast< int * >( value() ) = (int) d; else if ( _element.type() == NumberInt ) *reinterpret_cast< int * >( value() ) = (int) d;
else assert(0); else assert(0);
} }
void SetNumber(double d) { void SetNumber(double d);
if ( _element.type() == NumberDouble )
*getDur().writing( reinterpret_cast< double * >( value() )
) = d;
else if ( _element.type() == NumberInt )
*getDur().writing( reinterpret_cast< int * >( value() ) ) =
(int) d;
else assert(0);
}
void setLong(long long n) { void setLong(long long n) {
assert( _element.type() == NumberLong ); assert( _element.type() == NumberLong );
*reinterpret_cast< long long * >( value() ) = n; *reinterpret_cast< long long * >( value() ) = n;
} }
void SetLong(long long n) { void SetLong(long long n);
assert( _element.type() == NumberLong );
*getDur().writing( reinterpret_cast< long long * >(value()) ) =
n;
}
void setInt(int n) { void setInt(int n) {
assert( _element.type() == NumberInt ); assert( _element.type() == NumberInt );
*reinterpret_cast< int * >( value() ) = n; *reinterpret_cast< int * >( value() ) = n;
} }
void SetInt(int n) { void SetInt(int n);
assert( _element.type() == NumberInt );
getDur().writingInt( *reinterpret_cast< int * >( value() ) ) =
n;
}
/** Replace the type and value of the element with the type and val ue of e, /** Replace the type and value of the element with the type and val ue of e,
preserving the original fieldName */ preserving the original fieldName */
void replaceTypeAndValue( const BSONElement &e ) { void replaceTypeAndValue( const BSONElement &e ) {
*data() = e.type(); *data() = e.type();
memcpy( value(), e.value(), e.valuesize() ); memcpy( value(), e.value(), e.valuesize() );
} }
/* dur:: version */ /* dur:: version */
void ReplaceTypeAndValue( const BSONElement &e ) { void ReplaceTypeAndValue( const BSONElement &e );
char *d = data();
char *v = value();
int valsize = e.valuesize();
int ofs = (int) (v-d);
dassert( ofs > 0 );
char *p = (char *) getDur().writingPtr(d, valsize + ofs);
*p = e.type();
memcpy( p + ofs, e.value(), valsize );
}
static void lookForTimestamps( const BSONObj& obj ) { static void lookForTimestamps( const BSONObj& obj ) {
// If have a Timestamp field as the first or second element, // If have a Timestamp field as the first or second element,
// update it to a Date field set to OpTime::now().asDate(). Th e // update it to a Date field set to OpTime::now().asDate(). Th e
// replacement policy is a work in progress. // replacement policy is a work in progress.
BSONObjIterator i( obj ); BSONObjIterator i( obj );
for( int j = 0; i.moreWithEOO() && j < 2; ++j ) { for( int j = 0; i.moreWithEOO() && j < 2; ++j ) {
BSONElement e = i.next(); BSONElement e = i.next();
if ( e.eoo() ) if ( e.eoo() )
 End of changes. 6 change blocks. 
30 lines changed or deleted 8 lines changed or added


 key.h   key.h 
skipping to change at line 99 skipping to change at line 99
const unsigned char *_keyData; const unsigned char *_keyData;
BSONObj bson() const { BSONObj bson() const {
dassert( !isCompactFormat() ); dassert( !isCompactFormat() );
return BSONObj((const char *) _keyData+1); return BSONObj((const char *) _keyData+1);
} }
private: private:
int compareHybrid(const KeyV1& right, const Ordering& order) const; int compareHybrid(const KeyV1& right, const Ordering& order) const;
}; };
class KeyV1Owned : public KeyV1 { class KeyV1Owned : public KeyV1 {
KeyV1Owned(const KeyV1Owned&); // not copyable -- StackBufBuilder i s not copyable and that owns our buffer
void operator=(const KeyV1Owned&); void operator=(const KeyV1Owned&);
public: public:
/** @obj a BSON object to be translated to KeyV1 format. If the ob ject isn't /** @obj a BSON object to be translated to KeyV1 format. If the ob ject isn't
representable in KeyV1 format (which happens, intentionall y, at times) representable in KeyV1 format (which happens, intentionall y, at times)
it will stay as bson herein. it will stay as bson herein.
*/ */
KeyV1Owned(const BSONObj& obj); KeyV1Owned(const BSONObj& obj);
/** makes a copy (memcpy's the whole thing) */
KeyV1Owned(const KeyV1& rhs);
private: private:
StackBufBuilder b; StackBufBuilder b;
void traditional(const BSONObj& obj); // store as traditional bson not as compact format void traditional(const BSONObj& obj); // store as traditional bson not as compact format
}; };
}; };
 End of changes. 2 change blocks. 
1 lines changed or deleted 4 lines changed or added


 lasterror.h   lasterror.h 
skipping to change at line 31 skipping to change at line 31
namespace mongo { namespace mongo {
class BSONObjBuilder; class BSONObjBuilder;
class Message; class Message;
struct LastError { struct LastError {
int code; int code;
string msg; string msg;
enum UpdatedExistingType { NotUpdate, True, False } updatedExisting ; enum UpdatedExistingType { NotUpdate, True, False } updatedExisting ;
OID upsertedId; OID upsertedId;
OID writebackId; OID writebackId; // this shouldn't get reset so that old GLE are ha ndled
long long nObjects; long long nObjects;
int nPrev; int nPrev;
bool valid; bool valid;
bool disabled; bool disabled;
void writeback( OID& oid ) { void writeback( OID& oid ) {
reset( true ); reset( true );
writebackId = oid; writebackId = oid;
} }
void raiseError(int _code , const char *_msg) { void raiseError(int _code , const char *_msg) {
reset( true ); reset( true );
skipping to change at line 69 skipping to change at line 69
} }
void reset( bool _valid = false ) { void reset( bool _valid = false ) {
code = 0; code = 0;
msg.clear(); msg.clear();
updatedExisting = NotUpdate; updatedExisting = NotUpdate;
nObjects = 0; nObjects = 0;
nPrev = 1; nPrev = 1;
valid = _valid; valid = _valid;
disabled = false; disabled = false;
upsertedId.clear(); upsertedId.clear();
writebackId.clear();
} }
/** /**
* @return if there is an err * @return if there is an err
*/ */
bool appendSelf( BSONObjBuilder &b , bool blankErr = true ); bool appendSelf( BSONObjBuilder &b , bool blankErr = true );
/**
* appends fields which are not "error" related
* this whole mechanism needs to be re-written
* but needs a lot of real thought
*/
void appendSelfStatus( BSONObjBuilder &b );
struct Disabled : boost::noncopyable { struct Disabled : boost::noncopyable {
Disabled( LastError * le ) { Disabled( LastError * le ) {
_le = le; _le = le;
if ( _le ) { if ( _le ) {
_prev = _le->disabled; _prev = _le->disabled;
_le->disabled = true; _le->disabled = true;
} }
else { else {
_prev = false; _prev = false;
} }
 End of changes. 3 change blocks. 
2 lines changed or deleted 8 lines changed or added


 linenoise.h   linenoise.h 
skipping to change at line 39 skipping to change at line 39
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF T HE * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF T HE
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef __LINENOISE_H #ifndef __LINENOISE_H
#define __LINENOISE_H #define __LINENOISE_H
typedef struct linenoiseCompletions { struct linenoiseCompletions {
size_t len; int completionCount;
char **cvec; char * * completionStrings;
} linenoiseCompletions; };
typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletion typedef void( linenoiseCompletionCallback )( const char *, linenoiseComplet
s *); ions * );
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); void linenoiseSetCompletionCallback( linenoiseCompletionCallback * fn );
void linenoiseAddCompletion(linenoiseCompletions *, const char *); void linenoiseAddCompletion( linenoiseCompletions * lc, const char * str );
char *linenoise(const char *prompt); char *linenoise( const char* prompt );
int linenoiseHistoryAdd(const char *line); int linenoiseHistoryAdd( const char* line );
int linenoiseHistorySetMaxLen(int len); int linenoiseHistorySetMaxLen( int len );
int linenoiseHistorySave(const char *filename); int linenoiseHistorySave( const char* filename );
int linenoiseHistoryLoad(const char *filename); int linenoiseHistoryLoad( const char* filename );
void linenoiseClearScreen(void); void linenoiseHistoryFree( void );
void linenoiseClearScreen( void );
#endif /* __LINENOISE_H */ #endif /* __LINENOISE_H */
 End of changes. 3 change blocks. 
14 lines changed or deleted 15 lines changed or added


 list.h   list.h 
skipping to change at line 23 skipping to change at line 23
* 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
namespace mongo { namespace mongo {
/* this class uses a mutex for writes, but not for reads. /* DONT USE THIS. it was a dumb idea.
this class uses a mutex for writes, but not for reads.
we can get fancier later... we can get fancier later...
struct Member : public List1<Member>::Base { struct Member : public List1<Member>::Base {
const char *host; const char *host;
int port; int port;
}; };
List1<Member> _members; List1<Member> _members;
_members.head()->next(); _members.head()->next();
*/ */
 End of changes. 1 change blocks. 
1 lines changed or deleted 3 lines changed or added


 listen.h   listen.h 
skipping to change at line 86 skipping to change at line 86
long long _elapsedTime; long long _elapsedTime;
#ifdef MONGO_SSL #ifdef MONGO_SSL
SSLManager* _ssl; SSLManager* _ssl;
int _sslPort; int _sslPort;
#endif #endif
/** /**
* @return true iff everything went ok * @return true iff everything went ok
*/ */
bool _setupSockets( const vector<SockAddr>& mine , vector<int>& soc ks ); bool _setupSockets( const vector<SockAddr>& mine , vector<SOCKET>& socks );
void _logListen( int port , bool ssl ); void _logListen( int port , bool ssl );
static const Listener* _timeTracker; static const Listener* _timeTracker;
virtual bool useUnixSockets() const { return false; } virtual bool useUnixSockets() const { return false; }
}; };
/** /**
* keep track of elapsed time * keep track of elapsed time
skipping to change at line 111 skipping to change at line 111
public: public:
ElapsedTracker( int hitsBetweenMarks , int msBetweenMarks ) ElapsedTracker( int hitsBetweenMarks , int msBetweenMarks )
: _h( hitsBetweenMarks ) , _ms( msBetweenMarks ) , _pings(0) { : _h( hitsBetweenMarks ) , _ms( msBetweenMarks ) , _pings(0) {
_last = Listener::getElapsedTimeMillis(); _last = Listener::getElapsedTimeMillis();
} }
/** /**
* call this for every iteration * call this for every iteration
* returns true if one of the triggers has gone off * returns true if one of the triggers has gone off
*/ */
bool ping() { bool intervalHasElapsed() {
if ( ( ++_pings % _h ) == 0 ) { if ( ( ++_pings % _h ) == 0 ) {
_last = Listener::getElapsedTimeMillis(); _last = Listener::getElapsedTimeMillis();
return true; return true;
} }
long long now = Listener::getElapsedTimeMillis(); long long now = Listener::getElapsedTimeMillis();
if ( now - _last > _ms ) { if ( now - _last > _ms ) {
_last = now; _last = now;
return true; return true;
} }
return false; return false;
} }
void resetLastTime() {
_last = Listener::getElapsedTimeMillis();
}
private: private:
int _h; const int _h;
int _ms; const int _ms;
unsigned long long _pings; unsigned long long _pings;
long long _last; long long _last;
}; };
class ListeningSockets { class ListeningSockets {
public: public:
ListeningSockets() ListeningSockets()
 End of changes. 4 change blocks. 
8 lines changed or deleted 4 lines changed or added


 log.h   log.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 <string.h> #include <string.h>
#include <sstream>
#include <errno.h> #include <errno.h>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/thread/tss.hpp>
#include "../bson/util/builder.h" #include "../bson/util/builder.h"
#include "debug_util.h"
#ifndef _WIN32 #ifndef _WIN32
//#include <syslog.h> #include <syslog.h>
#endif #endif
namespace mongo { namespace mongo {
enum ExitCode;
enum LogLevel { LL_DEBUG , LL_INFO , LL_NOTICE , LL_WARNING , LL_ERROR , LL_SEVERE }; enum LogLevel { LL_DEBUG , LL_INFO , LL_NOTICE , LL_WARNING , LL_ERROR , LL_SEVERE };
inline const char * logLevelToString( LogLevel l ) { inline const char * logLevelToString( LogLevel l ) {
switch ( l ) { switch ( l ) {
case LL_DEBUG: case LL_DEBUG:
case LL_INFO: case LL_INFO:
case LL_NOTICE: case LL_NOTICE:
return ""; return "";
case LL_WARNING: case LL_WARNING:
return "warning" ; return "warning" ;
case LL_ERROR: case LL_ERROR:
return "ERROR"; return "ERROR";
case LL_SEVERE: case LL_SEVERE:
return "SEVERE"; return "SEVERE";
default: default:
return "UNKNOWN"; return "UNKNOWN";
} }
} }
#ifndef _WIN32
inline const int logLevelToSysLogLevel( LogLevel l) {
switch ( l ) {
case LL_DEBUG:
return LOG_DEBUG;
case LL_INFO:
return LOG_INFO;
case LL_NOTICE:
return LOG_NOTICE;
case LL_WARNING:
return LOG_WARNING;
case LL_ERROR:
return LOG_ERR;
case LL_SEVERE:
return LOG_CRIT;
default:
return LL_INFO;
}
}
#endif
class LabeledLevel { class LabeledLevel {
public: public:
LabeledLevel( int level ) : _level( level ) {} LabeledLevel( int level ) : _level( level ) {}
LabeledLevel( const char* label, int level ) : _label( label ), _lev el( level ) {} LabeledLevel( const char* label, int level ) : _label( label ), _lev el( level ) {}
LabeledLevel( const string& label, int level ) : _label( label ), _l evel( level ) {} LabeledLevel( const string& label, int level ) : _label( label ), _l evel( level ) {}
LabeledLevel operator+( int i ) const { LabeledLevel operator+( int i ) const {
return LabeledLevel( _label, _level + i ); return LabeledLevel( _label, _level + i );
} }
skipping to change at line 197 skipping to change at line 226
return *this; return *this;
} }
virtual Nullstream& operator<< (ios_base& (*hex)(ios_base&)) { virtual Nullstream& operator<< (ios_base& (*hex)(ios_base&)) {
return *this; return *this;
} }
virtual void flush(Tee *t = 0) {} virtual void flush(Tee *t = 0) {}
}; };
extern Nullstream nullstream; extern Nullstream nullstream;
class mutex;
class Logstream : public Nullstream { class Logstream : public Nullstream {
static mongo::mutex mutex; static mongo::mutex mutex;
static int doneSetup; static int doneSetup;
stringstream ss; stringstream ss;
int indent; int indent;
LogLevel logLevel; LogLevel logLevel;
static FILE* logfile; static FILE* logfile;
static boost::scoped_ptr<ostream> stream; static boost::scoped_ptr<ostream> stream;
static vector<Tee*> * globalTees; static vector<Tee*> * globalTees;
static bool isSyslog;
public: public:
inline static void logLockless( const StringData& s ); static void logLockless( const StringData& s );
static void setLogFile(FILE* f) { static void setLogFile(FILE* f);
scoped_lock lk(mutex); #ifndef _WIN32
logfile = f; static void useSyslog(const char * name) {
} cout << "using syslog ident: " << name << endl;
// openlog requires heap allocated non changing pointer
// this should only be called once per pragram execution
static int magicNumber() { char * newName = (char *) malloc( strlen(name) + 1 );
return 1717; strcpy( newName , name);
openlog( newName , LOG_ODELAY , LOG_USER );
isSyslog = true;
} }
#endif
static int magicNumber() { return 1717; }
static int getLogDesc() { static int getLogDesc() {
int fd = -1; int fd = -1;
if (logfile != NULL) if (logfile != NULL)
#if defined(_WIN32) #if defined(_WIN32)
// the ISO C++ conformant name is _fileno // the ISO C++ conformant name is _fileno
fd = _fileno( logfile ); fd = _fileno( logfile );
#else #else
fd = fileno( logfile ); fd = fileno( logfile );
#endif #endif
return fd; return fd;
} }
inline void flush(Tee *t = 0); void flush(Tee *t = 0);
inline Nullstream& setLogLevel(LogLevel l) { inline Nullstream& setLogLevel(LogLevel l) {
logLevel = l; logLevel = l;
return *this; return *this;
} }
/** note these are virtual */ /** note these are virtual */
Logstream& operator<<(const char *x) { ss << x; return *this; } Logstream& operator<<(const char *x) { ss << x; return *this; }
Logstream& operator<<(const string& x) { ss << x; return *this; } Logstream& operator<<(const string& x) { ss << x; return *this; }
Logstream& operator<<(const StringData& x) { ss << x.data(); return *this; } Logstream& operator<<(const StringData& x) { ss << x.data(); return *this; }
skipping to change at line 290 skipping to change at line 330
if ( ! globalTees ) if ( ! globalTees )
globalTees = new vector<Tee*>(); globalTees = new vector<Tee*>();
globalTees->push_back( t ); globalTees->push_back( t );
} }
void indentInc(){ indent++; } void indentInc(){ indent++; }
void indentDec(){ indent--; } void indentDec(){ indent--; }
int getIndent() const { return indent; } int getIndent() const { return indent; }
private: private:
static thread_specific_ptr<Logstream> tsp; static boost::thread_specific_ptr<Logstream> tsp;
Logstream() { Logstream() {
indent = 0; indent = 0;
_init(); _init();
} }
void _init() { void _init() {
ss.str(""); ss.str("");
logLevel = LL_INFO; logLevel = LL_INFO;
} }
public: public:
static Logstream& get() { static Logstream& get();
if ( StaticObserver::_destroyingStatics ) {
cout << "Logstream::get called in uninitialized state" << e
ndl;
}
Logstream *p = tsp.get();
if( p == 0 )
tsp.reset( p = new Logstream() );
return *p;
}
}; };
extern int logLevel; extern int logLevel;
extern int tlogLevel; extern int tlogLevel;
inline Nullstream& out( int level = 0 ) { inline Nullstream& out( int level = 0 ) {
if ( level > logLevel ) if ( level > logLevel )
return nullstream; return nullstream;
return Logstream::get(); return Logstream::get();
} }
skipping to change at line 342 skipping to change at line 374
} }
/** logging which we may not want during unit tests (dbtests) runs. /** logging which we may not want during unit tests (dbtests) runs.
set tlogLevel to -1 to suppress tlog() output in a test program. */ set tlogLevel to -1 to suppress tlog() output in a test program. */
inline Nullstream& tlog( int level = 0 ) { inline Nullstream& tlog( int level = 0 ) {
if ( level > tlogLevel || level > logLevel ) if ( level > tlogLevel || level > logLevel )
return nullstream; return nullstream;
return Logstream::get().prolog(); return Logstream::get().prolog();
} }
// log if debug build or if at a certain level
inline Nullstream& dlog( int level ) {
if ( level <= logLevel || DEBUG_BUILD )
return Logstream::get().prolog();
return nullstream;
}
inline Nullstream& log( int level ) { inline Nullstream& log( int level ) {
if ( level > logLevel ) if ( level > logLevel )
return nullstream; return nullstream;
return Logstream::get().prolog(); return Logstream::get().prolog();
} }
#define MONGO_LOG(level) if ( MONGO_unlikely(logLevel >= (level)) ) log( le vel ) #define MONGO_LOG(level) if ( MONGO_likely(logLevel < (level)) ) { } else l og( level )
#define LOG MONGO_LOG #define LOG MONGO_LOG
inline Nullstream& log( LogLevel l ) { inline Nullstream& log( LogLevel l ) {
return Logstream::get().prolog().setLogLevel( l ); return Logstream::get().prolog().setLogLevel( l );
} }
inline Nullstream& log( const LabeledLevel& ll ) { inline Nullstream& log( const LabeledLevel& ll ) {
Nullstream& stream = log( ll.getLevel() ); Nullstream& stream = log( ll.getLevel() );
if( ll.getLabel() != "" ) if( ll.getLabel() != "" )
stream << "[" << ll.getLabel() << "] "; stream << "[" << ll.getLabel() << "] ";
skipping to change at line 394 skipping to change at line 433
/** /**
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 );
std::string toUtf8String(const std::wstring& wide); std::string toUtf8String(const std::wstring& wide);
inline string errnoWithDescription(int x = errno) {
stringstream s;
s << "errno:" << x << ' ';
#if defined(_WIN32)
LPTSTR errorText = NULL;
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM
|FORMAT_MESSAGE_ALLOCATE_BUFFER
|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
x, 0,
(LPTSTR) &errorText, // output
0, // minimum size for output buffer
NULL);
if( errorText ) {
string x = toUtf8String(errorText);
for( string::iterator i = x.begin(); i != x.end(); i++ ) {
if( *i == '\n' || *i == '\r' )
break;
s << *i;
}
LocalFree(errorText);
}
else
s << strerror(x);
/*
DWORD n = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, x,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf, 0, NULL);
*/
#else
s << strerror(x);
#endif
return s.str();
}
/** output the error # and error message with prefix. /** output the error # and error message with prefix.
handy for use as parm in uassert/massert. handy for use as parm in uassert/massert.
*/ */
string errnoWithPrefix( const char * prefix ); string errnoWithPrefix( const char * prefix );
void Logstream::logLockless( const StringData& s ) {
if ( s.size() == 0 )
return;
if ( doneSetup == 1717 ) {
if (fwrite(s.data(), s.size(), 1, logfile)) {
fflush(logfile);
}
else {
int x = errno;
cout << "Failed to write to logfile: " << errnoWithDescript
ion(x) << endl;
}
}
else {
cout << s.data();
cout.flush();
}
}
void Logstream::flush(Tee *t) {
// this ensures things are sane
if ( doneSetup == 1717 ) {
string msg = ss.str();
string threadName = getThreadName();
const char * type = logLevelToString(logLevel);
int spaceNeeded = (int)(msg.size() + 64 + threadName.size());
int bufSize = 128;
while ( bufSize < spaceNeeded )
bufSize += 128;
BufBuilder b(bufSize);
time_t_to_String( time(0) , b.grow(20) );
if (!threadName.empty()) {
b.appendChar( '[' );
b.appendStr( threadName , false );
b.appendChar( ']' );
b.appendChar( ' ' );
}
for ( int i=0; i<indent; i++ )
b.appendChar( '\t' );
if ( type[0] ) {
b.appendStr( type , false );
b.appendStr( ": " , false );
}
b.appendStr( msg );
string out( b.buf() , b.len() - 1);
scoped_lock lk(mutex);
if( t ) t->write(logLevel,out);
if ( globalTees ) {
for ( unsigned i=0; i<globalTees->size(); i++ )
(*globalTees)[i]->write(logLevel,out);
}
#ifndef _WIN32
//syslog( LOG_INFO , "%s" , cc );
#endif
if(fwrite(out.data(), out.size(), 1, logfile)) {
fflush(logfile);
}
else {
int x = errno;
cout << "Failed to write to logfile: " << errnoWithDescript
ion(x) << ": " << out << endl;
}
#ifdef POSIX_FADV_DONTNEED
// This only applies to pages that have already been flushed
RARELY posix_fadvise(fileno(logfile), 0, 0, POSIX_FADV_DONTNEED
);
#endif
}
_init();
}
struct LogIndentLevel { struct LogIndentLevel {
LogIndentLevel(){ LogIndentLevel(){
Logstream::get().indentInc(); Logstream::get().indentInc();
} }
~LogIndentLevel(){ ~LogIndentLevel(){
Logstream::get().indentDec(); Logstream::get().indentDec();
} }
}; };
extern Tee* const warnings; // Things put here go in serverStatus extern Tee* const warnings; // Things put here go in serverStatus
string errnoWithDescription(int errorcode = -1);
} // namespace mongo } // namespace mongo
 End of changes. 20 change blocks. 
145 lines changed or deleted 61 lines changed or added


 logfile.h   logfile.h 
skipping to change at line 28 skipping to change at line 28
#pragma once #pragma once
namespace mongo { namespace mongo {
class LogFile { class LogFile {
public: public:
/** create the file and open. must not already exist. /** create the file and open. must not already exist.
throws UserAssertion on i/o error throws UserAssertion on i/o error
*/ */
LogFile(string name); LogFile(string name, bool readwrite = false);
/** closes */ /** closes */
~LogFile(); ~LogFile();
/** append to file. does not return until sync'd. uses direct i/o when possible. /** append to file. does not return until sync'd. uses direct i/o when possible.
throws UserAssertion on an i/o error throws UserAssertion on an i/o error
note direct i/o may have alignment requirements note direct i/o may have alignment requirements
*/ */
void synchronousAppend(const void *buf, size_t len); void synchronousAppend(const void *buf, size_t len);
/** write at specified offset. must be aligned. noreturn until phy
sically written. thread safe */
void writeAt(unsigned long long offset, const void *_bug, size_t _l
en);
void readAt(unsigned long long offset, void *_buf, size_t _len);
const string _name; const string _name;
void truncate(); // Removes extra data after current position void truncate(); // Removes extra data after current position
private: private:
#if defined(_WIN32) #if defined(_WIN32)
typedef HANDLE fd_type; typedef HANDLE fd_type;
#else #else
typedef int fd_type; typedef int fd_type;
#endif #endif
 End of changes. 2 change blocks. 
1 lines changed or deleted 8 lines changed or added


 matcher.h   matcher.h 
skipping to change at line 65 skipping to change at line 65
ElementMatcher() { ElementMatcher() {
} }
ElementMatcher( BSONElement e , int op, bool isNot ); ElementMatcher( BSONElement e , int op, bool isNot );
ElementMatcher( BSONElement e , int op , const BSONObj& array, bool isNot ); ElementMatcher( BSONElement e , int op , const BSONObj& array, bool isNot );
~ElementMatcher() { } ~ElementMatcher() { }
bool negativeCompareOp() const { return _compareOp == BSONObj::NE |
| _compareOp == BSONObj::NIN; }
int inverseOfNegativeCompareOp() const;
bool negativeCompareOpContainsNull() const;
BSONElement _toMatch; BSONElement _toMatch;
int _compareOp; int _compareOp;
bool _isNot; bool _isNot;
shared_ptr< set<BSONElement,element_lt> > _myset; shared_ptr< set<BSONElement,element_lt> > _myset;
shared_ptr< vector<RegexMatcher> > _myregex; shared_ptr< vector<RegexMatcher> > _myregex;
// these are for specific operators // these are for specific operators
int _mod; int _mod;
int _modm; int _modm;
BSONType _type; BSONType _type;
skipping to change at line 124 skipping to change at line 128
{ a : { $gt : 3 } } { a : { $gt : 3 } }
Not equal: Not equal:
{ a : { $ne : 3 } } { a : { $ne : 3 } }
TODO: we should rewrite the matcher to be more an AST style. TODO: we should rewrite the matcher to be more an AST style.
*/ */
class Matcher : boost::noncopyable { class Matcher : boost::noncopyable {
int matchesDotted( int matchesDotted(
const char *fieldName, const char *fieldName,
const BSONElement& toMatch, const BSONObj& obj, const BSONElement& toMatch, const BSONObj& obj,
int compareOp, const ElementMatcher& bm, bool isArr , MatchDeta ils * details ); int compareOp, const ElementMatcher& bm, bool isArr , MatchDeta ils * details ) const;
int matchesNe( /**
* Perform a NE or NIN match by returning the inverse of the opposi
te matching operation.
* Missing values are considered matches unless the match must not
equal null.
*/
int inverseMatch(
const char *fieldName, const char *fieldName,
const BSONElement &toMatch, const BSONObj &obj, const BSONElement &toMatch, const BSONObj &obj,
const ElementMatcher&bm, MatchDetails * details ); const ElementMatcher&bm, MatchDetails * details ) const;
public: public:
static int opDirection(int op) { static int opDirection(int op) {
return op <= BSONObj::LTE ? -1 : 1; return op <= BSONObj::LTE ? -1 : 1;
} }
Matcher(const BSONObj &pattern, bool nested=false); Matcher(const BSONObj &pattern, bool nested=false);
~Matcher(); ~Matcher();
bool matches(const BSONObj& j, MatchDetails * details = 0 ); bool matches(const BSONObj& j, MatchDetails * details = 0 ) const;
bool atomic() const { return _atomic; } bool atomic() const { return _atomic; }
string toString() const { string toString() const {
return _jsobj.toString(); return _jsobj.toString();
} }
void addOrDedupConstraint( const shared_ptr< FieldRangeVector > &fr v ) { void addOrDedupConstraint( const shared_ptr< FieldRangeVector > &fr v ) {
_orDedupConstraints.push_back( frv ); _orDedupConstraints.push_back( frv );
} }
skipping to change at line 162 skipping to change at line 170
void popOrClause() { void popOrClause() {
_orMatchers.pop_front(); _orMatchers.pop_front();
} }
/** /**
* @return true if this key matcher will return the same true/false * @return true if this key matcher will return the same true/false
* value as the provided doc matcher. * value as the provided doc matcher.
*/ */
bool keyMatch( const Matcher &docMatcher ) const; bool keyMatch( const Matcher &docMatcher ) const;
bool singleSimpleCriterion() const {
return false; // TODO SERVER-958
// // TODO Really check, especially if all basics are ok.
// // $all, etc
// // _orConstraints?
// return ( ( basics.size() + nRegex ) < 2 ) && !where && !_orMa
tchers.size() && !_norMatchers.size();
}
const BSONObj *getQuery() const { return &_jsobj; };
private: private:
/** /**
* Generate a matcher for the provided index key format using the * Generate a matcher for the provided index key format using the
* provided full doc matcher. * provided full doc matcher.
*/ */
Matcher( const Matcher &docMatcher, const BSONObj &constrainIndexKe y ); Matcher( const Matcher &docMatcher, const BSONObj &constrainIndexKe y );
void addBasic(const BSONElement &e, int c, bool isNot) { void addBasic(const BSONElement &e, int c, bool isNot) {
// TODO May want to selectively ignore these element types base d on op type. // TODO May want to selectively ignore these element types base d on op type.
if ( e.type() == MinKey || e.type() == MaxKey ) if ( e.type() == MinKey || e.type() == MaxKey )
return; return;
_basics.push_back( ElementMatcher( e , c, isNot ) ); _basics.push_back( ElementMatcher( e , c, isNot ) );
} }
void addRegex(const char *fieldName, const char *regex, const char *flags, bool isNot = false); void addRegex(const char *fieldName, const char *regex, const char *flags, bool isNot = false);
bool addOp( const BSONElement &e, const BSONElement &fe, bool isNot , const char *& regex, const char *&flags ); bool addOp( const BSONElement &e, const BSONElement &fe, bool isNot , const char *& regex, const char *&flags );
int valuesMatch(const BSONElement& l, const BSONElement& r, int op, const ElementMatcher& bm); int valuesMatch(const BSONElement& l, const BSONElement& r, int op, const ElementMatcher& bm) const;
bool parseClause( const BSONElement &e ); bool parseClause( const BSONElement &e );
void parseExtractedClause( const BSONElement &e, list< shared_ptr< Matcher > > &matchers ); void parseExtractedClause( const BSONElement &e, list< shared_ptr< Matcher > > &matchers );
void parseWhere( const BSONElement &e );
void parseMatchExpressionElement( const BSONElement &e, bool nested ); void parseMatchExpressionElement( const BSONElement &e, bool nested );
Where *_where; // set if query uses $where Where *_where; // set if query uses $where
BSONObj _jsobj; // the query pattern. e.g., { nam e: "joe" } BSONObj _jsobj; // the query pattern. e.g., { nam e: "joe" }
BSONObj _constrainIndexKey; BSONObj _constrainIndexKey;
vector<ElementMatcher> _basics; vector<ElementMatcher> _basics;
bool _haveSize; bool _haveSize;
bool _all; bool _all;
bool _hasArray; bool _hasArray;
bool _haveNeg; bool _haveNeg;
/* $atomic - if true, a multi document operation (some removes, upd ates) /* $atomic - if true, a multi document operation (some removes, upd ates)
should be done atomically. in that case, we do not yi eld - should be done atomically. in that case, we do not yi eld -
i.e. we stay locked the whole time. i.e. we stay locked the whole time.
http://www.mongodb.org/display/DOCS/Removing[ http://www.mongodb.org/display/DOCS/Removing[
*/ */
bool _atomic; bool _atomic;
RegexMatcher _regexs[4]; vector<RegexMatcher> _regexs;
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;
list< shared_ptr< Matcher > > _andMatchers; list< shared_ptr< Matcher > > _andMatchers;
list< shared_ptr< Matcher > > _orMatchers; list< shared_ptr< Matcher > > _orMatchers;
list< shared_ptr< Matcher > > _norMatchers; list< shared_ptr< Matcher > > _norMatchers;
vector< shared_ptr< FieldRangeVector > > _orDedupConstraints; vector< shared_ptr< FieldRangeVector > > _orDedupConstraints;
friend class CoveredIndexMatcher; friend class CoveredIndexMatcher;
}; };
 End of changes. 9 change blocks. 
7 lines changed or deleted 29 lines changed or added


 message.h   message.h 
skipping to change at line 78 skipping to change at line 78
case opReply: case opReply:
case dbMsg: case dbMsg:
case dbQuery: case dbQuery:
case dbGetMore: case dbGetMore:
case dbKillCursors: case dbKillCursors:
return false; return false;
case dbUpdate: case dbUpdate:
case dbInsert: case dbInsert:
case dbDelete: case dbDelete:
return false; return true;
default: default:
PRINT(op); PRINT(op);
assert(0); assert(0);
return ""; return "";
} }
} }
#pragma pack(1) #pragma pack(1)
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 message_port.h   message_port.h 
skipping to change at line 40 skipping to change at line 40
class AbstractMessagingPort : boost::noncopyable { class AbstractMessagingPort : boost::noncopyable {
public: public:
AbstractMessagingPort() : tag(0) {} AbstractMessagingPort() : tag(0) {}
virtual ~AbstractMessagingPort() { } virtual ~AbstractMessagingPort() { }
virtual void reply(Message& received, Message& response, MSGID resp onseTo) = 0; // like the reply below, but doesn't rely on received.data sti ll being available virtual void reply(Message& received, Message& response, MSGID resp onseTo) = 0; // like the reply below, but doesn't rely on received.data sti ll being available
virtual void reply(Message& received, Message& response) = 0; virtual void reply(Message& received, Message& response) = 0;
virtual HostAndPort remote() const = 0; virtual HostAndPort remote() const = 0;
virtual unsigned remotePort() const = 0; virtual unsigned remotePort() const = 0;
private: virtual void assertStillConnected() = 0;
public: public:
// TODO make this private with some helpers // TODO make this private with some helpers
/* ports can be tagged with various classes. see closeAllSockets(t ag). defaults to 0. */ /* ports can be tagged with various classes. see closeAllSockets(t ag). defaults to 0. */
unsigned tag; unsigned tag;
}; };
class MessagingPort : public AbstractMessagingPort , public Socket { class MessagingPort : public AbstractMessagingPort , public Socket {
skipping to change at line 91 skipping to change at line 91
* Note: if you fail to call recv and someone else uses this port, * Note: if you fail to call recv and someone else uses this port,
* horrible things will happend * horrible things will happend
*/ */
bool recv( const Message& sent , Message& response ); bool recv( const Message& sent , Message& response );
void piggyBack( Message& toSend , int responseTo = -1 ); void piggyBack( Message& toSend , int responseTo = -1 );
unsigned remotePort() const { return Socket::remotePort(); } unsigned remotePort() const { return Socket::remotePort(); }
virtual HostAndPort remote() const; virtual HostAndPort remote() const;
void assertStillConnected();
private: private:
PiggyBackData * piggyBackData; PiggyBackData * piggyBackData;
// this is the parsed version of remote // this is the parsed version of remote
// mutable because its initialized only on call to remote() // mutable because its initialized only on call to remote()
mutable HostAndPort _remoteParsed; mutable HostAndPort _remoteParsed;
public: public:
static void closeAllSockets(unsigned tagMask = 0xffffffff); static void closeAllSockets(unsigned tagMask = 0xffffffff);
 End of changes. 2 change blocks. 
1 lines changed or deleted 3 lines changed or added


 message_server.h   message_server.h 
skipping to change at line 29 skipping to change at line 29
abstract database server abstract database server
async io core, worker thread system async io core, worker thread system
*/ */
#pragma once #pragma once
#include "../../pch.h" #include "../../pch.h"
namespace mongo { namespace mongo {
struct LastError;
class MessageHandler { class MessageHandler {
public: public:
virtual ~MessageHandler() {} virtual ~MessageHandler() {}
/** /**
* called once when a socket is connected * called once when a socket is connected
*/ */
virtual void connected( AbstractMessagingPort* p ) = 0; virtual void connected( AbstractMessagingPort* p ) = 0;
/** /**
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 misc.h   misc.h 
skipping to change at line 79 skipping to change at line 79
return buf; return buf;
} }
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; }
void toTm (tm *buf) {
time_t dtime = (time_t)(millis/1000);
#if defined(_WIN32)
gmtime_s(buf, &dtime);
#else
gmtime_r(&dtime, buf);
#endif
}
string toString() const { string toString() const {
char buf[64]; char buf[64];
time_t_to_String(millis/1000, buf); time_t_to_String(millis/1000, buf);
return buf; return buf;
} }
}; };
// Like strlen, but only scans up to n bytes. // Like strlen, but only scans up to n bytes.
// Returns -1 if no '0' found. // Returns -1 if no '0' found.
inline int strnlen( const char *s, int n ) { inline int strnlen( const char *s, int n ) {
 End of changes. 1 change blocks. 
0 lines changed or deleted 8 lines changed or added


 mmap.h   mmap.h 
skipping to change at line 33 skipping to change at line 33
class MAdvise { class MAdvise {
void *_p; void *_p;
unsigned _len; unsigned _len;
public: public:
enum Advice { Sequential=1 }; enum Advice { Sequential=1 };
MAdvise(void *p, unsigned len, Advice a); MAdvise(void *p, unsigned len, Advice a);
~MAdvise(); // destructor resets the range to MADV_NORMAL ~MAdvise(); // destructor resets the range to MADV_NORMAL
}; };
// lock order: lock dbMutex before this if you lock both
class LockMongoFilesShared {
friend class LockMongoFilesExclusive;
static RWLockRecursiveNongreedy mmmutex;
static unsigned era;
RWLockRecursive::Shared lk;
public:
LockMongoFilesShared() : lk(mmmutex) { }
/** era changes anytime memory maps come and go. thus you can use
this as a cheap way to verify
that things are still in the condition you expected. of course
you must be shared locked
otherwise someone could be in progress. if you have unlocked t
his is a reasonable way to
check your memory mapped pointer is still good.
*/
static unsigned getEra() { return era; }
static void assertExclusivelyLocked() { mmmutex.assertExclusivelyLo
cked(); }
};
class LockMongoFilesExclusive {
RWLockRecursive::Exclusive lk;
public:
LockMongoFilesExclusive() : lk(LockMongoFilesShared::mmmutex) {
LockMongoFilesShared::era++;
}
};
/* the administrative-ish stuff here */ /* the administrative-ish stuff here */
class MongoFile : boost::noncopyable { class MongoFile : boost::noncopyable {
public: public:
/** Flushable has to fail nicely if the underlying object gets kill ed */ /** Flushable has to fail nicely if the underlying object gets kill ed */
class Flushable { class Flushable {
public: public:
virtual ~Flushable() {} virtual ~Flushable() {}
virtual void flush() = 0; virtual void flush() = 0;
}; };
skipping to change at line 76 skipping to change at line 103
static void closeAllFiles( stringstream &message ); static void closeAllFiles( stringstream &message );
#if defined(_DEBUG) #if defined(_DEBUG)
static void markAllWritable(); static void markAllWritable();
static void unmarkAllWritable(); static void unmarkAllWritable();
#else #else
static void markAllWritable() { } static void markAllWritable() { }
static void unmarkAllWritable() { } static void unmarkAllWritable() { }
#endif #endif
static bool exists(boost::filesystem::path p) { return boost::files
ystem::exists(p); }
virtual bool isMongoMMF() { return false; } virtual bool isMongoMMF() { return false; }
string filename() const { return _filename; } string filename() const { return _filename; }
void setFilename(string fn); void setFilename(string fn);
private: private:
string _filename; string _filename;
static int _flushAll( bool sync ); // returns n flushed static int _flushAll( bool sync ); // returns n flushed
protected: protected:
virtual void close() = 0; virtual void close() = 0;
skipping to change at line 113 skipping to change at line 138
virtual unsigned long long length() const = 0; virtual unsigned long long length() const = 0;
// only supporting on posix mmap // only supporting on posix mmap
virtual void _lock() {} virtual void _lock() {}
virtual void _unlock() {} virtual void _unlock() {}
static set<MongoFile*> mmfiles; static set<MongoFile*> mmfiles;
public: public:
static map<string,MongoFile*> pathToFile; static map<string,MongoFile*> pathToFile;
// lock order: lock dbMutex before this if you lock both
static RWLockRecursive mmmutex;
}; };
/** look up a MMF by filename. scoped mutex locking convention. /** look up a MMF by filename. scoped mutex locking convention.
example: example:
MMFFinderByName finder; MMFFinderByName finder;
MongoMMF *a = finder.find("file_name_a"); MongoMMF *a = finder.find("file_name_a");
MongoMMF *b = finder.find("file_name_b"); MongoMMF *b = finder.find("file_name_b");
*/ */
class MongoFileFinder : boost::noncopyable { class MongoFileFinder : boost::noncopyable {
public: public:
MongoFileFinder() : _lk(MongoFile::mmmutex) { } MongoFileFinder() { }
/** @return The MongoFile object associated with the specified file name. If no file is open /** @return The MongoFile object associated with the specified file name. If no file is open
with the specified name, returns null. with the specified name, returns null.
*/ */
MongoFile* findByPath(string path) { MongoFile* findByPath(string path) {
map<string,MongoFile*>::iterator i = MongoFile::pathToFile.find (path); map<string,MongoFile*>::iterator i = MongoFile::pathToFile.find (path);
return i == MongoFile::pathToFile.end() ? NULL : i->second; return i == MongoFile::pathToFile.end() ? NULL : i->second;
} }
private: private:
RWLockRecursive::Shared _lk; LockMongoFilesShared _lk;
}; };
struct MongoFileAllowWrites { struct MongoFileAllowWrites {
MongoFileAllowWrites() { MongoFileAllowWrites() {
MongoFile::markAllWritable(); MongoFile::markAllWritable();
} }
~MongoFileAllowWrites() { ~MongoFileAllowWrites() {
MongoFile::unmarkAllWritable(); MongoFile::unmarkAllWritable();
} }
}; };
skipping to change at line 161 skipping to change at line 183
virtual void* viewForFlushing() { virtual void* viewForFlushing() {
if( views.size() == 0 ) if( views.size() == 0 )
return 0; return 0;
assert( views.size() == 1 ); assert( views.size() == 1 );
return views[0]; return views[0];
} }
public: public:
MemoryMappedFile(); MemoryMappedFile();
virtual ~MemoryMappedFile() { virtual ~MemoryMappedFile() {
RWLockRecursive::Exclusive lk(mmmutex); LockMongoFilesExclusive lk;
close(); close();
} }
virtual void close(); virtual void close();
// Throws exception if file doesn't exist. (dm may2010: not sure if this is always true?) // Throws exception if file doesn't exist. (dm may2010: not sure if this is always true?)
void* map(const char *filename); void* map(const char *filename);
/** @param options see MongoFile::Options */ /** @param options see MongoFile::Options
*/
void* mapWithOptions(const char *filename, int options); void* mapWithOptions(const char *filename, int options);
/* Creates with length if DNE, otherwise uses existing file length, /* Creates with length if DNE, otherwise uses existing file length,
passed length. passed length.
@param options MongoFile::Options bits @param options MongoFile::Options bits
*/ */
void* map(const char *filename, unsigned long long &length, int opt ions = 0 ); void* map(const char *filename, unsigned long long &length, int opt ions = 0 );
/* Create. Must not exist. /* Create. Must not exist.
@param zero fill file with zeros when true @param zero fill file with zeros when true
skipping to change at line 236 skipping to change at line 259
/** close the current private view and open a new replacement */ /** close the current private view and open a new replacement */
void* remapPrivateView(void *oldPrivateAddr); void* remapPrivateView(void *oldPrivateAddr);
}; };
typedef MemoryMappedFile MMF; typedef MemoryMappedFile MMF;
/** p is called from within a mutex that MongoFile uses. so be careful not to deadlock. */ /** p is called from within a mutex that MongoFile uses. so be careful not to deadlock. */
template < class F > template < class F >
inline void MongoFile::forEach( F p ) { inline void MongoFile::forEach( F p ) {
RWLockRecursive::Shared lklk(mmmutex); LockMongoFilesShared lklk;
for ( set<MongoFile*>::iterator i = mmfiles.begin(); i != mmfiles.e nd(); i++ ) for ( set<MongoFile*>::iterator i = mmfiles.begin(); i != mmfiles.e nd(); i++ )
p(*i); p(*i);
} }
#if defined(_WIN32) #if defined(_WIN32)
class ourbitset { class ourbitset {
volatile unsigned bits[MemoryMappedFile::NChunks]; // volatile as w e are doing double check locking volatile unsigned bits[MemoryMappedFile::NChunks]; // volatile as w e are doing double check locking
public: public:
ourbitset() { ourbitset() {
memset((void*) bits, 0, sizeof(bits)); memset((void*) bits, 0, sizeof(bits));
skipping to change at line 277 skipping to change at line 300
inline void MemoryMappedFile::makeWritable(void *_p, unsigned len) { inline void MemoryMappedFile::makeWritable(void *_p, unsigned len) {
size_t p = (size_t) _p; size_t p = (size_t) _p;
unsigned a = p/ChunkSize; unsigned a = p/ChunkSize;
unsigned b = (p+len)/ChunkSize; unsigned b = (p+len)/ChunkSize;
for( unsigned i = a; i <= b; i++ ) { for( unsigned i = a; i <= b; i++ ) {
if( !writable.get(i) ) { if( !writable.get(i) ) {
makeChunkWritable(i); makeChunkWritable(i);
} }
} }
} }
extern void* getNextMemoryMappedFileLocation( unsigned long long mmfSiz e );
#endif #endif
} // namespace mongo } // namespace mongo
 End of changes. 9 change blocks. 
12 lines changed or deleted 38 lines changed or added


 module.h   module.h 
skipping to change at line 45 skipping to change at line 45
Module( const string& name ); Module( const string& name );
virtual ~Module(); virtual ~Module();
boost::program_options::options_description_easy_init add_options() { boost::program_options::options_description_easy_init add_options() {
return _options.add_options(); return _options.add_options();
} }
/** /**
* read config from command line * read config from command line
*/ */
virtual void config( program_options::variables_map& params ) = 0; virtual void config( boost::program_options::variables_map& params ) = 0;
/** /**
* called after configuration when the server is ready start * called after configuration when the server is ready start
*/ */
virtual void init() = 0; virtual void init() = 0;
/** /**
* called when the database is about to shutdown * called when the database is about to shutdown
*/ */
virtual void shutdown() = 0; virtual void shutdown() = 0;
const string& getName() { return _name; } const string& getName() { return _name; }
// --- static things // --- static things
static void addOptions( program_options::options_description& optio static void addOptions( boost::program_options::options_description
ns ); & options );
static void configAll( program_options::variables_map& params ); static void configAll( boost::program_options::variables_map& param
s );
static void initAll(); static void initAll();
private: private:
static std::list<Module*> * _all; static std::list<Module*> * _all;
string _name; string _name;
program_options::options_description _options; boost::program_options::options_description _options;
}; };
} }
 End of changes. 3 change blocks. 
5 lines changed or deleted 6 lines changed or added


 mongommf.h   mongommf.h 
skipping to change at line 39 skipping to change at line 39
class MongoMMF : private MemoryMappedFile { class MongoMMF : private MemoryMappedFile {
protected: protected:
virtual void* viewForFlushing() { return _view_write; } virtual void* viewForFlushing() { return _view_write; }
public: public:
MongoMMF(); MongoMMF();
virtual ~MongoMMF(); virtual ~MongoMMF();
virtual void close(); virtual void close();
/** @return true if opened ok. */ /** @return true if opened ok. */
bool open(string fname, bool sequentialHint); bool open(string fname, bool sequentialHint /*typically we open wit h this false*/);
/** @return file length */ /** @return file length */
unsigned long long length() const { return MemoryMappedFile::length (); } unsigned long long length() const { return MemoryMappedFile::length (); }
string filename() const { return MemoryMappedFile::filename(); } string filename() const { return MemoryMappedFile::filename(); }
void flush(bool sync) { MemoryMappedFile::flush(sync); } void flush(bool sync) { MemoryMappedFile::flush(sync); }
/* Creates with length if DNE, otherwise uses existing file length, /* Creates with length if DNE, otherwise uses existing file length,
passed length. passed length.
skipping to change at line 112 skipping to change at line 112
void setPath(string pathAndFileName); void setPath(string pathAndFileName);
bool finishOpening(); bool finishOpening();
}; };
/** for durability support we want to be able to map pointers to specif ic MongoMMF objects. /** for durability support we want to be able to map pointers to specif ic MongoMMF objects.
*/ */
class PointerToMMF : boost::noncopyable { class PointerToMMF : boost::noncopyable {
public: public:
PointerToMMF(); PointerToMMF();
/** register view. \ /** register view.
threadsafe threadsafe
*/ */
void add(void *view, MongoMMF *f); void add(void *view, MongoMMF *f);
/** de-register view. /** de-register view.
threadsafe threadsafe
*/ */
void remove(void *view); void remove(void *view);
/** find associated MMF object for a given pointer. /** find associated MMF object for a given pointer.
skipping to change at line 135 skipping to change at line 135
@return the MongoMMF to which this pointer belongs. null if not found. @return the MongoMMF to which this pointer belongs. null if not found.
*/ */
MongoMMF* find(void *p, /*out*/ size_t& ofs); MongoMMF* find(void *p, /*out*/ size_t& ofs);
/** for doing many finds in a row with one lock operation */ /** for doing many finds in a row with one lock operation */
mutex& _mutex() { return _m; } mutex& _mutex() { return _m; }
MongoMMF* find_inlock(void *p, /*out*/ size_t& ofs); MongoMMF* find_inlock(void *p, /*out*/ size_t& ofs);
map<void*,MongoMMF*>::iterator finditer_inlock(void *p) { return _v iews.upper_bound(p); } map<void*,MongoMMF*>::iterator finditer_inlock(void *p) { return _v iews.upper_bound(p); }
unsigned numberOfViews_inlock() const { return _views.size(); }
private: private:
mutex _m; mutex _m;
map<void*, MongoMMF*> _views; map<void*, MongoMMF*> _views;
}; };
// allows a pointer into any private view of a MongoMMF to be resolved to the MongoMMF object // allows a pointer into any private view of a MongoMMF to be resolved to the MongoMMF object
extern PointerToMMF privateViews; extern PointerToMMF privateViews;
} }
 End of changes. 3 change blocks. 
2 lines changed or deleted 4 lines changed or added


 mongomutex.h   mongomutex.h 
skipping to change at line 19 skipping to change at line 19
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* 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 Lice nse * You should have received a copy of the GNU Affero General Public Lice nse
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* Mutex heirarchy (1 = "leaf")
name level
Logstream::mutex 1
ClientCursor::ccmutex 2
dblock 3
End func name with _inlock to indicate "caller must lock before callin
g".
*/
#pragma once #pragma once
// note: include concurrency.h, not this. #include "../util/concurrency/rwlock.h"
#include "../util/mmap.h"
#include "../util/time_support.h"
#include "d_globals.h"
namespace mongo { namespace mongo {
/** the 'big lock' we use for most operations. a read/write lock. class Client;
there is one of these, dbMutex. Client* curopWaitingForLock( int type );
void curopGotLock(Client*);
/* mongomutex time stats */
class MutexInfo {
unsigned long long enter, timeLocked; // microseconds
int locked;
unsigned long long start; // last as we touch this least often
public:
MutexInfo() : timeLocked(0) , locked(0) {
start = curTimeMicros64();
}
void entered() {
if ( locked == 0 )
enter = curTimeMicros64();
locked++;
assert( locked >= 1 );
}
void leaving() {
locked--;
assert( locked >= 0 );
if ( locked == 0 )
timeLocked += curTimeMicros64() - enter;
}
int isLocked() const { return locked; }
void getTimingInfo(unsigned long long &s, unsigned long long &tl) c
onst {
s = start;
tl = timeLocked;
}
unsigned long long getTimeLocked() const { return timeLocked; }
};
/** the 'big lock'. a read/write lock.
there is one of these, d.dbMutex.
generally if you need to declare a mutex use the right primitive cl ass, not this. generally if you need to declare a mutex use the right primitive cl ass, not this.
use readlock and writelock classes for scoped locks on this rather than direct use readlock and writelock classes for scoped locks on this rather than direct
manipulation. manipulation.
*/ */
class MongoMutex { class MongoMutex {
public: public:
MongoMutex(const char * name); MongoMutex(const char * name);
/** @return /** @return
* > 0 write lock * > 0 write lock
* = 0 no lock * = 0 no lock
* < 0 read lock * < 0 read lock
*/ */
int getState() const { return _state.get(); } int getState() const { return _state.get(); }
bool atLeastReadLocked() const { return _state.get() != 0; } bool atLeastReadLocked() const { return _state.get() != 0; }
void assertAtLeastReadLocked() const { assert(atLeastReadLocked()); } void assertAtLeastReadLocked() const { assert(atLeastReadLocked()); }
bool isWriteLocked() const { return getState() > 0; } bool isWriteLocked/*by our thread*/() const { return getState() > 0 ; }
void assertWriteLocked() const { void assertWriteLocked() const {
assert( getState() > 0 ); assert( getState() > 0 );
DEV assert( !_releasedEarly.get() ); DEV assert( !_releasedEarly.get() );
} }
// write lock. use the writelock scoped lock class, not this direc tly. // write lock. use the writelock scoped lock class, not this direc tly.
void lock() { void lock() {
if ( _writeLockedAlready() ) if ( _writeLockedAlready() )
return; return;
_state.set(1); _state.set(1);
Client *c = curopWaitingForLock( 1 ); // stats curopWaitingForLock( 1 ); // stats
_m.lock(); _m.lock();
curopGotLock(c);
_minfo.entered();
MongoFile::markAllWritable(); // for _DEBUG validation -- a no op for release build MongoFile::markAllWritable(); // for _DEBUG validation -- a no op for release build
_acquiredWriteLock(); _acquiredWriteLock();
} }
// try write lock // try write lock
bool lock_try( int millis ) { bool lock_try( int millis ) {
if ( _writeLockedAlready() ) if ( _writeLockedAlready() ) // adjusts _state
return true; return true;
Client *c = curopWaitingForLock( 1 ); curopWaitingForLock( 1 );
bool got = _m.lock_try( millis ); bool got = _m.lock_try( millis );
if ( got ) { if ( got ) {
curopGotLock(c);
_minfo.entered();
_state.set(1); _state.set(1);
MongoFile::markAllWritable(); // for _DEBUG validation -- a no op for release build MongoFile::markAllWritable(); // for _DEBUG validation -- a no op for release build
_acquiredWriteLock(); _acquiredWriteLock();
} }
return got; return got;
} }
// un write lock // un write lock
void unlock() { void unlock() {
skipping to change at line 106 skipping to change at line 144
if( s != 1 ) { if( s != 1 ) {
if( _releasedEarly.get() ) { if( _releasedEarly.get() ) {
_releasedEarly.set(false); _releasedEarly.set(false);
return; return;
} }
massert( 12599, "internal error: attempt to unlock when was n't in a write lock", false); massert( 12599, "internal error: attempt to unlock when was n't in a write lock", false);
} }
_releasingWriteLock(); _releasingWriteLock();
MongoFile::unmarkAllWritable(); // _DEBUG validation MongoFile::unmarkAllWritable(); // _DEBUG validation
_state.set(0); _state.set(0);
_minfo.leaving();
_m.unlock(); _m.unlock();
} }
/* unlock (write lock), and when unlock() is called later, /* unlock (write lock), and when unlock() is called later,
be smart then and don't unlock it again. be smart then and don't unlock it again.
*/ */
void releaseEarly() { void releaseEarly() {
assert( getState() == 1 ); // must not be recursive assert( getState() == 1 ); // must not be recursive
assert( !_releasedEarly.get() ); assert( !_releasedEarly.get() );
_releasedEarly.set(true); _releasedEarly.set(true);
skipping to change at line 163 skipping to change at line 200
*/ */
bool got = _m.lock_shared_try( millis ); bool got = _m.lock_shared_try( millis );
if ( got ) if ( got )
_state.set(-1); _state.set(-1);
return got; return got;
} }
void unlock_shared() { void unlock_shared() {
int s = _state.get(); int s = _state.get();
if( s > 0 ) { if( s > 0 ) {
assert( s > 1 ); /* we must have done a lock write first to have s > 1 */ wassert( s > 1 ); /* we must have done a lock write first t o have s > 1 */
_state.set(s-1); _state.set(s-1);
return; return;
} }
if( s < -1 ) { if( s < -1 ) {
_state.set(s+1); _state.set(s+1);
return; return;
} }
assert( s == -1 ); wassert( s == -1 );
_state.set(0); _state.set(0);
_m.unlock_shared(); _m.unlock_shared();
} }
MutexInfo& info() { return _minfo; } MutexInfo& info() { return _minfo; }
private: private:
void lockedExclusively();
void unlockingExclusively();
void _acquiredWriteLock(); void _acquiredWriteLock();
void _releasingWriteLock(); void _releasingWriteLock();
/* @return true if was already write locked. increments recursive lock count. */ /* @return true if was already write locked. increments recursive lock count. */
bool _writeLockedAlready(); bool _writeLockedAlready();
RWLock _m; RWLock _m;
/* > 0 write lock with recurse count /* > 0 write lock with recurse count
< 0 read lock < 0 read lock
skipping to change at line 210 skipping to change at line 249
we use a separate TLS value for releasedEarly - that is ok as we use a separate TLS value for releasedEarly - that is ok as
our normal/common code path, we never even touch it */ our normal/common code path, we never even touch it */
ThreadLocalValue<bool> _releasedEarly; ThreadLocalValue<bool> _releasedEarly;
/* this is for fsyncAndLock command. otherwise write lock's greedi ness will /* this is for fsyncAndLock command. otherwise write lock's greedi ness will
make us block on any attempted write lock the the fsync's lock. make us block on any attempted write lock the the fsync's lock.
*/ */
//volatile bool _blockWrites; //volatile bool _blockWrites;
}; };
extern MongoMutex &dbMutex;
namespace dur { namespace dur {
void REMAPPRIVATEVIEW(); void REMAPPRIVATEVIEW();
void releasingWriteLock(); // because it's hard to include dur.h he re void releasingWriteLock(); // because it's hard to include dur.h he re
} }
inline void MongoMutex::_releasingWriteLock() { inline void MongoMutex::_releasingWriteLock() {
dur::releasingWriteLock(); dur::releasingWriteLock();
unlockingExclusively();
} }
inline void MongoMutex::_acquiredWriteLock() { inline void MongoMutex::_acquiredWriteLock() {
lockedExclusively();
if( _remapPrivateViewRequested ) { if( _remapPrivateViewRequested ) {
dur::REMAPPRIVATEVIEW(); dur::REMAPPRIVATEVIEW();
dassert( !_remapPrivateViewRequested ); dassert( !_remapPrivateViewRequested );
} }
} }
string sayClientState();
/* @return true if was already write locked. increments recursive lock count. */ /* @return true if was already write locked. increments recursive lock count. */
inline bool MongoMutex::_writeLockedAlready() { inline bool MongoMutex::_writeLockedAlready() {
int s = _state.get(); int s = _state.get();
if( s > 0 ) { if( s > 0 ) {
_state.set(s+1); _state.set(s+1);
return true; return true;
} }
massert( 10293 , string("internal error: locks are not upgradeable: ") + sayClientState() , s == 0 ); massert( 10293 , string("internal error: locks are not upgradeable: ") + sayClientState() , s == 0 );
return false; return false;
} }
struct writelock {
writelock() { d.dbMutex.lock(); }
writelock(const string& ns) { d.dbMutex.lock(); }
~writelock() {
DESTRUCTOR_GUARD(
d.dbMutex.unlock();
);
}
};
struct readlock {
readlock(const string& ns) {
d.dbMutex.lock_shared();
}
readlock() { d.dbMutex.lock_shared(); }
~readlock() {
DESTRUCTOR_GUARD(
d.dbMutex.unlock_shared();
);
}
};
struct readlocktry {
readlocktry( const string&ns , int tryms ) {
_got = d.dbMutex.lock_shared_try( tryms );
}
~readlocktry() {
if ( _got ) {
d.dbMutex.unlock_shared();
}
}
bool got() const { return _got; }
private:
bool _got;
};
struct writelocktry {
writelocktry( const string&ns , int tryms ) {
_got = d.dbMutex.lock_try( tryms );
}
~writelocktry() {
if ( _got ) {
d.dbMutex.unlock();
}
}
bool got() const { return _got; }
private:
bool _got;
};
struct readlocktryassert : public readlocktry {
readlocktryassert(const string& ns, int tryms) :
readlocktry(ns,tryms) {
uassert(13142, "timeout getting readlock", got());
}
};
/** assure we have at least a read lock - they key with this being
if you have a write lock, that's ok too.
*/
struct atleastreadlock {
atleastreadlock( const string& ns = "" ) {
_prev = d.dbMutex.getState();
if ( _prev == 0 )
d.dbMutex.lock_shared();
}
~atleastreadlock() {
if ( _prev == 0 )
d.dbMutex.unlock_shared();
}
private:
int _prev;
};
/* parameterized choice of read or write locking
use readlock and writelock instead of this when statically known whi
ch you want
*/
class mongolock {
bool _writelock;
public:
mongolock(bool write) : _writelock(write) {
if( _writelock ) {
d.dbMutex.lock();
}
else
d.dbMutex.lock_shared();
}
~mongolock() {
DESTRUCTOR_GUARD(
if( _writelock ) {
d.dbMutex.unlock();
}
else {
d.dbMutex.unlock_shared();
}
);
}
/* this unlocks, does NOT upgrade. that works for our current usage
*/
//void releaseAndWriteLock();
};
/* deprecated - use writelock and readlock instead */
struct dblock : public writelock {
dblock() : writelock("") { }
};
// eliminate this - we should just type "d.dbMutex.assertWriteLocked();
" instead
inline void assertInWriteLock() { d.dbMutex.assertWriteLocked(); }
} }
 End of changes. 19 change blocks. 
19 lines changed or deleted 173 lines changed or added


 mr.h   mr.h 
skipping to change at line 158 skipping to change at line 158
class Config { class Config {
public: public:
Config( const string& _dbname , const BSONObj& cmdObj ); Config( const string& _dbname , const BSONObj& cmdObj );
string dbname; string dbname;
string ns; string ns;
// options // options
bool verbose; bool verbose;
bool jsMode; bool jsMode;
int splitInfo;
// query options // query options
BSONObj filter; BSONObj filter;
BSONObj sort; BSONObj sort;
long long limit; long long limit;
// functions // functions
scoped_ptr<Mapper> mapper; scoped_ptr<Mapper> mapper;
skipping to change at line 196 skipping to change at line 197
float reduceTriggerRatio; float reduceTriggerRatio;
// maximum size of map before it gets dumped to disk // maximum size of map before it gets dumped to disk
long maxInMemSize; long maxInMemSize;
enum { REPLACE , // atomically replace the collection enum { REPLACE , // atomically replace the collection
MERGE , // merge keys, override dups MERGE , // merge keys, override dups
REDUCE , // merge keys, reduce dups REDUCE , // merge keys, reduce dups
INMEMORY // only store in memory, limited in size INMEMORY // only store in memory, limited in size
} outType; } outType;
// if true, no lock during output operation
bool outNonAtomic;
// true when called from mongos to do phase-1 of M/R
bool shardedFirstPass;
static AtomicUInt JOB_NUMBER; static AtomicUInt JOB_NUMBER;
}; // end MRsetup }; // end MRsetup
/** /**
* stores information about intermediate map reduce state * stores information about intermediate map reduce state
* controls flow of data from map->reduce->finalize->output * controls flow of data from map->reduce->finalize->output
*/ */
class State { class State {
public: public:
State( const Config& c ); State( const Config& c );
skipping to change at line 253 skipping to change at line 260
void finalReduce( BSONList& values ); void finalReduce( BSONList& values );
void finalReduce( CurOp * op , ProgressMeterHolder& pm ); void finalReduce( CurOp * op , ProgressMeterHolder& pm );
// ------- cleanup/data positioning ---------- // ------- cleanup/data positioning ----------
/** /**
@return number objects in collection @return number objects in collection
*/ */
long long postProcessCollection(); long long postProcessCollection( CurOp* op , ProgressMeterHolde
r& pm );
long long postProcessCollectionNonAtomic( CurOp* op , ProgressM
eterHolder& pm );
/** /**
* if INMEMORY will append * if INMEMORY will append
* may also append stats or anything else it likes * may also append stats or anything else it likes
*/ */
void appendResults( BSONObjBuilder& b ); void appendResults( BSONObjBuilder& b );
// -------- util ------------ // -------- util ------------
/** /**
 End of changes. 3 change blocks. 
1 lines changed or deleted 11 lines changed or added


 mr_shard.h   mr_shard.h 
skipping to change at line 165 skipping to change at line 165
float reduceTriggerRatio; float reduceTriggerRatio;
// maximum size of map before it gets dumped to disk // maximum size of map before it gets dumped to disk
long maxInMemSize; long maxInMemSize;
enum { REPLACE , // atomically replace the collection enum { REPLACE , // atomically replace the collection
MERGE , // merge keys, override dups MERGE , // merge keys, override dups
REDUCE , // merge keys, reduce dups REDUCE , // merge keys, reduce dups
INMEMORY // only store in memory, limited in size INMEMORY // only store in memory, limited in size
} outType; } outType;
// if true, no lock during output operation
bool outNonAtomic;
static AtomicUInt JOB_NUMBER; static AtomicUInt JOB_NUMBER;
}; // end MRsetup }; // end MRsetup
/** /**
* stores information about intermediate map reduce state * stores information about intermediate map reduce state
* controls flow of data from map->reduce->finalize->output * controls flow of data from map->reduce->finalize->output
*/ */
class State { class State {
public: public:
State( const Config& c ); State( const Config& c );
 End of changes. 1 change blocks. 
0 lines changed or deleted 3 lines changed or added


 msg.h   msg.h 
skipping to change at line 36 skipping to change at line 36
namespace task { namespace task {
typedef boost::function<void()> lam; typedef boost::function<void()> lam;
/** typical usage is: task::fork( new Server("threadname") ); */ /** typical usage is: task::fork( new Server("threadname") ); */
class Server : public Task { class Server : public Task {
public: public:
/** send a message to the port */ /** send a message to the port */
void send(lam); void send(lam);
Server(string name) : _name(name), rq(false) { } Server(string name) : m("server"), _name(name), rq(false) { }
virtual ~Server() { } virtual ~Server() { }
/** send message but block until function completes */ /** send message but block until function completes */
void call(const lam&); void call(const lam&);
void requeue() { rq = true; } void requeue() { rq = true; }
protected: protected:
/* REMINDER : for use in mongod, you will want to have this cal l Client::initThread(). */ /* REMINDER : for use in mongod, you will want to have this cal l Client::initThread(). */
virtual void starting() { } virtual void starting() { }
private: private:
virtual bool initClient() { return true; } virtual bool initClient() { return true; }
virtual string name() const { return _name; } virtual string name() const { return _name; }
void doWork(); void doWork();
deque<lam> d; deque<lam> d;
boost::mutex m; mongo::mutex m;
boost::condition c; boost::condition c;
string _name; string _name;
bool rq; bool rq;
}; };
} }
} }
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 multicmd.h   multicmd.h 
skipping to change at line 28 skipping to change at line 28
#pragma once #pragma once
#include "../../util/background.h" #include "../../util/background.h"
#include "connections.h" #include "connections.h"
namespace mongo { namespace mongo {
struct Target { struct Target {
Target(string hostport) : toHost(hostport), ok(false) { } Target(string hostport) : toHost(hostport), ok(false) { }
Target() : ok(false) { } //Target() : ok(false) { }
string toHost; const string toHost;
bool ok; bool ok;
BSONObj result; BSONObj result;
}; };
/* -- implementation ------------- */ /** send a command to several servers in parallel. waits for all to co
mplete before
returning.
in: Target::toHost
out: Target::result and Target::ok
*/
void multiCommand(BSONObj cmd, list<Target>& L);
class _MultiCommandJob : public BackgroundJob { class _MultiCommandJob : public BackgroundJob {
public: public:
BSONObj& cmd; BSONObj& cmd;
Target& d; Target& d;
_MultiCommandJob(BSONObj& _cmd, Target& _d) : cmd(_cmd), d(_d) { } _MultiCommandJob(BSONObj& _cmd, Target& _d) : cmd(_cmd), d(_d) { }
private: private:
string name() const { return "MultiCommandJob"; } string name() const { return "MultiCommandJob"; }
void run() { void run() {
 End of changes. 2 change blocks. 
3 lines changed or deleted 10 lines changed or added


 mutex.h   mutex.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 <map>
#include <set>
#include "../heapcheck.h" #include "../heapcheck.h"
#include "threadlocal.h"
#if defined(_DEBUG)
#include "mutexdebugger.h"
#endif
namespace mongo { namespace mongo {
void printStackTrace( ostream &o );
class mutex;
inline boost::xtime incxtimemillis( long long s ) { inline boost::xtime incxtimemillis( long long s ) {
boost::xtime xt; boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC); boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += (int)( s / 1000 ); xt.sec += (int)( s / 1000 );
xt.nsec += (int)(( s % 1000 ) * 1000000); xt.nsec += (int)(( s % 1000 ) * 1000000);
if ( xt.nsec >= 1000000000 ) { if ( xt.nsec >= 1000000000 ) {
xt.nsec -= 1000000000; xt.nsec -= 1000000000;
xt.sec++; xt.sec++;
} }
return xt; return xt;
} }
/** only used on _DEBUG builds.
MutexDebugger checks that we always acquire locks for multiple mute
xes in a consistant (acyclic) order.
If we were inconsistent we could deadlock.
*/
class MutexDebugger {
typedef const char * mid; // mid = mutex ID
typedef map<mid,int> Preceeding;
map< mid, int > maxNest;
boost::thread_specific_ptr< Preceeding > us;
map< mid, set<mid> > followers;
boost::mutex &x;
unsigned magic;
void aBreakPoint() { } // for debugging
public:
// set these to create an assert that
// b must never be locked before a
// so
// a.lock(); b.lock(); is fine
// b.lock(); alone is fine too
// only checked on _DEBUG builds.
string a,b;
/** outputs some diagnostic info on mutexes (on _DEBUG builds) */
void programEnding();
MutexDebugger();
void entering(mid m) {
if( this == 0 ) return;
assert( magic == 0x12345678 );
Preceeding *_preceeding = us.get();
if( _preceeding == 0 )
us.reset( _preceeding = new Preceeding() );
Preceeding &preceeding = *_preceeding;
if( a == m ) {
aBreakPoint();
if( preceeding[b.c_str()] ) {
cout << "****** MutexDebugger error! warning " << b <<
" was locked before " << a << endl;
assert(false);
}
}
preceeding[m]++;
if( preceeding[m] > 1 ) {
// recursive re-locking.
if( preceeding[m] > maxNest[m] )
maxNest[m] = preceeding[m];
return;
}
bool failed = false;
string err;
{
boost::mutex::scoped_lock lk(x);
followers[m];
for( Preceeding::iterator i = preceeding.begin(); i != prec
eeding.end(); i++ ) {
if( m != i->first && i->second > 0 ) {
followers[i->first].insert(m);
if( followers[m].count(i->first) != 0 ) {
failed = true;
stringstream ss;
mid bad = i->first;
ss << "mutex problem" <<
"\n when locking " << m <<
"\n " << bad << " was already locked and sh
ould not be."
"\n set a and b above to debug.\n";
stringstream q;
for( Preceeding::iterator i = preceeding.begin(
); i != preceeding.end(); i++ ) {
if( i->first != m && i->first != bad && i->
second > 0 )
q << " " << i->first << '\n';
}
string also = q.str();
if( !also.empty() )
ss << "also locked before " << m << " in th
is thread (no particular order):\n" << also;
err = ss.str();
break;
}
}
}
}
if( failed ) {
cout << err << endl;
assert( 0 );
}
}
void leaving(mid m) {
if( this == 0 ) return; // still in startup pre-main()
Preceeding& preceeding = *us.get();
preceeding[m]--;
if( preceeding[m] < 0 ) {
cout << "ERROR: lock count for " << m << " is " << preceedi
ng[m] << endl;
assert( preceeding[m] >= 0 );
}
}
};
extern MutexDebugger &mutexDebugger;
// If you create a local static instance of this class, that instance w ill be destroyed // If you create a local static instance of this class, that instance w ill be destroyed
// before all global static objects are destroyed, so _destroyingStatic s will be set // before all global static objects are destroyed, so _destroyingStatic s will be set
// to true before the global static variables are destroyed. // to true before the global static variables are destroyed.
class StaticObserver : boost::noncopyable { class StaticObserver : boost::noncopyable {
public: public:
static bool _destroyingStatics; static bool _destroyingStatics;
~StaticObserver() { _destroyingStatics = true; } ~StaticObserver() { _destroyingStatics = true; }
}; };
/** On pthread systems, it is an error to destroy a mutex while held (b oost mutex /** On pthread systems, it is an error to destroy a mutex while held (b oost mutex
* may use pthread). Static global mutexes may be held upon shutdow n in our * may use pthread). Static global mutexes may be held upon shutdow n in our
* implementation, and this way we avoid destroying them. * implementation, and this way we avoid destroying them.
* NOT recursive. * NOT recursive.
*/ */
class mutex : boost::noncopyable { class mutex : boost::noncopyable {
public: public:
#if defined(_DEBUG)
const char * const _name; const char * const _name;
mutex(const char *name) : _name(name) mutex(const char *name) : _name(name)
#else
mutex(const char *)
#endif
{ {
_m = new boost::timed_mutex(); _m = new boost::timed_mutex();
IGNORE_OBJECT( _m ); // Turn-off heap checking on _m IGNORE_OBJECT( _m ); // Turn-off heap checking on _m
} }
~mutex() { ~mutex() {
if( !StaticObserver::_destroyingStatics ) { if( !StaticObserver::_destroyingStatics ) {
UNIGNORE_OBJECT( _m ); UNIGNORE_OBJECT( _m );
delete _m; delete _m;
} }
} }
skipping to change at line 194 skipping to change at line 89
private: private:
boost::timed_mutex::scoped_timed_lock _l; boost::timed_mutex::scoped_timed_lock _l;
public: public:
const bool ok; const bool ok;
}; };
class scoped_lock : boost::noncopyable { class scoped_lock : boost::noncopyable {
public: public:
#if defined(_DEBUG) #if defined(_DEBUG)
struct PostStaticCheck { struct PostStaticCheck {
PostStaticCheck() { PostStaticCheck();
if ( StaticObserver::_destroyingStatics ) { } _check;
cout << "trying to lock a mongo::mutex during stati
c shutdown" << endl;
printStackTrace( cout );
}
}
};
PostStaticCheck _check;
mongo::mutex * const _mut; mongo::mutex * const _mut;
#endif #endif
scoped_lock( mongo::mutex &m ) : scoped_lock( mongo::mutex &m ) :
#if defined(_DEBUG) #if defined(_DEBUG)
_mut(&m), _mut(&m),
#endif #endif
_l( m.boost() ) { _l( m.boost() ) {
#if defined(_DEBUG) #if defined(_DEBUG)
mutexDebugger.entering(_mut->_name); mutexDebugger.entering(_mut->_name);
#endif #endif
skipping to change at line 243 skipping to change at line 131
implemented using OS-specific facilities in all environments (if desired). implemented using OS-specific facilities in all environments (if desired).
On Windows, the implementation below is faster than boost mutex. On Windows, the implementation below is faster than boost mutex.
*/ */
#if defined(_WIN32) #if defined(_WIN32)
class SimpleMutex : boost::noncopyable { class SimpleMutex : boost::noncopyable {
CRITICAL_SECTION _cs; CRITICAL_SECTION _cs;
public: public:
SimpleMutex(const char *name) { InitializeCriticalSection(&_cs); } SimpleMutex(const char *name) { InitializeCriticalSection(&_cs); }
~SimpleMutex() { DeleteCriticalSection(&_cs); } ~SimpleMutex() { DeleteCriticalSection(&_cs); }
void lock() { EnterCriticalSection(&_cs); } #if defined(_DEBUG)
void unlock() { LeaveCriticalSection(&_cs); } ThreadLocalValue<int> _nlocksByMe;
void lock() {
assert( _nlocksByMe.get() == 0 ); // indicates you rae trying t
o lock recursively
_nlocksByMe.set(1);
EnterCriticalSection(&_cs);
}
void dassertLocked() const {
assert( _nlocksByMe.get() == 1 );
}
void unlock() {
dassertLocked();
_nlocksByMe.set(0);
LeaveCriticalSection(&_cs);
}
#else
void dassertLocked() const { }
void lock() {
EnterCriticalSection(&_cs);
}
void unlock() {
LeaveCriticalSection(&_cs);
}
#endif
class scoped_lock : boost::noncopyable { class scoped_lock : boost::noncopyable {
SimpleMutex& _m; SimpleMutex& _m;
public: public:
scoped_lock( SimpleMutex &m ) : _m(m) { _m.lock(); } scoped_lock( SimpleMutex &m ) : _m(m) { _m.lock(); }
~scoped_lock() { _m.unlock(); } ~scoped_lock() { _m.unlock(); }
# if defined(_DEBUG)
const SimpleMutex& m() const { return _m; }
# endif
}; };
}; };
#else #else
class SimpleMutex : boost::noncopyable { class SimpleMutex : boost::noncopyable {
public: public:
void dassertLocked() const { }
SimpleMutex(const char* name) { assert( pthread_mutex_init(&_lock,0 ) == 0 ); } SimpleMutex(const char* name) { assert( pthread_mutex_init(&_lock,0 ) == 0 ); }
~SimpleMutex(){ ~SimpleMutex(){
if ( ! StaticObserver::_destroyingStatics ) { if ( ! StaticObserver::_destroyingStatics ) {
assert( pthread_mutex_destroy(&_lock) == 0 ); assert( pthread_mutex_destroy(&_lock) == 0 );
} }
} }
void lock() { assert( pthread_mutex_lock(&_lock) == 0 ); } void lock() { assert( pthread_mutex_lock(&_lock) == 0 ); }
void unlock() { assert( pthread_mutex_unlock(&_lock) == 0 ); } void unlock() { assert( pthread_mutex_unlock(&_lock) == 0 ); }
public:
class scoped_lock : boost::noncopyable { class scoped_lock : boost::noncopyable {
SimpleMutex& _m; SimpleMutex& _m;
public: public:
scoped_lock( SimpleMutex &m ) : _m(m) { _m.lock(); } scoped_lock( SimpleMutex &m ) : _m(m) { _m.lock(); }
~scoped_lock() { _m.unlock(); } ~scoped_lock() { _m.unlock(); }
const SimpleMutex& m() const { return _m; }
}; };
private: private:
pthread_mutex_t _lock; pthread_mutex_t _lock;
}; };
#endif #endif
/** This can be used instead of boost recursive mutex. The advantage is
the _DEBUG checks
* and ability to assertLocked(). This has not yet been tested for spe
ed vs. the boost one.
*/
class RecursiveMutex : boost::noncopyable {
public:
RecursiveMutex(const char* name) : m(name) { }
bool isLocked() const { return n.get() > 0; }
class scoped_lock : boost::noncopyable {
RecursiveMutex& rm;
int& nLocksByMe;
public:
scoped_lock( RecursiveMutex &m ) : rm(m), nLocksByMe(rm.n.getRe
f()) {
if( nLocksByMe++ == 0 )
rm.m.lock();
}
~scoped_lock() {
assert( nLocksByMe > 0 );
if( --nLocksByMe == 0 ) {
rm.m.unlock();
}
}
};
private:
SimpleMutex m;
ThreadLocalValue<int> n;
};
} }
 End of changes. 13 change blocks. 
130 lines changed or deleted 67 lines changed or added


 mvar.h   mvar.h 
skipping to change at line 18 skipping to change at line 18
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once
namespace mongo { namespace mongo {
/* This is based on haskell's MVar synchronization primitive: /* This is based on haskell's MVar synchronization primitive:
* http://www.haskell.org/ghc/docs/latest/html/libraries/base-4.2.0.0/C ontrol-Concurrent-MVar.html * http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-C oncurrent-MVar.html
* *
* It is a thread-safe queue that can hold at most one object. * It is a thread-safe queue that can hold at most one object.
* You can also think of it as a box that can be either full or empty. * You can also think of it as a box that can be either full or empty.
*/ */
template <typename T> template <typename T>
class MVar { class MVar {
public: public:
enum State {EMPTY=0, FULL}; enum State {EMPTY=0, FULL};
 End of changes. 2 change blocks. 
1 lines changed or deleted 3 lines changed or added


 namespace.h   namespace.h 
skipping to change at line 22 skipping to change at line 22
* 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 "../pch.h" #include "../pch.h"
#include "namespacestring.h"
#include "jsobj.h" #include "jsobj.h"
#include "querypattern.h" #include "querypattern.h"
#include "diskloc.h" #include "diskloc.h"
#include "../util/hashtab.h" #include "../util/hashtab.h"
#include "mongommf.h" #include "mongommf.h"
#include "d_concurrency.h"
namespace mongo { namespace mongo {
/* in the mongo source code, "client" means "database". */ class Database;
const int MaxDatabaseNameLen = 256; // max str len for the db name, inc
luding null char
/* e.g.
NamespaceString ns("acme.orders");
cout << ns.coll; // "orders"
*/
class NamespaceString {
public:
string db;
string coll; // note collection names can have periods in them for
organizing purposes (e.g. "system.indexes")
NamespaceString( const char * ns ) { init(ns); }
NamespaceString( const string& ns ) { init(ns.c_str()); }
string ns() const { return db + '.' + coll; }
bool isSystem() const { return strncmp(coll.c_str(), "system.", 7)
== 0; }
/**
* @return true if ns is 'normal'. $ used for collections holding
index data, which do not contain BSON objects in their records.
* special case for the local.oplog.$main ns -- naming it as such w
as a mistake.
*/
static bool normal(const char* ns) {
const char *p = strchr(ns, '$');
if( p == 0 )
return true;
return strcmp( ns, "local.oplog.$main" ) == 0;
}
static bool special(const char *ns) {
return !normal(ns) || strstr(ns, ".system.");
}
private:
void init(const char *ns) {
const char *p = strchr(ns, '.');
if( p == 0 ) return;
db = string(ns, p - ns);
coll = p + 1;
}
};
#pragma pack(1) #pragma pack(1)
/* This helper class is used to make the HashMap below in NamespaceDeta ils e.g. see line: /* This helper class is used to make the HashMap below in NamespaceInde x e.g. see line:
HashTable<Namespace,NamespaceDetails> *ht; HashTable<Namespace,NamespaceDetails> *ht;
*/ */
class Namespace { class Namespace {
public: public:
explicit Namespace(const char *ns) { *this = ns; } explicit Namespace(const char *ns) { *this = ns; }
Namespace& operator=(const char *ns); Namespace& operator=(const char *ns);
bool hasDollarSign() const { return strchr( buf , '$' ) > 0; } bool hasDollarSign() const { return strchr( buf , '$' ) > 0; }
void kill() { buf[0] = 0x7f; } void kill() { buf[0] = 0x7f; }
bool operator==(const char *r) const { return strcmp(buf, r) == 0; } bool operator==(const char *r) const { return strcmp(buf, r) == 0; }
skipping to change at line 321 skipping to change at line 284
*/ */
IndexDetails& addIndex(const char *thisns, bool resetTransient=true ); IndexDetails& addIndex(const char *thisns, bool resetTransient=true );
void aboutToDeleteAnIndex() { void aboutToDeleteAnIndex() {
*getDur().writing(&flags) = flags & ~Flag_HaveIdIndex; *getDur().writing(&flags) = flags & ~Flag_HaveIdIndex;
} }
/* returns index of the first index in which the field is present. -1 if not present. */ /* returns index of the first index in which the field is present. -1 if not present. */
int fieldIsIndexed(const char *fieldName); int fieldIsIndexed(const char *fieldName);
/* called to indicate that an update fit in place.
fits also called on an insert -- idea there is that if you had s
ome mix and then went to
pure inserts it would adapt and PF would trend to 1.0. note upd
ate calls insert on a move
so there is a double count there that must be adjusted for below
.
todo: greater sophistication could be helpful and added later.
for example the absolute
size of documents might be considered -- in some cases sma
ller ones are more likely
to grow than larger ones in the same collection? (not alwa
ys)
*/
void paddingFits() { void paddingFits() {
double x = paddingFactor - 0.01; MONGO_SOMETIMES(sometimes, 4) { // do this on a sampled basis t
if ( x >= 1.0 ) { o journal less
*getDur().writing(&paddingFactor) = x; double x = paddingFactor - 0.001;
//getDur().setNoJournal(&paddingFactor, &x, sizeof(x)); if ( x >= 1.0 ) {
*getDur().writing(&paddingFactor) = x;
//getDur().setNoJournal(&paddingFactor, &x, sizeof(x));
}
} }
} }
void paddingTooSmall() { void paddingTooSmall() {
double x = paddingFactor + 0.6; MONGO_SOMETIMES(sometimes, 4) { // do this on a sampled basis t
if ( x <= 2.0 ) { o journal less
*getDur().writing(&paddingFactor) = x; /* the more indexes we have, the higher the cost of a move.
//getDur().setNoJournal(&paddingFactor, &x, sizeof(x)); so we take that into
account herein. note on a move that insert() calls padd
ingFits(), thus
here for example with no inserts and nIndexes = 1 we hav
e
.001*4-.001 or a 3:1 ratio to non moves -> 75% nonmoves.
insert heavy
can pushes this down considerably. further tweaking will
be a good idea but
this should be an adequate starting point.
*/
double N = min(nIndexes,7) + 3;
double x = paddingFactor + (0.001 * N);
if ( x <= 2.0 ) {
*getDur().writing(&paddingFactor) = x;
//getDur().setNoJournal(&paddingFactor, &x, sizeof(x));
}
} }
} }
// @return offset in indexes[] // @return offset in indexes[]
int findIndexByName(const char *name); int findIndexByName(const char *name);
// @return offset in indexes[] // @return offset in indexes[]
int findIndexByKeyPattern(const BSONObj& keyPattern); int findIndexByKeyPattern(const BSONObj& keyPattern);
void findIndexByType( const string& name , vector<int>& matches ) { void findIndexByType( const string& name , vector<int>& matches ) {
skipping to change at line 374 skipping to change at line 358
} }
/* return which "deleted bucket" for this size object */ /* return which "deleted bucket" for this size object */
static int bucket(int n) { static int bucket(int n) {
for ( int i = 0; i < Buckets; i++ ) for ( int i = 0; i < Buckets; i++ )
if ( bucketSizes[i] > n ) if ( bucketSizes[i] > n )
return i; return i;
return Buckets-1; return Buckets-1;
} }
/* predetermine location of the next alloc without actually doing i
t.
if cannot predetermine returns null (so still call alloc() then)
*/
DiskLoc allocWillBeAt(const char *ns, int lenToAlloc);
/* allocate a new record. lenToAlloc includes headers. */ /* allocate a new record. lenToAlloc includes headers. */
DiskLoc alloc(const char *ns, int lenToAlloc, DiskLoc& extentLoc); DiskLoc alloc(const char *ns, int lenToAlloc, DiskLoc& extentLoc);
/* add a given record to the deleted chains for this NS */ /* add a given record to the deleted chains for this NS */
void addDeletedRec(DeletedRecord *d, DiskLoc dloc); void addDeletedRec(DeletedRecord *d, DiskLoc dloc);
void dumpDeleted(set<DiskLoc> *extents = 0); void dumpDeleted(set<DiskLoc> *extents = 0);
// Start from firstExtent by default. // Start from firstExtent by default.
DiskLoc firstRecord( const DiskLoc &startExtent = DiskLoc() ) const ; DiskLoc firstRecord( const DiskLoc &startExtent = DiskLoc() ) const ;
// Start from lastExtent by default. // Start from lastExtent by default.
DiskLoc lastRecord( const DiskLoc &startExtent = DiskLoc() ) const; DiskLoc lastRecord( const DiskLoc &startExtent = DiskLoc() ) const;
long long storageSize( int * numExtents = 0 , BSONArrayBuilder * ex tentInfo = 0 ) const; long long storageSize( int * numExtents = 0 , BSONArrayBuilder * ex tentInfo = 0 ) const;
int averageObjectSize() { int averageObjectSize() {
skipping to change at line 400 skipping to change at line 390
NamespaceDetails *writingWithoutExtra() { NamespaceDetails *writingWithoutExtra() {
return ( NamespaceDetails* ) getDur().writingPtr( this, sizeof( NamespaceDetails ) ); return ( NamespaceDetails* ) getDur().writingPtr( this, sizeof( NamespaceDetails ) );
} }
/** Make all linked Extra objects writeable as well */ /** Make all linked Extra objects writeable as well */
NamespaceDetails *writingWithExtra(); NamespaceDetails *writingWithExtra();
private: private:
DiskLoc _alloc(const char *ns, int len); DiskLoc _alloc(const char *ns, int len);
void maybeComplain( const char *ns, int len ) const; void maybeComplain( const char *ns, int len ) const;
DiskLoc __stdAlloc(int len); DiskLoc __stdAlloc(int len, bool willBeAt);
void compact(); // combine adjacent deleted records void compact(); // combine adjacent deleted records
friend class NamespaceIndex; friend class NamespaceIndex;
struct ExtraOld { struct ExtraOld {
// note we could use this field for more chaining later, so don 't waste it: // note we could use this field for more chaining later, so don 't waste it:
unsigned long long reserved1; unsigned long long reserved1;
IndexDetails details[NIndexesExtra]; IndexDetails details[NIndexesExtra];
unsigned reserved2; unsigned reserved2;
unsigned reserved3; unsigned reserved3;
}; };
/** Update cappedLastDelRecLastExtent() after capExtent changed in cappedTruncateAfter() */ /** Update cappedLastDelRecLastExtent() after capExtent changed in cappedTruncateAfter() */
skipping to change at line 431 skipping to change at line 421
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 todo: cleanup code, need abstractions and separation
*/ */
// todo: multiple db's with the same name (repairDatbase) is not handle
d herein. that may be
// the way to go, if not used by repair, but need some sort of en
forcement / asserts.
class NamespaceDetailsTransient : boost::noncopyable { class NamespaceDetailsTransient : boost::noncopyable {
BOOST_STATIC_ASSERT( sizeof(NamespaceDetails) == 496 ); BOOST_STATIC_ASSERT( sizeof(NamespaceDetails) == 496 );
/* general -------------------------------------------------------- //Database *database;
----- */ const string _ns;
private:
string _ns;
void reset(); void reset();
static std::map< string, shared_ptr< NamespaceDetailsTransient > > static std::map< string, shared_ptr< NamespaceDetailsTransient > >
_map; _nsdMap;
public:
NamespaceDetailsTransient(const char *ns) : _ns(ns), _keysComputed( NamespaceDetailsTransient(Database*,const char *ns);
false), _qcWriteCount() { }
private:
/* _get() is not threadsafe -- see get_inlock() comments */
static NamespaceDetailsTransient& _get(const char *ns);
public: public:
/* use get_w() when doing write operations. this is safe as there i ~NamespaceDetailsTransient();
s only 1 write op and it's exclusive to everything else. void addedIndex() { assertInWriteLock(); reset(); }
for reads you must lock and then use get_inlock() instead. */ void deletedIndex() { assertInWriteLock(); reset(); }
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. /* 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. Can be useful as index namespaces share the same start as the re gular collection.
SLOW - sequential scan of all NamespaceDetailsTransient objects */ SLOW - sequential scan of all NamespaceDetailsTransient objects */
static void clearForPrefix(const char *prefix); static void clearForPrefix(const char *prefix);
static void eraseForPrefix(const char *prefix); static void eraseForPrefix(const char *prefix);
/** /**
* @return a cursor interface to the query optimizer. The implemen tation may * @return a cursor interface to the query optimizer. The implemen tation may
* utilize a single query plan or interleave results from multiple query * utilize a single query plan or interleave results from multiple query
* plans before settling on a single query plan. Note that the sch ema of * plans before settling on a single query plan. Note that the sch ema of
* currKey() documents, the matcher(), and the isMultiKey() nature of the * currKey() documents, the matcher(), and the isMultiKey() nature of the
* cursor may change over the course of iteration. * cursor may change over the course of iteration.
* *
* @param order - If no index exists that satisfies this sort order * @param query - Query used to select indexes and populate matcher
, an s; this is not copied, and must outlive the Cursor
* empty shared_ptr will be returned. *
* @param order - Required ordering spec for documents produced by
this cursor,
* empty object default indicates no order requirement. If no inde
x exists that
* satisfies the required sort order, an empty shared_ptr is return
ed. This is nit copied, and must outlive the Cursor
*
* @param requireIndex - If true, no unindexed (ie collection scan)
cursors are
* used to generate the returned cursor. If an unindexed cursor is
required, an
* assertion is raised by the cursor during iteration.
*
* @param simpleEqualityMatch - Set to true for certain simple quer
ies -
* see queryoptimizer.cpp.
* *
* The returned cursor may @throw inside of advance() or recoverFro mYield() in * The returned cursor may @throw inside of advance() or recoverFro mYield() in
* certain error cases, for example if a capped overrun occurred du ring a yield. * certain error cases, for example if a capped overrun occurred du ring a yield.
* This indicates that the cursor was unable to perform a complete scan. * This indicates that the cursor was unable to perform a complete scan.
* *
* This is a work in progress. Partial list of features not yet im plemented: * This is a work in progress. Partial list of features not yet im plemented:
* - modification of scanned documents
* - covered indexes * - covered indexes
* - in memory sorting
*/ */
static shared_ptr<Cursor> getCursor( const char *ns, const BSONObj static shared_ptr<Cursor> getCursor( const char *ns, const BSONObj
&query, const BSONObj &order = BSONObj() ); &query,
const BSONObj &order = BSONObj(
), bool requireIndex = false,
bool *simpleEqualityMatch = 0 )
;
/**
* @return a single cursor that may work well for the given query.
* It is possible no cursor is returned if the sort is not supporte
d by an index. Clients are responsible
* for checking this if they are not sure an index for a sort exist
s, and defaulting to a non-sort if
* no suitable indices exist.
*/
static shared_ptr<Cursor> bestGuessCursor( const char *ns, const BS
ONObj &query, const BSONObj &sort );
/* indexKeys() cache ---------------------------------------------- ------ */ /* indexKeys() cache ---------------------------------------------- ------ */
/* assumed to be in write lock for this */ /* assumed to be in write lock for this */
private: private:
bool _keysComputed; bool _keysComputed;
set<string> _indexKeys; set<string> _indexKeys;
void computeIndexKeys(); void computeIndexKeys();
public: 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 secondary component of a co mpound index.) field is indexed (Note it might be a secondary component of a co mpound index.)
skipping to change at line 517 skipping to change at line 520
assert( spec._finishedInit ); assert( spec._finishedInit );
} }
} }
return spec; return spec;
} }
/* query cache (for query optimizer) ------------------------------ ------- */ /* query cache (for query optimizer) ------------------------------ ------- */
private: private:
int _qcWriteCount; int _qcWriteCount;
map< QueryPattern, pair< BSONObj, long long > > _qcCache; map< QueryPattern, pair< BSONObj, long long > > _qcCache;
static NamespaceDetailsTransient& make_inlock(const char *ns);
public: public:
static SimpleMutex _qcMutex; static SimpleMutex _qcMutex;
/* you must be in the qcMutex when calling this (and using the retu
rned val): */ /* you must be in the qcMutex when calling this.
static NamespaceDetailsTransient& get_inlock(const char *ns) { A NamespaceDetailsTransient object will not go out of scope on y
return _get(ns); ou if you are
d.dbMutex.atLeastReadLocked(), so you do't have to stay locked.
Creates a NamespaceDetailsTransient before returning if one DNE.
todo: avoid creating too many on erroneous ns queries.
*/
static NamespaceDetailsTransient& get_inlock(const char *ns);
static NamespaceDetailsTransient& get(const char *ns) {
SimpleMutex::scoped_lock lk(_qcMutex);
return get_inlock(ns);
} }
void clearQueryCache() { // public for unit tests void clearQueryCache() { // public for unit tests
_qcCache.clear(); _qcCache.clear();
_qcWriteCount = 0; _qcWriteCount = 0;
} }
/* you must notify the cache if you are doing writes, as query plan optimality will change */ /* you must notify the cache if you are doing writes, as query plan optimality will change */
void notifyOfWriteOp() { void notifyOfWriteOp() {
if ( _qcCache.empty() ) if ( _qcCache.empty() )
return; return;
if ( ++_qcWriteCount >= 1000 ) if ( ++_qcWriteCount >= 100 )
clearQueryCache(); clearQueryCache();
} }
BSONObj indexForPattern( const QueryPattern &pattern ) { BSONObj indexForPattern( const QueryPattern &pattern ) {
return _qcCache[ pattern ].first; return _qcCache[ pattern ].first;
} }
long long nScannedForPattern( const QueryPattern &pattern ) { long long nScannedForPattern( const QueryPattern &pattern ) {
return _qcCache[ 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 ) {
_qcCache[ pattern ] = make_pair( indexKey, nScanned ); _qcCache[ pattern ] = make_pair( indexKey, nScanned );
} }
}; /* NamespaceDetailsTransient */ }; /* NamespaceDetailsTransient */
inline NamespaceDetailsTransient& NamespaceDetailsTransient::_get(const inline NamespaceDetailsTransient& NamespaceDetailsTransient::get_inlock
char *ns) { (const char *ns) {
shared_ptr< NamespaceDetailsTransient > &t = _map[ ns ]; std::map< string, shared_ptr< NamespaceDetailsTransient > >::iterat
if ( t.get() == 0 ) or i = _nsdMap.find(ns);
t.reset( new NamespaceDetailsTransient(ns) ); if( i != _nsdMap.end() &&
return *t; i->second.get() ) { // could be null ptr from clearForPrefix
return *i->second;
}
return make_inlock(ns);
} }
/* 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;
public: public:
NamespaceIndex(const string &dir, const string &database) : NamespaceIndex(const string &dir, const string &database) :
ht( 0 ), dir_( dir ), database_( database ) {} ht( 0 ), dir_( dir ), database_( database ) {}
/* returns true if new db will be created if we init lazily */ /* returns true if new db will be created if we init lazily */
bool exists() const; bool exists() const;
void init(); void init() {
if( !ht )
void add_ns(const char *ns, DiskLoc& loc, bool capped) { _init();
NamespaceDetails details( loc, capped );
add_ns( ns, details );
}
void add_ns( const char *ns, const NamespaceDetails &details ) {
init();
Namespace n(ns);
uassert( 10081 , "too many namespaces/collections", ht->put(n,
details));
} }
/* just for diagnostics */ void add_ns(const char *ns, DiskLoc& loc, bool capped);
/*size_t detailsOffset(NamespaceDetails *d) { void add_ns( const char *ns, const NamespaceDetails &details );
if ( !ht )
return -1;
return ((char *) d) - (char *) ht->nodes;
}*/
NamespaceDetails* details(const char *ns) { NamespaceDetails* details(const char *ns) {
if ( !ht ) if ( !ht )
return 0; return 0;
Namespace n(ns); Namespace n(ns);
NamespaceDetails *d = ht->get(n); NamespaceDetails *d = ht->get(n);
if ( d && d->capped ) if ( d && d->capped )
d->cappedCheckMigrate(); d->cappedCheckMigrate();
return d; return d;
} }
skipping to change at line 606 skipping to change at line 609
bool find(const char *ns, DiskLoc& loc) { bool find(const char *ns, DiskLoc& loc) {
NamespaceDetails *l = details(ns); NamespaceDetails *l = details(ns);
if ( l ) { if ( l ) {
loc = l->firstExtent; loc = l->firstExtent;
return true; return true;
} }
return false; return false;
} }
bool allocated() const { bool allocated() const { return ht != 0; }
return ht != 0;
}
void getNamespaces( list<string>& tofill , bool onlyCollections = t rue ) const; void getNamespaces( list<string>& tofill , bool onlyCollections = t rue ) const;
NamespaceDetails::Extra* newExtra(const char *ns, int n, NamespaceD etails *d); NamespaceDetails::Extra* newExtra(const char *ns, int n, NamespaceD etails *d);
boost::filesystem::path path() const; boost::filesystem::path path() const;
unsigned long long fileLength() const { return f.length(); } unsigned long long fileLength() const { return f.length(); }
private: private:
void _init();
void maybeMkdir() const; void maybeMkdir() const;
MongoMMF f; MongoMMF f;
HashTable<Namespace,NamespaceDetails> *ht; HashTable<Namespace,NamespaceDetails> *ht;
string dir_; string dir_;
string database_; string database_;
}; };
extern string dbpath; // --dbpath parm extern string dbpath; // --dbpath parm
extern bool directoryperdb; extern bool directoryperdb;
// Rename a namespace within current 'client' db. // Rename a namespace within current 'client' db.
// (Arguments should include db name) // (Arguments should include db name)
void renameNamespace( const char *from, const char *to ); void renameNamespace( const char *from, const char *to, bool stayTemp);
// "database.a.b.c" -> "database"
inline void nsToDatabase(const char *ns, char *database) {
const char *p = ns;
char *q = database;
while ( *p != '.' ) {
if ( *p == 0 )
break;
*q++ = *p++;
}
*q = 0;
if (q-database>=MaxDatabaseNameLen) {
log() << "nsToDatabase: ns too long. terminating, buf overrun c
ondition" << endl;
dbexit( EXIT_POSSIBLE_CORRUPTION );
}
}
inline string nsToDatabase(const char *ns) {
char buf[MaxDatabaseNameLen];
nsToDatabase(ns, buf);
return buf;
}
inline string nsToDatabase(const string& ns) {
size_t i = ns.find( '.' );
if ( i == string::npos )
return ns;
return ns.substr( 0 , i );
}
} // namespace mongo } // namespace mongo
 End of changes. 29 change blocks. 
144 lines changed or deleted 137 lines changed or added


 ntservice.h   ntservice.h 
skipping to change at line 22 skipping to change at line 22
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#if defined(_WIN32) #if defined(_WIN32)
#include <windows.h> #include <windows.h>
#include "boost/program_options.hpp"
namespace mongo { namespace mongo {
typedef bool ( *ServiceCallback )( void ); typedef bool ( *ServiceCallback )( void );
bool serviceParamsCheck( program_options::variables_map& params, const std::string dbpath, int argc, char* argv[] ); bool serviceParamsCheck( boost::program_options::variables_map& params, const std::string dbpath, int argc, char* argv[] );
class ServiceController { class ServiceController {
public: public:
ServiceController(); ServiceController();
virtual ~ServiceController() {} virtual ~ServiceController() {}
static bool installService( const std::wstring& serviceName, const std::wstring& displayName, const std::wstring& serviceDesc, const std::wstr ing& serviceUser, const std::wstring& servicePassword, const std::string db path, int argc, char* argv[] ); static bool installService( const std::wstring& serviceName, const std::wstring& displayName, const std::wstring& serviceDesc, const std::wstr ing& serviceUser, const std::wstring& servicePassword, const std::string db path, int argc, char* argv[] );
static bool removeService( const std::wstring& serviceName ); static bool removeService( const std::wstring& serviceName );
static bool startService( const std::wstring& serviceName, ServiceC allback startService ); static bool startService( const std::wstring& serviceName, ServiceC allback startService );
static bool reportStatus( DWORD reportState, DWORD waitHint = 0 ); static bool reportStatus( DWORD reportState, DWORD waitHint = 0 );
 End of changes. 2 change blocks. 
1 lines changed or deleted 2 lines changed or added


 oid.h   oid.h 
skipping to change at line 77 skipping to change at line 77
void init( string s ); void init( string s );
/** Set to the min/max OID that could be generated at given timesta mp. */ /** Set to the min/max OID that could be generated at given timesta mp. */
void init( Date_t date, bool max=false ); void init( Date_t date, bool max=false );
time_t asTimeT(); time_t asTimeT();
Date_t asDateT() { return asTimeT() * (long long)1000; } Date_t asDateT() { return asTimeT() * (long long)1000; }
bool isSet() const { return a || b; } bool isSet() const { return a || b; }
/**
* this is not consistent
* do not store on disk
*/
void hash_combine(size_t &seed) const;
/** call this after a fork to update the process id */ /** call this after a fork to update the process id */
static void justForked(); static void justForked();
static unsigned getMachineId(); // features command uses static unsigned getMachineId(); // features command uses
static void regenMachineId(); // used by unit tests static void regenMachineId(); // used by unit tests
private: private:
struct MachineAndPid { struct MachineAndPid {
unsigned char _machineNumber[3]; unsigned char _machineNumber[3];
unsigned short _pid; unsigned short _pid;
skipping to change at line 101 skipping to change at line 107
struct { struct {
// 12 bytes total // 12 bytes total
unsigned char _time[4]; unsigned char _time[4];
MachineAndPid _machineAndPid; MachineAndPid _machineAndPid;
unsigned char _inc[3]; unsigned char _inc[3];
}; };
struct { struct {
long long a; long long a;
unsigned b; unsigned b;
}; };
struct {
// TODO: get rid of this eventually
// this is a hack because of hash_combine with older
versions of boost
// on 32-bit platforms
int x;
int y;
int z;
};
unsigned char data[12]; unsigned char data[12];
}; };
static unsigned ourPid(); static unsigned ourPid();
static void foldInPid(MachineAndPid& x); static void foldInPid(MachineAndPid& x);
static MachineAndPid genMachineAndPid(); static MachineAndPid genMachineAndPid();
}; };
#pragma pack() #pragma pack()
ostream& operator<<( ostream &s, const OID &o ); ostream& operator<<( ostream &s, const OID &o );
skipping to change at line 127 skipping to change at line 141
enum JsonStringFormat { enum JsonStringFormat {
/** strict RFC format */ /** strict RFC format */
Strict, Strict,
/** 10gen format, which is close to JS format. This form is unders tandable by /** 10gen format, which is close to JS format. This form is unders tandable by
javascript running inside the Mongo server via eval() */ javascript running inside the Mongo server via eval() */
TenGen, TenGen,
/** Javascript JSON compatible */ /** Javascript JSON compatible */
JS JS
}; };
inline ostream& operator<<( ostream &s, const OID &o ) { ostream& operator<<( ostream &s, const OID &o );
s << o.str();
return s;
}
} }
 End of changes. 3 change blocks. 
4 lines changed or deleted 16 lines changed or added


 oplog.h   oplog.h 
skipping to change at line 125 skipping to change at line 125
DiskLoc prevExtentFirstLoc( const DiskLoc &rec ); DiskLoc prevExtentFirstLoc( const DiskLoc &rec );
void createClientCursor( const DiskLoc &startLoc = DiskLoc() ); void createClientCursor( const DiskLoc &startLoc = DiskLoc() );
void destroyClientCursor() { void destroyClientCursor() {
_findingStartCursor.reset( 0 ); _findingStartCursor.reset( 0 );
} }
void init(); void init();
bool firstDocMatchesOrEmpty() const; bool firstDocMatchesOrEmpty() const;
}; };
class Sync {
protected:
string hn;
public:
Sync(const string& hostname) : hn(hostname) {}
virtual ~Sync() {}
virtual BSONObj getMissingDoc(const BSONObj& o);
/**
* If applyOperation_inlock should be called again after an update
fails.
*/
virtual bool shouldRetry(const BSONObj& o);
};
void pretouchOperation(const BSONObj& op); void pretouchOperation(const BSONObj& op);
void pretouchN(vector<BSONObj>&, unsigned a, unsigned b); void pretouchN(vector<BSONObj>&, unsigned a, unsigned b);
/** /**
* take an op and apply locally * take an op and apply locally
* used for applying from an oplog * used for applying from an oplog
* @param fromRepl really from replication or for testing/internal/comm and/etc... * @param fromRepl really from replication or for testing/internal/comm and/etc...
* Returns if the op was an update that could not be applied (true on f ailure) * Returns if the op was an update that could not be applied (true on f ailure)
*/ */
bool applyOperation_inlock(const BSONObj& op , bool fromRepl = true ); bool applyOperation_inlock(const BSONObj& op , bool fromRepl = true );
/**
* If applyOperation_inlock should be called again after an update fail
s.
*/
bool shouldRetry(const BSONObj& op , const string& hn);
} }
 End of changes. 2 change blocks. 
6 lines changed or deleted 15 lines changed or added


 oplogreader.h   oplogreader.h 
skipping to change at line 18 skipping to change at line 18
namespace mongo { namespace mongo {
/* started abstracting out the querying of the primary/master's oplog /* started abstracting out the querying of the primary/master's oplog
still fairly awkward but a start. still fairly awkward but a start.
*/ */
class OplogReader { class OplogReader {
shared_ptr<DBClientConnection> _conn; shared_ptr<DBClientConnection> _conn;
shared_ptr<DBClientCursor> cursor; shared_ptr<DBClientCursor> cursor;
public: public:
OplogReader() { }
OplogReader() { ~OplogReader() { }
} void resetCursor() { cursor.reset(); }
~OplogReader() {
}
void resetCursor() {
cursor.reset();
}
void resetConnection() { void resetConnection() {
cursor.reset(); cursor.reset();
_conn.reset(); _conn.reset();
} }
DBClientConnection* conn() { return _conn.get(); } DBClientConnection* conn() { return _conn.get(); }
BSONObj findOne(const char *ns, const Query& q) { BSONObj findOne(const char *ns, const Query& q) {
return conn()->findOne(ns, q, 0, QueryOption_SlaveOk); return conn()->findOne(ns, q, 0, QueryOption_SlaveOk);
} }
BSONObj getLastOp(const char *ns) { BSONObj getLastOp(const char *ns) {
return findOne(ns, Query().sort(reverseNaturalObj)); return findOne(ns, Query().sort(reverseNaturalObj));
} }
/* ok to call if already connected */ /* ok to call if already connected */
bool connect(string hostname); bool connect(string hostname);
bool connect(const BSONObj& rid, const int from, const string& to); bool connect(const BSONObj& rid, const int from, const string& to);
void tailCheck() { void tailCheck() {
if( cursor.get() && cursor->isDead() ) { if( cursor.get() && cursor->isDead() ) {
log() << "repl: old cursor isDead, will initiate a new one" << endl; log() << "repl: old cursor isDead, will initiate a new one" << endl;
resetCursor(); resetCursor();
} }
} }
bool haveCursor() { return cursor.get() != 0; } bool haveCursor() { return cursor.get() != 0; }
/** this is ok but commented out as when used one should consider i
f QueryOption_OplogReplay
is needed; if not fine, but if so, need to change.
*//*
void query(const char *ns, const BSONObj& query) { void query(const char *ns, const BSONObj& query) {
assert( !haveCursor() ); assert( !haveCursor() );
cursor.reset( _conn->query(ns, query, 0, 0, 0, QueryOption_Slav eOk).release() ); cursor.reset( _conn->query(ns, query, 0, 0, 0, QueryOption_Slav eOk).release() );
} }*/
/** this can be used; it is commented out as it does not indicate
QueryOption_OplogReplay and that is likely important. could be
uncommented
just need to add that.
*/
/*
void queryGTE(const char *ns, OpTime t) { void queryGTE(const char *ns, OpTime t) {
BSONObjBuilder q; BSONObjBuilder q;
q.appendDate("$gte", t.asDate()); q.appendDate("$gte", t.asDate());
BSONObjBuilder q2; BSONObjBuilder q2;
q2.append("ts", q.done()); q2.append("ts", q.done());
query(ns, q2.done()); query(ns, q2.done());
} }
*/
void tailingQuery(const char *ns, const BSONObj& query, const BSONO bj* fields=0) { void tailingQuery(const char *ns, const BSONObj& query, const BSONO bj* fields=0) {
assert( !haveCursor() ); assert( !haveCursor() );
log(2) << "repl: " << ns << ".find(" << query.toString() << ')' << endl; log(2) << "repl: " << ns << ".find(" << query.toString() << ')' << endl;
cursor.reset( _conn->query( ns, query, 0, 0, fields, cursor.reset( _conn->query( ns, query, 0, 0, fields,
QueryOption_CursorTailable | QueryO ption_SlaveOk | QueryOption_OplogReplay | QueryOption_CursorTailable | QueryO ption_SlaveOk | QueryOption_OplogReplay |
/* TODO: slaveok maybe shouldn't us e? */ /* TODO: slaveOk maybe shouldn't us e? */
QueryOption_AwaitData QueryOption_AwaitData
).release() ); ).release() );
} }
void tailingQueryGTE(const char *ns, OpTime t, const BSONObj* field s=0) { void tailingQueryGTE(const char *ns, OpTime t, const BSONObj* field s=0) {
BSONObjBuilder q; BSONObjBuilder q;
q.appendDate("$gte", t.asDate()); q.appendDate("$gte", t.asDate());
BSONObjBuilder query; BSONObjBuilder query;
query.append("ts", q.done()); query.append("ts", q.done());
tailingQuery(ns, query.done(), fields); tailingQuery(ns, query.done(), fields);
} }
/* Do a tailing query, but only send the ts field back. */ /* Do a tailing query, but only send the ts field back. */
void ghostQueryGTE(const char *ns, OpTime t) { void ghostQueryGTE(const char *ns, OpTime t) {
const BSONObj fields = BSON("ts" << 1 << "_id" << 0); const BSONObj fields = BSON("ts" << 1 << "_id" << 0);
return tailingQueryGTE(ns, t, &fields); return tailingQueryGTE(ns, t, &fields);
} }
bool more() { bool more() {
assert( cursor.get() ); uassert( 15910, "Doesn't have cursor for reading oplog", cursor .get() );
return cursor->more(); return cursor->more();
} }
bool moreInCurrentBatch() { bool moreInCurrentBatch() {
assert( cursor.get() ); uassert( 15911, "Doesn't have cursor for reading oplog", cursor .get() );
return cursor->moreInCurrentBatch(); return cursor->moreInCurrentBatch();
} }
/* old mongod's can't do the await flag... */ /* old mongod's can't do the await flag... */
bool awaitCapable() { bool awaitCapable() {
return cursor->hasResultFlag(ResultFlag_AwaitCapable); return cursor->hasResultFlag(ResultFlag_AwaitCapable);
} }
void peek(vector<BSONObj>& v, int n) { void peek(vector<BSONObj>& v, int n) {
if( cursor.get() ) if( cursor.get() )
cursor->peek(v,n); cursor->peek(v,n);
} }
BSONObj nextSafe() { return cursor->nextSafe(); } BSONObj nextSafe() { return cursor->nextSafe(); }
BSONObj next() { return cursor->next(); } BSONObj next() { return cursor->next(); }
void putBack(BSONObj op) { cursor->putBack(op); } void putBack(BSONObj op) { cursor->putBack(op); }
private: private:
bool commonConnect(const string& hostName); bool commonConnect(const string& hostName);
bool passthroughHandshake(const BSONObj& rid, const int f); bool passthroughHandshake(const BSONObj& rid, const int f);
}; };
} }
 End of changes. 13 change blocks. 
17 lines changed or deleted 19 lines changed or added


 optime.h   optime.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 "../db/concurrency.h" //#include "../db/concurrency.h"
namespace mongo { namespace mongo {
void exitCleanly( ExitCode code ); void exitCleanly( ExitCode code );
struct ClockSkewException : public DBException { struct ClockSkewException : public DBException {
ClockSkewException() : DBException( "clock skew exception" , 20001 ) {} ClockSkewException() : DBException( "clock skew exception" , 20001 ) {}
}; };
/* replsets used to use RSOpTime. /* replsets used to use RSOpTime.
M/S uses OpTime. M/S uses OpTime.
skipping to change at line 45 skipping to change at line 45
/* Operation sequence #. A combination of current second plus an ordin al value. /* Operation sequence #. A combination of current second plus an ordin al value.
*/ */
#pragma pack(4) #pragma pack(4)
class OpTime { class OpTime {
unsigned i; // ordinal comes first so we can do a single 64 bit com pare on little endian unsigned i; // ordinal comes first so we can do a single 64 bit com pare on little endian
unsigned secs; unsigned secs;
static OpTime last; static OpTime last;
static OpTime skewed(); static OpTime skewed();
public: public:
static void setLast(const Date_t &date) { static void setLast(const Date_t &date) {
notifier().notify_all(); // won't really do anything until writ
e-lock released
last = OpTime(date); last = OpTime(date);
} }
unsigned getSecs() const { unsigned getSecs() const {
return secs; return secs;
} }
unsigned getInc() const { unsigned getInc() const {
return i; return i;
} }
OpTime(Date_t date) { OpTime(Date_t date) {
reinterpret_cast<unsigned long long&>(*this) = date.millis; reinterpret_cast<unsigned long long&>(*this) = date.millis;
skipping to change at line 77 skipping to change at line 79
secs = other.secs; secs = other.secs;
i = other.i; i = other.i;
dassert( (int)secs >= 0 ); dassert( (int)secs >= 0 );
} }
OpTime() { OpTime() {
secs = 0; secs = 0;
i = 0; i = 0;
} }
// it isn't generally safe to not be locked for this. so use now(). some tests use this. // it isn't generally safe to not be locked for this. so use now(). some tests use this.
static OpTime now_inlock() { static OpTime now_inlock() {
notifier().notify_all(); // won't really do anything until writ
e-lock released
unsigned t = (unsigned) time(0); unsigned t = (unsigned) time(0);
if ( last.secs == t ) { if ( last.secs == t ) {
last.i++; last.i++;
return last; return last;
} }
if ( t < last.secs ) { if ( t < last.secs ) {
return skewed(); // separate function to keep out of the ho t code path return skewed(); // separate function to keep out of the ho t code path
} }
last = OpTime(t, 1); last = OpTime(t, 1);
return last; return last;
} }
static OpTime now() { static OpTime now();
DEV dbMutex.assertWriteLocked(); static OpTime last_inlock();
return now_inlock();
} // Waits for global OpTime to be different from *this
// Must be atLeastReadLocked
// Defined in instance.cpp (only current user) as it needs dbtempre
lease
void waitForDifferent(unsigned millis);
/* 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
better choice for now than say, Number, which is floating point. Note the BinData type better choice for now than say, Number, which is floating point. Note the BinData type
is perhaps the cleanest choice, lacking a true unsigned64 datatype , but BinData has 5 is perhaps the cleanest choice, lacking a true unsigned64 datatype , but BinData has 5
bytes of overhead. bytes of overhead.
*/ */
unsigned long long asDate() const { unsigned long long asDate() const {
return reinterpret_cast<const unsigned long long*>(&i)[0]; return reinterpret_cast<const unsigned long long*>(&i)[0];
} }
skipping to change at line 149 skipping to change at line 156
} }
bool operator<=(const OpTime& r) const { bool operator<=(const OpTime& r) const {
return *this < r || *this == r; return *this < r || *this == r;
} }
bool operator>(const OpTime& r) const { bool operator>(const OpTime& r) const {
return !(*this <= r); return !(*this <= r);
} }
bool operator>=(const OpTime& r) const { bool operator>=(const OpTime& r) const {
return !(*this < r); return !(*this < r);
} }
private:
// The following functions are to get around the need to define cla
ss-level statics in a cpp
static boost::condition& notifier() {
static boost::condition* holder = new boost::condition();
return *holder;
};
static boost::mutex& notifyMutex() {
static boost::mutex* holder = new boost::mutex();
return *holder;
};
}; };
#pragma pack() #pragma pack()
} // namespace mongo } // namespace mongo
 End of changes. 5 change blocks. 
5 lines changed or deleted 27 lines changed or added


 ordering.h   ordering.h 
skipping to change at line 50 skipping to change at line 50
get(1) == -1 get(1) == -1
*/ */
int get(int i) const { int get(int i) const {
return ((1 << i) & bits) ? -1 : 1; return ((1 << i) & bits) ? -1 : 1;
} }
// for woCompare... // for woCompare...
unsigned descending(unsigned mask) const { return bits & mask; } unsigned descending(unsigned mask) const { return bits & mask; }
/*operator string() const { /*operator string() const {
StringBuilder buf(32); StringBuilder buf;
for ( unsigned i=0; i<nkeys; i++) for ( unsigned i=0; i<nkeys; i++)
buf.append( get(i) > 0 ? "+" : "-" ); buf.append( get(i) > 0 ? "+" : "-" );
return buf.str(); return buf.str();
}*/ }*/
static Ordering make(const BSONObj& obj) { static Ordering make(const BSONObj& obj) {
unsigned b = 0; unsigned b = 0;
BSONObjIterator k(obj); BSONObjIterator k(obj);
unsigned n = 0; unsigned n = 0;
while( 1 ) { while( 1 ) {
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 parallel.h   parallel.h 
skipping to change at line 22 skipping to change at line 22
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/** /**
tools for working in parallel/sharded/clustered environment tools for working in parallel/sharded/clustered environment
*/ */
#pragma once
#include "../pch.h" #include "../pch.h"
#include "dbclient.h" #include "dbclient.h"
#include "redef_macros.h" #include "redef_macros.h"
#include "../db/dbmessage.h" #include "../db/dbmessage.h"
#include "../db/matcher.h" #include "../db/matcher.h"
#include "../util/concurrency/mvar.h" #include "../util/concurrency/mvar.h"
namespace mongo { namespace mongo {
/** /**
skipping to change at line 72 skipping to change at line 74
BSONObj _extra; BSONObj _extra;
BSONObj _orderObject; BSONObj _orderObject;
}; };
/** /**
* this is a cursor that works over a set of servers * this is a cursor that works over a set of servers
* can be used in serial/paralellel as controlled by sub classes * can be used in serial/paralellel as controlled by sub classes
*/ */
class ClusteredCursor { class ClusteredCursor {
public: public:
ClusteredCursor( const QuerySpec& q );
ClusteredCursor( QueryMessage& q ); ClusteredCursor( QueryMessage& q );
ClusteredCursor( const string& ns , const BSONObj& q , int options= 0 , const BSONObj& fields=BSONObj() ); ClusteredCursor( const string& ns , const BSONObj& q , int options= 0 , const BSONObj& fields=BSONObj() );
virtual ~ClusteredCursor(); virtual ~ClusteredCursor();
/** call before using */ /** call before using */
void init(); void init();
virtual bool more() = 0; virtual bool more() = 0;
virtual BSONObj next() = 0; virtual BSONObj next() = 0;
static BSONObj concatQuery( const BSONObj& query , const BSONObj& e xtraFilter ); static BSONObj concatQuery( const BSONObj& query , const BSONObj& e xtraFilter );
virtual string type() const = 0; virtual string type() const = 0;
virtual BSONObj explain(); virtual void explain(BSONObjBuilder& b) = 0;
protected: protected:
virtual void _init() = 0; virtual void _init() = 0;
auto_ptr<DBClientCursor> query( const string& server , int num = 0 , BSONObj extraFilter = BSONObj() , int skipLeft = 0 , bool lazy=false ); auto_ptr<DBClientCursor> query( const string& server , int num = 0 , BSONObj extraFilter = BSONObj() , int skipLeft = 0 , bool lazy=false );
BSONObj explain( const string& server , BSONObj extraFilter = BSONO bj() ); BSONObj explain( const string& server , BSONObj extraFilter = BSONO bj() );
/** /**
* checks the cursor for any errors * checks the cursor for any errors
* will throw an exceptionif an error is encountered * will throw an exceptionif an error is encountered
*/ */
void _checkCursor( DBClientCursor * cursor ); void _checkCursor( DBClientCursor * cursor );
static BSONObj _concatFilter( const BSONObj& filter , const BSONObj & extraFilter ); static BSONObj _concatFilter( const BSONObj& filter , const BSONObj & extraFilter );
virtual void _explain( map< string,list<BSONObj> >& out ) = 0; virtual void _explain( map< string,list<BSONObj> >& out ) = 0;
string _ns; string _ns;
BSONObj _query; BSONObj _query;
BSONObj _hint;
BSONObj _sort;
int _options; int _options;
BSONObj _fields; BSONObj _fields;
int _batchSize; int _batchSize;
bool _didInit; bool _didInit;
bool _done; bool _done;
}; };
class ParallelConnectionMetadata;
// TODO: We probably don't really need this as a separate class.
class FilteringClientCursor { class FilteringClientCursor {
public: public:
FilteringClientCursor( const BSONObj filter = BSONObj() ); FilteringClientCursor( const BSONObj filter = BSONObj() );
FilteringClientCursor( DBClientCursor* cursor , const BSONObj filte r = BSONObj() ); FilteringClientCursor( DBClientCursor* cursor , const BSONObj filte r = BSONObj() );
FilteringClientCursor( auto_ptr<DBClientCursor> cursor , const BSON Obj filter = BSONObj() ); FilteringClientCursor( auto_ptr<DBClientCursor> cursor , const BSON Obj filter = BSONObj() );
~FilteringClientCursor(); ~FilteringClientCursor();
void reset( auto_ptr<DBClientCursor> cursor ); void reset( auto_ptr<DBClientCursor> cursor );
void reset( DBClientCursor* cursor ); void reset( DBClientCursor* cursor, ParallelConnectionMetadata* _pc mData = NULL );
bool more(); bool more();
BSONObj next(); BSONObj next();
BSONObj peek(); BSONObj peek();
DBClientCursor* raw() { return _cursor.get(); } DBClientCursor* raw() { return _cursor.get(); }
ParallelConnectionMetadata* rawMData(){ return _pcmData; }
// Required for new PCursor
void release(){
_cursor.release();
_pcmData = NULL;
}
private: private:
void _advance(); void _advance();
Matcher _matcher; Matcher _matcher;
auto_ptr<DBClientCursor> _cursor; auto_ptr<DBClientCursor> _cursor;
ParallelConnectionMetadata* _pcmData;
BSONObj _next; BSONObj _next;
bool _done; bool _done;
}; };
class Servers { class Servers {
public: public:
Servers() { Servers() {
} }
skipping to change at line 219 skipping to change at line 236
void _init() {} void _init() {}
vector<ServerAndQuery> _servers; vector<ServerAndQuery> _servers;
unsigned _serverIndex; unsigned _serverIndex;
FilteringClientCursor _current; FilteringClientCursor _current;
int _needToSkip; int _needToSkip;
}; };
class CommandInfo {
public:
string versionedNS;
BSONObj cmdFilter;
CommandInfo() {}
CommandInfo( const string& vns, const BSONObj& filter ) : versioned
NS( vns ), cmdFilter( filter ) {}
bool isEmpty(){
return versionedNS.size() == 0;
}
string toString() const {
return str::stream() << "CInfo " << BSON( "v_ns" << versionedNS
<< "filter" << cmdFilter );
}
};
class ShardConnection;
typedef shared_ptr<ShardConnection> ShardConnectionPtr;
class DBClientCursor;
typedef shared_ptr<DBClientCursor> DBClientCursorPtr;
class Shard;
typedef shared_ptr<Shard> ShardPtr;
class ChunkManager;
typedef shared_ptr<const ChunkManager> ChunkManagerPtr;
class ParallelConnectionState {
public:
ParallelConnectionState() :
count( 0 ), done( false ) { }
ShardConnectionPtr conn;
DBClientCursorPtr cursor;
// Version information
ChunkManagerPtr manager;
ShardPtr primary;
// Cursor status information
long long count;
bool done;
BSONObj toBSON() const;
string toString() const {
return str::stream() << "PCState : " << toBSON();
}
};
typedef ParallelConnectionState PCState;
typedef shared_ptr<PCState> PCStatePtr;
class ParallelConnectionMetadata {
public:
ParallelConnectionMetadata() :
retryNext( false ), initialized( false ), finished( false ), co
mpleted( false ), errored( false ) { }
~ParallelConnectionMetadata(){
cleanup( true );
}
void cleanup( bool full = true );
PCStatePtr pcState;
bool retryNext;
bool initialized;
bool finished;
bool completed;
bool errored;
BSONObj toBSON() const;
string toString() const {
return str::stream() << "PCMData : " << toBSON();
}
};
typedef ParallelConnectionMetadata PCMData;
typedef shared_ptr<PCMData> PCMDataPtr;
/** /**
* runs a query in parellel across N servers * Runs a query in parallel across N servers. New logic has several mo
* sots des -
* 1) Standard query, enforces compatible chunk versions for queries ac
ross all results
* 2) Standard query, sent to particular servers with no compatible chu
nk version enforced, but handling
* stale configuration exceptions
* 3) Command query, either enforcing compatible chunk versions or sent
to particular shards.
*/ */
class ParallelSortClusteredCursor : public ClusteredCursor { class ParallelSortClusteredCursor : public ClusteredCursor {
public: public:
ParallelSortClusteredCursor( const QuerySpec& qSpec, const CommandI
nfo& cInfo = CommandInfo() );
ParallelSortClusteredCursor( const set<Shard>& servers, const Query
Spec& qSpec );
// LEGACY Constructors
ParallelSortClusteredCursor( const set<ServerAndQuery>& servers , Q ueryMessage& q , const BSONObj& sortKey ); ParallelSortClusteredCursor( const set<ServerAndQuery>& servers , Q ueryMessage& q , const BSONObj& sortKey );
ParallelSortClusteredCursor( const set<ServerAndQuery>& servers , c onst string& ns , ParallelSortClusteredCursor( const set<ServerAndQuery>& servers , c onst string& ns ,
const Query& q , int options=0, const BSONObj& fields=BSONObj() ); const Query& q , int options=0, const BSONObj& fields=BSONObj() );
virtual ~ParallelSortClusteredCursor(); virtual ~ParallelSortClusteredCursor();
virtual bool more(); virtual bool more();
virtual BSONObj next(); virtual BSONObj next();
virtual string type() const { return "ParallelSort"; } virtual string type() const { return "ParallelSort"; }
void fullInit();
void startInit();
void finishInit();
bool isCommand(){ return NamespaceString( _qSpec.ns() ).isCommand()
; }
bool isExplain(){ return _qSpec.isExplain(); }
bool isVersioned(){ return _qShards.size() == 0; }
bool isSharded();
ShardPtr getPrimary();
void getQueryShards( set<Shard>& shards );
ChunkManagerPtr getChunkManager( const Shard& shard );
DBClientCursorPtr getShardCursor( const Shard& shard );
BSONObj toBSON() const;
string toString() const;
virtual void explain(BSONObjBuilder& b);
protected: protected:
void _finishCons(); void _finishCons();
void _init(); void _init();
void _oldInit();
virtual void _explain( map< string,list<BSONObj> >& out ); virtual void _explain( map< string,list<BSONObj> >& out );
void _markStaleNS( const NamespaceString& staleNS, bool& forceReloa
d, bool& fullReload );
void _handleStaleNS( const NamespaceString& staleNS, bool forceRelo
ad, bool fullReload );
set<Shard> _qShards;
QuerySpec _qSpec;
CommandInfo _cInfo;
// Count round-trips req'd for namespaces and total
map<string,int> _staleNSMap;
int _totalTries;
map<Shard,PCMData> _cursorMap;
// LEGACY BELOW
int _numServers; int _numServers;
int _lastFrom;
set<ServerAndQuery> _servers; set<ServerAndQuery> _servers;
BSONObj _sortKey; BSONObj _sortKey;
FilteringClientCursor * _cursors; FilteringClientCursor * _cursors;
int _needToSkip; int _needToSkip;
}; };
/** /**
* tools for doing asynchronous operations * tools for doing asynchronous operations
* right now uses underlying sync network ops and uses another thread * right now uses underlying sync network ops and uses another thread
skipping to change at line 275 skipping to change at line 423
BSONObj result() const { BSONObj result() const {
assert( _done ); assert( _done );
return _res; return _res;
} }
/** /**
blocks until command is done blocks until command is done
returns ok() returns ok()
*/ */
bool join(); bool join( int maxRetries = 1 );
private: private:
CommandResult( const string& server , const string& db , const BSONObj& cmd , int options , DBClientBase * conn ); CommandResult( const string& server , const string& db , const BSONObj& cmd , int options , DBClientBase * conn );
void init();
string _server; string _server;
string _db; string _db;
int _options; int _options;
BSONObj _cmd; BSONObj _cmd;
DBClientBase * _conn; DBClientBase * _conn;
scoped_ptr<ScopedDbConnection> _connHolder; // used if not prov ided a connection scoped_ptr<ScopedDbConnection> _connHolder; // used if not prov ided a connection
scoped_ptr<DBClientCursor> _cursor; scoped_ptr<DBClientCursor> _cursor;
 End of changes. 18 change blocks. 
6 lines changed or deleted 167 lines changed or added


 paths.h   paths.h 
skipping to change at line 26 skipping to change at line 26
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "mongoutils/str.h" #include "mongoutils/str.h"
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <boost/filesystem/path.hpp>
namespace mongo { namespace mongo {
using namespace mongoutils; using namespace mongoutils;
extern string dbpath; extern string dbpath;
/** this is very much like a boost::path. however, we define a new typ e to get some type /** this is very much like a boost::path. however, we define a new typ e to get some type
checking. if you want to say 'my param MUST be a relative path", u se this. checking. if you want to say 'my param MUST be a relative path", u se this.
*/ */
struct RelativePath { struct RelativePath {
skipping to change at line 47 skipping to change at line 49
bool empty() const { return _p.empty(); } bool empty() const { return _p.empty(); }
static RelativePath fromRelativePath(string f) { static RelativePath fromRelativePath(string f) {
RelativePath rp; RelativePath rp;
rp._p = f; rp._p = f;
return rp; return rp;
} }
/** from a full path */ /** from a full path */
static RelativePath fromFullPath(path f) { static RelativePath fromFullPath(boost::filesystem::path f) {
path dbp(dbpath); // normalizes / and backslash boost::filesystem::path dbp(dbpath); // normalizes / and backsl
ash
string fullpath = f.string(); string fullpath = f.string();
string relative = str::after(fullpath, dbp.string()); string relative = str::after(fullpath, dbp.string());
if( relative.empty() ) { if( relative.empty() ) {
log() << "warning file is not under db path? " << fullpath << ' ' << dbp.string() << endl; log() << "warning file is not under db path? " << fullpath << ' ' << dbp.string() << endl;
RelativePath rp; RelativePath rp;
rp._p = fullpath; rp._p = fullpath;
return rp; return rp;
} }
/*uassert(13600, /*uassert(13600,
str::stream() << "file path is not under the db path? " << fullpath << ' ' << dbpath, str::stream() << "file path is not under the db path? " << fullpath << ' ' << dbpath,
skipping to change at line 75 skipping to change at line 77
return rp; return rp;
} }
string toString() const { return _p; } string toString() const { return _p; }
bool operator!=(const RelativePath& r) const { return _p != r._p; } bool operator!=(const RelativePath& r) const { return _p != r._p; }
bool operator==(const RelativePath& r) const { return _p == r._p; } bool operator==(const RelativePath& r) const { return _p == r._p; }
bool operator<(const RelativePath& r) const { return _p < r._p; } bool operator<(const RelativePath& r) const { return _p < r._p; }
string asFullPath() const { string asFullPath() const {
path x(dbpath); boost::filesystem::path x(dbpath);
x /= _p; x /= _p;
return x.string(); return x.string();
} }
}; };
inline dev_t getPartition(const string& path){ inline dev_t getPartition(const string& path){
struct stat stats; struct stat stats;
if (stat(path.c_str(), &stats) != 0){ if (stat(path.c_str(), &stats) != 0){
skipping to change at line 101 skipping to change at line 103
inline bool onSamePartition(const string& path1, const string& path2){ inline bool onSamePartition(const string& path1, const string& path2){
dev_t dev1 = getPartition(path1); dev_t dev1 = getPartition(path1);
dev_t dev2 = getPartition(path2); dev_t dev2 = getPartition(path2);
return dev1 == dev2; return dev1 == dev2;
} }
inline void flushMyDirectory(const boost::filesystem::path& file){ inline void flushMyDirectory(const boost::filesystem::path& file){
#ifdef __linux__ // this isn't needed elsewhere #ifdef __linux__ // this isn't needed elsewhere
massert(13652, str::stream() << "Couldn't find parent dir for file: // if called without a fully qualified path it asserts; that makes
" << file.string(), file.has_branch_path()); mongoperf fail. so make a warning. need a better solution longer term.
// massert(13652, str::stream() << "Couldn't find parent dir for fi
le: " << file.string(), );
if( !file.has_branch_path() ) {
log() << "warning flushMYDirectory couldn't find parent dir for
file: " << file.string() << endl;
return;
}
boost::filesystem::path dir = file.branch_path(); // parent_path in new boosts boost::filesystem::path dir = file.branch_path(); // parent_path in new boosts
log(1) << "flushing directory " << dir.string() << endl; log(1) << "flushing directory " << dir.string() << endl;
int fd = ::open(dir.string().c_str(), O_RDONLY); // DO NOT THROW OR ASSERT BEFORE CLOSING int fd = ::open(dir.string().c_str(), O_RDONLY); // DO NOT THROW OR ASSERT BEFORE CLOSING
massert(13650, str::stream() << "Couldn't open directory '" << dir. string() << "' for flushing: " << errnoWithDescription(), fd >= 0); massert(13650, str::stream() << "Couldn't open directory '" << dir. string() << "' for flushing: " << errnoWithDescription(), fd >= 0);
if (fsync(fd) != 0){ if (fsync(fd) != 0){
int e = errno; int e = errno;
close(fd); close(fd);
massert(13651, str::stream() << "Couldn't fsync directory '" << dir.string() << "': " << errnoWithDescription(e), false); massert(13651, str::stream() << "Couldn't fsync directory '" << dir.string() << "': " << errnoWithDescription(e), false);
} }
close(fd); close(fd);
#endif #endif
} }
boost::filesystem::path ensureParentDirCreated(const boost::filesystem:
:path& p);
} }
 End of changes. 5 change blocks. 
5 lines changed or deleted 19 lines changed or added


 pch.h   pch.h 
/** @file pch.h : include file for standard system include files, /** @file pch.h : include file for standard system include files,
* or project specific include files that are used frequently, but * or project specific include files that are used frequently, but
* are changed infrequently * are changed infrequently
*/ */
/* Copyright 2009 10gen Inc. /* Copyright 2009 10gen Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
skipping to change at line 25 skipping to change at line 25
* 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.
*/ */
#ifndef MONGO_PCH_H #ifndef MONGO_PCH_H
#define MONGO_PCH_H #define MONGO_PCH_H
#if defined(MONGO_EXPOSE_MACROS) #if defined(MONGO_EXPOSE_MACROS)
// this is defined in server.h for non-MONGO_EXPOSE_MACROS
# define BOOST_ENABLE_ASSERT_HANDLER 1
# define JS_C_STRINGS_ARE_UTF8 # define JS_C_STRINGS_ARE_UTF8
# undef SUPPORT_UCP # undef SUPPORT_UCP
# define SUPPORT_UCP # define SUPPORT_UCP
# undef SUPPORT_UTF8 # undef SUPPORT_UTF8
# define SUPPORT_UTF8 # define SUPPORT_UTF8
# undef _CRT_SECURE_NO_WARNINGS # undef _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS # define _CRT_SECURE_NO_WARNINGS
#endif #endif
#if defined(_WIN32) #if defined(_WIN32)
skipping to change at line 60 skipping to change at line 63
# define __builtin_strlen strlen # define __builtin_strlen strlen
# define __builtin_memchr memchr # define __builtin_memchr memchr
# define __builtin_memcmp memcmp # define __builtin_memcmp memcmp
# define __builtin_memcpy memcpy # define __builtin_memcpy memcpy
# define __builtin_memset memset # define __builtin_memset memset
# define __builtin_memmove memmove # define __builtin_memmove memmove
#endif #endif
#include <ctime> #include <ctime>
#include <cstring> #include <cstring>
#include <sstream>
#include <string> #include <string>
#include <memory> #include <memory>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <fstream>
#include <map> #include <map>
#include <vector> #include <vector>
#include <set> #include <set>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sstream>
#include <signal.h> #include <signal.h>
#include "targetver.h" #include "targetver.h"
#include "time.h" #include "time.h"
#include "string.h" #include "string.h"
#include "limits.h" #include "limits.h"
//#include <boost/any.hpp>
#include "boost/thread/once.hpp"
//#include <boost/archive/iterators/transform_width.hpp>
#define BOOST_FILESYSTEM_VERSION 2 #define BOOST_FILESYSTEM_VERSION 2
#include <boost/filesystem/convenience.hpp> #include <boost/lexical_cast.hpp>
#include <boost/filesystem/exception.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/program_options.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/smart_ptr.hpp> #include <boost/smart_ptr.hpp>
#include <boost/function.hpp> #include <boost/function.hpp>
#include "boost/bind.hpp" #include <boost/bind.hpp>
#include "boost/function.hpp"
#include <boost/thread/tss.hpp> #include <boost/thread/tss.hpp>
#include "boost/detail/endian.hpp" #include <boost/detail/endian.hpp>
#define BOOST_SPIRIT_THREADSAFE
#include <boost/version.hpp> #include <boost/version.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/thread/condition.hpp> #include <boost/thread/condition.hpp>
#include <boost/thread/recursive_mutex.hpp> #include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/xtime.hpp> #include <boost/thread/xtime.hpp>
#undef assert
#define assert MONGO_assert
namespace mongo { namespace mongo {
using namespace std; using namespace std;
using boost::shared_ptr; using boost::shared_ptr;
#if defined(_DEBUG) #if defined(_DEBUG)
const bool debug=true; const bool debug=true;
#else #else
const bool debug=false; const bool debug=false;
#endif #endif
// pdfile versions // pdfile versions
const int VERSION = 4; const int PDFILE_VERSION = 4;
const int VERSION_MINOR = 5; const int PDFILE_VERSION_MINOR = 5;
enum ExitCode { enum ExitCode {
EXIT_CLEAN = 0 , EXIT_CLEAN = 0 ,
EXIT_BADOPTIONS = 2 , EXIT_BADOPTIONS = 2 ,
EXIT_REPLICATION_ERROR = 3 , EXIT_REPLICATION_ERROR = 3 ,
EXIT_NEED_UPGRADE = 4 , EXIT_NEED_UPGRADE = 4 ,
EXIT_SHARDING_ERROR = 5 , EXIT_SHARDING_ERROR = 5 ,
EXIT_KILL = 12 , EXIT_KILL = 12 ,
EXIT_ABRUPT = 14 , EXIT_ABRUPT = 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_CLOCK_SKEW = 47 ,
EXIT_NET_ERROR = 48 , EXIT_NET_ERROR = 48 ,
EXIT_WINDOWS_SERVICE_STOP = 49 , EXIT_WINDOWS_SERVICE_STOP = 49 ,
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 = "", bool tryToGe tLock = false); void dbexit( ExitCode returnCode, const char *whyMsg = "", bool tryToGe tLock = false);
/** /**
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
you should either use dbexit to shutdown cleanly, or ::exit to tell the system to quit you should either use dbexit to shutdown cleanly, or ::exit to tell the system to quit
if you use this, you'll get a link error since mongo::exit isn't def ined if you use this, you'll get a link error since mongo::exit isn't def ined
*/ */
void exit( ExitCode returnCode ); void exit( ExitCode returnCode );
bool inShutdown(); bool inShutdown();
using namespace boost::filesystem;
void asserted(const char *msg, const char *file, unsigned line); void asserted(const char *msg, const char *file, unsigned line);
} }
#include "util/allocator.h"
#include "client/redef_macros.h"
// TODO: Rework the headers so we don't need this craziness // TODO: Rework the headers so we don't need this craziness
#include "bson/inline_decls.h" #include "bson/inline_decls.h"
#define MONGO_assert(_Expression) (void)( MONGO_likely(!!(_Expression)) || (mongo::asserted(#_Expression, __FILE__, __LINE__), 0) ) #define MONGO_assert(_Expression) (void)( MONGO_likely(!!(_Expression)) || (mongo::asserted(#_Expression, __FILE__, __LINE__), 0) )
#include "util/debug_util.h" #include "util/debug_util.h"
#include "util/goodies.h" #include "util/goodies.h"
#include "util/log.h" #include "util/log.h"
#include "util/allocator.h"
#include "util/assert_util.h" #include "util/assert_util.h"
namespace mongo { namespace mongo {
void sayDbContext(const char *msg = 0); void sayDbContext(const char *msg = 0);
void rawOut( const string &s ); void rawOut( const string &s );
typedef char _TCHAR; typedef char _TCHAR;
using boost::uint32_t; using boost::uint32_t;
using boost::uint64_t; using boost::uint64_t;
/** called by mongos, mongod, test. do not call from clients and such. /** called by mongos, mongod, test. do not call from clients and such.
invoked before about everything except global var construction. invoked before about everything except global var construction.
*/ */
void doPreServerStatupInits(); void doPreServerStartupInits();
} // namespace mongo } // namespace mongo
#endif // MONGO_PCH_H #endif // MONGO_PCH_H
 End of changes. 17 change blocks. 
26 lines changed or deleted 14 lines changed or added


 pdfile.h   pdfile.h 
skipping to change at line 35 skipping to change at line 35
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "../util/mmap.h" #include "../util/mmap.h"
#include "diskloc.h" #include "diskloc.h"
#include "jsobjmanipulator.h" #include "jsobjmanipulator.h"
#include "namespace-inl.h" #include "namespace-inl.h"
#include "client.h" #include "client.h"
#include "mongommf.h" #include "mongommf.h"
#include "memconcept.h"
namespace mongo { namespace mongo {
class DataFileHeader; class DataFileHeader;
class Extent; class Extent;
class Record; class Record;
class Cursor; class Cursor;
class OpDebug; class OpDebug;
void dropDatabase(string db); void dropDatabase(string db);
skipping to change at line 64 skipping to change at line 65
bool isValidNS( const StringData& ns ); bool isValidNS( const StringData& ns );
/*--------------------------------------------------------------------- */ /*--------------------------------------------------------------------- */
class MongoDataFile { class MongoDataFile {
friend class DataFileMgr; friend class DataFileMgr;
friend class BasicCursor; friend class BasicCursor;
public: public:
MongoDataFile(int fn) : _mb(0), fileNo(fn) { } MongoDataFile(int fn) : _mb(0), fileNo(fn) { }
/** @return true if found and opened. if uninitialized (prealloc on
ly) does not open. */
bool openExisting( const char *filename );
/** creates if DNE */
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);
DataFileHeader *getHeader() { return header(); } DataFileHeader *getHeader() { return header(); }
skipping to change at line 199 skipping to change at line 205
/** be careful when referencing this that your write intent was cor rect */ /** be careful when referencing this that your write intent was cor rect */
char data[4]; char data[4];
int netLength() { int netLength() {
return lengthWithHeaders - HeaderSize; return lengthWithHeaders - HeaderSize;
} }
//void setNewLength(int netlen) { lengthWithHeaders = netlen + Head erSize; } //void setNewLength(int netlen) { lengthWithHeaders = netlen + Head erSize; }
/* use this when a record is deleted. basically a union with next/p rev fields */ /* use this when a record is deleted. basically a union with next/p rev fields */
DeletedRecord& asDeleted() { DeletedRecord& asDeleted() { return *((DeletedRecord*) this); }
return *((DeletedRecord*) this);
} Extent* myExtent(const DiskLoc& myLoc) { return DataFileMgr::getExt
ent(DiskLoc(myLoc.a(), extentOfs)); }
Extent* myExtent(const DiskLoc& myLoc) {
return DataFileMgr::getExtent(DiskLoc(myLoc.a(), extentOfs));
}
/* get the next record in the namespace, traversing extents as nece ssary */ /* get the next record in the namespace, traversing extents as nece ssary */
DiskLoc getNext(const DiskLoc& myLoc); DiskLoc getNext(const DiskLoc& myLoc);
DiskLoc getPrev(const DiskLoc& myLoc); DiskLoc getPrev(const DiskLoc& myLoc);
DiskLoc nextInExtent(const DiskLoc& myLoc) { DiskLoc nextInExtent(const DiskLoc& myLoc) {
if ( nextOfs == DiskLoc::NullOfs ) if ( nextOfs == DiskLoc::NullOfs )
return DiskLoc(); return DiskLoc();
assert( nextOfs ); assert( nextOfs );
return DiskLoc(myLoc.a(), nextOfs); return DiskLoc(myLoc.a(), nextOfs);
} }
skipping to change at line 316 skipping to change at line 319
assert( dl.sameFile(myLoc) ); assert( dl.sameFile(myLoc) );
int x = dl.getOfs() - myLoc.getOfs(); int x = dl.getOfs() - myLoc.getOfs();
assert( x > 0 ); assert( x > 0 );
return (Record *) (((char *) this) + x); return (Record *) (((char *) this) + x);
} }
Extent* getNextExtent() { return xnext.isNull() ? 0 : DataFileMgr:: getExtent(xnext); } Extent* getNextExtent() { return xnext.isNull() ? 0 : DataFileMgr:: getExtent(xnext); }
Extent* getPrevExtent() { return xprev.isNull() ? 0 : DataFileMgr:: getExtent(xprev); } Extent* getPrevExtent() { return xprev.isNull() ? 0 : DataFileMgr:: getExtent(xprev); }
static int maxSize(); static int maxSize();
static int minSize() { return 0x1000; } static int minSize() { return 0x100; }
/** /**
* @param len lengt of record we need * @param len lengt of record we need
* @param lastRecord size of last extent which is a factor in next extent size * @param lastRecord size of last extent which is a factor in next extent size
*/ */
static int followupSize(int len, int lastExtentLen); static int followupSize(int len, int lastExtentLen);
/** get a suggested size for the first extent in a namespace /** get a suggested size for the first extent in a namespace
* @param len length of record we need to insert * @param len length of record we need to insert
*/ */
static int initialSize(int len); static int initialSize(int len);
skipping to change at line 369 skipping to change at line 372
int versionMinor; int versionMinor;
int fileLength; int fileLength;
DiskLoc unused; /* unused is the portion of the file that doesn't b elong to any allocated extents. -1 = no more */ DiskLoc unused; /* unused is the portion of the file that doesn't b elong to any allocated extents. -1 = no more */
int unusedLength; int unusedLength;
char reserved[8192 - 4*4 - 8]; char reserved[8192 - 4*4 - 8];
char data[4]; // first extent starts here char data[4]; // first extent starts here
enum { HeaderSize = 8192 }; enum { HeaderSize = 8192 };
bool isCurrentVersion() const { return ( version == VERSION ) && ( versionMinor == VERSION_MINOR ); } bool isCurrentVersion() const { return ( version == PDFILE_VERSION ) && ( versionMinor == PDFILE_VERSION_MINOR ); }
bool uninitialized() const { return version == 0; } bool uninitialized() const { return version == 0; }
void init(int fileno, int filelength, const char* filename) { void init(int fileno, int filelength, const char* filename) {
if ( uninitialized() ) { if ( uninitialized() ) {
DEV log() << "datafileheader::init initializing " << filena me << " n:" << fileno << endl;
if( !(filelength > 32768 ) ) { if( !(filelength > 32768 ) ) {
massert(13640, str::stream() << "DataFileHeader looks c orrupt at file open filelength:" << filelength << " fileno:" << fileno, fal se); massert(13640, str::stream() << "DataFileHeader looks c orrupt at file open filelength:" << filelength << " fileno:" << fileno, fal se);
} }
{
if( !d.dbMutex.isWriteLocked() ) {
log() << "*** TEMP NOT INITIALIZING FILE " << filen
ame << ", not in a write lock." << endl;
log() << "temp bypass until more elaborate change -
case that is manifesting is benign anyway" << endl;
return;
/**
log() << "ERROR can't create outside a write lock"
<< endl;
printStackTrace();
::abort();
**/
}
}
getDur().createdFile(filename, filelength); getDur().createdFile(filename, filelength);
assert( HeaderSize == 8192 ); assert( HeaderSize == 8192 );
DataFileHeader *h = getDur().writing(this); DataFileHeader *h = getDur().writing(this);
h->fileLength = filelength; h->fileLength = filelength;
h->version = VERSION; h->version = PDFILE_VERSION;
h->versionMinor = VERSION_MINOR; h->versionMinor = PDFILE_VERSION_MINOR;
h->unused.set( fileno, HeaderSize ); h->unused.set( fileno, HeaderSize );
assert( (data-(char*)this) == HeaderSize ); assert( (data-(char*)this) == HeaderSize );
h->unusedLength = fileLength - HeaderSize - 16; h->unusedLength = fileLength - HeaderSize - 16;
} }
} }
bool isEmpty() const { bool isEmpty() const {
return uninitialized() || ( unusedLength == fileLength - Header Size - 16 ); return uninitialized() || ( unusedLength == fileLength - Header Size - 16 );
} }
}; };
skipping to change at line 406 skipping to change at line 424
inline Extent* MongoDataFile::_getExtent(DiskLoc loc) const { inline Extent* MongoDataFile::_getExtent(DiskLoc loc) const {
loc.assertOk(); loc.assertOk();
Extent *e = (Extent *) (p()+loc.getOfs()); Extent *e = (Extent *) (p()+loc.getOfs());
return e; return e;
} }
inline Extent* MongoDataFile::getExtent(DiskLoc loc) const { inline Extent* MongoDataFile::getExtent(DiskLoc loc) const {
Extent *e = _getExtent(loc); Extent *e = _getExtent(loc);
e->assertOk(); e->assertOk();
memconcept::is(e, memconcept::extent);
return e; return e;
} }
} // namespace mongo } // namespace mongo
#include "cursor.h" #include "cursor.h"
namespace mongo { namespace mongo {
inline Record* MongoDataFile::recordAt(DiskLoc dl) { inline Record* MongoDataFile::recordAt(DiskLoc dl) {
skipping to change at line 457 skipping to change at line 476
} }
inline DiskLoc Record::getPrev(const DiskLoc& myLoc) { inline DiskLoc Record::getPrev(const DiskLoc& myLoc) {
if ( prevOfs != DiskLoc::NullOfs ) if ( prevOfs != DiskLoc::NullOfs )
return DiskLoc(myLoc.a(), prevOfs); return DiskLoc(myLoc.a(), prevOfs);
Extent *e = myExtent(myLoc); Extent *e = myExtent(myLoc);
if ( e->xprev.isNull() ) if ( e->xprev.isNull() )
return DiskLoc(); return DiskLoc();
return e->xprev.ext()->lastRecord; return e->xprev.ext()->lastRecord;
} }
inline Record* DiskLoc::rec() const {
return DataFileMgr::getRecord(*this);
}
inline BSONObj DiskLoc::obj() const { inline BSONObj DiskLoc::obj() const {
return BSONObj(rec()->accessed()); return BSONObj(rec()->accessed());
} }
inline DeletedRecord* DiskLoc::drec() const { inline DeletedRecord* DiskLoc::drec() const {
assert( _a != -1 ); assert( _a != -1 );
return (DeletedRecord*) rec(); DeletedRecord* dr = (DeletedRecord*) rec();
memconcept::is(dr, memconcept::deletedrecord);
return dr;
} }
inline Extent* DiskLoc::ext() const { inline Extent* DiskLoc::ext() const {
return DataFileMgr::getExtent(*this); return DataFileMgr::getExtent(*this);
} }
template< class V > template< class V >
inline inline
const BtreeBucket<V> * DiskLoc::btree() const { const BtreeBucket<V> * DiskLoc::btree() const {
assert( _a != -1 ); assert( _a != -1 );
return (const BtreeBucket<V> *) rec()->data; return (const BtreeBucket<V> *) rec()->data;
} }
} // namespace mongo } // namespace mongo
#include "database.h" #include "database.h"
#include "memconcept.h"
namespace mongo { namespace mongo {
boost::intmax_t dbSize( const char *database ); boost::intmax_t dbSize( const char *database );
inline NamespaceIndex* nsindex(const char *ns) { inline NamespaceIndex* nsindex(const char *ns) {
Database *database = cc().database(); Database *database = cc().database();
assert( database ); assert( database );
memconcept::is(database, memconcept::database, ns, sizeof(Database) );
DEV { DEV {
char buf[256]; char buf[256];
nsToDatabase(ns, buf); nsToDatabase(ns, buf);
if ( database->name != buf ) { if ( database->name != buf ) {
out() << "ERROR: attempt to write to wrong database databas e\n"; out() << "ERROR: attempt to write to wrong database\n";
out() << " ns:" << ns << '\n'; out() << " ns:" << ns << '\n';
out() << " database->name:" << database->name << endl; out() << " database->name:" << database->name << endl;
assert( database->name == buf ); assert( database->name == buf );
} }
} }
return &database->namespaceIndex; return &database->namespaceIndex;
} }
inline NamespaceDetails* nsdetails(const char *ns) { inline NamespaceDetails* nsdetails(const char *ns) {
// if this faults, did you set the current db first? (Client::Cont ext + dblock) // if this faults, did you set the current db first? (Client::Cont ext + dblock)
return nsindex(ns)->details(ns); NamespaceDetails *d = nsindex(ns)->details(ns);
if( d ) {
memconcept::is(d, memconcept::nsdetails, ns, sizeof(NamespaceDe
tails));
}
return d;
} }
inline Extent* DataFileMgr::getExtent(const DiskLoc& dl) { inline Extent* DataFileMgr::getExtent(const DiskLoc& dl) {
assert( dl.a() != -1 ); assert( dl.a() != -1 );
return cc().database()->getFile(dl.a())->getExtent(dl); return cc().database()->getFile(dl.a())->getExtent(dl);
} }
inline Record* DataFileMgr::getRecord(const DiskLoc& dl) { inline Record* DataFileMgr::getRecord(const DiskLoc& dl) {
assert( dl.a() != -1 ); assert( dl.a() != -1 );
return cc().database()->getFile(dl.a())->recordAt(dl); Record* r = cc().database()->getFile(dl.a())->recordAt(dl);
return r;
} }
BOOST_STATIC_ASSERT( 16 == sizeof(DeletedRecord) ); BOOST_STATIC_ASSERT( 16 == sizeof(DeletedRecord) );
inline DeletedRecord* DataFileMgr::makeDeletedRecord(const DiskLoc& dl, int len) { inline DeletedRecord* DataFileMgr::makeDeletedRecord(const DiskLoc& dl, int len) {
assert( dl.a() != -1 ); assert( dl.a() != -1 );
return (DeletedRecord*) cc().database()->getFile(dl.a())->makeRecor d(dl, sizeof(DeletedRecord)); return (DeletedRecord*) cc().database()->getFile(dl.a())->makeRecor d(dl, sizeof(DeletedRecord));
} }
void ensureHaveIdIndex(const char *ns); void ensureHaveIdIndex(const char *ns);
 End of changes. 17 change blocks. 
17 lines changed or deleted 48 lines changed or added


 query.h   query.h 
skipping to change at line 37 skipping to change at line 37
// struct QueryOptions, QueryResult, QueryResultFlags in: // struct QueryOptions, QueryResult, QueryResultFlags in:
#include "../../client/dbclient.h" #include "../../client/dbclient.h"
namespace mongo { namespace mongo {
extern const int MaxBytesToReturnToClientAtOnce; extern const int MaxBytesToReturnToClientAtOnce;
QueryResult* processGetMore(const char *ns, int ntoreturn, long long cu rsorid , CurOp& op, int pass, bool& exhaust); QueryResult* processGetMore(const char *ns, int ntoreturn, long long cu rsorid , CurOp& op, int pass, bool& exhaust);
long long runCount(const char *ns, const BSONObj& cmd, string& err);
const char * runQuery(Message& m, QueryMessage& q, CurOp& curop, Messag e &result); const char * runQuery(Message& m, QueryMessage& q, CurOp& curop, Messag e &result);
/* This is for languages whose "objects" are not well ordered (JSON is well ordered). /* This is for languages whose "objects" are not well ordered (JSON is well ordered).
[ { a : ... } , { b : ... } ] -> { a : ..., b : ... } [ { a : ... } , { b : ... } ] -> { a : ..., b : ... }
*/ */
inline BSONObj transformOrderFromArrayFormat(BSONObj order) { inline BSONObj transformOrderFromArrayFormat(BSONObj order) {
/* note: this is slow, but that is ok as order will have very few p ieces */ /* note: this is slow, but that is ok as order will have very few p ieces */
BSONObjBuilder b; BSONObjBuilder b;
char p[2] = "0"; char p[2] = "0";
 End of changes. 1 change blocks. 
2 lines changed or deleted 0 lines changed or added


 queryoptimizer.h   queryoptimizer.h 
skipping to change at line 52 skipping to change at line 52
int idxNo, // -1 = no index int idxNo, // -1 = no index
const FieldRangeSetPair &frsp, const FieldRangeSetPair &frsp,
const FieldRangeSetPair *originalFrsp, const FieldRangeSetPair *originalFrsp,
const BSONObj &originalQuery, const BSONObj &originalQuery,
const BSONObj &order, const BSONObj &order,
bool mustAssertOnYieldFailure = true, bool mustAssertOnYieldFailure = true,
const BSONObj &startKey = BSONObj(), const BSONObj &startKey = BSONObj(),
const BSONObj &endKey = BSONObj(), const BSONObj &endKey = BSONObj(),
string special="" ); string special="" );
/** @return true iff no other plans should be considered. */ /** @return true iff this plan cannot return any documents. */
bool impossible() const { return _impossible; }
/**
* @return true iff this plan should run as the only candidate plan
in the absence of an
* impossible plan.
*/
bool optimal() const { return _optimal; } bool optimal() const { return _optimal; }
/* @return true iff this plan should not be considered at all. */ /** @return true iff this plan should not be considered at all. */
bool unhelpful() const { return _unhelpful; } bool unhelpful() const { return _unhelpful; }
/** @return true iff ScanAndOrder processing will be required for r esult set. */ /** @return true iff ScanAndOrder processing will be required for r esult set. */
bool scanAndOrderRequired() const { return _scanAndOrderRequired; } bool scanAndOrderRequired() const { return _scanAndOrderRequired; }
/** /**
* @return true iff the index we are using has keys such that it ca n completely resolve the * @return true iff the index we are using has keys such that it ca n completely resolve the
* query expression to match by itself without ever checking the ma in object. * query expression to match by itself without ever checking the ma in object.
*/ */
bool exactKeyMatch() const { return _exactKeyMatch; } bool exactKeyMatch() const { return _exactKeyMatch; }
/** @return true iff this QueryPlan would perform an unindexed scan . */ /** @return true iff this QueryPlan would perform an unindexed scan . */
bool willScanTable() const { return _idxNo < 0 && !_impossible; } bool willScanTable() const { return _idxNo < 0 && !_impossible; }
/** @return 'special' attribute of the plan, which was either set e
xplicitly or generated from the index. */
const string &special() const { return _special; }
/** @return a new cursor based on this QueryPlan's index and FieldR angeSet. */ /** @return a new cursor based on this QueryPlan's index and FieldR angeSet. */
shared_ptr<Cursor> newCursor( const DiskLoc &startLoc = DiskLoc() , int numWanted=0 ) const; shared_ptr<Cursor> newCursor( const DiskLoc &startLoc = DiskLoc() , int numWanted=0 ) const;
/** @return a new reverse cursor if this is an unindexed plan. */ /** @return a new reverse cursor if this is an unindexed plan. */
shared_ptr<Cursor> newReverseCursor() const; shared_ptr<Cursor> newReverseCursor() const;
/** Register this plan as a winner for its QueryPattern, with speci fied 'nscanned'. */ /** Register this plan as a winner for its QueryPattern, with speci fied 'nscanned'. */
void registerSelf( long long nScanned ) const; void registerSelf( long long nScanned ) const;
int direction() const { return _direction; } int direction() const { return _direction; }
BSONObj indexKey() const; BSONObj indexKey() const;
skipping to change at line 88 skipping to change at line 95
NamespaceDetails *nsd() const { return _d; } NamespaceDetails *nsd() const { return _d; }
BSONObj originalQuery() const { return _originalQuery; } BSONObj originalQuery() const { return _originalQuery; }
BSONObj simplifiedQuery( const BSONObj& fields = BSONObj() ) const { return _frs.simplifiedQuery( fields ); } BSONObj simplifiedQuery( const BSONObj& fields = BSONObj() ) const { return _frs.simplifiedQuery( fields ); }
const FieldRange &range( const char *fieldName ) const { return _fr s.range( fieldName ); } const FieldRange &range( const char *fieldName ) const { return _fr s.range( fieldName ); }
shared_ptr<FieldRangeVector> originalFrv() const { return _original Frv; } shared_ptr<FieldRangeVector> originalFrv() const { return _original Frv; }
const FieldRangeSet &multikeyFrs() const { return _frsMulti; } const FieldRangeSet &multikeyFrs() const { return _frsMulti; }
bool mustAssertOnYieldFailure() const { return _mustAssertOnYieldFa ilure; } bool mustAssertOnYieldFailure() const { return _mustAssertOnYieldFa ilure; }
/** just for testing */ /** The following member functions are just for testing. */
shared_ptr<FieldRangeVector> frv() const { return _frv; } shared_ptr<FieldRangeVector> frv() const { return _frv; }
bool isMultiKey() const; bool isMultiKey() const;
private: private:
void checkTableScanAllowed() const;
void warnOnCappedIdTableScan() const;
NamespaceDetails * _d; NamespaceDetails * _d;
int _idxNo; int _idxNo;
const FieldRangeSet &_frs; const FieldRangeSet &_frs;
const FieldRangeSet &_frsMulti; const FieldRangeSet &_frsMulti;
const BSONObj &_originalQuery; const BSONObj &_originalQuery;
const BSONObj &_order; const BSONObj &_order;
const IndexDetails * _index; const IndexDetails * _index;
bool _optimal; bool _optimal;
bool _scanAndOrderRequired; bool _scanAndOrderRequired;
bool _exactKeyMatch; bool _exactKeyMatch;
skipping to change at line 293 skipping to change at line 303
} }
/** Initialize or iterate a runner generated from @param originalOp . */ /** Initialize or iterate a runner generated from @param originalOp . */
shared_ptr<QueryOp> nextOp( QueryOp &originalOp, bool retried = fal se ); shared_ptr<QueryOp> nextOp( QueryOp &originalOp, bool retried = fal se );
/** Yield the runner member. */ /** Yield the runner member. */
bool prepareToYield(); bool prepareToYield();
void recoverFromYield(); void recoverFromYield();
/** Clear the runner member. */
void clearRunner();
QueryPlanPtr firstPlan() const { return _plans[ 0 ]; } QueryPlanPtr firstPlan() const { return _plans[ 0 ]; }
/** @return metadata about cursors and index bounds for all plans, suitable for explain output. */ /** @return metadata about cursors and index bounds for all plans, suitable for explain output. */
BSONObj explain() const; BSONObj explain() const;
/** @return true iff a plan is selected based on previous success o f this plan. */ /** @return true iff a plan is selected based on previous success o f this plan. */
bool usingPrerecordedPlan() const { return _usingPrerecordedPlan; } bool usingCachedPlan() const { return _usingCachedPlan; }
/** @return a single plan that may work well for the specified quer y. */ /** @return a single plan that may work well for the specified quer y. */
QueryPlanPtr getBestGuess() const; QueryPlanPtr getBestGuess() const;
//for testing //for testing
const FieldRangeSetPair &frsp() const { return *_frsp; } const FieldRangeSetPair &frsp() const { return *_frsp; }
const FieldRangeSetPair *originalFrsp() const { return _originalFrs p.get(); } const FieldRangeSetPair *originalFrsp() const { return _originalFrs p.get(); }
bool modifiedKeys() const; bool modifiedKeys() const;
bool hasMultiKey() const; bool hasMultiKey() const;
private: private:
void addOtherPlans( bool checkFirst ); void addOtherPlans( bool checkFirst );
void addPlan( QueryPlanPtr plan, bool checkFirst ) { void addPlan( QueryPlanPtr plan, bool checkFirst ) {
if ( checkFirst && plan->indexKey().woCompare( _plans[ 0 ]->ind exKey() ) == 0 ) if ( checkFirst && plan->indexKey().woCompare( _plans[ 0 ]->ind exKey() ) == 0 )
return; return;
_plans.push_back( plan ); _plans.push_back( plan );
} }
void init(); void init();
void addHint( IndexDetails &id ); void addHint( IndexDetails &id );
void warnOnCappedIdTableScan() const;
class Runner { class Runner {
public: public:
Runner( QueryPlanSet &plans, QueryOp &op ); Runner( QueryPlanSet &plans, QueryOp &op );
/** /**
* Iterate interactively through candidate documents on all pla ns. * Iterate interactively through candidate documents on all pla ns.
* QueryOp objects are returned at each interleaved step. * QueryOp objects are returned at each interleaved step.
*/ */
/** @return a plan that has completed, otherwise an arbitrary p lan. */ /** @return a plan that has completed, otherwise an arbitrary p lan. */
skipping to change at line 369 skipping to change at line 381
}; };
our_priority_queue<OpHolder> _queue; our_priority_queue<OpHolder> _queue;
}; };
const char *_ns; const char *_ns;
BSONObj _originalQuery; BSONObj _originalQuery;
auto_ptr<FieldRangeSetPair> _frsp; auto_ptr<FieldRangeSetPair> _frsp;
auto_ptr<FieldRangeSetPair> _originalFrsp; auto_ptr<FieldRangeSetPair> _originalFrsp;
PlanSet _plans; PlanSet _plans;
bool _mayRecordPlan; bool _mayRecordPlan;
bool _usingPrerecordedPlan; bool _usingCachedPlan;
BSONObj _hint; BSONObj _hint;
BSONObj _order; BSONObj _order;
long long _oldNScanned; long long _oldNScanned;
bool _honorRecordedPlan; bool _honorRecordedPlan;
BSONObj _min; BSONObj _min;
BSONObj _max; BSONObj _max;
string _special; string _special;
bool _bestGuessOnly; bool _bestGuessOnly;
bool _mayYield; bool _mayYield;
ElapsedTracker _yieldSometimesTracker; ElapsedTracker _yieldSometimesTracker;
skipping to change at line 429 skipping to change at line 441
/** Initialize or iterate a runner generated from @param originalOp . */ /** Initialize or iterate a runner generated from @param originalOp . */
void initialOp( const shared_ptr<QueryOp> &originalOp ) { _baseOp = originalOp; } void initialOp( const shared_ptr<QueryOp> &originalOp ) { _baseOp = originalOp; }
shared_ptr<QueryOp> nextOp(); shared_ptr<QueryOp> nextOp();
/** Yield the runner member. */ /** Yield the runner member. */
bool prepareToYield(); bool prepareToYield();
void recoverFromYield(); void recoverFromYield();
/** Clear the runner member. */
void clearRunner();
int currentNPlans() const;
/** /**
* @return a single simple cursor if the scanner would run a single cursor * @return a single simple cursor if the scanner would run a single cursor
* for this query, otherwise return an empty shared_ptr. * for this query, otherwise return an empty shared_ptr.
*/ */
shared_ptr<Cursor> singleCursor() const; shared_ptr<Cursor> singleCursor() const;
/**
* @return the query plan that would be used if the scanner would r
un a single
* cursor for this query, otherwise 0. The returned plan is invali
d if this
* MultiPlanScanner is destroyed, hence we return a raw pointer.
*/
const QueryPlan *singlePlan() const;
/** @return true iff more $or clauses need to be scanned. */ /** @return true iff more $or clauses need to be scanned. */
bool mayRunMore() const { return _or ? ( !_tableScanned && !_org->o bool mayRunMore() const {
rFinished() ) : _i == 0; } return _or ? ( !_tableScanned && !_org->orRangesExhausted() ) :
_i == 0;
}
/** @return non-$or version of explain output. */ /** @return non-$or version of explain output. */
BSONObj oldExplain() const { assertNotOr(); return _currentQps->exp lain(); } BSONObj oldExplain() const { assertNotOr(); return _currentQps->exp lain(); }
/** @return true iff this is not a $or query and a plan is selected based on previous success of this plan. */ /** @return true iff this is not a $or query and a plan is selected based on previous success of this plan. */
bool usingPrerecordedPlan() const { return !_or && _currentQps->usi ngPrerecordedPlan(); } bool usingCachedPlan() const { return !_or && _currentQps->usingCac hedPlan(); }
/** Don't attempt to scan multiple plans, just use the best guess. */ /** Don't attempt to scan multiple plans, just use the best guess. */
void setBestGuessOnly() { _bestGuessOnly = true; } void setBestGuessOnly() { _bestGuessOnly = true; }
/** Yielding is allowed while running each QueryPlan. */ /** Yielding is allowed while running each QueryPlan. */
void mayYield( bool val ) { _mayYield = val; } void mayYield( bool val ) { _mayYield = val; }
bool modifiedKeys() const { return _currentQps->modifiedKeys(); } bool modifiedKeys() const { return _currentQps->modifiedKeys(); }
bool hasMultiKey() const { return _currentQps->hasMultiKey(); } bool hasMultiKey() const { return _currentQps->hasMultiKey(); }
private: private:
void assertNotOr() const { void assertNotOr() const {
massert( 13266, "not implemented for $or query", !_or ); massert( 13266, "not implemented for $or query", !_or );
} }
void assertMayRunMore() const { void assertMayRunMore() const {
massert( 13271, "can't run more ops", mayRunMore() ); massert( 13271, "can't run more ops", mayRunMore() );
} }
shared_ptr<QueryOp> nextOpBeginningClause(); shared_ptr<QueryOp> nextOpBeginningClause();
shared_ptr<QueryOp> nextOpHandleEndOfClause(); shared_ptr<QueryOp> nextOpHandleEndOfClause();
bool uselessOr( const BSONElement &hint ) const; bool uselessOr( const BSONElement &hint ) const;
const char * _ns; const string _ns;
bool _or; bool _or;
BSONObj _query; BSONObj _query;
shared_ptr<OrRangeGenerator> _org; // May be null in certain non $o r query cases. shared_ptr<OrRangeGenerator> _org; // May be null in certain non $o r query cases.
auto_ptr<QueryPlanSet> _currentQps; auto_ptr<QueryPlanSet> _currentQps;
int _i; int _i;
bool _honorRecordedPlan; bool _honorRecordedPlan;
bool _bestGuessOnly; bool _bestGuessOnly;
BSONObj _hint; BSONObj _hint;
bool _mayYield; bool _mayYield;
bool _tableScanned; bool _tableScanned;
skipping to change at line 482 skipping to change at line 508
/** Provides a cursor interface for certain limited uses of a MultiPlan Scanner. */ /** Provides a cursor interface for certain limited uses of a MultiPlan Scanner. */
class MultiCursor : public Cursor { class MultiCursor : public Cursor {
public: public:
class CursorOp : public QueryOp { class CursorOp : public QueryOp {
public: public:
CursorOp() {} CursorOp() {}
CursorOp( const QueryOp &other ) : QueryOp( other ) {} CursorOp( const QueryOp &other ) : QueryOp( other ) {}
virtual shared_ptr<Cursor> newCursor() const = 0; virtual shared_ptr<Cursor> newCursor() const = 0;
}; };
/** takes ownership of 'op' */ /** takes ownership of 'op' */
MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj &order, shared_ptr<CursorOp> op = shared_ptr<CursorOp>(), bool mayYield = f alse, bool hintIdElseNatural = false ); MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj &order, shared_ptr<CursorOp> op = shared_ptr<CursorOp>(), bool mayYield = f alse );
/** /**
* Used * Used
* 1. To handoff a query to a getMore() * 1. To handoff a query to a getMore()
* 2. To handoff a QueryOptimizerCursor * 2. To handoff a QueryOptimizerCursor
* @param nscanned is an optional initial value, if not supplied ns canned() * @param nscanned is an optional initial value, if not supplied ns canned()
* will always return -1 * will always return -1
*/ */
MultiCursor( auto_ptr<MultiPlanScanner> mps, const shared_ptr<Curso r> &c, const shared_ptr<CoveredIndexMatcher> &matcher, const QueryOp &op, l ong long nscanned = -1 ); MultiCursor( auto_ptr<MultiPlanScanner> mps, const shared_ptr<Curso r> &c, const shared_ptr<CoveredIndexMatcher> &matcher, const QueryOp &op, l ong long nscanned = -1 );
virtual bool ok() { return _c->ok(); } virtual bool ok() { return _c->ok(); }
skipping to change at line 518 skipping to change at line 544
virtual bool supportYields() { return _c->supportYields(); } virtual bool supportYields() { return _c->supportYields(); }
virtual BSONObj indexKeyPattern() { return _c->indexKeyPattern(); } virtual BSONObj indexKeyPattern() { return _c->indexKeyPattern(); }
/** /**
* with update we could potentially get the same document on multip le * with update we could potentially get the same document on multip le
* indexes, but update appears to already handle this with seenObje cts * indexes, but update appears to already handle this with seenObje cts
* so we don't have to do anything special here. * so we don't have to do anything special here.
*/ */
virtual bool getsetdup(DiskLoc loc) { return _c->getsetdup( loc ); } virtual bool getsetdup(DiskLoc loc) { return _c->getsetdup( loc ); }
virtual bool autoDedup() const { return _c->autoDedup(); }
virtual bool modifiedKeys() const { return _mps->modifiedKeys(); } virtual bool modifiedKeys() const { return _mps->modifiedKeys(); }
virtual bool isMultiKey() const { return _mps->hasMultiKey(); } virtual bool isMultiKey() const { return _mps->hasMultiKey(); }
virtual shared_ptr< CoveredIndexMatcher > matcherPtr() const { retu rn _matcher; } virtual shared_ptr< CoveredIndexMatcher > matcherPtr() const { retu rn _matcher; }
virtual CoveredIndexMatcher* matcher() const { return _matcher.get( ); } virtual CoveredIndexMatcher* matcher() const { return _matcher.get( ); }
virtual bool capped() const { return _c->capped(); }
/** return -1 if we're a getmore handoff */ /** return -1 if we're a getmore handoff */
virtual long long nscanned() { return _nscanned >= 0 ? _nscanned + _c->nscanned() : _nscanned; } virtual long long nscanned() { return _nscanned >= 0 ? _nscanned + _c->nscanned() : _nscanned; }
/** just for testing */ /** just for testing */
shared_ptr<Cursor> sub_c() const { return _c; } shared_ptr<Cursor> sub_c() const { return _c; }
private: private:
class NoOp : public CursorOp { class NoOp : public CursorOp {
public: public:
NoOp() {} NoOp() {}
NoOp( const QueryOp &other ) : CursorOp( other ) {} NoOp( const QueryOp &other ) : CursorOp( other ) {}
virtual void _init() { setComplete(); } virtual void _init() { setComplete(); }
virtual void next() {} virtual void next() {}
virtual bool mayRecordPlan() const { return false; } virtual bool mayRecordPlan() const { return false; }
virtual QueryOp *_createChild() const { return new NoOp(); } virtual QueryOp *_createChild() const { return new NoOp(); }
virtual shared_ptr<Cursor> newCursor() const { return qp().newC ursor(); } virtual shared_ptr<Cursor> newCursor() const { return qp().newC ursor(); }
virtual long long nscanned() { assert( false ); return 0; } virtual long long nscanned() { assert( false ); return 0; }
}; };
void nextClause(); void nextClause();
static BSONObj idElseNaturalHint( const char *ns );
shared_ptr<CursorOp> _op; shared_ptr<CursorOp> _op;
shared_ptr<Cursor> _c; shared_ptr<Cursor> _c;
BSONObj _hint;
BSONElement _hintElt;
auto_ptr<MultiPlanScanner> _mps; auto_ptr<MultiPlanScanner> _mps;
shared_ptr<CoveredIndexMatcher> _matcher; shared_ptr<CoveredIndexMatcher> _matcher;
long long _nscanned; long long _nscanned;
}; };
/** NOTE min, max, and keyPattern will be updated to be consistent with the selected index. */ /** NOTE min, max, and keyPattern will be updated to be consistent with the selected index. */
IndexDetails *indexDetailsForRange( const char *ns, string &errmsg, BSO NObj &min, BSONObj &max, BSONObj &keyPattern ); IndexDetails *indexDetailsForRange( const char *ns, string &errmsg, BSO NObj &min, BSONObj &max, BSONObj &keyPattern );
bool isSimpleIdQuery( const BSONObj& query );
/**
* @return a single cursor that may work well for the given query.
* It is possible no cursor is returned if the sort is not supported by
an index. Clients are responsible
* for checking this if they are not sure an index for a sort exists, a
nd defaulting to a non-sort if
* no suitable indices exist.
*/
shared_ptr<Cursor> bestGuessCursor( const char *ns, const BSONObj &quer
y, const BSONObj &sort );
/** /**
* Add-on functionality for queryutil classes requiring access to index ing * Add-on functionality for queryutil classes requiring access to index ing
* functionality not currently linked to mongos. * functionality not currently linked to mongos.
* TODO Clean this up a bit, possibly with separate sharded and non sha rded * TODO Clean this up a bit, possibly with separate sharded and non sha rded
* implementations for the appropriate queryutil classes or by pulling index * implementations for the appropriate queryutil classes or by pulling index
* related functionality into separate wrapper classes. * related functionality into separate wrapper classes.
*/ */
struct QueryUtilIndexed { struct QueryUtilIndexed {
/** @return true if the index may be useful according to its KeySpe c. */ /** @return true if the index may be useful according to its KeySpe c. */
static bool indexUseful( const FieldRangeSetPair &frsp, NamespaceDe tails *d, int idxNo, const BSONObj &order ); static bool indexUseful( const FieldRangeSetPair &frsp, NamespaceDe tails *d, int idxNo, const BSONObj &order );
 End of changes. 20 change blocks. 
27 lines changed or deleted 45 lines changed or added


 querypattern.h   querypattern.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 "jsobj.h" #include "jsobj.h"
#include "queryutil.h"
namespace mongo { namespace mongo {
/** /**
* Implements query pattern matching, used to determine if a query is * Implements query pattern matching, used to determine if a query is
* similar to an earlier query and should use the same plan. * similar to an earlier query and should use the same plan.
* *
* Two queries will generate the same QueryPattern, and therefore match each * Two queries will generate the same QueryPattern, and therefore match each
* other, if their fields have the same Types and they have the same so rt * other, if their fields have the same Types and they have the same so rt
* spec. * spec.
*/ */
class QueryPattern { class QueryPattern {
public: public:
friend class FieldRangeSet; QueryPattern( const FieldRangeSet &frs, const BSONObj &sort );
enum Type { enum Type {
Empty,
Equality, Equality,
LowerBound, LowerBound,
UpperBound, UpperBound,
UpperAndLowerBound, UpperAndLowerBound,
ConstraintPresent ConstraintPresent
}; };
bool operator<( const QueryPattern &other ) const; bool operator<( const QueryPattern &other ) const;
/** for testing only */ /** for testing only */
bool operator==( const QueryPattern &other ) const; bool operator==( const QueryPattern &other ) const;
/** for testing only */ /** for testing only */
bool operator!=( const QueryPattern &other ) const; bool operator!=( const QueryPattern &other ) const;
/** for development / debugging */
string toString() const;
private: private:
QueryPattern() {}
void setSort( const BSONObj sort ); void setSort( const BSONObj sort );
static BSONObj normalizeSort( const BSONObj &spec ); static BSONObj normalizeSort( const BSONObj &spec );
map<string,Type> _fieldTypes; map<string,Type> _fieldTypes;
BSONObj _sort; BSONObj _sort;
}; };
inline bool QueryPattern::operator<( const QueryPattern &other ) const { inline bool QueryPattern::operator<( const QueryPattern &other ) const {
map<string,Type>::const_iterator i = _fieldTypes.begin(); map<string,Type>::const_iterator i = _fieldTypes.begin();
map<string,Type>::const_iterator j = other._fieldTypes.begin(); map<string,Type>::const_iterator j = other._fieldTypes.begin();
while( i != _fieldTypes.end() ) { while( i != _fieldTypes.end() ) {
 End of changes. 5 change blocks. 
2 lines changed or deleted 5 lines changed or added


 queryutil-inl.h   queryutil-inl.h 
skipping to change at line 24 skipping to change at line 24
* 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.
*/ */
namespace mongo { namespace mongo {
inline bool FieldInterval::equality() const { inline bool FieldInterval::equality() const {
if ( _cachedEquality == -1 ) { if ( _cachedEquality == -1 ) {
_cachedEquality = ( _lower._inclusive && _upper._inclusive && _ lower._bound.woCompare( _upper._bound, false ) == 0 ); _cachedEquality = ( _lower._inclusive && _upper._inclusive && _ lower._bound.woCompare( _upper._bound, false ) == 0 );
} }
return _cachedEquality; return _cachedEquality != 0;
} }
inline bool FieldRange::equality() const { inline bool FieldRange::equality() const {
return return
!empty() && !empty() &&
min().woCompare( max(), false ) == 0 && min().woCompare( max(), false ) == 0 &&
maxInclusive() && maxInclusive() &&
minInclusive(); minInclusive();
} }
skipping to change at line 47 skipping to change at line 47
return true; return true;
} }
for( vector<FieldInterval>::const_iterator i = _intervals.begin(); i != _intervals.end(); ++i ) { for( vector<FieldInterval>::const_iterator i = _intervals.begin(); i != _intervals.end(); ++i ) {
if ( !i->equality() ) { if ( !i->equality() ) {
return false; return false;
} }
} }
return true; return true;
} }
/**
* TODO Assumes intervals are contiguous and minKey/maxKey will not be
* matched against.
*/
inline bool FieldRange::nontrivial() const {
return
! empty() &&
( _intervals.size() != 1 ||
minKey.firstElement().woCompare( min(), false ) != 0 ||
maxKey.firstElement().woCompare( max(), false ) != 0 );
}
inline const FieldRange &FieldRangeSet::range( const char *fieldName ) const { inline const FieldRange &FieldRangeSet::range( const char *fieldName ) const {
map<string,FieldRange>::const_iterator f = _ranges.find( fieldName ); map<string,FieldRange>::const_iterator f = _ranges.find( fieldName );
if ( f == _ranges.end() ) if ( f == _ranges.end() )
return trivialRange(); return universalRange();
return f->second; return f->second;
} }
inline FieldRange &FieldRangeSet::range( const char *fieldName ) { inline FieldRange &FieldRangeSet::range( const char *fieldName ) {
map<string,FieldRange>::iterator f = _ranges.find( fieldName ); map<string,FieldRange>::iterator f = _ranges.find( fieldName );
if ( f == _ranges.end() ) { if ( f == _ranges.end() ) {
_ranges.insert( make_pair( string( fieldName ), trivialRange() ) ); _ranges.insert( make_pair( string( fieldName ), universalRange( ) ) );
return _ranges.find( fieldName )->second; return _ranges.find( fieldName )->second;
} }
return f->second; return f->second;
} }
inline int FieldRangeSet::nNontrivialRanges() const {
int count = 0;
for( map<string,FieldRange>::const_iterator i = _ranges.begin(); i
!= _ranges.end(); ++i ) {
if ( i->second.nontrivial() )
++count;
}
return count;
}
inline bool FieldRangeSet::matchPossible() const { inline bool FieldRangeSet::matchPossible() const {
for( map<string,FieldRange>::const_iterator i = _ranges.begin(); i != _ranges.end(); ++i ) { for( map<string,FieldRange>::const_iterator i = _ranges.begin(); i != _ranges.end(); ++i ) {
if ( i->second.empty() ) { if ( i->second.empty() ) {
return false; return false;
} }
} }
return true; return true;
} }
inline bool FieldRangeSet::matchPossibleForIndex( const BSONObj &keyPat tern ) const { inline bool FieldRangeSet::matchPossibleForIndex( const BSONObj &keyPat tern ) const {
 End of changes. 5 change blocks. 
25 lines changed or deleted 3 lines changed or added


 queryutil.h   queryutil.h 
skipping to change at line 91 skipping to change at line 91
BSONElement min() const { assert( !empty() ); return _intervals[ 0 ]._lower._bound; } BSONElement min() const { assert( !empty() ); return _intervals[ 0 ]._lower._bound; }
BSONElement max() const { assert( !empty() ); return _intervals[ _i ntervals.size() - 1 ]._upper._bound; } BSONElement max() const { assert( !empty() ); return _intervals[ _i ntervals.size() - 1 ]._upper._bound; }
bool minInclusive() const { assert( !empty() ); return _intervals[ 0 ]._lower._inclusive; } bool minInclusive() const { assert( !empty() ); return _intervals[ 0 ]._lower._inclusive; }
bool maxInclusive() const { assert( !empty() ); return _intervals[ _intervals.size() - 1 ]._upper._inclusive; } bool maxInclusive() const { assert( !empty() ); return _intervals[ _intervals.size() - 1 ]._upper._inclusive; }
/** @return true iff this range expresses a single equality interva l. */ /** @return true iff this range expresses a single equality interva l. */
bool equality() const; bool equality() const;
/** @return true if all the intervals for this range are equalities */ /** @return true if all the intervals for this range are equalities */
bool inQuery() const; bool inQuery() const;
/** @return true iff this range does not include every BSONElement /**
*/ * @return true iff this range includes all BSONElements
bool nontrivial() const; * (the range is the universal set of BSONElements).
/** @return true iff this range matches no BSONElements. */ */
bool universal() const;
/** @return true iff this range includes no BSONElements. */
bool empty() const { return _intervals.empty(); } bool empty() const { return _intervals.empty(); }
/** Empty the range so it matches no BSONElements. */ /** Empty the range so it includes no BSONElements. */
void makeEmpty() { _intervals.clear(); } void makeEmpty() { _intervals.clear(); }
const vector<FieldInterval> &intervals() const { return _intervals; } const vector<FieldInterval> &intervals() const { return _intervals; }
string getSpecial() const { return _special; } string getSpecial() const { return _special; }
/** Make component intervals noninclusive. */ /** Make component intervals noninclusive. */
void setExclusiveBounds(); void setExclusiveBounds();
/** /**
* Constructs a range where all FieldIntervals and FieldBounds are in * Constructs a range where all FieldIntervals and FieldBounds are in
* the opposite order of the current range. * the opposite order of the current range.
* NOTE the resulting intervals might not be strictValid(). * NOTE the resulting intervals might not be strictValid().
*/ */
skipping to change at line 141 skipping to change at line 144
/** /**
* A set of FieldRanges determined from constraints on the fields of a query, * A set of FieldRanges determined from constraints on the fields of a query,
* that may be used to determine index bounds. * that may be used to determine index bounds.
*/ */
class FieldRangeSet { class FieldRangeSet {
public: public:
friend class OrRangeGenerator; friend class OrRangeGenerator;
friend class FieldRangeVector; friend class FieldRangeVector;
FieldRangeSet( const char *ns, const BSONObj &query , bool singleKe y , bool optimize=true ); FieldRangeSet( const char *ns, const BSONObj &query , bool singleKe y , bool optimize=true );
/** @return true if there is a nontrivial range for the given field
. */
bool hasRange( const char *fieldName ) const {
map<string, FieldRange>::const_iterator f = _ranges.find( field
Name );
return f != _ranges.end();
}
/** @return range for the given field. */ /** @return range for the given field. */
const FieldRange &range( const char *fieldName ) const; const FieldRange &range( const char *fieldName ) const;
/** @return range for the given field. */ /** @return range for the given field. */
FieldRange &range( const char *fieldName ); FieldRange &range( const char *fieldName );
/** @return the number of nontrivial ranges. */ /** @return the number of non universal ranges. */
int nNontrivialRanges() const; int numNonUniversalRanges() const;
/** @return the field ranges comprising this set. */
const map<string,FieldRange> &ranges() const { return _ranges; }
/** /**
* @return true if a match could be possible on every field. Genera lly this * @return true if a match could be possible on every field. Genera lly this
* is not useful information for a single key FieldRangeSet and * is not useful information for a single key FieldRangeSet and
* matchPossibleForIndex() should be used instead. * matchPossibleForIndex() should be used instead.
*/ */
bool matchPossible() const; bool matchPossible() const;
/** /**
* @return true if a match could be possible given the value of _si ngleKey * @return true if a match could be possible given the value of _si ngleKey
* and index key 'keyPattern'. * and index key 'keyPattern'.
* @param keyPattern May be {} or {$natural:1} for a non index scan . * @param keyPattern May be {} or {$natural:1} for a non index scan .
*/ */
bool matchPossibleForIndex( const BSONObj &keyPattern ) const; bool matchPossibleForIndex( const BSONObj &keyPattern ) const;
const char *ns() const { return _ns; } const char *ns() const { return _ns; }
/** /**
* @return a simplified query from the extreme values of the nontri vial * @return a simplified query from the extreme values of the non un iversal
* fields. * fields.
* @param fields If specified, the fields of the returned object ar e * @param fields If specified, the fields of the returned object ar e
* ordered to match those of 'fields'. * ordered to match those of 'fields'.
*/ */
BSONObj simplifiedQuery( const BSONObj &fields = BSONObj() ) const; BSONObj simplifiedQuery( const BSONObj &fields = BSONObj() ) const;
QueryPattern pattern( const BSONObj &sort = BSONObj() ) const; QueryPattern pattern( const BSONObj &sort = BSONObj() ) const;
string getSpecial() const; string getSpecial() const;
/** /**
skipping to change at line 191 skipping to change at line 191
* in 'this' but not 'other'. * in 'this' but not 'other'.
*/ */
const FieldRangeSet &operator-=( const FieldRangeSet &other ); const FieldRangeSet &operator-=( const FieldRangeSet &other );
/** @return intersection of 'this' with 'other'. */ /** @return intersection of 'this' with 'other'. */
const FieldRangeSet &operator&=( const FieldRangeSet &other ); const FieldRangeSet &operator&=( const FieldRangeSet &other );
/** /**
* @return an ordered list of bounds generated using an index key p attern * @return an ordered list of bounds generated using an index key p attern
* and traversal direction. * and traversal direction.
* *
* The value of matchPossible() should be true, otherwise this func
tion
* may @throw.
*
* NOTE This function is deprecated in the query optimizer and only * NOTE This function is deprecated in the query optimizer and only
* currently used by the sharding code. * currently used by sharding code.
*/ */
BoundList indexBounds( const BSONObj &keyPattern, int direction ) c onst; BoundList indexBounds( const BSONObj &keyPattern, int direction ) c onst;
/** /**
* @return - A new FieldRangeSet based on this FieldRangeSet, but w ith only * @return - A new FieldRangeSet based on this FieldRangeSet, but w ith only
* a subset of the fields. * a subset of the fields.
* @param fields - Only fields which are represented as field names in this object * @param fields - Only fields which are represented as field names in this object
* will be included in the returned FieldRangeSet. * will be included in the returned FieldRangeSet.
*/ */
FieldRangeSet *subset( const BSONObj &fields ) const; FieldRangeSet *subset( const BSONObj &fields ) const;
bool singleKey() const { return _singleKey; } bool singleKey() const { return _singleKey; }
BSONObj originalQuery() const { return _queries[ 0 ]; } BSONObj originalQuery() const { return _queries[ 0 ]; }
private: private:
void appendQueries( const FieldRangeSet &other ); void appendQueries( const FieldRangeSet &other );
void makeEmpty(); void makeEmpty();
void processQueryField( const BSONElement &e, bool optimize ); void processQueryField( const BSONElement &e, bool optimize );
void processOpElement( const char *fieldName, const BSONElement &f, bool isNot, bool optimize ); void processOpElement( const char *fieldName, const BSONElement &f, bool isNot, bool optimize );
static FieldRange *__singleKeyTrivialRange; static FieldRange *__singleKeyUniversalRange;
static FieldRange *__multiKeyTrivialRange; static FieldRange *__multiKeyUniversalRange;
const FieldRange &trivialRange() const; const FieldRange &universalRange() const;
map<string,FieldRange> _ranges; map<string,FieldRange> _ranges;
const char *_ns; const char *_ns;
// Owns memory for FieldRange BSONElements. // Owns memory for FieldRange BSONElements.
vector<BSONObj> _queries; vector<BSONObj> _queries;
bool _singleKey; bool _singleKey;
}; };
class NamespaceDetails; class NamespaceDetails;
/** /**
skipping to change at line 248 skipping to change at line 251
* @return the appropriate single or multi key FieldRangeSet for th e specified index. * @return the appropriate single or multi key FieldRangeSet for th e specified index.
* @param idxNo -1 for non index scan. * @param idxNo -1 for non index scan.
*/ */
const FieldRangeSet &frsForIndex( const NamespaceDetails* nsd, int idxNo ) const; const FieldRangeSet &frsForIndex( const NamespaceDetails* nsd, int idxNo ) const;
/** @return a field range in the single key FieldRangeSet. */ /** @return a field range in the single key FieldRangeSet. */
const FieldRange &singleKeyRange( const char *fieldName ) const { const FieldRange &singleKeyRange( const char *fieldName ) const {
return _singleKey.range( fieldName ); return _singleKey.range( fieldName );
} }
/** @return true if the range limits are equivalent to an empty que ry. */ /** @return true if the range limits are equivalent to an empty que ry. */
bool noNontrivialRanges() const; bool noNonUniversalRanges() const;
/** @return false if a match is impossible regardless of index. */ /** @return false if a match is impossible regardless of index. */
bool matchPossible() const { return _multiKey.matchPossible(); } bool matchPossible() const { return _multiKey.matchPossible(); }
/** /**
* @return false if a match is impossible on the specified index. * @return false if a match is impossible on the specified index.
* @param idxNo -1 for non index scan. * @param idxNo -1 for non index scan.
*/ */
bool matchPossibleForIndex( NamespaceDetails *d, int idxNo, const B SONObj &keyPattern ) const; bool matchPossibleForIndex( NamespaceDetails *d, int idxNo, const B SONObj &keyPattern ) const;
const char *ns() const { return _singleKey.ns(); } const char *ns() const { return _singleKey.ns(); }
skipping to change at line 291 skipping to change at line 294
BSONObj simplifiedQueryForIndex( NamespaceDetails *d, int idxNo, co nst BSONObj &keyPattern ) const; BSONObj simplifiedQueryForIndex( NamespaceDetails *d, int idxNo, co nst BSONObj &keyPattern ) const;
FieldRangeSet _singleKey; FieldRangeSet _singleKey;
FieldRangeSet _multiKey; FieldRangeSet _multiKey;
friend class OrRangeGenerator; friend class OrRangeGenerator;
friend struct QueryUtilIndexed; friend struct QueryUtilIndexed;
}; };
class IndexSpec; class IndexSpec;
/** /**
* An ordered list of fields and their FieldRanges, correspoinding to v alid * An ordered list of fields and their FieldRanges, corresponding to va lid
* index keys for a given index spec. * index keys for a given index spec.
*/ */
class FieldRangeVector { class FieldRangeVector {
public: public:
/** /**
* @param frs The valid ranges for all fields, as defined by the qu * @param frs The valid ranges for all fields, as defined by the qu
ery spec ery spec. None of the
* fields in indexSpec may be empty() ranges of frs.
* @param indexSpec The index spec (key pattern and info) * @param indexSpec The index spec (key pattern and info)
* @param direction The direction of index traversal * @param direction The direction of index traversal
*/ */
FieldRangeVector( const FieldRangeSet &frs, const IndexSpec &indexS pec, int direction ); FieldRangeVector( const FieldRangeSet &frs, const IndexSpec &indexS pec, int direction );
/** @return the number of index ranges represented by 'this' */ /** @return the number of index ranges represented by 'this' */
long long size(); long long size();
/** @return starting point for an index traversal. */ /** @return starting point for an index traversal. */
BSONObj startKey() const; BSONObj startKey() const;
/** @return end point for an index traversal. */ /** @return end point for an index traversal. */
BSONObj endKey() const; BSONObj endKey() const;
/** @return a client readable representation of 'this' */ /** @return a client readable representation of 'this' */
BSONObj obj() const; BSONObj obj() const;
const IndexSpec& getSpec(){ return _indexSpec; }
/** /**
* @return true iff the provided document matches valid ranges on a ll * @return true iff the provided document matches valid ranges on a ll
* of this FieldRangeVector's fields, which is the case iff this do cument * of this FieldRangeVector's fields, which is the case iff this do cument
* would be returned while scanning the index corresponding to this * would be returned while scanning the index corresponding to this
* FieldRangeVector. This function is used for $or clause deduping . * FieldRangeVector. This function is used for $or clause deduping .
*/ */
bool matches( const BSONObj &obj ) const; bool matches( const BSONObj &obj ) const;
/** /**
* @return first key of 'obj' that would be encountered by a forwar d * @return first key of 'obj' that would be encountered by a forwar d
* index scan using this FieldRangeVector, BSONObj() if no such key . * index scan using this FieldRangeVector, BSONObj() if no such key .
*/ */
BSONObj firstMatch( const BSONObj &obj ) const; BSONObj firstMatch( const BSONObj &obj ) const;
private: private:
int matchingLowElement( const BSONElement &e, int i, bool direction , bool &lowEquality ) const; int matchingLowElement( const BSONElement &e, int i, bool direction , bool &lowEquality ) const;
bool matchesElement( const BSONElement &e, int i, bool direction ) const; bool matchesElement( const BSONElement &e, int i, bool direction ) const;
bool matchesKey( const BSONObj &key ) const; bool matchesKey( const BSONObj &key ) const;
vector<FieldRange> _ranges; vector<FieldRange> _ranges;
IndexSpec _indexSpec; const IndexSpec _indexSpec;
int _direction; int _direction;
vector<BSONObj> _queries; // make sure mem owned vector<BSONObj> _queries; // make sure mem owned
friend class FieldRangeVectorIterator; friend class FieldRangeVectorIterator;
}; };
/** /**
* Helper class for iterating through an ordered representation of keys * Helper class for iterating through an ordered representation of keys
* to find those keys that match a specified FieldRangeVector. * to find those keys that match a specified FieldRangeVector.
*/ */
class FieldRangeVectorIterator { class FieldRangeVectorIterator {
skipping to change at line 391 skipping to change at line 397
/** /**
* As we iterate through $or clauses this class generates a FieldRangeS etPair * As we iterate through $or clauses this class generates a FieldRangeS etPair
* for the current $or clause, in some cases by excluding ranges that w ere * for the current $or clause, in some cases by excluding ranges that w ere
* included in a previous clause. * included in a previous clause.
*/ */
class OrRangeGenerator { class OrRangeGenerator {
public: public:
OrRangeGenerator( const char *ns, const BSONObj &query , bool optim ize=true ); OrRangeGenerator( const char *ns, const BSONObj &query , bool optim ize=true );
/** /** @return true iff we are done scanning $or clauses, or if there
* @return true iff we are done scanning $or clauses. if there's a are no $or clauses. */
* useless or clause, we won't use or index ranges to help with sca bool orRangesExhausted() const { return _orSets.empty(); }
nning.
*/
bool orFinished() const { return _orFound && _orSets.empty(); }
/** Iterates to the next $or clause by removing the current $or cla use. */ /** Iterates to the next $or clause by removing the current $or cla use. */
void popOrClause( NamespaceDetails *nsd, int idxNo, const BSONObj & keyPattern ); void popOrClause( NamespaceDetails *nsd, int idxNo, const BSONObj & keyPattern );
void popOrClauseSingleKey(); void popOrClauseSingleKey();
/** @return FieldRangeSetPair for the current $or clause. */ /** @return FieldRangeSetPair for the current $or clause. */
FieldRangeSetPair *topFrsp() const; FieldRangeSetPair *topFrsp() const;
/** /**
* @return original FieldRangeSetPair for the current $or clause. W hile the * @return original FieldRangeSetPair for the current $or clause. W hile the
* original bounds are looser, they are composed of fewer ranges an d it * original bounds are looser, they are composed of fewer ranges an d it
* is faster to do operations with them; when they can be used inst ead of * is faster to do operations with them; when they can be used inst ead of
* more precise bounds, they should. * more precise bounds, they should.
*/ */
FieldRangeSetPair *topFrspOriginal() const; FieldRangeSetPair *topFrspOriginal() const;
string getSpecial() const { return _baseSet.getSpecial(); } string getSpecial() const { return _baseSet.getSpecial(); }
bool moreOrClauses() const { return !_orSets.empty(); }
private: private:
void assertMayPopOrClause(); void assertMayPopOrClause();
void popOrClause( const FieldRangeSet *toDiff, NamespaceDetails *d = 0, int idxNo = -1, const BSONObj &keyPattern = BSONObj() ); void _popOrClause( const FieldRangeSet *toDiff, NamespaceDetails *d , int idxNo, const BSONObj &keyPattern );
FieldRangeSetPair _baseSet; FieldRangeSetPair _baseSet;
list<FieldRangeSetPair> _orSets; list<FieldRangeSetPair> _orSets;
list<FieldRangeSetPair> _originalOrSets; list<FieldRangeSetPair> _originalOrSets;
// ensure memory is owned // ensure memory is owned
list<FieldRangeSetPair> _oldOrSets; list<FieldRangeSetPair> _oldOrSets;
bool _orFound; bool _orFound;
friend struct QueryUtilIndexed; friend struct QueryUtilIndexed;
}; };
/** returns a string that when used as a matcher, would match a super s et of regex() /** returns a string that when used as a matcher, would match a super s et of regex()
skipping to change at line 437 skipping to change at line 438
if purePrefix != NULL, sets it to whether the regex can be converte d to a range query if purePrefix != NULL, sets it to whether the regex can be converte d to a range query
*/ */
string simpleRegex(const char* regex, const char* flags, bool* purePref ix=NULL); string simpleRegex(const char* regex, const char* flags, bool* purePref ix=NULL);
/** returns the upper bound of a query that matches prefix */ /** returns the upper bound of a query that matches prefix */
string simpleRegexEnd( string prefix ); string simpleRegexEnd( string prefix );
long long applySkipLimit( long long num , const BSONObj& cmd ); long long applySkipLimit( long long num , const BSONObj& cmd );
bool isSimpleIdQuery( const BSONObj& query );
} // namespace mongo } // namespace mongo
#include "queryutil-inl.h" #include "queryutil-inl.h"
 End of changes. 17 change blocks. 
33 lines changed or deleted 34 lines changed or added


 race.h   race.h 
#pragma once #pragma once
#include "../goodies.h" // printStackTrace #include "../goodies.h" // printStackTrace
#include "mutexdebugger.h"
namespace mongo { namespace mongo {
/** some self-testing of synchronization and attempts to catch race con namespace race {
ditions.
use something like:
CodeBlock myBlock;
void foo() {
CodeBlock::Within w(myBlock);
...
}
In _DEBUG builds, will (sometimes/maybe) fail if two threads are in
the same code block at
the same time. Also detects and disallows recursion.
*/
#ifdef _WIN32 #ifdef _WIN32
typedef unsigned threadId_t; typedef unsigned threadId_t;
#else #else
typedef pthread_t threadId_t; typedef pthread_t threadId_t;
#endif #endif
#if defined(_DEBUG) #if defined(_DEBUG)
namespace race { class Block {
volatile int n;
class CodePoint { unsigned ncalls;
public: const string file;
string lastName; const unsigned line;
threadId_t lastTid; void fail() {
string file; log() << "\n\n\nrace: synchronization (race condition) fail
CodePoint(string f) : lastTid(0), file(f) { } ure\ncurrent locks this thread (" << getThreadName() << "):\n"
}; << mutexDebugger.currentlyLocked() << endl;
class Check { printStackTrace();
public: ::abort();
Check(CodePoint& p) { }
threadId_t t = GetCurrentThreadId(); void enter() {
if( p.lastTid == 0 ) { if( ++n != 1 ) fail();
p.lastTid = t; ncalls++;
p.lastName = getThreadName(); if( ncalls < 100 ) {
sleepmillis(0);
} }
else if( t != p.lastTid ) { else {
log() << "\n\n\n\n\nRACE? error assert\n " << p.file < RARELY {
< '\n' sleepmillis(0);
<< " " << p.lastName if( ncalls < 128 * 20 ) {
<< " " << getThreadName() << "\n\n" << endl; OCCASIONALLY {
mongoAbort("racecheck"); sleepmillis(3);
}
}
}
} }
}; }
}; void leave() {
if( --n != 0 ) fail();
} }
#define RACECHECK
// dm TODO - the right code for this file is in a different branch
at the moment (merge)
//#define RACECHECK
//static race::CodePoint __cp(__FILE__);
//race::Check __ck(__cp);
class CodeBlock {
volatile int n;
threadId_t tid;
void fail() {
log() << "synchronization (race condition) failure" << endl;
printStackTrace();
::abort();
}
void enter() {
if( ++n != 1 ) fail();
#if defined(_WIN32)
tid = GetCurrentThreadId();
#endif
}
void leave() {
if( --n != 0 ) fail();
}
public:
CodeBlock() : n(0) { }
class Within {
CodeBlock& _s;
public: public:
Within(CodeBlock& s) : _s(s) { _s.enter(); } Block(string f, unsigned l) : n(0), ncalls(0), file(f), line(l)
~Within() { _s.leave(); } { }
~Block() {
if( ncalls > 1000000 ) {
// just so we know if we are slowing things down
log() << "race::Block lots of calls " << file << ' ' <<
line << " n:" << ncalls << endl;
}
}
class Within {
Block& _s;
public:
Within(Block& s) : _s(s) { _s.enter(); }
~Within() { _s.leave(); }
};
}; };
void assertWithin() { /* in a rwlock situation this will fail, so not appropriate for thi
assert( n == 1 ); ngs like that. */
#if defined(_WIN32) # define RACECHECK \
assert( GetCurrentThreadId() == tid ); static race::Block __cp(__FILE__, __LINE__); \
#endif race::Block::Within __ck(__cp);
}
};
#else #else
/* !_DEBUG */
#define RACECHECK # define RACECHECK
class CodeBlock{
public:
class Within {
public:
Within(CodeBlock&) { }
};
void assertWithin() { }
};
#endif #endif
} // namespace }
}
 End of changes. 9 change blocks. 
92 lines changed or deleted 54 lines changed or added


 redef_macros.h   redef_macros.h 
/** @file redef_macros.h macros for mongo internals /** @file redef_macros.h macros the implementation uses.
@see undef_macros.h undefines these after use to minimize name pollutio n. @see undef_macros.h undefines these after use to minimize name pollutio n.
*/ */
/* Copyright 2009 10gen Inc. /* Copyright 2009 10gen Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
skipping to change at line 23 skipping to change at line 23
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
// If you define a new global un-prefixed macro, please add it here and in undef_macros // If you define a new global un-prefixed macro, please add it here and in undef_macros
#define MONGO_MACROS_PUSHED 1 // #pragma once // this file is intended to be processed multiple times
#if defined(MONGO_MACROS_CLEANED)
// util/allocator.h // util/allocator.h
#pragma push_macro("malloc")
#undef malloc
#define malloc MONGO_malloc #define malloc MONGO_malloc
#pragma push_macro("realloc")
#undef realloc
#define realloc MONGO_realloc #define realloc MONGO_realloc
// util/assert_util.h // util/assert_util.h
#pragma push_macro("assert")
#undef assert
#define assert MONGO_assert #define assert MONGO_assert
#pragma push_macro("verify")
#undef verify
#define verify MONGO_verify
#pragma push_macro("dassert")
#undef dassert
#define dassert MONGO_dassert #define dassert MONGO_dassert
#pragma push_macro("wassert")
#undef wassert
#define wassert MONGO_wassert #define wassert MONGO_wassert
#pragma push_macro("massert")
#undef massert
#define massert MONGO_massert #define massert MONGO_massert
#pragma push_macro("uassert")
#undef uassert
#define uassert MONGO_uassert #define uassert MONGO_uassert
#define BOOST_CHECK_EXCEPTION MONGO_BOOST_CHECK_EXCEPTION #define BOOST_CHECK_EXCEPTION MONGO_BOOST_CHECK_EXCEPTION
#pragma push_macro("DESTRUCTOR_GUARD")
#undef DESTRUCTOR_GUARD
#define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD #define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD
// util/goodies.h // util/goodies.h
#pragma push_macro("PRINT")
#undef PRINT
#define PRINT MONGO_PRINT #define PRINT MONGO_PRINT
#pragma push_macro("PRINTFL")
#undef PRINTFL
#define PRINTFL MONGO_PRINTFL #define PRINTFL MONGO_PRINTFL
#pragma push_macro("asctime")
#undef asctime
#define asctime MONGO_asctime #define asctime MONGO_asctime
#pragma push_macro("gmtime")
#undef gmtime
#define gmtime MONGO_gmtime #define gmtime MONGO_gmtime
#pragma push_macro("localtime")
#undef localtime
#define localtime MONGO_localtime #define localtime MONGO_localtime
#pragma push_macro("ctime")
#undef ctime
#define ctime MONGO_ctime #define ctime MONGO_ctime
// util/debug_util.h // util/debug_util.h
#pragma push_macro("DEV")
#undef DEV
#define DEV MONGO_DEV #define DEV MONGO_DEV
#pragma push_macro("DEBUGGING")
#undef DEBUGGING
#define DEBUGGING MONGO_DEBUGGING #define DEBUGGING MONGO_DEBUGGING
#pragma push_macro("SOMETIMES")
#undef SOMETIMES
#define SOMETIMES MONGO_SOMETIMES #define SOMETIMES MONGO_SOMETIMES
#pragma push_macro("OCCASIONALLY")
#undef OCCASIONALLY
#define OCCASIONALLY MONGO_OCCASIONALLY #define OCCASIONALLY MONGO_OCCASIONALLY
#pragma push_macro("RARELY")
#undef RARELY
#define RARELY MONGO_RARELY #define RARELY MONGO_RARELY
#pragma push_macro("ONCE")
#undef ONCE
#define ONCE MONGO_ONCE #define ONCE MONGO_ONCE
// util/log.h // util/log.h
#pragma push_macro("LOG")
#undef LOG
#define LOG MONGO_LOG #define LOG MONGO_LOG
#undef MONGO_MACROS_CLEANED
#endif
 End of changes. 24 change blocks. 
47 lines changed or deleted 4 lines changed or added


 repl.h   repl.h 
skipping to change at line 61 skipping to change at line 61
/** true means we are master and doing replication. if we are not writing to oplog, this won't be true. */ /** true means we are master and doing replication. if we are not writing to oplog, this won't be true. */
bool master; bool master;
bool fastsync; bool fastsync;
bool autoresync; bool autoresync;
int slavedelay; int slavedelay;
set<string> discoveredSeeds; set<string> discoveredSeeds;
mutex discoveredSeeds_mx;
BSONObj reconfig; BSONObj reconfig;
ReplSettings() ReplSettings()
: slave(NotSlave) , master(false) , fastsync() , autoresync(fal : slave(NotSlave),
se), slavedelay(), discoveredSeeds() { master(false),
fastsync(),
autoresync(false),
slavedelay(),
discoveredSeeds(),
discoveredSeeds_mx("ReplSettings::discoveredSeeds") {
} }
}; };
extern ReplSettings replSettings; extern ReplSettings replSettings;
/* A replication exception */ /* A replication exception */
class SyncException : public DBException { class SyncException : public DBException {
public: public:
SyncException() : DBException( "sync exception" , 10001 ) {} SyncException() : DBException( "sync exception" , 10001 ) {}
 End of changes. 2 change blocks. 
2 lines changed or deleted 9 lines changed or added


 replutil.h   replutil.h 
skipping to change at line 64 skipping to change at line 64
if( replSettings.master ) { if( replSettings.master ) {
// if running with --master --slave, allow. // if running with --master --slave, allow.
return true; return true;
} }
if ( cc().isGod() ) if ( cc().isGod() )
return true; return true;
return false; return false;
} }
inline bool isMaster(const char *client = 0) { inline bool isMaster(const char * dbname = 0) {
if( _isMaster() ) if( _isMaster() )
return true; return true;
if ( !client ) { if ( ! dbname ) {
Database *database = cc().database(); Database *database = cc().database();
assert( database ); assert( database );
client = database->name.c_str(); dbname = database->name.c_str();
} }
return strcmp( client, "local" ) == 0; return strcmp( dbname , "local" ) == 0;
}
inline bool isMasterNs( const char *ns ) {
if ( _isMaster() )
return true;
assert( ns );
if ( ! str::startsWith( ns , "local" ) )
return false;
return ns[5] == 0 || ns[5] == '.';
} }
inline void notMasterUnless(bool expr) { inline void notMasterUnless(bool expr) {
uassert( 10107 , "not master" , expr ); uassert( 10107 , "not master" , expr );
} }
/** we allow queries to SimpleSlave's */ /** we allow queries to SimpleSlave's */
inline void replVerifyReadsOk(ParsedQuery& pq) { inline void replVerifyReadsOk(ParsedQuery& pq) {
if( replSet ) { if( replSet ) {
/* todo: speed up the secondary case. as written here there ar e 2 mutex entries, it can b 1. */ /* todo: speed up the secondary case. as written here there ar e 2 mutex entries, it can b 1. */
if( isMaster() ) return; if( isMaster() ) return;
uassert(13435, "not master and slaveok=false", pq.hasOption(Que uassert(13435, "not master and slaveOk=false", pq.hasOption(Que
ryOption_SlaveOk)); ryOption_SlaveOk));
uassert(13436, "not master or secondary, can't read", theReplSe uassert(13436, "not master or secondary; cannot currently read
t && theReplSet->isSecondary() ); from this replSet member", theReplSet && theReplSet->isSecondary() );
} }
else { else {
notMasterUnless(isMaster() || pq.hasOption(QueryOption_SlaveOk) || replSettings.slave == SimpleSlave ); notMasterUnless(isMaster() || pq.hasOption(QueryOption_SlaveOk) || replSettings.slave == SimpleSlave );
} }
} }
inline bool isMasterNs( const char *ns ) {
char cl[ 256 ];
nsToDatabase( ns, cl );
return isMaster( cl );
}
} // namespace mongo } // namespace mongo
 End of changes. 6 change blocks. 
14 lines changed or deleted 16 lines changed or added


 request.h   request.h 
skipping to change at line 70 skipping to change at line 70
ChunkManagerPtr getChunkManager() const { ChunkManagerPtr getChunkManager() const {
assert( _didInit ); assert( _didInit );
return _chunkManager; return _chunkManager;
} }
ClientInfo * getClientInfo() const { ClientInfo * getClientInfo() const {
return _clientInfo; return _clientInfo;
} }
void checkAuth() const; /**
* @param ns - 0=use ns from message
*/
void checkAuth( Auth::Level levelNeeded , const char * ns=0 ) const
;
// ---- remote location info ----- // ---- remote location info -----
Shard primaryShard() const ; Shard primaryShard() const ;
// ---- low level access ---- // ---- low level access ----
void reply( Message & response , const string& fromServer ); void reply( Message & response , const string& fromServer );
Message& m() { return _m; } Message& m() { return _m; }
DbMessage& d() { return _d; } DbMessage& d() { return _d; }
AbstractMessagingPort* p() const { return _p; } AbstractMessagingPort* p() const { return _p; }
void process( int attempt = 0 ); void process( int attempt = 0 );
void gotInsert(); void gotInsert();
void init(); void init();
void reset( bool reload=false, bool forceReload = false ); void reset();
private: private:
Message& _m; Message& _m;
DbMessage _d; DbMessage _d;
AbstractMessagingPort* _p; AbstractMessagingPort* _p;
MSGID _id; MSGID _id;
DBConfigPtr _config; DBConfigPtr _config;
ChunkManagerPtr _chunkManager; ChunkManagerPtr _chunkManager;
 End of changes. 2 change blocks. 
2 lines changed or deleted 6 lines changed or added


 rs.h   rs.h 
skipping to change at line 26 skipping to change at line 26
* 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 "../../util/concurrency/list.h" #include "../../util/concurrency/list.h"
#include "../../util/concurrency/value.h" #include "../../util/concurrency/value.h"
#include "../../util/concurrency/msg.h" #include "../../util/concurrency/msg.h"
#include "../../util/net/hostandport.h" #include "../../util/net/hostandport.h"
#include "../commands.h" #include "../commands.h"
#include "../oplog.h"
#include "../oplogreader.h" #include "../oplogreader.h"
#include "rs_exception.h" #include "rs_exception.h"
#include "rs_optime.h" #include "rs_optime.h"
#include "rs_member.h" #include "rs_member.h"
#include "rs_config.h" #include "rs_config.h"
/** /**
* Order of Events * Order of Events
* *
* On startup, if the --replSet option is present, startReplSets is called. * On startup, if the --replSet option is present, startReplSets is called.
skipping to change at line 61 skipping to change at line 62
extern bool replSet; // true if using repl sets extern bool replSet; // true if using repl sets
extern class ReplSet *theReplSet; // null until initialized extern class ReplSet *theReplSet; // null until initialized
extern Tee *rsLog; extern Tee *rsLog;
/* member of a replica set */ /* member of a replica set */
class Member : public List1<Member>::Base { class Member : public List1<Member>::Base {
private: private:
~Member(); // intentionally unimplemented as should never be called -- see List1<>::Base. ~Member(); // intentionally unimplemented as should never be called -- see List1<>::Base.
Member(const Member&); Member(const Member&);
public: public:
Member(HostAndPort h, unsigned ord, ReplSetConfig::MemberCfg *c, bo ol self); Member(HostAndPort h, unsigned ord, const ReplSetConfig::MemberCfg *c, bool self);
string fullName() const { return h().toString(); } string fullName() const { return h().toString(); }
const ReplSetConfig::MemberCfg& config() const { return _config; } const ReplSetConfig::MemberCfg& config() const { return _config; }
ReplSetConfig::MemberCfg& configw() { return _config; } ReplSetConfig::MemberCfg& configw() { return _config; }
const HeartbeatInfo& hbinfo() const { return _hbinfo; } const HeartbeatInfo& hbinfo() const { return _hbinfo; }
HeartbeatInfo& get_hbinfo() { return _hbinfo; } HeartbeatInfo& get_hbinfo() { return _hbinfo; }
string lhb() const { return _hbinfo.lastHeartbeatMsg; } string lhb() const { return _hbinfo.lastHeartbeatMsg; }
MemberState state() const { return _hbinfo.hbstate; } MemberState state() const { return _hbinfo.hbstate; }
const HostAndPort& h() const { return _h; } const HostAndPort& h() const { return _h; }
unsigned id() const { return _hbinfo.id(); } unsigned id() const { return _hbinfo.id(); }
skipping to change at line 83 skipping to change at line 84
bool potentiallyHot() const { return _config.potentiallyHot(); } // not arbiter, not priority 0 bool potentiallyHot() const { return _config.potentiallyHot(); } // not arbiter, not priority 0
void summarizeMember(stringstream& s) const; void summarizeMember(stringstream& s) const;
private: private:
friend class ReplSetImpl; friend class ReplSetImpl;
ReplSetConfig::MemberCfg _config; ReplSetConfig::MemberCfg _config;
const HostAndPort _h; const HostAndPort _h;
HeartbeatInfo _hbinfo; HeartbeatInfo _hbinfo;
}; };
namespace replset {
/**
* "Normal" replica set syncing
*/
class SyncTail : public Sync {
public:
virtual ~SyncTail() {}
SyncTail(const string& host) : Sync(host) {}
virtual bool syncApply(const BSONObj &o);
};
/**
* Initial clone and sync
*/
class InitialSync : public SyncTail {
public:
InitialSync(const string& host) : SyncTail(host) {}
virtual ~InitialSync() {}
bool oplogApplication(OplogReader& r, const Member* source, con
st OpTime& applyGTE, const OpTime& minValid);
virtual void applyOp(const BSONObj& o, const OpTime& minvalid);
};
// TODO: move hbmsg into an error-keeping class (SERVER-4444)
void sethbmsg(const string& s, const int logLevel=0);
} // namespace replset
class Manager : public task::Server { class Manager : public task::Server {
ReplSetImpl *rs; ReplSetImpl *rs;
bool busyWithElectSelf; bool busyWithElectSelf;
int _primary; int _primary;
/** @param two - if true two primaries were seen. this can happen transiently, in addition to our /** @param two - if true two primaries were seen. this can happen transiently, in addition to our
polling being only occasional. in this case null is returned, but the caller should polling being only occasional. in this case null is returned, but the caller should
not assume primary itself in that situation. not assume primary itself in that situation.
*/ */
const Member* findOtherPrimary(bool& two); const Member* findOtherPrimary(bool& two);
skipping to change at line 106 skipping to change at line 134
void checkAuth(); void checkAuth();
virtual void starting(); virtual void starting();
public: public:
Manager(ReplSetImpl *rs); Manager(ReplSetImpl *rs);
virtual ~Manager(); virtual ~Manager();
void msgReceivedNewConfig(BSONObj); void msgReceivedNewConfig(BSONObj);
void msgCheckNewState(); void msgCheckNewState();
}; };
class GhostSync : public task::Server { class GhostSync : public task::Server {
struct GhostSlave { struct GhostSlave : boost::noncopyable {
GhostSlave() : last(0), slave(0), init(false) {} GhostSlave() : last(0), slave(0), init(false) { }
OplogReader reader; OplogReader reader;
OpTime last; OpTime last;
Member* slave; Member* slave;
bool init; bool init;
}; };
/** /**
* This is a cache of ghost slaves * This is a cache of ghost slaves
*/ */
typedef map<mongo::OID,GhostSlave> MAP; typedef map< mongo::OID,shared_ptr<GhostSlave> > MAP;
MAP _ghostCache; MAP _ghostCache;
RWLock _lock; // protects _ghostCache RWLock _lock; // protects _ghostCache
ReplSetImpl *rs; ReplSetImpl *rs;
virtual void starting(); virtual void starting();
public: public:
GhostSync(ReplSetImpl *_rs) : task::Server("rsGhostSync"), _lock("G hostSync"), rs(_rs) {} GhostSync(ReplSetImpl *_rs) : task::Server("rsGhostSync"), _lock("G hostSync"), rs(_rs) {}
~GhostSync() { ~GhostSync() {
log() << "~GhostSync() called" << rsLog; log() << "~GhostSync() called" << rsLog;
} }
skipping to change at line 155 skipping to change at line 183
struct Target; struct Target;
class Consensus { class Consensus {
ReplSetImpl &rs; ReplSetImpl &rs;
struct LastYea { struct LastYea {
LastYea() : when(0), who(0xffffffff) { } LastYea() : when(0), who(0xffffffff) { }
time_t when; time_t when;
unsigned who; unsigned who;
}; };
static mutex lyMutex; static SimpleMutex lyMutex;
Guarded<LastYea,lyMutex> ly; Guarded<LastYea,lyMutex> ly;
unsigned yea(unsigned memberId); // throws VoteException unsigned yea(unsigned memberId); // throws VoteException
void electionFailed(unsigned meid); void electionFailed(unsigned meid);
void _electSelf(); void _electSelf();
bool weAreFreshest(bool& allUp, int& nTies); bool weAreFreshest(bool& allUp, int& nTies);
bool sleptLast; // slept last elect() pass bool sleptLast; // slept last elect() pass
public: public:
Consensus(ReplSetImpl *t) : rs(*t) { Consensus(ReplSetImpl *t) : rs(*t) {
sleptLast = false; sleptLast = false;
steppedDown = 0; steppedDown = 0;
skipping to change at line 349 skipping to change at line 377
bool _stepDown(int secs); bool _stepDown(int secs);
bool _freeze(int secs); bool _freeze(int secs);
private: private:
void assumePrimary(); void assumePrimary();
void loadLastOpTimeWritten(bool quiet=false); void loadLastOpTimeWritten(bool quiet=false);
void changeState(MemberState s); void changeState(MemberState s);
/** /**
* Find the closest member (using ping time) with a higher latest o ptime. * Find the closest member (using ping time) with a higher latest o ptime.
*/ */
const Member* getMemberToSyncTo(); Member* getMemberToSyncTo();
void veto(const string& host, unsigned secs=10);
Member* _currentSyncTarget; Member* _currentSyncTarget;
bool _blockSync; bool _blockSync;
void blockSync(bool block); void blockSync(bool block);
// set of electable members' _ids // set of electable members' _ids
set<unsigned> _electableSet; set<unsigned> _electableSet;
protected: protected:
// "heartbeat message" // "heartbeat message"
// sent in requestHeartbeat respond in field "hbm" // sent in requestHeartbeat respond in field "hbm"
skipping to change at line 491 skipping to change at line 520
void getTargets(list<Target>&, int &configVersion); void getTargets(list<Target>&, int &configVersion);
void startThreads(); void startThreads();
friend class FeedbackThread; friend class FeedbackThread;
friend class CmdReplSetElect; friend class CmdReplSetElect;
friend class Member; friend class Member;
friend class Manager; friend class Manager;
friend class GhostSync; friend class GhostSync;
friend class Consensus; friend class Consensus;
private: private:
/* pulling data from primary related - see rs_sync.cpp */ bool initialSyncOplogApplication(const OpTime& applyGTE, const OpTi
bool initialSyncOplogApplication(const Member *primary, OpTime appl me& minValid);
yGTE, OpTime minValid);
void _syncDoInitialSync(); void _syncDoInitialSync();
void syncDoInitialSync(); void syncDoInitialSync();
void _syncThread(); void _syncThread();
bool tryToGoLiveAsASecondary(OpTime&); // readlocks bool tryToGoLiveAsASecondary(OpTime&); // readlocks
void syncTail(); void syncTail();
bool syncApply(const BSONObj &o);
unsigned _syncRollback(OplogReader& r); unsigned _syncRollback(OplogReader& r);
void syncRollback(OplogReader& r); void syncRollback(OplogReader& r);
void syncFixUp(HowToFixUp& h, OplogReader& r); void syncFixUp(HowToFixUp& h, OplogReader& r);
bool _getOplogReader(OplogReader& r, string& hn);
bool _isStale(OplogReader& r, const string& hn); // get an oplog reader for a server with an oplog entry timestamp g
reater
// than or equal to minTS, if set.
Member* _getOplogReader(OplogReader& r, const OpTime& minTS);
// check lastOpTimeWritten against the remote's earliest op, fillin
g in
// remoteOldestOp.
bool _isStale(OplogReader& r, const OpTime& minTS, BSONObj& remoteO
ldestOp);
// keep a list of hosts that we've tried recently that didn't work
map<string,time_t> _veto;
public: public:
void syncThread(); void syncThread();
const OpTime lastOtherOpTime() const; const OpTime lastOtherOpTime() const;
}; };
class ReplSet : public ReplSetImpl { class ReplSet : public ReplSetImpl {
public: public:
ReplSet(ReplSetCmdline& replSetCmdline) : ReplSetImpl(replSetCmdlin e) { } ReplSet(ReplSetCmdline& replSetCmdline) : ReplSetImpl(replSetCmdlin e) { }
// for the replSetStepDown command // for the replSetStepDown command
skipping to change at line 597 skipping to change at line 633
errmsg = "replSet command unauthorized"; errmsg = "replSet command unauthorized";
return false; return false;
} }
} }
return true; return true;
} }
bool check(string& errmsg, BSONObjBuilder& result) { bool check(string& errmsg, BSONObjBuilder& result) {
if( !replSet ) { if( !replSet ) {
errmsg = "not running with --replSet"; errmsg = "not running with --replSet";
if( cmdLine.configsvr ) {
result.append("info", "configsvr"); // for shell prompt
}
return false; return false;
} }
if( theReplSet == 0 ) { if( theReplSet == 0 ) {
result.append("startupStatus", ReplSet::startupStatus); result.append("startupStatus", ReplSet::startupStatus);
string s; string s;
errmsg = ReplSet::startupStatusMsg.empty() ? "replset unkno wn error 2" : ReplSet::startupStatusMsg.get(); errmsg = ReplSet::startupStatusMsg.empty() ? "replset unkno wn error 2" : ReplSet::startupStatusMsg.get();
if( ReplSet::startupStatus == 3 ) if( ReplSet::startupStatus == 3 )
result.append("info", "run rs.initiate(...) if not yet done for the set"); result.append("info", "run rs.initiate(...) if not yet done for the set");
return false; return false;
skipping to change at line 621 skipping to change at line 660
}; };
/** /**
* does local authentication * does local authentication
* directly authorizes against AuthenticationInfo * directly authorizes against AuthenticationInfo
*/ */
void replLocalAuth(); void replLocalAuth();
/** inlines ----------------- */ /** inlines ----------------- */
inline Member::Member(HostAndPort h, unsigned ord, ReplSetConfig::Membe rCfg *c, bool self) : inline Member::Member(HostAndPort h, unsigned ord, const ReplSetConfig: :MemberCfg *c, bool self) :
_config(*c), _h(h), _hbinfo(ord) { _config(*c), _h(h), _hbinfo(ord) {
assert(c); assert(c);
if( self ) if( self )
_hbinfo.health = 1.0; _hbinfo.health = 1.0;
} }
} }
 End of changes. 12 change blocks. 
13 lines changed or deleted 56 lines changed or added


 rs_config.h   rs_config.h 
skipping to change at line 78 skipping to change at line 78
const set<TagSubgroup*>& groups() const { const set<TagSubgroup*>& groups() const {
return _groups; return _groups;
} }
set<TagSubgroup*>& groupsw() { set<TagSubgroup*>& groupsw() {
return _groups; return _groups;
} }
void check() const; /* check validity, assert if not. */ void check() const; /* check validity, assert if not. */
BSONObj asBson() const; BSONObj asBson() const;
bool potentiallyHot() const { return !arbiterOnly && priority > 0; } bool potentiallyHot() const { return !arbiterOnly && priority > 0; }
void updateGroups(const OpTime& last) { void updateGroups(const OpTime& last) {
for (set<TagSubgroup*>::iterator it = _groups.begin(); it ! RACECHECK
= _groups.end(); it++) { for (set<TagSubgroup*>::const_iterator it = groups().begin(
((TagSubgroup*)(*it))->updateLast(last); ); it != groups().end(); it++) {
(*it)->updateLast(last);
} }
} }
bool operator==(const MemberCfg& r) const { bool operator==(const MemberCfg& r) const {
if (!tags.empty() || !r.tags.empty()) { if (!tags.empty() || !r.tags.empty()) {
if (tags.size() != r.tags.size()) { if (tags.size() != r.tags.size()) {
return false; return false;
} }
// if they are the same size and not equal, at least on e // if they are the same size and not equal, at least on e
// element in A must be different in B // element in A must be different in B
skipping to change at line 134 skipping to change at line 135
/** check if modification makes sense */ /** check if modification makes sense */
static bool legalChange(const ReplSetConfig& old, const ReplSetConf ig& n, string& errmsg); static bool legalChange(const ReplSetConfig& old, const ReplSetConf ig& n, string& errmsg);
//static void receivedNewConfig(BSONObj); //static void receivedNewConfig(BSONObj);
void saveConfigLocally(BSONObj comment); // to local db void saveConfigLocally(BSONObj comment); // to local db
string saveConfigEverywhere(); // returns textual info on what happ ened string saveConfigEverywhere(); // returns textual info on what happ ened
/** /**
* Update members' groups when the config changes but members stay the same. * Update members' groups when the config changes but members stay the same.
*/ */
void updateMembers(List1<Member> &dest); void updateMembers(List1<Member> &dest) const;
BSONObj asBson() const; BSONObj asBson() const;
/** /**
* Getter and setter for _majority. This is almost always * Getter and setter for _majority. This is almost always
* members.size()/2+1, but can be the number of non-arbiter members if * members.size()/2+1, but can be the number of non-arbiter members if
* there are more arbiters than non-arbiters (writing to 3 out of 7 * there are more arbiters than non-arbiters (writing to 3 out of 7
* servers is safe if 4 of the servers are arbiters). * servers is safe if 4 of the servers are arbiters).
*/ */
private:
void setMajority(); void setMajority();
public:
int getMajority() const; int getMajority() const;
bool _constructed; bool _constructed;
private: private:
bool _ok; bool _ok;
int _majority; int _majority;
void from(BSONObj); void from(BSONObj);
void clear(); void clear();
 End of changes. 4 change blocks. 
4 lines changed or deleted 7 lines changed or added


 rs_member.h   rs_member.h 
skipping to change at line 72 skipping to change at line 72
bool operator==(const MemberState& r) const { return s == r.s; } bool operator==(const MemberState& r) const { return s == r.s; }
bool operator!=(const MemberState& r) const { return s != r.s; } bool operator!=(const MemberState& r) const { return s != r.s; }
}; };
/* this is supposed to be just basic information on a member, /* this is supposed to be just basic information on a member,
and copy constructable. */ and copy constructable. */
class HeartbeatInfo { class HeartbeatInfo {
unsigned _id; unsigned _id;
public: public:
HeartbeatInfo() : _id(0xffffffff), hbstate(MemberState::RS_UNKNOWN) , health(-1.0), HeartbeatInfo() : _id(0xffffffff), hbstate(MemberState::RS_UNKNOWN) , health(-1.0),
downSince(0), skew(INT_MIN), authIssue(false) { } downSince(0), skew(INT_MIN), authIssue(false), ping(0) { }
HeartbeatInfo(unsigned id); HeartbeatInfo(unsigned id);
unsigned id() const { return _id; } unsigned id() const { return _id; }
MemberState hbstate; MemberState hbstate;
double health; double health;
time_t upSince; time_t upSince;
long long downSince; long long downSince;
time_t lastHeartbeat; time_t lastHeartbeat;
DiagStr lastHeartbeatMsg; DiagStr lastHeartbeatMsg;
OpTime opTime; OpTime opTime;
int skew; int skew;
skipping to change at line 98 skipping to change at line 98
/** health is set to -1 on startup. that means we haven't even che cked yet. 0 means we checked and it failed. */ /** health is set to -1 on startup. that means we haven't even che cked yet. 0 means we checked and it failed. */
bool maybeUp() const { return health != 0; } bool maybeUp() const { return health != 0; }
long long timeDown() const; // ms long long timeDown() const; // ms
/* true if changed in a way of interest to the repl set manager. */ /* true if changed in a way of interest to the repl set manager. */
bool changed(const HeartbeatInfo& old) const; bool changed(const HeartbeatInfo& old) const;
}; };
inline HeartbeatInfo::HeartbeatInfo(unsigned id) : _id(id), authIssue(f inline HeartbeatInfo::HeartbeatInfo(unsigned id) :
alse) { _id(id),
authIssue(false),
ping(0) {
hbstate = MemberState::RS_UNKNOWN; hbstate = MemberState::RS_UNKNOWN;
health = -1.0; health = -1.0;
downSince = 0; downSince = 0;
lastHeartbeat = upSince = 0; lastHeartbeat = upSince = 0;
skew = INT_MIN; skew = INT_MIN;
} }
inline bool HeartbeatInfo::changed(const HeartbeatInfo& old) const { inline bool HeartbeatInfo::changed(const HeartbeatInfo& old) const {
return health != old.health || return health != old.health ||
hbstate != old.hbstate; hbstate != old.hbstate;
 End of changes. 2 change blocks. 
3 lines changed or deleted 5 lines changed or added


 rwlock.h   rwlock.h 
skipping to change at line 23 skipping to change at line 23
* 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 Lice nse * You should have received a copy of the GNU Affero General Public Lice nse
* 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 "mutex.h" #include "mutex.h"
#include "../time_support.h" #include "../time_support.h"
#include "rwlockimpl.h"
// this requires newer windows versions #if defined(_DEBUG)
// it works better than sharable_mutex under high contention #include "mutexdebugger.h"
#if defined(_WIN64)
//#define MONGO_USE_SRW_ON_WINDOWS 1
#endif
#if !defined(MONGO_USE_SRW_ON_WINDOWS)
#if BOOST_VERSION >= 103500
# define BOOST_RWLOCK
#else
# if defined(_WIN32)
# error need boost >= 1.35 for windows
# endif
# include <pthread.h>
#endif
#if defined(_WIN32)
# include "shared_mutex_win.hpp"
namespace mongo {
typedef boost::modified_shared_mutex shared_mutex;
}
# undef assert
# define assert MONGO_assert
#elif defined(BOOST_RWLOCK)
# include <boost/thread/shared_mutex.hpp>
# undef assert
# define assert MONGO_assert
#endif
#endif #endif
namespace mongo { namespace mongo {
#if defined(MONGO_USE_SRW_ON_WINDOWS) && defined(_WIN32) /** separated out as later the implementation of this may be different
than RWLock,
// Windows RWLock implementation (requires newer versions of windows th depending on OS, as there is no upgrade etc. facility herein.
us the above macro) */
class RWLock : boost::noncopyable { class SimpleRWLock : public RWLockBase {
public: public:
RWLock(const char *, int lowPriorityWaitMS=0 ) : _lowPriorityWaitMS explicit SimpleRWLock(const char *) { }
(lowPriorityWaitMS) SimpleRWLock() { }
{ InitializeSRWLock(&_lock); } void lock() { RWLockBase::lock(); }
~RWLock() { } void unlock() { RWLockBase::unlock(); }
const char * implType() const { return "WINSRW"; } void lock_shared() { RWLockBase::lock_shared(); }
int lowPriorityWaitMS() const { return _lowPriorityWaitMS; } void unlock_shared() { RWLockBase::unlock_shared(); }
void lock() { AcquireSRWLockExclusive(&_lock); } class Shared : boost::noncopyable {
void unlock() { ReleaseSRWLockExclusive(&_lock); } SimpleRWLock& _r;
void lock_shared() { AcquireSRWLockShared(&_lock); } public:
void unlock_shared() { ReleaseSRWLockShared(&_lock); } Shared(SimpleRWLock& rwlock) : _r(rwlock) {_r.lock_shared(); }
bool lock_shared_try( int millis ) { ~Shared() { _r.unlock_shared(); }
if( TryAcquireSRWLockShared(&_lock) ) };
return true; class Exclusive : boost::noncopyable {
if( millis == 0 ) SimpleRWLock& _r;
return false; public:
unsigned long long end = curTimeMicros64() + millis*1000; Exclusive(SimpleRWLock& rwlock) : _r(rwlock) {_r.lock(); }
while( 1 ) { ~Exclusive() { _r.unlock(); }
Sleep(1); };
if( TryAcquireSRWLockShared(&_lock) )
return true;
if( curTimeMicros64() >= end )
break;
}
return false;
}
bool lock_try( int millis = 0 ) {
if( TryAcquireSRWLockExclusive(&_lock) ) // quick check to opti
mistically avoid calling curTimeMicros64
return true;
if( millis == 0 )
return false;
unsigned long long end = curTimeMicros64() + millis*1000;
do {
Sleep(1);
if( TryAcquireSRWLockExclusive(&_lock) )
return true;
} while( curTimeMicros64() < end );
return false;
}
private:
SRWLOCK _lock;
const int _lowPriorityWaitMS;
}; };
#elif defined(BOOST_RWLOCK) class RWLock : public RWLockBase {
enum { NilState, UpgradableState, Exclusive } x; // only bother to
// Boost based RWLock implementation set when doing upgradable related things
class RWLock : boost::noncopyable {
shared_mutex _m;
const int _lowPriorityWaitMS;
public: public:
const char * const _name; const char * const _name;
RWLock(const char *name) : _name(name) {
RWLock(const char *name, int lowPriorityWait=0) : _lowPriorityWaitM x = NilState;
S(lowPriorityWait) , _name(name) { } }
const char * implType() const { return "boost"; }
int lowPriorityWaitMS() const { return _lowPriorityWaitMS; }
void lock() { void lock() {
_m.lock(); RWLockBase::lock();
DEV mutexDebugger.entering(_name); #if defined(_DEBUG)
mutexDebugger.entering(_name);
#endif
} }
/*void lock() {
// This sequence gives us the lock semantics we want: specifica
lly that write lock acquisition is
// greedy EXCEPT when someone already is in upgradable state.
lockAsUpgradable();
upgrade();
DEV mutexDebugger.entering(_name);
}*/
void unlock() { void unlock() {
DEV mutexDebugger.leaving(_name); #if defined(_DEBUG)
_m.unlock(); mutexDebugger.leaving(_name);
#endif
RWLockBase::unlock();
} }
void lockAsUpgradable() { void lock_shared() { RWLockBase::lock_shared(); }
_m.lock_upgrade(); void unlock_shared() { RWLockBase::unlock_shared(); }
} private:
void lockAsUpgradable() { RWLockBase::lockAsUpgradable(); }
void unlockFromUpgradable() { // upgradable -> unlocked void unlockFromUpgradable() { // upgradable -> unlocked
_m.unlock_upgrade(); RWLockBase::unlockFromUpgradable();
}
void upgrade() { // upgradable -> exclusive lock
_m.unlock_upgrade_and_lock();
}
void lock_shared() {
_m.lock_shared();
}
void unlock_shared() {
_m.unlock_shared();
}
bool lock_shared_try( int millis ) {
if( _m.timed_lock_shared( boost::posix_time::milliseconds(milli
s) ) ) {
return true;
}
return false;
}
bool lock_try( int millis = 0 ) {
if( _m.timed_lock( boost::posix_time::milliseconds(millis) ) )
{
DEV mutexDebugger.entering(_name);
return true;
}
return false;
} }
};
#else
// Posix RWLock implementation
class RWLock : boost::noncopyable {
pthread_rwlock_t _lock;
const int _lowPriorityWaitMS;
static void check( int x ) {
if( MONGO_likely(x == 0) )
return;
log() << "pthread rwlock failed: " << x << endl;
assert( x == 0 );
}
public: public:
const char *_name; void upgrade() { // upgradable -> exclusive lock
RWLock(const char *name, int lowPriorityWaitMS=0) : _lowPriorityWai assert( x == UpgradableState );
tMS(lowPriorityWaitMS), _name(name) RWLockBase::upgrade();
{ x = Exclusive;
check( pthread_rwlock_init( &_lock , 0 ) );
}
~RWLock() {
if ( ! StaticObserver::_destroyingStatics ) {
wassert( pthread_rwlock_destroy( &_lock ) == 0 ); // wasser
t as don't want to throw from a destructor
}
}
const char * implType() const { return "posix"; }
int lowPriorityWaitMS() const { return _lowPriorityWaitMS; }
void lock() {
check( pthread_rwlock_wrlock( &_lock ) );
DEV mutexDebugger.entering(_name);
}
void unlock() {
DEV mutexDebugger.leaving(_name);
check( pthread_rwlock_unlock( &_lock ) );
}
void lock_shared() {
check( pthread_rwlock_rdlock( &_lock ) );
}
void unlock_shared() {
check( pthread_rwlock_unlock( &_lock ) );
} }
bool lock_shared_try( int millis ) { bool lock_shared_try( int millis ) { return RWLockBase::lock_shared
return _try( millis , false ); _try(millis); }
}
bool lock_try( int millis = 0 ) { bool lock_try( int millis = 0 ) {
if( _try( millis , true ) ) { if( RWLockBase::lock_try(millis) ) {
DEV mutexDebugger.entering(_name); #if defined(_DEBUG)
mutexDebugger.entering(_name);
#endif
return true; return true;
} }
return false; return false;
} }
bool _try( int millis , bool write ) { /** acquire upgradable state. You must be unlocked before creating
while ( true ) { .
int x = write ? unlocks on destruction, whether in upgradable state or upgraded
pthread_rwlock_trywrlock( &_lock ) : to exclusive
pthread_rwlock_tryrdlock( &_lock ); in the interim.
*/
if ( x <= 0 ) { class Upgradable : boost::noncopyable {
return true; RWLock& _r;
public:
Upgradable(RWLock& r) : _r(r) {
r.lockAsUpgradable();
assert( _r.x == NilState );
_r.x = RWLock::UpgradableState;
}
~Upgradable() {
if( _r.x == RWLock::UpgradableState ) {
_r.x = NilState;
_r.unlockFromUpgradable();
} }
else {
if ( millis-- <= 0 ) //TEMP assert( _r.x == Exclusive );
return false; // has been upgraded
_r.x = NilState;
if ( x == EBUSY ) { _r.unlock();
sleepmillis(1);
continue;
} }
check(x);
} }
};
return false;
}
}; };
#endif
/** throws on failure to acquire in the specified time period. */ /** throws on failure to acquire in the specified time period. */
class rwlock_try_write : boost::noncopyable { class rwlock_try_write : boost::noncopyable {
public: public:
struct exception { }; struct exception { };
rwlock_try_write(RWLock& l, int millis = 0) : _l(l) { rwlock_try_write(RWLock& l, int millis = 0) : _l(l) {
if( !l.lock_try(millis) ) if( !l.lock_try(millis) )
throw exception(); throw exception();
} }
~rwlock_try_write() { _l.unlock(); } ~rwlock_try_write() { _l.unlock(); }
private: private:
skipping to change at line 287 skipping to change at line 158
/* scoped lock for RWLock */ /* scoped lock for RWLock */
class rwlock : boost::noncopyable { class rwlock : boost::noncopyable {
public: public:
/** /**
* @param write acquire write lock if true sharable if false * @param write acquire write lock if true sharable if false
* @param lowPriority if > 0, will try to get the lock non-greedily for that many ms * @param lowPriority if > 0, will try to get the lock non-greedily for that many ms
*/ */
rwlock( const RWLock& lock , bool write, /* bool alreadyHaveLock = false , */int lowPriorityWaitMS = 0 ) rwlock( const RWLock& lock , bool write, /* bool alreadyHaveLock = false , */int lowPriorityWaitMS = 0 )
: _lock( (RWLock&)lock ) , _write( write ) { : _lock( (RWLock&)lock ) , _write( write ) {
{ {
if ( _write ) { if ( _write ) {
_lock.lock();
if ( ! lowPriorityWaitMS && lock.lowPriorityWaitMS() )
lowPriorityWaitMS = lock.lowPriorityWaitMS();
if ( lowPriorityWaitMS ) {
bool got = false;
for ( int i=0; i<lowPriorityWaitMS; i++ ) {
if ( _lock.lock_try(0) ) {
got = true;
break;
}
int sleep = 1;
if ( i > ( lowPriorityWaitMS / 20 ) )
sleep = 10;
sleepmillis(sleep);
i += ( sleep - 1 );
}
if ( ! got ) {
log() << "couldn't get lazy rwlock" << endl;
_lock.lock();
}
}
else {
_lock.lock();
}
} }
else { else {
_lock.lock_shared(); _lock.lock_shared();
} }
} }
} }
~rwlock() { ~rwlock() {
if ( _write ) if ( _write )
_lock.unlock(); _lock.unlock();
else else
_lock.unlock_shared(); _lock.unlock_shared();
} }
private: private:
RWLock& _lock; RWLock& _lock;
const bool _write; const bool _write;
}; };
// --------------------------------------------------------------------
--------------------
/** recursive on shared locks is ok for this implementation */ /** recursive on shared locks is ok for this implementation */
class RWLockRecursive : boost::noncopyable { class RWLockRecursive : protected RWLockBase {
protected:
ThreadLocalValue<int> _state; ThreadLocalValue<int> _state;
RWLock _lk; void lock(); // not implemented - Lock() should be used; didn't ove
friend class Exclusive; rload this name to avoid mistakes
virtual void Lock() { RWLockBase::lock(); }
public: public:
/** @param lpwaitms lazy wait */ virtual ~RWLockRecursive() { }
RWLockRecursive(const char *name, int lpwaitms) : _lk(name, lpwaitm const char * const _name;
s) { } RWLockRecursive(const char *name) : _name(name) { }
void assertExclusivelyLocked() { void assertExclusivelyLocked() {
dassert( _state.get() < 0 ); assert( _state.get() < 0 );
} }
// RWLockRecursive::Exclusive scoped lock
class Exclusive : boost::noncopyable { class Exclusive : boost::noncopyable {
RWLockRecursive& _r; RWLockRecursive& _r;
rwlock *_scopedLock;
public: public:
Exclusive(RWLockRecursive& r) : _r(r), _scopedLock(0) { Exclusive(RWLockRecursive& r) : _r(r) {
int s = _r._state.get(); int s = _r._state.get();
dassert( s <= 0 ); dassert( s <= 0 );
if( s == 0 ) if( s == 0 )
_scopedLock = new rwlock(_r._lk, true); _r.Lock();
_r._state.set(s-1); _r._state.set(s-1);
} }
~Exclusive() { ~Exclusive() {
int s = _r._state.get(); int s = _r._state.get();
DEV wassert( s < 0 ); // wassert: don't throw from destruct ors DEV wassert( s < 0 ); // wassert: don't throw from destruct ors
_r._state.set(s+1); ++s;
delete _scopedLock; _r._state.set(s);
if ( s == 0 )
_r.unlock();
} }
}; };
// RWLockRecursive::Shared scoped lock
class Shared : boost::noncopyable { class Shared : boost::noncopyable {
RWLockRecursive& _r; RWLockRecursive& _r;
bool _alreadyExclusive; bool _alreadyLockedExclusiveByUs;
public: public:
Shared(RWLockRecursive& r) : _r(r) { Shared(RWLockRecursive& r) : _r(r) {
int s = _r._state.get(); int s = _r._state.get();
_alreadyExclusive = s < 0; _alreadyLockedExclusiveByUs = s < 0;
if( !_alreadyExclusive ) { if( !_alreadyLockedExclusiveByUs ) {
dassert( s >= 0 ); // -1 would mean exclusive dassert( s >= 0 ); // -1 would mean exclusive
if( s == 0 ) if( s == 0 )
_r._lk.lock_shared(); _r.lock_shared();
_r._state.set(s+1); _r._state.set(s+1);
} }
} }
~Shared() { ~Shared() {
if( _alreadyExclusive ) { if( _alreadyLockedExclusiveByUs ) {
DEV wassert( _r._state.get() < 0 ); DEV wassert( _r._state.get() < 0 );
} }
else { else {
int s = _r._state.get() - 1; int s = _r._state.get() - 1;
if( s == 0 )
_r._lk.unlock_shared();
_r._state.set(s);
DEV wassert( s >= 0 ); DEV wassert( s >= 0 );
_r._state.set(s);
if( s == 0 )
_r.unlock_shared();
} }
} }
}; };
}; };
class RWLockRecursiveNongreedy : public RWLockRecursive {
virtual void Lock() {
bool got = false;
for ( int i=0; i<lowPriorityWaitMS; i++ ) {
if ( lock_try(0) ) {
got = true;
break;
}
int sleep = 1;
if ( i > ( lowPriorityWaitMS / 20 ) )
sleep = 10;
sleepmillis(sleep);
i += ( sleep - 1 );
}
if ( ! got ) {
log() << "couldn't lazily get rwlock" << endl;
RWLockBase::lock();
}
}
public:
const int lowPriorityWaitMS;
RWLockRecursiveNongreedy(const char *nm, int lpwaitms) : RWLockRecu
rsive(nm), lowPriorityWaitMS(lpwaitms) { }
const char * implType() const { return RWLockRecursive::implType();
}
//just for testing:
bool __lock_try( int millis ) { return RWLockRecursive::lock_try(mi
llis); }
};
} }
 End of changes. 40 change blocks. 
261 lines changed or deleted 139 lines changed or added


 scanandorder.h   scanandorder.h 
skipping to change at line 29 skipping to change at line 29
*/ */
#pragma once #pragma once
#include "indexkey.h" #include "indexkey.h"
#include "queryutil.h" #include "queryutil.h"
#include "projection.h" #include "projection.h"
namespace mongo { namespace mongo {
/* todo: static const int ScanAndOrderMemoryLimitExceededAssertionCode = 10128;
_ limit amount of data
*/
class KeyType : boost::noncopyable { class KeyType : boost::noncopyable {
public: public:
IndexSpec _spec; IndexSpec _spec;
FieldRangeVector _keyCutter; FieldRangeVector _keyCutter;
public: public:
KeyType(BSONObj pattern, const FieldRangeSet &frs): KeyType(const BSONObj &pattern, const FieldRangeSet &frs):
_spec((assert(!pattern.isEmpty()),pattern)), _spec((assert(!pattern.isEmpty()),pattern)),
_keyCutter(frs, _spec, 1) { _keyCutter(frs, _spec, 1) {
} }
/** /**
* @return first key of the object that would be encountered while * @return first key of the object that would be encountered while
* scanning index with keySpec 'pattern' using constraints 'frs', o r * scanning index with keySpec 'pattern' using constraints 'frs', o r
* BSONObj() if no such key. * BSONObj() if no such key.
*/ */
BSONObj getKeyFromObject(BSONObj o) { BSONObj getKeyFromObject(const BSONObj &o) const {
return _keyCutter.firstMatch(o); return _keyCutter.firstMatch(o);
} }
}; };
/* todo: /* todo:
_ respect limit
_ check for excess mem usage
_ response size limit from runquery; push it up a bit. _ response size limit from runquery; push it up a bit.
*/ */
inline void fillQueryResultFromObj(BufBuilder& bb, Projection *filter, inline void fillQueryResultFromObj(BufBuilder& bb, const Projection *fi
const BSONObj& js, DiskLoc* loc=NULL) { lter, const BSONObj& js,
const DiskLoc* loc=NULL) {
if ( filter ) { if ( filter ) {
BSONObjBuilder b( bb ); BSONObjBuilder b( bb );
filter->transform( js , b ); filter->transform( js , b );
if (loc) if (loc)
b.append("$diskLoc", loc->toBSONObj()); b.append("$diskLoc", loc->toBSONObj());
b.done(); b.done();
} }
else if (loc) { else if (loc) {
BSONObjBuilder b( bb ); BSONObjBuilder b( bb );
b.appendElements(js); b.appendElements(js);
skipping to change at line 83 skipping to change at line 80
else { else {
bb.appendBuf((void*) js.objdata(), js.objsize()); bb.appendBuf((void*) js.objdata(), js.objsize());
} }
} }
typedef multimap<BSONObj,BSONObj,BSONObjCmp> BestMap; typedef multimap<BSONObj,BSONObj,BSONObjCmp> BestMap;
class ScanAndOrder { class ScanAndOrder {
public: public:
static const unsigned MaxScanAndOrderBytes; static const unsigned MaxScanAndOrderBytes;
ScanAndOrder(int startFrom, int limit, BSONObj order, const FieldRa ngeSet &frs) : ScanAndOrder(int startFrom, int limit, const BSONObj &order, const FieldRangeSet &frs) :
_best( BSONObjCmp( order ) ), _best( BSONObjCmp( order ) ),
_startFrom(startFrom), _order(order, frs) { _startFrom(startFrom), _order(order, frs) {
_limit = limit > 0 ? limit + _startFrom : 0x7fffffff; _limit = limit > 0 ? limit + _startFrom : 0x7fffffff;
_approxSize = 0; _approxSize = 0;
} }
int size() const { return _best.size(); } int size() const { return _best.size(); }
void add(BSONObj o, DiskLoc* loc); /**
* @throw ScanAndOrderMemoryLimitExceededAssertionCode if adding wo
uld grow memory usage
* to ScanAndOrder::MaxScanAndOrderBytes.
*/
void add(const BSONObj &o, const DiskLoc* loc);
/* 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, Projection *filter, int& nout ) const; void fill(BufBuilder& b, const Projection *filter, int& nout ) cons
t;
/** Functions for testing. */
protected:
unsigned approxSize() const { return _approxSize; }
private: private:
void _add(BSONObj& k, BSONObj o, DiskLoc* loc); void _add(const BSONObj& k, const BSONObj& o, const DiskLoc* loc);
void _addIfBetter(const BSONObj& k, const BSONObj& o, const BestMap
::iterator& i,
const DiskLoc* loc);
void _addIfBetter(BSONObj& k, BSONObj o, BestMap::iterator i, DiskL /**
oc* loc); * @throw ScanAndOrderMemoryLimitExceededAssertionCode if approxSiz
e would grow too high,
* otherwise update _approxSize.
*/
void _validateAndUpdateApproxSize( const int approxSizeDelta );
BestMap _best; // key -> full object BestMap _best; // key -> full object
int _startFrom; int _startFrom;
int _limit; // max to send back. int _limit; // max to send back.
KeyType _order; KeyType _order;
unsigned _approxSize; unsigned _approxSize;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 10 change blocks. 
15 lines changed or deleted 31 lines changed or added


 security.h   security.h 
skipping to change at line 38 skipping to change at line 38
namespace mongo { namespace mongo {
/* /*
* for a particular db * for a particular db
* levels * levels
* 0 : none * 0 : none
* 1 : read * 1 : read
* 2 : write * 2 : write
*/ */
struct Auth { struct Auth {
Auth() { level = 0; }
int level; enum Level { NONE = 0 , READ = 1 , WRITE = 2 };
Auth() { level = NONE; }
Level level;
string user; string user;
}; };
class AuthenticationInfo : boost::noncopyable { class AuthenticationInfo : boost::noncopyable {
public: public:
bool isLocalHost; bool isLocalHost;
AuthenticationInfo(){ isLocalHost = false; } AuthenticationInfo(){ isLocalHost = false; }
~AuthenticationInfo() {} ~AuthenticationInfo() {}
// -- modifiers ---- // -- modifiers ----
void logout(const string& dbname ) { void logout(const string& dbname ) {
scoped_spinlock lk(_lock); scoped_spinlock lk(_lock);
_dbs.erase(dbname); _dbs.erase(dbname);
} }
void authorize(const string& dbname , const string& user ) { void authorize(const string& dbname , const string& user ) {
scoped_spinlock lk(_lock); scoped_spinlock lk(_lock);
_dbs[dbname].level = 2; _dbs[dbname].level = Auth::WRITE;
_dbs[dbname].user = user; _dbs[dbname].user = user;
} }
void authorizeReadOnly(const string& dbname , const string& user ) { void authorizeReadOnly(const string& dbname , const string& user ) {
scoped_spinlock lk(_lock); scoped_spinlock lk(_lock);
_dbs[dbname].level = 1; _dbs[dbname].level = Auth::READ;
_dbs[dbname].user = user; _dbs[dbname].user = user;
} }
// -- accessors --- // -- accessors ---
bool isAuthorized(const string& dbname) const { bool isAuthorized(const string& dbname) const {
return _isAuthorized( dbname, 2 ); return _isAuthorized( dbname, Auth::WRITE );
} }
bool isAuthorizedReads(const string& dbname) const { bool isAuthorizedReads(const string& dbname) const {
return _isAuthorized( dbname, 1 ); return _isAuthorized( dbname, Auth::READ );
} }
/**
* @param lockType - this is from dbmutex 1 is write, 0 is read
*/
bool isAuthorizedForLock(const string& dbname, int lockType ) const { bool isAuthorizedForLock(const string& dbname, int lockType ) const {
return _isAuthorized( dbname , lockType > 0 ? 2 : 1 ); return _isAuthorized( dbname , lockType > 0 ? Auth::WRITE : Aut
h::READ );
}
bool isAuthorizedForLevel( const string& dbname , Auth::Level level
) const {
return _isAuthorized( dbname , level );
} }
string getUser( const string& dbname ) const; string getUser( const string& dbname ) const;
void print() const; void print() const;
protected: protected:
/** takes a lock */ /** takes a lock */
bool _isAuthorized(const string& dbname, int level) const; bool _isAuthorized(const string& dbname, Auth::Level level) const;
bool _isAuthorizedSingle_inlock(const string& dbname, int level) co nst; bool _isAuthorizedSingle_inlock(const string& dbname, Auth::Level l evel) const;
/** cannot call this locked */ /** cannot call this locked */
bool _isAuthorizedSpecialChecks( const string& dbname ) const ; bool _isAuthorizedSpecialChecks( const string& dbname ) const ;
private: private:
mutable SpinLock _lock; mutable SpinLock _lock;
typedef map<string,Auth> MA; typedef map<string,Auth> MA;
MA _dbs; // dbname -> auth MA _dbs; // dbname -> auth
 End of changes. 9 change blocks. 
9 lines changed or deleted 21 lines changed or added


 server.h   server.h 
/** @file server.h /** @file server.h
This file contains includes commonly needed in the server files (mongod This file contains includes commonly needed in the server files (mongod
, mongos, test). It is NOT included in the C++ client. , mongos, test). It is *NOT* included in the C++ client; i.e.
this is a very good place for global-ish things that you don't need to
be in the client lib.
Over time we should move more here, and more out of pch.h. And get rid of pch.h at some point. Over time we should move more here, and more out of pch.h. And get rid of pch.h at some point.
*/ */
// todo is there a boost thign for this already?
#pragma once #pragma once
#if !defined(MONGO_EXPOSE_MACROS)
# error this file is for mongo server programs not client lib
#endif
#define BOOST_ENABLE_ASSERT_HANDLER 1
#include <map>
#include <vector>
#include <set>
#include "bson/inline_decls.h" #include "bson/inline_decls.h"
//using namespace std;
//using namespace bson;
/* Note: do not clutter code with these -- ONLY use in hot spots / signific ant loops. */ /* Note: do not clutter code with these -- ONLY use in hot spots / signific ant loops. */
// branch prediction. indicate we expect to be true // branch prediction. indicate we expect to be true
#define likely MONGO_likely #define likely MONGO_likely
// branch prediction. indicate we expect to be false // branch prediction. indicate we expect to be false
#define unlikely MONGO_unlikely #define unlikely MONGO_unlikely
// prefetch data from memory
//#define PREFETCH MONGOPREFETCH
#if defined(__GNUC__)
#define CACHEALIGN __attribute__((aligned(64))
#elif defined(_MSC_VER)
#define CACHEALIGN __declspec(align(64))
#else
#define CACHEALIGN
#endif
// log but not too fast. this is rather simplistic we can do something fan
cier later
#define LOGSOME static time_t __last; time_t __now=time(0); if(__last+5<__n
ow) {} else log()
 End of changes. 5 change blocks. 
4 lines changed or deleted 17 lines changed or added


 shard.h   shard.h 
skipping to change at line 30 skipping to change at line 30
#include "../pch.h" #include "../pch.h"
#include "../client/connpool.h" #include "../client/connpool.h"
namespace mongo { namespace mongo {
class ShardConnection; class ShardConnection;
class ShardStatus; class ShardStatus;
/* /*
* A "shard" is a database (replica pair typically) which represents * A "shard" one partition of the overall database (and a replica set t
* one partition of the overall database. ypically).
*/ */
class Shard { class Shard {
public: public:
Shard() Shard()
: _name("") , _addr("") , _maxSize(0) , _isDraining( false ) { : _name("") , _addr("") , _maxSize(0) , _isDraining( false ) {
} }
Shard( const string& name , const string& addr, long long maxSize = 0 , bool isDraining = false ) Shard( const string& name , const string& addr, long long maxSize = 0 , bool isDraining = false )
: _name(name) , _addr( addr ) , _maxSize( maxSize ) , _isDraini ng( isDraining ) { : _name(name) , _addr( addr ) , _maxSize( maxSize ) , _isDraini ng( isDraining ) {
skipping to change at line 126 skipping to change at line 125
} }
bool operator!=( const string& s ) const { bool operator!=( const string& s ) const {
return _name != s && _addr != s; return _name != s && _addr != s;
} }
bool operator<(const Shard& o) const { bool operator<(const Shard& o) const {
return _name < o._name; return _name < o._name;
} }
bool ok() const { bool ok() const { return _addr.size() > 0; }
return _addr.size() > 0 && _addr.size() > 0;
}
BSONObj runCommand( const string& db , const string& simple ) const { BSONObj runCommand( const string& db , const string& simple ) const {
return runCommand( db , BSON( simple << 1 ) ); return runCommand( db , BSON( simple << 1 ) );
} }
BSONObj runCommand( const string& db , const BSONObj& cmd ) const ; BSONObj runCommand( const string& db , const BSONObj& cmd ) const ;
ShardStatus getStatus() const ; ShardStatus getStatus() const ;
/** /**
* mostly for replica set * mostly for replica set
* retursn true if node is the shard * retursn true if node is the shard
* of if the replica set contains node * of if the replica set contains node
*/ */
bool containsNode( const string& node ) const; bool containsNode( const string& node ) const;
static void getAllShards( vector<Shard>& all ); static void getAllShards( vector<Shard>& all );
static void printShardInfo( ostream& out ); static void printShardInfo( ostream& out );
static Shard lookupRSName( const string& name);
/** /**
* @parm current - shard where the chunk/database currently lives i n * @parm current - shard where the chunk/database currently lives i n
* @return the currently emptiest shard, if best then current, or E MPTY * @return the currently emptiest shard, if best then current, or E MPTY
*/ */
static Shard pick( const Shard& current = EMPTY ); static Shard pick( const Shard& current = EMPTY );
static void reloadShardInfo(); static void reloadShardInfo();
static void removeShard( const string& name ); static void removeShard( const string& name );
skipping to change at line 213 skipping to change at line 211
return _hasOpsQueued; return _hasOpsQueued;
} }
private: private:
Shard _shard; Shard _shard;
long long _mapped; long long _mapped;
bool _hasOpsQueued; // true if 'writebacks' are pending bool _hasOpsQueued; // true if 'writebacks' are pending
double _writeLock; double _writeLock;
}; };
class ChunkManager;
typedef shared_ptr<const ChunkManager> ChunkManagerPtr;
class ShardConnection : public AScopedConnection { class ShardConnection : public AScopedConnection {
public: public:
ShardConnection( const Shard * s , const string& ns ); ShardConnection( const Shard * s , const string& ns, ChunkManagerPt
ShardConnection( const Shard& s , const string& ns ); r manager = ChunkManagerPtr() );
ShardConnection( const string& addr , const string& ns ); ShardConnection( const Shard& s , const string& ns, ChunkManagerPtr
manager = ChunkManagerPtr() );
ShardConnection( const string& addr , const string& ns, ChunkManage
rPtr manager = ChunkManagerPtr() );
~ShardConnection(); ~ShardConnection();
void done(); void done();
void kill(); void kill();
DBClientBase& conn() { DBClientBase& conn() {
_finishInit(); _finishInit();
assert( _conn ); assert( _conn );
return *_conn; return *_conn;
skipping to change at line 246 skipping to change at line 247
DBClientBase* get() { DBClientBase* get() {
_finishInit(); _finishInit();
assert( _conn ); assert( _conn );
return _conn; return _conn;
} }
string getHost() const { string getHost() const {
return _addr; return _addr;
} }
string getNS() const {
return _ns;
}
ChunkManagerPtr getManager() const {
return _manager;
}
bool setVersion() { bool setVersion() {
_finishInit(); _finishInit();
return _setVersion; return _setVersion;
} }
static void sync(); static void sync();
void donotCheckVersion() { void donotCheckVersion() {
_setVersion = false; _setVersion = false;
_finishedInit = true; _finishedInit = true;
skipping to change at line 276 skipping to change at line 285
static void checkMyConnectionVersions( const string & ns ); static void checkMyConnectionVersions( const string & ns );
private: private:
void _init(); void _init();
void _finishInit(); void _finishInit();
bool _finishedInit; bool _finishedInit;
string _addr; string _addr;
string _ns; string _ns;
ChunkManagerPtr _manager;
DBClientBase* _conn; DBClientBase* _conn;
bool _setVersion; bool _setVersion;
}; };
extern DBConnectionPool shardConnectionPool; extern DBConnectionPool shardConnectionPool;
class ShardingConnectionHook : public DBConnectionHook { class ShardingConnectionHook : public DBConnectionHook {
public: public:
ShardingConnectionHook( bool shardedConnections ) ShardingConnectionHook( bool shardedConnections )
 End of changes. 7 change blocks. 
8 lines changed or deleted 23 lines changed or added


 sock.h   sock.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 "../../pch.h" #include "../../pch.h"
#include <stdio.h> #include <stdio.h>
#include <sstream>
#include "../goodies.h"
#include "../../db/cmdline.h"
#include "../mongoutils/str.h"
#ifndef _WIN32 #ifndef _WIN32
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include <errno.h> #include <errno.h>
#ifdef __openbsd__ #ifdef __openbsd__
skipping to change at line 71 skipping to change at line 67
}; };
#else // _WIN32 #else // _WIN32
inline void closesocket(int s) { close(s); } inline void closesocket(int s) { close(s); }
const int INVALID_SOCKET = -1; const int INVALID_SOCKET = -1;
typedef int SOCKET; typedef int SOCKET;
#endif // _WIN32 #endif // _WIN32
inline string makeUnixSockPath(int port) { string makeUnixSockPath(int port);
return mongoutils::str::stream() << cmdLine.socket << "/mongodb-" <
< port << ".sock";
}
// If an ip address is passed in, just return that. If a hostname is p assed // If an ip address is passed in, just return that. If a hostname is p assed
// in, look up its ip and return that. Returns "" on failure. // in, look up its ip and return that. Returns "" on failure.
string hostbyname(const char *hostname); string hostbyname(const char *hostname);
void enableIPv6(bool state=true); void enableIPv6(bool state=true);
bool IPv6Enabled(); bool IPv6Enabled();
void setSockTimeouts(int sock, double secs); void setSockTimeouts(int sock, double secs);
/** /**
skipping to change at line 215 skipping to change at line 209
SockAddr remoteAddr() const { return _remote; } SockAddr remoteAddr() const { return _remote; }
string remoteString() const { return _remote.toString(); } string remoteString() const { return _remote.toString(); }
unsigned remotePort() const { return _remote.getPort(); } unsigned remotePort() const { return _remote.getPort(); }
void clearCounters() { _bytesIn = 0; _bytesOut = 0; } void clearCounters() { _bytesIn = 0; _bytesOut = 0; }
long long getBytesIn() const { return _bytesIn; } long long getBytesIn() const { return _bytesIn; }
long long getBytesOut() const { return _bytesOut; } long long getBytesOut() const { return _bytesOut; }
void setTimeout( double secs ); void setTimeout( double secs );
bool stillConnected();
#ifdef MONGO_SSL #ifdef MONGO_SSL
/** secures inline */ /** secures inline */
void secure( SSLManager * ssl ); void secure( SSLManager * ssl );
void secureAccepted( SSLManager * ssl ); void secureAccepted( SSLManager * ssl );
#endif #endif
/** /**
* call this after a fork for server sockets * call this after a fork for server sockets
*/ */
void postFork(); void postFork();
private: private:
void _init(); void _init();
/** raw send, same semantics as ::send */ /** raw send, same semantics as ::send */
public:
int _send( const char * data , int len ); int _send( const char * data , int len );
private:
/** sends dumbly, just each buffer at a time */ /** sends dumbly, just each buffer at a time */
void _send( const vector< pair< char *, int > > &data, const char * context ); void _send( const vector< pair< char *, int > > &data, const char * context );
/** raw recv, same semantics as ::recv */ /** raw recv, same semantics as ::recv */
int _recv( char * buf , int max ); int _recv( char * buf , int max );
int _fd; int _fd;
SockAddr _remote; SockAddr _remote;
double _timeout; double _timeout;
 End of changes. 6 change blocks. 
8 lines changed or deleted 6 lines changed or added


 spin_lock.h   spin_lock.h 
skipping to change at line 34 skipping to change at line 34
/** /**
* The spinlock currently requires late GCC support routines to be effi cient. * The spinlock currently requires late GCC support routines to be effi cient.
* Other platforms default to a mutex implemenation. * Other platforms default to a mutex implemenation.
*/ */
class SpinLock : boost::noncopyable { class SpinLock : boost::noncopyable {
public: public:
SpinLock(); SpinLock();
~SpinLock(); ~SpinLock();
void lock();
void unlock();
static bool isfast(); // true if a real spinlock on this platform static bool isfast(); // true if a real spinlock on this platform
private: private:
#if defined(_WIN32) #if defined(_WIN32)
CRITICAL_SECTION _cs; CRITICAL_SECTION _cs;
public:
void lock() {EnterCriticalSection(&_cs); }
void unlock() { LeaveCriticalSection(&_cs); }
#elif defined(__USE_XOPEN2K) #elif defined(__USE_XOPEN2K)
pthread_spinlock_t _lock; pthread_spinlock_t _lock;
void _lk();
public:
void unlock() { pthread_spin_unlock(&_lock); }
void lock() {
if ( pthread_spin_trylock( &_lock ) == 0 )
return;
_lk();
}
#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
volatile bool _locked; volatile bool _locked;
public:
void unlock() {__sync_lock_release(&_locked); }
void lock();
#else #else
// default to a mutex if not implemented // default to a mutex if not implemented
SimpleMutex _mutex; SimpleMutex _mutex;
public:
void unlock() { _mutex.unlock(); }
void lock() { _mutex.lock(); }
#endif #endif
}; };
class scoped_spinlock : boost::noncopyable { class scoped_spinlock : boost::noncopyable {
public: public:
scoped_spinlock( SpinLock& l ) : _l(l) { scoped_spinlock( SpinLock& l ) : _l(l) {
_l.lock(); _l.lock();
} }
~scoped_spinlock() { ~scoped_spinlock() {
_l.unlock();} _l.unlock();}
 End of changes. 5 change blocks. 
3 lines changed or deleted 17 lines changed or added


 str.h   str.h 
skipping to change at line 72 skipping to change at line 72
const char *s = str; const char *s = str;
const char *p = prefix; const char *p = prefix;
while( *p ) { while( *p ) {
if( *p != *s ) return false; if( *p != *s ) return false;
p++; s++; p++; s++;
} }
return true; return true;
} }
inline bool startsWith(string s, string p) { return startsWith(s.c_ str(), p.c_str()); } inline bool startsWith(string s, string p) { return startsWith(s.c_ str(), p.c_str()); }
// while these are trivial today use in case we do different wide c
har things later
inline bool startsWith(const char *p, char ch) { return *p == ch; }
inline bool startsWith(string s, char ch) { return startsWith(s.c_s
tr(), ch); }
inline bool endsWith(string s, string p) { inline bool endsWith(string s, string p) {
int l = p.size(); int l = p.size();
int x = s.size(); int x = s.size();
if( x < l ) return false; if( x < l ) return false;
return strncmp(s.c_str()+x-l, p.c_str(), l) == 0; return strncmp(s.c_str()+x-l, p.c_str(), l) == 0;
} }
inline bool endsWith(const char *s, char p) {
size_t len = strlen(s);
return len && s[len-1] == p;
}
inline bool equals( const char * a , const char * b ) { return strc mp( a , b ) == 0; } inline bool equals( const char * a , const char * b ) { return strc mp( a , b ) == 0; }
/** find char x, and return rest of string thereafter, or "" if not found */ /** find char x, and return rest of string thereafter, or "" if not found */
inline const char * after(const char *s, char x) { inline const char * after(const char *s, char x) {
const char *p = strchr(s, x); const char *p = strchr(s, x);
return (p != 0) ? p+1 : ""; return (p != 0) ? p+1 : "";
} }
inline string after(const string& s, char x) { inline string after(const string& s, char x) {
const char *p = strchr(s.c_str(), x); const char *p = strchr(s.c_str(), x);
 End of changes. 2 change blocks. 
0 lines changed or deleted 10 lines changed or added


 strategy.h   strategy.h 
skipping to change at line 34 skipping to change at line 34
namespace mongo { namespace mongo {
class Strategy { class Strategy {
public: public:
Strategy() {} Strategy() {}
virtual ~Strategy() {} virtual ~Strategy() {}
virtual void queryOp( Request& r ) = 0; virtual void queryOp( Request& r ) = 0;
virtual void getMore( Request& r ) = 0; virtual void getMore( Request& r ) = 0;
virtual void writeOp( int op , Request& r ) = 0; virtual void writeOp( int op , Request& r ) = 0;
virtual void insertSharded( DBConfigPtr conf, const char* ns, BSONO void insert( const Shard& shard , const char * ns , const BSONObj&
bj& o, int flags, bool safe=false, const char* nsChunkLookup=0 ) = 0; obj , int flags=0 , bool safe=false );
virtual void updateSharded( DBConfigPtr conf, const char* ns, BSONO
bj& query, BSONObj& toupdate, int flags, bool safe=false ) = 0; virtual void commandOp( const string& db, const BSONObj& command, i
nt options,
const string& versionedNS, const BSONObj& f
ilter,
map<Shard,BSONObj>& results )
{
// Only call this from sharded, for now.
// TODO: Refactor all this.
assert( false );
}
protected: protected:
void doWrite( int op , Request& r , const Shard& shard , bool check Version = true ); void doWrite( int op , Request& r , const Shard& shard , bool check Version = true );
void doQuery( Request& r , const Shard& shard ); void doQuery( Request& r , const Shard& shard );
void insert( const Shard& shard , const char * ns , const BSONObj& obj , int flags=0 , bool safe=false ); void insert( const Shard& shard , const char * ns , const vector<BS ONObj>& v , int flags=0 , bool safe=false );
void update( const Shard& shard , const char * ns , const BSONObj& query , const BSONObj& toupdate , int flags=0, bool safe=false ); void update( const Shard& shard , const char * ns , const BSONObj& query , const BSONObj& toupdate , int flags=0, bool safe=false );
}; };
extern Strategy * SINGLE; extern Strategy * SINGLE;
extern Strategy * SHARDED; extern Strategy * SHARDED;
} }
 End of changes. 2 change blocks. 
5 lines changed or deleted 14 lines changed or added


 syncclusterconnection.h   syncclusterconnection.h 
skipping to change at line 79 skipping to change at line 79
virtual void insert( const string &ns, BSONObj obj, int flags=0); virtual void insert( const string &ns, BSONObj obj, int flags=0);
virtual void insert( const string &ns, const vector< BSONObj >& v, int flags=0); virtual void insert( const string &ns, const vector< BSONObj >& v, int flags=0);
virtual void remove( const string &ns , Query query, bool justOne ) ; virtual void remove( const string &ns , Query query, bool justOne ) ;
virtual void update( const string &ns , Query query , BSONObj obj , bool upsert , bool multi ); virtual void update( const string &ns , Query query , BSONObj obj , bool upsert , bool multi );
virtual bool call( Message &toSend, Message &response, bool assertO k , string * actualServer ); virtual bool call( Message &toSend, Message &response, bool assertO k , string * actualServer );
virtual void say( Message &toSend, bool isRetry = false ); virtual void say( Message &toSend, bool isRetry = false , string * actualServer = 0 );
virtual void sayPiggyBack( Message &toSend ); virtual void sayPiggyBack( Message &toSend );
virtual void killCursor( long long cursorID ); virtual void killCursor( long long cursorID );
virtual string getServerAddress() const { return _address; } virtual string getServerAddress() const { return _address; }
virtual bool isFailed() const { return false; } virtual bool isFailed() const { return false; }
virtual string toString() { return _toString(); } virtual string toString() { return _toString(); }
virtual BSONObj getLastErrorDetailed(); virtual BSONObj getLastErrorDetailed(bool fsync=false, bool j=false , int w=0, int wtimeout=0);
virtual bool callRead( Message& toSend , Message& response ); virtual bool callRead( Message& toSend , Message& response );
virtual ConnectionString::ConnectionType type() const { return Conn ectionString::SYNC; } virtual ConnectionString::ConnectionType type() const { return Conn ectionString::SYNC; }
void setAllSoTimeouts( double socketTimeout ); void setAllSoTimeouts( double socketTimeout );
double getSoTimeout() const { return _socketTimeout; } double getSoTimeout() const { return _socketTimeout; }
virtual bool auth(const string &dbname, const string &username, con st string &password_text, string& errmsg, bool digestPassword); virtual bool auth(const string &dbname, const string &username, con st string &password_text, string& errmsg, bool digestPassword, Auth::Level* level=NULL);
virtual bool lazySupported() const { return false; } virtual bool lazySupported() const { return false; }
private: private:
SyncClusterConnection( SyncClusterConnection& prev, double socketTi meout = 0 ); SyncClusterConnection( SyncClusterConnection& prev, double socketTi meout = 0 );
string _toString() const; string _toString() const;
bool _commandOnActive(const string &dbname, const BSONObj& cmd, BSO NObj &info, int options=0); bool _commandOnActive(const string &dbname, const BSONObj& cmd, BSO NObj &info, int options=0);
auto_ptr<DBClientCursor> _queryOnActive(const string &ns, Query que ry, int nToReturn, int nToSkip, auto_ptr<DBClientCursor> _queryOnActive(const string &ns, Query que ry, int nToReturn, int nToSkip,
const BSONObj *fieldsToRetu rn, int queryOptions, int batchSize ); const BSONObj *fieldsToRetu rn, int queryOptions, int batchSize );
int _lockType( const string& name ); int _lockType( const string& name );
void _checkLast(); void _checkLast();
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 synchronization.h   synchronization.h 
skipping to change at line 31 skipping to change at line 31
#include "mutex.h" #include "mutex.h"
namespace mongo { namespace mongo {
/* /*
* A class to establish a synchronization point between two threads. On e thread is the waiter and one is * A class to establish a synchronization point between two threads. On e thread is the waiter and one is
* the notifier. After the notification event, both proceed normally. * the notifier. After the notification event, both proceed normally.
* *
* This class is thread-safe. * This class is thread-safe.
*/ */
class Notification { class Notification : boost::noncopyable {
public: public:
Notification(); Notification();
~Notification();
/* /*
* Blocks until the method 'notifyOne()' is called. * Blocks until the method 'notifyOne()' is called.
*/ */
void waitToBeNotified(); void waitToBeNotified();
/* /*
* Notifies the waiter of '*this' that it can proceed. Can only be called once. * Notifies the waiter of '*this' that it can proceed. Can only be called once.
*/ */
void notifyOne(); void notifyOne();
private: private:
mongo::mutex _mutex; // protects state below mongo::mutex _mutex; // protects state below
bool _notified; // was notifyOne() issued? unsigned long long lookFor;
unsigned long long cur;
boost::condition _condition; // cond over _notified being true boost::condition _condition; // cond over _notified being true
}; };
/** establishes a synchronization point between threads. N threads are waits and one is notifier. /** establishes a synchronization point between threads. N threads are waits and one is notifier.
threadsafe. threadsafe.
*/ */
class NotifyAll : boost::noncopyable { class NotifyAll : boost::noncopyable {
public: public:
NotifyAll(); NotifyAll();
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 taskqueue.h   taskqueue.h 
skipping to change at line 49 skipping to change at line 49
see DefInvoke in dbtests/ for an example. see DefInvoke in dbtests/ for an example.
*/ */
template< class MT > template< class MT >
class TaskQueue { class TaskQueue {
public: public:
TaskQueue() : _which(0), _invokeMutex("deferredinvoker") { } TaskQueue() : _which(0), _invokeMutex("deferredinvoker") { }
void defer(MT mt) { void defer(MT mt) {
// only one writer allowed. however the invoke processing belo w can occur concurrently with // only one writer allowed. however the invoke processing belo w can occur concurrently with
// writes (for the most part) // writes (for the most part)
DEV dbMutex.assertWriteLocked(); DEV d.dbMutex.assertWriteLocked();
_queues[_which].push_back(mt); _queues[_which].push_back(mt);
} }
/** call to process deferrals. /** call to process deferrals.
concurrency: handled herein. multiple threads could call invok e(), but their efforts will be concurrency: handled herein. multiple threads could call invok e(), but their efforts will be
serialized. the common case is that there is a si ngle processor calling invoke(). serialized. the common case is that there is a si ngle processor calling invoke().
normally, you call this outside of any lock. but if you want t o fully drain the queue, normally, you call this outside of any lock. but if you want t o fully drain the queue,
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 text.h   text.h 
skipping to change at line 48 skipping to change at line 48
public: public:
/** @param big the string to be split /** @param big the string to be split
@param splitter the delimiter @param splitter the delimiter
*/ */
StringSplitter( const char * big , const char * splitter ) StringSplitter( const char * big , const char * splitter )
: _big( big ) , _splitter( splitter ) { : _big( big ) , _splitter( splitter ) {
} }
/** @return true if more to be taken via next() */ /** @return true if more to be taken via next() */
bool more() { bool more() {
return _big[0]; return _big[0] != 0;
} }
/** get next split string fragment */ /** get next split string fragment */
string next() { string next() {
const char * foo = strstr( _big , _splitter ); const char * foo = strstr( _big , _splitter );
if ( foo ) { if ( foo ) {
string s( _big , foo - _big ); string s( _big , foo - _big );
_big = foo + 1; _big = foo + 1;
while ( *_big && strstr( _big , _splitter ) == _big ) while ( *_big && strstr( _big , _splitter ) == _big )
_big++; _big++;
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 time_support.h   time_support.h 
skipping to change at line 22 skipping to change at line 22
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include <cstdio> // sscanf #include <cstdio> // sscanf
#include <ctime> #include <ctime>
#include <boost/thread/thread.hpp>
#include <boost/thread/tss.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/xtime.hpp> #include <boost/thread/xtime.hpp>
#undef assert #undef assert
#define assert MONGO_assert #define assert MONGO_assert
#include "../bson/util/misc.h" // Date_t
namespace mongo { namespace mongo {
inline void time_t_to_Struct(time_t t, struct tm * buf , bool local = f alse ) { inline void time_t_to_Struct(time_t t, struct tm * buf , bool local = f alse ) {
#if defined(_WIN32) #if defined(_WIN32)
if ( local ) if ( local )
localtime_s( buf , &t ); localtime_s( buf , &t );
else else
gmtime_s(buf, &t); gmtime_s(buf, &t);
#else #else
skipping to change at line 99 skipping to change at line 102
#define asctime MONGO_asctime #define asctime MONGO_asctime
#define MONGO_gmtime _gmtime_not_threadsafe_ #define MONGO_gmtime _gmtime_not_threadsafe_
#define gmtime MONGO_gmtime #define gmtime MONGO_gmtime
#define MONGO_localtime _localtime_not_threadsafe_ #define MONGO_localtime _localtime_not_threadsafe_
#define localtime MONGO_localtime #define localtime MONGO_localtime
#define MONGO_ctime _ctime_is_not_threadsafe_ #define MONGO_ctime _ctime_is_not_threadsafe_
#define ctime MONGO_ctime #define ctime MONGO_ctime
#if defined(_WIN32) #if defined(_WIN32)
inline void sleepsecs(int s) { inline void sleepsecs(int s) {
// todo : add an assert here that we are not locked in d.dbMutex.
there may be debugging things where we
// are but otherwise it's quite likely that would be a mista
ke.
Sleep(s*1000); Sleep(s*1000);
} }
inline void sleepmillis(long long s) { inline void sleepmillis(long long s) {
assert( s <= 0xffffffff ); assert( s <= 0xffffffff );
Sleep((DWORD) s); Sleep((DWORD) s);
} }
inline void sleepmicros(long long s) { inline void sleepmicros(long long s) {
if ( s <= 0 ) if ( s <= 0 )
return; return;
boost::xtime xt; boost::xtime xt;
 End of changes. 3 change blocks. 
0 lines changed or deleted 7 lines changed or added


 timer.h   timer.h 
skipping to change at line 24 skipping to change at line 24
* 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 "time_support.h" #include "time_support.h"
namespace mongo { namespace mongo {
#if !defined(_WIN32)
/** /**
* simple scoped timer * simple scoped timer
*/ */
class Timer /*copyable*/ { class Timer /*copyable*/ {
public: public:
Timer() { reset(); } Timer() { reset(); }
Timer( unsigned long long startMicros ) { old = startMicros; }
int seconds() const { return (int)(micros() / 1000000); } int seconds() const { return (int)(micros() / 1000000); }
int millis() const { return (int)(micros() / 1000); } int millis() const { return (int)(micros() / 1000); }
int minutes() const { return seconds() / 60; } int minutes() const { return seconds() / 60; }
/** gets time interval and resets at the same time. this way we ca n call curTimeMicros /** gets time interval and resets at the same time. this way we ca n call curTimeMicros
once instead of twice if one wanted millis() and then reset() . once instead of twice if one wanted millis() and then reset() .
@return time in millis @return time in millis
*/ */
int millisReset() { int millisReset() {
unsigned long long now = curTimeMicros64(); unsigned long long now = curTimeMicros64();
skipping to change at line 56 skipping to change at line 57
// note: dubious that the resolution is as anywhere near as high as ethod name implies! // note: dubious that the resolution is as anywhere near as high as ethod name implies!
unsigned long long micros() const { unsigned long long micros() const {
unsigned long long n = curTimeMicros64(); unsigned long long n = curTimeMicros64();
return n - old; return n - old;
} }
unsigned long long micros(unsigned long long & n) const { // return s cur time in addition to timer result unsigned long long micros(unsigned long long & n) const { // return s cur time in addition to timer result
n = curTimeMicros64(); n = curTimeMicros64();
return n - old; return n - old;
} }
unsigned long long startTime() const { return old; }
void reset() { old = curTimeMicros64(); } void reset() { old = curTimeMicros64(); }
private: private:
unsigned long long old; unsigned long long old;
}; };
#if 1 #else
class DevTimer {
public: class Timer /*copyable*/ {
class scoped {
public:
scoped(DevTimer& dt) { }
~scoped() { }
};
DevTimer(string) { }
~DevTimer() { }
};
#elif defined(_WIN32)
class DevTimer {
const string _name;
public: public:
unsigned long long _ticks; Timer() { reset(); }
class scoped {
DevTimer& _dt; int seconds() const {
unsigned long long _start; int s = static_cast<int>((now() - old) / countsPerSecond);
public: return s;
scoped(DevTimer& dt) : _dt(dt) { }
LARGE_INTEGER i;
QueryPerformanceCounter(&i); int millis() const {
_start = i.QuadPart; return (int)
} ((now() - old) * 1000.0 / countsPerSecond);
~scoped() { }
LARGE_INTEGER i;
QueryPerformanceCounter(&i); int minutes() const { return seconds() / 60; }
_dt._ticks += (i.QuadPart - _start);
} /** gets time interval and resets at the same time. this way we ca
}; n call curTimeMicros
DevTimer(string name) : _name(name), _ticks(0) { once instead of twice if one wanted millis() and then reset()
} .
~DevTimer() { @return time in millis
LARGE_INTEGER freq; */
assert( QueryPerformanceFrequency(&freq) ); int millisReset() {
cout << "devtimer\t" << _name << '\t' << _ticks*1000.0/freq.Qua unsigned long long nw = now();
dPart << "ms" << endl; int m = static_cast<int>((nw - old) * 1000.0 / countsPerSecond)
;
old = nw;
return m;
}
void reset() {
old = now();
}
unsigned long long micros() const {
return (unsigned long long)
((now() - old) * 1000000.0 / countsPerSecond);
} }
static unsigned long long countsPerSecond;
private:
unsigned long long now() const {
LARGE_INTEGER i;
QueryPerformanceCounter(&i);
return i.QuadPart;
}
unsigned long long old;
}; };
#endif #endif
} // namespace mongo } // namespace mongo
 End of changes. 7 change blocks. 
39 lines changed or deleted 52 lines changed or added


 tool.h   tool.h 
skipping to change at line 32 skipping to change at line 32
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#if defined(_WIN32) #if defined(_WIN32)
#include <io.h> #include <io.h>
#endif #endif
#include "client/dbclient.h" #include "client/dbclient.h"
#include "db/instance.h" #include "db/instance.h"
#include "db/matcher.h" #include "db/matcher.h"
#include "db/security.h"
using std::string; using std::string;
namespace mongo { namespace mongo {
class Tool { class Tool {
public: public:
enum DBAccess { enum DBAccess {
NONE = 0 , NONE = 0 ,
REMOTE_SERVER = 1 << 1 , REMOTE_SERVER = 1 << 1 ,
skipping to change at line 106 skipping to change at line 107
virtual void printHelp(ostream &out); virtual void printHelp(ostream &out);
virtual void printExtraHelp( ostream & out ) {} virtual void printExtraHelp( ostream & out ) {}
virtual void printExtraHelpAfter( ostream & out ) {} virtual void printExtraHelpAfter( ostream & out ) {}
virtual void printVersion(ostream &out); virtual void printVersion(ostream &out);
protected: protected:
mongo::DBClientBase &conn( bool slaveIfPaired = false ); mongo::DBClientBase &conn( bool slaveIfPaired = false );
void auth( string db = "" ); void auth( string db = "", Auth::Level * level = NULL);
string _name; string _name;
string _db; string _db;
string _coll; string _coll;
string _fileName; string _fileName;
string _username; string _username;
string _password; string _password;
skipping to change at line 155 skipping to change at line 156
auto_ptr<Matcher> _matcher; auto_ptr<Matcher> _matcher;
public: public:
BSONTool( const char * name , DBAccess access=ALL, bool objcheck = false ); BSONTool( const char * name , DBAccess access=ALL, bool objcheck = false );
virtual int doRun() = 0; virtual int doRun() = 0;
virtual void gotObject( const BSONObj& obj ) = 0; virtual void gotObject( const BSONObj& obj ) = 0;
virtual int run(); virtual int run();
long long processFile( const path& file ); long long processFile( const boost::filesystem::path& file );
}; };
} }
 End of changes. 3 change blocks. 
2 lines changed or deleted 3 lines changed or added


 top.h   top.h 
skipping to change at line 89 skipping to change at line 89
void _appendToUsageMap( BSONObjBuilder& b , const UsageMap& map ) c onst; void _appendToUsageMap( BSONObjBuilder& b , const UsageMap& map ) c onst;
void _appendStatsEntry( BSONObjBuilder& b , const char * statsName , const UsageData& map ) const; void _appendStatsEntry( BSONObjBuilder& b , const char * statsName , const UsageData& map ) const;
void _record( CollectionData& c , int op , int lockType , long long micros , bool command ); void _record( CollectionData& c , int op , int lockType , long long micros , bool command );
mutable mongo::mutex _lock; mutable mongo::mutex _lock;
CollectionData _global; CollectionData _global;
UsageMap _usage; UsageMap _usage;
string _lastDropped; string _lastDropped;
}; };
/* Records per namespace utilization of the mongod process.
No two functions of this class may be called concurrently.
*/
class TopOld {
typedef boost::posix_time::ptime T;
typedef boost::posix_time::time_duration D;
typedef boost::tuple< D, int, int, int > UsageData;
public:
TopOld() : _read(false), _write(false) { }
/* these are used to record activity: */
void clientStart( const char *client ) {
clientStop();
_currentStart = currentTime();
_current = client;
}
/* indicate current request is a read operation. */
void setRead() { _read = true; }
void setWrite() { _write = true; }
void clientStop() {
if ( _currentStart == T() )
return;
D d = currentTime() - _currentStart;
{
scoped_lock L(topMutex);
recordUsage( _current, d );
}
_currentStart = T();
_read = false;
_write = false;
}
/* these are used to fetch the stats: */
struct Usage {
string ns;
D time;
double pct;
int reads, writes, calls;
};
static void usage( vector< Usage > &res ) {
scoped_lock L(topMutex);
// Populate parent namespaces
UsageMap snapshot;
UsageMap totalUsage;
fillParentNamespaces( snapshot, _snapshot );
fillParentNamespaces( totalUsage, _totalUsage );
multimap< D, string, more > sorted;
for( UsageMap::iterator i = snapshot.begin(); i != snapshot.end
(); ++i )
sorted.insert( make_pair( i->second.get<0>(), i->first ) );
for( multimap< D, string, more >::iterator i = sorted.begin();
i != sorted.end(); ++i ) {
if ( trivialNs( i->second.c_str() ) )
continue;
Usage u;
u.ns = i->second;
u.time = totalUsage[ u.ns ].get<0>();
u.pct = _snapshotDuration != D() ? 100.0 * i->first.ticks()
/ _snapshotDuration.ticks() : 0;
u.reads = snapshot[ u.ns ].get<1>();
u.writes = snapshot[ u.ns ].get<2>();
u.calls = snapshot[ u.ns ].get<3>();
res.push_back( u );
}
for( UsageMap::iterator i = totalUsage.begin(); i != totalUsage
.end(); ++i ) {
if ( snapshot.count( i->first ) != 0 || trivialNs( i->first
.c_str() ) )
continue;
Usage u;
u.ns = i->first;
u.time = i->second.get<0>();
u.pct = 0;
u.reads = 0;
u.writes = 0;
u.calls = 0;
res.push_back( u );
}
}
static void completeSnapshot() {
scoped_lock L(topMutex);
if ( &_snapshot == &_snapshotA ) {
_snapshot = _snapshotB;
_nextSnapshot = _snapshotA;
}
else {
_snapshot = _snapshotA;
_nextSnapshot = _snapshotB;
}
_snapshotDuration = currentTime() - _snapshotStart;
_snapshotStart = currentTime();
_nextSnapshot.clear();
}
private:
static mongo::mutex topMutex;
static bool trivialNs( const char *ns ) {
const char *ret = strrchr( ns, '.' );
return ret && ret[ 1 ] == '\0';
}
typedef map<string,UsageData> UsageMap; // duration, # reads, # wri
tes, # total calls
static T currentTime() {
return boost::posix_time::microsec_clock::universal_time();
}
void recordUsage( const string &client, D duration ) {
recordUsageForMap( _totalUsage, client, duration );
recordUsageForMap( _nextSnapshot, client, duration );
}
void recordUsageForMap( UsageMap &map, const string &client, D dura
tion ) {
UsageData& g = map[client];
g.get< 0 >() += duration;
if ( _read && !_write )
g.get< 1 >()++;
else if ( !_read && _write )
g.get< 2 >()++;
g.get< 3 >()++;
}
static void fillParentNamespaces( UsageMap &to, const UsageMap &fro
m ) {
for( UsageMap::const_iterator i = from.begin(); i != from.end()
; ++i ) {
string current = i->first;
size_t dot = current.rfind( "." );
if ( dot == string::npos || dot != current.length() - 1 ) {
inc( to[ current ], i->second );
}
while( dot != string::npos ) {
current = current.substr( 0, dot );
inc( to[ current ], i->second );
dot = current.rfind( "." );
}
}
}
static void inc( UsageData &to, const UsageData &from ) {
to.get<0>() += from.get<0>();
to.get<1>() += from.get<1>();
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; } };
string _current;
T _currentStart;
static T _snapshotStart;
static D _snapshotDuration;
static UsageMap _totalUsage;
static UsageMap _snapshotA;
static UsageMap _snapshotB;
static UsageMap &_snapshot;
static UsageMap &_nextSnapshot;
bool _read;
bool _write;
};
} // namespace mongo } // namespace mongo
 End of changes. 1 change blocks. 
168 lines changed or deleted 0 lines changed or added


 undef_macros.h   undef_macros.h 
skipping to change at line 22 skipping to change at line 22
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
// If you define a new global un-prefixed macro, please add it here and in redef_macros // If you define a new global un-prefixed macro, please add it here and in redef_macros
// #pragma once // this file is intended to be processed multiple times // #pragma once // this file is intended to be processed multiple times
#if !defined (MONGO_EXPOSE_MACROS) /** MONGO_EXPOSE_MACROS - when defined, indicates that you are compiling a
mongo program rather
#ifdef MONGO_MACROS_PUSHED than just using the C++ driver.
*/
#if !defined(MONGO_EXPOSE_MACROS) && !defined(MONGO_MACROS_CLEANED)
// util/allocator.h // util/allocator.h
#undef malloc #undef malloc
#pragma pop_macro("malloc")
#undef realloc #undef realloc
#pragma pop_macro("realloc")
// util/assert_util.h // util/assert_util.h
#undef assert #undef assert
#pragma pop_macro("assert")
#undef dassert #undef dassert
#pragma pop_macro("dassert")
#undef wassert #undef wassert
#pragma pop_macro("wassert")
#undef massert #undef massert
#pragma pop_macro("massert")
#undef uassert #undef uassert
#pragma pop_macro("uassert")
#undef BOOST_CHECK_EXCEPTION #undef BOOST_CHECK_EXCEPTION
#undef verify
#pragma pop_macro("verify")
#undef DESTRUCTOR_GUARD #undef DESTRUCTOR_GUARD
#pragma pop_macro("DESTRUCTOR_GUARD")
// util/goodies.h // util/goodies.h
#undef PRINT #undef PRINT
#pragma pop_macro("PRINT")
#undef PRINTFL #undef PRINTFL
#pragma pop_macro("PRINTFL")
#undef asctime #undef asctime
#pragma pop_macro("asctime")
#undef gmtime #undef gmtime
#pragma pop_macro("gmtime")
#undef localtime #undef localtime
#pragma pop_macro("localtime")
#undef ctime #undef ctime
#pragma pop_macro("ctime")
// util/debug_util.h // util/debug_util.h
#undef DEV #undef DEV
#pragma pop_macro("DEV")
#undef DEBUGGING #undef DEBUGGING
#pragma pop_macro("DEBUGGING")
#undef SOMETIMES #undef SOMETIMES
#pragma pop_macro("SOMETIMES")
#undef OCCASIONALLY #undef OCCASIONALLY
#pragma pop_macro("OCCASIONALLY")
#undef RARELY #undef RARELY
#pragma pop_macro("RARELY")
#undef ONCE #undef ONCE
#pragma pop_macro("ONCE")
// util/log.h // util/log.h
#undef LOG #undef LOG
#pragma pop_macro("LOG")
#undef MONGO_MACROS_PUSHED #define MONGO_MACROS_CLEANED
#endif
#endif #endif
 End of changes. 24 change blocks. 
28 lines changed or deleted 6 lines changed or added


 update.h   update.h 
skipping to change at line 29 skipping to change at line 29
#include "../../pch.h" #include "../../pch.h"
#include "../jsobj.h" #include "../jsobj.h"
#include "../../util/embedded_builder.h" #include "../../util/embedded_builder.h"
#include "../matcher.h" #include "../matcher.h"
namespace mongo { namespace mongo {
// ---------- public ------------- // ---------- public -------------
struct UpdateResult { struct UpdateResult {
bool existing; // if existing objects were modified const bool existing; // if existing objects were modified
bool mod; // was this a $ mod const bool mod; // was this a $ mod
long long num; // how many objects touched const long long num; // how many objects touched
OID upserted; // if something was upserted, the new _id of the obj ect OID upserted; // if something was upserted, the new _id of the obj ect
UpdateResult( bool e, bool m, unsigned long long n , const BSONObj& upsertedObject = BSONObj() ) UpdateResult( bool e, bool m, unsigned long long n , const BSONObj& upsertedObject = BSONObj() )
: existing(e) , mod(m), num(n) { : existing(e) , mod(m), num(n) {
upserted.clear(); upserted.clear();
BSONElement id = upsertedObject["_id"]; BSONElement id = upsertedObject["_id"];
if ( ! e && n == 1 && id.type() == jstOID ) { if ( ! e && n == 1 && id.type() == jstOID ) {
upserted = id.OID(); upserted = id.OID();
} }
} }
}; };
class RemoveSaver; class RemoveSaver;
/* returns true if an existing object was updated, false if no existing object was found. /* returns true if an existing object was updated, false if no existing object was found.
multi - update multiple objects - mostly useful with things like $se t multi - update multiple objects - mostly useful with things like $se t
god - allow access to system namespaces god - allow access to system namespaces
*/ */
UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BS ONObj pattern, bool upsert, bool multi , bool logop , OpDebug& debug, bool hintIdElseNatural = false ); UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BS ONObj pattern, bool upsert, bool multi , bool logop , OpDebug& debug );
UpdateResult _updateObjects(bool god, const char *ns, const BSONObj& up dateobj, BSONObj pattern, UpdateResult _updateObjects(bool god, const char *ns, const BSONObj& up dateobj, BSONObj pattern,
bool upsert, bool multi , bool logop , OpDe bool upsert, bool multi , bool logop , OpDe
bug& debug , RemoveSaver * rs = 0, bug& debug , RemoveSaver * rs = 0 );
bool hintIdElseNatural = false);
// ---------- private ------------- // ---------- private -------------
class ModState; class ModState;
class ModSetState; class ModSetState;
/* Used for modifiers such as $inc, $set, $push, ... /* Used for modifiers such as $inc, $set, $push, ...
* stores the info about a single operation * stores the info about a single operation
* once created should never be modified * once created should never be modified
*/ */
skipping to change at line 186 skipping to change at line 183
} }
bool isIndexed( const set<string>& idxKeys ) const { bool isIndexed( const set<string>& idxKeys ) const {
string fullName = fieldName; string fullName = fieldName;
if ( isIndexed( fullName , idxKeys ) ) if ( isIndexed( fullName , idxKeys ) )
return true; return true;
if ( strstr( fieldName , "." ) ) { if ( strstr( fieldName , "." ) ) {
// check for a.0.1 // check for a.0.1
StringBuilder buf( fullName.size() + 1 ); StringBuilder buf;
for ( size_t i=0; i<fullName.size(); i++ ) { for ( size_t i=0; i<fullName.size(); i++ ) {
char c = fullName[i]; char c = fullName[i];
if ( c == '$' && if ( c == '$' &&
i > 0 && fullName[i-1] == '.' && i > 0 && fullName[i-1] == '.' &&
i+1<fullName.size() && i+1<fullName.size() &&
fullName[i+1] == '.' ) { fullName[i+1] == '.' ) {
i++; i++;
continue; continue;
} }
skipping to change at line 580 skipping to change at line 577
void appendNewFromMod( ModState& ms , Builder& b ) { void appendNewFromMod( ModState& ms , Builder& b ) {
if ( ms.dontApply ) { if ( ms.dontApply ) {
return; return;
} }
//const Mod& m = *(ms.m); // HACK //const Mod& m = *(ms.m); // HACK
Mod& m = *((Mod*)(ms.m)); // HACK Mod& m = *((Mod*)(ms.m)); // HACK
switch ( m.op ) { switch ( m.op ) {
case Mod::PUSH: case Mod::PUSH: {
if ( m.isEach() ) {
b.appendArray( m.shortFieldName, m.getEach() );
} else {
BSONObjBuilder arr( b.subarrayStart( m.shortFieldName )
);
arr.appendAs( m.elt, "0" );
arr.done();
}
break;
}
case Mod::ADDTOSET: { case Mod::ADDTOSET: {
if ( m.isEach() ) { if ( m.isEach() ) {
b.appendArray( m.shortFieldName , m.getEach() ); // Remove any duplicates in given array
BSONObjBuilder arr( b.subarrayStart( m.shortFieldName )
);
BSONElementSet toadd;
m.parseEach( toadd );
BSONObjIterator i( m.getEach() );
int n = 0;
while ( i.more() ) {
BSONElement e = i.next();
if ( toadd.count(e) ) {
arr.appendAs( e , BSONObjBuilder::numStr( n++ )
);
toadd.erase( e );
}
}
arr.done();
} }
else { else {
BSONObjBuilder arr( b.subarrayStart( m.shortFieldName ) ); BSONObjBuilder arr( b.subarrayStart( m.shortFieldName ) );
arr.appendAs( m.elt, "0" ); arr.appendAs( m.elt, "0" );
arr.done(); arr.done();
} }
break; break;
} }
case Mod::PUSH_ALL: { case Mod::PUSH_ALL: {
skipping to change at line 623 skipping to change at line 642
ms.handleRename( b, m.shortFieldName ); ms.handleRename( b, m.shortFieldName );
break; break;
default: default:
stringstream ss; stringstream ss;
ss << "unknown mod in appendNewFromMod: " << m.op; ss << "unknown mod in appendNewFromMod: " << m.op;
throw UserException( 9015, ss.str() ); throw UserException( 9015, ss.str() );
} }
} }
/** @return true iff the elements aren't eoo(), are distinct, and s
hare a field name. */
static bool duplicateFieldName( const BSONElement &a, const BSONEle
ment &b );
public: public:
bool canApplyInPlace() const { bool canApplyInPlace() const {
return _inPlacePossible; return _inPlacePossible;
} }
/** /**
* modified underlying _obj * modified underlying _obj
* @param isOnDisk - true means this is an on disk object, and this update needs to be made durable * @param isOnDisk - true means this is an on disk object, and this update needs to be made durable
*/ */
 End of changes. 9 change blocks. 
17 lines changed or deleted 34 lines changed or added


 util.h   util.h 
skipping to change at line 124 skipping to change at line 124
inline ostream& operator<<( ostream &s , const ShardChunkVersion& v) { inline ostream& operator<<( ostream &s , const ShardChunkVersion& v) {
s << v._major << "|" << v._minor; s << v._major << "|" << v._minor;
return s; return s;
} }
/** /**
* your config info for a given shard/chunk is out of date * your config info for a given shard/chunk is out of date
*/ */
class StaleConfigException : public AssertionException { class StaleConfigException : public AssertionException {
public: public:
StaleConfigException( const string& ns , const string& raw , bool j StaleConfigException( const string& ns , const string& raw , int co
ustConnection = false ) de, bool justConnection = false )
: AssertionException( (string)"ns: " + ns + " " + raw , 9996 ) : AssertionException( (string)"ns: " + ns + " " + raw , code )
, ,
_justConnection(justConnection) , _justConnection(justConnection) ,
_ns(ns) { _ns(ns) {
} }
virtual ~StaleConfigException() throw() {} virtual ~StaleConfigException() throw() {}
virtual void appendPrefix( stringstream& ss ) const { ss << "stale sharding config exception: "; } virtual void appendPrefix( stringstream& ss ) const { ss << "stale sharding config exception: "; }
bool justConnection() const { return _justConnection; } bool justConnection() const { return _justConnection; }
skipping to change at line 155 skipping to change at line 155
ns = big.substr( start + 1 , ( end - start ) - 1 ); ns = big.substr( start + 1 , ( end - start ) - 1 );
raw = big.substr( end + 1 ); raw = big.substr( end + 1 );
return true; return true;
} }
private: private:
bool _justConnection; bool _justConnection;
string _ns; string _ns;
}; };
extern boost::function1<bool, DBClientBase* > isVersionableCB; class SendStaleConfigException : public StaleConfigException {
extern boost::function2<bool, DBClientBase&, BSONObj& > initShardVersio public:
nCB; SendStaleConfigException( const string& ns , const string& raw , bo
extern boost::function4<bool, DBClientBase&, const string&, bool, int> ol justConnection = false )
checkShardVersionCB; : StaleConfigException( ns, raw + "(send)", SendStaleConfigCode
extern boost::function1<void, DBClientBase*> resetShardVersionCB; , justConnection ) {}
};
class RecvStaleConfigException : public StaleConfigException {
public:
RecvStaleConfigException( const string& ns , const string& raw , bo
ol justConnection = false )
: StaleConfigException( ns, raw + "(recv)", RecvStaleConfigCode
, justConnection ) {}
};
class ShardConnection;
class VersionManager {
public:
VersionManager(){};
bool isVersionableCB( DBClientBase* );
bool initShardVersionCB( DBClientBase*, BSONObj& );
bool forceRemoteCheckShardVersionCB( const string& );
bool checkShardVersionCB( DBClientBase*, const string&, bool, int )
;
bool checkShardVersionCB( ShardConnection*, bool, int );
void resetShardVersionCB( DBClientBase* );
};
extern VersionManager versionManager;
} }
 End of changes. 2 change blocks. 
10 lines changed or deleted 36 lines changed or added


 utils.h   utils.h 
skipping to change at line 44 skipping to change at line 44
// 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 ); void initScope( Scope &scope );
void onConnect( DBClientWithCommands &c ); void onConnect( DBClientWithCommands &c );
const char* getUserDir();
} }
} }
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 v8_db.h   v8_db.h 
skipping to change at line 48 skipping to change at line 48
mongo::DBClientBase * getConnection( const v8::Arguments& args ); mongo::DBClientBase * getConnection( const v8::Arguments& args );
// Mongo members // Mongo members
v8::Handle<v8::Value> mongoConsLocal(V8Scope* scope, const v8::Argument s& args); v8::Handle<v8::Value> mongoConsLocal(V8Scope* scope, const v8::Argument s& args);
v8::Handle<v8::Value> mongoConsExternal(V8Scope* scope, const v8::Argum ents& args); v8::Handle<v8::Value> mongoConsExternal(V8Scope* scope, const v8::Argum ents& args);
v8::Handle<v8::Value> mongoFind(V8Scope* scope, const v8::Arguments& ar gs); v8::Handle<v8::Value> mongoFind(V8Scope* scope, const v8::Arguments& ar gs);
v8::Handle<v8::Value> mongoInsert(V8Scope* scope, const v8::Arguments& args); v8::Handle<v8::Value> mongoInsert(V8Scope* scope, const v8::Arguments& args);
v8::Handle<v8::Value> mongoRemove(V8Scope* scope, const v8::Arguments& args); v8::Handle<v8::Value> mongoRemove(V8Scope* scope, const v8::Arguments& args);
v8::Handle<v8::Value> mongoUpdate(V8Scope* scope, const v8::Arguments& args); v8::Handle<v8::Value> mongoUpdate(V8Scope* scope, const v8::Arguments& args);
v8::Handle<v8::Value> mongoAuth(V8Scope* scope, const v8::Arguments& ar gs);
v8::Handle<v8::Value> internalCursorCons(V8Scope* scope, const v8::Argu ments& args); v8::Handle<v8::Value> internalCursorCons(V8Scope* scope, const v8::Argu ments& args);
v8::Handle<v8::Value> internalCursorNext(V8Scope* scope, const v8::Argu ments& args); v8::Handle<v8::Value> internalCursorNext(V8Scope* scope, const v8::Argu ments& args);
v8::Handle<v8::Value> internalCursorHasNext(V8Scope* scope, const v8::A rguments& args); v8::Handle<v8::Value> internalCursorHasNext(V8Scope* scope, const v8::A rguments& args);
v8::Handle<v8::Value> internalCursorObjsLeftInBatch(V8Scope* scope, con st v8::Arguments& args); v8::Handle<v8::Value> internalCursorObjsLeftInBatch(V8Scope* scope, con st v8::Arguments& args);
v8::Handle<v8::Value> internalCursorReadOnly(V8Scope* scope, const v8:: Arguments& args);
// DB members // DB members
v8::Handle<v8::Value> dbInit(V8Scope* scope, const v8::Arguments& args) ; v8::Handle<v8::Value> dbInit(V8Scope* scope, const v8::Arguments& args) ;
v8::Handle<v8::Value> collectionInit(V8Scope* scope, const v8::Argument s& args ); v8::Handle<v8::Value> collectionInit(V8Scope* scope, const v8::Argument s& args );
v8::Handle<v8::Value> objectIdInit( V8Scope* scope, const v8::Arguments & args ); v8::Handle<v8::Value> objectIdInit( V8Scope* scope, const v8::Arguments & args );
v8::Handle<v8::Value> dbRefInit( V8Scope* scope, const v8::Arguments& a rgs ); v8::Handle<v8::Value> dbRefInit( V8Scope* scope, const v8::Arguments& a rgs );
v8::Handle<v8::Value> dbPointerInit( V8Scope* scope, const v8::Argument s& args ); v8::Handle<v8::Value> dbPointerInit( V8Scope* scope, const v8::Argument s& args );
v8::Handle<v8::Value> dbTimestampInit( V8Scope* scope, const v8::Argume nts& args ); v8::Handle<v8::Value> dbTimestampInit( V8Scope* scope, const v8::Argume nts& args );
skipping to change at line 84 skipping to change at line 86
v8::Handle<v8::Value> numberLongToNumber(V8Scope* scope, const v8::Argu ments& args); v8::Handle<v8::Value> numberLongToNumber(V8Scope* scope, const v8::Argu ments& args);
v8::Handle<v8::Value> numberLongValueOf(V8Scope* scope, const v8::Argum ents& args); v8::Handle<v8::Value> numberLongValueOf(V8Scope* scope, const v8::Argum ents& args);
v8::Handle<v8::Value> numberLongToString(V8Scope* scope, const v8::Argu ments& args); v8::Handle<v8::Value> numberLongToString(V8Scope* scope, const v8::Argu ments& args);
v8::Handle<v8::Value> numberIntInit( V8Scope* scope, const v8::Argument s& args ); v8::Handle<v8::Value> numberIntInit( V8Scope* scope, const v8::Argument s& args );
v8::Handle<v8::Value> numberIntToNumber(V8Scope* scope, const v8::Argum ents& args); v8::Handle<v8::Value> numberIntToNumber(V8Scope* scope, const v8::Argum ents& args);
v8::Handle<v8::Value> numberIntValueOf(V8Scope* scope, const v8::Argume nts& args); v8::Handle<v8::Value> numberIntValueOf(V8Scope* scope, const v8::Argume nts& args);
v8::Handle<v8::Value> numberIntToString(V8Scope* scope, const v8::Argum ents& args); v8::Handle<v8::Value> numberIntToString(V8Scope* scope, const v8::Argum ents& args);
v8::Handle<v8::Value> dbQueryInit( V8Scope* scope, const v8::Arguments& args ); v8::Handle<v8::Value> dbQueryInit( V8Scope* scope, 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:: AccessorInfo& info );
v8::Handle<v8::Value> collectionFallback( v8::Local<v8::String> name, c v8::Handle<v8::Value> collectionGetter( v8::Local<v8::String> name, con
onst v8::AccessorInfo &info); st v8::AccessorInfo &info);
v8::Handle<v8::Value> collectionSetter( Local<v8::String> name, Local<V
alue> value, const AccessorInfo& info );
v8::Handle<v8::Value> bsonsize( V8Scope* scope, const v8::Arguments& ar gs ); v8::Handle<v8::Value> bsonsize( V8Scope* scope, const v8::Arguments& ar gs );
// call with v8 mutex:
void enableV8Interrupt();
void disableV8Interrupt();
} }
 End of changes. 5 change blocks. 
7 lines changed or deleted 7 lines changed or added


 value.h   value.h 
/* @file value.h
concurrency helpers DiagStr, Guarded
*/
/** /**
* Copyright (C) 2008 10gen Inc. * Copyright (c) 2011 10gen Inc.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3 * it under the terms of the GNU Affero General Public License, version 3,
, * as published by the Free Software Foundation.
* as published by the Free Software Foundation. *
* * This program is distributed in the hope that it will be useful,
* This program is distributed in the hope that it will be useful,b * 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 License
* You should have received a copy of the GNU Affero General Public Licen * along with this program. If not, see <http://www.gnu.org/licenses/>.
se */
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once #pragma once
#include "mutex.h" #include "pch.h"
#include "spin_lock.h" #include "bson/bsontypes.h"
#include "bson/oid.h"
#include "util/intrusive_counter.h"
namespace mongo { namespace mongo {
class BSONElement;
class Builder;
class Document;
class Value;
/** declare that a variable that is "guarded" by a mutex. class ValueIterator :
public IntrusiveCounterUnsigned {
public:
virtual ~ValueIterator();
The decl documents the rule. For example "counta and countb are gu /*
arded by xyzMutex": Ask if there are more fields to return.
Guarded<int, xyzMutex> counta; @returns true if there are more fields, false otherwise
Guarded<int, xyzMutex> countb; */
virtual bool more() const = 0;
Upon use, specify the scoped_lock object. This makes it hard for s /*
omeone Move the iterator to point to the next field and return it.
later to forget to be in the lock. Check is made that it is the ri
ght lock in _DEBUG
builds at runtime.
*/
template <typename T, mutex& BY>
class Guarded : boost::noncopyable {
T _val;
public:
T& ref(const scoped_lock& lk) {
dassert( lk._mut == &BY );
return _val;
}
};
class DiagStr { @returns the next field's <name, Value>
string _s; */
mutable SpinLock m; virtual intrusive_ptr<const Value> next() = 0;
public:
DiagStr(const DiagStr& r) : _s(r.get()) { }
DiagStr() { }
bool empty() const {
scoped_spinlock lk(m);
return _s.empty();
}
string get() const {
scoped_spinlock lk(m);
return _s;
}
void set(const char *s) {
scoped_spinlock lk(m);
_s = s;
}
void set(const string& s) {
scoped_spinlock lk(m);
_s = s;
}
operator string() const { return get(); }
void operator=(const string& s) { set(s); }
void operator=(const DiagStr& rhs) {
scoped_spinlock lk(m);
_s = rhs.get();
}
}; };
#if 0 // not including in 2.0 /*
Values are immutable, so these are passed around as
intrusive_ptr<const Value>.
*/
class Value :
public IntrusiveCounterUnsigned {
public:
~Value();
/** Thread safe map. /*
Be careful not to use this too much or it could make things slow; Construct a Value from a BSONElement.
if not a hot code path no problem.
Examples: This ignores the name of the element, and only uses the value,
whatever type it is.
mapsf<int,int> mp; @returns a new Value initialized from the bsonElement
*/
static intrusive_ptr<const Value> createFromBsonElement(
BSONElement *pBsonElement);
/*
Construct an integer-valued Value.
For commonly used values, consider using one of the singleton
instances defined below.
@param value the value
@returns a Value with the given value
*/
static intrusive_ptr<const Value> createInt(int value);
/*
Construct an long(long)-valued Value.
For commonly used values, consider using one of the singleton
instances defined below.
@param value the value
@returns a Value with the given value
*/
static intrusive_ptr<const Value> createLong(long long value);
/*
Construct a double-valued Value.
@param value the value
@returns a Value with the given value
*/
static intrusive_ptr<const Value> createDouble(double value);
/*
Construct a string-valued Value.
@param value the value
@returns a Value with the given value
*/
static intrusive_ptr<const Value> createString(const string &value)
;
/*
Construct a date-valued Value.
@param value the value
@returns a Value with the given value
*/
static intrusive_ptr<const Value> createDate(const Date_t &value);
/*
Construct a document-valued Value.
@param value the value
@returns a Value with the given value
*/
static intrusive_ptr<const Value> createDocument(
const intrusive_ptr<Document> &pDocument);
/*
Construct an array-valued Value.
@param value the value
@returns a Value with the given value
*/
static intrusive_ptr<const Value> createArray(
const vector<intrusive_ptr<const Value> > &vpValue);
/*
Get the BSON type of the field.
If the type is jstNULL, no value getter will work.
@return the BSON type of the field.
*/
BSONType getType() const;
/*
Getters.
@returns the Value's value; asserts if the requested value type i
s
incorrect.
*/
double getDouble() const;
string getString() const;
intrusive_ptr<Document> getDocument() const;
intrusive_ptr<ValueIterator> getArray() const;
OID getOid() const;
bool getBool() const;
Date_t getDate() const;
string getRegex() const;
string getSymbol() const;
int getInt() const;
unsigned long long getTimestamp() const;
long long getLong() const;
/*
Get the length of an array value.
@returns the length of the array, if this is array-valued; otherw
ise
throws an error
*/
size_t getArrayLength() const;
/*
Add this value to the BSON object under construction.
*/
void addToBsonObj(BSONObjBuilder *pBuilder, string fieldName) const
;
/*
Add this field to the BSON array under construction.
As part of an array, the Value's name will be ignored.
*/
void addToBsonArray(BSONArrayBuilder *pBuilder) const;
/*
Get references to singleton instances of commonly used field valu
es.
*/
static intrusive_ptr<const Value> getUndefined();
static intrusive_ptr<const Value> getNull();
static intrusive_ptr<const Value> getTrue();
static intrusive_ptr<const Value> getFalse();
static intrusive_ptr<const Value> getMinusOne();
static intrusive_ptr<const Value> getZero();
static intrusive_ptr<const Value> getOne();
/*
Coerce (cast) a value to a native bool, using JSON rules.
@returns the bool value
*/
bool coerceToBool() const;
/*
Coerce (cast) a value to a Boolean Value, using JSON rules.
@returns the Boolean Value value
*/
intrusive_ptr<const Value> coerceToBoolean() const;
/*
Coerce (cast) a value to an int, using JSON rules.
@returns the int value
*/
int coerceToInt() const;
/*
Coerce (cast) a value to a long long, using JSON rules.
@returns the long value
*/
long long coerceToLong() const;
/*
Coerce (cast) a value to a double, using JSON rules.
@returns the double value
*/
double coerceToDouble() const;
/*
Coerce (cast) a value to a date, using JSON rules.
@returns the date value
*/
Date_t coerceToDate() const;
/*
Coerce (cast) a value to a string, using JSON rules.
@returns the date value
*/
string coerceToString() const;
/*
Compare two Values.
@param rL left value
@param rR right value
@returns an integer less than zero, zero, or an integer greater t
han
zero, depending on whether rL < rR, rL == rR, or rL > rR
*/
static int compare(const intrusive_ptr<const Value> &rL,
const intrusive_ptr<const Value> &rR);
/*
Figure out what the widest of two numeric types is.
Widest can be thought of as "most capable," or "able to hold the
largest or most precise value." The progression is Int, Long, Do
uble.
@param rL left value
@param rR right value
@returns a BSONType of NumberInt, NumberLong, or NumberDouble
*/
static BSONType getWidestNumeric(BSONType lType, BSONType rType);
/*
Get the approximate storage size of the value, in bytes.
@returns approximate storage size of the value.
*/
size_t getApproximateSize() const;
/*
Calculate a hash value.
Meant to be used to create composite hashes suitable for
boost classes such as unordered_map<>.
@param seed value to augment with this' hash
*/
void hash_combine(size_t &seed) const;
/*
struct Hash is defined to enable the use of Values as
keys in boost::unordered_map<>.
Values are always referenced as immutables in the form
intrusive_ptr<const Value>, so these operate on that construction
.
*/
struct Hash :
unary_function<intrusive_ptr<const Value>, size_t> {
size_t operator()(const intrusive_ptr<const Value> &rV) const;
};
int x = mp.get(); protected:
Value(); // creates null value
Value(BSONType type); // creates an empty (unitialized value) of ty
pe
// mostly useful for Undefi
ned
Value(bool boolValue);
Value(int intValue);
private:
Value(BSONElement *pBsonElement);
Value(long long longValue);
Value(double doubleValue);
Value(const Date_t &dateValue);
Value(const string &stringValue);
Value(const intrusive_ptr<Document> &pDocument);
Value(const vector<intrusive_ptr<const Value> > &vpValue);
void addToBson(Builder *pBuilder) const;
BSONType type;
/* store value in one of these */
union {
double doubleValue;
bool boolValue;
int intValue;
unsigned long long timestampValue;
long long longValue;
} simple; // values that don't need a ctor/dtor
OID oidValue;
Date_t dateValue;
string stringValue; // String, Regex, Symbol
intrusive_ptr<Document> pDocumentValue;
vector<intrusive_ptr<const Value> > vpValue; // for arrays
/*
These are often used as the result of boolean or comparison
expressions.
These are obtained via public static getters defined above.
*/
static const intrusive_ptr<const Value> pFieldUndefined;
static const intrusive_ptr<const Value> pFieldNull;
static const intrusive_ptr<const Value> pFieldTrue;
static const intrusive_ptr<const Value> pFieldFalse;
static const intrusive_ptr<const Value> pFieldMinusOne;
static const intrusive_ptr<const Value> pFieldZero;
static const intrusive_ptr<const Value> pFieldOne;
/* this implementation is used for getArray() */
class vi :
public ValueIterator {
public:
// virtuals from ValueIterator
virtual ~vi();
virtual bool more() const;
virtual intrusive_ptr<const Value> next();
private:
friend class Value;
vi(const intrusive_ptr<const Value> &pSource,
const vector<intrusive_ptr<const Value> > *pvpValue);
size_t size;
size_t nextIndex;
const vector<intrusive_ptr<const Value> > *pvpValue;
}; /* class vi */
map<int,int> two; };
mp.swap(two);
{ /*
mapsf<int,int>::ref r(mp); Equality operator for values.
r[9] = 1;
map<int,int>::iterator i = r.r.begin();
}
*/ Useful for unordered_map<>, etc.
template< class K, class V > */
struct mapsf : boost::noncopyable { inline bool operator==(const intrusive_ptr<const Value> &v1,
SimpleMutex m; const intrusive_ptr<const Value> &v2) {
map<K,V> val; return (Value::compare(v1, v2) == 0);
friend struct ref; }
/*
For performance reasons, there are various sharable static values
defined in class Value, obtainable by methods such as getUndefined(),
getTrue(), getOne(), etc. We don't want these to go away as they are
used by a multitude of threads evaluating pipelines. In order to avo
id
having to use atomic integers in the intrusive reference counter, thi
s
class overrides the reference counting methods to do nothing, making
it
safe to use for static Values.
At this point, only the constructors necessary for the static Values
in
common use have been defined. The remainder can be defined if necess
ary.
*/
class ValueStatic :
public Value {
public: public:
mapsf() : m("mapsf") { } // virtuals from IntrusiveCounterUnsigned
void swap(map<K,V>& rhs) { virtual void addRef() const;
SimpleMutex::scoped_lock lk(m); virtual void release() const;
val.swap(rhs);
} // constructors
// safe as we pass by value: ValueStatic();
V get(K k) { ValueStatic(BSONType type);
SimpleMutex::scoped_lock lk(m); ValueStatic(bool boolValue);
map<K,V>::iterator i = val.find(k); ValueStatic(int intValue);
if( i == val.end() )
return K();
return i->second;
}
// think about deadlocks when using ref. the other methods
// above will always be safe as they are "leaf" operations.
struct ref {
SimpleMutex::scoped_lock lk;
public:
map<K,V> const &r;
ref(mapsf<K,V> &m) : lk(m.m), r(m.val) { }
V& operator[](const K& k) { return r[k]; }
};
}; };
#endif
} }
/* ======================= INLINED IMPLEMENTATIONS ========================
== */
namespace mongo {
inline BSONType Value::getType() const {
return type;
}
inline size_t Value::getArrayLength() const {
assert(getType() == Array);
return vpValue.size();
}
inline intrusive_ptr<const Value> Value::getUndefined() {
return pFieldUndefined;
}
inline intrusive_ptr<const Value> Value::getNull() {
return pFieldNull;
}
inline intrusive_ptr<const Value> Value::getTrue() {
return pFieldTrue;
}
inline intrusive_ptr<const Value> Value::getFalse() {
return pFieldFalse;
}
inline intrusive_ptr<const Value> Value::getMinusOne() {
return pFieldMinusOne;
}
inline intrusive_ptr<const Value> Value::getZero() {
return pFieldZero;
}
inline intrusive_ptr<const Value> Value::getOne() {
return pFieldOne;
}
inline size_t Value::Hash::operator()(
const intrusive_ptr<const Value> &rV) const {
size_t seed = 0xf0afbeef;
rV->hash_combine(seed);
return seed;
}
inline ValueStatic::ValueStatic():
Value() {
}
inline ValueStatic::ValueStatic(BSONType type):
Value(type) {
}
inline ValueStatic::ValueStatic(bool boolValue):
Value(boolValue) {
}
inline ValueStatic::ValueStatic(int intValue):
Value(intValue) {
}
};
 End of changes. 20 change blocks. 
114 lines changed or deleted 392 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/