| bsoninlines.h | | bsoninlines.h | |
| | | | |
| skipping to change at line 263 | | skipping to change at line 263 | |
| | | | |
| inline void BSONElement::validate() const { | | inline void BSONElement::validate() const { | |
| const BSONType t = type(); | | const BSONType t = type(); | |
| | | | |
| switch( t ) { | | switch( t ) { | |
| case DBRef: | | case DBRef: | |
| case Code: | | case Code: | |
| case Symbol: | | case Symbol: | |
| case mongo::String: { | | case mongo::String: { | |
| int x = valuestrsize(); | | int x = valuestrsize(); | |
|
| if ( x > 0 && valuestr()[x-1] == 0 ) | | if ( x > 0 && x < BSONObjMaxSize && valuestr()[x-1] == 0 ) | |
| return; | | return; | |
| StringBuilder buf; | | StringBuilder buf; | |
| buf << "Invalid dbref/code/string/symbol size: " << x << " str
nlen:" << mongo::strnlen( valuestr() , x ); | | buf << "Invalid dbref/code/string/symbol size: " << x << " str
nlen:" << mongo::strnlen( valuestr() , x ); | |
| msgasserted( 10321 , buf.str() ); | | msgasserted( 10321 , buf.str() ); | |
| break; | | break; | |
| } | | } | |
| case CodeWScope: { | | case CodeWScope: { | |
| int totalSize = *( int * )( value() ); | | int totalSize = *( int * )( value() ); | |
| massert( 10322 , "Invalid CodeWScope size", totalSize >= 8 ); | | massert( 10322 , "Invalid CodeWScope size", totalSize >= 8 ); | |
| int strSizeWNull = *( int * )( value() + 4 ); | | int strSizeWNull = *( int * )( value() + 4 ); | |
| | | | |
| skipping to change at line 349 | | skipping to change at line 349 | |
| case BinData: | | case BinData: | |
| massert( 10317 , "Insufficient bytes to calculate element size
", maxLen == -1 || remain > 3 ); | | massert( 10317 , "Insufficient bytes to calculate element size
", maxLen == -1 || remain > 3 ); | |
| x = valuestrsize() + 4 + 1/*subtype*/; | | x = valuestrsize() + 4 + 1/*subtype*/; | |
| break; | | break; | |
| case RegEx: | | case RegEx: | |
| { | | { | |
| const char *p = value(); | | const char *p = value(); | |
| size_t len1 = ( maxLen == -1 ) ? strlen( p ) : mongo::strnlen(
p, remain ); | | size_t len1 = ( maxLen == -1 ) ? strlen( p ) : mongo::strnlen(
p, remain ); | |
| //massert( 10318 , "Invalid regex string", len1 != -1 ); // ER
H - 4/28/10 - don't think this does anything | | //massert( 10318 , "Invalid regex string", len1 != -1 ); // ER
H - 4/28/10 - don't think this does anything | |
| p = p + len1 + 1; | | p = p + len1 + 1; | |
|
| size_t len2 = ( maxLen == -1 ) ? strlen( p ) : mongo::strnlen( | | size_t len2; | |
| p, remain - len1 - 1 ); | | if( maxLen == -1 ) | |
| | | len2 = strlen( p ); | |
| | | else { | |
| | | size_t x = remain - len1 - 1; | |
| | | assert( x <= 0x7fffffff ); | |
| | | len2 = mongo::strnlen( p, (int) x ); | |
| | | } | |
| //massert( 10319 , "Invalid regex options string", len2 != -1
); // ERH - 4/28/10 - don't think this does anything | | //massert( 10319 , "Invalid regex options string", len2 != -1
); // ERH - 4/28/10 - don't think this does anything | |
| x = (int) (len1 + 1 + len2 + 1); | | x = (int) (len1 + 1 + len2 + 1); | |
| } | | } | |
| break; | | break; | |
| default: { | | default: { | |
| StringBuilder ss; | | StringBuilder ss; | |
| ss << "BSONElement: bad type " << (int) type(); | | ss << "BSONElement: bad type " << (int) type(); | |
| string msg = ss.str(); | | string msg = ss.str(); | |
| massert( 10320 , msg.c_str(),false); | | massert( 10320 , msg.c_str(),false); | |
| } | | } | |
| | | | |
End of changes. 2 change blocks. |
| 3 lines changed or deleted | | 9 lines changed or added | |
|
| bsonobjbuilder.h | | bsonobjbuilder.h | |
| | | | |
| skipping to change at line 235 | | skipping to change at line 235 | |
| * mostly for JS | | * mostly for JS | |
| */ | | */ | |
| BSONObjBuilder& appendNumber( const StringData& fieldName , int n )
{ | | BSONObjBuilder& appendNumber( const StringData& fieldName , int n )
{ | |
| return append( fieldName , n ); | | return append( fieldName , n ); | |
| } | | } | |
| | | | |
| BSONObjBuilder& appendNumber( const StringData& fieldName , double
d ){ | | BSONObjBuilder& appendNumber( const StringData& fieldName , double
d ){ | |
| return append( fieldName , d ); | | return append( fieldName , d ); | |
| } | | } | |
| | | | |
|
| | | BSONObjBuilder& appendNumber( const StringData& fieldName , size_t | |
| | | n ){ | |
| | | static size_t maxInt = (size_t)pow( 2.0 , 30.0 ); | |
| | | | |
| | | if ( n < maxInt ) | |
| | | append( fieldName , (int)n ); | |
| | | else | |
| | | append( fieldName , (long long)n ); | |
| | | return *this; | |
| | | } | |
| | | | |
| BSONObjBuilder& appendNumber( const StringData& fieldName , long lo
ng l ){ | | BSONObjBuilder& appendNumber( const StringData& fieldName , long lo
ng l ){ | |
| static long long maxInt = (int)pow( 2.0 , 30.0 ); | | static long long maxInt = (int)pow( 2.0 , 30.0 ); | |
| static long long maxDouble = (long long)pow( 2.0 , 40.0 ); | | static long long maxDouble = (long long)pow( 2.0 , 40.0 ); | |
| | | | |
| if ( l < maxInt ) | | if ( l < maxInt ) | |
| append( fieldName , (int)l ); | | append( fieldName , (int)l ); | |
| else if ( l < maxDouble ) | | else if ( l < maxDouble ) | |
| append( fieldName , (double)l ); | | append( fieldName , (double)l ); | |
| else | | else | |
| append( fieldName , l ); | | append( fieldName , l ); | |
| | | | |
| skipping to change at line 337 | | skipping to change at line 347 | |
| return *this; | | return *this; | |
| } | | } | |
| BSONObjBuilder& append(const StringData& fieldName, Date_t dt) { | | BSONObjBuilder& append(const StringData& fieldName, Date_t dt) { | |
| return appendDate(fieldName, dt); | | return appendDate(fieldName, dt); | |
| } | | } | |
| | | | |
| /** Append a regular expression value | | /** Append a regular expression value | |
| @param regex the regular expression pattern | | @param regex the regular expression pattern | |
| @param regex options such as "i" or "g" | | @param regex options such as "i" or "g" | |
| */ | | */ | |
|
| BSONObjBuilder& appendRegex(const StringData& fieldName, const char
*regex, const char *options = "") { | | BSONObjBuilder& appendRegex(const StringData& fieldName, const Stri
ngData& regex, const StringData& options = "") { | |
| _b.appendNum((char) RegEx); | | _b.appendNum((char) RegEx); | |
| _b.appendStr(fieldName); | | _b.appendStr(fieldName); | |
| _b.appendStr(regex); | | _b.appendStr(regex); | |
| _b.appendStr(options); | | _b.appendStr(options); | |
| return *this; | | return *this; | |
| } | | } | |
|
| /** Append a regular expression value | | | |
| @param regex the regular expression pattern | | BSONObjBuilder& appendCode(const StringData& fieldName, const Strin | |
| @param regex options such as "i" or "g" | | gData& code) { | |
| */ | | | |
| BSONObjBuilder& appendRegex(const StringData& fieldName, string reg | | | |
| ex, string options = "") { | | | |
| return appendRegex(fieldName, regex.c_str(), options.c_str()); | | | |
| } | | | |
| BSONObjBuilder& appendCode(const StringData& fieldName, const char | | | |
| *code) { | | | |
| _b.appendNum((char) Code); | | _b.appendNum((char) Code); | |
| _b.appendStr(fieldName); | | _b.appendStr(fieldName); | |
|
| _b.appendNum((int) strlen(code)+1); | | _b.appendNum((int) code.size()+1); | |
| _b.appendStr(code); | | _b.appendStr(code); | |
| return *this; | | return *this; | |
| } | | } | |
|
| | | | |
| /** Append a string element. len DOES include terminating nul */ | | /** Append a string element. len DOES include terminating nul */ | |
| BSONObjBuilder& append(const StringData& fieldName, const char *str
, int len) { | | BSONObjBuilder& append(const StringData& fieldName, const char *str
, int len) { | |
| _b.appendNum((char) String); | | _b.appendNum((char) String); | |
| _b.appendStr(fieldName); | | _b.appendStr(fieldName); | |
| _b.appendNum((int)len); | | _b.appendNum((int)len); | |
| _b.appendBuf(str, len); | | _b.appendBuf(str, len); | |
| return *this; | | return *this; | |
| } | | } | |
| /** Append a string element */ | | /** Append a string element */ | |
| BSONObjBuilder& append(const StringData& fieldName, const char *str
) { | | BSONObjBuilder& append(const StringData& fieldName, const char *str
) { | |
| | | | |
| skipping to change at line 368 | | skipping to change at line 373 | |
| /** Append a string element. len DOES include terminating nul */ | | /** Append a string element. len DOES include terminating nul */ | |
| BSONObjBuilder& append(const StringData& fieldName, const char *str
, int len) { | | BSONObjBuilder& append(const StringData& fieldName, const char *str
, int len) { | |
| _b.appendNum((char) String); | | _b.appendNum((char) String); | |
| _b.appendStr(fieldName); | | _b.appendStr(fieldName); | |
| _b.appendNum((int)len); | | _b.appendNum((int)len); | |
| _b.appendBuf(str, len); | | _b.appendBuf(str, len); | |
| return *this; | | return *this; | |
| } | | } | |
| /** Append a string element */ | | /** Append a string element */ | |
| BSONObjBuilder& append(const StringData& fieldName, const char *str
) { | | BSONObjBuilder& append(const StringData& fieldName, const char *str
) { | |
|
| return append(fieldName, str, (int) strlen(str)+1); | | return append(fieldName, str, (int) strlen(str)+1); | |
| } | | } | |
| /** Append a string element */ | | /** Append a string element */ | |
| BSONObjBuilder& append(const StringData& fieldName, string str) { | | BSONObjBuilder& append(const StringData& fieldName, string str) { | |
| return append(fieldName, str.c_str(), (int) str.size()+1); | | return append(fieldName, str.c_str(), (int) str.size()+1); | |
| } | | } | |
|
| BSONObjBuilder& appendSymbol(const StringData& fieldName, const cha | | | |
| r *symbol) { | | BSONObjBuilder& appendSymbol(const StringData& fieldName, const Str | |
| | | ingData& symbol) { | |
| _b.appendNum((char) Symbol); | | _b.appendNum((char) Symbol); | |
| _b.appendStr(fieldName); | | _b.appendStr(fieldName); | |
|
| _b.appendNum((int) strlen(symbol)+1); | | _b.appendNum((int) symbol.size()+1); | |
| _b.appendStr(symbol); | | _b.appendStr(symbol); | |
| return *this; } | | return *this; } | |
| | | | |
| /** Append a Null element to the object */ | | /** Append a Null element to the object */ | |
| BSONObjBuilder& appendNull( const StringData& fieldName ) { | | BSONObjBuilder& appendNull( const StringData& fieldName ) { | |
| _b.appendNum( (char) jstNULL ); | | _b.appendNum( (char) jstNULL ); | |
| _b.appendStr( fieldName ); | | _b.appendStr( fieldName ); | |
| return *this; } | | return *this; } | |
| | | | |
| // Append an element that is less than all other keys. | | // Append an element that is less than all other keys. | |
| | | | |
| skipping to change at line 426 | | skipping to change at line 432 | |
| Timestamps are a special BSON datatype that is used internally for
replication. | | Timestamps are a special BSON datatype that is used internally for
replication. | |
| Append a timestamp element to the object being ebuilt. | | Append a timestamp element to the object being ebuilt. | |
| @param time - in millis (but stored in seconds) | | @param time - in millis (but stored in seconds) | |
| */ | | */ | |
| BSONObjBuilder& appendTimestamp( const StringData& fieldName , unsi
gned long long time , unsigned int inc ); | | BSONObjBuilder& appendTimestamp( const StringData& fieldName , unsi
gned long long time , unsigned int inc ); | |
| | | | |
| /* | | /* | |
| Append an element of the deprecated DBRef type. | | Append an element of the deprecated DBRef type. | |
| @deprecated | | @deprecated | |
| */ | | */ | |
|
| BSONObjBuilder& appendDBRef( const StringData& fieldName, const cha
r *ns, const OID &oid ) { | | BSONObjBuilder& appendDBRef( const StringData& fieldName, const Str
ingData& ns, const OID &oid ) { | |
| _b.appendNum( (char) DBRef ); | | _b.appendNum( (char) DBRef ); | |
| _b.appendStr( fieldName ); | | _b.appendStr( fieldName ); | |
|
| _b.appendNum( (int) strlen( ns ) + 1 ); | | _b.appendNum( (int) ns.size() + 1 ); | |
| _b.appendStr( ns ); | | _b.appendStr( ns ); | |
| _b.appendBuf( (void *) &oid, 12 ); | | _b.appendBuf( (void *) &oid, 12 ); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
| /** Append a binary data element | | /** Append a binary data element | |
| @param fieldName name of the field | | @param fieldName name of the field | |
| @param len length of the binary data in bytes | | @param len length of the binary data in bytes | |
| @param subtype subtype information for the data. @see enum BinD
ataType in bsontypes.h. | | @param subtype subtype information for the data. @see enum BinD
ataType in bsontypes.h. | |
| Use BinDataGeneral if you don't care about the type. | | Use BinDataGeneral if you don't care about the type. | |
| | | | |
| skipping to change at line 473 | | skipping to change at line 479 | |
| _b.appendNum( len + 4 ); | | _b.appendNum( len + 4 ); | |
| _b.appendNum( (char)0x2 ); | | _b.appendNum( (char)0x2 ); | |
| _b.appendNum( len ); | | _b.appendNum( len ); | |
| _b.appendBuf( (void *) data, len ); | | _b.appendBuf( (void *) data, len ); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
| /** Append to the BSON object a field of type CodeWScope. This is
a javascript code | | /** Append to the BSON object a field of type CodeWScope. This is
a javascript code | |
| fragment accompanied by some scope that goes with it. | | fragment accompanied by some scope that goes with it. | |
| */ | | */ | |
|
| BSONObjBuilder& appendCodeWScope( const StringData& fieldName, cons
t char *code, const BSONObj &scope ) { | | BSONObjBuilder& appendCodeWScope( const StringData& fieldName, cons
t StringData& code, const BSONObj &scope ) { | |
| _b.appendNum( (char) CodeWScope ); | | _b.appendNum( (char) CodeWScope ); | |
| _b.appendStr( fieldName ); | | _b.appendStr( fieldName ); | |
|
| _b.appendNum( ( int )( 4 + 4 + strlen( code ) + 1 + scope.objsi | | _b.appendNum( ( int )( 4 + 4 + code.size() + 1 + scope.objsize( | |
| ze() ) ); | | ) ) ); | |
| _b.appendNum( ( int ) strlen( code ) + 1 ); | | _b.appendNum( ( int ) code.size() + 1 ); | |
| _b.appendStr( code ); | | _b.appendStr( code ); | |
| _b.appendBuf( ( void * )scope.objdata(), scope.objsize() ); | | _b.appendBuf( ( void * )scope.objdata(), scope.objsize() ); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
| void appendUndefined( const StringData& fieldName ) { | | void appendUndefined( const StringData& fieldName ) { | |
| _b.appendNum( (char) Undefined ); | | _b.appendNum( (char) Undefined ); | |
| _b.appendStr( fieldName ); | | _b.appendStr( fieldName ); | |
| } | | } | |
| | | | |
| /* helper function -- see Query::where() for primary way to do this
. */ | | /* helper function -- see Query::where() for primary way to do this
. */ | |
|
| void appendWhere( const char *code, const BSONObj &scope ){ | | void appendWhere( const StringData& code, const BSONObj &scope ){ | |
| appendCodeWScope( "$where" , code , scope ); | | appendCodeWScope( "$where" , code , scope ); | |
| } | | } | |
|
| void appendWhere( const string &code, const BSONObj &scope ){ | | | |
| appendWhere( code.c_str(), scope ); | | | |
| } | | | |
| | | | |
| /** | | /** | |
| these are the min/max when comparing, not strict min/max element
s for a given type | | these are the min/max when comparing, not strict min/max element
s for a given type | |
| */ | | */ | |
| void appendMinForType( const StringData& fieldName , int type ); | | void appendMinForType( const StringData& fieldName , int type ); | |
| void appendMaxForType( const StringData& fieldName , int type ); | | void appendMaxForType( const StringData& fieldName , int type ); | |
| | | | |
| /** Append an array of values. */ | | /** Append an array of values. */ | |
| template < class T > | | template < class T > | |
| BSONObjBuilder& append( const StringData& fieldName, const vector<
T >& vals ); | | BSONObjBuilder& append( const StringData& fieldName, const vector<
T >& vals ); | |
| | | | |
| skipping to change at line 670 | | skipping to change at line 673 | |
| | | | |
| void doneFast() { _b.doneFast(); } | | void doneFast() { _b.doneFast(); } | |
| | | | |
| template <typename T> | | template <typename T> | |
| BSONArrayBuilder& append(const StringData& name, const T& x){ | | BSONArrayBuilder& append(const StringData& name, const T& x){ | |
| fill( name ); | | fill( name ); | |
| append( x ); | | append( x ); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
|
| BufBuilder &subobjStart( const char *name = "0" ) { | | BufBuilder &subobjStart( const StringData& name = "0" ) { | |
| fill( name ); | | fill( name ); | |
|
| return _b.subobjStart( num().c_str() ); | | return _b.subobjStart( num() ); | |
| } | | } | |
| | | | |
| BufBuilder &subarrayStart( const char *name ) { | | BufBuilder &subarrayStart( const char *name ) { | |
| fill( name ); | | fill( name ); | |
|
| return _b.subarrayStart( num().c_str() ); | | return _b.subarrayStart( num() ); | |
| } | | } | |
| | | | |
| void appendArray( const StringData& name, BSONObj subObj ) { | | void appendArray( const StringData& name, BSONObj subObj ) { | |
| fill( name ); | | fill( name ); | |
|
| _b.appendArray( num().c_str(), 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 ); | |
| } | | } | |
| | | | |
| private: | | private: | |
| void fill( const StringData& name ) { | | void fill( const StringData& name ) { | |
| char *r; | | char *r; | |
| | | | |
End of changes. 18 change blocks. |
| 30 lines changed or deleted | | 33 lines changed or added | |
|
| btree.h | | btree.h | |
| | | | |
| skipping to change at line 238 | | skipping to change at line 238 | |
| /** | | /** | |
| * find the first instance of the key | | * find the first instance of the key | |
| * does not handle dups | | * does not handle dups | |
| * returned DiskLock isNull if can't find anything with that | | * returned DiskLock isNull if can't find anything with that | |
| */ | | */ | |
| DiskLoc findSingle( const IndexDetails& , const DiskLoc& thisLoc, c
onst BSONObj& key ); | | DiskLoc findSingle( const IndexDetails& , const DiskLoc& thisLoc, c
onst BSONObj& key ); | |
| | | | |
| /* advance one key position in the index: */ | | /* advance one key position in the index: */ | |
| DiskLoc advance(const DiskLoc& thisLoc, int& keyOfs, int direction,
const char *caller); | | DiskLoc advance(const DiskLoc& thisLoc, int& keyOfs, int direction,
const char *caller); | |
| | | | |
|
| void advanceTo(const IndexDetails &id, DiskLoc &thisLoc, int &keyOf | | void advanceTo(DiskLoc &thisLoc, int &keyOfs, const BSONObj &keyBeg | |
| s, const BSONObj &keyBegin, int keyBeginLen, const vector< const BSONElemen | | in, int keyBeginLen, bool afterKey, const vector< const BSONElement * > &ke | |
| t * > &keyEnd, const Ordering &order, int direction ); | | yEnd, const vector< bool > &keyEndInclusive, const Ordering &order, int dir | |
| | | ection ); | |
| | | 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 ); | |
| | | | |
| DiskLoc getHead(const DiskLoc& thisLoc); | | DiskLoc getHead(const DiskLoc& thisLoc); | |
| | | | |
| /* get tree shape */ | | /* get tree shape */ | |
| void shape(stringstream&); | | void shape(stringstream&); | |
| | | | |
| static void a_test(IndexDetails&); | | static void a_test(IndexDetails&); | |
| | | | |
| private: | | private: | |
| void fixParentPtrs(const DiskLoc& thisLoc); | | void fixParentPtrs(const DiskLoc& thisLoc); | |
| | | | |
| skipping to change at line 262 | | skipping to change at line 263 | |
| return keyOfs >= n ? BSONObj() : keyNode(keyOfs).key; | | return keyOfs >= n ? BSONObj() : keyNode(keyOfs).key; | |
| } | | } | |
| static BtreeBucket* allocTemp(); /* caller must release with free()
*/ | | static BtreeBucket* allocTemp(); /* caller must release with free()
*/ | |
| void insertHere(DiskLoc thisLoc, int keypos, | | void insertHere(DiskLoc thisLoc, int keypos, | |
| DiskLoc recordLoc, const BSONObj& key, const Orderi
ng &order, | | DiskLoc recordLoc, const BSONObj& key, const Orderi
ng &order, | |
| DiskLoc lchild, DiskLoc rchild, IndexDetails&); | | DiskLoc lchild, DiskLoc rchild, IndexDetails&); | |
| int _insert(DiskLoc thisLoc, DiskLoc recordLoc, | | int _insert(DiskLoc thisLoc, DiskLoc recordLoc, | |
| const BSONObj& key, const Ordering &order, bool dupsAll
owed, | | const BSONObj& key, const Ordering &order, bool dupsAll
owed, | |
| DiskLoc lChild, DiskLoc rChild, IndexDetails&); | | DiskLoc lChild, DiskLoc rChild, IndexDetails&); | |
| bool find(const IndexDetails& idx, const BSONObj& key, DiskLoc reco
rdLoc, const Ordering &order, int& pos, bool assertIfDup); | | bool find(const IndexDetails& idx, const BSONObj& key, DiskLoc reco
rdLoc, const Ordering &order, int& pos, bool assertIfDup); | |
|
| bool customFind( int l, int h, const BSONObj &keyBegin, int keyBegi
nLen, const vector< const BSONElement * > &keyEnd, const Ordering &order, i
nt direction, DiskLoc &thisLoc, int &keyOfs, pair< DiskLoc, int > &bestPare
nt ); | | 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 ); | |
| 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, const vector< const BSONElement * > &rEnd, const Ordering &o
); | | 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 ); | |
| public: | | public: | |
| // simply builds and returns a dup key error message string | | // simply builds and returns a dup key error message string | |
| static string dupKeyError( const IndexDetails& idx , const BSONObj&
key ); | | static string dupKeyError( const IndexDetails& idx , const BSONObj&
key ); | |
| }; | | }; | |
| #pragma pack() | | #pragma pack() | |
| | | | |
| class BtreeCursor : public Cursor { | | class BtreeCursor : public Cursor { | |
| public: | | public: | |
| 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 ); | |
| | | | |
| | | | |
| skipping to change at line 367 | | skipping to change at line 368 | |
| } | | } | |
| | | | |
| void forgetEndKey() { endKey = BSONObj(); } | | void forgetEndKey() { endKey = BSONObj(); } | |
| | | | |
| virtual CoveredIndexMatcher *matcher() const { return _matcher.get(
); } | | virtual CoveredIndexMatcher *matcher() const { return _matcher.get(
); } | |
| | | | |
| virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher
) { | | virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher
) { | |
| _matcher = matcher; | | _matcher = matcher; | |
| } | | } | |
| | | | |
|
| | | virtual long long nscanned() { return _nscanned; } | |
| | | | |
| // for debugging only | | // for debugging only | |
| DiskLoc getBucket() const { return bucket; } | | DiskLoc getBucket() const { return bucket; } | |
| | | | |
| private: | | private: | |
| /* Our btrees may (rarely) have "unused" keys when items are delete
d. | | /* Our btrees may (rarely) have "unused" keys when items are delete
d. | |
| Skip past them. | | Skip past them. | |
| */ | | */ | |
| bool skipUnusedKeys( bool mayJump ); | | bool skipUnusedKeys( bool mayJump ); | |
| bool skipOutOfRangeKeysAndCheckEnd(); | | bool skipOutOfRangeKeysAndCheckEnd(); | |
| void skipAndCheck(); | | void skipAndCheck(); | |
| void checkEnd(); | | void checkEnd(); | |
| | | | |
| // selective audits on construction | | // selective audits on construction | |
| void audit(); | | void audit(); | |
| | | | |
| // set initial bucket | | // set initial bucket | |
| void init(); | | void init(); | |
| | | | |
|
| void advanceTo( const BSONObj &keyBegin, int keyBeginLen, const vec | | // if afterKey is true, we want the first key with values of the ke | |
| tor< const BSONElement * > &keyEnd); | | yBegin fields greater than keyBegin | |
| | | void advanceTo( const BSONObj &keyBegin, int keyBeginLen, bool afte | |
| | | rKey, const vector< const BSONElement * > &keyEnd, const vector< bool > &ke | |
| | | yEndInclusive ); | |
| | | | |
| friend class BtreeBucket; | | friend class BtreeBucket; | |
| set<DiskLoc> dups; | | set<DiskLoc> dups; | |
| NamespaceDetails *d; | | NamespaceDetails *d; | |
| int idxNo; | | int idxNo; | |
| | | | |
| BSONObj startKey; | | BSONObj startKey; | |
| BSONObj endKey; | | BSONObj endKey; | |
| bool endKeyInclusive_; | | bool endKeyInclusive_; | |
| | | | |
| | | | |
| skipping to change at line 411 | | skipping to change at line 415 | |
| DiskLoc bucket; | | DiskLoc bucket; | |
| int keyOfs; | | int keyOfs; | |
| int direction; // 1=fwd,-1=reverse | | 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; | |
| shared_ptr< FieldRangeVector > bounds_; | | shared_ptr< FieldRangeVector > bounds_; | |
| auto_ptr< FieldRangeVector::Iterator > _boundsIterator; | | auto_ptr< FieldRangeVector::Iterator > _boundsIterator; | |
| const IndexSpec& _spec; | | const IndexSpec& _spec; | |
| shared_ptr< CoveredIndexMatcher > _matcher; | | shared_ptr< CoveredIndexMatcher > _matcher; | |
| bool _independentFieldRanges; | | bool _independentFieldRanges; | |
|
| | | long long _nscanned; | |
| }; | | }; | |
| | | | |
| inline bool IndexDetails::hasKey(const BSONObj& key) { | | inline bool IndexDetails::hasKey(const BSONObj& key) { | |
| return head.btree()->exists(*this, head, key, Ordering::make(keyPat
tern())); | | return head.btree()->exists(*this, head, key, Ordering::make(keyPat
tern())); | |
| } | | } | |
| inline bool IndexDetails::wouldCreateDup(const BSONObj& key, DiskLoc se
lf) { | | inline bool IndexDetails::wouldCreateDup(const BSONObj& key, DiskLoc se
lf) { | |
| return head.btree()->wouldCreateDup(*this, head, key, Ordering::mak
e(keyPattern()), self); | | return head.btree()->wouldCreateDup(*this, head, key, Ordering::mak
e(keyPattern()), self); | |
| } | | } | |
| | | | |
| /* build btree from the bottom up */ | | /* build btree from the bottom up */ | |
| | | | |
End of changes. 6 change blocks. |
| 7 lines changed or deleted | | 18 lines changed or added | |
|
| clientcursor.h | | clientcursor.h | |
| | | | |
| skipping to change at line 79 | | skipping to change at line 79 | |
| public: | | public: | |
| static void assertNoCursors(); | | static void assertNoCursors(); | |
| | | | |
| /* use this to assure we don't in the background time out cursor wh
ile it is under use. | | /* use this to assure we don't in the background time out cursor wh
ile it is under use. | |
| if you are using noTimeout() already, there is no risk anyway. | | if you are using noTimeout() already, there is no risk anyway. | |
| Further, this mechanism guards against two getMore requests on t
he same cursor executing | | Further, this mechanism guards against two getMore requests on t
he same cursor executing | |
| at the same time - which might be bad. That should never happen
, but if a client driver | | at the same time - which might be bad. That should never happen
, but if a client driver | |
| had a bug, it could (or perhaps some sort of attack situation). | | had a bug, it could (or perhaps some sort of attack situation). | |
| */ | | */ | |
| class Pointer : boost::noncopyable { | | class Pointer : boost::noncopyable { | |
|
| public: | | | |
| ClientCursor *_c; | | ClientCursor *_c; | |
|
| | | public: | |
| | | ClientCursor * c() { return _c; } | |
| void release() { | | void release() { | |
| if( _c ) { | | if( _c ) { | |
| assert( _c->_pinValue >= 100 ); | | assert( _c->_pinValue >= 100 ); | |
| _c->_pinValue -= 100; | | _c->_pinValue -= 100; | |
|
| | | _c = 0; | |
| } | | } | |
|
| _c = 0; | | | |
| } | | } | |
|
| | | ~Pointer() { release(); } | |
| Pointer(long long cursorid) { | | Pointer(long long cursorid) { | |
| recursive_scoped_lock lock(ccmutex); | | recursive_scoped_lock lock(ccmutex); | |
| _c = ClientCursor::find_inlock(cursorid, true); | | _c = ClientCursor::find_inlock(cursorid, true); | |
| if( _c ) { | | if( _c ) { | |
| if( _c->_pinValue >= 100 ) { | | if( _c->_pinValue >= 100 ) { | |
| _c = 0; | | _c = 0; | |
|
| uassert(12051, "clientcursor already in use? driver
problem?", false); | | uasserted(12051, "clientcursor already in use? driv
er problem?"); | |
| } | | } | |
| _c->_pinValue += 100; | | _c->_pinValue += 100; | |
| } | | } | |
| } | | } | |
|
| ~Pointer() { | | | |
| release(); | | | |
| } | | | |
| }; | | }; | |
| | | | |
| // This object assures safe and reliable cleanup of the ClientCurso
r. | | // This object assures safe and reliable cleanup of the ClientCurso
r. | |
| // The implementation assumes that there will be no duplicate ids a
mong cursors | | // The implementation assumes that there will be no duplicate ids a
mong cursors | |
| // (which is assured if cursors must last longer than 1 second). | | // (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 ); | |
| } | | } | |
|
| | | | |
| if ( c ) { | | if ( c ) { | |
| _c = c; | | _c = c; | |
| _id = c->cursorid; | | _id = c->cursorid; | |
| } else { | | } else { | |
| _c = 0; | | _c = 0; | |
| _id = -1; | | _id = -1; | |
| } | | } | |
| } | | } | |
| ~CleanupPointer() { | | ~CleanupPointer() { | |
| DESTRUCTOR_GUARD ( reset(); ); | | DESTRUCTOR_GUARD ( reset(); ); | |
| | | | |
| skipping to change at line 163 | | skipping to change at line 159 | |
| _db( cc().database() ) | | _db( cc().database() ) | |
| { | | { | |
| assert( _db ); | | assert( _db ); | |
| assert( str::startsWith(_ns, _db->name) ); | | assert( str::startsWith(_ns, _db->name) ); | |
| if( queryOptions & QueryOption_NoCursorTimeout ) | | if( queryOptions & QueryOption_NoCursorTimeout ) | |
| noTimeout(); | | noTimeout(); | |
| recursive_scoped_lock lock(ccmutex); | | recursive_scoped_lock lock(ccmutex); | |
| cursorid = allocCursorId_inlock(); | | cursorid = allocCursorId_inlock(); | |
| clientCursorsById.insert( make_pair(cursorid, this) ); | | clientCursorsById.insert( make_pair(cursorid, this) ); | |
| } | | } | |
|
| | | | |
| ~ClientCursor(); | | ~ClientCursor(); | |
| | | | |
|
| DiskLoc lastLoc() const { | | DiskLoc lastLoc() const { return _lastLoc; } | |
| return _lastLoc; | | | |
| } | | | |
| | | | |
| shared_ptr< ParsedQuery > pq; | | shared_ptr< ParsedQuery > pq; | |
| shared_ptr< FieldMatcher > fields; // which fields query wants retu
rned | | shared_ptr< FieldMatcher > fields; // which fields query wants retu
rned | |
| Message originalMessage; // this is effectively an auto ptr for dat
a the matcher points to | | Message originalMessage; // this is effectively an auto ptr for dat
a the matcher points to | |
| | | | |
| /* Get rid of cursors for namespaces that begin with nsprefix. | | /* Get rid of cursors for namespaces that begin with nsprefix. | |
| Used by drop, dropIndexes, dropDatabase. | | Used by drop, dropIndexes, dropDatabase. | |
| */ | | */ | |
| static void invalidate(const char *nsPrefix); | | static void invalidate(const char *nsPrefix); | |
| | | | |
| | | | |
| skipping to change at line 217 | | skipping to change at line 212 | |
| cc->prepareToYield( _data ); | | cc->prepareToYield( _data ); | |
| _unlock.reset(new dbtempreleasecond()); | | _unlock.reset(new dbtempreleasecond()); | |
| } | | } | |
| } | | } | |
| ~YieldLock(){ | | ~YieldLock(){ | |
| if ( _unlock ){ | | if ( _unlock ){ | |
| log( LL_WARNING ) << "ClientCursor::YieldLock not close
d properly" << endl; | | log( LL_WARNING ) << "ClientCursor::YieldLock not close
d properly" << endl; | |
| relock(); | | relock(); | |
| } | | } | |
| } | | } | |
|
| | | | |
| bool stillOk(){ | | bool stillOk(){ | |
| if ( ! _canYield ) | | if ( ! _canYield ) | |
| return true; | | return true; | |
|
| | | | |
| relock(); | | relock(); | |
|
| | | | |
| return ClientCursor::recoverFromYield( _data ); | | return ClientCursor::recoverFromYield( _data ); | |
| } | | } | |
|
| | | | |
| void relock(){ | | void relock(){ | |
| _unlock.reset(); | | _unlock.reset(); | |
| } | | } | |
|
| | | | |
| private: | | private: | |
|
| bool _canYield; | | const bool _canYield; | |
| YieldData _data; | | YieldData _data; | |
|
| | | | |
| scoped_ptr<dbtempreleasecond> _unlock; | | scoped_ptr<dbtempreleasecond> _unlock; | |
|
| | | | |
| }; | | }; | |
| | | | |
| // --- some pass through helpers for Cursor --- | | // --- some pass through helpers for Cursor --- | |
| | | | |
|
| BSONObj indexKeyPattern() { | | BSONObj indexKeyPattern() { return c->indexKeyPattern(); } | |
| return c->indexKeyPattern(); | | bool ok() { return c->ok(); } | |
| } | | bool advance(){ return c->advance(); } | |
| | | BSONObj current() { return c->current(); } | |
| bool ok(){ | | | |
| return c->ok(); | | | |
| } | | | |
| | | | |
| bool advance(){ | | | |
| return c->advance(); | | | |
| } | | | |
| | | | |
| bool currentMatches(){ | | bool currentMatches(){ | |
| if ( ! c->matcher() ) | | if ( ! c->matcher() ) | |
| return true; | | return true; | |
| return c->matcher()->matchesCurrent( c.get() ); | | return c->matcher()->matchesCurrent( c.get() ); | |
| } | | } | |
| | | | |
|
| BSONObj current(){ | | | |
| return c->current(); | | | |
| } | | | |
| | | | |
| private: | | private: | |
| void setLastLoc_inlock(DiskLoc); | | void setLastLoc_inlock(DiskLoc); | |
| | | | |
| static ClientCursor* find_inlock(CursorId id, bool warn = true) { | | static ClientCursor* find_inlock(CursorId id, bool warn = true) { | |
| CCById::iterator it = clientCursorsById.find(id); | | CCById::iterator it = clientCursorsById.find(id); | |
| if ( it == clientCursorsById.end() ) { | | if ( it == clientCursorsById.end() ) { | |
| if ( warn ) | | if ( warn ) | |
| OCCASIONALLY out() << "ClientCursor::find(): cursor not
found in map " << id << " (ok after a drop)\n"; | | OCCASIONALLY out() << "ClientCursor::find(): cursor not
found in map " << id << " (ok after a drop)\n"; | |
| return 0; | | return 0; | |
| } | | } | |
| | | | |
End of changes. 22 change blocks. |
| 36 lines changed or deleted | | 13 lines changed or added | |
|
| cmdline.h | | cmdline.h | |
| | | | |
| skipping to change at line 30 | | skipping to change at line 30 | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| /* command line options | | /* command line options | |
| */ | | */ | |
| /* concurrency: OK/READ */ | | /* concurrency: OK/READ */ | |
| struct CmdLine { | | struct CmdLine { | |
| int port; // --port | | int port; // --port | |
| string bind_ip; // --bind_ip | | string bind_ip; // --bind_ip | |
| bool rest; // --rest | | bool rest; // --rest | |
|
| | | bool jsonp; // --jsonp | |
| | | | |
| string _replSet; // --replSet[/<seedlist>] | | string _replSet; // --replSet[/<seedlist>] | |
| string ourSetName() const { | | string ourSetName() const { | |
| string setname; | | string setname; | |
| size_t sl = _replSet.find('/'); | | size_t sl = _replSet.find('/'); | |
| if( sl == string::npos ) | | if( sl == string::npos ) | |
| return _replSet; | | return _replSet; | |
| return _replSet.substr(0, sl); | | return _replSet.substr(0, sl); | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 66 | | skipping to change at line 67 | |
| 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 | |
| | | | |
| enum { | | enum { | |
| DefaultDBPort = 27017, | | DefaultDBPort = 27017, | |
| ConfigServerPort = 27019, | | ConfigServerPort = 27019, | |
| ShardServerPort = 27018 | | ShardServerPort = 27018 | |
| }; | | }; | |
| | | | |
| CmdLine() : | | CmdLine() : | |
|
| port(DefaultDBPort), rest(false), quiet(false), notablescan(fal
se), prealloc(true), smallfiles(false), | | port(DefaultDBPort), rest(false), jsonp(false), quiet(false), n
otablescan(false), prealloc(true), smallfiles(false), | |
| quota(false), quotaFiles(8), cpu(false), oplogSize(0), defaultP
rofile(0), slowMS(100), pretouch(0), moveParanoia( true ) | | quota(false), quotaFiles(8), cpu(false), oplogSize(0), defaultP
rofile(0), slowMS(100), pretouch(0), moveParanoia( true ) | |
| { } | | { } | |
| | | | |
| 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 , | |
| | | boost::program_options::options_descr | |
| | | iption& hidden ); | |
| | | | |
| /** | | /** | |
| * @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 ); | |
| }; | | }; | |
| | | | |
| | | | |
End of changes. 3 change blocks. |
| 1 lines changed or deleted | | 7 lines changed or added | |
|
| connections.h | | connections.h | |
| | | | |
| skipping to change at line 47 | | skipping to change at line 47 | |
| } | | } | |
| | | | |
| throws exception on connect error (but fine to try again later with
a new | | throws exception on connect error (but fine to try again later with
a new | |
| 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(); | |
|
| | | DBClientConnection* operator->(); | |
| /* 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 | | | |
| 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) { | | | |
| return conn()->runCommand(dbname, cmd, info, options); | | | |
| } | | | |
| unsigned long long count(const string &ns) { | | | |
| return conn()->count(ns); | | | |
| } | | | |
| BSONObj findOne(const string &ns, const Query& q, const BSONObj *fi | | | |
| eldsToReturn = 0, int queryOptions = 0) { | | | |
| return conn()->findOne(ns, q, fieldsToReturn, queryOptions); | | | |
| } | | | |
| | | | |
| private: | | private: | |
| auto_ptr<scoped_lock> connLock; | | auto_ptr<scoped_lock> connLock; | |
| static mutex mapMutex; | | static mutex mapMutex; | |
| struct X { | | struct X { | |
| mutex z; | | mutex z; | |
| DBClientConnection cc; | | DBClientConnection cc; | |
|
| X() : z("X"), cc(/*reconnect*/ true, 0, | | X() : z("X"), cc(/*reconnect*/true, 0, /*timeout*/10) { | |
| /*timeout*/ theReplSet ? theReplSet->config(). | | | |
| ho.heartbeatTimeoutMillis/1000.0 : 10.0) { | | | |
| 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; } | | | |
| }; | | }; | |
| | | | |
| inline ScopedConn::ScopedConn(string hostport) { | | inline ScopedConn::ScopedConn(string hostport) { | |
| bool first = false; | | bool first = false; | |
| { | | { | |
| scoped_lock lk(mapMutex); | | scoped_lock lk(mapMutex); | |
| x = _map[hostport]; | | x = _map[hostport]; | |
| if( x == 0 ) { | | if( x == 0 ) { | |
| x = _map[hostport] = new X(); | | x = _map[hostport] = new X(); | |
| first = true; | | first = true; | |
| | | | |
| skipping to change at line 104 | | skipping to change at line 87 | |
| | | | |
| // we already locked above... | | // we already locked above... | |
| string err; | | string err; | |
| x->cc.connect(hostport, err); | | x->cc.connect(hostport, err); | |
| } | | } | |
| | | | |
| inline ScopedConn::~ScopedConn() { | | inline ScopedConn::~ScopedConn() { | |
| // conLock releases... | | // conLock releases... | |
| } | | } | |
| | | | |
|
| /*inline DBClientConnection* ScopedConn::operator->() { | | inline DBClientConnection* ScopedConn::operator->() { | |
| return &x->cc; | | return &x->cc; | |
|
| }*/ | | } | |
| | | | |
| } | | } | |
| | | | |
End of changes. 5 change blocks. |
| 27 lines changed or deleted | | 4 lines changed or added | |
|
| core.h | | core.h | |
| | | | |
| skipping to change at line 394 | | skipping to change at line 394 | |
| StringBuilder buf(32); | | StringBuilder buf(32); | |
| buf << "(" << _x << "," << _y << ")"; | | buf << "(" << _x << "," << _y << ")"; | |
| return buf.str(); | | return buf.str(); | |
| | | | |
| } | | } | |
| | | | |
| double _x; | | double _x; | |
| double _y; | | double _y; | |
| }; | | }; | |
| | | | |
|
| extern double EARTH_RADIUS_KM; | | extern const double EARTH_RADIUS_KM; | |
| extern double EARTH_RADIUS_MILES; | | extern const double EARTH_RADIUS_MILES; | |
| | | | |
| | | inline double deg2rad(double deg) { return deg * (M_PI/180); } | |
| | | inline double rad2deg(double rad) { return rad * (180/M_PI); } | |
| | | | |
| // WARNING: _x and _y MUST be longitude and latitude in that order | | // WARNING: _x and _y MUST be longitude and latitude in that order | |
| // note: multiply by earth radius for distance | | // note: multiply by earth radius for distance | |
| inline double spheredist_rad( const Point& p1, const Point& p2 ) { | | inline double spheredist_rad( const Point& p1, const Point& p2 ) { | |
| // this uses the n-vector formula: http://en.wikipedia.org/wiki/N-v
ector | | // this uses the n-vector formula: http://en.wikipedia.org/wiki/N-v
ector | |
| // If you try to match the code to the formula, note that I inline
the cross-product. | | // If you try to match the code to the formula, note that I inline
the cross-product. | |
| // TODO: optimize with SSE | | // TODO: optimize with SSE | |
| | | | |
| double sin_x1(sin(p1._x)), cos_x1(cos(p1._x)); | | double sin_x1(sin(p1._x)), cos_x1(cos(p1._x)); | |
| double sin_y1(sin(p1._y)), cos_y1(cos(p1._y)); | | double sin_y1(sin(p1._y)), cos_y1(cos(p1._y)); | |
| double sin_x2(sin(p2._x)), cos_x2(cos(p2._x)); | | double sin_x2(sin(p2._x)), cos_x2(cos(p2._x)); | |
| double sin_y2(sin(p2._y)), cos_y2(cos(p2._y)); | | double sin_y2(sin(p2._y)), cos_y2(cos(p2._y)); | |
| | | | |
| double cross_prod = | | double cross_prod = | |
| (cos_y1*cos_x1 * cos_y2*cos_x2) + | | (cos_y1*cos_x1 * cos_y2*cos_x2) + | |
| (cos_y1*sin_x1 * cos_y2*sin_x2) + | | (cos_y1*sin_x1 * cos_y2*sin_x2) + | |
| (sin_y1 * sin_y2); | | (sin_y1 * sin_y2); | |
| | | | |
|
| | | if (cross_prod >= 1 || cross_prod <= -1){ | |
| | | // fun with floats | |
| | | assert( fabs(cross_prod)-1 < 1e-6 ); | |
| | | return cross_prod > 0 ? 0 : M_PI; | |
| | | } | |
| | | | |
| return acos(cross_prod); | | return acos(cross_prod); | |
| } | | } | |
| | | | |
| // note: return is still in radians as that can be multiplied by radius
to get arc length | | // note: return is still in radians as that can be multiplied by radius
to get arc length | |
| inline double spheredist_deg( const Point& p1, const Point& p2 ) { | | inline double spheredist_deg( const Point& p1, const Point& p2 ) { | |
| return spheredist_rad( | | return spheredist_rad( | |
|
| Point( p1._x * (M_PI/180), p1._y * (M_PI/180)), | | Point( deg2rad(p1._x), deg2rad(p1._y) ), | |
| Point( p2._x * (M_PI/180), p2._y * (M_PI/180)) | | Point( deg2rad(p2._x), deg2rad(p2._y) ) | |
| ); | | ); | |
| } | | } | |
| | | | |
| } | | } | |
| | | | |
End of changes. 3 change blocks. |
| 4 lines changed or deleted | | 13 lines changed or added | |
|
| curop.h | | curop.h | |
| | | | |
| skipping to change at line 23 | | skipping to change at line 23 | |
| * | | * | |
| * 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 "namespace.h" | | #include "namespace.h" | |
| #include "client.h" | | #include "client.h" | |
| #include "../bson/util/atomic_int.h" | | #include "../bson/util/atomic_int.h" | |
|
| | | #include "../util/concurrency/spin_lock.h" | |
| #include "db.h" | | #include "db.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| /* lifespan is different than CurOp because of recursives with DBDirect
Client */ | | /* lifespan is different than CurOp because of recursives with DBDirect
Client */ | |
| class OpDebug { | | class OpDebug { | |
| public: | | public: | |
| StringBuilder str; | | StringBuilder str; | |
| | | | |
| void reset(){ | | void reset(){ | |
| str.reset(); | | str.reset(); | |
| } | | } | |
| }; | | }; | |
| | | | |
|
| | | class CachedBSONObj { | |
| | | public: | |
| | | | |
| | | static BSONObj _tooBig; // { $msg : "query not recording (too large | |
| | | )" } | |
| | | | |
| | | CachedBSONObj(){ | |
| | | _size = (int*)_buf; | |
| | | reset(); | |
| | | } | |
| | | | |
| | | void reset( int sz = 0 ){ | |
| | | _size[0] = sz; | |
| | | } | |
| | | | |
| | | void set( const BSONObj& o ){ | |
| | | _lock.lock(); | |
| | | try { | |
| | | int sz = o.objsize(); | |
| | | | |
| | | if ( sz > (int) sizeof(_buf) ) { | |
| | | reset(1); // flag as too big and return | |
| | | } | |
| | | else { | |
| | | memcpy(_buf, o.objdata(), sz ); | |
| | | } | |
| | | | |
| | | _lock.unlock(); | |
| | | } | |
| | | catch ( ... ){ | |
| | | _lock.unlock(); | |
| | | throw; | |
| | | } | |
| | | | |
| | | } | |
| | | | |
| | | int size() const { return *_size; } | |
| | | bool have() const { return size() > 0; } | |
| | | | |
| | | BSONObj get( bool threadSafe ){ | |
| | | _lock.lock(); | |
| | | | |
| | | BSONObj o; | |
| | | | |
| | | try { | |
| | | o = _get( threadSafe ); | |
| | | _lock.unlock(); | |
| | | } | |
| | | catch ( ... ){ | |
| | | _lock.unlock(); | |
| | | throw; | |
| | | } | |
| | | | |
| | | return o; | |
| | | | |
| | | } | |
| | | | |
| | | void append( BSONObjBuilder& b , const StringData& name ){ | |
| | | _lock.lock(); | |
| | | try { | |
| | | b.append( name , _get( false ) ); | |
| | | _lock.unlock(); | |
| | | } | |
| | | catch ( ... ){ | |
| | | _lock.unlock(); | |
| | | throw; | |
| | | } | |
| | | } | |
| | | | |
| | | private: | |
| | | | |
| | | /** you have to be locked when you call this */ | |
| | | BSONObj _get( bool getCopy ){ | |
| | | int sz = size(); | |
| | | | |
| | | if ( sz == 0 ) | |
| | | return BSONObj(); | |
| | | | |
| | | if ( sz == 1 ) | |
| | | return _tooBig; | |
| | | | |
| | | return BSONObj( _buf ).copy(); | |
| | | } | |
| | | | |
| | | SpinLock _lock; | |
| | | char _buf[512]; | |
| | | int * _size; | |
| | | }; | |
| | | | |
| /* Current operation (for the current Client). | | /* Current operation (for the current Client). | |
| an embedded member of Client class, and typically used from within t
he mutex there. */ | | an embedded member of Client class, and typically used from within t
he mutex there. */ | |
| class CurOp : boost::noncopyable { | | class CurOp : boost::noncopyable { | |
| static AtomicUInt _nextOpNum; | | static AtomicUInt _nextOpNum; | |
|
| static BSONObj _tooBig; // { $msg : "query not recording (too large
)" } | | | |
| | | | |
| 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; | |
| char _ns[Namespace::MaxNsLen+2]; | | char _ns[Namespace::MaxNsLen+2]; | |
| struct SockAddr _remote; | | struct SockAddr _remote; | |
|
| char _queryBuf[256]; | | CachedBSONObj _query; | |
| | | | |
| void resetQuery(int x=0) { *((int *)_queryBuf) = x; } | | | |
| | | | |
| OpDebug _debug; | | OpDebug _debug; | |
| | | | |
| ThreadSafeString _message; | | ThreadSafeString _message; | |
| ProgressMeter _progressMeter; | | ProgressMeter _progressMeter; | |
| | | | |
| void _reset(){ | | void _reset(){ | |
| _command = false; | | _command = false; | |
| _lockType = 0; | | _lockType = 0; | |
| _dbprofile = 0; | | _dbprofile = 0; | |
| | | | |
| skipping to change at line 84 | | skipping to change at line 170 | |
| _message = ""; | | _message = ""; | |
| _progressMeter.finished(); | | _progressMeter.finished(); | |
| } | | } | |
| | | | |
| void setNS(const char *ns) { | | void setNS(const char *ns) { | |
| strncpy(_ns, ns, Namespace::MaxNsLen); | | strncpy(_ns, ns, Namespace::MaxNsLen); | |
| } | | } | |
| | | | |
| public: | | public: | |
| | | | |
|
| int querySize() const { return *((int *) _queryBuf); } | | bool haveQuery() const { return _query.have(); } | |
| bool haveQuery() const { return querySize() != 0; } | | BSONObj query( bool threadSafe = false ){ return _query.get( thread | |
| | | Safe ); } | |
| BSONObj query( bool threadSafe = false); | | | |
| | | | |
| void ensureStarted(){ | | void ensureStarted(){ | |
| if ( _start == 0 ) | | if ( _start == 0 ) | |
| _start = _checkpoint = curTimeMicros64(); | | _start = _checkpoint = curTimeMicros64(); | |
| } | | } | |
| void enter( Client::Context * context ){ | | void enter( Client::Context * context ){ | |
| ensureStarted(); | | ensureStarted(); | |
| setNS( context->ns() ); | | setNS( context->ns() ); | |
| if ( context->_db && context->_db->profile > _dbprofile ) | | if ( context->_db && context->_db->profile > _dbprofile ) | |
| _dbprofile = context->_db->profile; | | _dbprofile = context->_db->profile; | |
| | | | |
| skipping to change at line 113 | | skipping to change at line 197 | |
| _checkpoint = now; | | _checkpoint = now; | |
| } | | } | |
| | | | |
| void reset(){ | | void reset(){ | |
| _reset(); | | _reset(); | |
| _start = _checkpoint = 0; | | _start = _checkpoint = 0; | |
| _active = true; | | _active = true; | |
| _opNum = _nextOpNum++; | | _opNum = _nextOpNum++; | |
| _ns[0] = '?'; // just in case not set later | | _ns[0] = '?'; // just in case not set later | |
| _debug.reset(); | | _debug.reset(); | |
|
| resetQuery(); | | _query.reset(); | |
| } | | } | |
| | | | |
| void reset( const SockAddr & remote, int op ) { | | void reset( const SockAddr & remote, int op ) { | |
| reset(); | | reset(); | |
| _remote = remote; | | _remote = remote; | |
| _op = op; | | _op = op; | |
| } | | } | |
| | | | |
| void markCommand(){ | | void markCommand(){ | |
| _command = true; | | _command = true; | |
| | | | |
| skipping to change at line 195 | | skipping to change at line 279 | |
| 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() { | | int elapsedSeconds() { | |
| return elapsedMillis() / 1000; | | return elapsedMillis() / 1000; | |
| } | | } | |
| | | | |
| void setQuery(const BSONObj& query) { | | void setQuery(const BSONObj& query) { | |
|
| if( query.objsize() > (int) sizeof(_queryBuf) ) { | | _query.set( query ); | |
| resetQuery(1); // flag as too big and return | | | |
| return; | | | |
| } | | | |
| memcpy(_queryBuf, query.objdata(), query.objsize()); | | | |
| } | | } | |
| | | | |
| Client * getClient() const { | | Client * getClient() const { | |
| return _client; | | return _client; | |
| } | | } | |
| | | | |
| CurOp( Client * client , CurOp * wrapped = 0 ) { | | CurOp( Client * client , CurOp * wrapped = 0 ) { | |
| _client = client; | | _client = client; | |
| _wrapped = wrapped; | | _wrapped = wrapped; | |
| if ( _wrapped ){ | | if ( _wrapped ){ | |
| _client->_curOp = this; | | _client->_curOp = this; | |
| } | | } | |
| _start = _checkpoint = 0; | | _start = _checkpoint = 0; | |
| _active = false; | | _active = false; | |
| _reset(); | | _reset(); | |
| _op = 0; | | _op = 0; | |
| // These addresses should never be written to again. The zeroe
s are | | // These addresses should never be written to again. The zeroe
s are | |
| // placed here as a precaution because currentOp may be accesse
d | | // placed here as a precaution because currentOp may be accesse
d | |
| // without the db mutex. | | // without the db mutex. | |
| memset(_ns, 0, sizeof(_ns)); | | memset(_ns, 0, sizeof(_ns)); | |
|
| memset(_queryBuf, 0, sizeof(_queryBuf)); | | | |
| } | | } | |
| | | | |
| ~CurOp(); | | ~CurOp(); | |
| | | | |
| BSONObj info() { | | BSONObj info() { | |
| if( ! cc().getAuthenticationInfo()->isAuthorized("admin") ) { | | if( ! cc().getAuthenticationInfo()->isAuthorized("admin") ) { | |
| BSONObjBuilder b; | | BSONObjBuilder b; | |
| b.append("err", "unauthorized"); | | b.append("err", "unauthorized"); | |
| return b.obj(); | | return b.obj(); | |
| } | | } | |
| return infoNoauth(); | | return infoNoauth(); | |
| } | | } | |
| | | | |
|
| BSONObj infoNoauth( int attempt = 0 ); | | BSONObj infoNoauth(); | |
| | | | |
| string getRemoteString( bool includePort = true ){ | | string getRemoteString( bool includePort = true ){ | |
| return _remote.toString(includePort); | | return _remote.toString(includePort); | |
| } | | } | |
| | | | |
| ProgressMeter& setMessage( const char * msg , long long progressMet
erTotal = 0 , int secondsBetween = 3 ){ | | ProgressMeter& setMessage( const char * msg , long long progressMet
erTotal = 0 , int secondsBetween = 3 ){ | |
| | | | |
| if ( progressMeterTotal ){ | | if ( progressMeterTotal ){ | |
| if ( _progressMeter.isActive() ){ | | if ( _progressMeter.isActive() ){ | |
| cout << "about to assert, old _message: " << _message <
< " new message:" << msg << endl; | | cout << "about to assert, old _message: " << _message <
< " new message:" << msg << endl; | |
| | | | |
End of changes. 9 change blocks. |
| 16 lines changed or deleted | | 97 lines changed or added | |
|
| cursor.h | | cursor.h | |
| | | | |
| skipping to change at line 99 | | skipping to change at line 99 | |
| @param deep - match was against an array, so we know it is multi
key. this is legacy and kept | | @param deep - match was against an array, so we know it is multi
key. this is legacy and kept | |
| for backwards datafile compatibility. 'deep' can
be eliminated next time we | | for backwards datafile compatibility. 'deep' can
be eliminated next time we | |
| force a data file conversion. 7Jul09 | | force a data file conversion. 7Jul09 | |
| */ | | */ | |
| virtual bool getsetdup(DiskLoc loc) = 0; | | virtual bool getsetdup(DiskLoc loc) = 0; | |
| | | | |
| virtual BSONObj prettyIndexBounds() const { return BSONArray(); } | | virtual BSONObj prettyIndexBounds() const { return BSONArray(); } | |
| | | | |
| virtual bool capped() const { return false; } | | virtual bool capped() const { return false; } | |
| | | | |
|
| | | 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. | |
| virtual CoveredIndexMatcher *matcher() const { return 0; } | | virtual CoveredIndexMatcher *matcher() const { return 0; } | |
| | | | |
| // 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 ); | |
| | | | |
| skipping to change at line 127 | | skipping to change at line 129 | |
| }; | | }; | |
| | | | |
| const AdvanceStrategy *forward(); | | const AdvanceStrategy *forward(); | |
| const AdvanceStrategy *reverse(); | | const AdvanceStrategy *reverse(); | |
| | | | |
| /* table-scan style cursor */ | | /* table-scan style cursor */ | |
| class BasicCursor : public Cursor { | | class BasicCursor : public Cursor { | |
| protected: | | protected: | |
| DiskLoc curr, last; | | DiskLoc curr, last; | |
| const AdvanceStrategy *s; | | const AdvanceStrategy *s; | |
|
| | | void incNscanned() { if ( !curr.isNull() ) { ++_nscanned; } } | |
| | | | |
| private: | | private: | |
| bool tailable_; | | bool tailable_; | |
| shared_ptr< CoveredIndexMatcher > _matcher; | | shared_ptr< CoveredIndexMatcher > _matcher; | |
|
| | | long long _nscanned; | |
| void init() { | | void init() { | |
| tailable_ = false; | | tailable_ = false; | |
| } | | } | |
| public: | | public: | |
| bool ok() { | | bool ok() { | |
| return !curr.isNull(); | | return !curr.isNull(); | |
| } | | } | |
| Record* _current() { | | Record* _current() { | |
| assert( ok() ); | | assert( ok() ); | |
| return curr.rec(); | | return curr.rec(); | |
| | | | |
| skipping to change at line 156 | | skipping to change at line 160 | |
| } | | } | |
| virtual DiskLoc currLoc() { | | virtual DiskLoc currLoc() { | |
| return curr; | | return curr; | |
| } | | } | |
| virtual DiskLoc refLoc() { | | virtual DiskLoc refLoc() { | |
| return curr.isNull() ? last : curr; | | return curr.isNull() ? last : curr; | |
| } | | } | |
| | | | |
| bool advance(); | | bool advance(); | |
| | | | |
|
| BasicCursor(DiskLoc dl, const AdvanceStrategy *_s = forward()) : cu | | BasicCursor(DiskLoc dl, const AdvanceStrategy *_s = forward()) : cu | |
| rr(dl), s( _s ) { | | rr(dl), s( _s ), _nscanned() { | |
| | | incNscanned(); | |
| init(); | | init(); | |
| } | | } | |
|
| BasicCursor(const AdvanceStrategy *_s = forward()) : s( _s ) { | | BasicCursor(const AdvanceStrategy *_s = forward()) : s( _s ), _nsca
nned() { | |
| init(); | | init(); | |
| } | | } | |
| virtual string toString() { | | virtual string toString() { | |
| return "BasicCursor"; | | return "BasicCursor"; | |
| } | | } | |
| virtual void setTailable() { | | virtual void setTailable() { | |
| if ( !curr.isNull() || !last.isNull() ) | | if ( !curr.isNull() || !last.isNull() ) | |
| tailable_ = true; | | tailable_ = true; | |
| } | | } | |
| virtual bool tailable() { | | virtual bool tailable() { | |
| | | | |
| skipping to change at line 183 | | skipping to change at line 188 | |
| | | | |
| virtual bool supportGetMore() { return true; } | | virtual bool supportGetMore() { return true; } | |
| virtual bool supportYields() { return true; } | | virtual bool supportYields() { return true; } | |
| | | | |
| virtual CoveredIndexMatcher *matcher() const { return _matcher.get(
); } | | virtual CoveredIndexMatcher *matcher() const { return _matcher.get(
); } | |
| | | | |
| virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher
) { | | virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher
) { | |
| _matcher = matcher; | | _matcher = matcher; | |
| } | | } | |
| | | | |
|
| | | virtual long long nscanned() { return _nscanned; } | |
| | | | |
| }; | | }; | |
| | | | |
| /* used for order { $natural: -1 } */ | | /* used for order { $natural: -1 } */ | |
| class ReverseCursor : public BasicCursor { | | class ReverseCursor : public BasicCursor { | |
| public: | | public: | |
| ReverseCursor(DiskLoc dl) : BasicCursor( dl, reverse() ) { } | | ReverseCursor(DiskLoc dl) : BasicCursor( dl, reverse() ) { } | |
| ReverseCursor() : BasicCursor( reverse() ) { } | | ReverseCursor() : BasicCursor( reverse() ) { } | |
| virtual string toString() { | | virtual string toString() { | |
| return "ReverseCursor"; | | return "ReverseCursor"; | |
| } | | } | |
| | | | |
End of changes. 6 change blocks. |
| 3 lines changed or deleted | | 10 lines changed or added | |
|
| database.h | | database.h | |
| | | | |
| skipping to change at line 36 | | skipping to change at line 36 | |
| | | | |
| /** | | /** | |
| * 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; | |
| | | | |
|
| Database(const char *nm, bool& newDb, const string& _path = dbpath) | | Database(const char *nm, /*out*/ bool& newDb, const string& _path = | |
| ; | | dbpath); | |
| | | private: | |
| ~Database() { | | ~Database(); | |
| magic = 0; | | public: | |
| btreeStore->closeFiles(name, path); | | /* you must use this to close - there is essential code in this met | |
| size_t n = files.size(); | | hod that is not in the ~Database destructor. | |
| for ( size_t i = 0; i < n; i++ ) | | thus the destructor is private. this could be cleaned up one da | |
| delete files[i]; | | y... | |
| } | | */ | |
| | | static void closeDatabase( const char *db, const string& path ); | |
| | | | |
| /** | | /** | |
| * tries to make sure that this hasn't been deleted | | * tries to make sure that this hasn't been deleted | |
| */ | | */ | |
|
| bool isOk(){ | | bool isOk() const { return magic == 781231; } | |
| return magic == 781231; | | | |
| } | | | |
| | | | |
| bool isEmpty(){ | | bool isEmpty(){ | |
| return ! namespaceIndex.allocated(); | | return ! namespaceIndex.allocated(); | |
| } | | } | |
| | | | |
|
| boost::filesystem::path fileName( int n ) { | | boost::filesystem::path fileName( int n ) const { | |
| stringstream ss; | | stringstream ss; | |
| ss << name << '.' << n; | | ss << name << '.' << n; | |
| boost::filesystem::path fullName; | | boost::filesystem::path fullName; | |
| fullName = boost::filesystem::path(path); | | fullName = boost::filesystem::path(path); | |
| if ( directoryperdb ) | | if ( directoryperdb ) | |
| fullName /= name; | | fullName /= name; | |
| fullName /= ss.str(); | | fullName /= ss.str(); | |
| return fullName; | | return fullName; | |
| } | | } | |
| | | | |
|
| bool exists(int n) { | | bool exists(int n) const { | |
| return boost::filesystem::exists( fileName( n ) ); | | return boost::filesystem::exists( fileName( n ) ); | |
| } | | } | |
| | | | |
| void openAllFiles() { | | void openAllFiles() { | |
| int n = 0; | | int n = 0; | |
| while( exists(n) ) { | | while( exists(n) ) { | |
| getFile(n); | | getFile(n); | |
| n++; | | n++; | |
| } | | } | |
| // If last file is empty, consider it preallocated and make sur
e it's not mapped | | // If last file is empty, consider it preallocated and make sur
e it's not mapped | |
| | | | |
| skipping to change at line 178 | | skipping to change at line 175 | |
| int n = (int) files.size(); | | int n = (int) files.size(); | |
| if ( n > 0 ) { | | if ( n > 0 ) { | |
| n--; | | n--; | |
| } else { | | } else { | |
| return 0; | | return 0; | |
| } | | } | |
| return getFile(n); | | return getFile(n); | |
| } | | } | |
| | | | |
| /** | | /** | |
|
| * @return true if success, false otherwise | | * @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 finishInit(); | | void finishInit(); | |
| | | | |
| static bool validDBName( const string& ns ); | | static bool validDBName( const string& ns ); | |
| | | | |
| long long fileSize(){ | | long long fileSize(){ | |
| long long size=0; | | long long size=0; | |
| for (int n=0; exists(n); n++) | | for (int n=0; exists(n); n++) | |
| size += boost::filesystem::file_size( fileName(n) ); | | size += boost::filesystem::file_size( fileName(n) ); | |
| return size; | | return size; | |
| } | | } | |
| | | | |
| void flushFiles( bool sync ); | | void flushFiles( bool sync ); | |
| | | | |
| vector<MongoDataFile*> files; | | vector<MongoDataFile*> files; | |
|
| string name; // "alleyinsider" | | const string name; // "alleyinsider" | |
| string path; | | const string path; | |
| NamespaceIndex namespaceIndex; | | NamespaceIndex namespaceIndex; | |
| int profile; // 0=off. | | int profile; // 0=off. | |
|
| string profileName; // "alleyinsider.system.profile" | | const string profileName; // "alleyinsider.system.profile" | |
| | | | |
| multimap<DiskLoc, ClientCursor*> ccByLoc; | | multimap<DiskLoc, ClientCursor*> 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. 8 change blocks. |
| 21 lines changed or deleted | | 18 lines changed or added | |
|
| dbclient.h | | dbclient.h | |
| | | | |
| skipping to change at line 798 | | skipping to change at line 798 | |
| boost::scoped_ptr<SockAddr> server; | | boost::scoped_ptr<SockAddr> server; | |
| bool failed; // true if some sort of fatal error has ever happened | | bool failed; // true if some sort of fatal error has ever happened | |
| bool autoReconnect; | | bool autoReconnect; | |
| time_t lastReconnectTry; | | time_t lastReconnectTry; | |
| HostAndPort _server; // remember for reconnects | | HostAndPort _server; // remember for reconnects | |
| string _serverString; | | string _serverString; | |
| int _port; | | int _port; | |
| void _checkConnection(); | | void _checkConnection(); | |
| void checkConnection() { if( failed ) _checkConnection(); } | | void checkConnection() { if( failed ) _checkConnection(); } | |
| map< string, pair<string,string> > authCache; | | map< string, pair<string,string> > authCache; | |
|
| double _timeout; | | int _timeout; | |
| | | | |
| bool _connect( string& errmsg ); | | bool _connect( string& errmsg ); | |
| public: | | public: | |
| | | | |
| /** | | /** | |
| @param _autoReconnect if true, automatically reconnect on a conn
ection failure | | @param _autoReconnect if true, automatically reconnect on a conn
ection failure | |
| @param cp used by DBClientReplicaSet. You do not need to specif
y this parameter | | @param cp used by DBClientReplicaSet. You do not need to specif
y this parameter | |
| @param timeout tcp timeout in seconds - this is for read/write,
not connect. | | @param timeout tcp timeout in seconds - this is for read/write,
not connect. | |
| Connect timeout is fixed, but short, at 5 seconds. | | Connect timeout is fixed, but short, at 5 seconds. | |
| */ | | */ | |
|
| DBClientConnection(bool _autoReconnect=false, DBClientReplicaSet* c
p=0, double timeout=0) : | | DBClientConnection(bool _autoReconnect=false, DBClientReplicaSet* c
p=0, int timeout=0) : | |
| clientSet(cp), failed(false), autoReconnect(_autoReconnect)
, lastReconnectTry(0), _timeout(timeout) { } | | clientSet(cp), failed(false), autoReconnect(_autoReconnect)
, lastReconnectTry(0), _timeout(timeout) { } | |
| | | | |
| /** Connect to a Mongo database server. | | /** Connect to a Mongo database server. | |
| | | | |
| If autoReconnect is true, you can try to use the DBClientConnect
ion even when | | If autoReconnect is true, you can try to use the DBClientConnect
ion even when | |
| false was returned -- it will try to connect again. | | false was returned -- it will try to connect again. | |
| | | | |
| @param serverHostname host to connect to. can include port numb
er ( 127.0.0.1 , 127.0.0.1:5555 ) | | @param serverHostname host to connect to. can include port numb
er ( 127.0.0.1 , 127.0.0.1:5555 ) | |
| If you use IPv6 you must add a port number
( ::1:27017 ) | | If you use IPv6 you must add a port number
( ::1:27017 ) | |
| @param errmsg any relevant error message will appended to the st
ring | | @param errmsg any relevant error message will appended to the st
ring | |
| | | | |
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 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 "../db/jsobj.h" | | #include "../db/jsobj.h" | |
| | | | |
|
| extern const char * jsconcatcode; // TODO: change name to mongoJSCode | | | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
|
| | | struct JSFile { | |
| | | const char* name; | |
| | | const StringData& source; | |
| | | }; | |
| | | | |
| | | namespace JSFiles { | |
| | | extern const JSFile collection; | |
| | | extern const JSFile db; | |
| | | extern const JSFile mongo; | |
| | | extern const JSFile mr; | |
| | | extern const JSFile query; | |
| | | extern const JSFile servers; | |
| | | extern const JSFile utils; | |
| | | } | |
| | | | |
| typedef unsigned long long ScriptingFunction; | | typedef unsigned long long ScriptingFunction; | |
| typedef BSONObj (*NativeFunction) ( const BSONObj &args ); | | typedef BSONObj (*NativeFunction) ( const BSONObj &args ); | |
| | | | |
| class Scope : boost::noncopyable { | | class Scope : boost::noncopyable { | |
| public: | | public: | |
| Scope(); | | Scope(); | |
| virtual ~Scope(); | | virtual ~Scope(); | |
| | | | |
| virtual void reset() = 0; | | virtual void reset() = 0; | |
| virtual void init( BSONObj * data ) = 0; | | virtual void init( BSONObj * data ) = 0; | |
| void init( const char * data ){ | | void init( const char * data ){ | |
| BSONObj o( data , 0 ); | | BSONObj o( data , 0 ); | |
| init( &o ); | | init( &o ); | |
| } | | } | |
| | | | |
| virtual void localConnect( const char * dbName ) = 0; | | virtual void localConnect( const char * dbName ) = 0; | |
| virtual void externalSetup() = 0; | | virtual void externalSetup() = 0; | |
| | | | |
|
| | | class NoDBAccess { | |
| | | Scope * _s; | |
| | | public: | |
| | | NoDBAccess( Scope * s ){ | |
| | | _s = s; | |
| | | } | |
| | | ~NoDBAccess(){ | |
| | | _s->rename( "____db____" , "db" ); | |
| | | } | |
| | | }; | |
| | | NoDBAccess disableDBAccess( const char * why ){ | |
| | | rename( "db" , "____db____" ); | |
| | | return NoDBAccess( this ); | |
| | | } | |
| | | | |
| virtual double getNumber( const char *field ) = 0; | | virtual double getNumber( const char *field ) = 0; | |
| virtual int getNumberInt( const char *field ){ return (int)getNumbe
r( field ); } | | virtual int getNumberInt( const char *field ){ return (int)getNumbe
r( field ); } | |
| virtual long long getNumberLongLong( const char *field ){ return (l
ong long)getNumber( field ); } | | virtual long long getNumberLongLong( const char *field ){ return (l
ong long)getNumber( field ); } | |
| virtual string getString( const char *field ) = 0; | | virtual string getString( const char *field ) = 0; | |
| virtual bool getBoolean( const char *field ) = 0; | | virtual bool getBoolean( const char *field ) = 0; | |
| virtual BSONObj getObject( const char *field ) = 0; | | virtual BSONObj getObject( const char *field ) = 0; | |
| | | | |
| virtual int type( const char *field ) = 0; | | virtual int type( const char *field ) = 0; | |
| | | | |
| void append( BSONObjBuilder & builder , const char * fieldName , co
nst char * scopeName ); | | void append( BSONObjBuilder & builder , const char * fieldName , co
nst char * scopeName ); | |
| | | | |
| virtual void setElement( const char *field , const BSONElement& e )
= 0; | | virtual void setElement( const char *field , const BSONElement& e )
= 0; | |
| virtual void setNumber( const char *field , double val ) = 0; | | virtual void setNumber( const char *field , double val ) = 0; | |
| virtual void setString( const char *field , const char * val ) = 0; | | virtual void setString( const char *field , const char * val ) = 0; | |
| virtual void setObject( const char *field , const BSONObj& obj , bo
ol readOnly=true ) = 0; | | virtual void setObject( const char *field , const BSONObj& obj , bo
ol readOnly=true ) = 0; | |
| virtual void setBoolean( const char *field , bool val ) = 0; | | virtual void setBoolean( const char *field , bool val ) = 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; | |
| /** | | /** | |
| * @return 0 on success | | * @return 0 on success | |
| */ | | */ | |
| virtual int invoke( ScriptingFunction func , const BSONObj& args, i
nt timeoutMs = 0 , bool ignoreReturn = false ) = 0; | | virtual int invoke( ScriptingFunction func , const BSONObj& args, i
nt timeoutMs = 0 , bool ignoreReturn = false ) = 0; | |
| void invokeSafe( ScriptingFunction func , const BSONObj& args, int
timeoutMs = 0 ){ | | void invokeSafe( ScriptingFunction func , const BSONObj& args, int
timeoutMs = 0 ){ | |
| int res = invoke( func , args , timeoutMs ); | | int res = invoke( func , args , timeoutMs ); | |
| if ( res == 0 ) | | if ( res == 0 ) | |
| return; | | return; | |
| throw UserException( 9004 , (string)"invoke failed: " + getErro
r() ); | | throw UserException( 9004 , (string)"invoke failed: " + getErro
r() ); | |
| } | | } | |
| virtual string getError() = 0; | | virtual string getError() = 0; | |
| | | | |
| int invoke( const char* code , const BSONObj& args, int timeoutMs =
0 ); | | int invoke( const char* code , const BSONObj& args, int timeoutMs =
0 ); | |
| void invokeSafe( const char* code , const BSONObj& args, int timeou
tMs = 0 ){ | | void invokeSafe( const char* code , const BSONObj& args, int timeou
tMs = 0 ){ | |
| if ( invoke( code , args , timeoutMs ) == 0 ) | | if ( invoke( code , args , timeoutMs ) == 0 ) | |
| return; | | return; | |
| throw UserException( 9005 , (string)"invoke failed: " + getErro
r() ); | | throw UserException( 9005 , (string)"invoke failed: " + getErro
r() ); | |
| } | | } | |
| | | | |
|
| virtual bool exec( const string& code , const string& name , bool p | | virtual bool exec( const StringData& code , const string& name , bo | |
| rintResult , bool reportError , bool assertOnError, int timeoutMs = 0 ) = 0 | | ol printResult , bool reportError , bool assertOnError, int timeoutMs = 0 ) | |
| ; | | = 0; | |
| virtual void execSetup( const string& code , const string& name = " | | virtual void execSetup( const StringData& code , const string& name | |
| setup" ){ | | = "setup" ){ | |
| exec( code , name , false , true , true , 0 ); | | exec( code , name , false , true , true , 0 ); | |
| } | | } | |
|
| | | | |
| | | void execSetup( const JSFile& file){ | |
| | | execSetup(file.source, file.name); | |
| | | } | |
| | | | |
| | | void execCoreFiles(){ | |
| | | // keeping same order as in SConstruct | |
| | | execSetup(JSFiles::utils); | |
| | | execSetup(JSFiles::db); | |
| | | execSetup(JSFiles::mongo); | |
| | | execSetup(JSFiles::mr); | |
| | | execSetup(JSFiles::query); | |
| | | execSetup(JSFiles::collection); | |
| | | } | |
| | | | |
| virtual bool execFile( const string& filename , bool printResult ,
bool reportError , bool assertOnError, int timeoutMs = 0 ); | | virtual bool execFile( const string& filename , bool printResult ,
bool reportError , bool assertOnError, int timeoutMs = 0 ); | |
| | | | |
| virtual void injectNative( const char *field, NativeFunction func )
= 0; | | virtual void injectNative( const char *field, NativeFunction func )
= 0; | |
| | | | |
| virtual void gc() = 0; | | virtual void gc() = 0; | |
| | | | |
| void loadStored( bool ignoreNotConnected = false ); | | void loadStored( bool ignoreNotConnected = false ); | |
| | | | |
| /** | | /** | |
| if any changes are made to .system.js, call this | | if any changes are made to .system.js, call this | |
| | | | |
End of changes. 6 change blocks. |
| 7 lines changed or deleted | | 51 lines changed or added | |
|
| log.h | | log.h | |
| | | | |
| skipping to change at line 83 | | skipping to change at line 83 | |
| virtual Nullstream& operator<< (Tee* tee) { | | virtual Nullstream& operator<< (Tee* tee) { | |
| return *this; | | return *this; | |
| } | | } | |
| virtual ~Nullstream() {} | | virtual ~Nullstream() {} | |
| virtual Nullstream& operator<<(const char *) { | | virtual Nullstream& operator<<(const char *) { | |
| return *this; | | return *this; | |
| } | | } | |
| virtual Nullstream& operator<<(const string& ) { | | virtual Nullstream& operator<<(const string& ) { | |
| return *this; | | return *this; | |
| } | | } | |
|
| | | virtual Nullstream& operator<<(const StringData& ) { | |
| | | return *this; | |
| | | } | |
| virtual Nullstream& operator<<(char *) { | | virtual Nullstream& operator<<(char *) { | |
| return *this; | | return *this; | |
| } | | } | |
| virtual Nullstream& operator<<(char) { | | virtual Nullstream& operator<<(char) { | |
| return *this; | | return *this; | |
| } | | } | |
| virtual Nullstream& operator<<(int) { | | virtual Nullstream& operator<<(int) { | |
| return *this; | | return *this; | |
| } | | } | |
| virtual Nullstream& operator<<(ExitCode) { | | virtual Nullstream& operator<<(ExitCode) { | |
| | | | |
| skipping to change at line 172 | | skipping to change at line 175 | |
| | | | |
| static void setLogFile(FILE* f){ | | static void setLogFile(FILE* f){ | |
| scoped_lock lk(mutex); | | scoped_lock lk(mutex); | |
| logfile = f; | | logfile = f; | |
| } | | } | |
| | | | |
| static int magicNumber(){ | | static int magicNumber(){ | |
| return 1717; | | return 1717; | |
| } | | } | |
| | | | |
|
| | | static int getLogDesc() { | |
| | | int fd = -1; | |
| | | if (logfile != NULL) | |
| | | fd = fileno( logfile ); | |
| | | return fd; | |
| | | } | |
| | | | |
| inline void flush(Tee *t = 0); | | inline 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<<(char *x) { ss << x; return *this; } | | Logstream& operator<<(char *x) { ss << x; return *this; } | |
| Logstream& operator<<(char x) { ss << x; return *this; } | | Logstream& operator<<(char x) { ss << x; return *this; } | |
| Logstream& operator<<(int x) { ss << x; return *this; } | | Logstream& operator<<(int x) { ss << x; return *this; } | |
| Logstream& operator<<(ExitCode x) { ss << x; return *this; } | | Logstream& operator<<(ExitCode x) { ss << x; return *this; } | |
| Logstream& operator<<(long x) { ss << x; return *this; } | | Logstream& operator<<(long x) { ss << x; return *this; } | |
| Logstream& operator<<(unsigned long x) { ss << x; return *this; } | | Logstream& operator<<(unsigned long x) { ss << x; return *this; } | |
| Logstream& operator<<(unsigned x) { ss << x; return *this; } | | Logstream& operator<<(unsigned x) { ss << x; return *this; } | |
| Logstream& operator<<(double x) { ss << x; return *this; } | | Logstream& operator<<(double x) { ss << x; return *this; } | |
| Logstream& operator<<(void *x) { ss << x; return *this; } | | Logstream& operator<<(void *x) { ss << x; return *this; } | |
| Logstream& operator<<(const void *x) { ss << x; return *this; } | | Logstream& operator<<(const void *x) { ss << x; return *this; } | |
| | | | |
| skipping to change at line 378 | | skipping to change at line 389 | |
| 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 ){ | | void Logstream::logLockless( const StringData& s ){ | |
| if ( doneSetup == 1717 ){ | | if ( doneSetup == 1717 ){ | |
| if(fwrite(s.data(), s.size(), 1, logfile)){ | | if(fwrite(s.data(), s.size(), 1, logfile)){ | |
| fflush(logfile); | | fflush(logfile); | |
| }else{ | | }else{ | |
| int x = errno; | | int x = errno; | |
|
| cout << "Failed to write to logfile: " << errnoWithDescript
ion(x) << ": " << out << endl; | | cout << "Failed to write to logfile: " << errnoWithDescript
ion(x) << endl; | |
| } | | } | |
| } | | } | |
| else { | | else { | |
|
| cout << s.data() << endl; | | cout << s.data(); | |
| | | cout.flush(); | |
| } | | } | |
| } | | } | |
| | | | |
| void Logstream::flush(Tee *t) { | | void Logstream::flush(Tee *t) { | |
| // this ensures things are sane | | // this ensures things are sane | |
| if ( doneSetup == 1717 ) { | | if ( doneSetup == 1717 ) { | |
| string msg = ss.str(); | | string msg = ss.str(); | |
| string threadName = getThreadName(); | | string threadName = getThreadName(); | |
| const char * type = logLevelToString(logLevel); | | const char * type = logLevelToString(logLevel); | |
| | | | |
| | | | |
End of changes. 5 change blocks. |
| 2 lines changed or deleted | | 14 lines changed or added | |
|
| message.h | | message.h | |
| | | | |
| skipping to change at line 89 | | skipping to change at line 89 | |
| 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; | |
| | | | |
| virtual int getClientId(){ | | virtual int getClientId(){ | |
| int x = remotePort(); | | int x = remotePort(); | |
| x = x << 16; | | x = x << 16; | |
|
| x |= ( ( 0xFF0 & (long long)this ) >> 8 ); // lowest byte in po
inter often meaningless | | | |
| return x; | | return x; | |
| } | | } | |
| }; | | }; | |
| | | | |
| class MessagingPort : public AbstractMessagingPort { | | class MessagingPort : public AbstractMessagingPort { | |
| public: | | public: | |
| MessagingPort(int sock, const SockAddr& farEnd); | | MessagingPort(int sock, const SockAddr& farEnd); | |
| | | | |
| // in some cases the timeout will actually be 2x this value - eg we
do a partial send, | | // in some cases the timeout will actually be 2x this value - eg we
do a partial send, | |
| // then the timeout fires, then we try to send again, then the time
out fires again with | | // then the timeout fires, then we try to send again, then the time
out fires again with | |
| // no data sent, then we detect that the other side is down | | // no data sent, then we detect that the other side is down | |
|
| MessagingPort(double timeout = 0, int logLevel = 0 ); | | MessagingPort(int timeout = 0, int logLevel = 0 ); | |
| | | | |
| virtual ~MessagingPort(); | | virtual ~MessagingPort(); | |
| | | | |
| void shutdown(); | | void shutdown(); | |
| | | | |
| bool connect(SockAddr& farEnd); | | bool connect(SockAddr& farEnd); | |
| | | | |
| /* it's assumed if you reuse a message object, that it doesn't cros
s MessagingPort's. | | /* it's assumed if you reuse a message object, that it doesn't cros
s MessagingPort's. | |
| also, the Message data will go out of scope on the subsequent re
cv call. | | also, the Message data will go out of scope on the subsequent re
cv call. | |
| */ | | */ | |
| | | | |
| skipping to change at line 136 | | skipping to change at line 135 | |
| | | | |
| // recv len or throw SocketException | | // recv len or throw SocketException | |
| void recv( char * data , int len ); | | void recv( char * data , int len ); | |
| | | | |
| int unsafe_recv( char *buf, int max ); | | int unsafe_recv( char *buf, int max ); | |
| private: | | private: | |
| int sock; | | int sock; | |
| PiggyBackData * piggyBackData; | | PiggyBackData * piggyBackData; | |
| public: | | public: | |
| SockAddr farEnd; | | SockAddr farEnd; | |
|
| double _timeout; | | int _timeout; | |
| int _logLevel; // passed to log() when logging errors | | int _logLevel; // passed to log() when logging errors | |
| | | | |
| static void closeAllSockets(unsigned tagMask = 0xffffffff); | | static void closeAllSockets(unsigned tagMask = 0xffffffff); | |
| | | | |
| /* 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; | |
| | | | |
| friend class PiggyBackData; | | friend class PiggyBackData; | |
| }; | | }; | |
| | | | |
| | | | |
End of changes. 3 change blocks. |
| 3 lines changed or deleted | | 2 lines changed or added | |
|
| mutex.h | | mutex.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 <map> | | #include <map> | |
| #include <set> | | #include <set> | |
| | | | |
|
| | | #include "../heapcheck.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| extern bool __destroyingStatics; | | extern bool __destroyingStatics; | |
| class mutex; | | class mutex; | |
| | | | |
| // only used on _DEBUG builds: | | // only used on _DEBUG builds: | |
| class MutexDebugger { | | class MutexDebugger { | |
| typedef const char * mid; // mid = mutex ID | | typedef const char * mid; // mid = mutex ID | |
| typedef map<mid,int> Preceeding; | | typedef map<mid,int> Preceeding; | |
| map< mid, int > maxNest; | | map< mid, int > maxNest; | |
| | | | |
| skipping to change at line 50 | | skipping to change at line 52 | |
| // so | | // so | |
| // a.lock(); b.lock(); is fine | | // a.lock(); b.lock(); is fine | |
| // b.lock(); alone is fine too | | // b.lock(); alone is fine too | |
| // only checked on _DEBUG builds. | | // only checked on _DEBUG builds. | |
| string a,b; | | string a,b; | |
| | | | |
| void aBreakPoint(){} | | void aBreakPoint(){} | |
| void programEnding(); | | void programEnding(); | |
| MutexDebugger(); | | MutexDebugger(); | |
| void entering(mid m) { | | void entering(mid m) { | |
|
| if( magic != 0x12345678 ) return; | | if( this == 0 ) return; | |
| | | assert( magic == 0x12345678 ); | |
| | | | |
| Preceeding *_preceeding = us.get(); | | Preceeding *_preceeding = us.get(); | |
| if( _preceeding == 0 ) | | if( _preceeding == 0 ) | |
| us.reset( _preceeding = new Preceeding() ); | | us.reset( _preceeding = new Preceeding() ); | |
| Preceeding &preceeding = *_preceeding; | | Preceeding &preceeding = *_preceeding; | |
| | | | |
| if( a == m ) { | | if( a == m ) { | |
| aBreakPoint(); | | aBreakPoint(); | |
| if( preceeding[b.c_str()] ) { | | if( preceeding[b.c_str()] ) { | |
| cout << "mutex problem " << b << " was locked before "
<< a << endl; | | cout << "mutex problem " << b << " was locked before "
<< a << endl; | |
| | | | |
| skipping to change at line 109 | | skipping to change at line 112 | |
| } | | } | |
| } | | } | |
| } | | } | |
| } | | } | |
| if( failed ) { | | if( failed ) { | |
| cout << err << endl; | | cout << err << endl; | |
| assert( 0 ); | | assert( 0 ); | |
| } | | } | |
| } | | } | |
| void leaving(mid m) { | | void leaving(mid m) { | |
|
| if( magic != 0x12345678 ) return; | | if( this == 0 ) return; // still in startup pre-main() | |
| Preceeding& preceeding = *us.get(); | | Preceeding& preceeding = *us.get(); | |
| preceeding[m]--; | | preceeding[m]--; | |
| if( preceeding[m] < 0 ) { | | if( preceeding[m] < 0 ) { | |
| cout << "ERROR: lock count for " << m << " is " << preceedi
ng[m] << endl; | | cout << "ERROR: lock count for " << m << " is " << preceedi
ng[m] << endl; | |
| assert( preceeding[m] >= 0 ); | | assert( preceeding[m] >= 0 ); | |
| } | | } | |
| } | | } | |
| }; | | }; | |
| extern MutexDebugger &mutexDebugger; | | extern MutexDebugger &mutexDebugger; | |
| | | | |
| | | | |
| skipping to change at line 145 | | skipping to change at line 148 | |
| #endif | | #endif | |
| | | | |
| #if defined(_DEBUG) | | #if defined(_DEBUG) | |
| mutex(const char *name) | | mutex(const char *name) | |
| : _name(name) | | : _name(name) | |
| #else | | #else | |
| mutex(const char *) | | mutex(const char *) | |
| #endif | | #endif | |
| { | | { | |
| _m = new boost::mutex(); | | _m = new boost::mutex(); | |
|
| | | IGNORE_OBJECT( _m ); // Turn-off heap checking on _m | |
| } | | } | |
| ~mutex() { | | ~mutex() { | |
| if( !__destroyingStatics ) { | | if( !__destroyingStatics ) { | |
|
| | | UNIGNORE_OBJECT( _m ); | |
| delete _m; | | delete _m; | |
| } | | } | |
| } | | } | |
| class scoped_lock : boost::noncopyable { | | class scoped_lock : boost::noncopyable { | |
| #if defined(_DEBUG) | | #if defined(_DEBUG) | |
| mongo::mutex *mut; | | mongo::mutex *mut; | |
| #endif | | #endif | |
| public: | | public: | |
| scoped_lock( mongo::mutex &m ) : _l( m.boost() ) { | | scoped_lock( mongo::mutex &m ) : _l( m.boost() ) { | |
| #if defined(_DEBUG) | | #if defined(_DEBUG) | |
| | | | |
End of changes. 5 change blocks. |
| 2 lines changed or deleted | | 7 lines changed or added | |
|
| queryoptimizer.h | | queryoptimizer.h | |
| | | | |
| skipping to change at line 117 | | skipping to change at line 117 | |
| } | | } | |
| _init(); | | _init(); | |
| } | | } | |
| virtual void next() = 0; | | virtual void next() = 0; | |
| | | | |
| virtual bool mayRecordPlan() const = 0; | | virtual bool mayRecordPlan() const = 0; | |
| | | | |
| virtual bool prepareToYield() { massert( 13335, "yield not supporte
d", false ); return false; } | | virtual bool prepareToYield() { massert( 13335, "yield not supporte
d", false ); return false; } | |
| virtual void recoverFromYield() { massert( 13336, "yield not suppor
ted", false ); } | | virtual void recoverFromYield() { massert( 13336, "yield not suppor
ted", false ); } | |
| | | | |
|
| | | virtual long long nscanned() = 0; | |
| | | | |
| /** @return a copy of the inheriting class, which will be run with
its own | | /** @return a copy of the inheriting class, which will be run with
its own | |
| query plan. If multiple plan sets are required for an
$or query, | | query plan. If multiple plan sets are required for an
$or query, | |
| the QueryOp of the winning plan from a given set will b
e cloned | | the QueryOp of the winning plan from a given set will b
e cloned | |
| to generate QueryOps for the subsequent plan set. This
function | | to generate QueryOps for the subsequent plan set. This
function | |
| should only be called after the query op has completed
executing. | | should only be called after the query op has completed
executing. | |
| */ | | */ | |
| QueryOp *createChild() { | | QueryOp *createChild() { | |
| if( _orConstraint.get() ) { | | if( _orConstraint.get() ) { | |
| _matcher->advanceOrClause( _orConstraint ); | | _matcher->advanceOrClause( _orConstraint ); | |
| _orConstraint.reset(); | | _orConstraint.reset(); | |
| | | | |
| skipping to change at line 315 | | skipping to change at line 317 | |
| 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
= false ) | | MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj
&order, shared_ptr< CursorOp > op = shared_ptr< CursorOp >(), bool mayYield
= false ) | |
|
| : _mps( new MultiPlanScanner( ns, pattern, order, 0, true, BSONObj(
), BSONObj(), !op.get(), mayYield ) ) { | | : _mps( new MultiPlanScanner( ns, pattern, order, 0, true, BSONObj(
), BSONObj(), !op.get(), mayYield ) ), _nscanned() { | |
| if ( op.get() ) { | | if ( op.get() ) { | |
| _op = op; | | _op = op; | |
| } else { | | } else { | |
| _op.reset( new NoOp() ); | | _op.reset( new NoOp() ); | |
| } | | } | |
| if ( _mps->mayRunMore() ) { | | if ( _mps->mayRunMore() ) { | |
| nextClause(); | | nextClause(); | |
| if ( !ok() ) { | | if ( !ok() ) { | |
| advance(); | | advance(); | |
| } | | } | |
| } else { | | } else { | |
| _c.reset( new BasicCursor( DiskLoc() ) ); | | _c.reset( new BasicCursor( DiskLoc() ) ); | |
| } | | } | |
| } | | } | |
| // used to handoff a query to a getMore() | | // used to handoff a query to a getMore() | |
| MultiCursor( auto_ptr< MultiPlanScanner > mps, const shared_ptr< Cu
rsor > &c, const shared_ptr< CoveredIndexMatcher > &matcher, const QueryOp
&op ) | | MultiCursor( auto_ptr< MultiPlanScanner > mps, const shared_ptr< Cu
rsor > &c, const shared_ptr< CoveredIndexMatcher > &matcher, const QueryOp
&op ) | |
|
| : _op( new NoOp( op ) ), _c( c ), _mps( mps ), _matcher( matcher )
{ | | : _op( new NoOp( op ) ), _c( c ), _mps( mps ), _matcher( matcher ),
_nscanned( -1 ) { | |
| _mps->setBestGuessOnly(); | | _mps->setBestGuessOnly(); | |
| _mps->mayYield( false ); // with a NoOp, there's no need to yie
ld in QueryPlanSet | | _mps->mayYield( false ); // with a NoOp, there's no need to yie
ld in QueryPlanSet | |
| if ( !ok() ) { | | if ( !ok() ) { | |
| // would have been advanced by UserQueryOp if possible | | // would have been advanced by UserQueryOp if possible | |
| advance(); | | advance(); | |
| } | | } | |
| } | | } | |
| virtual bool ok() { return _c->ok(); } | | virtual bool ok() { return _c->ok(); } | |
| virtual Record* _current() { return _c->_current(); } | | virtual Record* _current() { return _c->_current(); } | |
| virtual BSONObj current() { return _c->current(); } | | virtual BSONObj current() { return _c->current(); } | |
| | | | |
| skipping to change at line 368 | | skipping to change at line 370 | |
| } | | } | |
| virtual bool supportGetMore() { return true; } | | virtual bool supportGetMore() { return true; } | |
| virtual bool supportYields() { return _c->supportYields(); } | | virtual bool supportYields() { return _c->supportYields(); } | |
| // 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) { | | virtual bool getsetdup(DiskLoc loc) { | |
| return _c->getsetdup( loc ); | | return _c->getsetdup( loc ); | |
| } | | } | |
| virtual CoveredIndexMatcher *matcher() const { return _matcher.get(
); } | | virtual CoveredIndexMatcher *matcher() const { return _matcher.get(
); } | |
|
| | | // return -1 if we're a getmore handoff | |
| | | 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().ne
wCursor(); } | | virtual shared_ptr< Cursor > newCursor() const { return qp().ne
wCursor(); } | |
|
| | | virtual long long nscanned() { assert( false ); return 0; } | |
| }; | | }; | |
| void nextClause() { | | void nextClause() { | |
|
| | | if ( _nscanned >= 0 && _c.get() ) { | |
| | | _nscanned += _c->nscanned(); | |
| | | } | |
| shared_ptr< CursorOp > best = _mps->runOpOnce( *_op ); | | shared_ptr< CursorOp > best = _mps->runOpOnce( *_op ); | |
| if ( ! best->complete() ) | | if ( ! best->complete() ) | |
| throw MsgAssertionException( best->exception() ); | | throw MsgAssertionException( best->exception() ); | |
| _c = best->newCursor(); | | _c = best->newCursor(); | |
| _matcher = best->matcher(); | | _matcher = best->matcher(); | |
| _op = best; | | _op = best; | |
| } | | } | |
| shared_ptr< CursorOp > _op; | | shared_ptr< CursorOp > _op; | |
| shared_ptr< Cursor > _c; | | shared_ptr< Cursor > _c; | |
| auto_ptr< MultiPlanScanner > _mps; | | auto_ptr< MultiPlanScanner > _mps; | |
| shared_ptr< CoveredIndexMatcher > _matcher; | | shared_ptr< CoveredIndexMatcher > _matcher; | |
|
| | | 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 ); | |
| | | | |
| inline bool isSimpleIdQuery( const BSONObj& query ){ | | inline bool isSimpleIdQuery( const BSONObj& query ){ | |
| BSONObjIterator i(query); | | BSONObjIterator i(query); | |
| if( !i.more() ) return false; | | if( !i.more() ) return false; | |
| BSONElement e = i.next(); | | BSONElement e = i.next(); | |
| if( i.more() ) return false; | | if( i.more() ) return false; | |
| | | | |
End of changes. 7 change blocks. |
| 2 lines changed or deleted | | 12 lines changed or added | |
|
| queryutil.h | | queryutil.h | |
| | | | |
| skipping to change at line 63 | | skipping to change at line 63 | |
| }; | | }; | |
| | | | |
| // range of a field's value that may be determined from query -- used t
o | | // range of a field's value that may be determined from query -- used t
o | |
| // determine index limits | | // determine index limits | |
| class FieldRange { | | class FieldRange { | |
| public: | | public: | |
| FieldRange( const BSONElement &e = BSONObj().firstElement() , bool
isNot=false , bool optimize=true ); | | FieldRange( const BSONElement &e = BSONObj().firstElement() , bool
isNot=false , bool optimize=true ); | |
| const FieldRange &operator&=( const FieldRange &other ); | | const FieldRange &operator&=( const FieldRange &other ); | |
| const FieldRange &operator|=( const FieldRange &other ); | | const FieldRange &operator|=( const FieldRange &other ); | |
| // does not remove fully contained ranges (eg [1,3] - [2,2] doesn't
remove anything) | | // does not remove fully contained ranges (eg [1,3] - [2,2] doesn't
remove anything) | |
|
| // in future we can change so that an or on $in:[3] combined with $
in:{$gt:2} doesn't scan 3 a second time | | // in future we can change so that an or on $in:[3] combined with $
gt:2 doesn't scan 3 a second time | |
| const FieldRange &operator-=( const FieldRange &other ); | | const FieldRange &operator-=( const FieldRange &other ); | |
| // true iff other includes this | | // true iff other includes this | |
| bool operator<=( const FieldRange &other ); | | bool operator<=( const FieldRange &other ); | |
| BSONElement min() const { assert( !empty() ); return _intervals[ 0
]._lower._bound; } | | BSONElement min() const { assert( !empty() ); return _intervals[ 0
]._lower._bound; } | |
| BSONElement max() const { assert( !empty() ); return _intervals[ _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; } | |
| bool equality() const { | | bool equality() const { | |
| return | | return | |
| !empty() && | | !empty() && | |
| | | | |
| skipping to change at line 92 | | skipping to change at line 92 | |
| for( vector< FieldInterval >::const_iterator i = _intervals.beg
in(); i != _intervals.end(); ++i ) { | | for( vector< FieldInterval >::const_iterator i = _intervals.beg
in(); i != _intervals.end(); ++i ) { | |
| if ( !i->equality() ) { | | if ( !i->equality() ) { | |
| return false; | | return false; | |
| } | | } | |
| } | | } | |
| return true; | | return true; | |
| } | | } | |
| bool nontrivial() const { | | bool nontrivial() const { | |
| return | | return | |
| ! empty() && | | ! empty() && | |
|
| ( minKey.firstElement().woCompare( min(), false ) != 0 || | | ( _intervals.size() != 1 || | |
| | | minKey.firstElement().woCompare( min(), false ) != 0 || | |
| maxKey.firstElement().woCompare( max(), false ) != 0 ); | | maxKey.firstElement().woCompare( max(), false ) != 0 ); | |
| } | | } | |
| bool empty() const { return _intervals.empty(); } | | bool empty() const { return _intervals.empty(); } | |
| void makeEmpty() { _intervals.clear(); } | | void makeEmpty() { _intervals.clear(); } | |
| const vector< FieldInterval > &intervals() const { return _i
ntervals; } | | const vector< FieldInterval > &intervals() const { return _i
ntervals; } | |
| string getSpecial() const { return _special; } | | string getSpecial() const { return _special; } | |
| void setExclusiveBounds() { | | void setExclusiveBounds() { | |
| for( vector< FieldInterval >::iterator i = _intervals.begin();
i != _intervals.end(); ++i ) { | | for( vector< FieldInterval >::iterator i = _intervals.begin();
i != _intervals.end(); ++i ) { | |
| i->_lower._inclusive = false; | | i->_lower._inclusive = false; | |
| i->_upper._inclusive = false; | | i->_upper._inclusive = false; | |
| | | | |
| skipping to change at line 223 | | skipping to change at line 224 | |
| return f->second; | | return f->second; | |
| } | | } | |
| FieldRange &range( const char *fieldName ) { | | FieldRange &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() ) | |
| return trivialRange(); | | return trivialRange(); | |
| return f->second; | | return f->second; | |
| } | | } | |
| int nNontrivialRanges() const { | | int nNontrivialRanges() const { | |
| int count = 0; | | int count = 0; | |
|
| for( map< string, FieldRange >::const_iterator i = _ranges.begi
n(); i != _ranges.end(); ++i ) | | for( map< string, FieldRange >::const_iterator i = _ranges.begi
n(); i != _ranges.end(); ++i ) { | |
| if ( i->second.nontrivial() ) | | if ( i->second.nontrivial() ) | |
| ++count; | | ++count; | |
|
| | | } | |
| return count; | | return count; | |
| } | | } | |
| const char *ns() const { return _ns; } | | const char *ns() const { return _ns; } | |
| // if fields is specified, order fields of returned object to match
those of 'fields' | | // if fields is specified, order fields of returned object to match
those of 'fields' | |
| BSONObj simplifiedQuery( const BSONObj &fields = BSONObj() ) const; | | BSONObj simplifiedQuery( const BSONObj &fields = BSONObj() ) const; | |
| bool matchPossible() const { | | bool matchPossible() const { | |
| for( map< string, FieldRange >::const_iterator i = _ranges.begi
n(); i != _ranges.end(); ++i ) | | for( map< string, FieldRange >::const_iterator i = _ranges.begi
n(); i != _ranges.end(); ++i ) | |
| if ( i->second.empty() ) | | if ( i->second.empty() ) | |
| return false; | | return false; | |
| return true; | | return true; | |
| | | | |
| skipping to change at line 384 | | skipping to change at line 386 | |
| j != _ranges[ i ].intervals().end(); ++j ) { | | j != _ranges[ i ].intervals().end(); ++j ) { | |
| a << BSONArray( BSON_ARRAY( j->_lower._bound << j->_upp
er._bound ).clientReadable() ); | | a << BSONArray( BSON_ARRAY( j->_lower._bound << j->_upp
er._bound ).clientReadable() ); | |
| } | | } | |
| a.done(); | | a.done(); | |
| } | | } | |
| return b.obj(); | | return b.obj(); | |
| } | | } | |
| bool matches( const BSONObj &obj ) const; | | bool matches( const BSONObj &obj ) const; | |
| class Iterator { | | class Iterator { | |
| public: | | public: | |
|
| Iterator( const FieldRangeVector &v ) : _v( v ), _i( _v._ranges | | Iterator( const FieldRangeVector &v ) : _v( v ), _i( _v._ranges | |
| .size(), -1 ), _cmp( _v._ranges.size(), 0 ), _superlative( _v._ranges.size( | | .size(), -1 ), _cmp( _v._ranges.size(), 0 ), _inc( _v._ranges.size(), false | |
| ), 0 ) { | | ), _after() { | |
| static BSONObj minObj = minObject(); | | | |
| static BSONElement minElt = minObj.firstElement(); | | | |
| static BSONObj maxObj = maxObject(); | | | |
| static BSONElement maxElt = maxObj.firstElement(); | | | |
| BSONObjIterator i( _v._keyPattern ); | | | |
| for( int j = 0; j < (int)_superlative.size(); ++j ) { | | | |
| int number = (int) i.next().number(); | | | |
| bool forward = ( ( number >= 0 ? 1 : -1 ) * ( _v._direc | | | |
| tion >= 0 ? 1 : -1 ) > 0 ); | | | |
| _superlative[ j ] = forward ? &maxElt : &minElt; | | | |
| } | | | |
| } | | } | |
| static BSONObj minObject() { | | static BSONObj minObject() { | |
| BSONObjBuilder b; | | BSONObjBuilder b; | |
| b.appendMinKey( "" ); | | b.appendMinKey( "" ); | |
| return b.obj(); | | return b.obj(); | |
| } | | } | |
| static BSONObj maxObject() { | | static BSONObj maxObject() { | |
| BSONObjBuilder b; | | BSONObjBuilder b; | |
| b.appendMaxKey( "" ); | | b.appendMaxKey( "" ); | |
| return b.obj(); | | return b.obj(); | |
| | | | |
| skipping to change at line 427 | | skipping to change at line 419 | |
| _i[ 0 ] = _v._ranges[ 0 ].intervals().size(); | | _i[ 0 ] = _v._ranges[ 0 ].intervals().size(); | |
| } | | } | |
| return ok(); | | return ok(); | |
| } | | } | |
| // return value | | // return value | |
| // -2 end of iteration | | // -2 end of iteration | |
| // -1 no skipping | | // -1 no skipping | |
| // >= 0 skip parameter | | // >= 0 skip parameter | |
| int advance( const BSONObj &curr ); | | int advance( const BSONObj &curr ); | |
| const vector< const BSONElement * > &cmp() const { return _cmp;
} | | const vector< const BSONElement * > &cmp() const { return _cmp;
} | |
|
| | | const vector< bool > &inc() const { return _inc; } | |
| | | bool after() const { return _after; } | |
| | | void prepDive(); | |
| void setZero( int i ) { | | void setZero( int i ) { | |
| for( int j = i; j < (int)_i.size(); ++j ) { | | for( int j = i; j < (int)_i.size(); ++j ) { | |
| _i[ j ] = 0; | | _i[ j ] = 0; | |
| } | | } | |
| } | | } | |
| void setMinus( int i ) { | | void setMinus( int i ) { | |
| for( int j = i; j < (int)_i.size(); ++j ) { | | for( int j = i; j < (int)_i.size(); ++j ) { | |
| _i[ j ] = -1; | | _i[ j ] = -1; | |
| } | | } | |
| } | | } | |
| | | | |
| skipping to change at line 462 | | skipping to change at line 457 | |
| const FieldInterval &fi = _v._ranges[ i ].intervals()[
_i[ i ] ]; | | const FieldInterval &fi = _v._ranges[ i ].intervals()[
_i[ i ] ]; | |
| b.appendAs( fi._upper._bound, "" ); | | b.appendAs( fi._upper._bound, "" ); | |
| } | | } | |
| return b.obj(); | | return b.obj(); | |
| } | | } | |
| // check | | // check | |
| private: | | private: | |
| const FieldRangeVector &_v; | | const FieldRangeVector &_v; | |
| vector< int > _i; | | vector< int > _i; | |
| vector< const BSONElement* > _cmp; | | vector< const BSONElement* > _cmp; | |
|
| vector< const BSONElement* > _superlative; | | vector< bool > _inc; | |
| | | bool _after; | |
| }; | | }; | |
| private: | | private: | |
|
| int matchingLowElement( const BSONElement &e, int i, bool direction
) 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; | |
| vector< FieldRange > _ranges; | | vector< FieldRange > _ranges; | |
| BSONObj _keyPattern; | | BSONObj _keyPattern; | |
| int _direction; | | int _direction; | |
| vector< BSONObj > _queries; // make sure mem owned | | vector< BSONObj > _queries; // make sure mem owned | |
| }; | | }; | |
| | | | |
| // generages FieldRangeSet objects, accounting for or clauses | | // generages FieldRangeSet objects, accounting for or clauses | |
| class FieldRangeOrSet { | | class FieldRangeOrSet { | |
| public: | | public: | |
| | | | |
End of changes. 8 change blocks. |
| 19 lines changed or deleted | | 14 lines changed or added | |
|
| rs.h | | rs.h | |
| | | | |
| skipping to change at line 209 | | skipping to change at line 209 | |
| sp.state = s; sp.primary = p; | | sp.state = s; sp.primary = p; | |
| } | | } | |
| void setSelfPrimary(const Member *self) { change(MemberState::RS_PR
IMARY, self); } | | void setSelfPrimary(const Member *self) { change(MemberState::RS_PR
IMARY, self); } | |
| void setOtherPrimary(const Member *mem) { | | void setOtherPrimary(const Member *mem) { | |
| scoped_lock lk(m); | | scoped_lock lk(m); | |
| assert( !sp.state.primary() ); | | assert( !sp.state.primary() ); | |
| sp.primary = mem; | | sp.primary = mem; | |
| } | | } | |
| void noteRemoteIsPrimary(const Member *remote) { | | void noteRemoteIsPrimary(const Member *remote) { | |
| scoped_lock lk(m); | | scoped_lock lk(m); | |
|
| if( !sp.state.secondary() && !sp.state.fatal() ) | | if( !sp.state.secondary() ) | |
| sp.state = MemberState::RS_RECOVERING; | | sp.state = MemberState::RS_RECOVERING; | |
| sp.primary = remote; | | sp.primary = remote; | |
| } | | } | |
| StateBox() : m("StateBox") { } | | StateBox() : m("StateBox") { } | |
| private: | | private: | |
| mutex m; | | mutex m; | |
| SP sp; | | SP sp; | |
| }; | | }; | |
| | | | |
| void parseReplsetCmdLine(string cfgString, string& setname, vector<Host
AndPort>& seeds, set<HostAndPort>& seedSet ); | | void parseReplsetCmdLine(string cfgString, string& setname, vector<Host
AndPort>& seeds, set<HostAndPort>& seedSet ); | |
| | | | |
| skipping to change at line 259 | | skipping to change at line 259 | |
| | | | |
| StateBox box; | | StateBox box; | |
| | | | |
| OpTime lastOpTimeWritten; | | OpTime lastOpTimeWritten; | |
| long long lastH; // hash we use to make sure we are reading the rig
ht flow of ops and aren't on an out-of-date "fork" | | long long lastH; // hash we use to make sure we are reading the rig
ht flow of ops and aren't on an out-of-date "fork" | |
| private: | | private: | |
| set<ReplSetHealthPollTask*> healthTasks; | | set<ReplSetHealthPollTask*> healthTasks; | |
| void endOldHealthTasks(); | | void endOldHealthTasks(); | |
| void startHealthTaskFor(Member *m); | | void startHealthTaskFor(Member *m); | |
| | | | |
|
| | | private: | |
| Consensus elect; | | Consensus elect; | |
|
| | | bool ok() const { return !box.getState().fatal(); } | |
| | | | |
| void relinquish(); | | void relinquish(); | |
| void forgetPrimary(); | | void forgetPrimary(); | |
|
| | | | |
| protected: | | protected: | |
| bool _stepDown(); | | bool _stepDown(); | |
| private: | | private: | |
| void assumePrimary(); | | void assumePrimary(); | |
| void loadLastOpTimeWritten(); | | void loadLastOpTimeWritten(); | |
| void changeState(MemberState s); | | void changeState(MemberState s); | |
|
| | | | |
| protected: | | protected: | |
| // "heartbeat message" | | // "heartbeat message" | |
| // sent in requestHeartbeat respond in field "hbm" | | // sent in requestHeartbeat respond in field "hbm" | |
| char _hbmsg[256]; // we change this unlocked, thus not an stl::stri
ng | | char _hbmsg[256]; // we change this unlocked, thus not an stl::stri
ng | |
| time_t _hbmsgTime; // when it was logged | | time_t _hbmsgTime; // when it was logged | |
| public: | | public: | |
| void sethbmsg(string s, int logLevel = 0); | | void sethbmsg(string s, int logLevel = 0); | |
| protected: | | protected: | |
| bool initFromConfig(ReplSetConfig& c, bool reconf=false); // true i
f ok; throws if config really bad; false if config doesn't include self | | bool initFromConfig(ReplSetConfig& c, bool reconf=false); // true i
f ok; throws if config really bad; false if config doesn't include self | |
| void _fillIsMaster(BSONObjBuilder&); | | void _fillIsMaster(BSONObjBuilder&); | |
| | | | |
| skipping to change at line 360 | | skipping to change at line 365 | |
| | | | |
| bool stepDown() { return _stepDown(); } | | bool stepDown() { return _stepDown(); } | |
| | | | |
| string selfFullName() { | | string selfFullName() { | |
| lock lk(this); | | lock lk(this); | |
| return _self->fullName(); | | return _self->fullName(); | |
| } | | } | |
| | | | |
| /* call after constructing to start - returns fairly quickly after
la[unching its threads */ | | /* call after constructing to start - returns fairly quickly after
la[unching its threads */ | |
| void go() { _go(); } | | void go() { _go(); } | |
|
| | | | |
| void fatal() { _fatal(); } | | void fatal() { _fatal(); } | |
|
| bool isPrimary() { return box.getState().primary(); } | | bool isPrimary(); | |
| bool isSecondary() { return box.getState().secondary(); } | | bool isSecondary(); | |
| MemberState state() const { return ReplSetImpl::state(); } | | MemberState state() const { return ReplSetImpl::state(); } | |
| string name() const { return ReplSetImpl::name(); } | | string name() const { return ReplSetImpl::name(); } | |
| const ReplSetConfig& config() { return ReplSetImpl::config(); } | | const ReplSetConfig& config() { return ReplSetImpl::config(); } | |
| void getOplogDiagsAsHtml(unsigned server_id, stringstream& ss) cons
t { _getOplogDiagsAsHtml(server_id,ss); } | | void getOplogDiagsAsHtml(unsigned server_id, stringstream& ss) cons
t { _getOplogDiagsAsHtml(server_id,ss); } | |
| void summarizeAsHtml(stringstream& ss) const { _summarizeAsHtml(ss)
; } | | void summarizeAsHtml(stringstream& ss) const { _summarizeAsHtml(ss)
; } | |
| void summarizeStatus(BSONObjBuilder& b) const { _summarizeStatus(b
); } | | void summarizeStatus(BSONObjBuilder& b) const { _summarizeStatus(b
); } | |
| void fillIsMaster(BSONObjBuilder& b) { _fillIsMaster(b); } | | void fillIsMaster(BSONObjBuilder& b) { _fillIsMaster(b); } | |
| | | | |
| /* we have a new config (reconfig) - apply it. | | /* we have a new config (reconfig) - apply it. | |
| @param comment write a no-op comment to the oplog about it. onl
y makes sense if one is primary and initiating the reconf. | | @param comment write a no-op comment to the oplog about it. onl
y makes sense if one is primary and initiating the reconf. | |
| | | | |
| skipping to change at line 425 | | skipping to change at line 429 | |
| | | | |
| /** inlines ----------------- */ | | /** inlines ----------------- */ | |
| | | | |
| inline Member::Member(HostAndPort h, unsigned ord, const ReplSetConfig:
:MemberCfg *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) | |
| { | | { | |
| if( self ) | | if( self ) | |
| _hbinfo.health = 1.0; | | _hbinfo.health = 1.0; | |
| } | | } | |
| | | | |
|
| | | inline bool ReplSet::isPrimary() { | |
| | | /* todo replset */ | |
| | | return box.getState().primary(); | |
| | | } | |
| | | | |
| | | inline bool ReplSet::isSecondary() { | |
| | | return box.getState().secondary(); | |
| | | } | |
| | | | |
| } | | } | |
| | | | |
End of changes. 8 change blocks. |
| 4 lines changed or deleted | | 17 lines changed or added | |
|