array.h | array.h | |||
---|---|---|---|---|
// array.h | // array.h | |||
/* | ||||
* Copyright 2010 10gen Inc. | ||||
* | ||||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||||
* you may not use this file except in compliance with the License. | ||||
* You may obtain a copy of the License at | ||||
* | ||||
* http://www.apache.org/licenses/LICENSE-2.0 | ||||
* | ||||
* Unless required by applicable law or agreed to in writing, software | ||||
* distributed under the License is distributed on an "AS IS" BASIS, | ||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli | ||||
ed. | ||||
* See the License for the specific language governing permissions and | ||||
* limitations under the License. | ||||
*/ | ||||
namespace mongo { | namespace mongo { | |||
template<typename T> | template<typename T> | |||
class FastArray { | class FastArray { | |||
public: | public: | |||
FastArray( int capacity=10000 ) | FastArray( int capacity=10000 ) | |||
: _capacity( capacity ) , _size(0) , _end(this,capacity){ | : _capacity( capacity ) , _size(0) , _end(this,capacity){ | |||
_data = new T[capacity]; | _data = new T[capacity]; | |||
} | } | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 17 lines changed or added | |||
assert_util.h | assert_util.h | |||
---|---|---|---|---|
skipping to change at line 216 | skipping to change at line 216 | |||
string demangleName( const type_info& typeinfo ); | string demangleName( const type_info& typeinfo ); | |||
} // namespace mongo | } // namespace mongo | |||
#define BOOST_CHECK_EXCEPTION MONGO_BOOST_CHECK_EXCEPTION | #define BOOST_CHECK_EXCEPTION MONGO_BOOST_CHECK_EXCEPTION | |||
#define MONGO_BOOST_CHECK_EXCEPTION( expression ) \ | #define MONGO_BOOST_CHECK_EXCEPTION( expression ) \ | |||
try { \ | try { \ | |||
expression; \ | expression; \ | |||
} catch ( const std::exception &e ) { \ | } catch ( const std::exception &e ) { \ | |||
problem() << "caught boost exception: " << e.what() << endl; | stringstream ss; \ | |||
\ | ss << "caught boost exception: " << e.what(); \ | |||
assert( false ); \ | msgasserted( 13294 , ss.str() ); \ | |||
} catch ( ... ) { \ | } catch ( ... ) { \ | |||
massert( 10437 , "unknown boost failed" , false ); \ | massert( 10437 , "unknown boost failed" , false ); \ | |||
} | } | |||
#define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD | #define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD | |||
#define MONGO_DESTRUCTOR_GUARD( expression ) \ | #define MONGO_DESTRUCTOR_GUARD( expression ) \ | |||
try { \ | try { \ | |||
expression; \ | expression; \ | |||
} catch ( const std::exception &e ) { \ | } catch ( const std::exception &e ) { \ | |||
problem() << "caught exception (" << e.what() << ") in destructor ( " << __FUNCTION__ << ")" << endl; \ | problem() << "caught exception (" << e.what() << ") in destructor ( " << __FUNCTION__ << ")" << endl; \ | |||
End of changes. 1 change blocks. | ||||
3 lines changed or deleted | 3 lines changed or added | |||
balance.h | balance.h | |||
---|---|---|---|---|
skipping to change at line 24 | skipping to change at line 24 | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Licen se | * You should have received a copy of the GNU Affero General Public Licen se | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../pch.h" | #include "../pch.h" | |||
#include "../util/background.h" | #include "../util/background.h" | |||
#include "../client/dbclient.h" | #include "../client/dbclient.h" | |||
#include "balancer_policy.h" | ||||
namespace mongo { | namespace mongo { | |||
class Balancer : public BackgroundJob { | class Balancer : public BackgroundJob { | |||
public: | public: | |||
string name() { return "Balancer"; } | ||||
Balancer(); | Balancer(); | |||
virtual ~Balancer(); | ||||
void run(); | // BackgroundJob methods | |||
virtual void run(); | ||||
virtual string name() { return "Balancer"; } | ||||
private: | private: | |||
bool shouldIBalance( DBClientBase& conn ); | typedef BalancerPolicy::ChunkInfo CandidateChunk; | |||
typedef shared_ptr<CandidateChunk> CandidateChunkPtr; | ||||
/** | /** | |||
* @return true if everything is ok | * Returns true iff this mongos process gained (or maintained) the | |||
* reponsibility moving chunks around. | ||||
*/ | */ | |||
bool checkOIDs(); | bool _shouldIBalance( DBClientBase& conn ); | |||
/** | /** | |||
* @return number of collections balanced | * Gathers all the necessary information about shards and chunks, a | |||
nd | ||||
* decides whether there are candidate chunks to be moved. | ||||
*/ | */ | |||
int balance( DBClientBase& conn ); | void _doBalanceRound( DBClientBase& conn, vector<CandidateChunkPtr> | |||
bool balance( DBClientBase& conn , const string& ns , const BSONObj | * candidateChunks ); | |||
& data ); | ||||
void ping(); | /** | |||
void ping( DBClientBase& conn ); | * Execute the chunk migrations described in 'candidateChunks' and | |||
* returns the number of chunks effectively moved. | ||||
*/ | ||||
int _moveChunks( const vector<CandidateChunkPtr>* candidateChunks ) | ||||
; | ||||
BSONObj pickChunk( vector<BSONObj>& from, vector<BSONObj>& to ); | /** | |||
* Check the health of the master configuration server | ||||
*/ | ||||
void _ping(); | ||||
void _ping( DBClientBase& conn ); | ||||
string _myid; | /** | |||
time_t _started; | * @return true if everything is ok | |||
int _balancedLastTime; | */ | |||
bool _checkOIDs(); | ||||
// internal state | ||||
string _myid; // hostname:port of my mongos | ||||
time_t _started; // time Balancer starte running | ||||
int _balancedLastTime; // number of moved chunks in las | ||||
t round | ||||
BalancerPolicy* _policy; // decide which chunks to move; | ||||
owned here. | ||||
// non-copyable, non-assignable | ||||
Balancer(const Balancer&); | ||||
Balancer operator=(const Balancer&); | ||||
}; | }; | |||
extern Balancer balancer; | extern Balancer balancer; | |||
} | } | |||
End of changes. 12 change blocks. | ||||
15 lines changed or deleted | 46 lines changed or added | |||
bson.h | bson.h | |||
---|---|---|---|---|
skipping to change at line 66 | skipping to change at line 66 | |||
} | } | |||
#endif | #endif | |||
#if !defined(uassert) | #if !defined(uassert) | |||
inline void uassert(unsigned msgid, std::string msg, bool expr) { | inline void uassert(unsigned msgid, std::string msg, bool expr) { | |||
if( !expr ) | if( !expr ) | |||
throw bson::assertion(); | throw bson::assertion(); | |||
} | } | |||
inline void msgasserted(int msgid, const char *msg) { | inline void msgasserted(int msgid, const char *msg) { | |||
throw bson::assertion(); | throw bson::assertion(); | |||
} | } | |||
inline void msgasserted(int msgid, const std::string &msg) { msgasserte d(msgid, msg.c_str()); } | ||||
inline void massert(unsigned msgid, std::string msg, bool expr) { | inline void massert(unsigned msgid, std::string msg, bool expr) { | |||
if(!expr) { | if(!expr) { | |||
std::cout << "assertion failure in bson library: " << msgid << ' ' << msg << std::endl; | std::cout << "assertion failure in bson library: " << msgid << ' ' << msg << std::endl; | |||
throw bson::assertion(); | throw bson::assertion(); | |||
} | } | |||
} | } | |||
#endif | #endif | |||
} | } | |||
#include "../bson/bsontypes.h" | #include "../bson/bsontypes.h" | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 1 lines changed or added | |||
bsonelement.h | bsonelement.h | |||
---|---|---|---|---|
skipping to change at line 233 | skipping to change at line 233 | |||
} | } | |||
/** Get the embedded object this element holds. */ | /** Get the embedded object this element holds. */ | |||
BSONObj embeddedObject() const; | BSONObj embeddedObject() const; | |||
/* uasserts if not an object */ | /* uasserts if not an object */ | |||
BSONObj embeddedObjectUserCheck() const; | BSONObj embeddedObjectUserCheck() const; | |||
BSONObj codeWScopeObject() const; | BSONObj codeWScopeObject() const; | |||
/** Get binary data. Element must be of type BinData */ | /** Get raw binary data. Element must be of type BinData. Doesn't hand le type 2 specially */ | |||
const char *binData(int& len) const { | const char *binData(int& len) const { | |||
// BinData: <int len> <byte subtype> <byte[len] data> | // BinData: <int len> <byte subtype> <byte[len] data> | |||
assert( type() == BinData ); | assert( type() == BinData ); | |||
len = valuestrsize(); | len = valuestrsize(); | |||
return value() + 5; | return value() + 5; | |||
} | } | |||
/** Get binary data. Element must be of type BinData. Handles type 2 * | ||||
/ | ||||
const char *binDataClean(int& len) const { | ||||
// BinData: <int len> <byte subtype> <byte[len] data> | ||||
if (binDataType() != ByteArrayDeprecated){ | ||||
return binData(len); | ||||
} else { | ||||
// Skip extra size | ||||
len = valuestrsize() - 4; | ||||
return value() + 5 + 4; | ||||
} | ||||
} | ||||
BinDataType binDataType() const { | BinDataType binDataType() const { | |||
// BinData: <int len> <byte subtype> <byte[len] data> | // BinData: <int len> <byte subtype> <byte[len] data> | |||
assert( type() == BinData ); | assert( type() == BinData ); | |||
unsigned char c = (value() + 4)[0]; | unsigned char c = (value() + 4)[0]; | |||
return (BinDataType)c; | return (BinDataType)c; | |||
} | } | |||
/** Retrieve the regex string for a Regex element */ | /** Retrieve the regex string for a Regex element */ | |||
const char *regex() const { | const char *regex() const { | |||
End of changes. 2 change blocks. | ||||
1 lines changed or deleted | 13 lines changed or added | |||
bsoninlines.h | bsoninlines.h | |||
---|---|---|---|---|
skipping to change at line 246 | skipping to change at line 246 | |||
s << ", "; | s << ", "; | |||
s << e.toString( !isArray ); | s << e.toString( !isArray ); | |||
} | } | |||
s << ( isArray ? " ]" : " }" ); | s << ( isArray ? " ]" : " }" ); | |||
return s.str(); | return s.str(); | |||
} | } | |||
extern unsigned getRandomNumber(); | extern unsigned getRandomNumber(); | |||
inline void BSONElement::validate() const { | inline void BSONElement::validate() const { | |||
switch( type() ) { | const BSONType t = type(); | |||
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 ( t == mongo::String && x + fieldNameSize() + 5 != size() ){ | ||||
StringBuilder buf; | ||||
buf << "Invalid string size. element size: " << size() << | ||||
" fieldNameSize: " << fieldNameSize() << " valuestrsize(): " << valuestrsi | ||||
ze(); | ||||
cout << "ELIOT : " << buf.str() << endl; | ||||
msgasserted( 13292 , buf.str() ); | ||||
} | ||||
if ( x > 0 && valuestr()[x-1] == 0 ) | if ( x > 0 && valuestr()[x-1] == 0 ) | |||
return; | return; | |||
StringBuilder buf; | StringBuilder buf; | |||
buf << "Invalid dbref/code/string/symbol size: " << x << " str nlen:" << strnlen( valuestr() , x ); | buf << "Invalid dbref/code/string/symbol size: " << x << " str nlen:" << strnlen( valuestr() , x ); | |||
massert( 10321 , buf.str() , 0 ); | 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 ); | |||
massert( 10323 , "Invalid CodeWScope string size", totalSize > = strSizeWNull + 4 + 4 ); | massert( 10323 , "Invalid CodeWScope string size", totalSize > = strSizeWNull + 4 + 4 ); | |||
massert( 10324 , "Invalid CodeWScope string size", | massert( 10324 , "Invalid CodeWScope string size", | |||
strSizeWNull > 0 && | strSizeWNull > 0 && | |||
strSizeWNull - 1 == strnlen( codeWScopeCode(), strSize WNull ) ); | strSizeWNull - 1 == strnlen( codeWScopeCode(), strSize WNull ) ); | |||
End of changes. 3 change blocks. | ||||
2 lines changed or deleted | 13 lines changed or added | |||
bsonobjbuilder.h | bsonobjbuilder.h | |||
---|---|---|---|---|
skipping to change at line 42 | skipping to change at line 42 | |||
// warning: 'this' : used in base member initializer list | // warning: 'this' : used in base member initializer list | |||
#pragma warning( disable : 4355 ) | #pragma warning( disable : 4355 ) | |||
#endif | #endif | |||
/** Utility for creating a BSONObj. | /** Utility for creating a BSONObj. | |||
See also the BSON() and BSON_ARRAY() macros. | See also the BSON() and BSON_ARRAY() macros. | |||
*/ | */ | |||
class BSONObjBuilder : boost::noncopyable { | class BSONObjBuilder : boost::noncopyable { | |||
public: | public: | |||
/** @param initsize this is just a hint as to the final size of the object */ | /** @param initsize this is just a hint as to the final size of the object */ | |||
BSONObjBuilder(int initsize=512) : _b(_buf), _buf(initsize), _offse t( 0 ), _s( this ) , _tracker(0) { | BSONObjBuilder(int initsize=512) : _b(_buf), _buf(initsize), _offse t( 0 ), _s( this ) , _tracker(0) , _doneCalled(false) { | |||
_b.skip(4); /*leave room for size field*/ | _b.skip(4); /*leave room for size field*/ | |||
} | } | |||
/** @param baseBuilder construct a BSONObjBuilder using an existing BufBuilder */ | /** @param baseBuilder construct a BSONObjBuilder using an existing BufBuilder */ | |||
BSONObjBuilder( BufBuilder &baseBuilder ) : _b( baseBuilder ), _buf ( 0 ), _offset( baseBuilder.len() ), _s( this ) , _tracker(0) { | BSONObjBuilder( BufBuilder &baseBuilder ) : _b( baseBuilder ), _buf ( 0 ), _offset( baseBuilder.len() ), _s( this ) , _tracker(0) , _doneCalled (false) { | |||
_b.skip( 4 ); | _b.skip( 4 ); | |||
} | } | |||
BSONObjBuilder( const BSONSizeTracker & tracker ) : _b(_buf) , _buf (tracker.getSize() ), _offset(0), _s( this ) , _tracker( (BSONSizeTracker*) (&tracker) ){ | BSONObjBuilder( const BSONSizeTracker & tracker ) : _b(_buf) , _buf (tracker.getSize() ), _offset(0), _s( this ) , _tracker( (BSONSizeTracker*) (&tracker) ) , _doneCalled(false) { | |||
_b.skip( 4 ); | _b.skip( 4 ); | |||
} | } | |||
~BSONObjBuilder(){ | ||||
if ( !_doneCalled && _b.buf() && _buf.getSize() == 0 ){ | ||||
_done(); | ||||
} | ||||
} | ||||
/** add all the fields from the object specified to this object */ | /** add all the fields from the object specified to this object */ | |||
BSONObjBuilder& appendElements(BSONObj x); | BSONObjBuilder& appendElements(BSONObj x); | |||
/** append element to the object we are building */ | /** append element to the object we are building */ | |||
BSONObjBuilder& append( const BSONElement& e) { | BSONObjBuilder& append( const BSONElement& e) { | |||
assert( !e.eoo() ); // do not append eoo, that would corrupt us . the builder auto appends when done() is called. | assert( !e.eoo() ); // do not append eoo, that would corrupt us . the builder auto appends when done() is called. | |||
_b.append((void*) e.rawdata(), e.size()); | _b.append((void*) e.rawdata(), e.size()); | |||
return *this; | return *this; | |||
} | } | |||
skipping to change at line 379 | skipping to change at line 385 | |||
_b.append( fieldName ); | _b.append( fieldName ); | |||
_b.append( (int) strlen( ns ) + 1 ); | _b.append( (int) strlen( ns ) + 1 ); | |||
_b.append( ns ); | _b.append( ns ); | |||
_b.append( (void *) &oid, 12 ); | _b.append( (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 type type information for the data. @see BinDataType. U | @param subtype subtype information for the data. @see enum BinD | |||
se ByteArray if you | ataType in bsontypes.h. | |||
don't care about the type. | Use BinDataGeneral if you don't care about the type. | |||
@param data the byte array | @param data the byte array | |||
*/ | */ | |||
BSONObjBuilder& appendBinData( const char *fieldName, int len, BinD ataType type, const char *data ) { | BSONObjBuilder& appendBinData( const char *fieldName, int len, BinD ataType type, const char *data ) { | |||
_b.append( (char) BinData ); | _b.append( (char) BinData ); | |||
_b.append( fieldName ); | _b.append( fieldName ); | |||
_b.append( len ); | _b.append( len ); | |||
_b.append( (char) type ); | _b.append( (char) type ); | |||
_b.append( (void *) data, len ); | _b.append( (void *) data, len ); | |||
return *this; | return *this; | |||
} | } | |||
BSONObjBuilder& appendBinData( const char *fieldName, int len, BinD ataType type, const unsigned char *data ) { | BSONObjBuilder& appendBinData( const char *fieldName, int len, BinD ataType type, const unsigned char *data ) { | |||
return appendBinData(fieldName, len, type, (const char *) data) ; | return appendBinData(fieldName, len, type, (const char *) data) ; | |||
} | } | |||
/** | /** | |||
Subtype 2 is deprecated. | ||||
Append a BSON bindata bytearray element. | Append a BSON bindata bytearray element. | |||
@param data a byte array | @param data a byte array | |||
@param len the length of data | @param len the length of data | |||
*/ | */ | |||
BSONObjBuilder& appendBinDataArray( const char * fieldName , const char * data , int len ){ | BSONObjBuilder& appendBinDataArrayDeprecated( const char * fieldNam e , const char * data , int len ){ | |||
_b.append( (char) BinData ); | _b.append( (char) BinData ); | |||
_b.append( fieldName ); | _b.append( fieldName ); | |||
_b.append( len + 4 ); | _b.append( len + 4 ); | |||
_b.append( (char)0x2 ); | _b.append( (char)0x2 ); | |||
_b.append( len ); | _b.append( len ); | |||
_b.append( (void *) data, len ); | _b.append( (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. | |||
skipping to change at line 472 | skipping to change at line 479 | |||
return BSONObj(_done()); | return BSONObj(_done()); | |||
} | } | |||
/** Peek at what is in the builder, but leave the builder ready for more appends. | /** Peek at what is in the builder, but leave the builder ready for more appends. | |||
The returned object is only valid until the next modification o r destruction of the builder. | The returned object is only valid until the next modification o r destruction of the builder. | |||
Intended use case: append a field if not already there. | Intended use case: append a field if not already there. | |||
*/ | */ | |||
BSONObj asTempObj() { | BSONObj asTempObj() { | |||
BSONObj temp(_done()); | BSONObj temp(_done()); | |||
_b.setlen(_b.len()-1); //next append should overwrite the EOO | _b.setlen(_b.len()-1); //next append should overwrite the EOO | |||
_doneCalled = false; | ||||
return temp; | return temp; | |||
} | } | |||
/* assume ownership of the buffer - you must then free it (with fre e()) */ | /* assume ownership of the buffer - you must then free it (with fre e()) */ | |||
char* decouple(int& l) { | char* decouple(int& l) { | |||
char *x = _done(); | char *x = _done(); | |||
assert( x ); | assert( x ); | |||
l = _b.len(); | l = _b.len(); | |||
_b.decouple(); | _b.decouple(); | |||
return x; | return x; | |||
} | } | |||
void decouple() { | void decouple() { | |||
_b.decouple(); // post done() call version. be sure jsobj f rees... | _b.decouple(); // post done() call version. be sure jsobj f rees... | |||
} | } | |||
void appendKeys( const BSONObj& keyPattern , const BSONObj& values ); | void appendKeys( const BSONObj& keyPattern , const BSONObj& values ); | |||
public: | ||||
static string numStr( int i ) { | static string numStr( int i ) { | |||
if (i>=0 && i<100) | if (i>=0 && i<100) | |||
return numStrs[i]; | return numStrs[i]; | |||
stringstream o; | stringstream o; | |||
o << i; | o << i; | |||
return o.str(); | return o.str(); | |||
} | } | |||
/** Stream oriented way to add field names and values. */ | /** Stream oriented way to add field names and values. */ | |||
BSONObjBuilderValueStream &operator<<(const char * name ) { | BSONObjBuilderValueStream &operator<<(const char * name ) { | |||
skipping to change at line 530 | skipping to change at line 537 | |||
return _s << l; | return _s << l; | |||
} | } | |||
/** @return true if we are using our own bufbuilder, and not an alt ernate that was given to us in our constructor */ | /** @return true if we are using our own bufbuilder, and not an alt ernate that was given to us in our constructor */ | |||
bool owned() const { return &_b == &_buf; } | bool owned() const { return &_b == &_buf; } | |||
BSONObjIterator iterator() const ; | BSONObjIterator iterator() const ; | |||
private: | private: | |||
char* _done() { | char* _done() { | |||
if ( _doneCalled ) | ||||
return _b.buf() + _offset; | ||||
_doneCalled = true; | ||||
_s.endField(); | _s.endField(); | |||
_b.append((char) EOO); | _b.append((char) EOO); | |||
char *data = _b.buf() + _offset; | char *data = _b.buf() + _offset; | |||
int size = _b.len() - _offset; | int size = _b.len() - _offset; | |||
*((int*)data) = size; | *((int*)data) = size; | |||
if ( _tracker ) | if ( _tracker ) | |||
_tracker->got( size ); | _tracker->got( size ); | |||
return data; | return data; | |||
} | } | |||
BufBuilder &_b; | BufBuilder &_b; | |||
BufBuilder _buf; | BufBuilder _buf; | |||
int _offset; | int _offset; | |||
BSONObjBuilderValueStream _s; | BSONObjBuilderValueStream _s; | |||
BSONSizeTracker * _tracker; | BSONSizeTracker * _tracker; | |||
bool _doneCalled; | ||||
static const string numStrs[100]; // cache of 0 to 99 inclusive | static const string numStrs[100]; // cache of 0 to 99 inclusive | |||
}; | }; | |||
class BSONArrayBuilder : boost::noncopyable { | class BSONArrayBuilder : boost::noncopyable { | |||
public: | public: | |||
BSONArrayBuilder() : _i(0), _b() {} | BSONArrayBuilder() : _i(0), _b() {} | |||
BSONArrayBuilder( BufBuilder &_b ) : _i(0), _b(_b) {} | BSONArrayBuilder( BufBuilder &_b ) : _i(0), _b(_b) {} | |||
template <typename T> | template <typename T> | |||
End of changes. 11 change blocks. | ||||
8 lines changed or deleted | 20 lines changed or added | |||
bsontypes.h | bsontypes.h | |||
---|---|---|---|---|
skipping to change at line 97 | skipping to change at line 97 | |||
/** max type that is not MaxKey */ | /** max type that is not MaxKey */ | |||
JSTypeMax=18, | JSTypeMax=18, | |||
/** larger than all other types */ | /** larger than all other types */ | |||
MaxKey=127 | MaxKey=127 | |||
}; | }; | |||
/* subtypes of BinData. | /* subtypes of BinData. | |||
bdtCustom and above are ones that the JS compiler understands, but a re | bdtCustom and above are ones that the JS compiler understands, but a re | |||
opaque to the database. | opaque to the database. | |||
*/ | */ | |||
enum BinDataType { Function=1, ByteArray=2, bdtUUID = 3, MD5Type=5, bdt | enum BinDataType { | |||
Custom=128 }; | BinDataGeneral=0, | |||
Function=1, | ||||
ByteArrayDeprecated=2, /* use BinGeneral instead */ | ||||
bdtUUID = 3, | ||||
MD5Type=5, | ||||
bdtCustom=128 | ||||
}; | ||||
} | } | |||
End of changes. 1 change blocks. | ||||
2 lines changed or deleted | 8 lines changed or added | |||
btree.h | btree.h | |||
---|---|---|---|---|
skipping to change at line 209 | skipping to change at line 209 | |||
likewise below in bt_insert() etc. | likewise below in bt_insert() etc. | |||
*/ | */ | |||
bool exists(const IndexDetails& idx, DiskLoc thisLoc, const BSONObj & key, const Ordering& order); | bool exists(const IndexDetails& idx, DiskLoc thisLoc, const BSONObj & key, const Ordering& order); | |||
bool wouldCreateDup( | bool wouldCreateDup( | |||
const IndexDetails& idx, DiskLoc thisLoc, | const IndexDetails& idx, DiskLoc thisLoc, | |||
const BSONObj& key, const Ordering& order, | const BSONObj& key, const Ordering& order, | |||
DiskLoc self); | DiskLoc self); | |||
static DiskLoc addBucket(IndexDetails&); /* start a new index off, empty */ | static DiskLoc addBucket(IndexDetails&); /* start a new index off, empty */ | |||
void deallocBucket(const DiskLoc &thisLoc); // clear bucket memory, placeholder for deallocation | void deallocBucket(const DiskLoc &thisLoc, IndexDetails &id); | |||
static void renameIndexNamespace(const char *oldNs, const char *new Ns); | static void renameIndexNamespace(const char *oldNs, const char *new Ns); | |||
int bt_insert(DiskLoc thisLoc, DiskLoc recordLoc, | int bt_insert(DiskLoc thisLoc, DiskLoc recordLoc, | |||
const BSONObj& key, const Ordering &order, bool dupsAllo wed, | const BSONObj& key, const Ordering &order, bool dupsAllo wed, | |||
IndexDetails& idx, bool toplevel = true); | IndexDetails& idx, bool toplevel = true); | |||
bool unindex(const DiskLoc& thisLoc, IndexDetails& id, BSONObj& key , const DiskLoc& recordLoc); | bool unindex(const DiskLoc& thisLoc, IndexDetails& id, BSONObj& key , const DiskLoc& recordLoc); | |||
/* locate may return an "unused" key that is just a marker. so be careful. | /* locate may return an "unused" key that is just a marker. so be careful. | |||
skipping to change at line 361 | skipping to change at line 361 | |||
ba << BSON_ARRAY( prettyKey( i->first ) << prettyKey( i ->second ) ); | ba << BSON_ARRAY( prettyKey( i->first ) << prettyKey( i ->second ) ); | |||
} | } | |||
} | } | |||
return ba.arr(); | return ba.arr(); | |||
} | } | |||
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( auto_ptr< CoveredIndexMatcher > matcher ) { | virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) { | |||
_matcher = matcher; | _matcher = matcher; | |||
} | } | |||
private: | private: | |||
/* Our btrees may (rarely) have "unused" keys when items are delete d. | /* Our btrees may (rarely) have "unused" keys when items are delete d. | |||
Skip past them. | Skip past them. | |||
*/ | */ | |||
void skipUnusedKeys(); | void skipUnusedKeys(); | |||
/* Check if the current key is beyond endKey. */ | /* Check if the current key is beyond endKey. */ | |||
skipping to change at line 402 | skipping to change at line 402 | |||
const IndexDetails& indexDetails; | const IndexDetails& indexDetails; | |||
BSONObj order; | BSONObj order; | |||
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; | |||
BoundList bounds_; | BoundList bounds_; | |||
unsigned boundIndex_; | unsigned boundIndex_; | |||
const IndexSpec& _spec; | const IndexSpec& _spec; | |||
auto_ptr< CoveredIndexMatcher > _matcher; | shared_ptr< CoveredIndexMatcher > _matcher; | |||
}; | }; | |||
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. 3 change blocks. | ||||
3 lines changed or deleted | 3 lines changed or added | |||
builder.h | builder.h | |||
---|---|---|---|---|
skipping to change at line 61 | skipping to change at line 61 | |||
} | } | |||
} | } | |||
void reset( int maxSize = 0 ){ | void reset( int maxSize = 0 ){ | |||
l = 0; | l = 0; | |||
if ( maxSize && size > maxSize ){ | if ( maxSize && size > maxSize ){ | |||
free(data); | free(data); | |||
data = (char*)malloc(maxSize); | data = (char*)malloc(maxSize); | |||
size = maxSize; | size = maxSize; | |||
} | } | |||
} | } | |||
/* leave room for some stuff later */ | /* leave room for some stuff later */ | |||
char* skip(int n) { return grow(n); } | char* skip(int n) { return grow(n); } | |||
/* note this may be deallocated (realloced) if you keep writing. */ | /* note this may be deallocated (realloced) if you keep writing. */ | |||
char* buf() { return data; } | char* buf() { return data; } | |||
const char* buf() const { return data; } | const char* buf() const { return data; } | |||
/* assume ownership of the buffer - you must then free it */ | /* assume ownership of the buffer - you must then free() it */ | |||
void decouple() { | void decouple() { data = 0; } | |||
data = 0; | ||||
} | ||||
template<class T> void append(T j) { | template<class T> void append(T j) { | |||
*((T*)grow(sizeof(T))) = j; | *((T*)grow(sizeof(T))) = j; | |||
} | } | |||
void append(short j) { | void append(short j) { | |||
append<short>(j); | append<short>(j); | |||
} | } | |||
void append(int j) { | void append(int j) { | |||
append<int>(j); | append<int>(j); | |||
} | } | |||
skipping to change at line 133 | skipping to change at line 130 | |||
if ( l > a ) | if ( l > a ) | |||
a = l + 16 * 1024; | a = l + 16 * 1024; | |||
if( a > 64 * 1024 * 1024 ) | if( a > 64 * 1024 * 1024 ) | |||
msgasserted(10000, "BufBuilder grow() > 64MB"); | msgasserted(10000, "BufBuilder grow() > 64MB"); | |||
data = (char *) realloc(data, a); | data = (char *) realloc(data, a); | |||
size= a; | size= a; | |||
} | } | |||
return data + oldlen; | return data + oldlen; | |||
} | } | |||
int getSize() const { return size; } | ||||
private: | private: | |||
char *data; | char *data; | |||
int l; | int l; | |||
int size; | int size; | |||
friend class StringBuilder; | friend class StringBuilder; | |||
}; | }; | |||
#if defined(_WIN32) | #if defined(_WIN32) | |||
#pragma warning( disable : 4996 ) | #pragma warning( disable : 4996 ) | |||
End of changes. 3 change blocks. | ||||
5 lines changed or deleted | 4 lines changed or added | |||
chunk.h | chunk.h | |||
---|---|---|---|---|
skipping to change at line 57 | skipping to change at line 57 | |||
typedef map<BSONObj,ChunkPtr,BSONObjCmp> ChunkMap; | typedef map<BSONObj,ChunkPtr,BSONObjCmp> ChunkMap; | |||
typedef map<BSONObj,shared_ptr<ChunkRange>,BSONObjCmp> ChunkRangeMap; | typedef map<BSONObj,shared_ptr<ChunkRange>,BSONObjCmp> ChunkRangeMap; | |||
/** | /** | |||
config.chunks | config.chunks | |||
{ ns : "alleyinsider.fs.chunks" , min : {} , max : {} , server : "lo calhost:30001" } | { ns : "alleyinsider.fs.chunks" , min : {} , max : {} , server : "lo calhost:30001" } | |||
x is in a shard iff | x is in a shard iff | |||
min <= x < max | min <= x < max | |||
*/ | */ | |||
class Chunk : public Model , boost::noncopyable { | class Chunk : public Model , boost::noncopyable, public boost::enable_s hared_from_this<Chunk> { | |||
public: | public: | |||
Chunk( ChunkManager * info ); | Chunk( ChunkManager * info ); | |||
const BSONObj& getMin() const { return _min; } | const BSONObj& getMin() const { return _min; } | |||
const BSONObj& getMax() const { return _max; } | const BSONObj& getMax() const { return _max; } | |||
void setMin(const BSONObj& o){ | void setMin(const BSONObj& o){ | |||
_min = o; | _min = o; | |||
} | } | |||
skipping to change at line 160 | skipping to change at line 160 | |||
BSONObj _max; | BSONObj _max; | |||
Shard _shard; | Shard _shard; | |||
ShardChunkVersion _lastmod; | ShardChunkVersion _lastmod; | |||
bool _modified; | bool _modified; | |||
// transient stuff | // transient stuff | |||
long _dataWritten; | long _dataWritten; | |||
ChunkPtr _this; | ||||
// methods, etc.. | // methods, etc.. | |||
void _split( BSONObj& middle ); | void _split( BSONObj& middle ); | |||
friend class ChunkManager; | friend class ChunkManager; | |||
friend class ShardObjUnitTest; | friend class ShardObjUnitTest; | |||
}; | }; | |||
class ChunkRange{ | class ChunkRange{ | |||
public: | public: | |||
skipping to change at line 311 | skipping to change at line 309 | |||
} | } | |||
/** | /** | |||
* @param me - so i don't get deleted before i'm done | * @param me - so i don't get deleted before i'm done | |||
*/ | */ | |||
void drop( ChunkManagerPtr me ); | void drop( ChunkManagerPtr me ); | |||
private: | private: | |||
void _reload(); | void _reload(); | |||
void _reload_inlock(); | ||||
void _load(); | void _load(); | |||
DBConfig * _config; | DBConfig * _config; | |||
string _ns; | string _ns; | |||
ShardKeyPattern _key; | ShardKeyPattern _key; | |||
bool _unique; | bool _unique; | |||
vector<ChunkPtr> _chunks; | vector<ChunkPtr> _chunks; | |||
map<string,unsigned long long> _maxMarkers; | map<string,unsigned long long> _maxMarkers; | |||
End of changes. 3 change blocks. | ||||
3 lines changed or deleted | 2 lines changed or added | |||
client.h | client.h | |||
---|---|---|---|---|
skipping to change at line 32 | skipping to change at line 32 | |||
todo: switch to asio...this will fit nicely with that. | todo: switch to asio...this will fit nicely with that. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../pch.h" | #include "../pch.h" | |||
#include "security.h" | #include "security.h" | |||
#include "namespace.h" | #include "namespace.h" | |||
#include "lasterror.h" | #include "lasterror.h" | |||
#include "stats/top.h" | #include "stats/top.h" | |||
#include "repl/rs.h" | ||||
namespace mongo { | namespace mongo { | |||
class AuthenticationInfo; | class AuthenticationInfo; | |||
class Database; | class Database; | |||
class CurOp; | class CurOp; | |||
class Command; | class Command; | |||
class Client; | class Client; | |||
extern boost::thread_specific_ptr<Client> currentClient; | extern boost::thread_specific_ptr<Client> currentClient; | |||
skipping to change at line 106 | skipping to change at line 107 | |||
/** | /** | |||
* if you are doing this after allowing a write there could be a race condition | * if you are doing this after allowing a write there could be a race condition | |||
* if someone closes that db. this checks that the DB is still valid | * if someone closes that db. this checks that the DB is still valid | |||
*/ | */ | |||
Context( string ns , Database * db, bool doauth=true ); | Context( string ns , Database * db, bool doauth=true ); | |||
~Context(); | ~Context(); | |||
Client* getClient() const { return _client; } | Client* getClient() const { return _client; } | |||
Database* db() const { return _db; } | ||||
Database* db() const { | const char * ns() const { return _ns.c_str(); } | |||
return _db; | bool justCreated() const { return _justCreated; } | |||
} | ||||
const char * ns() const { | ||||
return _ns.c_str(); | ||||
} | ||||
bool justCreated() const { | ||||
return _justCreated; | ||||
} | ||||
bool equals( const string& ns , const string& path=dbpath ) con st { | bool equals( const string& ns , const string& path=dbpath ) con st { | |||
return _ns == ns && _path == path; | return _ns == ns && _path == path; | |||
} | } | |||
bool inDB( const string& db , const string& path=dbpath ) const { | bool inDB( const string& db , const string& path=dbpath ) const { | |||
if ( _path != path ) | if ( _path != path ) | |||
return false; | return false; | |||
if ( db == _ns ) | if ( db == _ns ) | |||
skipping to change at line 167 | skipping to change at line 159 | |||
}; | }; | |||
private: | private: | |||
CurOp * _curOp; | CurOp * _curOp; | |||
Context * _context; | Context * _context; | |||
bool _shutdown; | bool _shutdown; | |||
list<string> _tempCollections; | list<string> _tempCollections; | |||
const char *_desc; | const char *_desc; | |||
bool _god; | bool _god; | |||
AuthenticationInfo _ai; | AuthenticationInfo _ai; | |||
OpTime _lastOp; | ReplTime _lastOp; | |||
BSONObj _handshake; | BSONObj _handshake; | |||
BSONObj _remoteId; | BSONObj _remoteId; | |||
public: | public: | |||
string clientAddress() const; | string clientAddress() const; | |||
AuthenticationInfo * getAuthenticationInfo(){ return &_ai; } | AuthenticationInfo * getAuthenticationInfo(){ return &_ai; } | |||
bool isAdmin() { return _ai.isAuthorized( "admin" ); } | bool isAdmin() { return _ai.isAuthorized( "admin" ); } | |||
CurOp* curop() { return _curOp; } | CurOp* curop() { return _curOp; } | |||
Context* getContext(){ return _context; } | Context* getContext(){ return _context; } | |||
Database* database() { return _context ? _context->db() : 0; } | Database* database() { return _context ? _context->db() : 0; } | |||
const char *ns() const { return _context->ns(); } | const char *ns() const { return _context->ns(); } | |||
const char *desc() const { return _desc; } | const char *desc() const { return _desc; } | |||
Client(const char *desc); | Client(const char *desc); | |||
~Client(); | ~Client(); | |||
void addTempCollection( const string& ns ) { _tempCollections.push_ back( ns ); } | void addTempCollection( const string& ns ) { _tempCollections.push_ back( ns ); } | |||
void dropTempCollectionsInDB(const string db); | void dropTempCollectionsInDB(const string db); | |||
void dropAllTempCollectionsInDB(const string db); | void dropAllTempCollectionsInDB(const string db); | |||
void setLastOp( const OpTime& op ){ | void setLastOp( ReplTime op ) { | |||
_lastOp = op; | _lastOp = op; | |||
} | } | |||
OpTime getLastOp() const { | ReplTime getLastOp() const { | |||
return _lastOp; | return _lastOp; | |||
} | } | |||
void appendLastOp( BSONObjBuilder& b ){ | void appendLastOp( BSONObjBuilder& b ) { | |||
if ( ! _lastOp.isNull() ) | if( theReplSet ) { | |||
b.appendTimestamp( "lastOp" , _lastOp.asDate() ); | b.append("lastOp" , (long long) _lastOp); | |||
} | ||||
else { | ||||
OpTime lo(_lastOp); | ||||
if ( ! lo.isNull() ) | ||||
b.appendTimestamp( "lastOp" , lo.asDate() ); | ||||
} | ||||
} | } | |||
/* each thread which does db operations has a Client object in TLS. | /* each thread which does db operations has a Client object in TLS. | |||
call this when your thread starts. | call this when your thread starts. | |||
*/ | */ | |||
static void initThread(const char *desc); | static void initThread(const char *desc); | |||
/* | /* | |||
this has to be called as the client goes away, but before thread termination | this has to be called as the client goes away, but before thread termination | |||
@return true if anything was done | @return true if anything was done | |||
End of changes. 6 change blocks. | ||||
18 lines changed or deleted | 16 lines changed or added | |||
clientcursor.h | clientcursor.h | |||
---|---|---|---|---|
skipping to change at line 107 | skipping to change at line 107 | |||
} | } | |||
} | } | |||
~Pointer() { | ~Pointer() { | |||
release(); | release(); | |||
} | } | |||
}; | }; | |||
/*const*/ CursorId cursorid; | /*const*/ CursorId cursorid; | |||
string ns; | string ns; | |||
shared_ptr<Cursor> c; | shared_ptr<Cursor> c; | |||
int pos; // # objects into the curs or so far | int pos; // # objects into the cursor so far | |||
BSONObj query; | BSONObj query; | |||
int _queryOptions; | int _queryOptions; // see enum QueryOptions dbclient.h | |||
OpTime _slaveReadTill; | OpTime _slaveReadTill; | |||
ClientCursor(int queryOptions, shared_ptr<Cursor>& _c, const char * _ns) : | ClientCursor(int queryOptions, shared_ptr<Cursor>& _c, const char * _ns) : | |||
_idleAgeMillis(0), _pinValue(0), | _idleAgeMillis(0), _pinValue(0), | |||
_doingDeletes(false), | _doingDeletes(false), | |||
ns(_ns), c(_c), | ns(_ns), c(_c), | |||
pos(0), _queryOptions(queryOptions) | pos(0), _queryOptions(queryOptions) | |||
{ | { | |||
if( queryOptions & QueryOption_NoCursorTimeout ) | if( queryOptions & QueryOption_NoCursorTimeout ) | |||
noTimeout(); | noTimeout(); | |||
End of changes. 2 change blocks. | ||||
2 lines changed or deleted | 2 lines changed or added | |||
concurrency.h | concurrency.h | |||
---|---|---|---|---|
skipping to change at line 89 | skipping to change at line 89 | |||
class MongoMutex { | class MongoMutex { | |||
MutexInfo _minfo; | MutexInfo _minfo; | |||
RWLock _m; | RWLock _m; | |||
ThreadLocalValue<int> _state; | ThreadLocalValue<int> _state; | |||
/* we use a separate TLS value for releasedEarly - that is ok as | /* we use a separate TLS value for releasedEarly - that is ok as | |||
our normal/common code path, we never even touch it. | our normal/common code path, we never even touch it. | |||
*/ | */ | |||
ThreadLocalValue<bool> _releasedEarly; | ThreadLocalValue<bool> _releasedEarly; | |||
public: | public: | |||
MongoMutex(const char * name) : _m(name) { } | ||||
/** | /** | |||
* @return | * @return | |||
* > 0 write lock | * > 0 write lock | |||
* = 0 no lock | * = 0 no lock | |||
* < 0 read lock | * < 0 read lock | |||
*/ | */ | |||
int getState(){ return _state.get(); } | int getState(){ return _state.get(); } | |||
void assertWriteLocked() { | void assertWriteLocked() { | |||
assert( getState() > 0 ); | assert( getState() > 0 ); | |||
DEV assert( !_releasedEarly.get() ); | DEV assert( !_releasedEarly.get() ); | |||
} | } | |||
bool atLeastReadLocked() { return _state.get() != 0; } | bool atLeastReadLocked() { return _state.get() != 0; } | |||
void assertAtLeastReadLocked() { assert(atLeastReadLocked()); } | void assertAtLeastReadLocked() { assert(atLeastReadLocked()); } | |||
void lock() { | bool _checkWriteLockAlready(){ | |||
//DEV cout << "LOCK" << endl; | //DEV cout << "LOCK" << endl; | |||
DEV assert( haveClient() ); | DEV assert( haveClient() ); | |||
int s = _state.get(); | int s = _state.get(); | |||
if( s > 0 ) { | if( s > 0 ) { | |||
_state.set(s+1); | _state.set(s+1); | |||
return; | return true; | |||
} | } | |||
massert( 10293 , (string)"internal error: locks are not upgrade able: " + sayClientState() , s == 0 ); | massert( 10293 , (string)"internal error: locks are not upgrade able: " + sayClientState() , s == 0 ); | |||
return false; | ||||
} | ||||
void lock() { | ||||
if ( _checkWriteLockAlready() ) | ||||
return; | ||||
_state.set(1); | _state.set(1); | |||
curopWaitingForLock( 1 ); | curopWaitingForLock( 1 ); | |||
_m.lock(); | _m.lock(); | |||
curopGotLock(); | curopGotLock(); | |||
_minfo.entered(); | _minfo.entered(); | |||
} | } | |||
bool lock_try( int millis ) { | ||||
if ( _checkWriteLockAlready() ) | ||||
return true; | ||||
curopWaitingForLock( 1 ); | ||||
bool got = _m.lock_try( millis ); | ||||
curopGotLock(); | ||||
if ( got ){ | ||||
_minfo.entered(); | ||||
_state.set(1); | ||||
} | ||||
return got; | ||||
} | ||||
void unlock() { | void unlock() { | |||
//DEV cout << "UNLOCK" << endl; | //DEV cout << "UNLOCK" << endl; | |||
int s = _state.get(); | int s = _state.get(); | |||
if( s > 1 ) { | if( s > 1 ) { | |||
_state.set(s-1); | _state.set(s-1); | |||
return; | return; | |||
} | } | |||
if( s != 1 ) { | if( s != 1 ) { | |||
if( _releasedEarly.get() ) { | if( _releasedEarly.get() ) { | |||
_releasedEarly.set(false); | _releasedEarly.set(false); | |||
skipping to change at line 249 | skipping to change at line 277 | |||
if ( _got ){ | if ( _got ){ | |||
dbunlocking_read(); | dbunlocking_read(); | |||
dbMutex.unlock_shared(); | dbMutex.unlock_shared(); | |||
} | } | |||
} | } | |||
bool got() const { return _got; } | bool got() const { return _got; } | |||
private: | private: | |||
bool _got; | bool _got; | |||
}; | }; | |||
struct writelocktry { | ||||
writelocktry( const string&ns , int tryms ){ | ||||
_got = dbMutex.lock_try( tryms ); | ||||
} | ||||
~writelocktry() { | ||||
if ( _got ){ | ||||
dbunlocking_read(); | ||||
dbMutex.unlock(); | ||||
} | ||||
} | ||||
bool got() const { return _got; } | ||||
private: | ||||
bool _got; | ||||
}; | ||||
struct readlocktryassert : public readlocktry { | struct readlocktryassert : public readlocktry { | |||
readlocktryassert(const string& ns, int tryms) : | readlocktryassert(const string& ns, int tryms) : | |||
readlocktry(ns,tryms) { | readlocktry(ns,tryms) { | |||
uassert(13142, "timeout getting readlock", got()); | uassert(13142, "timeout getting readlock", got()); | |||
} | } | |||
}; | }; | |||
/** assure we have at least a read lock - they key with this being | /** assure we have at least a read lock - they key with this being | |||
if you have a write lock, that's ok too. | if you have a write lock, that's ok too. | |||
*/ | */ | |||
End of changes. 7 change blocks. | ||||
2 lines changed or deleted | 45 lines changed or added | |||
connpool.h | connpool.h | |||
---|---|---|---|---|
skipping to change at line 31 | skipping to change at line 31 | |||
#include "dbclient.h" | #include "dbclient.h" | |||
#include "redef_macros.h" | #include "redef_macros.h" | |||
namespace mongo { | namespace mongo { | |||
class Shard; | class Shard; | |||
struct PoolForHost { | struct PoolForHost { | |||
PoolForHost() | PoolForHost() | |||
: created(0){} | : created(0){} | |||
PoolForHost( const PoolForHost& other ){ | ||||
assert(other.pool.size() == 0); | ||||
created = other.created; | ||||
assert( created == 0 ); | ||||
} | ||||
std::stack<DBClientBase*> pool; | std::stack<DBClientBase*> pool; | |||
long long created; | long long created; | |||
}; | }; | |||
class DBConnectionHook { | class DBConnectionHook { | |||
public: | public: | |||
virtual ~DBConnectionHook(){} | virtual ~DBConnectionHook(){} | |||
virtual void onCreate( DBClientBase * conn ){} | virtual void onCreate( DBClientBase * conn ){} | |||
virtual void onHandedOut( DBClientBase * conn ){} | virtual void onHandedOut( DBClientBase * conn ){} | |||
}; | }; | |||
skipping to change at line 59 | skipping to change at line 65 | |||
Usage: | Usage: | |||
{ | { | |||
ScopedDbConnection c("myserver"); | ScopedDbConnection c("myserver"); | |||
c.conn()... | c.conn()... | |||
} | } | |||
*/ | */ | |||
class DBConnectionPool { | class DBConnectionPool { | |||
mongo::mutex _mutex; | mongo::mutex _mutex; | |||
map<string,PoolForHost*> _pools; // servername -> pool | map<string,PoolForHost> _pools; // servername -> pool | |||
list<DBConnectionHook*> _hooks; | list<DBConnectionHook*> _hooks; | |||
public: | public: | |||
DBConnectionPool() : _mutex("DBConnectionPool") { } | DBConnectionPool() : _mutex("DBConnectionPool") { } | |||
~DBConnectionPool(); | ||||
void onCreate( DBClientBase * conn ); | void onCreate( DBClientBase * conn ); | |||
void onHandedOut( DBClientBase * conn ); | void onHandedOut( DBClientBase * conn ); | |||
void flush(); | void flush(); | |||
DBClientBase *get(const string& host); | DBClientBase *get(const string& host); | |||
void release(const string& host, DBClientBase *c) { | void release(const string& host, DBClientBase *c) { | |||
if ( c->isFailed() ){ | if ( c->isFailed() ){ | |||
delete c; | delete c; | |||
return; | return; | |||
} | } | |||
scoped_lock L(_mutex); | scoped_lock L(_mutex); | |||
_pools[host]->pool.push(c); | _pools[host].pool.push(c); | |||
} | } | |||
void addHook( DBConnectionHook * hook ); | void addHook( DBConnectionHook * hook ); | |||
void appendInfo( BSONObjBuilder& b ); | void appendInfo( BSONObjBuilder& b ); | |||
}; | }; | |||
extern DBConnectionPool pool; | extern DBConnectionPool pool; | |||
/** Use to get a connection from the pool. On exceptions things | /** Use to get a connection from the pool. On exceptions things | |||
clean up nicely. | clean up nicely. | |||
*/ | */ | |||
End of changes. 4 change blocks. | ||||
2 lines changed or deleted | 9 lines changed or added | |||
cursor.h | cursor.h | |||
---|---|---|---|---|
skipping to change at line 106 | skipping to change at line 106 | |||
virtual bool capped() const { return false; } | virtual bool capped() const { return false; } | |||
// 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( auto_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 ); | |||
} | } | |||
}; | }; | |||
// strategy object implementing direction of traversal. | // strategy object implementing direction of traversal. | |||
class AdvanceStrategy { | class AdvanceStrategy { | |||
public: | public: | |||
virtual ~AdvanceStrategy() { } | virtual ~AdvanceStrategy() { } | |||
virtual DiskLoc next( const DiskLoc &prev ) const = 0; | virtual DiskLoc next( const DiskLoc &prev ) const = 0; | |||
}; | }; | |||
skipping to change at line 129 | skipping to change at line 129 | |||
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; | |||
private: | private: | |||
bool tailable_; | bool tailable_; | |||
auto_ptr< CoveredIndexMatcher > _matcher; | shared_ptr< CoveredIndexMatcher > _matcher; | |||
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 177 | skipping to change at line 177 | |||
} | } | |||
virtual bool tailable() { | virtual bool tailable() { | |||
return tailable_; | return tailable_; | |||
} | } | |||
virtual bool getsetdup(DiskLoc loc) { return false; } | virtual bool getsetdup(DiskLoc loc) { return false; } | |||
virtual bool supportGetMore() { return true; } | virtual bool supportGetMore() { return true; } | |||
virtual CoveredIndexMatcher *matcher() const { return _matcher.get( ); } | virtual CoveredIndexMatcher *matcher() const { return _matcher.get( ); } | |||
virtual void setMatcher( auto_ptr< CoveredIndexMatcher > matcher ) { | virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) { | |||
_matcher = matcher; | _matcher = matcher; | |||
} | } | |||
}; | }; | |||
/* 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() ) { } | |||
End of changes. 3 change blocks. | ||||
3 lines changed or deleted | 3 lines changed or added | |||
cursors.h | cursors.h | |||
---|---|---|---|---|
skipping to change at line 57 | skipping to change at line 57 | |||
int _skip; | int _skip; | |||
int _ntoreturn; | int _ntoreturn; | |||
int _totalSent; | int _totalSent; | |||
bool _done; | bool _done; | |||
long long _id; | long long _id; | |||
}; | }; | |||
typedef boost::shared_ptr<ShardedClientCursor> ShardedClientCursorPtr; | ||||
class CursorCache { | class CursorCache { | |||
public: | public: | |||
typedef map<long long,ShardedClientCursorPtr> MapSharded; | ||||
typedef map<long long,string> MapNormal; | ||||
CursorCache(); | CursorCache(); | |||
~CursorCache(); | ~CursorCache(); | |||
ShardedClientCursor * get( long long id ); | ShardedClientCursorPtr get( long long id ); | |||
void store( ShardedClientCursor* cursor ); | void store( ShardedClientCursorPtr cursor ); | |||
void remove( long long id ); | void remove( long long id ); | |||
void storeRef( const string& server , long long id ); | ||||
void gotKillCursors(Message& m ); | ||||
void appendInfo( BSONObjBuilder& result ); | ||||
private: | private: | |||
map<long long,ShardedClientCursor*> _cursors; | mutex _mutex; | |||
MapSharded _cursors; | ||||
MapNormal _refs; | ||||
}; | }; | |||
extern CursorCache cursorCache; | extern CursorCache cursorCache; | |||
} | } | |||
End of changes. 5 change blocks. | ||||
3 lines changed or deleted | 17 lines changed or added | |||
d_logic.h | d_logic.h | |||
---|---|---|---|---|
skipping to change at line 21 | skipping to change at line 21 | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | * GNU Affero General Public License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Lice nse | * You should have received a copy of the GNU Affero General Public Lice nse | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../pch.h" | #include "../pch.h" | |||
#include "../db/jsobj.h" | ||||
namespace mongo { | namespace mongo { | |||
class ShardingState; | ||||
typedef unsigned long long ConfigVersion; | ||||
typedef map<string,ConfigVersion> NSVersionMap; | ||||
// ----------- | ||||
/** | ||||
* TODO: this only works with single fields at the moment | ||||
*/ | ||||
class ChunkMatcher { | ||||
typedef map<BSONObj,pair<BSONObj,BSONObj>,BSONObjCmp> MyMap; | ||||
public: | ||||
bool belongsToMe( const BSONObj& key , const DiskLoc& loc ) const; | ||||
private: | ||||
ChunkMatcher( ConfigVersion version ); | ||||
void gotRange( const BSONObj& min , const BSONObj& max ); | ||||
ConfigVersion _version; | ||||
string _field; | ||||
MyMap _map; | ||||
friend class ShardingState; | ||||
}; | ||||
typedef shared_ptr<ChunkMatcher> ChunkMatcherPtr; | ||||
// -------------- | ||||
// --- global state --- | ||||
// -------------- | ||||
class ShardingState { | ||||
public: | ||||
ShardingState(); | ||||
bool enabled() const { return _enabled; } | ||||
const string& getConfigServer() const { return _configServer; } | ||||
void enable( const string& server ); | ||||
void gotShardName( const string& name ); | ||||
void gotShardHost( const string& host ); | ||||
bool hasVersion( const string& ns ); | ||||
bool hasVersion( const string& ns , ConfigVersion& version ); | ||||
ConfigVersion& getVersion( const string& ns ); // TODO: this is dan | ||||
geroues | ||||
void setVersion( const string& ns , const ConfigVersion& version ); | ||||
void appendInfo( BSONObjBuilder& b ); | ||||
ChunkMatcherPtr getChunkMatcher( const string& ns ); | ||||
private: | ||||
bool _enabled; | ||||
string _configServer; | ||||
string _shardName; | ||||
string _shardHost; | ||||
mongo::mutex _mutex; | ||||
NSVersionMap _versions; | ||||
map<string,ChunkMatcherPtr> _chunks; | ||||
}; | ||||
extern ShardingState shardingState; | ||||
// -------------- | ||||
// --- per connection --- | ||||
// -------------- | ||||
class ShardedConnectionInfo { | ||||
public: | ||||
ShardedConnectionInfo(); | ||||
const OID& getID() const { return _id; } | ||||
bool hasID() const { return _id.isSet(); } | ||||
void setID( const OID& id ); | ||||
ConfigVersion& getVersion( const string& ns ); // TODO: this is dan | ||||
geroues | ||||
void setVersion( const string& ns , const ConfigVersion& version ); | ||||
static ShardedConnectionInfo* get( bool create ); | ||||
private: | ||||
OID _id; | ||||
NSVersionMap _versions; | ||||
static boost::thread_specific_ptr<ShardedConnectionInfo> _tl; | ||||
}; | ||||
// ----------------- | ||||
// --- core --- | ||||
// ----------------- | ||||
unsigned long long extractVersion( BSONElement e , string& errmsg ); | ||||
/** | /** | |||
* @return true if we have any shard info for the ns | * @return true if we have any shard info for the ns | |||
*/ | */ | |||
bool haveLocalShardingInfo( const string& ns ); | bool haveLocalShardingInfo( const string& ns ); | |||
/** | /** | |||
* @return true if the current threads shard version is ok, or not in s harded version | * @return true if the current threads shard version is ok, or not in s harded version | |||
*/ | */ | |||
bool shardVersionOk( const string& ns , string& errmsg ); | bool shardVersionOk( const string& ns , string& errmsg ); | |||
/** | /** | |||
* @return true if we took care of the message and nothing else should be done | * @return true if we took care of the message and nothing else should be done | |||
*/ | */ | |||
bool handlePossibleShardedMessage( Message &m, DbResponse &dbresponse ) ; | bool handlePossibleShardedMessage( Message &m, DbResponse &dbresponse ) ; | |||
// ----------------- | ||||
// --- writeback --- | ||||
// ----------------- | ||||
/* queue a write back on a remote server for a failed write */ | ||||
void queueWriteBack( const string& remote , const BSONObj& o ); | ||||
} | } | |||
End of changes. 3 change blocks. | ||||
0 lines changed or deleted | 112 lines changed or added | |||
database.h | database.h | |||
---|---|---|---|---|
skipping to change at line 34 | skipping to change at line 34 | |||
/** | /** | |||
* 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, bool& newDb, const string& _path = dbpath) | |||
: name(nm), path(_path), namespaceIndex( path, name ) { | ; | |||
{ // check db name is valid | ||||
size_t L = strlen(nm); | ||||
uassert( 10028 , "db name is empty", L > 0 ); | ||||
uassert( 10029 , "bad db name [1]", *nm != '.' ); | ||||
uassert( 10030 , "bad db name [2]", nm[L-1] != '.' ); | ||||
uassert( 10031 , "bad char(s) in db name", strchr(nm, ' ') | ||||
== 0 ); | ||||
uassert( 10032 , "db name too long", L < 64 ); | ||||
} | ||||
newDb = namespaceIndex.exists(); | ||||
profile = 0; | ||||
profileName = name + ".system.profile"; | ||||
// If already exists, open. Otherwise behave as if empty until | ||||
// there's a write, then open. | ||||
if ( ! newDb || cmdLine.defaultProfile ) { | ||||
namespaceIndex.init(); | ||||
if( _openAllFiles ) | ||||
openAllFiles(); | ||||
} | ||||
magic = 781231; | ||||
} | ||||
~Database() { | ~Database() { | |||
magic = 0; | magic = 0; | |||
btreeStore->closeFiles(name, path); | btreeStore->closeFiles(name, path); | |||
size_t n = files.size(); | size_t n = files.size(); | |||
for ( size_t i = 0; i < n; i++ ) | for ( size_t i = 0; i < n; i++ ) | |||
delete files[i]; | delete files[i]; | |||
} | } | |||
/** | /** | |||
skipping to change at line 210 | skipping to change at line 184 | |||
/** | /** | |||
* @return true if success, false otherwise | * @return true if success, false otherwise | |||
*/ | */ | |||
bool setProfilingLevel( int newLevel , string& errmsg ); | bool setProfilingLevel( int newLevel , string& errmsg ); | |||
void finishInit(); | void finishInit(); | |||
static bool validDBName( const string& ns ); | static bool validDBName( const string& ns ); | |||
long long fileSize(){ | ||||
long long size=0; | ||||
for (int n=0; exists(n); n++) | ||||
size += boost::filesystem::file_size( fileName(n) ); | ||||
return size; | ||||
} | ||||
vector<MongoDataFile*> files; | vector<MongoDataFile*> files; | |||
string name; // "alleyinsider" | string name; // "alleyinsider" | |||
string path; | string path; | |||
NamespaceIndex namespaceIndex; | NamespaceIndex namespaceIndex; | |||
int profile; // 0=off. | int profile; // 0=off. | |||
string profileName; // "alleyinsider.system.profile" | string profileName; // "alleyinsider.system.profile" | |||
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. 2 change blocks. | ||||
28 lines changed or deleted | 9 lines changed or added | |||
dbclient.h | dbclient.h | |||
---|---|---|---|---|
skipping to change at line 54 | skipping to change at line 54 | |||
// findingStart mode is used to find the first operation of interes t when | // findingStart mode is used to find the first operation of interes t when | |||
// we are scanning through a repl log. For efficiency in the commo n case, | // we are scanning through a repl log. For efficiency in the commo n case, | |||
// where the first operation of interest is closer to the tail than the head, | // where the first operation of interest is closer to the tail than the head, | |||
// we start from the tail of the log and work backwards until we fi nd the | // we start from the tail of the log and work backwards until we fi nd the | |||
// first operation of interest. Then we scan forward from that fir st operation, | // first operation of interest. Then we scan forward from that fir st operation, | |||
// actually returning results to the client. During the findingSta rt phase, | // actually returning results to the client. During the findingSta rt phase, | |||
// we release the db mutex occasionally to avoid blocking the db pr ocess for | // we release the db mutex occasionally to avoid blocking the db pr ocess for | |||
// an extended period of time. | // an extended period of time. | |||
QueryOption_OplogReplay = 1 << 3, | QueryOption_OplogReplay = 1 << 3, | |||
/** The server normally times out idle cursors after an inactivy pe riod to prevent excess memory use | /** The server normally times out idle cursors after an inactivy pe riod to prevent excess memory uses | |||
Set this option to prevent that. | Set this option to prevent that. | |||
*/ | */ | |||
QueryOption_NoCursorTimeout = 1 << 4, | QueryOption_NoCursorTimeout = 1 << 4, | |||
/** Use with QueryOption_CursorTailable. If we are at the end of t he data, block for a while rather | /** Use with QueryOption_CursorTailable. If we are at the end of t he data, block for a while rather | |||
than returning no data. After a timeout period, we do return as normal. | than returning no data. After a timeout period, we do return as normal. | |||
*/ | */ | |||
QueryOption_AwaitData = 1 << 5 | QueryOption_AwaitData = 1 << 5, | |||
/** Stream the data down full blast in multiple "more" packages, on | ||||
the assumption that the client | ||||
will fully read all data queried. Faster when you are pulling | ||||
a lot of data and know you want to | ||||
pull it all down. Note: it is not allowed to not read all the | ||||
data unless you close the connection. | ||||
*/ | ||||
QueryOption_Exhaust = 1 << 6 | ||||
}; | }; | |||
enum UpdateOptions { | enum UpdateOptions { | |||
/** Upsert - that is, insert the item if no matching item is found. */ | /** Upsert - that is, insert the item if no matching item is found. */ | |||
UpdateOption_Upsert = 1 << 0, | UpdateOption_Upsert = 1 << 0, | |||
/** Update multiple documents (if multiple documents match query ex pression). | /** Update multiple documents (if multiple documents match query ex pression). | |||
(Default is update a single document and stop.) */ | (Default is update a single document and stop.) */ | |||
UpdateOption_Multi = 1 << 1 | UpdateOption_Multi = 1 << 1 | |||
skipping to change at line 211 | skipping to change at line 217 | |||
/** | /** | |||
interface that handles communication with the db | interface that handles communication with the db | |||
*/ | */ | |||
class DBConnector { | class DBConnector { | |||
public: | public: | |||
virtual ~DBConnector() {} | virtual ~DBConnector() {} | |||
virtual bool call( Message &toSend, Message &response, bool assertO k=true ) = 0; | virtual bool call( Message &toSend, Message &response, bool assertO k=true ) = 0; | |||
virtual void say( Message &toSend ) = 0; | virtual void say( Message &toSend ) = 0; | |||
virtual void sayPiggyBack( Message &toSend ) = 0; | virtual void sayPiggyBack( Message &toSend ) = 0; | |||
virtual void checkResponse( const string &data, int nReturned ) {} | virtual void checkResponse( const string &data, int nReturned ) {} | |||
/* used by QueryOption_Exhaust. To use that your subclass must imp | ||||
lement this. */ | ||||
virtual void recv( Message& m ) { assert(false); } | ||||
}; | }; | |||
/** | /** | |||
The interface that any db connection should implement | The interface that any db connection should implement | |||
*/ | */ | |||
class DBClientInterface : boost::noncopyable { | class DBClientInterface : boost::noncopyable { | |||
public: | public: | |||
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0, | virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0, | |||
const BSONObj *fieldsToRetur n = 0, int queryOptions = 0 , int batchSize = 0 ) = 0; | const BSONObj *fieldsToRetur n = 0, int queryOptions = 0 , int batchSize = 0 ) = 0; | |||
/** don't use this - called automatically by DBClientCursor for you */ | ||||
virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo ng cursorId, int nToReturn = 0, int options = 0 ) = 0; | virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo ng cursorId, int nToReturn = 0, int options = 0 ) = 0; | |||
virtual void insert( const string &ns, BSONObj obj ) = 0; | virtual void insert( const string &ns, BSONObj obj ) = 0; | |||
virtual void insert( const string &ns, const vector< BSONObj >& v ) = 0; | virtual void insert( const string &ns, const vector< BSONObj >& v ) = 0; | |||
virtual void remove( const string &ns , Query query, bool justOne = 0 ) = 0; | virtual void remove( const string &ns , Query query, bool justOne = 0 ) = 0; | |||
virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = 0 , bool multi = 0 ) = 0; | virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = 0 , bool multi = 0 ) = 0; | |||
skipping to change at line 307 | skipping to change at line 317 | |||
returns true if command invoked successfully. | returns true if command invoked successfully. | |||
*/ | */ | |||
virtual bool isMaster(bool& isMaster, BSONObj *info=0); | virtual bool isMaster(bool& isMaster, BSONObj *info=0); | |||
/** | /** | |||
Create a new collection in the database. Normally, collection c reation is automatic. You would | Create a new collection in the database. Normally, collection c reation is automatic. You would | |||
use this function if you wish to specify special options on crea tion. | use this function if you wish to specify special options on crea tion. | |||
If the collection already exists, no action occurs. | If the collection already exists, no action occurs. | |||
ns: fully qualified collection name | @param ns fully qualified collection name | |||
size: desired initial extent size for the collection. | @param size desired initial extent size for the collection. | |||
Must be <= 1000000000 for normal collections. | Must be <= 1000000000 for normal collections. | |||
For fixed size (capped) collections, this size is | For fixed size (capped) collections, this size is | |||
the total/max size of the | the total/max size of the | |||
collection. | collection. | |||
capped: if true, this is a fixed size collection (where old data | @param capped if true, this is a fixed size collection (where ol | |||
rolls out). | d data rolls out). | |||
max: maximum number of objects if capped (optional). | @param max maximum number of objects if capped (optional). | |||
returns true if successful. | returns true if successful. | |||
*/ | */ | |||
bool createCollection(const string &ns, unsigned size = 0, bool cap ped = false, int max = 0, BSONObj *info = 0); | bool createCollection(const string &ns, long long size = 0, bool ca pped = false, int max = 0, BSONObj *info = 0); | |||
/** Get error result from the last operation on this connection. | /** Get error result from the last operation on this connection. | |||
@return error message text, or empty string if no error. | @return error message text, or empty string if no error. | |||
*/ | */ | |||
string getLastError(); | string getLastError(); | |||
/** Get error result from the last operation on this connect ion. | /** Get error result from the last operation on this connect ion. | |||
@return full error object. | @return full error object. | |||
*/ | */ | |||
BSONObj getLastErrorDetailed(); | BSONObj getLastErrorDetailed(); | |||
static string getLastErrorString( const BSONObj& res ); | ||||
/** Return the last error which has occurred, even if not the very last operation. | /** Return the last error which has occurred, even if not the very last operation. | |||
@return { err : <error message>, nPrev : <how_many_ops_back_occu rred>, ok : 1 } | @return { err : <error message>, nPrev : <how_many_ops_back_occu rred>, ok : 1 } | |||
result.err will be null if no error has occurred. | result.err will be null if no error has occurred. | |||
*/ | */ | |||
BSONObj getPrevError(); | BSONObj getPrevError(); | |||
/** Reset the previous error state for this connection (accessed vi a getLastError and | /** Reset the previous error state for this connection (accessed vi a getLastError and | |||
getPrevError). Useful when performing several operations at on ce and then checking | getPrevError). Useful when performing several operations at on ce and then checking | |||
skipping to change at line 583 | skipping to change at line 594 | |||
@param nToSkip start with the nth item | @param nToSkip start with the nth item | |||
@param fieldsToReturn optional template of which fields to select. if unspecified, returns all fields | @param fieldsToReturn optional template of which fields to select. if unspecified, returns all fields | |||
@param queryOptions see options enum at top of this file | @param queryOptions see options enum at top of this file | |||
@return cursor. 0 if error (connection failure) | @return cursor. 0 if error (connection failure) | |||
@throws AssertionException | @throws AssertionException | |||
*/ | */ | |||
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0, | virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0, | |||
const BSONObj *fieldsToRetur n = 0, int queryOptions = 0 , int batchSize = 0 ); | const BSONObj *fieldsToRetur n = 0, int queryOptions = 0 , int batchSize = 0 ); | |||
/** @param cursorId id of cursor to retrieve | /** don't use this - called automatically by DBClientCursor for you | |||
@param cursorId id of cursor to retrieve | ||||
@return an handle to a previously allocated cursor | @return an handle to a previously allocated cursor | |||
@throws AssertionException | @throws AssertionException | |||
*/ | */ | |||
virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo ng cursorId, int nToReturn = 0, int options = 0 ); | virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo ng cursorId, int nToReturn = 0, int options = 0 ); | |||
/** | /** | |||
insert an object into the database | insert an object into the database | |||
*/ | */ | |||
virtual void insert( const string &ns , BSONObj obj ); | virtual void insert( const string &ns , BSONObj obj ); | |||
skipping to change at line 614 | skipping to change at line 626 | |||
/** | /** | |||
updates objects matching query | updates objects matching query | |||
*/ | */ | |||
virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = false , bool multi = false ); | virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = false , bool multi = false ); | |||
virtual string getServerAddress() const = 0; | virtual string getServerAddress() const = 0; | |||
virtual bool isFailed() const = 0; | virtual bool isFailed() const = 0; | |||
virtual void killCursor( long long cursorID ) = 0; | ||||
static int countCommas( const string& s ){ | static int countCommas( const string& s ){ | |||
int n = 0; | int n = 0; | |||
for ( unsigned i=0; i<s.size(); i++ ) | for ( unsigned i=0; i<s.size(); i++ ) | |||
if ( s[i] == ',' ) | if ( s[i] == ',' ) | |||
n++; | n++; | |||
return n; | return n; | |||
} | } | |||
}; // end DBClientBase | }; // DBClientBase | |||
class DBClientPaired; | class DBClientPaired; | |||
class ConnectException : public UserException { | class ConnectException : public UserException { | |||
public: | public: | |||
ConnectException(string msg) : UserException(9000,msg) { } | ConnectException(string msg) : UserException(9000,msg) { } | |||
}; | }; | |||
/** | /** | |||
A basic connection to the database. | A basic connection to the database. | |||
This is the main entry point for talking to a simple Mongo setup | This is the main entry point for talking to a simple Mongo setup | |||
*/ | */ | |||
class DBClientConnection : public DBClientBase { | class DBClientConnection : public DBClientBase { | |||
DBClientPaired *clientPaired; | DBClientPaired *clientPaired; | |||
auto_ptr<MessagingPort> p; | boost::scoped_ptr<MessagingPort> p; | |||
auto_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; | |||
string serverAddress; // remember for reconnects | string serverAddress; // remember for reconnects | |||
void _checkConnection(); | void _checkConnection(); | |||
void checkConnection() { if( failed ) _checkConnection(); } | void checkConnection() { if( failed ) _checkConnection(); } | |||
map< string, pair<string,string> > authCache; | map< string, pair<string,string> > authCache; | |||
int _timeout; | int _timeout; | |||
public: | public: | |||
skipping to change at line 691 | skipping to change at line 705 | |||
} | } | |||
virtual bool auth(const string &dbname, const string &username, con st string &pwd, string& errmsg, bool digestPassword = true); | virtual bool auth(const string &dbname, const string &username, con st string &pwd, string& errmsg, bool digestPassword = true); | |||
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y=Query(), int nToReturn = 0, int nToSkip = 0, | virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y=Query(), int nToReturn = 0, int nToSkip = 0, | |||
const BSONObj *fieldsToRetur n = 0, int queryOptions = 0 , int batchSize = 0 ) { | const BSONObj *fieldsToRetur n = 0, int queryOptions = 0 , int batchSize = 0 ) { | |||
checkConnection(); | checkConnection(); | |||
return DBClientBase::query( ns, query, nToReturn, nToSkip, fiel dsToReturn, queryOptions , batchSize ); | return DBClientBase::query( ns, query, nToReturn, nToSkip, fiel dsToReturn, queryOptions , batchSize ); | |||
} | } | |||
/** uses QueryOption_Exhaust | ||||
*/ | ||||
unsigned long long query( boost::function<void(const BSONObj&)> f, | ||||
const string& ns, Query query, const BSONObj *fieldsToReturn = 0); | ||||
/** | /** | |||
@return true if this connection is currently in a failed state. When autoreconnect is on, | @return true if this connection is currently in a failed state. When autoreconnect is on, | |||
a connection will transition back to an ok state after r econnecting. | a connection will transition back to an ok state after r econnecting. | |||
*/ | */ | |||
bool isFailed() const { | bool isFailed() const { | |||
return failed; | return failed; | |||
} | } | |||
MessagingPort& port() { | MessagingPort& port() { | |||
return *p.get(); | return *p; | |||
} | } | |||
string toStringLong() const { | string toStringLong() const { | |||
stringstream ss; | stringstream ss; | |||
ss << serverAddress; | ss << serverAddress; | |||
if ( failed ) ss << " failed"; | if ( failed ) ss << " failed"; | |||
return ss.str(); | return ss.str(); | |||
} | } | |||
/** Returns the address of the server */ | /** Returns the address of the server */ | |||
string toString() { | string toString() { | |||
return serverAddress; | return serverAddress; | |||
} | } | |||
string getServerAddress() const { | string getServerAddress() const { | |||
return serverAddress; | return serverAddress; | |||
} | } | |||
virtual void killCursor( long long cursorID ); | ||||
protected: | ||||
friend class SyncClusterConnection; | ||||
virtual void recv( Message& m ); | ||||
virtual bool call( Message &toSend, Message &response, bool assertO k = true ); | virtual bool call( Message &toSend, Message &response, bool assertO k = true ); | |||
virtual void say( Message &toSend ); | virtual void say( Message &toSend ); | |||
virtual void sayPiggyBack( Message &toSend ); | virtual void sayPiggyBack( Message &toSend ); | |||
virtual void checkResponse( const char *data, int nReturned ); | virtual void checkResponse( const char *data, int nReturned ); | |||
}; | }; | |||
/** Use this class to connect to a replica pair of servers. The class will manage | /** Use this class to connect to a replica pair of servers. The class will manage | |||
checking for which server in a replica pair is master, and do failov er automatically. | checking for which server in a replica pair is master, and do failov er automatically. | |||
On a failover situation, expect at least one operation to return an error (throw | On a failover situation, expect at least one operation to return an error (throw | |||
skipping to change at line 792 | skipping to change at line 815 | |||
/** remove */ | /** remove */ | |||
virtual void remove( const string &ns , Query obj , bool justOne = 0 ) { | virtual void remove( const string &ns , Query obj , bool justOne = 0 ) { | |||
checkMaster().remove(ns, obj, justOne); | checkMaster().remove(ns, obj, justOne); | |||
} | } | |||
/** update */ | /** update */ | |||
virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = 0 , bool multi = 0 ) { | virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = 0 , bool multi = 0 ) { | |||
return checkMaster().update(ns, query, obj, upsert,multi); | return checkMaster().update(ns, query, obj, upsert,multi); | |||
} | } | |||
virtual void killCursor( long long cursorID ){ | ||||
checkMaster().killCursor( cursorID ); | ||||
} | ||||
string toString(); | string toString(); | |||
/* this is the callback from our underlying connections to notify u s that we got a "not master" error. | /* this is the callback from our underlying connections to notify u s that we got a "not master" error. | |||
*/ | */ | |||
void isntMaster() { | void isntMaster() { | |||
master = ( ( master == Left ) ? NotSetR : NotSetL ); | master = ( ( master == Left ) ? NotSetR : NotSetL ); | |||
} | } | |||
string getServerAddress() const { | string getServerAddress() const { | |||
return left.getServerAddress() + "," + right.getServerAddress() ; | return left.getServerAddress() + "," + right.getServerAddress() ; | |||
End of changes. 15 change blocks. | ||||
17 lines changed or deleted | 50 lines changed or added | |||
dbclientcursor.h | dbclientcursor.h | |||
---|---|---|---|---|
skipping to change at line 148 | skipping to change at line 148 | |||
/** by default we "own" the cursor and will send the server a KillC ursor | /** by default we "own" the cursor and will send the server a KillC ursor | |||
message when ~DBClientCursor() is called. This function overrid es that. | message when ~DBClientCursor() is called. This function overrid es that. | |||
*/ | */ | |||
void decouple() { _ownCursor = false; } | void decouple() { _ownCursor = false; } | |||
void attach( ScopedDbConnection * conn ); | void attach( ScopedDbConnection * conn ); | |||
void attach( ShardConnection * conn ); | void attach( ShardConnection * conn ); | |||
private: | private: | |||
friend class DBClientBase; | friend class DBClientBase; | |||
friend class DBClientConnection; | ||||
bool init(); | bool init(); | |||
int nextBatchSize(); | int nextBatchSize(); | |||
DBConnector *connector; | DBConnector *connector; | |||
string ns; | string ns; | |||
BSONObj query; | BSONObj query; | |||
int nToReturn; | int nToReturn; | |||
bool haveLimit; | bool haveLimit; | |||
int nToSkip; | int nToSkip; | |||
const BSONObj *fieldsToReturn; | const BSONObj *fieldsToReturn; | |||
int opts; | int opts; | |||
int batchSize; | int batchSize; | |||
auto_ptr<Message> m; | auto_ptr<Message> m; | |||
stack< BSONObj > _putBack; | stack< BSONObj > _putBack; | |||
int resultFlags; | int resultFlags; | |||
long long cursorId; | long long cursorId; | |||
int nReturned; | int nReturned; | |||
int pos; | int pos; | |||
const char *data; | const char *data; | |||
void dataReceived(); | void dataReceived(); | |||
void requestMore(); | void requestMore(); | |||
void exhaustReceiveMore(); // for exhaust | ||||
bool _ownCursor; // see decouple() | bool _ownCursor; // see decouple() | |||
string _scopedHost; | string _scopedHost; | |||
}; | }; | |||
} // namespace mongo | } // namespace mongo | |||
#include "undef_macros.h" | #include "undef_macros.h" | |||
End of changes. 2 change blocks. | ||||
0 lines changed or deleted | 2 lines changed or added | |||
dbhelpers.h | dbhelpers.h | |||
---|---|---|---|---|
skipping to change at line 31 | skipping to change at line 31 | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../pch.h" | #include "../pch.h" | |||
#include "client.h" | #include "client.h" | |||
#include "db.h" | #include "db.h" | |||
namespace mongo { | namespace mongo { | |||
const BSONObj reverseNaturalObj = BSON( "$natural" << -1 ); | ||||
class Cursor; | class Cursor; | |||
class CoveredIndexMatcher; | class CoveredIndexMatcher; | |||
class CursorIterator { | class CursorIterator { | |||
public: | public: | |||
CursorIterator( shared_ptr<Cursor> c , BSONObj filter = BSONObj() ) ; | CursorIterator( shared_ptr<Cursor> c , BSONObj filter = BSONObj() ) ; | |||
BSONObj next(); | BSONObj next(); | |||
bool hasNext(); | bool hasNext(); | |||
private: | private: | |||
skipping to change at line 69 | skipping to change at line 71 | |||
OCCASIONALLY ensureIndex(...); | OCCASIONALLY ensureIndex(...); | |||
Note: use ensureHaveIdIndex() for the _id index: it is faster. | Note: use ensureHaveIdIndex() for the _id index: it is faster. | |||
Note: does nothing if collection does not yet exist. | Note: does nothing if collection does not yet exist. | |||
*/ | */ | |||
static void ensureIndex(const char *ns, BSONObj keyPattern, bool un ique, const char *name); | static void ensureIndex(const char *ns, BSONObj keyPattern, bool un ique, const char *name); | |||
/* fetch a single object from collection ns that matches query. | /* fetch a single object from collection ns that matches query. | |||
set your db SavedContext first. | set your db SavedContext first. | |||
@param query - the query to perform. note this is the low level | ||||
portion of query so "orderby : ..." | ||||
won't work. | ||||
@param requireIndex if true, complain if no index for the query. a way to guard against | @param requireIndex if true, complain if no index for the query. a way to guard against | |||
writing a slow query. | writing a slow query. | |||
@return true if object found | @return true if object found | |||
*/ | */ | |||
static bool findOne(const char *ns, BSONObj query, BSONObj& result, bool requireIndex = false); | static bool findOne(const char *ns, const BSONObj &query, BSONObj& result, bool requireIndex = false); | |||
/** | /** | |||
* @param foundIndex if passed in will be set to 1 if ns and index found | * @param foundIndex if passed in will be set to 1 if ns and index found | |||
* @return true if object found | * @return true if object found | |||
*/ | */ | |||
static bool findById(Client&, const char *ns, BSONObj query, BSONOb j& result , | static bool findById(Client&, const char *ns, BSONObj query, BSONOb j& result , | |||
bool * nsFound = 0 , bool * indexFound = 0 ); | bool * nsFound = 0 , bool * indexFound = 0 ); | |||
static auto_ptr<CursorIterator> find( const char *ns , BSONObj quer y = BSONObj() , bool requireIndex = false ); | static auto_ptr<CursorIterator> find( const char *ns , BSONObj quer y = BSONObj() , bool requireIndex = false ); | |||
/** Get/put the first object from a collection. Generally only use ful if the collection | /** Get/put the first (or last) object from a collection. Generall y only useful if the collection | |||
only ever has a single object -- which is a "singleton collecti on". | only ever has a single object -- which is a "singleton collecti on". | |||
You do not need to set the database before calling. | You do not need to set the database (Context) before calling. | |||
@return true if object exists. | @return true if object exists. | |||
*/ | */ | |||
static bool getSingleton(const char *ns, BSONObj& result); | static bool getSingleton(const char *ns, BSONObj& result); | |||
static void putSingleton(const char *ns, BSONObj obj); | static void putSingleton(const char *ns, BSONObj obj); | |||
static void putSingletonGod(const char *ns, BSONObj obj, bool logTh eOp); | static void putSingletonGod(const char *ns, BSONObj obj, bool logTh eOp); | |||
static bool getFirst(const char *ns, BSONObj& result) { return getS | ||||
ingleton(ns, result); } | ||||
static bool getLast(const char *ns, BSONObj& result); // get last o | ||||
bject int he collection; e.g. {$natural : -1} | ||||
/** You do not need to set the database before calling. | /** You do not need to set the database before calling. | |||
@return true if collection is empty. | @return true if collection is empty. | |||
*/ | */ | |||
static bool isEmpty(const char *ns); | static bool isEmpty(const char *ns); | |||
/* Remove all objects from a collection. | /* Remove all objects from a collection. | |||
You do not need to set the database before calling. | You do not need to set the database before calling. | |||
*/ | */ | |||
static void emptyCollection(const char *ns); | static void emptyCollection(const char *ns); | |||
End of changes. 6 change blocks. | ||||
3 lines changed or deleted | 13 lines changed or added | |||
dbmessage.h | dbmessage.h | |||
---|---|---|---|---|
skipping to change at line 78 | skipping to change at line 78 | |||
return dataAsInt(); | return dataAsInt(); | |||
} | } | |||
void setResultFlagsToOk() { | void setResultFlagsToOk() { | |||
_resultFlags() = ResultFlag_AwaitCapable; | _resultFlags() = ResultFlag_AwaitCapable; | |||
} | } | |||
}; | }; | |||
#pragma pack() | #pragma pack() | |||
/* For the database/server protocol, these objects and functions encaps ulate | /* For the database/server protocol, these objects and functions encaps ulate | |||
the various messages transmitted over the connection. | the various messages transmitted over the connection. | |||
*/ | ||||
See http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol | ||||
*/ | ||||
class DbMessage { | class DbMessage { | |||
public: | public: | |||
DbMessage(const Message& _m) : m(_m) { | DbMessage(const Message& _m) : m(_m) | |||
{ | ||||
// for received messages, Message has only one buffer | // for received messages, Message has only one buffer | |||
theEnd = _m.singleData()->_data + _m.header()->dataLen(); | theEnd = _m.singleData()->_data + _m.header()->dataLen(); | |||
int *r = (int *) _m.singleData()->_data; | char *r = _m.singleData()->_data; | |||
reserved = *r; | reserved = (int *) r; | |||
r++; | data = r + 4; | |||
data = (const char *) r; | ||||
nextjsobj = data; | nextjsobj = data; | |||
} | } | |||
/** the 32 bit field before the ns */ | ||||
int& reservedField() { return *reserved; } | ||||
const char * getns() const { | const char * getns() const { | |||
return data; | return data; | |||
} | } | |||
void getns(Namespace& ns) const { | void getns(Namespace& ns) const { | |||
ns = data; | ns = data; | |||
} | } | |||
const char * afterNS() const { | const char * afterNS() const { | |||
return data + strlen( data ) + 1; | return data + strlen( data ) + 1; | |||
} | } | |||
int getInt( int num ) const { | int getInt( int num ) const { | |||
const int * foo = (const int*)afterNS(); | const int * foo = (const int*)afterNS(); | |||
return foo[num]; | return foo[num]; | |||
} | } | |||
int getQueryNToReturn() const { | int getQueryNToReturn() const { | |||
return getInt( 1 ); | return getInt( 1 ); | |||
} | } | |||
void resetPull(){ | void resetPull(){ nextjsobj = data; } | |||
nextjsobj = data; | int pullInt() const { return pullInt(); } | |||
} | int& pullInt() { | |||
int pullInt() { | ||||
if ( nextjsobj == data ) | if ( nextjsobj == data ) | |||
nextjsobj += strlen(data) + 1; // skip namespace | nextjsobj += strlen(data) + 1; // skip namespace | |||
int i = *((int *)nextjsobj); | int& i = *((int *)nextjsobj); | |||
nextjsobj += 4; | nextjsobj += 4; | |||
return i; | return i; | |||
} | } | |||
long long pullInt64() const { | long long pullInt64() const { | |||
return pullInt64(); | return pullInt64(); | |||
} | } | |||
long long &pullInt64() { | long long &pullInt64() { | |||
if ( nextjsobj == data ) | if ( nextjsobj == data ) | |||
nextjsobj += strlen(data) + 1; // skip namespace | nextjsobj += strlen(data) + 1; // skip namespace | |||
long long &i = *((long long *)nextjsobj); | long long &i = *((long long *)nextjsobj); | |||
skipping to change at line 153 | skipping to change at line 156 | |||
/* for insert and update msgs */ | /* for insert and update msgs */ | |||
bool moreJSObjs() const { | bool moreJSObjs() const { | |||
return nextjsobj != 0; | return nextjsobj != 0; | |||
} | } | |||
BSONObj nextJsObj() { | BSONObj nextJsObj() { | |||
if ( nextjsobj == data ) { | if ( nextjsobj == data ) { | |||
nextjsobj += strlen(data) + 1; // skip namespace | nextjsobj += strlen(data) + 1; // skip namespace | |||
massert( 13066 , "Message contains no documents", theEnd > nextjsobj ); | massert( 13066 , "Message contains no documents", theEnd > nextjsobj ); | |||
} | } | |||
massert( 10304 , "Remaining data too small for BSON object", t heEnd - nextjsobj > 3 ); | massert( 10304 , "Client Error: Remaining data too small for B SON object", theEnd - nextjsobj > 3 ); | |||
BSONObj js(nextjsobj); | BSONObj js(nextjsobj); | |||
massert( 10305 , "Invalid object size", js.objsize() > 3 ); | massert( 10305 , "Client Error: Invalid object size", js.objsi | |||
massert( 10306 , "Next object larger than available space", | ze() > 3 ); | |||
massert( 10306 , "Client Error: Next object larger than space | ||||
left in message", | ||||
js.objsize() < ( theEnd - data ) ); | js.objsize() < ( theEnd - data ) ); | |||
if ( objcheck && !js.valid() ) { | if ( objcheck && !js.valid() ) { | |||
massert( 10307 , "bad object in message", false); | massert( 10307 , "Client Error: bad object in message", fal se); | |||
} | } | |||
nextjsobj += js.objsize(); | nextjsobj += js.objsize(); | |||
if ( nextjsobj >= theEnd ) | if ( nextjsobj >= theEnd ) | |||
nextjsobj = 0; | nextjsobj = 0; | |||
return js; | return js; | |||
} | } | |||
const Message& msg() const { | const Message& msg() const { return m; } | |||
return m; | ||||
} | ||||
void markSet(){ | void markSet(){ | |||
mark = nextjsobj; | mark = nextjsobj; | |||
} | } | |||
void markReset(){ | void markReset(){ | |||
nextjsobj = mark; | nextjsobj = mark; | |||
} | } | |||
private: | private: | |||
const Message& m; | const Message& m; | |||
int reserved; | int* reserved; | |||
const char *data; | const char *data; | |||
const char *nextjsobj; | const char *nextjsobj; | |||
const char *theEnd; | const char *theEnd; | |||
const char * mark; | const char * mark; | |||
}; | }; | |||
/* a request to run a query, received from the database */ | /* a request to run a query, received from the database */ | |||
class QueryMessage { | class QueryMessage { | |||
public: | public: | |||
End of changes. 12 change blocks. | ||||
19 lines changed or deleted | 22 lines changed or added | |||
debug_util.h | debug_util.h | |||
---|---|---|---|---|
skipping to change at line 74 | skipping to change at line 74 | |||
#define ONCE MONGO_ONCE | #define ONCE MONGO_ONCE | |||
#if defined(_WIN32) | #if defined(_WIN32) | |||
inline int strcasecmp(const char* s1, const char* s2) {return _stricmp( s1, s2);} | inline int strcasecmp(const char* s1, const char* s2) {return _stricmp( s1, s2);} | |||
#endif | #endif | |||
// Sets SIGTRAP handler to launch GDB | // Sets SIGTRAP handler to launch GDB | |||
// Noop unless on *NIX and compiled with _DEBUG | // Noop unless on *NIX and compiled with _DEBUG | |||
void setupSIGTRAPforGDB(); | void setupSIGTRAPforGDB(); | |||
#if defined(_WIN32) | extern int tlogLevel; | |||
inline void breakpoint() {} //noop | ||||
#else // defined(_WIN32) | ||||
// code to raise a breakpoint in GDB | ||||
inline void breakpoint(){ | inline void breakpoint(){ | |||
if ( tlogLevel < 0 ) | ||||
return; | ||||
#ifndef _WIN32 | ||||
// code to raise a breakpoint in GDB | ||||
ONCE { | ONCE { | |||
//prevent SIGTRAP from crashing the program if default action i s specified and we are not in gdb | //prevent SIGTRAP from crashing the program if default action i s specified and we are not in gdb | |||
struct sigaction current; | struct sigaction current; | |||
sigaction(SIGTRAP, NULL, ¤t); | sigaction(SIGTRAP, NULL, ¤t); | |||
if (current.sa_handler == SIG_DFL){ | if (current.sa_handler == SIG_DFL){ | |||
signal(SIGTRAP, SIG_IGN); | signal(SIGTRAP, SIG_IGN); | |||
} | } | |||
} | } | |||
raise(SIGTRAP); | raise(SIGTRAP); | |||
#endif | ||||
} | } | |||
#endif // defined(_WIN32) | ||||
// conditional breakpoint | // conditional breakpoint | |||
inline void breakif(bool test){ | inline void breakif(bool test){ | |||
if (test) | if (test) | |||
breakpoint(); | breakpoint(); | |||
} | } | |||
} // namespace mongo | } // namespace mongo | |||
End of changes. 4 change blocks. | ||||
5 lines changed or deleted | 7 lines changed or added | |||
engine_spidermonkey.h | engine_spidermonkey.h | |||
---|---|---|---|---|
skipping to change at line 40 | skipping to change at line 40 | |||
#include "mozjs/jsregexp.h" | #include "mozjs/jsregexp.h" | |||
#warning if you are using an ubuntu version of spider monkey, we recommend installing spider monkey from source | #warning if you are using an ubuntu version of spider monkey, we recommend installing spider monkey from source | |||
#elif defined( OLDJS ) | #elif defined( OLDJS ) | |||
#ifdef WIN32 | #ifdef WIN32 | |||
#include "jstypes.h" | #include "jstypes.h" | |||
#undef JS_PUBLIC_API | #undef JS_PUBLIC_API | |||
#undef JS_PUBLIC_DATA | #undef JS_PUBLIC_DATA | |||
#define JS_PUBLIC_API(t) t | #define JS_PUBLIC_API(t) t __cdecl | |||
#define JS_PUBLIC_DATA(t) t | #define JS_PUBLIC_DATA(t) t | |||
#endif | #endif | |||
#include "jsapi.h" | #include "jsapi.h" | |||
#include "jsobj.h" | #include "jsobj.h" | |||
#include "jsdate.h" | #include "jsdate.h" | |||
#include "jsregexp.h" | #include "jsregexp.h" | |||
#else | #else | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
file.h | file.h | |||
---|---|---|---|---|
skipping to change at line 30 | skipping to change at line 30 | |||
#if !defined(_WIN32) | #if !defined(_WIN32) | |||
#include "errno.h" | #include "errno.h" | |||
#include <sys/mman.h> | #include <sys/mman.h> | |||
#include <sys/types.h> | #include <sys/types.h> | |||
#include <sys/stat.h> | #include <sys/stat.h> | |||
#include <fcntl.h> | #include <fcntl.h> | |||
#else | #else | |||
#include <windows.h> | #include <windows.h> | |||
#endif | #endif | |||
#include "text.h" | ||||
namespace mongo { | namespace mongo { | |||
#ifndef __sunos__ | #ifndef __sunos__ | |||
typedef uint64_t fileofs; | typedef uint64_t fileofs; | |||
#else | #else | |||
typedef boost::uint64_t fileofs; | typedef boost::uint64_t fileofs; | |||
#endif | #endif | |||
class FileInterface { | class FileInterface { | |||
public: | public: | |||
void open(const char *fn) {} | void open(const char *fn) {} | |||
void write(fileofs o, const char *data, unsigned len) {} | void write(fileofs o, const char *data, unsigned len) {} | |||
void read(fileofs o, char *data, unsigned len) {} | void read(fileofs o, char *data, unsigned len) {} | |||
bool bad() {return false;} | bool bad() {return false;} | |||
bool is_open() {return false;} | bool is_open() {return false;} | |||
fileofs len() { return 0; } | fileofs len() { return 0; } | |||
}; | }; | |||
#if defined(_WIN32) | #if defined(_WIN32) | |||
#include <io.h> | #include <io.h> | |||
std::wstring toWideString(const char *s); | ||||
class File : public FileInterface { | class File : public FileInterface { | |||
HANDLE fd; | HANDLE fd; | |||
bool _bad; | bool _bad; | |||
void err(BOOL b=false) { /* false = error happened */ | void err(BOOL b=false) { /* false = error happened */ | |||
if( !b && !_bad ) { | if( !b && !_bad ) { | |||
_bad = true; | _bad = true; | |||
log() << "File I/O error " << GetLastError() << '\n'; | log() << "File I/O error " << GetLastError() << '\n'; | |||
} | } | |||
} | } | |||
public: | public: | |||
File() { | File() { | |||
fd = INVALID_HANDLE_VALUE; | fd = INVALID_HANDLE_VALUE; | |||
_bad = true; | _bad = true; | |||
} | } | |||
~File() { | ~File() { | |||
if( is_open() ) CloseHandle(fd); | if( is_open() ) CloseHandle(fd); | |||
fd = INVALID_HANDLE_VALUE; | fd = INVALID_HANDLE_VALUE; | |||
} | } | |||
void open(const char *filename, bool readOnly=false ) { | void open(const char *filename, bool readOnly=false ) { | |||
std::wstring filenamew = toWideString(filename); | ||||
fd = CreateFile( | fd = CreateFile( | |||
filenamew.c_str(), ( readOnly ? 0 : GENERIC_WRITE ) | GENE | toNativeString(filename).c_str(), | |||
RIC_READ, FILE_SHARE_READ, | ( readOnly ? 0 : GENERIC_WRITE ) | GENERIC_READ, FILE_SHAR | |||
E_READ, | ||||
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | |||
if( !is_open() ) { | if( !is_open() ) { | |||
out() << "CreateFile failed " << filename << endl; | out() << "CreateFile failed " << filename << endl; | |||
} | } | |||
else | else | |||
_bad = false; | _bad = false; | |||
} | } | |||
void write(fileofs o, const char *data, unsigned len) { | void write(fileofs o, const char *data, unsigned len) { | |||
LARGE_INTEGER li; | LARGE_INTEGER li; | |||
li.QuadPart = o; | li.QuadPart = o; | |||
End of changes. 4 change blocks. | ||||
4 lines changed or deleted | 5 lines changed or added | |||
file_allocator.h | file_allocator.h | |||
---|---|---|---|---|
//file_allocator.h | // @file file_allocator.h | |||
/* Copyright 2009 10gen Inc. | /* Copyright 2009 10gen Inc. | |||
* | * | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | * You may obtain a copy of the License at | |||
* | * | |||
* http://www.apache.org/licenses/LICENSE-2.0 | * http://www.apache.org/licenses/LICENSE-2.0 | |||
* | * | |||
* Unless required by applicable law or agreed to in writing, software | * Unless required by applicable law or agreed to in writing, software | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
framework.h | framework.h | |||
---|---|---|---|---|
skipping to change at line 113 | skipping to change at line 113 | |||
template<class T> | template<class T> | |||
void add(){ | void add(){ | |||
_tests.push_back( new TestHolder0<T>() ); | _tests.push_back( new TestHolder0<T>() ); | |||
} | } | |||
template<class T , typename A > | template<class T , typename A > | |||
void add( const A& a ){ | void add( const A& a ){ | |||
_tests.push_back( new TestHolder1<T,A>(a) ); | _tests.push_back( new TestHolder1<T,A>(a) ); | |||
} | } | |||
Result * run(); | Result * run( const string& filter ); | |||
static int run( vector<string> suites ); | static int run( vector<string> suites , const string& filter ); | |||
static int run( int argc , char ** argv , string default_dbpath ); | static int run( int argc , char ** argv , string default_dbpath ); | |||
protected: | protected: | |||
virtual void setupTests() = 0; | virtual void setupTests() = 0; | |||
private: | private: | |||
string _name; | string _name; | |||
list<TestCase*> _tests; | list<TestCase*> _tests; | |||
bool _ran; | bool _ran; | |||
End of changes. 2 change blocks. | ||||
2 lines changed or deleted | 2 lines changed or added | |||
goodies.h | goodies.h | |||
---|---|---|---|---|
skipping to change at line 624 | skipping to change at line 624 | |||
bool operator==( const ThreadSafeString& other ) const { | bool operator==( const ThreadSafeString& other ) const { | |||
return strcmp( _buf , other._buf ) == 0; | return strcmp( _buf , other._buf ) == 0; | |||
} | } | |||
bool operator==( const char * str ) const { | bool operator==( const char * str ) const { | |||
return strcmp( _buf , str ) == 0; | return strcmp( _buf , str ) == 0; | |||
} | } | |||
bool operator!=( const char * str ) const { | bool operator!=( const char * str ) const { | |||
return strcmp( _buf , str ); | return strcmp( _buf , str ) != 0; | |||
} | } | |||
bool empty() const { | bool empty() const { | |||
return _buf[0] == 0; | return _buf[0] == 0; | |||
} | } | |||
private: | private: | |||
size_t _size; | size_t _size; | |||
char * _buf; | char * _buf; | |||
}; | }; | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
gridfs.h | gridfs.h | |||
---|---|---|---|---|
skipping to change at line 37 | skipping to change at line 37 | |||
class GridFS; | class GridFS; | |||
class GridFile; | class GridFile; | |||
class Chunk { | class Chunk { | |||
public: | public: | |||
Chunk( BSONObj data ); | Chunk( BSONObj data ); | |||
Chunk( BSONObj fileId , int chunkNumber , const char * data , int l en ); | Chunk( BSONObj fileId , int chunkNumber , const char * data , int l en ); | |||
int len(){ | int len(){ | |||
int len; | int len; | |||
const char * data = _data["data"].binData( len ); | const char * data = _data["data"].binDataClean( len ); | |||
int * foo = (int*)data; | int * foo = (int*)data; | |||
assert( len - 4 == foo[0] ); | assert( len == foo[0] ); | |||
return len - 4; | return len; | |||
} | } | |||
const char * data( int & len ){ | const char * data( int & len ){ | |||
const char * data = _data["data"].binData( len ); | const char * data = _data["data"].binDataClean( len ); | |||
int * foo = (int*)data; | int * foo = (int*)data; | |||
assert( len - 4 == foo[0] ); | assert( len == foo[0] ); | |||
len = len - 4; | len = len; | |||
return data + 4; | return data; | |||
} | } | |||
private: | private: | |||
BSONObj _data; | BSONObj _data; | |||
friend class GridFS; | friend class GridFS; | |||
}; | }; | |||
/** | /** | |||
this is the main entry point into the mongo grid fs | this is the main entry point into the mongo grid fs | |||
*/ | */ | |||
skipping to change at line 71 | skipping to change at line 71 | |||
public: | public: | |||
/** | /** | |||
* @param client - db connection | * @param client - db connection | |||
* @param dbName - root database name | * @param dbName - root database name | |||
* @param prefix - if you want your data somewhere besides <dbname> .fs | * @param prefix - if you want your data somewhere besides <dbname> .fs | |||
*/ | */ | |||
GridFS( DBClientBase& client , const string& dbName , const string& prefix="fs" ); | GridFS( DBClientBase& client , const string& dbName , const string& prefix="fs" ); | |||
~GridFS(); | ~GridFS(); | |||
/** | /** | |||
* @param | ||||
*/ | ||||
void setChunkSize(unsigned int size); | ||||
/** | ||||
* puts the file reference by fileName into the db | * puts the file reference by fileName into the db | |||
* @param fileName local filename relative to process | * @param fileName local filename relative to process | |||
* @param remoteName optional filename to use for file stored in Gr idFS | * @param remoteName optional filename to use for file stored in Gr idFS | |||
* (default is to use fileName parameter) | * (default is to use fileName parameter) | |||
* @param contentType optional MIME type for this object. | * @param contentType optional MIME type for this object. | |||
* (default is to omit) | * (default is to omit) | |||
* @return the file object | * @return the file object | |||
*/ | */ | |||
BSONObj storeFile( const string& fileName , const string& remoteNam e="" , const string& contentType=""); | BSONObj storeFile( const string& fileName , const string& remoteNam e="" , const string& contentType=""); | |||
skipping to change at line 125 | skipping to change at line 130 | |||
* convenience method to get all the files with a filter | * convenience method to get all the files with a filter | |||
*/ | */ | |||
auto_ptr<DBClientCursor> list( BSONObj query ); | auto_ptr<DBClientCursor> list( BSONObj query ); | |||
private: | private: | |||
DBClientBase& _client; | DBClientBase& _client; | |||
string _dbName; | string _dbName; | |||
string _prefix; | string _prefix; | |||
string _filesNS; | string _filesNS; | |||
string _chunksNS; | string _chunksNS; | |||
unsigned int _chunkSize; | ||||
// insert fileobject. All chunks must be in DB. | // insert fileobject. All chunks must be in DB. | |||
BSONObj insertFile(const string& name, const OID& id, unsigned leng th, const string& contentType); | BSONObj insertFile(const string& name, const OID& id, unsigned leng th, const string& contentType); | |||
friend class GridFile; | friend class GridFile; | |||
}; | }; | |||
/** | /** | |||
wrapper for a file stored in the Mongo database | wrapper for a file stored in the Mongo database | |||
*/ | */ | |||
End of changes. 7 change blocks. | ||||
7 lines changed or deleted | 13 lines changed or added | |||
instance.h | instance.h | |||
---|---|---|---|---|
skipping to change at line 96 | skipping to change at line 96 | |||
}; | }; | |||
extern DiagLog _diaglog; | extern DiagLog _diaglog; | |||
/* we defer response until we unlock. don't want a blocked socket to | /* we defer response until we unlock. don't want a blocked socket to | |||
keep things locked. | keep things locked. | |||
*/ | */ | |||
struct DbResponse { | struct DbResponse { | |||
Message *response; | Message *response; | |||
MSGID responseTo; | MSGID responseTo; | |||
DbResponse(Message *r, MSGID rt) : response(r), responseTo(rt) { | const char *exhaust; /* points to ns if exhaust mode. 0=normal mode | |||
} | */ | |||
DbResponse(Message *r, MSGID rt) : response(r), responseTo(rt), exh | ||||
aust(0) { } | ||||
DbResponse() { | DbResponse() { | |||
response = 0; | response = 0; | |||
exhaust = 0; | ||||
} | } | |||
~DbResponse() { | ~DbResponse() { delete response; } | |||
delete response; | ||||
} | ||||
}; | }; | |||
bool assembleResponse( Message &m, DbResponse &dbresponse, const SockAd dr &client = unknownAddress ); | bool assembleResponse( Message &m, DbResponse &dbresponse, const SockAd dr &client = unknownAddress ); | |||
void getDatabaseNames( vector< string > &names ); | void getDatabaseNames( vector< string > &names , const string& usePath = dbpath ); | |||
// --- local client --- | // --- local client --- | |||
class DBDirectClient : public DBClientBase { | class DBDirectClient : public DBClientBase { | |||
public: | public: | |||
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0, | virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0, | |||
const BSONObj *fieldsToRetur n = 0, int queryOptions = 0); | const BSONObj *fieldsToRetur n = 0, int queryOptions = 0); | |||
virtual bool isFailed() const { | virtual bool isFailed() const { | |||
skipping to change at line 133 | skipping to change at line 132 | |||
} | } | |||
virtual string getServerAddress() const{ | virtual string getServerAddress() const{ | |||
return "localhost"; // TODO: should this have the port? | return "localhost"; // TODO: should this have the port? | |||
} | } | |||
virtual bool call( Message &toSend, Message &response, bool assertO k=true ); | virtual bool call( Message &toSend, Message &response, bool assertO k=true ); | |||
virtual void say( Message &toSend ); | virtual void say( Message &toSend ); | |||
virtual void sayPiggyBack( Message &toSend ) { | virtual void sayPiggyBack( Message &toSend ) { | |||
// don't need to piggy back when connected locally | // don't need to piggy back when connected locally | |||
return say( toSend ); | return say( toSend ); | |||
} | } | |||
virtual void killCursor( long long cursorID ); | ||||
}; | }; | |||
extern int lockFile; | extern int lockFile; | |||
void acquirePathLock(); | void acquirePathLock(); | |||
} // namespace mongo | } // namespace mongo | |||
End of changes. 5 change blocks. | ||||
6 lines changed or deleted | 9 lines changed or added | |||
json.h | json.h | |||
---|---|---|---|---|
skipping to change at line 38 | skipping to change at line 38 | |||
<http://mongodb.onconfluence.com/display/DOCS/Mongo+Extended+JSON>, | <http://mongodb.onconfluence.com/display/DOCS/Mongo+Extended+JSON>, | |||
this function accepts certain unquoted field names and allows single q uotes | this function accepts certain unquoted field names and allows single q uotes | |||
to optionally be used when specifying field names and string values in stead | to optionally be used when specifying field names and string values in stead | |||
of double quotes. JSON unicode escape sequences (of the form \uXXXX) are | of double quotes. JSON unicode escape sequences (of the form \uXXXX) are | |||
converted to utf8. | converted to utf8. | |||
\throws MsgAssertionException if parsing fails. The message included with | \throws MsgAssertionException if parsing fails. The message included with | |||
this assertion includes a rough indication of where parsing failed. | this assertion includes a rough indication of where parsing failed. | |||
*/ | */ | |||
BSONObj fromjson(const string &str); | BSONObj fromjson(const string &str); | |||
BSONObj fromjson(const char *str); | /** len will be size of JSON object in text chars. */ | |||
BSONObj fromjson(const char *str, int* len=NULL); | ||||
} // namespace mongo | } // namespace mongo | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 2 lines changed or added | |||
lasterror.h | lasterror.h | |||
---|---|---|---|---|
skipping to change at line 91 | skipping to change at line 91 | |||
void setID( int id ); | void setID( int id ); | |||
int getID(); | int getID(); | |||
void remove( int id ); | void remove( int id ); | |||
void release(); | void release(); | |||
/** when db receives a message/request, call this */ | /** when db receives a message/request, call this */ | |||
void startRequest( Message& m , LastError * connectionOwned ); | void startRequest( Message& m , LastError * connectionOwned ); | |||
LastError * startRequest( Message& m , int clientId = 0 ); | LastError * startRequest( Message& m , int clientId = 0 ); | |||
void disconnect( int clientId ); | ||||
// used to disable lastError reporting while processing a killCurso rs message | // used to disable lastError reporting while processing a killCurso rs message | |||
// disable causes get() to return 0. | // disable causes get() to return 0. | |||
LastError *disableForCommand(); // only call once per command invoc ation! | LastError *disableForCommand(); // only call once per command invoc ation! | |||
private: | private: | |||
ThreadLocalValue<int> _id; | ThreadLocalValue<int> _id; | |||
boost::thread_specific_ptr<LastError> _tl; | boost::thread_specific_ptr<LastError> _tl; | |||
struct Status { | struct Status { | |||
time_t time; | time_t time; | |||
LastError *lerr; | LastError *lerr; | |||
}; | }; | |||
static mongo::mutex _idsmutex; | static mongo::mutex _idsmutex; | |||
map<int,Status> _ids; | map<int,Status> _ids; | |||
} lastError; | } lastError; | |||
inline void raiseError(int code , const char *msg) { | void raiseError(int code , const char *msg); | |||
LastError *le = lastError.get(); | ||||
if ( le == 0 ) { | ||||
/* might be intentional (non-user thread) */ | ||||
DEV log() << "warning dev: lastError==0 won't report:" << msg < | ||||
< endl; | ||||
} else if ( le->disabled ) { | ||||
log() << "lastError disabled, can't report: " << msg << endl; | ||||
} else { | ||||
le->raiseError(code, msg); | ||||
} | ||||
} | ||||
inline void recordUpdate( bool updatedExisting, int nChanged ) { | inline void recordUpdate( bool updatedExisting, int nChanged ) { | |||
LastError *le = lastError.get(); | LastError *le = lastError.get(); | |||
if ( le ) | if ( le ) | |||
le->recordUpdate( updatedExisting, nChanged ); | le->recordUpdate( updatedExisting, nChanged ); | |||
} | } | |||
inline void recordDelete( int nDeleted ) { | inline void recordDelete( int nDeleted ) { | |||
LastError *le = lastError.get(); | LastError *le = lastError.get(); | |||
if ( le ) | if ( le ) | |||
End of changes. 2 change blocks. | ||||
12 lines changed or deleted | 3 lines changed or added | |||
locks.h | locks.h | |||
---|---|---|---|---|
skipping to change at line 19 | skipping to change at line 19 | |||
* | * | |||
* This program is distributed in the hope that it will be useful, | * This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | * GNU Affero General Public License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Lice nse | * You should have received a copy of the GNU Affero General Public Lice nse | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
//#include "../pch.h" | ||||
#pragma once | #pragma once | |||
#include "mutex.h" | ||||
#if BOOST_VERSION >= 103500 | #if BOOST_VERSION >= 103500 | |||
#define BOOST_RWLOCK | #define BOOST_RWLOCK | |||
#else | #else | |||
#if defined(_WIN32) | #if defined(_WIN32) | |||
#error need boost >= 1.35 for windows | #error need boost >= 1.35 for windows | |||
#endif | #endif | |||
#include <pthread.h> | #include <pthread.h> | |||
skipping to change at line 46 | skipping to change at line 46 | |||
#include <boost/thread/shared_mutex.hpp> | #include <boost/thread/shared_mutex.hpp> | |||
#undef assert | #undef assert | |||
#define assert MONGO_assert | #define assert MONGO_assert | |||
#endif | #endif | |||
namespace mongo { | namespace mongo { | |||
#ifdef BOOST_RWLOCK | #ifdef BOOST_RWLOCK | |||
class RWLock { | class RWLock { | |||
boost::shared_mutex _m; | boost::shared_mutex _m; | |||
public: | public: | |||
#if defined(_DEBUG) | ||||
const char *_name; | ||||
RWLock(const char *name) : _name(name) { } | ||||
#else | ||||
RWLock(const char *) { } | ||||
#endif | ||||
void lock(){ | void lock(){ | |||
_m.lock(); | _m.lock(); | |||
#if defined(_DEBUG) | ||||
mutexDebugger.entering(_name); | ||||
#endif | ||||
} | } | |||
void unlock(){ | void unlock(){ | |||
#if defined(_DEBUG) | ||||
mutexDebugger.leaving(_name); | ||||
#endif | ||||
_m.unlock(); | _m.unlock(); | |||
} | } | |||
void lock_shared(){ | void lock_shared(){ | |||
_m.lock_shared(); | _m.lock_shared(); | |||
} | } | |||
void unlock_shared(){ | void unlock_shared(){ | |||
_m.unlock_shared(); | _m.unlock_shared(); | |||
} | } | |||
bool lock_shared_try( int millis ){ | bool lock_shared_try( int millis ){ | |||
boost::system_time until = get_system_time(); | boost::system_time until = get_system_time(); | |||
until += boost::posix_time::milliseconds(millis); | until += boost::posix_time::milliseconds(millis); | |||
return _m.timed_lock_shared( until ); | if( _m.timed_lock_shared( until ) ) { | |||
return true; | ||||
} | ||||
return false; | ||||
} | } | |||
bool lock_try( int millis ){ | bool lock_try( int millis ){ | |||
boost::system_time until = get_system_time(); | boost::system_time until = get_system_time(); | |||
until += boost::posix_time::milliseconds(millis); | until += boost::posix_time::milliseconds(millis); | |||
return _m.timed_lock( until ); | if( _m.timed_lock( until ) ) { | |||
#if defined(_DEBUG) | ||||
mutexDebugger.entering(_name); | ||||
#endif | ||||
return true; | ||||
} | ||||
return false; | ||||
} | } | |||
}; | }; | |||
#else | #else | |||
class RWLock { | class RWLock { | |||
pthread_rwlock_t _lock; | pthread_rwlock_t _lock; | |||
inline void check( int x ){ | inline void check( int x ){ | |||
if( x == 0 ) | if( x == 0 ) | |||
return; | return; | |||
log() << "pthread rwlock failed: " << x << endl; | log() << "pthread rwlock failed: " << x << endl; | |||
assert( x == 0 ); | assert( x == 0 ); | |||
} | } | |||
public: | public: | |||
RWLock(){ | #if defined(_DEBUG) | |||
const char *_name; | ||||
RWLock(const char *name) : _name(name) { | ||||
#else | ||||
RWLock(const char *) { | ||||
#endif | ||||
check( pthread_rwlock_init( &_lock , 0 ) ); | check( pthread_rwlock_init( &_lock , 0 ) ); | |||
} | } | |||
~RWLock(){ | ~RWLock(){ | |||
if ( ! __destroyingStatics ){ | if ( ! __destroyingStatics ){ | |||
check( pthread_rwlock_destroy( &_lock ) ); | check( pthread_rwlock_destroy( &_lock ) ); | |||
} | } | |||
} | } | |||
void lock(){ | void lock(){ | |||
check( pthread_rwlock_wrlock( &_lock ) ); | check( pthread_rwlock_wrlock( &_lock ) ); | |||
#if defined(_DEBUG) | ||||
mutexDebugger.entering(_name); | ||||
#endif | ||||
} | } | |||
void unlock(){ | void unlock(){ | |||
#if defined(_DEBUG) | ||||
mutexDebugger.leaving(_name); | ||||
#endif | ||||
check( pthread_rwlock_unlock( &_lock ) ); | check( pthread_rwlock_unlock( &_lock ) ); | |||
} | } | |||
void lock_shared(){ | void lock_shared(){ | |||
check( pthread_rwlock_rdlock( &_lock ) ); | check( pthread_rwlock_rdlock( &_lock ) ); | |||
} | } | |||
void unlock_shared(){ | void unlock_shared(){ | |||
check( pthread_rwlock_unlock( &_lock ) ); | check( pthread_rwlock_unlock( &_lock ) ); | |||
} | } | |||
bool lock_shared_try( int millis ){ | bool lock_shared_try( int millis ){ | |||
return _try( millis , false ); | return _try( millis , false ); | |||
} | } | |||
bool lock_try( int millis ){ | bool lock_try( int millis ){ | |||
return _try( millis , true ); | if( _try( millis , true ) ) { | |||
#if defined(_DEBUG) | ||||
mutexDebugger.entering(_name); | ||||
#endif | ||||
return true; | ||||
} | ||||
return false; | ||||
} | } | |||
bool _try( int millis , bool write ){ | bool _try( int millis , bool write ){ | |||
while ( true ) { | while ( true ) { | |||
int x = write ? | int x = write ? | |||
pthread_rwlock_trywrlock( &_lock ) : | pthread_rwlock_trywrlock( &_lock ) : | |||
pthread_rwlock_tryrdlock( &_lock ); | pthread_rwlock_tryrdlock( &_lock ); | |||
if ( x <= 0 ) | if ( x <= 0 ) { | |||
return true; | return true; | |||
} | ||||
if ( millis-- <= 0 ) | if ( millis-- <= 0 ) | |||
return false; | return false; | |||
if ( x == EBUSY ){ | if ( x == EBUSY ){ | |||
sleepmillis(1); | sleepmillis(1); | |||
continue; | continue; | |||
} | } | |||
check(x); | check(x); | |||
} | } | |||
End of changes. 14 change blocks. | ||||
8 lines changed or deleted | 46 lines changed or added | |||
log.h | log.h | |||
---|---|---|---|---|
// log.h | // @file log.h | |||
/* Copyright 2009 10gen Inc. | /* Copyright 2009 10gen Inc. | |||
* | * | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | * You may obtain a copy of the License at | |||
* | * | |||
* http://www.apache.org/licenses/LICENSE-2.0 | * http://www.apache.org/licenses/LICENSE-2.0 | |||
* | * | |||
* Unless required by applicable law or agreed to in writing, software | * Unless required by applicable law or agreed to in writing, software | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
matcher.h | matcher.h | |||
---|---|---|---|---|
skipping to change at line 136 | skipping to change at line 136 | |||
int matchesNe( | int matchesNe( | |||
const char *fieldName, | const char *fieldName, | |||
const BSONElement &toMatch, const BSONObj &obj, | const BSONElement &toMatch, const BSONObj &obj, | |||
const ElementMatcher&bm, MatchDetails * details ); | const ElementMatcher&bm, MatchDetails * details ); | |||
public: | public: | |||
static int opDirection(int op) { | static int opDirection(int op) { | |||
return op <= BSONObj::LTE ? -1 : 1; | return op <= BSONObj::LTE ? -1 : 1; | |||
} | } | |||
// Only specify constrainIndexKey if matches() will be called with | Matcher(const BSONObj &pattern, bool subMatcher = false); | |||
// index keys having empty string field names. | ||||
Matcher(const BSONObj &pattern, const BSONObj &constrainIndexKey = | ||||
BSONObj(), bool subMatcher = false); | ||||
~Matcher(); | ~Matcher(); | |||
bool matches(const BSONObj& j, MatchDetails * details = 0 ); | bool matches(const BSONObj& j, MatchDetails * details = 0 ); | |||
// until SERVER-109 $or is opaque to indexes | // fast rough check to see if we must load the real doc - we also | |||
bool keyMatch() const { return !all && !haveSize && !hasArray && !h | // compare field counts against covereed index matcher; for $or cla | |||
aveNeg && _orMatchers.size() == 0; } | uses | |||
// we just compare field counts | ||||
bool keyMatch() const { return !all && !haveSize && !hasArray && !h | ||||
aveNeg; } | ||||
bool atomic() const { return _atomic; } | bool atomic() const { return _atomic; } | |||
bool hasType( BSONObj::MatchType type ) const; | bool hasType( BSONObj::MatchType type ) const; | |||
string toString() const { | string toString() const { | |||
return jsobj.toString(); | return jsobj.toString(); | |||
} | } | |||
// void popOr() { | void addOrConstraint( const BSONObj &o ) { | |||
// massert( 13261, "no or to pop", !_orMatchers.empty() ); | _norMatchers.push_back( shared_ptr< Matcher >( new Matcher( o ) | |||
// _norMatchers.push_back( _orMatchers.front() ); | ) ); | |||
// _orMatchers.pop_front(); | } | |||
// } | ||||
bool sameCriteriaCount( const Matcher &other ) const; | ||||
private: | private: | |||
// Only specify constrainIndexKey if matches() will be called with | ||||
// index keys having empty string field names. | ||||
Matcher( const Matcher &other, const BSONObj &constrainIndexKey ); | ||||
void addBasic(const BSONElement &e, int c, bool isNot) { | void addBasic(const BSONElement &e, int c, bool isNot) { | |||
// TODO May want to selectively ignore these element types base d on op type. | // TODO May want to selectively ignore these element types base d on op type. | |||
if ( e.type() == MinKey || e.type() == MaxKey ) | if ( e.type() == MinKey || e.type() == MaxKey ) | |||
return; | return; | |||
basics.push_back( ElementMatcher( e , c, isNot ) ); | basics.push_back( ElementMatcher( e , c, isNot ) ); | |||
} | } | |||
void addRegex(const char *fieldName, const char *regex, const char *flags, bool isNot = false); | void addRegex(const char *fieldName, const char *regex, const char *flags, bool isNot = false); | |||
bool addOp( const BSONElement &e, const BSONElement &fe, bool isNot , const char *& regex, const char *&flags ); | bool addOp( const BSONElement &e, const BSONElement &fe, bool isNot , const char *& regex, const char *&flags ); | |||
skipping to change at line 208 | skipping to change at line 212 | |||
list< shared_ptr< Matcher > > _orMatchers; | list< shared_ptr< Matcher > > _orMatchers; | |||
list< shared_ptr< Matcher > > _norMatchers; | list< shared_ptr< Matcher > > _norMatchers; | |||
friend class CoveredIndexMatcher; | friend class CoveredIndexMatcher; | |||
}; | }; | |||
// If match succeeds on index key, then attempt to match full document. | // If match succeeds on index key, then attempt to match full document. | |||
class CoveredIndexMatcher : boost::noncopyable { | class CoveredIndexMatcher : boost::noncopyable { | |||
public: | public: | |||
CoveredIndexMatcher(const BSONObj &pattern, const BSONObj &indexKey Pattern , bool alwaysUseRecord=false ); | CoveredIndexMatcher(const BSONObj &pattern, const BSONObj &indexKey Pattern , bool alwaysUseRecord=false ); | |||
bool matches(const BSONObj &o){ return _docMatcher.matches( o ); } | bool matches(const BSONObj &o){ return _docMatcher->matches( o ); } | |||
bool matches(const BSONObj &key, const DiskLoc &recLoc , MatchDetai ls * details = 0 ); | bool matches(const BSONObj &key, const DiskLoc &recLoc , MatchDetai ls * details = 0 ); | |||
bool matchesCurrent( Cursor * cursor , MatchDetails * details = 0 ) ; | bool matchesCurrent( Cursor * cursor , MatchDetails * details = 0 ) ; | |||
bool needRecord(){ return _needRecord; } | bool needRecord(){ return _needRecord; } | |||
Matcher& docMatcher() { return _docMatcher; } | Matcher& docMatcher() { return *_docMatcher; } | |||
// once this is called, shouldn't use this matcher for matching any | ||||
more | ||||
void addOrConstraint( const BSONObj &o ) { | ||||
_docMatcher->addOrConstraint( o ); | ||||
} | ||||
CoveredIndexMatcher *nextClauseMatcher( const BSONObj &indexKeyPatt | ||||
ern, bool alwaysUseRecord=false ) { | ||||
return new CoveredIndexMatcher( _docMatcher, indexKeyPattern, a | ||||
lwaysUseRecord ); | ||||
} | ||||
private: | private: | |||
CoveredIndexMatcher(const shared_ptr< Matcher > &docMatcher, const | ||||
BSONObj &indexKeyPattern , bool alwaysUseRecord=false ); | ||||
void init( bool alwaysUseRecord ); | ||||
shared_ptr< Matcher > _docMatcher; | ||||
Matcher _keyMatcher; | Matcher _keyMatcher; | |||
Matcher _docMatcher; | ||||
bool _needRecord; | bool _needRecord; | |||
}; | }; | |||
} // namespace mongo | } // namespace mongo | |||
End of changes. 8 change blocks. | ||||
15 lines changed or deleted | 35 lines changed or added | |||
message.h | message.h | |||
---|---|---|---|---|
// message.h | // Message.h | |||
/* Copyright 2009 10gen Inc. | /* Copyright 2009 10gen Inc. | |||
* | * | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | * You may obtain a copy of the License at | |||
* | * | |||
* http://www.apache.org/licenses/LICENSE-2.0 | * http://www.apache.org/licenses/LICENSE-2.0 | |||
* | * | |||
* Unless required by applicable law or agreed to in writing, software | * Unless required by applicable law or agreed to in writing, software | |||
skipping to change at line 60 | skipping to change at line 60 | |||
}; | }; | |||
class AbstractMessagingPort { | class AbstractMessagingPort { | |||
public: | public: | |||
virtual ~AbstractMessagingPort() { } | virtual ~AbstractMessagingPort() { } | |||
virtual void reply(Message& received, Message& response, MSGID resp onseTo) = 0; // like the reply below, but doesn't rely on received.data sti ll being available | virtual void reply(Message& received, Message& response, MSGID resp onseTo) = 0; // like the reply below, but doesn't rely on received.data sti ll being available | |||
virtual void reply(Message& received, Message& response) = 0; | virtual void reply(Message& received, Message& response) = 0; | |||
virtual HostAndPort remote() const = 0; | virtual HostAndPort remote() const = 0; | |||
virtual unsigned remotePort() const = 0; | virtual unsigned remotePort() const = 0; | |||
virtual int getClientId(){ | ||||
int x = remotePort(); | ||||
x = x << 16; | ||||
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(int timeout = 0, int logLevel = 0 ); | MessagingPort(int timeout = 0, int logLevel = 0 ); | |||
skipping to change at line 110 | skipping to change at line 116 | |||
int sock; | int sock; | |||
PiggyBackData * piggyBackData; | PiggyBackData * piggyBackData; | |||
public: | public: | |||
SockAddr farEnd; | SockAddr farEnd; | |||
int _timeout; | int _timeout; | |||
int _logLevel; // passed to log() when logging errors | int _logLevel; // passed to log() when logging errors | |||
friend class PiggyBackData; | friend class PiggyBackData; | |||
}; | }; | |||
//#pragma pack() | ||||
#pragma pack(1) | ||||
enum Operations { | enum Operations { | |||
opReply = 1, /* reply. responseTo is set. */ | opReply = 1, /* reply. responseTo is set. */ | |||
dbMsg = 1000, /* generic msg command followed by a string */ | dbMsg = 1000, /* generic msg command followed by a string */ | |||
dbUpdate = 2001, /* update object */ | dbUpdate = 2001, /* update object */ | |||
dbInsert = 2002, | dbInsert = 2002, | |||
//dbGetByOID = 2003, | //dbGetByOID = 2003, | |||
dbQuery = 2004, | dbQuery = 2004, | |||
dbGetMore = 2005, | dbGetMore = 2005, | |||
dbDelete = 2006, | dbDelete = 2006, | |||
dbKillCursors = 2007 | dbKillCursors = 2007 | |||
skipping to change at line 145 | skipping to change at line 148 | |||
case dbGetMore: return "getmore"; | case dbGetMore: return "getmore"; | |||
case dbDelete: return "remove"; | case dbDelete: return "remove"; | |||
case dbKillCursors: return "killcursors"; | case dbKillCursors: return "killcursors"; | |||
default: | default: | |||
PRINT(op); | PRINT(op); | |||
assert(0); | assert(0); | |||
return ""; | return ""; | |||
} | } | |||
} | } | |||
#pragma pack(1) | ||||
/* see http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol | ||||
*/ | ||||
struct MSGHEADER { | ||||
int messageLength; // total message size, including this | ||||
int requestID; // identifier for this message | ||||
int responseTo; // requestID from the original request | ||||
// (used in reponses from db) | ||||
int opCode; | ||||
}; | ||||
struct OP_GETMORE : public MSGHEADER { | ||||
MSGHEADER header; // standard message header | ||||
int ZERO_or_flags; // 0 - reserved for future use | ||||
//cstring fullCollectionName; // "dbname.collectionname" | ||||
//int32 numberToReturn; // number of documents to return | ||||
//int64 cursorID; // cursorID from the OP_REPLY | ||||
}; | ||||
#pragma pack() | ||||
#pragma pack(1) | ||||
/* todo merge this with MSGHEADER (or inherit from it). */ | ||||
struct MsgData { | struct MsgData { | |||
int len; /* len of the msg, including this field */ | int len; /* len of the msg, including this field */ | |||
MSGID id; /* request/reply id's match... */ | MSGID id; /* request/reply id's match... */ | |||
MSGID responseTo; /* id of the message we are responding to */ | MSGID responseTo; /* id of the message we are responding to */ | |||
int _operation; | int _operation; | |||
int operation() const { | int operation() const { | |||
return _operation; | return _operation; | |||
} | } | |||
void setOperation(int o) { | void setOperation(int o) { | |||
_operation = o; | _operation = o; | |||
skipping to change at line 170 | skipping to change at line 194 | |||
} | } | |||
bool valid(){ | bool valid(){ | |||
if ( len <= 0 || len > ( 1024 * 1024 * 10 ) ) | if ( len <= 0 || len > ( 1024 * 1024 * 10 ) ) | |||
return false; | return false; | |||
if ( _operation < 0 || _operation > 100000 ) | if ( _operation < 0 || _operation > 100000 ) | |||
return false; | return false; | |||
return true; | return true; | |||
} | } | |||
long long getCursor(){ | ||||
assert( responseTo > 0 ); | ||||
assert( _operation == opReply ); | ||||
long long * l = (long long *)(_data + 4); | ||||
return l[0]; | ||||
} | ||||
int dataLen(); // len without header | int dataLen(); // len without header | |||
}; | }; | |||
const int MsgDataHeaderSize = sizeof(MsgData) - 4; | const int MsgDataHeaderSize = sizeof(MsgData) - 4; | |||
inline int MsgData::dataLen() { | inline int MsgData::dataLen() { | |||
return len - MsgDataHeaderSize; | return len - MsgDataHeaderSize; | |||
} | } | |||
#pragma pack() | #pragma pack() | |||
class Message { | class Message { | |||
public: | public: | |||
// we assume here that a vector with initial size 0 does no allocat ion (0 is the default, but wanted to make it explicit). | // we assume here that a vector with initial size 0 does no allocat ion (0 is the default, but wanted to make it explicit). | |||
Message() : _buf( 0 ), _data( 0 ), _freeIt( false ) {} | Message() : _buf( 0 ), _data( 0 ), _freeIt( false ) {} | |||
Message( void * data , bool freeIt ) : | Message( void * data , bool freeIt ) : | |||
_buf( 0 ), _data( 0 ), _freeIt( false ) { | _buf( 0 ), _data( 0 ), _freeIt( false ) { | |||
_setData( reinterpret_cast< MsgData* >( data ), freeIt ); | _setData( reinterpret_cast< MsgData* >( data ), freeIt ); | |||
}; | }; | |||
skipping to change at line 209 | skipping to change at line 239 | |||
} | } | |||
int operation() const { return header()->operation(); } | int operation() const { return header()->operation(); } | |||
MsgData *singleData() const { | MsgData *singleData() const { | |||
massert( 13273, "single data buffer expected", _buf ); | massert( 13273, "single data buffer expected", _buf ); | |||
return header(); | return header(); | |||
} | } | |||
bool empty() const { return !_buf && _data.empty(); } | bool empty() const { return !_buf && _data.empty(); } | |||
int size() const{ | ||||
int res = 0; | ||||
if ( _buf ){ | ||||
res = _buf->len; | ||||
} else { | ||||
for (MsgVec::const_iterator it = _data.begin(); it != _data | ||||
.end(); ++it){ | ||||
res += it->second; | ||||
} | ||||
} | ||||
return res; | ||||
} | ||||
// concat multiple buffers - noop if <2 buffers already, otherwise can be expensive copy | // concat multiple buffers - noop if <2 buffers already, otherwise can be expensive copy | |||
// can get rid of this if we make response handling smarter | // can get rid of this if we make response handling smarter | |||
void concat() { | void concat() { | |||
if ( _buf || empty() ) { | if ( _buf || empty() ) { | |||
return; | return; | |||
} | } | |||
assert( _freeIt ); | assert( _freeIt ); | |||
int totalSize = 0; | int totalSize = 0; | |||
for( vector< pair< char *, int > >::const_iterator i = _data.be gin(); i != _data.end(); ++i ) { | for( vector< pair< char *, int > >::const_iterator i = _data.be gin(); i != _data.end(); ++i ) { | |||
skipping to change at line 321 | skipping to change at line 363 | |||
} | } | |||
private: | private: | |||
void _setData( MsgData *d, bool freeIt ) { | void _setData( MsgData *d, bool freeIt ) { | |||
_freeIt = freeIt; | _freeIt = freeIt; | |||
_buf = d; | _buf = d; | |||
} | } | |||
// if just one buffer, keep it in _buf, otherwise keep a sequence o f buffers in _data | // if just one buffer, keep it in _buf, otherwise keep a sequence o f buffers in _data | |||
MsgData * _buf; | MsgData * _buf; | |||
// byte buffer(s) - the first must contain at least a full MsgData unless using _buf for storage instead | // byte buffer(s) - the first must contain at least a full MsgData unless using _buf for storage instead | |||
vector< pair< char*, int > > _data; | typedef vector< pair< char*, int > > MsgVec; | |||
MsgVec _data; | ||||
bool _freeIt; | bool _freeIt; | |||
}; | }; | |||
class SocketException : public DBException { | class SocketException : public DBException { | |||
public: | public: | |||
virtual const char* what() const throw() { return "socket exception "; } | virtual const char* what() const throw() { return "socket exception "; } | |||
virtual int getCode() const { return 9001; } | virtual int getCode() const { return 9001; } | |||
}; | }; | |||
MSGID nextMessageId(); | MSGID nextMessageId(); | |||
End of changes. 8 change blocks. | ||||
6 lines changed or deleted | 50 lines changed or added | |||
message_server.h | message_server.h | |||
---|---|---|---|---|
skipping to change at line 33 | skipping to change at line 33 | |||
#pragma once | #pragma once | |||
#include "../pch.h" | #include "../pch.h" | |||
namespace mongo { | namespace mongo { | |||
class MessageHandler { | class MessageHandler { | |||
public: | public: | |||
virtual ~MessageHandler(){} | virtual ~MessageHandler(){} | |||
virtual void process( Message& m , AbstractMessagingPort* p ) = 0; | virtual void process( Message& m , AbstractMessagingPort* p ) = 0; | |||
virtual void disconnected( AbstractMessagingPort* p ) = 0; | ||||
}; | }; | |||
class MessageServer { | class MessageServer { | |||
public: | public: | |||
MessageServer( int port , MessageHandler * handler ) : _port( port | struct Options { | |||
) , _handler( handler ){} | int port; // port to bind to | |||
virtual ~MessageServer(){} | string ipList; // addresses to bind to | |||
virtual void run() = 0; | ||||
protected: | Options() : port(0), ipList(""){} | |||
}; | ||||
int _port; | virtual ~MessageServer(){} | |||
MessageHandler* _handler; | virtual void run() = 0; | |||
}; | }; | |||
MessageServer * createServer( int port , MessageHandler * handler ); | // TODO use a factory here to decide between port and asio variations | |||
MessageServer * createServer( const MessageServer::Options& opts , Mess | ||||
ageHandler * handler ); | ||||
} | } | |||
End of changes. 5 change blocks. | ||||
9 lines changed or deleted | 11 lines changed or added | |||
mutex.h | mutex.h | |||
---|---|---|---|---|
skipping to change at line 28 | skipping to change at line 28 | |||
#pragma once | #pragma once | |||
#include <map> | #include <map> | |||
#include <set> | #include <set> | |||
namespace mongo { | namespace mongo { | |||
extern bool __destroyingStatics; | extern bool __destroyingStatics; | |||
class mutex; | class mutex; | |||
// only used on _DEBUG builds: | ||||
class MutexDebugger { | class MutexDebugger { | |||
typedef const char * mid; // mid = mutex ID | typedef const char * mid; // mid = mutex ID | |||
boost::thread_specific_ptr< set<mid> > us; | typedef map<mid,int> Preceeding; | |||
map< mid, int > maxNest; | ||||
boost::thread_specific_ptr< Preceeding > us; | ||||
map< mid, set<mid> > followers; | map< mid, set<mid> > followers; | |||
boost::mutex &x; | boost::mutex &x; | |||
unsigned magic; | unsigned magic; | |||
public: | public: | |||
// set these to create an assert that | ||||
// b must never be locked before a | ||||
// so | ||||
// a.lock(); b.lock(); is fine | ||||
// b.lock(); alone is fine too | ||||
// only checked on _DEBUG builds. | ||||
string a,b; | ||||
void programEnding(); | void programEnding(); | |||
MutexDebugger() : x( *(new boost::mutex()) ), magic(0x12345678) { } | MutexDebugger(); | |||
void entering(mid m) { | void entering(mid m) { | |||
if( magic != 0x12345678 ) return; | if( magic != 0x12345678 ) return; | |||
set<mid> *preceeding = us.get(); | ||||
if( preceeding == 0 ) | Preceeding *_preceeding = us.get(); | |||
us.reset( preceeding = new set<mid>() ); | if( _preceeding == 0 ) | |||
us.reset( _preceeding = new Preceeding() ); | ||||
Preceeding &preceeding = *_preceeding; | ||||
if( a == m ) { | ||||
if( preceeding[b.c_str()] ) { | ||||
cout << "mutex problem " << b << " was locked before " | ||||
<< a << endl; | ||||
assert(false); | ||||
} | ||||
} | ||||
preceeding[m]++; | ||||
if( preceeding[m] > 1 ) { | ||||
// recursive re-locking. | ||||
if( preceeding[m] > maxNest[m] ) | ||||
maxNest[m] = preceeding[m]; | ||||
return; | ||||
} | ||||
bool failed = false; | ||||
string err; | ||||
{ | { | |||
boost::mutex::scoped_lock lk(x); | boost::mutex::scoped_lock lk(x); | |||
followers[m]; | followers[m]; | |||
for( set<mid>::iterator i = preceeding->begin(); i != prece | for( Preceeding::iterator i = preceeding.begin(); i != prec | |||
eding->end(); i++ ) { | eeding.end(); i++ ) { | |||
followers[*i].insert(m); | if( m != i->first && i->second > 0 ) { | |||
assert( followers[m].count(*i) == 0 ); | followers[i->first].insert(m); | |||
if( followers[m].count(i->first) != 0 ){ | ||||
failed = true; | ||||
stringstream ss; | ||||
mid bad = i->first; | ||||
ss << "mutex problem" << | ||||
"\n when locking " << m << | ||||
"\n " << bad << " was already locked and s | ||||
hould not be." | ||||
"\n set a and b above to debug.\n"; | ||||
stringstream q; | ||||
for( Preceeding::iterator i = preceeding.begin( | ||||
); i != preceeding.end(); i++ ) { | ||||
if( i->first != m && i->first != bad && i-> | ||||
second > 0 ) | ||||
q << " " << i->first << '\n'; | ||||
} | ||||
string also = q.str(); | ||||
if( !also.empty() ) | ||||
ss << "also locked before " << m << " in th | ||||
is thread (no particular order):\n" << also; | ||||
err = ss.str(); | ||||
break; | ||||
} | ||||
} | ||||
} | } | |||
} | } | |||
preceeding->insert(m); | if( failed ) { | |||
cout << err << endl; | ||||
assert( 0 ); | ||||
} | ||||
} | } | |||
void leaving(mid m) { | void leaving(mid m) { | |||
if( magic != 0x12345678 ) return; | if( magic != 0x12345678 ) return; | |||
us.get()->erase(m); | Preceeding& preceeding = *us.get(); | |||
preceeding[m]--; | ||||
if( preceeding[m] < 0 ) { | ||||
cout << "ERROR: lock count for " << m << " is " << preceedi | ||||
ng[m] << endl; | ||||
assert( preceeding[m] >= 0 ); | ||||
} | ||||
} | } | |||
}; | }; | |||
extern MutexDebugger mutexDebugger; | extern MutexDebugger mutexDebugger; | |||
// If you create a local static instance of this class, that instance w ill be destroyed | // If you create a local static instance of this class, that instance w ill be destroyed | |||
// before all global static objects are destroyed, so __destroyingStati cs will be set | // before all global static objects are destroyed, so __destroyingStati cs will be set | |||
// to true before the global static variables are destroyed. | // to true before the global static variables are destroyed. | |||
class StaticObserver : boost::noncopyable { | class StaticObserver : boost::noncopyable { | |||
public: | public: | |||
~StaticObserver() { __destroyingStatics = true; } | ~StaticObserver() { __destroyingStatics = true; } | |||
End of changes. 8 change blocks. | ||||
11 lines changed or deleted | 76 lines changed or added | |||
namespace.h | namespace.h | |||
---|---|---|---|---|
skipping to change at line 643 | skipping to change at line 643 | |||
} | } | |||
bool allocated() const { | bool allocated() const { | |||
return ht != 0; | return ht != 0; | |||
} | } | |||
void getNamespaces( list<string>& tofill , bool onlyCollections = t rue ) const; | void getNamespaces( list<string>& tofill , bool onlyCollections = t rue ) const; | |||
NamespaceDetails::Extra* newExtra(const char *ns, int n, NamespaceD etails *d); | NamespaceDetails::Extra* newExtra(const char *ns, int n, NamespaceD etails *d); | |||
private: | ||||
boost::filesystem::path path() const; | boost::filesystem::path path() const; | |||
private: | ||||
void maybeMkdir() const; | void maybeMkdir() const; | |||
MMF f; | MMF f; | |||
HashTable<Namespace,NamespaceDetails,MMF::Pointer> *ht; | HashTable<Namespace,NamespaceDetails,MMF::Pointer> *ht; | |||
string dir_; | string dir_; | |||
string database_; | string database_; | |||
}; | }; | |||
extern string dbpath; // --dbpath parm | extern string dbpath; // --dbpath parm | |||
extern bool directoryperdb; | extern bool directoryperdb; | |||
End of changes. 2 change blocks. | ||||
1 lines changed or deleted | 2 lines changed or added | |||
ntservice.h | ntservice.h | |||
---|---|---|---|---|
skipping to change at line 32 | skipping to change at line 32 | |||
namespace mongo { | namespace mongo { | |||
typedef bool ( *ServiceCallback )( void ); | typedef bool ( *ServiceCallback )( void ); | |||
class ServiceController { | class ServiceController { | |||
public: | public: | |||
ServiceController(); | ServiceController(); | |||
virtual ~ServiceController() {} | virtual ~ServiceController() {} | |||
static bool installService( const std::wstring& serviceName, const std::wstring& displayName, const std::wstring& serviceDesc, int argc, char* argv[] ); | static bool installService( const std::wstring& serviceName, const std::wstring& displayName, const std::wstring& serviceDesc, const std::wstr ing& serviceUser, const std::wstring& servicePassword, int argc, char* argv [] ); | |||
static bool removeService( const std::wstring& serviceName ); | static bool removeService( const std::wstring& serviceName ); | |||
static bool startService( const std::wstring& serviceName, ServiceC allback startService ); | static bool startService( const std::wstring& serviceName, ServiceC allback startService ); | |||
static bool reportStatus( DWORD reportState, DWORD waitHint = 0 ); | static bool reportStatus( DWORD reportState, DWORD waitHint = 0 ); | |||
static void WINAPI initService( DWORD argc, LPTSTR *argv ); | static void WINAPI initService( DWORD argc, LPTSTR *argv ); | |||
static void WINAPI serviceCtrl( DWORD ctrlCode ); | static void WINAPI serviceCtrl( DWORD ctrlCode ); | |||
protected: | protected: | |||
static std::wstring _serviceName; | static std::wstring _serviceName; | |||
static SERVICE_STATUS_HANDLE _statusHandle; | static SERVICE_STATUS_HANDLE _statusHandle; | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
oid.h | oid.h | |||
---|---|---|---|---|
skipping to change at line 102 | skipping to change at line 102 | |||
/** Set to the hex string value specified. */ | /** Set to the hex string value specified. */ | |||
void init( string s ); | void init( string s ); | |||
/** Set to the min/max OID that could be generated at given timesta mp. */ | /** Set to the min/max OID that could be generated at given timesta mp. */ | |||
void init( Date_t date, bool max=false ); | void init( Date_t date, bool max=false ); | |||
time_t asTimeT(); | time_t asTimeT(); | |||
Date_t asDateT() { return asTimeT() * (long long)1000; } | Date_t asDateT() { return asTimeT() * (long long)1000; } | |||
bool isSet() const { return a || b; } | ||||
}; | }; | |||
#pragma pack() | #pragma pack() | |||
ostream& operator<<( ostream &s, const OID &o ); | ostream& operator<<( ostream &s, const OID &o ); | |||
/** Formatting mode for generating JSON from BSON. | /** Formatting mode for generating JSON from BSON. | |||
See <http://mongodb.onconfluence.com/display/DOCS/Mongo+Extended+JS ON> | See <http://mongodb.onconfluence.com/display/DOCS/Mongo+Extended+JS ON> | |||
for details. | for details. | |||
*/ | */ | |||
enum JsonStringFormat { | enum JsonStringFormat { | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 1 lines changed or added | |||
oplog.h | oplog.h | |||
---|---|---|---|---|
skipping to change at line 31 | skipping to change at line 31 | |||
local.oplog.$main is the default | local.oplog.$main is the default | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "pdfile.h" | #include "pdfile.h" | |||
#include "db.h" | #include "db.h" | |||
#include "dbhelpers.h" | #include "dbhelpers.h" | |||
#include "query.h" | #include "query.h" | |||
#include "queryoptimizer.h" | #include "queryoptimizer.h" | |||
#include "../client/dbclient.h" | #include "../client/dbclient.h" | |||
#include "../util/optime.h" | #include "../util/optime.h" | |||
namespace mongo { | namespace mongo { | |||
void createOplog(); | void createOplog(); | |||
/* Write operation to the log (local.oplog.$main) | /** Write operation to the log (local.oplog.$main) | |||
"i" insert | ||||
"u" update | @param opstr | |||
"d" delete | "i" insert | |||
"c" db cmd | "u" update | |||
"db" declares presence of a database (ns is set to the db name + '.' | "d" delete | |||
) | "c" db cmd | |||
"n" no-op | ||||
"db" declares presence of a database (ns is set to the db name + '. | ||||
') | ||||
See _logOp() in oplog.cpp for more details. | ||||
*/ | */ | |||
void logOp(const char *opstr, const char *ns, const BSONObj& obj, BSONO bj *patt = 0, bool *b = 0); | void logOp(const char *opstr, const char *ns, const BSONObj& obj, BSONO bj *patt = 0, bool *b = 0); | |||
void logKeepalive(); | void logKeepalive(); | |||
/** puts obj in the oplog as a comment (a no-op). Just for diags. | ||||
convention is | ||||
{ msg : "text", ... } | ||||
*/ | ||||
void logOpComment(const BSONObj& obj); | ||||
void oplogCheckCloseDatabase( Database * db ); | void oplogCheckCloseDatabase( Database * db ); | |||
extern int __findingStartInitialTimeout; // configurable for testing | extern int __findingStartInitialTimeout; // configurable for testing | |||
class FindingStartCursor { | class FindingStartCursor { | |||
public: | public: | |||
FindingStartCursor( const QueryPlan & qp ) : | FindingStartCursor( const QueryPlan & qp ) : | |||
_qp( qp ), | _qp( qp ), | |||
_findingStart( true ), | _findingStart( true ), | |||
_findingStartMode(), | _findingStartMode(), | |||
skipping to change at line 189 | skipping to change at line 198 | |||
_findingStartCursor = ClientCursor::find( id, false ); | _findingStartCursor = ClientCursor::find( id, false ); | |||
} | } | |||
} | } | |||
void init() { | void init() { | |||
// Use a ClientCursor here so we can release db mutex while sca nning | // Use a ClientCursor here so we can release db mutex while sca nning | |||
// oplog (can take quite a while with large oplogs). | // oplog (can take quite a while with large oplogs). | |||
shared_ptr<Cursor> c = _qp.newReverseCursor(); | shared_ptr<Cursor> c = _qp.newReverseCursor(); | |||
_findingStartCursor = new ClientCursor(QueryOption_NoCursorTime out, c, _qp.ns()); | _findingStartCursor = new ClientCursor(QueryOption_NoCursorTime out, c, _qp.ns()); | |||
_findingStartTimer.reset(); | _findingStartTimer.reset(); | |||
_findingStartMode = Initial; | _findingStartMode = Initial; | |||
BSONElement tsElt = _qp.query()[ "ts" ]; | BSONElement tsElt = _qp.originalQuery()[ "ts" ]; | |||
massert( 13044, "no ts field in query", !tsElt.eoo() ); | massert( 13044, "no ts field in query", !tsElt.eoo() ); | |||
BSONObjBuilder b; | BSONObjBuilder b; | |||
b.append( tsElt ); | b.append( tsElt ); | |||
BSONObj tsQuery = b.obj(); | BSONObj tsQuery = b.obj(); | |||
_matcher.reset(new CoveredIndexMatcher(tsQuery, _qp.indexKey()) ); | _matcher.reset(new CoveredIndexMatcher(tsQuery, _qp.indexKey()) ); | |||
} | } | |||
}; | }; | |||
} | } | |||
End of changes. 5 change blocks. | ||||
10 lines changed or deleted | 19 lines changed or added | |||
optime.h | optime.h | |||
---|---|---|---|---|
skipping to change at line 23 | skipping to change at line 23 | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. | |||
* See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | |||
* limitations under the License. | * limitations under the License. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../db/concurrency.h" | #include "../db/concurrency.h" | |||
namespace mongo { | namespace mongo { | |||
void exitCleanly( int code ); | void exitCleanly( ExitCode code ); | |||
struct ClockSkewException : public DBException { | struct ClockSkewException : public DBException { | |||
virtual const char* what() const throw() { return "clock skew excep tion"; } | virtual const char* what() const throw() { return "clock skew excep tion"; } | |||
virtual int getCode() const { return 20001; } | virtual int getCode() const { return 20001; } | |||
}; | }; | |||
/* replsets use RSOpTime. | ||||
M/S uses OpTime. | ||||
But this is useable from both. | ||||
*/ | ||||
typedef unsigned long long ReplTime; | ||||
/* Operation sequence #. A combination of current second plus an ordin al value. | /* Operation sequence #. A combination of current second plus an ordin al value. | |||
*/ | */ | |||
#pragma pack(4) | #pragma pack(4) | |||
class OpTime { | class OpTime { | |||
unsigned i; | unsigned i; | |||
unsigned secs; | unsigned secs; | |||
static OpTime last; | static OpTime last; | |||
public: | public: | |||
static void setLast(const Date_t &date) { | static void setLast(const Date_t &date) { | |||
last = OpTime(date); | last = OpTime(date); | |||
} | } | |||
unsigned getSecs() const { | unsigned getSecs() const { | |||
return secs; | return secs; | |||
} | } | |||
OpTime(Date_t date) { | OpTime(Date_t date) { | |||
reinterpret_cast<unsigned long long&>(*this) = date.millis; | reinterpret_cast<unsigned long long&>(*this) = date.millis; | |||
} | } | |||
OpTime(unsigned long long date) { | OpTime(ReplTime x) { | |||
reinterpret_cast<unsigned long long&>(*this) = date; | reinterpret_cast<unsigned long long&>(*this) = x; | |||
} | } | |||
OpTime(unsigned a, unsigned b) { | OpTime(unsigned a, unsigned b) { | |||
secs = a; | secs = a; | |||
i = b; | i = b; | |||
} | } | |||
OpTime() { | OpTime() { | |||
secs = 0; | secs = 0; | |||
i = 0; | i = 0; | |||
} | } | |||
static OpTime now() { | static OpTime now() { | |||
End of changes. 3 change blocks. | ||||
3 lines changed or deleted | 9 lines changed or added | |||
password.h | password.h | |||
---|---|---|---|---|
/* | ||||
* Copyright 2010 10gen Inc. | ||||
* | ||||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||||
* you may not use this file except in compliance with the License. | ||||
* You may obtain a copy of the License at | ||||
* | ||||
* http://www.apache.org/licenses/LICENSE-2.0 | ||||
* | ||||
* Unless required by applicable law or agreed to in writing, software | ||||
* distributed under the License is distributed on an "AS IS" BASIS, | ||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli | ||||
ed. | ||||
* See the License for the specific language governing permissions and | ||||
* limitations under the License. | ||||
*/ | ||||
#pragma once | #pragma once | |||
#include <boost/program_options.hpp> | #include <boost/program_options.hpp> | |||
#include <string> | #include <string> | |||
namespace mongo { | namespace mongo { | |||
struct PasswordValue : public boost::program_options::typed_value<std:: string> { | struct PasswordValue : public boost::program_options::typed_value<std:: string> { | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 16 lines changed or added | |||
pch.h | pch.h | |||
---|---|---|---|---|
skipping to change at line 23 | skipping to change at line 23 | |||
* | * | |||
* Unless required by applicable law or agreed to in writing, software | * Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | * distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. | |||
* See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | |||
* limitations under the License. | * limitations under the License. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#if defined(MONGO_EXPOSE_MACROS) | ||||
# define JS_C_STRINGS_ARE_UTF8 | ||||
# undef SUPPORT_UCP | ||||
# define SUPPORT_UCP | ||||
# undef SUPPORT_UTF8 | ||||
# define SUPPORT_UTF8 | ||||
# undef _CRT_SECURE_NO_WARNINGS | ||||
# define _CRT_SECURE_NO_WARNINGS | ||||
#endif | ||||
#if defined(WIN32) | ||||
// so you don't have to define this yourself as the code seems to use it... | ||||
#undef _WIN32 | ||||
#define _WIN32 | ||||
#endif | ||||
#if defined(_WIN32) | #if defined(_WIN32) | |||
# define NOMINMAX | # define NOMINMAX | |||
# include <winsock2.h> //this must be included before the first windows.h | # include <winsock2.h> //this must be included before the first windows.h i | |||
include | nclude | |||
# include <ws2tcpip.h> | # include <ws2tcpip.h> | |||
# include <windows.h> | # include <windows.h> | |||
#endif | #endif | |||
#include <ctime> | #include <ctime> | |||
#include <sstream> | #include <sstream> | |||
#include <string> | #include <string> | |||
#include <memory> | #include <memory> | |||
#include <string> | #include <string> | |||
#include <iostream> | #include <iostream> | |||
#include <fstream> | #include <fstream> | |||
#include <map> | #include <map> | |||
skipping to change at line 56 | skipping to change at line 72 | |||
#include "string.h" | #include "string.h" | |||
#include "limits.h" | #include "limits.h" | |||
#include <boost/any.hpp> | #include <boost/any.hpp> | |||
#include <boost/archive/iterators/transform_width.hpp> | #include <boost/archive/iterators/transform_width.hpp> | |||
#include <boost/filesystem/convenience.hpp> | #include <boost/filesystem/convenience.hpp> | |||
#include <boost/filesystem/operations.hpp> | #include <boost/filesystem/operations.hpp> | |||
#include <boost/program_options.hpp> | #include <boost/program_options.hpp> | |||
#include <boost/shared_ptr.hpp> | #include <boost/shared_ptr.hpp> | |||
#include <boost/smart_ptr.hpp> | #include <boost/smart_ptr.hpp> | |||
#include <boost/function.hpp> | ||||
#include "boost/bind.hpp" | #include "boost/bind.hpp" | |||
#include "boost/function.hpp" | #include "boost/function.hpp" | |||
#include <boost/thread/tss.hpp> | #include <boost/thread/tss.hpp> | |||
#include "boost/detail/endian.hpp" | #include "boost/detail/endian.hpp" | |||
#define BOOST_SPIRIT_THREADSAFE | #define BOOST_SPIRIT_THREADSAFE | |||
#include <boost/version.hpp> | #include <boost/version.hpp> | |||
#include <boost/tuple/tuple.hpp> | #include <boost/tuple/tuple.hpp> | |||
#include <boost/thread/thread.hpp> | #include <boost/thread/thread.hpp> | |||
#include <boost/thread/condition.hpp> | #include <boost/thread/condition.hpp> | |||
#include <boost/thread/recursive_mutex.hpp> | #include <boost/thread/recursive_mutex.hpp> | |||
#include <boost/thread/xtime.hpp> | #include <boost/thread/xtime.hpp> | |||
#undef assert | #undef assert | |||
#define assert MONGO_assert | #define assert MONGO_assert | |||
namespace mongo { | namespace mongo { | |||
skipping to change at line 85 | skipping to change at line 101 | |||
#if defined(_DEBUG) | #if defined(_DEBUG) | |||
const bool debug=true; | const bool debug=true; | |||
#else | #else | |||
const bool debug=false; | const bool debug=false; | |||
#endif | #endif | |||
// pdfile versions | // pdfile versions | |||
const int VERSION = 4; | const int VERSION = 4; | |||
const int VERSION_MINOR = 5; | const int VERSION_MINOR = 5; | |||
// mongo version | ||||
extern const char versionString[]; | ||||
enum ExitCode { | enum ExitCode { | |||
EXIT_CLEAN = 0 , | EXIT_CLEAN = 0 , | |||
EXIT_BADOPTIONS = 2 , | EXIT_BADOPTIONS = 2 , | |||
EXIT_REPLICATION_ERROR = 3 , | EXIT_REPLICATION_ERROR = 3 , | |||
EXIT_NEED_UPGRADE = 4 , | EXIT_NEED_UPGRADE = 4 , | |||
EXIT_KILL = 12 , | EXIT_KILL = 12 , | |||
EXIT_ABRUBT = 14 , | EXIT_ABRUBT = 14 , | |||
EXIT_NTSERVICE_ERROR = 20 , | EXIT_NTSERVICE_ERROR = 20 , | |||
EXIT_JAVA = 21 , | EXIT_JAVA = 21 , | |||
EXIT_OOM_MALLOC = 42 , | EXIT_OOM_MALLOC = 42 , | |||
EXIT_OOM_REALLOC = 43 , | EXIT_OOM_REALLOC = 43 , | |||
EXIT_FS = 45 , | EXIT_FS = 45 , | |||
EXIT_CLOCK_SKEW = 47 , | EXIT_CLOCK_SKEW = 47 , | |||
EXIT_NET_ERROR = 48 , | ||||
EXIT_POSSIBLE_CORRUPTION = 60 , // this means we detected a possibl e corruption situation, like a buf overflow | EXIT_POSSIBLE_CORRUPTION = 60 , // this means we detected a possibl e corruption situation, like a buf overflow | |||
EXIT_UNCAUGHT = 100 , // top level exception that wasn't caught | EXIT_UNCAUGHT = 100 , // top level exception that wasn't caught | |||
EXIT_TEST = 101 , | EXIT_TEST = 101 , | |||
}; | }; | |||
void dbexit( ExitCode returnCode, const char *whyMsg = ""); | void dbexit( ExitCode returnCode, const char *whyMsg = ""); | |||
/** | /** | |||
this is here so you can't just type exit() to quit the program | this is here so you can't just type exit() to quit the program | |||
you should either use dbexit to shutdown cleanly, or ::exit to tell the system to quiy | you should either use dbexit to shutdown cleanly, or ::exit to tell the system to quit | |||
if you use this, you'll get a link error since mongo::exit isn't def ined | if you use this, you'll get a link error since mongo::exit isn't def ined | |||
*/ | */ | |||
void exit( ExitCode returnCode ); | void exit( ExitCode returnCode ); | |||
bool inShutdown(); | bool inShutdown(); | |||
} // namespace mongo | } // namespace mongo | |||
namespace mongo { | namespace mongo { | |||
using namespace boost::filesystem; | using namespace boost::filesystem; | |||
void asserted(const char *msg, const char *file, unsigned line); | void asserted(const char *msg, const char *file, unsigned line); | |||
skipping to change at line 141 | skipping to change at line 155 | |||
namespace mongo { | namespace mongo { | |||
void sayDbContext(const char *msg = 0); | void sayDbContext(const char *msg = 0); | |||
void rawOut( const string &s ); | void rawOut( const string &s ); | |||
} // namespace mongo | } // namespace mongo | |||
namespace mongo { | namespace mongo { | |||
const char * gitVersion(); | typedef char _TCHAR; | |||
string sysInfo(); | ||||
string mongodVersion(); | ||||
void printGitVersion(); | using boost::uint32_t; | |||
void printSysInfo(); | using boost::uint64_t; | |||
typedef char _TCHAR; | ||||
} // namespace mongo | } // namespace mongo | |||
End of changes. 10 change blocks. | ||||
16 lines changed or deleted | 27 lines changed or added | |||
pdfile.h | pdfile.h | |||
---|---|---|---|---|
skipping to change at line 489 | skipping to change at line 489 | |||
inline DeletedRecord* DataFileMgr::makeDeletedRecord(const DiskLoc& dl, int len) { | inline DeletedRecord* DataFileMgr::makeDeletedRecord(const DiskLoc& dl, int len) { | |||
assert( dl.a() != -1 ); | assert( dl.a() != -1 ); | |||
return (DeletedRecord*) cc().database()->getFile(dl.a())->makeRecor d(dl, sizeof(DeletedRecord)); | return (DeletedRecord*) cc().database()->getFile(dl.a())->makeRecor d(dl, sizeof(DeletedRecord)); | |||
} | } | |||
void ensureHaveIdIndex(const char *ns); | void ensureHaveIdIndex(const char *ns); | |||
bool dropIndexes( NamespaceDetails *d, const char *ns, const char *name , string &errmsg, BSONObjBuilder &anObjBuilder, bool maydeleteIdIndex ); | bool dropIndexes( NamespaceDetails *d, const char *ns, const char *name , string &errmsg, BSONObjBuilder &anObjBuilder, bool maydeleteIdIndex ); | |||
/** | ||||
* @return true if ns is ok | ||||
*/ | ||||
inline bool nsDollarCheck( const char* ns ){ | ||||
if ( strchr( ns , '$' ) == 0 ) | ||||
return true; | ||||
return strcmp( ns, "local.oplog.$main" ) == 0; | ||||
} | ||||
} // namespace mongo | } // namespace mongo | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 9 lines changed or added | |||
query.h | query.h | |||
---|---|---|---|---|
skipping to change at line 79 | skipping to change at line 79 | |||
// struct QueryOptions, QueryResult, QueryResultFlags in: | // struct QueryOptions, QueryResult, QueryResultFlags in: | |||
#include "../client/dbclient.h" | #include "../client/dbclient.h" | |||
namespace mongo { | namespace mongo { | |||
extern const int MaxBytesToReturnToClientAtOnce; | extern const int MaxBytesToReturnToClientAtOnce; | |||
// for an existing query (ie a ClientCursor), send back additional info rmation. | // for an existing query (ie a ClientCursor), send back additional info rmation. | |||
struct GetMoreWaitException { }; | struct GetMoreWaitException { }; | |||
QueryResult* processGetMore(const char *ns, int ntoreturn, long long cu rsorid , CurOp& op, int pass ); | QueryResult* processGetMore(const char *ns, int ntoreturn, long long cu rsorid , CurOp& op, int pass, bool& exhaust); | |||
struct UpdateResult { | struct UpdateResult { | |||
bool existing; | bool existing; | |||
bool mod; | bool mod; | |||
long long num; | long long num; | |||
UpdateResult( bool e, bool m, unsigned long long n ) | UpdateResult( bool e, bool m, unsigned long long n ) | |||
: existing(e) , mod(m), num(n ){} | : existing(e) , mod(m), num(n ){} | |||
int oldCode(){ | int oldCode(){ | |||
skipping to change at line 117 | skipping to change at line 117 | |||
god - allow access to system namespaces | god - allow access to system namespaces | |||
*/ | */ | |||
UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BS ONObj pattern, bool upsert, bool multi , bool logop , OpDebug& debug ); | UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BS ONObj pattern, bool upsert, bool multi , bool logop , OpDebug& debug ); | |||
UpdateResult _updateObjects(bool god, const char *ns, const BSONObj& up dateobj, BSONObj pattern, bool upsert, bool multi , bool logop , OpDebug& d ebug ); | UpdateResult _updateObjects(bool god, const char *ns, const BSONObj& up dateobj, BSONObj pattern, bool upsert, bool multi , bool logop , OpDebug& d ebug ); | |||
// If justOne is true, deletedId is set to the id of the deleted object . | // If justOne is true, deletedId is set to the id of the deleted object . | |||
long long deleteObjects(const char *ns, BSONObj pattern, bool justOne, bool logop = false, bool god=false); | long long deleteObjects(const char *ns, BSONObj pattern, bool justOne, bool logop = false, bool god=false); | |||
long long runCount(const char *ns, const BSONObj& cmd, string& err); | long long runCount(const char *ns, const BSONObj& cmd, string& err); | |||
void runQuery(Message& m, QueryMessage& q, CurOp& curop, Message &resul t); | const char * runQuery(Message& m, QueryMessage& q, CurOp& curop, Messag e &result); | |||
/* This is for languages whose "objects" are not well ordered (JSON is well ordered). | /* This is for languages whose "objects" are not well ordered (JSON is well ordered). | |||
[ { a : ... } , { b : ... } ] -> { a : ..., b : ... } | [ { a : ... } , { b : ... } ] -> { a : ..., b : ... } | |||
*/ | */ | |||
inline BSONObj transformOrderFromArrayFormat(BSONObj order) { | inline BSONObj transformOrderFromArrayFormat(BSONObj order) { | |||
/* note: this is slow, but that is ok as order will have very few p ieces */ | /* note: this is slow, but that is ok as order will have very few p ieces */ | |||
BSONObjBuilder b; | BSONObjBuilder b; | |||
char p[2] = "0"; | char p[2] = "0"; | |||
while ( 1 ) { | while ( 1 ) { | |||
End of changes. 2 change blocks. | ||||
2 lines changed or deleted | 2 lines changed or added | |||
queryoptimizer.h | queryoptimizer.h | |||
---|---|---|---|---|
skipping to change at line 36 | skipping to change at line 36 | |||
namespace mongo { | namespace mongo { | |||
class IndexDetails; | class IndexDetails; | |||
class IndexType; | class IndexType; | |||
class QueryPlan : boost::noncopyable { | class QueryPlan : boost::noncopyable { | |||
public: | public: | |||
QueryPlan(NamespaceDetails *_d, | QueryPlan(NamespaceDetails *_d, | |||
int _idxNo, // -1 = no index | int _idxNo, // -1 = no index | |||
const FieldRangeSet &fbs, | const FieldRangeSet &fbs, | |||
const BSONObj &originalQuery, | ||||
const BSONObj &order, | const BSONObj &order, | |||
const BSONObj &startKey = BSONObj(), | const BSONObj &startKey = BSONObj(), | |||
const BSONObj &endKey = BSONObj() , | const BSONObj &endKey = BSONObj() , | |||
string special="" ); | string special="" ); | |||
/* If true, no other index can do better. */ | /* If true, no other index can do better. */ | |||
bool optimal() const { return optimal_; } | bool optimal() const { return optimal_; } | |||
/* ScanAndOrder processing will be required if true */ | /* ScanAndOrder processing will be required if true */ | |||
bool scanAndOrderRequired() const { return scanAndOrderRequired_; } | bool scanAndOrderRequired() const { return scanAndOrderRequired_; } | |||
/* When true, the index we are using has keys such that it can comp letely resolve the | /* When true, the index we are using has keys such that it can comp letely resolve the | |||
skipping to change at line 58 | skipping to change at line 59 | |||
bool exactKeyMatch() const { return exactKeyMatch_; } | bool exactKeyMatch() const { return exactKeyMatch_; } | |||
/* If true, the startKey and endKey are unhelpful and the index ord er doesn't match the | /* If true, the startKey and endKey are unhelpful and the index ord er doesn't match the | |||
requested sort order */ | requested sort order */ | |||
bool unhelpful() const { return unhelpful_; } | bool unhelpful() const { return unhelpful_; } | |||
int direction() const { return direction_; } | int direction() const { return direction_; } | |||
shared_ptr<Cursor> newCursor( const DiskLoc &startLoc = DiskLoc() , int numWanted=0 ) const; | shared_ptr<Cursor> newCursor( const DiskLoc &startLoc = DiskLoc() , int numWanted=0 ) const; | |||
shared_ptr<Cursor> newReverseCursor() const; | shared_ptr<Cursor> newReverseCursor() const; | |||
BSONObj indexKey() const; | BSONObj indexKey() const; | |||
const char *ns() const { return fbs_.ns(); } | const char *ns() const { return fbs_.ns(); } | |||
NamespaceDetails *nsd() const { return d; } | NamespaceDetails *nsd() const { return d; } | |||
BSONObj query() const { return fbs_.query(); } | BSONObj originalQuery() const { return _originalQuery; } | |||
BSONObj simplifiedQuery( const BSONObj& fields = BSONObj() ) const | BSONObj simplifiedQuery( const BSONObj& fields = BSONObj(), bool ex | |||
{ return fbs_.simplifiedQuery( fields ); } | pandIn = false ) const { return fbs_.simplifiedQuery( fields, expandIn ); } | |||
const FieldRange &range( const char *fieldName ) const { return fbs _.range( fieldName ); } | const FieldRange &range( const char *fieldName ) const { return fbs _.range( fieldName ); } | |||
void registerSelf( long long nScanned ) const; | void registerSelf( long long nScanned ) const; | |||
// just for testing | // just for testing | |||
BoundList indexBounds() const { return indexBounds_; } | BoundList indexBounds() const { return indexBounds_; } | |||
private: | private: | |||
NamespaceDetails *d; | NamespaceDetails *d; | |||
int idxNo; | int idxNo; | |||
const FieldRangeSet &fbs_; | const FieldRangeSet &fbs_; | |||
const BSONObj &_originalQuery; | ||||
const BSONObj &order_; | const BSONObj &order_; | |||
const IndexDetails *index_; | const IndexDetails *index_; | |||
bool optimal_; | bool optimal_; | |||
bool scanAndOrderRequired_; | bool scanAndOrderRequired_; | |||
bool exactKeyMatch_; | bool exactKeyMatch_; | |||
int direction_; | int direction_; | |||
BoundList indexBounds_; | BoundList indexBounds_; | |||
bool endKeyInclusive_; | bool endKeyInclusive_; | |||
bool unhelpful_; | bool unhelpful_; | |||
string _special; | string _special; | |||
IndexType * _type; | IndexType * _type; | |||
}; | }; | |||
// Inherit from this interface to implement a new query operation. | // Inherit from this interface to implement a new query operation. | |||
// The query optimizer will clone the QueryOp that is provided, giving | // The query optimizer will clone the QueryOp that is provided, giving | |||
// each clone its own query plan. | // each clone its own query plan. | |||
class QueryOp { | class QueryOp { | |||
public: | public: | |||
QueryOp() : _complete(), _stopRequested(), _qp(), _error() {} | QueryOp() : _complete(), _stopRequested(), _qp(), _error(), _haveOr | |||
Constraint() {} | ||||
// Used when handing off from one QueryOp type to another | ||||
QueryOp( const QueryOp &other ) : | ||||
_complete(), _stopRequested(), _qp(), _error(), _matcher( other._ma | ||||
tcher ), | ||||
_haveOrConstraint( other._haveOrConstraint ), _orConstraint( other. | ||||
_orConstraint ) {} | ||||
virtual ~QueryOp() {} | virtual ~QueryOp() {} | |||
/** this gets called after a query plan is set? ERH 2/16/10 */ | /** these gets called after a query plan is set */ | |||
virtual void init() = 0; | void init() { | |||
if ( _oldMatcher.get() ) { | ||||
_matcher.reset( _oldMatcher->nextClauseMatcher( qp().indexK | ||||
ey() ) ); | ||||
} else { | ||||
_matcher.reset( new CoveredIndexMatcher( qp().originalQuery | ||||
(), qp().indexKey(), alwaysUseRecord() ) ); | ||||
} | ||||
_init(); | ||||
} | ||||
virtual void next() = 0; | virtual void next() = 0; | |||
virtual bool mayRecordPlan() const = 0; | virtual bool mayRecordPlan() const = 0; | |||
/** @return a copy of the inheriting class, which will be run with 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. | to generate QueryOps for the subsequent plan set. This | |||
function | ||||
should only be called after the query op has completed | ||||
executing. | ||||
*/ | */ | |||
virtual QueryOp *clone() const = 0; | QueryOp *createChild() { | |||
if( _haveOrConstraint ) { | ||||
_matcher->addOrConstraint( _orConstraint ); | ||||
_haveOrConstraint = false; | ||||
} | ||||
QueryOp *ret = _createChild(); | ||||
ret->_oldMatcher = _matcher; | ||||
return ret; | ||||
} | ||||
bool complete() const { return _complete; } | bool complete() const { return _complete; } | |||
bool error() const { return _error; } | bool error() const { return _error; } | |||
bool stopRequested() const { return _stopRequested; } | bool stopRequested() const { return _stopRequested; } | |||
string exceptionMessage() const { return _exceptionMessage; } | string exceptionMessage() const { return _exceptionMessage; } | |||
const QueryPlan &qp() const { return *_qp; } | const QueryPlan &qp() const { return *_qp; } | |||
// To be called by QueryPlanSet::Runner only. | // To be called by QueryPlanSet::Runner only. | |||
void setQueryPlan( const QueryPlan *qp ) { _qp = qp; } | void setQueryPlan( const QueryPlan *qp ) { _qp = qp; } | |||
void setExceptionMessage( const string &exceptionMessage ) { | void setExceptionMessage( const string &exceptionMessage ) { | |||
_error = true; | _error = true; | |||
_exceptionMessage = exceptionMessage; | _exceptionMessage = exceptionMessage; | |||
} | } | |||
shared_ptr< CoveredIndexMatcher > matcher() const { return _matcher ; } | ||||
protected: | protected: | |||
void setComplete() { _complete = true; } | void setComplete() { | |||
_haveOrConstraint = true; | ||||
_orConstraint = qp().simplifiedQuery( qp().indexKey(), true ); | ||||
_complete = true; | ||||
} | ||||
void setStop() { setComplete(); _stopRequested = true; } | void setStop() { setComplete(); _stopRequested = true; } | |||
virtual void _init() = 0; | ||||
virtual QueryOp *_createChild() const = 0; | ||||
virtual bool alwaysUseRecord() const { return false; } | ||||
private: | private: | |||
bool _complete; | bool _complete; | |||
bool _stopRequested; | bool _stopRequested; | |||
string _exceptionMessage; | string _exceptionMessage; | |||
const QueryPlan *_qp; | const QueryPlan *_qp; | |||
bool _error; | bool _error; | |||
shared_ptr< CoveredIndexMatcher > _matcher; | ||||
shared_ptr< CoveredIndexMatcher > _oldMatcher; | ||||
bool _haveOrConstraint; | ||||
BSONObj _orConstraint; | ||||
}; | }; | |||
// Set of candidate query plans for a particular query. Used for runni ng | // Set of candidate query plans for a particular query. Used for runni ng | |||
// a QueryOp on these plans. | // a QueryOp on these plans. | |||
class QueryPlanSet { | class QueryPlanSet { | |||
public: | public: | |||
typedef boost::shared_ptr< QueryPlan > PlanPtr; | typedef boost::shared_ptr< QueryPlan > PlanPtr; | |||
typedef vector< PlanPtr > PlanSet; | typedef vector< PlanPtr > PlanSet; | |||
QueryPlanSet( const char *ns, | QueryPlanSet( const char *ns, | |||
const BSONObj &query, | auto_ptr< FieldRangeSet > frs, | |||
const BSONObj &originalQuery, | ||||
const BSONObj &order, | const BSONObj &order, | |||
const BSONElement *hint = 0, | const BSONElement *hint = 0, | |||
bool honorRecordedPlan = true, | bool honorRecordedPlan = true, | |||
const BSONObj &min = BSONObj(), | const BSONObj &min = BSONObj(), | |||
const BSONObj &max = BSONObj() ); | const BSONObj &max = BSONObj() ); | |||
int nPlans() const { return plans_.size(); } | int nPlans() const { return plans_.size(); } | |||
shared_ptr< QueryOp > runOp( QueryOp &op ); | shared_ptr< QueryOp > runOp( QueryOp &op ); | |||
template< class T > | template< class T > | |||
shared_ptr< T > runOp( T &op ) { | shared_ptr< T > runOp( T &op ) { | |||
return dynamic_pointer_cast< T >( runOp( static_cast< QueryOp& >( op ) ) ); | return dynamic_pointer_cast< T >( runOp( static_cast< QueryOp& >( op ) ) ); | |||
} | } | |||
BSONObj explain() const; | BSONObj explain() const; | |||
bool usingPrerecordedPlan() const { return usingPrerecordedPlan_; } | bool usingPrerecordedPlan() const { return usingPrerecordedPlan_; } | |||
PlanPtr getBestGuess() const; | PlanPtr getBestGuess() const; | |||
void setBestGuessOnly() { _bestGuessOnly = true; } | void setBestGuessOnly() { _bestGuessOnly = true; } | |||
//for testing | //for testing | |||
const FieldRangeSet &fbs() const { return fbs_; } | const FieldRangeSet &fbs() const { return *fbs_; } | |||
private: | private: | |||
void addOtherPlans( bool checkFirst ); | void addOtherPlans( bool checkFirst ); | |||
void addPlan( PlanPtr plan, bool checkFirst ) { | void addPlan( PlanPtr plan, bool checkFirst ) { | |||
if ( checkFirst && plan->indexKey().woCompare( plans_[ 0 ]->ind exKey() ) == 0 ) | if ( checkFirst && plan->indexKey().woCompare( plans_[ 0 ]->ind exKey() ) == 0 ) | |||
return; | return; | |||
plans_.push_back( plan ); | plans_.push_back( plan ); | |||
} | } | |||
void init(); | void init(); | |||
void addHint( IndexDetails &id ); | void addHint( IndexDetails &id ); | |||
struct Runner { | struct Runner { | |||
Runner( QueryPlanSet &plans, QueryOp &op ); | Runner( QueryPlanSet &plans, QueryOp &op ); | |||
shared_ptr< QueryOp > run(); | shared_ptr< QueryOp > run(); | |||
QueryOp &op_; | QueryOp &op_; | |||
QueryPlanSet &plans_; | QueryPlanSet &plans_; | |||
static void initOp( QueryOp &op ); | static void initOp( QueryOp &op ); | |||
static void nextOp( QueryOp &op ); | static void nextOp( QueryOp &op ); | |||
}; | }; | |||
const char *ns; | const char *ns; | |||
BSONObj query_; | BSONObj _originalQuery; | |||
FieldRangeSet fbs_; | auto_ptr< FieldRangeSet > fbs_; | |||
PlanSet plans_; | PlanSet plans_; | |||
bool mayRecordPlan_; | bool mayRecordPlan_; | |||
bool usingPrerecordedPlan_; | bool usingPrerecordedPlan_; | |||
BSONObj hint_; | BSONObj hint_; | |||
BSONObj order_; | BSONObj order_; | |||
long long oldNScanned_; | long long oldNScanned_; | |||
bool honorRecordedPlan_; | bool honorRecordedPlan_; | |||
BSONObj min_; | BSONObj min_; | |||
BSONObj max_; | BSONObj max_; | |||
string _special; | string _special; | |||
skipping to change at line 224 | skipping to change at line 266 | |||
shared_ptr< QueryOp > runOp( QueryOp &op ); | shared_ptr< QueryOp > runOp( QueryOp &op ); | |||
template< class T > | template< class T > | |||
shared_ptr< T > runOp( T &op ) { | shared_ptr< T > runOp( T &op ) { | |||
return dynamic_pointer_cast< T >( runOp( static_cast< QueryOp& >( op ) ) ); | return dynamic_pointer_cast< T >( runOp( static_cast< QueryOp& >( op ) ) ); | |||
} | } | |||
shared_ptr< QueryOp > runOpOnce( QueryOp &op ); | shared_ptr< QueryOp > runOpOnce( QueryOp &op ); | |||
template< class T > | template< class T > | |||
shared_ptr< T > runOpOnce( T &op ) { | shared_ptr< T > runOpOnce( T &op ) { | |||
return dynamic_pointer_cast< T >( runOpOnce( static_cast< Query Op& >( op ) ) ); | return dynamic_pointer_cast< T >( runOpOnce( static_cast< Query Op& >( op ) ) ); | |||
} | } | |||
bool mayRunMore() const { return _i < _n; } | bool mayRunMore() const { return _or ? !_fros.orFinished() : _i == 0; } | |||
BSONObj oldExplain() const { assertNotOr(); return _currentQps->exp lain(); } | BSONObj oldExplain() const { assertNotOr(); return _currentQps->exp lain(); } | |||
// just report this when only one query op | // just report this when only one query op | |||
bool usingPrerecordedPlan() const { | bool usingPrerecordedPlan() const { | |||
return !_or && _currentQps->usingPrerecordedPlan(); | return !_or && _currentQps->usingPrerecordedPlan(); | |||
} | } | |||
void setBestGuessOnly() { _bestGuessOnly = true; } | void setBestGuessOnly() { _bestGuessOnly = true; } | |||
private: | private: | |||
//temp | ||||
void assertNotOr() const { | void assertNotOr() const { | |||
massert( 13266, "not implemented for $or query", !_or ); | massert( 13266, "not implemented for $or query", !_or ); | |||
} | } | |||
// temp (and yucky) | bool uselessOr( const BSONElement &hint ) const; | |||
BSONObj nextSimpleQuery() { | ||||
massert( 13267, "only generate simple query if $or", _or ); | ||||
massert( 13270, "no more simple queries", mayRunMore() ); | ||||
BSONObjBuilder b; | ||||
BSONArrayBuilder norb; | ||||
BSONObjIterator i( _query ); | ||||
while( i.more() ) { | ||||
BSONElement e = i.next(); | ||||
if ( strcmp( e.fieldName(), "$nor" ) == 0 ) { | ||||
massert( 13269, "$nor must be array", e.type() == Array | ||||
); | ||||
BSONObjIterator j( e.embeddedObject() ); | ||||
while( j.more() ) { | ||||
norb << j.next(); | ||||
} | ||||
} else if ( strcmp( e.fieldName(), "$or" ) == 0 ) { | ||||
BSONObjIterator j( e.embeddedObject() ); | ||||
for( int k = 0; k < _i; ++k ) { | ||||
norb << j.next(); | ||||
} | ||||
b << "$or" << BSON_ARRAY( j.next() ); | ||||
} else { | ||||
b.append( e ); | ||||
} | ||||
} | ||||
BSONArray nor = norb.arr(); | ||||
if ( !nor.isEmpty() ) { | ||||
b << "$nor" << nor; | ||||
} | ||||
++_i; | ||||
BSONObj ret = b.obj(); | ||||
return ret; | ||||
} | ||||
const char * _ns; | const char * _ns; | |||
bool _or; | bool _or; | |||
BSONObj _query; | BSONObj _query; | |||
// FieldRangeOrSet _fros; | FieldRangeOrSet _fros; | |||
auto_ptr< QueryPlanSet > _currentQps; | auto_ptr< QueryPlanSet > _currentQps; | |||
int _i; | int _i; | |||
int _n; | ||||
bool _honorRecordedPlan; | bool _honorRecordedPlan; | |||
bool _bestGuessOnly; | bool _bestGuessOnly; | |||
BSONObj _hint; | ||||
}; | }; | |||
class MultiCursor : public Cursor { | class MultiCursor : public Cursor { | |||
public: | public: | |||
class CursorOp : public QueryOp { | class CursorOp : public QueryOp { | |||
public: | public: | |||
CursorOp() {} | ||||
CursorOp( const QueryOp &other ) : QueryOp( other ) {} | ||||
virtual shared_ptr< Cursor > newCursor() const = 0; | virtual shared_ptr< Cursor > newCursor() const = 0; | |||
virtual auto_ptr< CoveredIndexMatcher > newMatcher() const = 0; | ||||
}; | }; | |||
// takes ownership of 'op' | // takes ownership of 'op' | |||
MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj &order, auto_ptr< CursorOp > op = auto_ptr< CursorOp >( 0 ) ) | MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj &order, shared_ptr< CursorOp > op = shared_ptr< CursorOp >() ) | |||
: _mps( new MultiPlanScanner( ns, pattern, order ) ) { | : _mps( new MultiPlanScanner( ns, pattern, order ) ) { | |||
if ( op.get() ) { | if ( op.get() ) { | |||
_op = op; | _op = op; | |||
} else { | } else { | |||
_op.reset( new NoOp() ); | _op.reset( new NoOp() ); | |||
_mps->setBestGuessOnly(); | _mps->setBestGuessOnly(); | |||
} | } | |||
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 | MultiCursor( auto_ptr< MultiPlanScanner > mps, const shared_ptr< Cu | |||
rsor > &c, auto_ptr< CoveredIndexMatcher > matcher ) | rsor > &c, const shared_ptr< CoveredIndexMatcher > &matcher, const QueryOp | |||
: _op( new NoOp() ), _c( c ), _mps( mps ), _matcher( matcher ) { | &op ) | |||
: _op( new NoOp( op ) ), _c( c ), _mps( mps ), _matcher( matcher ) | ||||
{ | ||||
_mps->setBestGuessOnly(); | _mps->setBestGuessOnly(); | |||
if ( !ok() ) { | ||||
// would have been advanced by UserQueryOp if possible | ||||
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(); } | |||
virtual DiskLoc currLoc() { return _c->currLoc(); } | virtual DiskLoc currLoc() { return _c->currLoc(); } | |||
virtual bool advance() { | virtual bool advance() { | |||
_c->advance(); | _c->advance(); | |||
while( !ok() && _mps->mayRunMore() ) { | while( !ok() && _mps->mayRunMore() ) { | |||
nextClause(); | nextClause(); | |||
} | } | |||
return ok(); | return ok(); | |||
} | } | |||
virtual BSONObj currKey() const { return _c->currKey(); } | virtual BSONObj currKey() const { return _c->currKey(); } | |||
virtual DiskLoc refLoc() { return _c->refLoc(); } | virtual DiskLoc refLoc() { return _c->refLoc(); } | |||
virtual void noteLocation() { _c->noteLocation(); } | virtual void noteLocation() { | |||
_c->noteLocation(); | ||||
} | ||||
virtual void checkLocation() { | virtual void checkLocation() { | |||
_c->checkLocation(); | _c->checkLocation(); | |||
if ( !ok() ) { | ||||
advance(); | ||||
} | ||||
} | } | |||
virtual bool supportGetMore() { return true; } | virtual bool supportGetMore() { return true; } | |||
// 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( ); } | |||
private: | private: | |||
class NoOp : public CursorOp { | class NoOp : public CursorOp { | |||
virtual void init() { setComplete(); } | public: | |||
NoOp() {} | ||||
NoOp( const QueryOp &other ) : CursorOp( other ) {} | ||||
virtual void _init() { setComplete(); } | ||||
virtual void next() {} | virtual void next() {} | |||
virtual bool mayRecordPlan() const { return false; } | virtual bool mayRecordPlan() const { return false; } | |||
virtual QueryOp *clone() 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 auto_ptr< CoveredIndexMatcher > newMatcher() const { | private: | |||
return auto_ptr< CoveredIndexMatcher >( new CoveredIndexMat | shared_ptr< CoveredIndexMatcher > _matcher; | |||
cher( qp().query(), qp().indexKey() ) ); | shared_ptr< CoveredIndexMatcher > _oldMatcher; | |||
} | ||||
}; | }; | |||
void nextClause() { | void nextClause() { | |||
shared_ptr< CursorOp > best = _mps->runOpOnce( *_op ); | shared_ptr< CursorOp > best = _mps->runOpOnce( *_op ); | |||
massert( 10401 , best->exceptionMessage(), best->complete() ); | massert( 10401 , best->exceptionMessage(), best->complete() ); | |||
_c = best->newCursor(); | _c = best->newCursor(); | |||
_matcher = best->newMatcher(); | _matcher = best->matcher(); | |||
_op = best; | ||||
} | } | |||
auto_ptr< CursorOp > _op; | shared_ptr< CursorOp > _op; | |||
shared_ptr< Cursor > _c; | shared_ptr< Cursor > _c; | |||
auto_ptr< MultiPlanScanner > _mps; | auto_ptr< MultiPlanScanner > _mps; | |||
auto_ptr< CoveredIndexMatcher > _matcher; | shared_ptr< CoveredIndexMatcher > _matcher; | |||
}; | }; | |||
// 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 ){ | |||
return | return | |||
strcmp( query.firstElement().fieldName() , "_id" ) == 0 && | strcmp( query.firstElement().fieldName() , "_id" ) == 0 && | |||
query.nFields() == 1 && | query.nFields() == 1 && | |||
query.firstElement().isSimpleType(); | query.firstElement().isSimpleType(); | |||
} | } | |||
// matcher() will always work on the returned cursor | // matcher() will always work on the returned cursor | |||
inline shared_ptr< Cursor > bestGuessCursor( const char *ns, const BSON Obj &query, const BSONObj &sort ) { | inline shared_ptr< Cursor > bestGuessCursor( const char *ns, const BSON Obj &query, const BSONObj &sort ) { | |||
if( !query.getField( "$or" ).eoo() ) { | if( !query.getField( "$or" ).eoo() ) { | |||
return shared_ptr< Cursor >( new MultiCursor( ns, query, sort ) ); | return shared_ptr< Cursor >( new MultiCursor( ns, query, sort ) ); | |||
} else { | } else { | |||
shared_ptr< Cursor > ret = QueryPlanSet( ns, query, sort ).getB | auto_ptr< FieldRangeSet > frs( new FieldRangeSet( ns, query ) ) | |||
estGuess()->newCursor(); | ; | |||
shared_ptr< Cursor > ret = QueryPlanSet( ns, frs, query, sort ) | ||||
.getBestGuess()->newCursor(); | ||||
if ( !query.isEmpty() ) { | if ( !query.isEmpty() ) { | |||
auto_ptr< CoveredIndexMatcher > matcher( new CoveredIndexMa tcher( query, ret->indexKeyPattern() ) ); | shared_ptr< CoveredIndexMatcher > matcher( new CoveredIndex Matcher( query, ret->indexKeyPattern() ) ); | |||
ret->setMatcher( matcher ); | ret->setMatcher( matcher ); | |||
} | } | |||
return ret; | return ret; | |||
} | } | |||
} | } | |||
} // namespace mongo | } // namespace mongo | |||
End of changes. 36 change blocks. | ||||
72 lines changed or deleted | 98 lines changed or added | |||
queryutil.h | queryutil.h | |||
---|---|---|---|---|
skipping to change at line 31 | skipping to change at line 31 | |||
namespace mongo { | namespace mongo { | |||
struct FieldBound { | struct FieldBound { | |||
BSONElement _bound; | BSONElement _bound; | |||
bool _inclusive; | bool _inclusive; | |||
bool operator==( const FieldBound &other ) const { | bool operator==( const FieldBound &other ) const { | |||
return _bound.woCompare( other._bound ) == 0 && | return _bound.woCompare( other._bound ) == 0 && | |||
_inclusive == other._inclusive; | _inclusive == other._inclusive; | |||
} | } | |||
void flipInclusive() { _inclusive = !_inclusive; } | ||||
}; | }; | |||
struct FieldInterval { | struct FieldInterval { | |||
FieldInterval(){} | FieldInterval(){} | |||
FieldInterval( const BSONElement& e ){ | FieldInterval( const BSONElement& e ){ | |||
_lower._bound = _upper._bound = e; | _lower._bound = _upper._bound = e; | |||
_lower._inclusive = _upper._inclusive = true; | _lower._inclusive = _upper._inclusive = true; | |||
} | } | |||
FieldBound _lower; | FieldBound _lower; | |||
FieldBound _upper; | FieldBound _upper; | |||
bool valid() const { | bool valid() const { | |||
int cmp = _lower._bound.woCompare( _upper._bound, false ); | int cmp = _lower._bound.woCompare( _upper._bound, false ); | |||
return ( cmp < 0 || ( cmp == 0 && _lower._inclusive && _upper._ inclusive ) ); | return ( cmp < 0 || ( cmp == 0 && _lower._inclusive && _upper._ inclusive ) ); | |||
} | } | |||
bool equality() const { return _lower._inclusive && _upper._inclusi ve && _lower._bound.woCompare( _upper._bound, false ) == 0; } | ||||
}; | }; | |||
// 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) | |||
skipping to change at line 77 | skipping to change at line 79 | |||
} | } | |||
bool nontrivial() const { | bool nontrivial() const { | |||
return | return | |||
! empty() && | ! empty() && | |||
( minKey.firstElement().woCompare( min(), false ) != 0 || | ( 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(); } | |||
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() { | ||||
for( vector< FieldInterval >::iterator i = _intervals.begin(); | ||||
i != _intervals.end(); ++i ) { | ||||
i->_lower._inclusive = false; | ||||
i->_upper._inclusive = false; | ||||
} | ||||
} | ||||
// reconstructs $in, regex, inequality matches | ||||
// this is a hack - we should submit FieldRange directly to a Match | ||||
er instead | ||||
BSONObj simplifiedComplex() const; | ||||
private: | private: | |||
BSONObj addObj( const BSONObj &o ); | BSONObj addObj( const BSONObj &o ); | |||
void finishOperation( const vector< FieldInterval > &newIntervals, const FieldRange &other ); | void finishOperation( const vector< FieldInterval > &newIntervals, const FieldRange &other ); | |||
vector< FieldInterval > _intervals; | vector< FieldInterval > _intervals; | |||
vector< BSONObj > _objData; | vector< BSONObj > _objData; | |||
string _special; | string _special; | |||
}; | }; | |||
// implements query pattern matching, used to determine if a query is | // implements query pattern matching, used to determine if a query is | |||
// similar to an earlier query and should use the same plan | // similar to an earlier query and should use the same plan | |||
skipping to change at line 164 | skipping to change at line 174 | |||
// and direction +1, one valid BoundList is: (1, 2); (4, 6). The same BoundList | // and direction +1, one valid BoundList is: (1, 2); (4, 6). The same BoundList | |||
// would be valid for index {i:-1} with direction -1. | // would be valid for index {i:-1} with direction -1. | |||
typedef vector< pair< BSONObj, BSONObj > > BoundList; | typedef vector< pair< BSONObj, BSONObj > > BoundList; | |||
// ranges of fields' value that may be determined from query -- used to | // ranges of fields' value that may be determined from query -- used to | |||
// determine index limits | // determine index limits | |||
class FieldRangeSet { | class FieldRangeSet { | |||
public: | public: | |||
friend class FieldRangeOrSet; | friend class FieldRangeOrSet; | |||
FieldRangeSet( const char *ns, const BSONObj &query , bool optimize =true ); | FieldRangeSet( const char *ns, const BSONObj &query , bool optimize =true ); | |||
bool hasRange( const char *fieldName ) const { | ||||
map< string, FieldRange >::const_iterator f = _ranges.find( fie | ||||
ldName ); | ||||
return f != _ranges.end(); | ||||
} | ||||
const FieldRange &range( const char *fieldName ) const { | const FieldRange &range( const char *fieldName ) const { | |||
map< string, FieldRange >::const_iterator f = _ranges.find( fie ldName ); | map< string, FieldRange >::const_iterator f = _ranges.find( fie ldName ); | |||
if ( f == _ranges.end() ) | if ( f == _ranges.end() ) | |||
return trivialRange(); | return trivialRange(); | |||
return f->second; | return f->second; | |||
} | } | |||
FieldRange &range( const char *fieldName ) { | ||||
map< string, FieldRange >::iterator f = _ranges.find( fieldName | ||||
); | ||||
if ( f == _ranges.end() ) | ||||
return trivialRange(); | ||||
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(), bool ex pandIn = false ) 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; | |||
} | } | |||
QueryPattern pattern( const BSONObj &sort = BSONObj() ) const; | QueryPattern pattern( const BSONObj &sort = BSONObj() ) const; | |||
BoundList indexBounds( const BSONObj &keyPattern, int direction ) c onst; | BoundList indexBounds( const BSONObj &keyPattern, int direction ) c onst; | |||
string getSpecial() const; | string getSpecial() const; | |||
// intended to handle sets without _orSets | ||||
const FieldRangeSet &operator-=( const FieldRangeSet &other ) { | const FieldRangeSet &operator-=( const FieldRangeSet &other ) { | |||
for( map< string, FieldRange >::const_iterator i = other._range | map< string, FieldRange >::iterator i = _ranges.begin(); | |||
s.begin(); | map< string, FieldRange >::const_iterator j = other._ranges.beg | |||
i != other._ranges.end(); ++i ) { | in(); | |||
map< string, FieldRange >::iterator f = _ranges.find( i->fi | while( i != _ranges.end() && j != other._ranges.end() ) { | |||
rst.c_str() ); | int cmp = i->first.compare( j->first ); | |||
if ( f != _ranges.end() ) | if ( cmp == 0 ) { | |||
f->second -= i->second; | i->second -= j->second; | |||
++i; | ||||
++j; | ||||
} else if ( cmp < 0 ) { | ||||
++i; | ||||
} else { | ||||
++j; | ||||
} | ||||
} | ||||
return *this; | ||||
} | ||||
const FieldRangeSet &operator&=( const FieldRangeSet &other ) { | ||||
map< string, FieldRange >::iterator i = _ranges.begin(); | ||||
map< string, FieldRange >::const_iterator j = other._ranges.beg | ||||
in(); | ||||
while( i != _ranges.end() && j != other._ranges.end() ) { | ||||
int cmp = i->first.compare( j->first ); | ||||
if ( cmp == 0 ) { | ||||
i->second &= j->second; | ||||
++i; | ||||
++j; | ||||
} else if ( cmp < 0 ) { | ||||
++i; | ||||
} else { | ||||
_ranges[ j->first ] = j->second; | ||||
++j; | ||||
} | ||||
} | ||||
while( j != other._ranges.end() ) { | ||||
_ranges[ j->first ] = j->second; | ||||
++j; | ||||
} | } | |||
return *this; | return *this; | |||
} | } | |||
BSONObj query() const { return _query; } | ||||
private: | private: | |||
void processQueryField( const BSONElement &e, bool optimize ); | void processQueryField( const BSONElement &e, bool optimize ); | |||
void processOpElement( const char *fieldName, const BSONElement &f, bool isNot, bool optimize ); | void processOpElement( const char *fieldName, const BSONElement &f, bool isNot, bool optimize ); | |||
static FieldRange *trivialRange_; | static FieldRange *trivialRange_; | |||
static FieldRange &trivialRange(); | static FieldRange &trivialRange(); | |||
mutable map< string, FieldRange > _ranges; | mutable map< string, FieldRange > _ranges; | |||
const char *_ns; | const char *_ns; | |||
// make sure memory for FieldRange BSONElements is owned | ||||
BSONObj _query; | BSONObj _query; | |||
}; | }; | |||
// generages FieldRangeSet objects, accounting for or clauses | // generages FieldRangeSet objects, accounting for or clauses | |||
// class FieldRangeOrSet { | class FieldRangeOrSet { | |||
// public: | public: | |||
// FieldRangeOrSet( const char *ns, const BSONObj &query , bool opti | FieldRangeOrSet( const char *ns, const BSONObj &query , bool optimi | |||
mize=true ); | ze=true ); | |||
// // if there's a trivial or clause, we won't use or ranges to help | // if there's a useless or clause, we won't use or ranges to help w | |||
with scanning | ith scanning | |||
// bool trivialOr() const { | bool orFinished() const { return _orFound && _orSets.empty(); } | |||
// for( list< FieldRangeSet >::const_iterator i = _orSets.begin( | // removes first or clause, and removes the field ranges it covers | |||
); i != _orSets.end(); ++i ) { | from all subsequent or clauses | |||
// if ( i->nNontrivialRanges() == 0 ) { | // this could invalidate the result of the last topFrs() | |||
// return true; | void popOrClause( const char *firstField, const char *secondField ) | |||
// } | { | |||
// } | massert( 13274, "no or clause to pop", !orFinished() ); | |||
// return false; | const FieldRangeSet &toPop = _orSets.front(); | |||
// } | if ( toPop.hasRange( firstField ) ) { | |||
// bool orFinished() const { return _orFound && _orSets.empty(); } | if ( secondField && toPop.hasRange( secondField ) ) { | |||
// // removes first or clause, and removes the field ranges it cover | // modifying existing front is ok - this is the last ti | |||
s from all subsequent or clauses | me we'll use it | |||
// void popOrClause() { | _orSets.front().range( firstField ).setExclusiveBounds( | |||
// massert( 13274, "no or clause to pop", !orFinished() ); | ); | |||
// const FieldRangeSet &toPop = _orSets.front(); | } | |||
// list< FieldRangeSet >::iterator i = _orSets.begin(); | const FieldRange &r = toPop.range( firstField ); | |||
// ++i; | list< FieldRangeSet >::iterator i = _orSets.begin(); | |||
// while( i != _orSets.end() ) { | ++i; | |||
// *i -= toPop; | while( i != _orSets.end() ) { | |||
// if( !i->matchPossible() ) { | if ( i->hasRange( firstField ) ) { | |||
// i = _orSets.erase( i ); | i->range( firstField ) -= r; | |||
// } else { | if( !i->matchPossible() ) { | |||
// ++i; | i = _orSets.erase( i ); | |||
// } | } else { | |||
// } | ++i; | |||
// _orSets.pop_front(); | } | |||
// } | } else { | |||
// private: | ++i; | |||
// FieldRangeSet _baseSet; | } | |||
// list< FieldRangeSet > _orSets; | } | |||
// bool _orFound; | } | |||
// }; | _oldOrSets.push_front( toPop ); | |||
_orSets.pop_front(); | ||||
} | ||||
FieldRangeSet *topFrs() const { | ||||
FieldRangeSet *ret = new FieldRangeSet( _baseSet ); | ||||
*ret &= _orSets.front(); | ||||
return ret; | ||||
} | ||||
void allClausesSimplified( vector< BSONObj > &ret ) const { | ||||
for( list< FieldRangeSet >::const_iterator i = _orSets.begin(); | ||||
i != _orSets.end(); ++i ) { | ||||
ret.push_back( i->simplifiedQuery() ); | ||||
} | ||||
} | ||||
string getSpecial() const { return _baseSet.getSpecial(); } | ||||
private: | ||||
FieldRangeSet _baseSet; | ||||
list< FieldRangeSet > _orSets; | ||||
list< FieldRangeSet > _oldOrSets; // make sure memory is owned | ||||
bool _orFound; | ||||
}; | ||||
/** | /** | |||
used for doing field limiting | used for doing field limiting | |||
*/ | */ | |||
class FieldMatcher { | class FieldMatcher { | |||
public: | public: | |||
FieldMatcher() | FieldMatcher() | |||
: _include(true) | : _include(true) | |||
, _special(false) | , _special(false) | |||
, _includeID(true) | , _includeID(true) | |||
End of changes. 11 change blocks. | ||||
49 lines changed or deleted | 122 lines changed or added | |||
queue.h | queue.h | |||
---|---|---|---|---|
// queue.h | // @file queue.h | |||
/* Copyright 2009 10gen Inc. | /* Copyright 2009 10gen Inc. | |||
* | * | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | * You may obtain a copy of the License at | |||
* | * | |||
* http://www.apache.org/licenses/LICENSE-2.0 | * http://www.apache.org/licenses/LICENSE-2.0 | |||
* | * | |||
* Unless required by applicable law or agreed to in writing, software | * Unless required by applicable law or agreed to in writing, software | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
replpair.h | replpair.h | |||
---|---|---|---|---|
skipping to change at line 25 | skipping to change at line 25 | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "db.h" | #include "db.h" | |||
#include "dbhelpers.h" | #include "dbhelpers.h" | |||
#include "json.h" | #include "json.h" | |||
#include "../client/dbclient.h" | #include "../client/dbclient.h" | |||
#include "repl.h" | #include "repl.h" | |||
#include "cmdline.h" | #include "cmdline.h" | |||
#include "repl/replset.h" | #include "repl/rs.h" | |||
namespace mongo { | namespace mongo { | |||
extern const char *replAllDead; | extern const char *replAllDead; | |||
/* ReplPair is a pair of db servers replicating to one another and coop erating. | /* ReplPair is a pair of db servers replicating to one another and coop erating. | |||
Only one member of the pair is active at a time; so this is a smart master/slave | Only one member of the pair is active at a time; so this is a smart master/slave | |||
configuration basically. | configuration basically. | |||
skipping to change at line 221 | skipping to change at line 221 | |||
} | } | |||
bool initialSyncCompleted() { | bool initialSyncCompleted() { | |||
return initialsynccomplete != 0; | return initialsynccomplete != 0; | |||
} | } | |||
void setInitialSyncCompleted() { | void setInitialSyncCompleted() { | |||
BSONObj o = fromjson("{\"initialsynccomplete\":1}"); | BSONObj o = fromjson("{\"initialsynccomplete\":1}"); | |||
Helpers::putSingleton("local.pair.sync", o); | Helpers::putSingleton("local.pair.sync", o); | |||
initialsynccomplete = 1; | initialsynccomplete = 1; | |||
log() << "pair: initial sync complete" << endl; | tlog() << "pair: initial sync complete" << endl; | |||
} | } | |||
void setInitialSyncCompletedLocking() { | void setInitialSyncCompletedLocking() { | |||
if ( initialsynccomplete == 1 ) | if ( initialsynccomplete == 1 ) | |||
return; | return; | |||
dblock lk; | dblock lk; | |||
setInitialSyncCompleted(); | setInitialSyncCompleted(); | |||
} | } | |||
}; | }; | |||
End of changes. 2 change blocks. | ||||
2 lines changed or deleted | 2 lines changed or added | |||
request.h | request.h | |||
---|---|---|---|---|
skipping to change at line 52 | skipping to change at line 52 | |||
} | } | |||
bool expectResponse() const { | bool expectResponse() const { | |||
return op() == dbQuery || op() == dbGetMore; | return op() == dbQuery || op() == dbGetMore; | |||
} | } | |||
bool isCommand() const; | bool isCommand() const; | |||
MSGID id() const { | MSGID id() const { | |||
return _id; | return _id; | |||
} | } | |||
DBConfig * getConfig() const { | DBConfigPtr getConfig() const { | |||
return _config; | return _config; | |||
} | } | |||
bool isShardingEnabled() const { | bool isShardingEnabled() const { | |||
return _config->isShardingEnabled(); | return _config->isShardingEnabled(); | |||
} | } | |||
ChunkManagerPtr getChunkManager() const { | ChunkManagerPtr getChunkManager() const { | |||
return _chunkManager; | return _chunkManager; | |||
} | } | |||
skipping to change at line 76 | skipping to change at line 76 | |||
ClientInfo * getClientInfo() const { | ClientInfo * getClientInfo() const { | |||
return _clientInfo; | return _clientInfo; | |||
} | } | |||
// ---- remote location info ----- | // ---- remote location info ----- | |||
Shard primaryShard() const ; | Shard primaryShard() const ; | |||
// ---- low level access ---- | // ---- low level access ---- | |||
void reply( Message & response ){ | void reply( Message & response , const string& fromServer ); | |||
_p->reply( _m , response , _id ); | ||||
} | ||||
Message& m() { return _m; } | Message& m() { return _m; } | |||
DbMessage& d() { return _d; } | DbMessage& d() { return _d; } | |||
AbstractMessagingPort* p() const { return _p; } | AbstractMessagingPort* p() const { return _p; } | |||
void process( int attempt = 0 ); | void process( int attempt = 0 ); | |||
void gotInsert(); | void gotInsert(); | |||
private: | private: | |||
void reset( bool reload=false ); | void reset( bool reload=false ); | |||
Message& _m; | Message& _m; | |||
DbMessage _d; | DbMessage _d; | |||
AbstractMessagingPort* _p; | AbstractMessagingPort* _p; | |||
MSGID _id; | MSGID _id; | |||
DBConfig * _config; | DBConfigPtr _config; | |||
ChunkManagerPtr _chunkManager; | ChunkManagerPtr _chunkManager; | |||
int _clientId; | int _clientId; | |||
ClientInfo * _clientInfo; | ClientInfo * _clientInfo; | |||
OpCounters* _counter; | OpCounters* _counter; | |||
}; | }; | |||
typedef map<int,ClientInfo*> ClientCache; | typedef map<int,ClientInfo*> ClientCache; | |||
skipping to change at line 122 | skipping to change at line 120 | |||
string getRemote() const { return _remote; } | string getRemote() const { return _remote; } | |||
void addShard( const string& shard ); | void addShard( const string& shard ); | |||
set<string> * getPrev() const { return _prev; }; | set<string> * getPrev() const { return _prev; }; | |||
void newRequest( AbstractMessagingPort* p = 0 ); | void newRequest( AbstractMessagingPort* p = 0 ); | |||
void disconnect(); | void disconnect(); | |||
static ClientInfo * get( int clientId = 0 , bool create = true ); | static ClientInfo * get( int clientId = 0 , bool create = true ); | |||
static void disconnect( int clientId ); | ||||
const set<string>& sinceLastGetError() const { return _sinceLastGet | ||||
Error; } | ||||
void clearSinceLastGetError(){ | ||||
_sinceLastGetError.clear(); | ||||
} | ||||
private: | private: | |||
int _id; | int _id; | |||
string _remote; | string _remote; | |||
set<string> _a; | set<string> _a; | |||
set<string> _b; | set<string> _b; | |||
set<string> * _cur; | set<string> * _cur; | |||
set<string> * _prev; | set<string> * _prev; | |||
int _lastAccess; | int _lastAccess; | |||
set<string> _sinceLastGetError; | ||||
static mongo::mutex _clientsLock; | static mongo::mutex _clientsLock; | |||
static ClientCache _clients; | static ClientCache& _clients; | |||
static boost::thread_specific_ptr<ClientInfo> _tlInfo; | static boost::thread_specific_ptr<ClientInfo> _tlInfo; | |||
}; | }; | |||
} | } | |||
#include "strategy.h" | #include "strategy.h" | |||
End of changes. 6 change blocks. | ||||
6 lines changed or deleted | 13 lines changed or added | |||
rs_config.h | rs_config.h | |||
---|---|---|---|---|
skipping to change at line 51 | skipping to change at line 51 | |||
struct MemberCfg { | struct MemberCfg { | |||
MemberCfg() : _id(-1), votes(1), priority(1.0), arbiterOnly(fal se) { } | MemberCfg() : _id(-1), votes(1), priority(1.0), arbiterOnly(fal se) { } | |||
int _id; /* ordinal */ | int _id; /* ordinal */ | |||
unsigned votes; /* how many votes this node gets. default 1. */ | unsigned votes; /* how many votes this node gets. default 1. */ | |||
HostAndPort h; | HostAndPort h; | |||
double priority; /* 0 means can never be primary */ | double priority; /* 0 means can never be primary */ | |||
bool arbiterOnly; | bool arbiterOnly; | |||
void check() const; /* check validity, assert if not. */ | void check() const; /* check validity, assert if not. */ | |||
BSONObj asBson() const; | BSONObj asBson() const; | |||
bool hot() const { | ||||
return !arbiterOnly; | ||||
} | ||||
}; | }; | |||
vector<MemberCfg> members; | vector<MemberCfg> members; | |||
string _id; | string _id; | |||
int version; | int version; | |||
HealthOptions ho; | HealthOptions ho; | |||
string md5; | string md5; | |||
BSONObj getLastErrorDefaults; | BSONObj getLastErrorDefaults; | |||
list<HostAndPort> otherMemberHostnames() const; // except self | list<HostAndPort> otherMemberHostnames() const; // except self | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 3 lines changed or added | |||
rsmember.h | rsmember.h | |||
---|---|---|---|---|
// @file rsmember.h | // @file rsmember.h | |||
/* | ||||
* Copyright (C) 2010 10gen Inc. | ||||
* | ||||
* This program is free software: you can redistribute it and/or modify | ||||
* it under the terms of the GNU Affero General Public License, version | ||||
3, | ||||
* as published by the Free Software Foundation. | ||||
* | ||||
* This program is distributed in the hope that it will be useful, | ||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
* GNU Affero General Public License for more details. | ||||
* | ||||
* You should have received a copy of the GNU Affero General Public Lice | ||||
nse | ||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
*/ | ||||
/** replica set member */ | /** replica set member */ | |||
#pragma once | #pragma once | |||
namespace mongo { | namespace mongo { | |||
enum MemberState { | enum MemberState { | |||
STARTUP, | STARTUP, | |||
PRIMARY, | PRIMARY, | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 17 lines changed or added | |||
shard.h | shard.h | |||
---|---|---|---|---|
skipping to change at line 32 | skipping to change at line 32 | |||
#include "../client/connpool.h" | #include "../client/connpool.h" | |||
namespace mongo { | namespace mongo { | |||
class ShardConnection; | class ShardConnection; | |||
class ShardStatus; | class ShardStatus; | |||
class Shard { | class Shard { | |||
public: | public: | |||
Shard() | Shard() | |||
: _name(""),_addr(""){ | : _name("") , _addr("") , _maxSize(0) , _isDraining( false ){ | |||
} | } | |||
Shard( const string& name , const string& addr ) | ||||
: _name(name), _addr( addr ){ | Shard( const string& name , const string& addr, long long maxSize = | |||
0 , bool isDraining = false ) | ||||
: _name(name) , _addr( addr ) , _maxSize( maxSize ) , _isDraini | ||||
ng( isDraining ){ | ||||
} | } | |||
Shard( const string& ident ){ | Shard( const string& ident ){ | |||
reset( ident ); | reset( ident ); | |||
} | } | |||
Shard( const Shard& other ) | Shard( const Shard& other ) | |||
: _name( other._name ) , _addr( other._addr ){ | : _name( other._name ) , _addr( other._addr ) , _maxSize( other ._maxSize ) , _isDraining( other._isDraining ){ | |||
} | } | |||
Shard( const Shard* other ) | Shard( const Shard* other ) | |||
: _name( other->_name ) ,_addr( other->_addr ){ | : _name( other->_name ) , _addr( other->_addr ), _maxSize( othe r->_maxSize ) , _isDraining( other->_isDraining ){ | |||
} | } | |||
static Shard make( const string& ident ){ | static Shard make( const string& ident ){ | |||
Shard s; | Shard s; | |||
s.reset( ident ); | s.reset( ident ); | |||
return s; | return s; | |||
} | } | |||
/** | /** | |||
* @param ident either name or address | * @param ident either name or address | |||
skipping to change at line 73 | skipping to change at line 74 | |||
string getName() const { | string getName() const { | |||
assert( _name.size() ); | assert( _name.size() ); | |||
return _name; | return _name; | |||
} | } | |||
string getConnString() const { | string getConnString() const { | |||
assert( _addr.size() ); | assert( _addr.size() ); | |||
return _addr; | return _addr; | |||
} | } | |||
long long getMaxSize() const { | ||||
return _maxSize; | ||||
} | ||||
bool isDraining() const { | ||||
return _isDraining; | ||||
} | ||||
string toString() const { | string toString() const { | |||
return _name + ":" + _addr; | return _name + ":" + _addr; | |||
} | } | |||
friend ostream& operator << (ostream& out, const Shard& s) { | friend ostream& operator << (ostream& out, const Shard& s) { | |||
return (out << s.toString()); | return (out << s.toString()); | |||
} | } | |||
bool operator==( const Shard& s ) const { | bool operator==( const Shard& s ) const { | |||
bool n = _name == s._name; | bool n = _name == s._name; | |||
skipping to change at line 130 | skipping to change at line 139 | |||
/** | /** | |||
* picks a Shard for more load | * picks a Shard for more load | |||
*/ | */ | |||
static Shard pick(); | static Shard pick(); | |||
static void reloadShardInfo(); | static void reloadShardInfo(); | |||
static Shard EMPTY; | static Shard EMPTY; | |||
private: | private: | |||
string _name; | string _name; | |||
string _addr; | string _addr; | |||
long long _maxSize; // in MBytes, 0 is unlimited | ||||
bool _isDraining; // shard is currently being removed | ||||
}; | }; | |||
class ShardStatus { | class ShardStatus { | |||
public: | public: | |||
ShardStatus( const Shard& shard , const BSONObj& obj ); | ShardStatus( const Shard& shard , const BSONObj& obj ); | |||
friend ostream& operator << (ostream& out, const ShardStatus& s) { | friend ostream& operator << (ostream& out, const ShardStatus& s) { | |||
out << (string)s; | out << (string)s; | |||
return out; | return out; | |||
skipping to change at line 158 | skipping to change at line 169 | |||
} | } | |||
bool operator<( const ShardStatus& other ) const{ | bool operator<( const ShardStatus& other ) const{ | |||
return _mapped < other._mapped; | return _mapped < other._mapped; | |||
} | } | |||
Shard shard() const { | Shard shard() const { | |||
return _shard; | return _shard; | |||
} | } | |||
long long mapped() const { | ||||
return _mapped; | ||||
} | ||||
private: | private: | |||
Shard _shard; | Shard _shard; | |||
long long _mapped; | long long _mapped; | |||
double _writeLock; | double _writeLock; | |||
}; | }; | |||
class ShardConnection { | class ShardConnection : boost::noncopyable{ | |||
public: | public: | |||
ShardConnection( const Shard * s , const string& ns ); | ShardConnection( const Shard * s , const string& ns ); | |||
ShardConnection( const Shard& s , const string& ns ); | ShardConnection( const Shard& s , const string& ns ); | |||
ShardConnection( const string& addr , const string& ns ); | ShardConnection( const string& addr , const string& ns ); | |||
~ShardConnection(); | ||||
void done(); | void done(); | |||
void kill(); | void kill(); | |||
DBClientBase& conn(){ | DBClientBase& conn(){ | |||
assert( _conn ); | assert( _conn ); | |||
return *_conn; | return *_conn; | |||
} | } | |||
DBClientBase* operator->(){ | DBClientBase* operator->(){ | |||
assert( _conn ); | assert( _conn ); | |||
End of changes. 9 change blocks. | ||||
8 lines changed or deleted | 27 lines changed or added | |||
str.h | str.h | |||
---|---|---|---|---|
skipping to change at line 27 | skipping to change at line 27 | |||
#pragma once | #pragma once | |||
/* Things in the mongoutils namespace | /* Things in the mongoutils namespace | |||
(1) are not database specific, rather, true utilities | (1) are not database specific, rather, true utilities | |||
(2) are cross platform | (2) are cross platform | |||
(3) may require boost headers, but not libs | (3) may require boost headers, but not libs | |||
(4) are clean and easy to use in any c++ project without pulling in lots of other stuff | (4) are clean and easy to use in any c++ project without pulling in lots of other stuff | |||
Note: within this module, we use int for all offsets -- there are no uns igned offsets | Note: within this module, we use int for all offsets -- there are no uns igned offsets | |||
and no size_t's. If you need 3 gigabyte long strings, don't use this mo | and no size_t's. If you need 3 gigabyte long strings, don't use this mo | |||
dule. */ | dule. | |||
*/ | ||||
#include <string> | #include <string> | |||
namespace mongoutils { | namespace mongoutils { | |||
namespace str { | namespace str { | |||
using namespace std; | using namespace std; | |||
/** the idea here is to make one liners easy. e.g.: | ||||
return str::stream() << 1 << ' ' << 2; | ||||
since the following doesn't work: | ||||
(stringstream() << 1).str(); | ||||
*/ | ||||
class stream { | ||||
public: | ||||
stringstream ss; | ||||
template<class T> | ||||
stream& operator<<(const T& v) { | ||||
ss << v; | ||||
return *this; | ||||
} | ||||
operator std::string () const { return ss.str(); } | ||||
}; | ||||
inline bool startsWith(const char *str, const char *prefix) { | inline bool startsWith(const char *str, const char *prefix) { | |||
size_t l = strlen(prefix); | size_t l = strlen(prefix); | |||
if ( strlen(str) < l ) return false; | if ( strlen(str) < l ) return false; | |||
return strncmp(str, prefix, l) == 0; | return strncmp(str, prefix, l) == 0; | |||
} | } | |||
inline bool startsWith(string s, string p) { return startsWith(s.c_ str(), p.c_str()); } | inline bool startsWith(string s, string p) { return startsWith(s.c_ str(), p.c_str()); } | |||
inline bool endsWith(string s, string p) { | inline bool endsWith(string s, string p) { | |||
int l = p.size(); | int l = p.size(); | |||
int x = s.size(); | int x = s.size(); | |||
End of changes. 2 change blocks. | ||||
2 lines changed or deleted | 24 lines changed or added | |||
syncclusterconnection.h | syncclusterconnection.h | |||
---|---|---|---|---|
skipping to change at line 80 | skipping to change at line 80 | |||
virtual void insert( const string &ns, const vector< BSONObj >& v ) ; | virtual void insert( const string &ns, const vector< BSONObj >& v ) ; | |||
virtual void remove( const string &ns , Query query, bool justOne ) ; | virtual void remove( const string &ns , Query query, bool justOne ) ; | |||
virtual void update( const string &ns , Query query , BSONObj obj , bool upsert , bool multi ); | virtual void update( const string &ns , Query query , BSONObj obj , bool upsert , bool multi ); | |||
virtual bool call( Message &toSend, Message &response, bool assertO k ); | virtual bool call( Message &toSend, Message &response, bool assertO k ); | |||
virtual void say( Message &toSend ); | virtual void say( Message &toSend ); | |||
virtual void sayPiggyBack( Message &toSend ); | virtual void sayPiggyBack( Message &toSend ); | |||
virtual void killCursor( long long cursorID ); | ||||
virtual string getServerAddress() const { return _address; } | virtual string getServerAddress() const { return _address; } | |||
virtual bool isFailed() const { return false; } | virtual bool isFailed() const { return false; } | |||
virtual string toString() { return _toString(); } | virtual string toString() { return _toString(); } | |||
private: | private: | |||
SyncClusterConnection( SyncClusterConnection& prev ); | SyncClusterConnection( SyncClusterConnection& prev ); | |||
string _toString() const; | string _toString() const; | |||
bool _commandOnActive(const string &dbname, const BSONObj& cmd, BSO NObj &info, int options=0); | bool _commandOnActive(const string &dbname, const BSONObj& cmd, BSO NObj &info, int options=0); | |||
auto_ptr<DBClientCursor> _queryOnActive(const string &ns, Query que ry, int nToReturn, int nToSkip, | auto_ptr<DBClientCursor> _queryOnActive(const string &ns, Query que ry, int nToReturn, int nToSkip, | |||
const BSONObj *fieldsToRetu rn, int queryOptions, int batchSize ); | const BSONObj *fieldsToRetu rn, int queryOptions, int batchSize ); | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 2 lines changed or added | |||
text.h | text.h | |||
---|---|---|---|---|
// text.h | // text.h | |||
/* | ||||
* Copyright 2010 10gen Inc. | ||||
* | ||||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||||
* you may not use this file except in compliance with the License. | ||||
* You may obtain a copy of the License at | ||||
* | ||||
* http://www.apache.org/licenses/LICENSE-2.0 | ||||
* | ||||
* Unless required by applicable law or agreed to in writing, software | ||||
* distributed under the License is distributed on an "AS IS" BASIS, | ||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli | ||||
ed. | ||||
* See the License for the specific language governing permissions and | ||||
* limitations under the License. | ||||
*/ | ||||
/* Copyright 2009 10gen Inc. | ||||
* | ||||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||||
* you may not use this file except in compliance with the License. | ||||
* You may obtain a copy of the License at | ||||
* | ||||
* http://www.apache.org/licenses/LICENSE-2.0 | ||||
* | ||||
* Unless required by applicable law or agreed to in writing, software | ||||
* distributed under the License is distributed on an "AS IS" BASIS, | ||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli | ||||
ed. | ||||
* See the License for the specific language governing permissions and | ||||
* limitations under the License. | ||||
*/ | ||||
#pragma once | #pragma once | |||
namespace mongo { | namespace mongo { | |||
class StringSplitter { | class StringSplitter { | |||
public: | public: | |||
StringSplitter( const char * big , const char * splitter ) | StringSplitter( const char * big , const char * splitter ) | |||
: _big( big ) , _splitter( splitter ){ | : _big( big ) , _splitter( splitter ){ | |||
} | } | |||
skipping to change at line 64 | skipping to change at line 94 | |||
ss << l[i]; | ss << l[i]; | |||
} | } | |||
return ss.str(); | return ss.str(); | |||
} | } | |||
private: | private: | |||
const char * _big; | const char * _big; | |||
const char * _splitter; | const char * _splitter; | |||
}; | }; | |||
/* This doesn't defend against ALL bad UTF8, but it will guarantee that | ||||
the | ||||
* string can be converted to sequence of codepoints. However, it doesn | ||||
't | ||||
* guarantee that the codepoints are valid. | ||||
*/ | ||||
bool isValidUTF8(const char *s); | ||||
inline bool isValidUTF8(string s) { return isValidUTF8(s.c_str()); } | ||||
#if defined(_WIN32) | ||||
std::string toUtf8String(const std::wstring& wide); | ||||
std::wstring toWideString(const char *s); | ||||
/* like toWideString but UNICODE macro sensitive */ | ||||
# if !defined(_UNICODE) | ||||
#error temp error | ||||
inline std::string toNativeString(const char *s) { return s; } | ||||
# else | ||||
inline std::wstring toNativeString(const char *s) { return toWideString | ||||
(s); } | ||||
# endif | ||||
#endif | ||||
} | } | |||
End of changes. 2 change blocks. | ||||
0 lines changed or deleted | 58 lines changed or added | |||
tool.h | tool.h | |||
---|---|---|---|---|
skipping to change at line 99 | skipping to change at line 99 | |||
string _name; | string _name; | |||
string _db; | string _db; | |||
string _coll; | string _coll; | |||
string _username; | string _username; | |||
string _password; | string _password; | |||
bool _usesstdout; | bool _usesstdout; | |||
bool _noconnection; | bool _noconnection; | |||
bool _autoreconnect; | ||||
void addFieldOptions(); | void addFieldOptions(); | |||
void needFields(); | void needFields(); | |||
vector<string> _fields; | vector<string> _fields; | |||
BSONObj _fieldsObj; | BSONObj _fieldsObj; | |||
string _host; | string _host; | |||
protected: | protected: | |||
skipping to change at line 121 | skipping to change at line 122 | |||
bool _paired; | bool _paired; | |||
boost::program_options::options_description * _options; | boost::program_options::options_description * _options; | |||
boost::program_options::options_description * _hidden_options; | boost::program_options::options_description * _hidden_options; | |||
boost::program_options::positional_options_description _positonalOp tions; | boost::program_options::positional_options_description _positonalOp tions; | |||
boost::program_options::variables_map _params; | boost::program_options::variables_map _params; | |||
}; | }; | |||
class BSONTool : public Tool { | ||||
bool _objcheck; | ||||
auto_ptr<Matcher> _matcher; | ||||
public: | ||||
BSONTool( const char * name , bool objcheck = false ); | ||||
virtual int doRun() = 0; | ||||
virtual void gotObject( const BSONObj& obj ) = 0; | ||||
virtual int run(); | ||||
long long processFile( const path& file ); | ||||
}; | ||||
} | } | |||
End of changes. 2 change blocks. | ||||
0 lines changed or deleted | 17 lines changed or added | |||