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, &current); sigaction(SIGTRAP, NULL, &current);
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

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/