balance.h   balance.h 
skipping to change at line 44 skipping to change at line 44
virtual void run(); virtual void run();
virtual string name() { return "Balancer"; } virtual string name() { return "Balancer"; }
private: private:
typedef BalancerPolicy::ChunkInfo CandidateChunk; typedef BalancerPolicy::ChunkInfo CandidateChunk;
typedef shared_ptr<CandidateChunk> CandidateChunkPtr; typedef shared_ptr<CandidateChunk> CandidateChunkPtr;
/** /**
* Returns true iff this mongos process gained (or maintained) the
* reponsibility moving chunks around.
*/
bool _shouldIBalance( DBClientBase& conn );
/**
* Gathers all the necessary information about shards and chunks, a nd * Gathers all the necessary information about shards and chunks, a nd
* decides whether there are candidate chunks to be moved. * decides whether there are candidate chunks to be moved.
*/ */
void _doBalanceRound( DBClientBase& conn, vector<CandidateChunkPtr> * candidateChunks ); void _doBalanceRound( DBClientBase& conn, vector<CandidateChunkPtr> * candidateChunks );
/** /**
* Execute the chunk migrations described in 'candidateChunks' and * Execute the chunk migrations described in 'candidateChunks' and
* returns the number of chunks effectively moved. * returns the number of chunks effectively moved.
*/ */
int _moveChunks( const vector<CandidateChunkPtr>* candidateChunks ) ; int _moveChunks( const vector<CandidateChunkPtr>* candidateChunks ) ;
 End of changes. 1 change blocks. 
6 lines changed or deleted 0 lines changed or added


 bson_db.h   bson_db.h 
skipping to change at line 44 skipping to change at line 44
Append a timestamp element to the object being ebuilt. Append a timestamp element to the object being ebuilt.
@param time - in millis (but stored in seconds) @param time - in millis (but stored in seconds)
*/ */
inline BSONObjBuilder& BSONObjBuilder::appendTimestamp( const char *fie ldName , unsigned long long time , unsigned int inc ){ inline BSONObjBuilder& BSONObjBuilder::appendTimestamp( const char *fie ldName , unsigned long long time , unsigned int inc ){
OpTime t( (unsigned) (time / 1000) , inc ); OpTime t( (unsigned) (time / 1000) , inc );
appendTimestamp( fieldName , t.asDate() ); appendTimestamp( fieldName , t.asDate() );
return *this; return *this;
} }
inline OpTime BSONElement::_opTime() const { inline OpTime BSONElement::_opTime() const {
return OpTime( *reinterpret_cast< const unsigned long long* >( valu if( type() == mongo::Date || type() == Timestamp )
e() ) ); return OpTime( *reinterpret_cast< const unsigned long long* >(
value() ) );
return OpTime();
} }
inline string BSONElement::_asCode() const { inline string BSONElement::_asCode() const {
switch( type() ){ switch( type() ){
case mongo::String: case mongo::String:
case Code: case Code:
return string(valuestr(), valuestrsize()-1); return string(valuestr(), valuestrsize()-1);
case CodeWScope: case CodeWScope:
return string(codeWScopeCode(), *(int*)(valuestr())-1); return string(codeWScopeCode(), *(int*)(valuestr())-1);
default: default:
 End of changes. 1 change blocks. 
2 lines changed or deleted 4 lines changed or added


 bsonelement.h   bsonelement.h 
skipping to change at line 87 skipping to change at line 87
void Val(mongo::OID& v) const { v = OID(); } void Val(mongo::OID& v) const { v = OID(); }
void Val(int& v) const { v = Int(); } void Val(int& v) const { v = Int(); }
void Val(double& v) const { v = Double(); } void Val(double& v) const { v = Double(); }
void Val(string& v) const { v = String(); } void Val(string& v) const { v = String(); }
/** Use ok() to check if a value is assigned: /** Use ok() to check if a value is assigned:
if( myObj["foo"].ok() ) ... if( myObj["foo"].ok() ) ...
*/ */
bool ok() const { return !eoo(); } bool ok() const { return !eoo(); }
string toString( bool includeFieldName = true ) const; string toString( bool includeFieldName = true, bool full=false) const;
operator string() const { return toString(); } operator string() const { return toString(); }
string jsonString( JsonStringFormat format, bool includeFieldNames = tr ue, int pretty = 0 ) const; string jsonString( JsonStringFormat format, bool includeFieldNames = tr ue, int pretty = 0 ) const;
/** Returns the type of the element */ /** Returns the type of the element */
BSONType type() const { return (BSONType) *data; } BSONType type() const { return (BSONType) *data; }
/** retrieve a field within this element /** retrieve a field within this element
throws exception if *this is not an embedded object throws exception if *this is not an embedded object
*/ */
BSONElement operator[] (const string& field) const; BSONElement operator[] (const string& field) const;
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 bsoninlines.h   bsoninlines.h 
skipping to change at line 22 skipping to change at line 22
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include <map> #include <map>
#include "util/atomic_int.h" #include "util/atomic_int.h"
#include "../util/hex.h"
namespace mongo { namespace mongo {
inline BSONObjIterator BSONObj::begin() { inline BSONObjIterator BSONObj::begin() {
return BSONObjIterator(*this); return BSONObjIterator(*this);
} }
inline BSONObj BSONElement::embeddedObjectUserCheck() const { inline BSONObj BSONElement::embeddedObjectUserCheck() const {
uassert( 10065 , "invalid parameter: expected an object", isABSONO bj() ); uassert( 10065 , "invalid parameter: expected an object", isABSONO bj() );
return BSONObj(value()); return BSONObj(value());
skipping to change at line 212 skipping to change at line 213
typedef set<BSONElement, BSONElementFieldNameCmp> BSONSortedElements; typedef set<BSONElement, BSONElementFieldNameCmp> BSONSortedElements;
inline BSONSortedElements bson2set( const BSONObj& obj ){ inline BSONSortedElements bson2set( const BSONObj& obj ){
BSONSortedElements s; BSONSortedElements s;
BSONObjIterator it(obj); BSONObjIterator it(obj);
while ( it.more() ) while ( it.more() )
s.insert( it.next() ); s.insert( it.next() );
return s; return s;
} }
inline string BSONObj::toString( bool isArray ) const { inline string BSONObj::toString( bool isArray, bool full ) const {
if ( isEmpty() ) return "{}"; if ( isEmpty() ) return "{}";
stringstream s; stringstream s;
s << ( isArray ? "[ " : "{ " ); s << ( isArray ? "[ " : "{ " );
BSONObjIterator i(*this); BSONObjIterator i(*this);
bool first = true; bool first = true;
while ( 1 ) { while ( 1 ) {
massert( 10327 , "Object does not end with EOO", i.moreWithEOO () ); massert( 10327 , "Object does not end with EOO", i.moreWithEOO () );
BSONElement e = i.next( true ); BSONElement e = i.next( true );
massert( 10328 , "Invalid element size", e.size() > 0 ); massert( 10328 , "Invalid element size", e.size() > 0 );
skipping to change at line 237 skipping to change at line 238
e.validate(); e.validate();
bool end = ( e.size() + offset == this->objsize() ); bool end = ( e.size() + offset == this->objsize() );
if ( e.eoo() ) { if ( e.eoo() ) {
massert( 10331 , "EOO Before end of object", end ); massert( 10331 , "EOO Before end of object", end );
break; break;
} }
if ( first ) if ( first )
first = false; first = false;
else else
s << ", "; s << ", ";
s << e.toString( !isArray ); s << e.toString( !isArray, full );
} }
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 {
const BSONType t = type(); const BSONType t = type();
skipping to change at line 364 skipping to change at line 365
ss << "BSONElement: bad type " << (int) type(); ss << "BSONElement: bad type " << (int) type();
string msg = ss.str(); string msg = ss.str();
massert( 10320 , msg.c_str(),false); massert( 10320 , msg.c_str(),false);
} }
} }
totalSize = x + fieldNameSize() + 1; // BSONType totalSize = x + fieldNameSize() + 1; // BSONType
return totalSize; return totalSize;
} }
inline string BSONElement::toString( bool includeFieldName ) const { inline string BSONElement::toString( bool includeFieldName, bool full ) const {
stringstream s; stringstream s;
if ( includeFieldName && type() != EOO ) if ( includeFieldName && type() != EOO )
s << fieldName() << ": "; s << fieldName() << ": ";
switch ( type() ) { switch ( type() ) {
case EOO: case EOO:
return "EOO"; return "EOO";
case mongo::Date: case mongo::Date:
s << "new Date(" << date() << ')'; s << "new Date(" << date() << ')';
break; break;
case RegEx: case RegEx:
skipping to change at line 403 skipping to change at line 404
case NumberLong: case NumberLong:
s << _numberLong(); s << _numberLong();
break; break;
case NumberInt: case NumberInt:
s << _numberInt(); s << _numberInt();
break; break;
case mongo::Bool: case mongo::Bool:
s << ( boolean() ? "true" : "false" ); s << ( boolean() ? "true" : "false" );
break; break;
case Object: case Object:
s << embeddedObject().toString(); s << embeddedObject().toString(false, full);
break; break;
case mongo::Array: case mongo::Array:
s << embeddedObject().toString( true ); s << embeddedObject().toString(true, full);
break; break;
case Undefined: case Undefined:
s << "undefined"; s << "undefined";
break; break;
case jstNULL: case jstNULL:
s << "null"; s << "null";
break; break;
case MaxKey: case MaxKey:
s << "MaxKey"; s << "MaxKey";
break; break;
case MinKey: case MinKey:
s << "MinKey"; s << "MinKey";
break; break;
case CodeWScope: case CodeWScope:
s << "CodeWScope( " s << "CodeWScope( "
<< codeWScopeCode() << ", " << codeWScopeObject().toString( ) << ")"; << codeWScopeCode() << ", " << codeWScopeObject().toString( false, full) << ")";
break; break;
case Code: case Code:
if ( valuestrsize() > 80 ) { if ( !full && valuestrsize() > 80 ) {
s.write(valuestr(), 70); s.write(valuestr(), 70);
s << "..."; s << "...";
} else { } else {
s.write(valuestr(), valuestrsize()-1); s.write(valuestr(), valuestrsize()-1);
} }
break; break;
case Symbol: case Symbol:
case mongo::String: case mongo::String:
s << '"'; s << '"';
if ( valuestrsize() > 80 ) { if ( !full && valuestrsize() > 80 ) {
s.write(valuestr(), 70); s.write(valuestr(), 70);
s << "...\""; s << "...\"";
} else { } else {
s.write(valuestr(), valuestrsize()-1); s.write(valuestr(), valuestrsize()-1);
s << '"'; s << '"';
} }
break; break;
case DBRef: case DBRef:
s << "DBRef('" << valuestr() << "',"; s << "DBRef('" << valuestr() << "',";
{ {
mongo::OID *x = (mongo::OID *) (valuestr() + valuestrsize() ); mongo::OID *x = (mongo::OID *) (valuestr() + valuestrsize() );
s << *x << ')'; s << *x << ')';
} }
break; break;
case jstOID: case jstOID:
s << "ObjectId('"; s << "ObjectId('";
s << __oid() << "')"; s << __oid() << "')";
break; break;
case BinData: case BinData:
s << "BinData"; s << "BinData";
if (full){
int len;
const char* data = binDataClean(len);
s << '(' << binDataType() << ", " << toHex(data, len) << ')
';
}
break; break;
case Timestamp: case Timestamp:
s << "Timestamp " << timestampTime() << "|" << timestampInc(); s << "Timestamp " << timestampTime() << "|" << timestampInc();
break; break;
default: default:
s << "?type=" << type(); s << "?type=" << type();
break; break;
} }
return s.str(); return s.str();
} }
 End of changes. 10 change blocks. 
8 lines changed or deleted 15 lines changed or added


 bsonobj.h   bsonobj.h 
skipping to change at line 90 skipping to change at line 90
~BSONObj() { _objdata = 0; } ~BSONObj() { _objdata = 0; }
void appendSelfToBufBuilder(BufBuilder& b) const { void appendSelfToBufBuilder(BufBuilder& b) const {
assert( objsize() ); assert( objsize() );
b.append(reinterpret_cast<const void *>( objdata() ), objsize() ); b.append(reinterpret_cast<const void *>( objdata() ), objsize() );
} }
/** Readable representation of a BSON object in an extended JSON-st yle notation. /** Readable representation of a BSON object in an extended JSON-st yle notation.
This is an abbreviated representation which might be used for l ogging. This is an abbreviated representation which might be used for l ogging.
*/ */
string toString( bool isArray = false ) const; string toString( bool isArray = false, bool full=false ) const;
operator string() const { return toString(); } operator string() const { return toString(); }
/** Properly formatted JSON string. /** Properly formatted JSON string.
@param pretty if true we try to add some lf's and indentation @param pretty if true we try to add some lf's and indentation
*/ */
string jsonString( JsonStringFormat format = Strict, int pretty = 0 ) const; string jsonString( JsonStringFormat format = Strict, int pretty = 0 ) const;
/** note: addFields always adds _id even if not specified */ /** note: addFields always adds _id even if not specified */
int addFields(BSONObj& from, set<string>& fields); /* returns n add ed */ int addFields(BSONObj& from, set<string>& fields); /* returns n add ed */
skipping to change at line 175 skipping to change at line 175
/** @return subobject of the given name */ /** @return subobject of the given name */
BSONObj getObjectField(const char *name) const; BSONObj getObjectField(const char *name) const;
/** @return INT_MIN if not present - does some type conversions */ /** @return INT_MIN if not present - does some type conversions */
int getIntField(const char *name) const; int getIntField(const char *name) const;
/** @return false if not present */ /** @return false if not present */
bool getBoolField(const char *name) const; bool getBoolField(const char *name) const;
/** makes a new BSONObj with the fields specified in pattern.
fields returned in the order they appear in pattern.
if any field is missing or undefined in the object, that field i
n the
output will be null.
sets output field names to match pattern field names.
If an array is encountered while scanning the dotted names in pa
ttern,
that field is treated as missing.
*/
BSONObj extractFieldsDotted(BSONObj pattern) const;
/** /**
sets element field names to empty string sets element field names to empty string
If a field in pattern is missing, it is omitted from the returne d If a field in pattern is missing, it is omitted from the returne d
object. object.
*/ */
BSONObj extractFieldsUnDotted(BSONObj pattern) const; BSONObj extractFieldsUnDotted(BSONObj pattern) const;
/** extract items from object which match a pattern object. /** extract items from object which match a pattern object.
e.g., if pattern is { x : 1, y : 1 }, builds an obje ct with e.g., if pattern is { x : 1, y : 1 }, builds an obje ct with
x and y elements of this object, if they are present . x and y elements of this object, if they are present .
 End of changes. 2 change blocks. 
14 lines changed or deleted 1 lines changed or added


 bsonobjbuilder.h   bsonobjbuilder.h 
skipping to change at line 138 skipping to change at line 138
/** add a subobject as a member */ /** add a subobject as a member */
BSONObjBuilder& append(const char *fieldName, BSONObj subObj) { BSONObjBuilder& append(const char *fieldName, BSONObj subObj) {
_b.append((char) Object); _b.append((char) Object);
_b.append(fieldName); _b.append(fieldName);
_b.append((void *) subObj.objdata(), subObj.objsize()); _b.append((void *) subObj.objdata(), subObj.objsize());
return *this; return *this;
} }
/** add a subobject as a member */ /** add a subobject as a member */
BSONObjBuilder& append(const string& fieldName , BSONObj subObj) { BSONObjBuilder& append(const string& fieldName , BSONObj subObj) {
return append( fieldName.c_str() , subObj ); _b.append((char) Object);
_b.append(fieldName.c_str(), fieldName.size()+1);
_b.append((void *) subObj.objdata(), subObj.objsize());
return *this;
} }
/** add header for a new subobject and return bufbuilder for writin g to /** add header for a new subobject and return bufbuilder for writin g to
the subobject's body */ the subobject's body */
BufBuilder &subobjStart(const char *fieldName) { BufBuilder &subobjStart(const char *fieldName) {
_b.append((char) Object); _b.append((char) Object);
_b.append(fieldName); _b.append(fieldName);
return _b; return _b;
} }
skipping to change at line 321 skipping to change at line 324
_b.append((char) Date); _b.append((char) Date);
_b.append(fieldName); _b.append(fieldName);
_b.append(static_cast<unsigned long long>(dt) * 1000); _b.append(static_cast<unsigned long long>(dt) * 1000);
return *this; return *this;
} }
/** Append a date. /** Append a date.
@param dt a Java-style 64 bit date value, that is @param dt a Java-style 64 bit date value, that is
the number of milliseconds since January 1, 1970, 00:00:00 GMT the number of milliseconds since January 1, 1970, 00:00:00 GMT
*/ */
BSONObjBuilder& appendDate(const char *fieldName, Date_t dt) { BSONObjBuilder& appendDate(const char *fieldName, Date_t dt) {
/* easy to pass a time_t to this and get a bad result. thus th
is warning. */
#if defined(_DEBUG) && defined(MONGO_EXPOSE_MACROS)
if( dt > 0 && dt <= 0xffffffff ) {
static int n;
if( n++ == 0 )
log() << "DEV WARNING appendDate() called with a tiny (
but nonzero) date" << endl;
}
#endif
_b.append((char) Date); _b.append((char) Date);
_b.append(fieldName); _b.append(fieldName);
_b.append(dt); _b.append(dt);
return *this; return *this;
} }
BSONObjBuilder& append(const char *fieldName, Date_t dt) { BSONObjBuilder& append(const char *fieldName, Date_t dt) {
return appendDate(fieldName, dt); return appendDate(fieldName, dt);
} }
/** Append a regular expression value /** Append a regular expression value
 End of changes. 2 change blocks. 
1 lines changed or deleted 14 lines changed or added


 bsonobjiterator.h   bsonobjiterator.h 
skipping to change at line 20 skipping to change at line 20
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
namespace mongo { #include <boost/preprocessor/cat.hpp> // like the ## operator but works wit h __LINE__
namespace mongo {
/** iterator for a BSONObj /** iterator for a BSONObj
Note each BSONObj ends with an EOO element: so you will get more() o n an empty Note each BSONObj ends with an EOO element: so you will get more() o n an empty
object, although next().eoo() will be true. object, although next().eoo() will be true.
todo: we may want to make a more stl-like iterator interface for thi s todo: we may want to make a more stl-like iterator interface for thi s
with things like begin() and end() with things like begin() and end()
*/ */
class BSONObjIterator { class BSONObjIterator {
public: public:
skipping to change at line 104 skipping to change at line 105
return BSONElement( _fields[_cur++] ); return BSONElement( _fields[_cur++] );
return BSONElement(); return BSONElement();
} }
private: private:
const char ** _fields; const char ** _fields;
int _nfields; int _nfields;
int _cur; int _cur;
}; };
/** Similar to BOOST_FOREACH
*
* because the iterator is defined outside of the for, you must use {} aro
und
* the surrounding scope. Don't do this:
*
* if (foo)
* BSONForEach(e, obj)
* doSomething(e);
*
* but this is OK:
*
* if (foo) {
* BSONForEach(e, obj)
* doSomething(e);
* }
*
*/
#define BSONForEach(e, obj) \
BSONObjIterator BOOST_PP_CAT(it_,__LINE__)(obj); \
for ( BSONElement e; \
(BOOST_PP_CAT(it_,__LINE__).more() ? \
(e = BOOST_PP_CAT(it_,__LINE__).next(), true) : \
false) ; \
/*nothing*/ )
} }
 End of changes. 3 change blocks. 
1 lines changed or deleted 29 lines changed or added


 btree.h   btree.h 
skipping to change at line 237 skipping to change at line 237
/** /**
* find the first instance of the key * find the first instance of the key
* does not handle dups * does not handle dups
* returned DiskLock isNull if can't find anything with that * returned DiskLock isNull if can't find anything with that
*/ */
DiskLoc findSingle( const IndexDetails& , const DiskLoc& thisLoc, c onst BSONObj& key ); DiskLoc findSingle( const IndexDetails& , const DiskLoc& thisLoc, c onst BSONObj& key );
/* advance one key position in the index: */ /* advance one key position in the index: */
DiskLoc advance(const DiskLoc& thisLoc, int& keyOfs, int direction, const char *caller); DiskLoc advance(const DiskLoc& thisLoc, int& keyOfs, int direction, const char *caller);
void advanceTo(const IndexDetails &id, DiskLoc &thisLoc, int &keyOf
s, const BSONObj &keyBegin, int keyBeginLen, const vector< const BSONElemen
t * > &keyEnd, const Ordering &order, int direction );
DiskLoc getHead(const DiskLoc& thisLoc); DiskLoc getHead(const DiskLoc& thisLoc);
/* get tree shape */ /* get tree shape */
void shape(stringstream&); void shape(stringstream&);
static void a_test(IndexDetails&); static void a_test(IndexDetails&);
private: private:
void fixParentPtrs(const DiskLoc& thisLoc); void fixParentPtrs(const DiskLoc& thisLoc);
void delBucket(const DiskLoc& thisLoc, IndexDetails&); void delBucket(const DiskLoc& thisLoc, IndexDetails&);
skipping to change at line 259 skipping to change at line 262
return keyOfs >= n ? BSONObj() : keyNode(keyOfs).key; return keyOfs >= n ? BSONObj() : keyNode(keyOfs).key;
} }
static BtreeBucket* allocTemp(); /* caller must release with free() */ static BtreeBucket* allocTemp(); /* caller must release with free() */
void insertHere(DiskLoc thisLoc, int keypos, void insertHere(DiskLoc thisLoc, int keypos,
DiskLoc recordLoc, const BSONObj& key, const Orderi ng &order, DiskLoc recordLoc, const BSONObj& key, const Orderi ng &order,
DiskLoc lchild, DiskLoc rchild, IndexDetails&); DiskLoc lchild, DiskLoc rchild, IndexDetails&);
int _insert(DiskLoc thisLoc, DiskLoc recordLoc, int _insert(DiskLoc thisLoc, DiskLoc recordLoc,
const BSONObj& key, const Ordering &order, bool dupsAll owed, const BSONObj& key, const Ordering &order, bool dupsAll owed,
DiskLoc lChild, DiskLoc rChild, IndexDetails&); DiskLoc lChild, DiskLoc rChild, IndexDetails&);
bool find(const IndexDetails& idx, const BSONObj& key, DiskLoc reco rdLoc, const Ordering &order, int& pos, bool assertIfDup); bool find(const IndexDetails& idx, const BSONObj& key, DiskLoc reco rdLoc, const Ordering &order, int& pos, bool assertIfDup);
bool customFind( int l, int h, const BSONObj &keyBegin, int keyBegi nLen, const vector< const BSONElement * > &keyEnd, const Ordering &order, i nt direction, DiskLoc &thisLoc, int &keyOfs, pair< DiskLoc, int > &bestPare nt );
static void findLargestKey(const DiskLoc& thisLoc, DiskLoc& largest Loc, int& largestKey); static void findLargestKey(const DiskLoc& thisLoc, DiskLoc& largest Loc, int& largestKey);
static int customBSONCmp( const BSONObj &l, const BSONObj &rBegin, int rBeginLen, const vector< const BSONElement * > &rEnd, const Ordering &o );
public: public:
// simply builds and returns a dup key error message string // simply builds and returns a dup key error message string
static string dupKeyError( const IndexDetails& idx , const BSONObj& key ); static string dupKeyError( const IndexDetails& idx , const BSONObj& key );
}; };
#pragma pack() #pragma pack()
class BtreeCursor : public Cursor { class BtreeCursor : public Cursor {
public: public:
BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int direction ); BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int direction );
BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails& _id, const BoundList &_bounds, int _direction ); BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails& _id, const shared_ptr< FieldRangeVector > &_bounds, int _direction );
~BtreeCursor(){ ~BtreeCursor(){
} }
virtual bool ok() { virtual bool ok() {
return !bucket.isNull(); return !bucket.isNull();
} }
bool eof() { bool eof() {
return !ok(); return !ok();
} }
virtual bool advance(); virtual bool advance();
skipping to change at line 337 skipping to change at line 342
} }
virtual Record* _current() { virtual Record* _current() {
return currLoc().rec(); return currLoc().rec();
} }
virtual BSONObj current() { virtual BSONObj current() {
return BSONObj(_current()); return BSONObj(_current());
} }
virtual string toString() { virtual string toString() {
string s = string("BtreeCursor ") + indexDetails.indexName(); string s = string("BtreeCursor ") + indexDetails.indexName();
if ( direction < 0 ) s += " reverse"; if ( direction < 0 ) s += " reverse";
if ( bounds_.size() > 1 ) s += " multi"; if ( bounds_.get() && bounds_->size() > 1 ) s += " multi";
return s; return s;
} }
BSONObj prettyKey( const BSONObj &key ) const { BSONObj prettyKey( const BSONObj &key ) const {
return key.replaceFieldNames( indexDetails.keyPattern() ).clien tReadable(); return key.replaceFieldNames( indexDetails.keyPattern() ).clien tReadable();
} }
virtual BSONArray prettyIndexBounds() const { virtual BSONObj prettyIndexBounds() const {
BSONArrayBuilder ba; if ( !_independentFieldRanges ) {
if ( bounds_.size() == 0 ) { return BSON( "start" << prettyKey( startKey ) << "end" << p
ba << BSON_ARRAY( prettyKey( startKey ) << prettyKey( endKe rettyKey( endKey ) );
y ) );
} else { } else {
for( BoundList::const_iterator i = bounds_.begin(); i != bo return bounds_->obj();
unds_.end(); ++i ) {
ba << BSON_ARRAY( prettyKey( i->first ) << prettyKey( i
->second ) );
}
} }
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( shared_ptr< CoveredIndexMatcher > matcher ) { virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) {
_matcher = matcher; _matcher = matcher;
} }
// for debugging only // for debugging only
DiskLoc getBucket() const { return bucket; } DiskLoc getBucket() const { return bucket; }
private: private:
/* Our btrees may (rarely) have "unused" keys when items are delete d. /* Our btrees may (rarely) have "unused" keys when items are delete d.
Skip past them. Skip past them.
*/ */
void skipUnusedKeys(); bool skipUnusedKeys( bool mayJump );
bool skipOutOfRangeKeysAndCheckEnd();
/* Check if the current key is beyond endKey. */ void skipAndCheck();
void checkEnd(); void checkEnd();
// selective audits on construction // selective audits on construction
void audit(); void audit();
// set initial bucket // set initial bucket
void init(); void init();
// init start / end keys with a new range void advanceTo( const BSONObj &keyBegin, int keyBeginLen, const vec
void initInterval(); tor< const BSONElement * > &keyEnd);
friend class BtreeBucket; friend class BtreeBucket;
set<DiskLoc> dups; set<DiskLoc> dups;
NamespaceDetails *d; NamespaceDetails *d;
int idxNo; int idxNo;
BSONObj startKey; BSONObj startKey;
BSONObj endKey; BSONObj endKey;
bool endKeyInclusive_; bool endKeyInclusive_;
bool multikey; // note this must be updated every getmore batch in case someone added a multikey... bool multikey; // note this must be updated every getmore batch in case someone added a multikey...
const IndexDetails& indexDetails; const IndexDetails& indexDetails;
BSONObj order; BSONObj order;
Ordering _ordering;
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_; shared_ptr< FieldRangeVector > bounds_;
unsigned boundIndex_; auto_ptr< FieldRangeVector::Iterator > _boundsIterator;
const IndexSpec& _spec; const IndexSpec& _spec;
shared_ptr< CoveredIndexMatcher > _matcher; shared_ptr< CoveredIndexMatcher > _matcher;
bool _independentFieldRanges;
}; };
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. 15 change blocks. 
20 lines changed or deleted 25 lines changed or added


 builder.h   builder.h 
skipping to change at line 117 skipping to change at line 117
void setlen( int newLen ){ void setlen( int newLen ){
l = newLen; l = newLen;
} }
/* returns the pre-grow write position */ /* returns the pre-grow write position */
char* grow(int by) { char* grow(int by) {
int oldlen = l; int oldlen = l;
l += by; l += by;
if ( l > size ) { if ( l > size ) {
int a = size * 2; grow_reallocate();
if ( a == 0 )
a = 512;
if ( l > a )
a = l + 16 * 1024;
if( a > 64 * 1024 * 1024 )
msgasserted(10000, "BufBuilder grow() > 64MB");
data = (char *) realloc(data, a);
size= a;
} }
return data + oldlen; return data + oldlen;
} }
/* "slow" portion of 'grow()' */
void grow_reallocate() {
int a = size * 2;
if ( a == 0 )
a = 512;
if ( l > a )
a = l + 16 * 1024;
if( a > 64 * 1024 * 1024 )
msgasserted(10000, "BufBuilder grow() > 64MB");
data = (char *) realloc(data, a);
size= a;
}
int getSize() const { return size; } 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;
}; };
 End of changes. 2 change blocks. 
9 lines changed or deleted 14 lines changed or added


 chunk.h   chunk.h 
skipping to change at line 33 skipping to change at line 33
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "../client/dbclient.h" #include "../client/dbclient.h"
#include "../client/model.h" #include "../client/model.h"
#include "../bson/util/atomic_int.h" #include "../bson/util/atomic_int.h"
#include "shardkey.h" #include "shardkey.h"
#include "shard.h" #include "shard.h"
#include "config.h" #include "config.h"
#include "util.h"
namespace mongo { namespace mongo {
class DBConfig; class DBConfig;
class Chunk; class Chunk;
class ChunkRange; class ChunkRange;
class ChunkManager; class ChunkManager;
class ChunkRangeMangager; class ChunkRangeMangager;
class ChunkObjUnitTest; class ChunkObjUnitTest;
struct ShardChunkVersion {
union {
struct {
int _minor;
int _major;
};
unsigned long long _combined;
};
ShardChunkVersion( int major=0, int minor=0 )
: _minor(minor),_major(major){
}
ShardChunkVersion( unsigned long long ll )
: _combined( ll ){
}
ShardChunkVersion incMajor() const {
return ShardChunkVersion( _major + 1 , 0 );
}
void operator++(){
_minor++;
}
unsigned long long toLong() const {
return _combined;
}
bool isSet() const {
return _combined > 0;
}
string toString() const {
stringstream ss;
ss << _major << "|" << _minor;
return ss.str();
}
operator unsigned long long() const { return _combined; }
operator string() const { return toString(); }
ShardChunkVersion& operator=( const BSONElement& elem ){
switch ( elem.type() ){
case Timestamp:
case NumberLong:
case Date:
_combined = elem._numberLong();
break;
case EOO:
_combined = 0;
break;
default:
assert(0);
}
return *this;
}
};
typedef shared_ptr<Chunk> ChunkPtr; typedef shared_ptr<Chunk> ChunkPtr;
// key is max for each Chunk or ChunkRange // key is max for each Chunk or ChunkRange
typedef map<BSONObj,ChunkPtr,BSONObjCmp> ChunkMap; typedef map<BSONObj,ChunkPtr,BSONObjCmp> ChunkMap;
typedef map<BSONObj,shared_ptr<ChunkRange>,BSONObjCmp> ChunkRangeMap; typedef map<BSONObj,shared_ptr<ChunkRange>,BSONObjCmp> ChunkRangeMap;
/** /**
config.chunks config.chunks
{ ns : "alleyinsider.fs.chunks" , min : {} , max : {} , server : "lo calhost:30001" } { ns : "alleyinsider.fs.chunks" , min : {} , max : {} , server : "lo calhost:30001" }
skipping to change at line 148 skipping to change at line 90
string toString() const; string toString() const;
operator string() const { return toString(); } operator string() const { return toString(); }
friend ostream& operator << (ostream& out, const Chunk& c){ return (out << c.toString()); } friend ostream& operator << (ostream& out, const Chunk& c){ return (out << c.toString()); }
bool operator==(const Chunk& s) const; bool operator==(const Chunk& s) const;
bool operator!=(const Chunk& s) const{ bool operator!=(const Chunk& s) const{
return ! ( *this == s ); return ! ( *this == s );
} }
void getFilter( BSONObjBuilder& b ) const;
BSONObj getFilter() const{ BSONObjBuilder b; getFilter( b ); return
b.obj(); }
// if min/max key is pos/neg infinity // if min/max key is pos/neg infinity
bool minIsInf() const; bool minIsInf() const;
bool maxIsInf() const; bool maxIsInf() const;
BSONObj pickSplitPoint() const; BSONObj pickSplitPoint() const;
ChunkPtr split(); ChunkPtr split();
ChunkPtr split( const BSONObj& middle );
void pickSplitVector( vector<BSONObj>* splitPoints ) const;
ChunkPtr multiSplit( const vector<BSONObj>& splitPoints );
/** /**
* @return size of shard in bytes * @return size of shard in bytes
* talks to mongod to do this * talks to mongod to do this
*/ */
long getPhysicalSize() const; long getPhysicalSize() const;
long countObjects( const BSONObj& filter = BSONObj() ) const; int countObjects(int maxcount=0) const;
/** /**
* if the amount of data written nears the max size of a shard * if the amount of data written nears the max size of a shard
* then we check the real size, and if its too big, we split * then we check the real size, and if its too big, we split
*/ */
bool splitIfShould( long dataWritten ); bool splitIfShould( long dataWritten );
/* /*
* moves either this shard or newShard if it makes sense too * moves either this shard or newShard if it makes sense too
* @return whether or not a shard was moved * @return whether or not a shard was moved
*/ */
bool moveIfShould( ChunkPtr newShard = ChunkPtr() ); bool moveIfShould( ChunkPtr newShard = ChunkPtr() );
bool moveAndCommit( const Shard& to , string& errmsg ); bool moveAndCommit( const Shard& to , string& errmsg );
const char * getNS(){ return "config.chunks"; } const char * getNS(){ return "config.chunks"; }
void serialize(BSONObjBuilder& to, ShardChunkVersion myLastMod=0); void serialize(BSONObjBuilder& to, ShardChunkVersion myLastMod=0);
void unserialize(const BSONObj& from); void unserialize(const BSONObj& from);
string modelServer(); string modelServer() const;
void appendShortVersion( const char * name , BSONObjBuilder& b ); void appendShortVersion( const char * name , BSONObjBuilder& b );
void ensureIndex(); void ensureIndex();
void _markModified(); void _markModified();
static int MaxChunkSize; static int MaxChunkSize;
string genID(); string genID() const;
static string genID( const string& ns , const BSONObj& min ); static string genID( const string& ns , const BSONObj& min );
const ChunkManager* getManager() const { return _manager; } const ChunkManager* getManager() const { return _manager; }
bool modified(); bool modified();
ShardChunkVersion getVersionOnConfigServer() const;
private: private:
bool _splitIfShould( long dataWritten );
// main shard info // main shard info
ChunkManager * _manager; ChunkManager * _manager;
ShardKeyPattern skey() const; ShardKeyPattern skey() const;
BSONObj _min; BSONObj _min;
BSONObj _max; BSONObj _max;
Shard _shard; Shard _shard;
ShardChunkVersion _lastmod; ShardChunkVersion _lastmod;
skipping to change at line 236 skipping to change at line 181
class ChunkRange{ class ChunkRange{
public: public:
const ChunkManager* getManager() const{ return _manager; } const ChunkManager* getManager() const{ return _manager; }
Shard getShard() const{ return _shard; } Shard getShard() const{ return _shard; }
const BSONObj& getMin() const { return _min; } const BSONObj& getMin() const { return _min; }
const BSONObj& getMax() const { return _max; } const BSONObj& getMax() const { return _max; }
// clones of Chunk methods // clones of Chunk methods
bool contains(const BSONObj& obj) const; bool contains(const BSONObj& obj) const;
void getFilter( BSONObjBuilder& b ) const;
BSONObj getFilter() const{ BSONObjBuilder b; getFilter( b ); return
b.obj(); }
long countObjects( const BSONObj& filter = BSONObj() ) const;
ChunkRange(ChunkMap::const_iterator begin, const ChunkMap::const_it erator end) ChunkRange(ChunkMap::const_iterator begin, const ChunkMap::const_it erator end)
: _manager(begin->second->getManager()) : _manager(begin->second->getManager())
, _shard(begin->second->getShard()) , _shard(begin->second->getShard())
, _min(begin->second->getMin()) , _min(begin->second->getMin())
, _max(prior(end)->second->getMax()) , _max(prior(end)->second->getMax())
{ {
assert( begin != end ); assert( begin != end );
DEV while (begin != end){ DEV while (begin != end){
skipping to change at line 324 skipping to change at line 266
int numChunks(){ rwlock lk( _lock , false ); return _chunkMap.size( ); } int numChunks(){ rwlock lk( _lock , false ); return _chunkMap.size( ); }
bool hasShardKey( const BSONObj& obj ); bool hasShardKey( const BSONObj& obj );
ChunkPtr findChunk( const BSONObj& obj , bool retry = false ); ChunkPtr findChunk( const BSONObj& obj , bool retry = false );
ChunkPtr findChunkOnServer( const Shard& shard ) const; ChunkPtr findChunkOnServer( const Shard& shard ) const;
ShardKeyPattern& getShardKey(){ return _key; } ShardKeyPattern& getShardKey(){ return _key; }
const ShardKeyPattern& getShardKey() const { return _key; } const ShardKeyPattern& getShardKey() const { return _key; }
bool isUnique(){ return _unique; } bool isUnique(){ return _unique; }
void maybeChunkCollection();
/** /**
* makes sure the shard index is on all servers * makes sure the shard index is on all servers
*/ */
void ensureIndex(); void ensureIndex();
/** void getShardsForQuery( set<Shard>& shards , const BSONObj& query )
* @return number of Chunk added to the vector ;
*/
int getChunksForQuery( vector<shared_ptr<ChunkRange> >& chunks , co
nst BSONObj& query );
/**
* @return number of Shards added to the set
*/
int getShardsForQuery( set<Shard>& shards , const BSONObj& query );
void getAllShards( set<Shard>& all ); void getAllShards( set<Shard>& all );
void save(); void save();
string toString() const; string toString() const;
operator string() const { return toString(); } operator string() const { return toString(); }
ShardChunkVersion getVersion( const Shard& shard ) const; ShardChunkVersion getVersion( const Shard& shard ) const;
ShardChunkVersion getVersion() const; ShardChunkVersion getVersion() const;
/** /**
* actually does a query on the server
* doesn't look at any local data
*/
ShardChunkVersion getVersionOnConfigServer() const;
/**
* this is just an increasing number of how many ChunkManagers we h ave so we know if something has been updated * this is just an increasing number of how many ChunkManagers we h ave so we know if something has been updated
*/ */
unsigned long long getSequenceNumber(){ unsigned long long getSequenceNumber(){
return _sequenceNumber; return _sequenceNumber;
} }
/** /**
* @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 );
skipping to change at line 397 skipping to change at line 339
RWLock _lock; RWLock _lock;
// This should only be called from Chunk after it has been migrated // This should only be called from Chunk after it has been migrated
void _migrationNotification(Chunk* c); void _migrationNotification(Chunk* c);
friend class Chunk; friend class Chunk;
friend class ChunkRangeManager; // only needed for CRM::assertValid () friend class ChunkRangeManager; // only needed for CRM::assertValid ()
static AtomicUInt NextSequenceNumber; static AtomicUInt NextSequenceNumber;
bool _isValid() const; bool _isValid() const;
/**
* @return number of Chunk matching the query or -1 for all chunks.
*/
int _getChunksForQuery( vector<shared_ptr<ChunkRange> >& chunks , c
onst BSONObj& query );
}; };
// like BSONObjCmp. for use as an STL comparison functor // like BSONObjCmp. for use as an STL comparison functor
// key-order in "order" argument must match key-order in shardkey // key-order in "order" argument must match key-order in shardkey
class ChunkCmp { class ChunkCmp {
public: public:
ChunkCmp( const BSONObj &order = BSONObj() ) : _cmp( order ) {} ChunkCmp( const BSONObj &order = BSONObj() ) : _cmp( order ) {}
bool operator()( const Chunk &l, const Chunk &r ) const { bool operator()( const Chunk &l, const Chunk &r ) const {
return _cmp(l.getMin(), r.getMin()); return _cmp(l.getMin(), r.getMin());
} }
skipping to change at line 436 skipping to change at line 373
/* /*
struct chunk_lock { struct chunk_lock {
chunk_lock( const Chunk* c ){ chunk_lock( const Chunk* c ){
} }
Chunk _c; Chunk _c;
}; };
*/ */
inline string Chunk::genID(){ return genID(_manager->getns(), _min); } inline string Chunk::genID() const { return genID(_manager->getns(), _m in); }
} // namespace mongo } // namespace mongo
 End of changes. 15 change blocks. 
88 lines changed or deleted 22 lines changed or added


 client.h   client.h 
skipping to change at line 157 skipping to change at line 157
_finishInit(); _finishInit();
} }
friend class CurOp; friend class CurOp;
}; };
private: private:
CurOp * _curOp; CurOp * _curOp;
Context * _context; Context * _context;
bool _shutdown; bool _shutdown;
list<string> _tempCollections; set<string> _tempCollections;
const char *_desc; const char *_desc;
bool _god; bool _god;
AuthenticationInfo _ai; AuthenticationInfo _ai;
ReplTime _lastOp; ReplTime _lastOp;
BSONObj _handshake; BSONObj _handshake;
BSONObj _remoteId; BSONObj _remoteId;
void _dropns( const string& ns );
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_ void addTempCollection( const string& ns );
back( ns ); }
void dropTempCollectionsInDB(const string db); void _invalidateDB(const string& db);
void dropAllTempCollectionsInDB(const string db); static void invalidateDB(const string& db);
static void invalidateNS( const string& ns );
void setLastOp( ReplTime op ) { void setLastOp( ReplTime op ) {
_lastOp = op; _lastOp = op;
} }
ReplTime getLastOp() const { ReplTime getLastOp() const {
return _lastOp; return _lastOp;
} }
void appendLastOp( BSONObjBuilder& b ) { void appendLastOp( BSONObjBuilder& b ) {
 End of changes. 3 change blocks. 
5 lines changed or deleted 9 lines changed or added


 clientcursor.h   clientcursor.h 
skipping to change at line 105 skipping to change at line 105
uassert(12051, "clientcursor already in use? driver problem?", false); uassert(12051, "clientcursor already in use? driver problem?", false);
} }
_c->_pinValue += 100; _c->_pinValue += 100;
} }
} }
~Pointer() { ~Pointer() {
release(); release();
} }
}; };
// This object assures safe and reliable cleanup of the ClientCurso
r.
// The implementation assumes that there will be no duplicate ids a
mong cursors
// (which is assured if cursors must last longer than 1 second).
class CleanupPointer : boost::noncopyable {
public:
CleanupPointer() : _c( 0 ), _id( -1 ) {}
void reset( ClientCursor *c = 0 ) {
if ( c == _c ) {
return;
}
if ( _c ) {
// be careful in case cursor was deleted by someone els
e
ClientCursor::erase( _id );
}
if ( c ) {
_c = c;
_id = c->cursorid;
} else {
_c = 0;
_id = -1;
}
}
~CleanupPointer() {
DESTRUCTOR_GUARD ( reset(); );
}
operator bool() { return _c; }
ClientCursor * operator-> () { return _c; }
private:
ClientCursor *_c;
CursorId _id;
};
/*const*/ CursorId cursorid; /*const*/ CursorId cursorid;
string ns; string ns;
shared_ptr<Cursor> c; shared_ptr<Cursor> c;
int pos; // # objects into the cursor so far int pos; // # objects into the cursor so far
BSONObj query; BSONObj query;
int _queryOptions; // see enum QueryOptions dbclient.h 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 string & _ns) :
_idleAgeMillis(0), _pinValue(0), _idleAgeMillis(0), _pinValue(0),
_doingDeletes(false), _yieldSometimesTracker(128,10), _doingDeletes(false), _yieldSometimesTracker(128,10),
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();
recursive_scoped_lock lock(ccmutex); recursive_scoped_lock lock(ccmutex);
cursorid = allocCursorId_inlock(); cursorid = allocCursorId_inlock();
clientCursorsById.insert( make_pair(cursorid, this) ); clientCursorsById.insert( make_pair(cursorid, this) );
skipping to change at line 158 skipping to change at line 192
* if false is returned, then this ClientCursor should be c onsidered deleted - * if false is returned, then this ClientCursor should be c onsidered deleted -
* in fact, the whole database could be gone. * in fact, the whole database could be gone.
*/ */
bool yield( int microsToSleep = -1 ); bool yield( int microsToSleep = -1 );
/** /**
* @return same as yield() * @return same as yield()
*/ */
bool yieldSometimes(); bool yieldSometimes();
static int yieldSuggest();
static void staticYield( int micros );
struct YieldData { CursorId _id; bool _doingDeletes; };
void prepareToYield( YieldData &data );
static bool recoverFromYield( const YieldData &data );
struct YieldLock : boost::noncopyable { struct YieldLock : boost::noncopyable {
explicit YieldLock( ptr<ClientCursor> cc ) explicit YieldLock( ptr<ClientCursor> cc )
: _cc( cc ) , _id( cc->cursorid ) , _doingDeletes( cc->_doi ngDeletes ) { : _cc( cc ) , _id( cc->cursorid ) , _doingDeletes( cc->_doi ngDeletes ) {
cc->updateLocation(); cc->updateLocation();
_unlock.reset(new dbtempreleasecond()); _unlock.reset(new dbtempreleasecond());
} }
~YieldLock(){ ~YieldLock(){
assert( ! _unlock ); if ( _unlock ){
log( LL_WARNING ) << "ClientCursor::YieldLock not close
d properly" << endl;
relock();
}
} }
bool stillOk(){ bool stillOk(){
relock(); relock();
if ( ClientCursor::find( _id , false ) == 0 ){ if ( ClientCursor::find( _id , false ) == 0 ){
// i was deleted // i was deleted
return false; return false;
} }
 End of changes. 4 change blocks. 
2 lines changed or deleted 50 lines changed or added


 cmdline.h   cmdline.h 
skipping to change at line 47 skipping to change at line 47
bool smallfiles; // --smallfiles bool smallfiles; // --smallfiles
bool quota; // --quota bool quota; // --quota
int quotaFiles; // --quotaFiles int quotaFiles; // --quotaFiles
bool cpu; // --cpu show cpu time periodically bool cpu; // --cpu show cpu time periodically
long long oplogSize; // --oplogSize long long oplogSize; // --oplogSize
int defaultProfile; // --profile int defaultProfile; // --profile
int slowMS; // --time in ms that is "slow" int slowMS; // --time in ms that is "slow"
int pretouch; // --pretouch for replication application (e
xperimental)
enum { enum {
DefaultDBPort = 27017, DefaultDBPort = 27017,
ConfigServerPort = 27019, ConfigServerPort = 27019,
ShardServerPort = 27018 ShardServerPort = 27018
}; };
CmdLine() : CmdLine() :
port(DefaultDBPort), rest(false), quiet(false), notablescan(fal se), prealloc(true), smallfiles(false), port(DefaultDBPort), rest(false), quiet(false), notablescan(fal se), prealloc(true), smallfiles(false),
quota(false), quotaFiles(8), cpu(false), oplogSize(0), defaultP rofile(0), slowMS(100) quota(false), quotaFiles(8), cpu(false), oplogSize(0), defaultP rofile(0), slowMS(100)
{ } { }
 End of changes. 1 change blocks. 
0 lines changed or deleted 3 lines changed or added


 commands.h   commands.h 
skipping to change at line 115 skipping to change at line 115
protected: protected:
BSONObj getQuery( const BSONObj& cmdObj ){ BSONObj getQuery( const BSONObj& cmdObj ){
if ( cmdObj["query"].type() == Object ) if ( cmdObj["query"].type() == Object )
return cmdObj["query"].embeddedObject(); return cmdObj["query"].embeddedObject();
if ( cmdObj["q"].type() == Object ) if ( cmdObj["q"].type() == Object )
return cmdObj["q"].embeddedObject(); return cmdObj["q"].embeddedObject();
return BSONObj(); return BSONObj();
} }
void logIfSlow( const string& msg) const; static void logIfSlow( const Timer& cmdTimer, const string& msg);
static map<string,Command*> * _commands; static map<string,Command*> * _commands;
static map<string,Command*> * _commandsByBestName; static map<string,Command*> * _commandsByBestName;
static map<string,Command*> * _webCommands; static map<string,Command*> * _webCommands;
Timer _timer; // started right before call
ing run
public: public:
static const map<string,Command*>* commandsByBestName() { return _c ommandsByBestName; } static const map<string,Command*>* commandsByBestName() { return _c ommandsByBestName; }
static const map<string,Command*>* webCommands() { return _webComma nds; } static const map<string,Command*>* webCommands() { return _webComma nds; }
static bool runAgainstRegistered(const char *ns, BSONObj& jsobj, BS ONObjBuilder& anObjBuilder); static bool runAgainstRegistered(const char *ns, BSONObj& jsobj, BS ONObjBuilder& anObjBuilder);
static LockType locktype( const string& name ); static LockType locktype( const string& name );
static Command * findCommand( const string& name ); static Command * findCommand( const string& name );
}; };
bool _runCommands(const char *ns, BSONObj& jsobj, BufBuilder &b, BSONOb jBuilder& anObjBuilder, bool fromRepl, int queryOptions); bool _runCommands(const char *ns, BSONObj& jsobj, BufBuilder &b, BSONOb jBuilder& anObjBuilder, bool fromRepl, int queryOptions);
 End of changes. 2 change blocks. 
4 lines changed or deleted 1 lines changed or added


 core.h   core.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 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
#include "../../pch.h" #include "../../pch.h"
#include "../jsobj.h" #include "../jsobj.h"
#include <cmath>
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif
namespace mongo { namespace mongo {
class GeoBitSets { class GeoBitSets {
public: public:
GeoBitSets(){ GeoBitSets(){
for ( int i=0; i<32; i++ ){ for ( int i=0; i<32; i++ ){
masks32[i] = ( 1 << ( 31 - i ) ); masks32[i] = ( 1 << ( 31 - i ) );
} }
for ( int i=0; i<64; i++ ){ for ( int i=0; i<64; i++ ){
masks64[i] = ( 1LL << ( 63 - i ) ); masks64[i] = ( 1LL << ( 63 - i ) );
skipping to change at line 380 skipping to change at line 388
string toString() const { string toString() const {
StringBuilder buf(32); StringBuilder buf(32);
buf << "(" << _x << "," << _y << ")"; buf << "(" << _x << "," << _y << ")";
return buf.str(); return buf.str();
} }
double _x; double _x;
double _y; double _y;
}; };
// WARNING: _x and _y MUST be longitude and latitude in that order
inline double spheredist_rad( const Point& p1, const Point& p2 ) {
// this uses the n-vector formula: http://en.wikipedia.org/wiki/N-v
ector
// If you try to match the code to the formula, note that I inline
the cross-product.
// TODO: optimize with SSE
double sin_x1(sin(p1._x)), cos_x1(cos(p1._x));
double sin_y1(sin(p1._y)), cos_y1(cos(p1._y));
double sin_x2(sin(p2._x)), cos_x2(cos(p2._x));
double sin_y2(sin(p2._y)), cos_y2(cos(p2._y));
double cross_prod =
(cos_y1*cos_x1 * cos_y2*cos_x2) +
(cos_y1*sin_x1 * cos_y2*sin_x2) +
(sin_y1 * sin_y2);
return acos(cross_prod);
}
// note: return is still in radians as that can be multiplied by radius
to get arc length
inline double spheredist_deg( const Point& p1, const Point& p2 ) {
return spheredist_rad(
Point( p1._x * (M_PI/180), p1._y * (M_PI/180)),
Point( p2._x * (M_PI/180), p2._y * (M_PI/180))
);
}
} }
 End of changes. 3 change blocks. 
0 lines changed or deleted 38 lines changed or added


 cursor.h   cursor.h 
skipping to change at line 94 skipping to change at line 94
/* used for multikey index traversal to avoid sending back dups. se e Matcher::matches(). /* used for multikey index traversal to avoid sending back dups. se e Matcher::matches().
if a multikey index traversal: if a multikey index traversal:
if loc has already been sent, returns true. if loc has already been sent, returns true.
otherwise, marks loc as sent. otherwise, marks loc as sent.
@param deep - match was against an array, so we know it is multi key. this is legacy and kept @param deep - match was against an array, so we know it is multi key. this is legacy and kept
for backwards datafile compatibility. 'deep' can be eliminated next time we for backwards datafile compatibility. 'deep' can be eliminated next time we
force a data file conversion. 7Jul09 force a data file conversion. 7Jul09
*/ */
virtual bool getsetdup(DiskLoc loc) = 0; virtual bool getsetdup(DiskLoc loc) = 0;
virtual BSONArray prettyIndexBounds() const { return BSONArray(); } virtual BSONObj prettyIndexBounds() const { return BSONArray(); }
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
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 d_logic.h   d_logic.h 
skipping to change at line 22 skipping to change at line 22
* 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" #include "../db/jsobj.h"
#include "util.h"
namespace mongo { namespace mongo {
class ShardingState; class ShardingState;
typedef unsigned long long ConfigVersion; typedef ShardChunkVersion ConfigVersion;
typedef map<string,ConfigVersion> NSVersionMap; typedef map<string,ConfigVersion> NSVersionMap;
// ----------- // -----------
/**
* TODO: this only works with single fields at the moment
*/
class ChunkMatcher { class ChunkMatcher {
typedef map<BSONObj,pair<BSONObj,BSONObj>,BSONObjCmp> MyMap; typedef map<BSONObj,pair<BSONObj,BSONObj>,BSONObjCmp> MyMap;
public: public:
bool belongsToMe( const BSONObj& key , const DiskLoc& loc ) const; bool belongsToMe( const BSONObj& key , const DiskLoc& loc ) const;
private: private:
ChunkMatcher( ConfigVersion version ); ChunkMatcher( ConfigVersion version );
void gotRange( const BSONObj& min , const BSONObj& max ); void gotRange( const BSONObj& min , const BSONObj& max );
ConfigVersion _version; ConfigVersion _version;
string _field; BSONObj _key;
MyMap _map; MyMap _map;
friend class ShardingState; friend class ShardingState;
}; };
typedef shared_ptr<ChunkMatcher> ChunkMatcherPtr; typedef shared_ptr<ChunkMatcher> ChunkMatcherPtr;
// -------------- // --------------
// --- global state --- // --- global state ---
// -------------- // --------------
skipping to change at line 79 skipping to change at line 77
bool hasVersion( const string& ns ); bool hasVersion( const string& ns );
bool hasVersion( const string& ns , ConfigVersion& version ); bool hasVersion( const string& ns , ConfigVersion& version );
ConfigVersion& getVersion( const string& ns ); // TODO: this is dan geroues ConfigVersion& getVersion( const string& ns ); // TODO: this is dan geroues
void setVersion( const string& ns , const ConfigVersion& version ); void setVersion( const string& ns , const ConfigVersion& version );
void appendInfo( BSONObjBuilder& b ); void appendInfo( BSONObjBuilder& b );
ChunkMatcherPtr getChunkMatcher( const string& ns ); ChunkMatcherPtr getChunkMatcher( const string& ns );
bool inCriticalMigrateSection();
private: private:
bool _enabled; bool _enabled;
string _configServer; string _configServer;
string _shardName; string _shardName;
string _shardHost; string _shardHost;
mongo::mutex _mutex; mongo::mutex _mutex;
skipping to change at line 112 skipping to change at line 111
const OID& getID() const { return _id; } const OID& getID() const { return _id; }
bool hasID() const { return _id.isSet(); } bool hasID() const { return _id.isSet(); }
void setID( const OID& id ); void setID( const OID& id );
ConfigVersion& getVersion( const string& ns ); // TODO: this is dan geroues ConfigVersion& getVersion( const string& ns ); // TODO: this is dan geroues
void setVersion( const string& ns , const ConfigVersion& version ); void setVersion( const string& ns , const ConfigVersion& version );
static ShardedConnectionInfo* get( bool create ); static ShardedConnectionInfo* get( bool create );
bool inForceMode() const {
return _forceMode;
}
void enterForceMode(){ _forceMode = true; }
void leaveForceMode(){ _forceMode = false; }
private: private:
OID _id; OID _id;
NSVersionMap _versions; NSVersionMap _versions;
bool _forceMode;
static boost::thread_specific_ptr<ShardedConnectionInfo> _tl; static boost::thread_specific_ptr<ShardedConnectionInfo> _tl;
}; };
struct ShardForceModeBlock {
ShardForceModeBlock(){
info = ShardedConnectionInfo::get( false );
if ( info )
info->enterForceMode();
}
~ShardForceModeBlock(){
if ( info )
info->leaveForceMode();
}
ShardedConnectionInfo * info;
};
// ----------------- // -----------------
// --- core --- // --- core ---
// ----------------- // -----------------
unsigned long long extractVersion( BSONElement e , string& errmsg ); 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 );
skipping to change at line 141 skipping to change at line 162
/** /**
* @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 ) ;
void logOpForSharding( const char * opstr , const char * ns , const BSO
NObj& obj , BSONObj * patt );
// ----------------- // -----------------
// --- writeback --- // --- writeback ---
// ----------------- // -----------------
/* queue a write back on a remote server for a failed write */ /* queue a write back on a remote server for a failed write */
void queueWriteBack( const string& remote , const BSONObj& o ); void queueWriteBack( const string& remote , const BSONObj& o );
} }
 End of changes. 9 change blocks. 
5 lines changed or deleted 29 lines changed or added


 dbclient.h   dbclient.h 
skipping to change at line 71 skipping to change at line 71
*/ */
QueryOption_AwaitData = 1 << 5, QueryOption_AwaitData = 1 << 5,
/** Stream the data down full blast in multiple "more" packages, on the assumption that the client /** 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 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. pull it all down. Note: it is not allowed to not read all the data unless you close the connection.
Use the query( boost::function<void(const BSONObj&)> f, ... ) v ersion of the connection's query() Use the query( boost::function<void(const BSONObj&)> f, ... ) v ersion of the connection's query()
method, and it will take care of all the details for you. method, and it will take care of all the details for you.
*/ */
QueryOption_Exhaust = 1 << 6 QueryOption_Exhaust = 1 << 6,
QueryOption_AllSupported = QueryOption_CursorTailable | QueryOption
_SlaveOk | QueryOption_OplogReplay | QueryOption_NoCursorTimeout | QueryOpt
ion_AwaitData | QueryOption_Exhaust
}; };
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 177 skipping to change at line 179
*/ */
enum WriteConcern { enum WriteConcern {
W_NONE = 0 , // TODO: not every connection type fully supports this W_NONE = 0 , // TODO: not every connection type fully supports this
W_NORMAL = 1 W_NORMAL = 1
// TODO SAFE = 2 // TODO SAFE = 2
}; };
class BSONObj; class BSONObj;
class ScopedDbConnection; class ScopedDbConnection;
class DBClientCursor; class DBClientCursor;
class DBClientCursorBatchIterator;
/** Represents a Mongo query expression. Typically one uses the QUERY( ...) macro to construct a Query object. /** Represents a Mongo query expression. Typically one uses the QUERY( ...) macro to construct a Query object.
Examples: Examples:
QUERY( "age" << 33 << "school" << "UCLA" ).sort("name") QUERY( "age" << 33 << "school" << "UCLA" ).sort("name")
QUERY( "age" << GT << 30 << LT << 50 ) QUERY( "age" << GT << 30 << LT << 50 )
*/ */
class Query { class Query {
public: public:
BSONObj obj; BSONObj obj;
Query() : obj(BSONObj()) { } Query() : obj(BSONObj()) { }
skipping to change at line 344 skipping to change at line 347
/** /**
DB "commands" DB "commands"
Basically just invocations of connection.$cmd.findOne({...}); Basically just invocations of connection.$cmd.findOne({...});
*/ */
class DBClientWithCommands : public DBClientInterface { class DBClientWithCommands : public DBClientInterface {
set<string> _seenIndexes; set<string> _seenIndexes;
public: public:
/** controls how chatty the client is about network errors & such. See log.h */ /** controls how chatty the client is about network errors & such. See log.h */
int _logLevel; int _logLevel;
DBClientWithCommands() : _logLevel(0) { } DBClientWithCommands() : _logLevel(0), _cachedAvailableOptions( (en um QueryOptions)0 ), _haveCachedAvailableOptions(false) { }
/** helper function. run a simple command where the command expres sion is simply /** helper function. run a simple command where the command expres sion is simply
{ command : 1 } { command : 1 }
@param info -- where to put result object. may be null if call er doesn't need that info @param info -- where to put result object. may be null if call er doesn't need that info
@param command -- command name @param command -- command name
@return true if the command returned "ok". @return true if the command returned "ok".
*/ */
bool simpleCommand(const string &dbname, BSONObj *info, const strin g &command); bool simpleCommand(const string &dbname, BSONObj *info, const strin g &command);
/** Run a database command. Database commands are represented as B SON objects. Common database /** Run a database command. Database commands are represented as B SON objects. Common database
skipping to change at line 643 skipping to change at line 646
string::size_type pos = ns.find( "." ); string::size_type pos = ns.find( "." );
if ( pos == string::npos ) if ( pos == string::npos )
return ""; return "";
return ns.substr( pos + 1 ); return ns.substr( pos + 1 );
} }
protected: protected:
bool isOk(const BSONObj&); bool isOk(const BSONObj&);
enum QueryOptions availableOptions();
private:
enum QueryOptions _cachedAvailableOptions;
bool _haveCachedAvailableOptions;
}; };
/** /**
abstract class that implements the core db operations abstract class that implements the core db operations
*/ */
class DBClientBase : public DBClientWithCommands, public DBConnector { class DBClientBase : public DBClientWithCommands, public DBConnector {
protected: protected:
WriteConcern _writeConcern; WriteConcern _writeConcern;
public: public:
skipping to change at line 790 skipping to change at line 798
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 /** uses QueryOption_Exhaust
*/ */
unsigned long long query( boost::function<void(const BSONObj&)> f, unsigned long long query( boost::function<void(const BSONObj&)> f,
const string& ns, Query query, const BSONObj *fieldsToReturn = 0); const string& ns, Query query, const BSONObj *fieldsToReturn = 0, int query
Options = 0);
unsigned long long query( boost::function<void(DBClientCursorBatchI
terator&)> f, const string& ns, Query query, const BSONObj *fieldsToReturn
= 0, int queryOptions = 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() {
 End of changes. 5 change blocks. 
4 lines changed or deleted 18 lines changed or added


 dbclientcursor.h   dbclientcursor.h 
skipping to change at line 41 skipping to change at line 41
class DBClientCursor : boost::noncopyable { class DBClientCursor : boost::noncopyable {
public: public:
/** If true, safe to call next(). Requests more from server if necessary. */ /** If true, safe to call next(). Requests more from server if necessary. */
bool more(); bool more();
/** If true, there is more in our local buffers to be fetched via n ext(). Returns /** If true, there is more in our local buffers to be fetched via n ext(). Returns
false when a getMore request back to server would be required. You can use this false when a getMore request back to server would be required. You can use this
if you want to exhaust whatever data has been fetched to the cl ient already but if you want to exhaust whatever data has been fetched to the cl ient already but
then perhaps stop. then perhaps stop.
*/ */
bool moreInCurrentBatch() { return !_putBack.empty() || pos < nRetu rned; } bool moreInCurrentBatch() { _assertIfNull(); return !_putBack.empty () || pos < nReturned; }
/** next /** next
@return next object in the result cursor. @return next object in the result cursor.
on an error at the remote server, you will get back: on an error at the remote server, you will get back:
{ $err: <string> } { $err: <string> }
if you do not want to handle that yourself, call nextSafe(). if you do not want to handle that yourself, call nextSafe().
*/ */
BSONObj next(); BSONObj next();
/** /**
skipping to change at line 68 skipping to change at line 68
BSONObj o = next(); BSONObj o = next();
BSONElement e = o.firstElement(); BSONElement e = o.firstElement();
if( strcmp(e.fieldName(), "$err") == 0 ) { if( strcmp(e.fieldName(), "$err") == 0 ) {
if( logLevel >= 5 ) if( logLevel >= 5 )
log() << "nextSafe() error " << o.toString() << endl; log() << "nextSafe() error " << o.toString() << endl;
uassert(13106, "nextSafe(): " + o.toString(), false); uassert(13106, "nextSafe(): " + o.toString(), false);
} }
return o; return o;
} }
/** peek ahead at items buffered for future next() calls.
never requests new data from the server. so peek only effectiv
e
with what is already buffered.
WARNING: no support for _putBack yet!
*/
void peek(vector<BSONObj>&, int atMost);
/** /**
iterate the rest of the cursor and return the number if items iterate the rest of the cursor and return the number if items
*/ */
int itcount(){ int itcount(){
int c = 0; int c = 0;
while ( more() ){ while ( more() ){
next(); next();
c++; c++;
} }
return c; return c;
} }
/** cursor no longer valid -- use with tailable cursors. /** cursor no longer valid -- use with tailable cursors.
note you should only rely on this once more() returns false; note you should only rely on this once more() returns false;
'dead' may be preset yet some data still queued and locally 'dead' may be preset yet some data still queued and locally
available from the dbclientcursor. available from the dbclientcursor.
*/ */
bool isDead() const { bool isDead() const {
return cursorId == 0; return !this || cursorId == 0;
} }
bool tailable() const { bool tailable() const {
return (opts & QueryOption_CursorTailable) != 0; return (opts & QueryOption_CursorTailable) != 0;
} }
/** see QueryResult::ResultFlagType (db/dbmessage.h) for flag value s /** see QueryResult::ResultFlagType (db/dbmessage.h) for flag value s
mostly these flags are for internal purposes - mostly these flags are for internal purposes -
ResultFlag_ErrSet is the possible exception to that ResultFlag_ErrSet is the possible exception to that
*/ */
bool hasResultFlag( int flag ){ bool hasResultFlag( int flag ){
_assertIfNull();
return (resultFlags & flag) != 0; return (resultFlags & flag) != 0;
} }
DBClientCursor( DBConnector *_connector, const string &_ns, BSONObj _query, int _nToReturn, DBClientCursor( DBConnector *_connector, const string &_ns, BSONObj _query, int _nToReturn,
int _nToSkip, const BSONObj *_fieldsToReturn, int q ueryOptions , int bs ) : int _nToSkip, const BSONObj *_fieldsToReturn, int q ueryOptions , int bs ) :
connector(_connector), connector(_connector),
ns(_ns), ns(_ns),
query(_query), query(_query),
nToReturn(_nToReturn), nToReturn(_nToReturn),
haveLimit( _nToReturn > 0 && !(queryOptions & QueryOption_C ursorTailable)), haveLimit( _nToReturn > 0 && !(queryOptions & QueryOption_C ursorTailable)),
skipping to change at line 172 skipping to change at line 180
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 void exhaustReceiveMore(); // for exhaust
bool _ownCursor; // see decouple() bool _ownCursor; // see decouple()
string _scopedHost; string _scopedHost;
// Don't call from a virtual function
void _assertIfNull() { uassert(13348, "connection died", this); }
};
/** iterate over objects in current batch only - will not cause a netwo
rk call
*/
class DBClientCursorBatchIterator {
public:
DBClientCursorBatchIterator( DBClientCursor &c ) : _c( c ), _n() {}
bool moreInCurrentBatch() { return _c.moreInCurrentBatch(); }
BSONObj nextSafe() {
massert( 13383, "BatchIterator empty", moreInCurrentBatch() );
++_n;
return _c.nextSafe();
}
int n() const { return _n; }
private:
DBClientCursor &_c;
int _n;
}; };
} // namespace mongo } // namespace mongo
#include "undef_macros.h" #include "undef_macros.h"
 End of changes. 5 change blocks. 
2 lines changed or deleted 32 lines changed or added


 dbhelpers.h   dbhelpers.h 
skipping to change at line 103 skipping to change at line 103
You do not need to set the database (Context) 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 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} static bool getLast(const char *ns, BSONObj& result); // get last o bject int he collection; e.g. {$natural : -1}
/**
* you have to lock
* you do not have to have Context set
* o has to have an _id field or will assert
*/
static void upsert( const string& ns , const BSONObj& o );
/** 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);
// TODO: this should be somewhere else probably
static BSONObj toKeyFormat( const BSONObj& o , BSONObj& key );
static long long removeRange( const string& ns , const BSONObj& min
, const BSONObj& max , bool yield = false , bool maxInclusive = false );
/* 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);
}; };
class Database; class Database;
// manage a set using collection backed storage // manage a set using collection backed storage
 End of changes. 2 change blocks. 
0 lines changed or deleted 13 lines changed or added


 distlock.h   distlock.h 
skipping to change at line 19 skipping to change at line 19
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/** /**
* distribuetd locking mechanism * distributed locking mechanism
*/ */
#include "../pch.h" #include "../pch.h"
#include "dbclient.h" #include "dbclient.h"
#include "connpool.h"
#include "redef_macros.h" #include "redef_macros.h"
#include "syncclusterconnection.h"
namespace mongo { namespace mongo {
extern string ourHostname;
class DistributedLock { class DistributedLock {
public: public:
DistributedLock( const ConnectionString& conn , const string& name /**
) * @param takeoverMinutes how long before we steal lock in minutes
: _conn(conn),_name(name),_myid(""){ */
_id = BSON( "_id" << name ); DistributedLock( const ConnectionString& conn , const string& name
_ns = "config.locks"; , int takeoverMinutes = 10 );
}
int getState(){ int getState(){
return _state.get(); return _state.get();
} }
bool isLocked(){ bool isLocked(){
return _state.get() != 0; return _state.get() != 0;
} }
bool lock_try( string why , BSONObj * other = 0 ){ bool lock_try( string why , BSONObj * other = 0 );
// recursive void unlock();
if ( getState() > 0 )
return true;
ScopedDbConnection conn( _conn );
{ // make sure its there so we can use simple update logic belo
w
BSONObj o = conn->findOne( _ns , _id );
if ( o.isEmpty() ){
try {
conn->insert( _ns , BSON( "_id" << _name << "state"
<< 0 << "who" << "" ) );
}
catch ( UserException& e ){
}
}
}
BSONObjBuilder b;
b.appendElements( _id );
b.append( "state" , 0 );
conn->update( _ns , b.obj() , BSON( "$set" << BSON( "state" <<
1 << "who" << myid() << "when" << DATENOW << "why" << why ) ) );
BSONObj o = conn->getLastErrorDetailed();
BSONObj now = conn->findOne( _ns , _id );
conn.done();
log() << "dist_lock lock getLastErrorDetailed: " << o << " now:
" << now << endl;
if ( o["n"].numberInt() == 0 ){
if ( other )
*other = now;
return false;
}
_state.set( 1 );
return true;
}
void unlock(){
ScopedDbConnection conn( _conn );
conn->update( _ns , _id, BSON( "$set" << BSON( "state" << 0 ) )
);
log() << "dist_lock unlock unlock: " << conn->findOne( _ns , _i
d ) << endl;
conn.done();
_state.set( 0 );
}
string myid(){
string s = _myid.get();
if ( s.empty() ){
stringstream ss;
ss << ourHostname << ":" << time(0) << ":" << rand();
s = ss.str();
_myid.set( s );
}
return s;
}
private: private:
ConnectionString _conn; ConnectionString _conn;
string _ns;
string _name; string _name;
int _takeoverMinutes;
string _ns;
BSONObj _id; BSONObj _id;
ThreadLocalValue<int> _state; ThreadLocalValue<int> _state;
ThreadLocalValue<string> _myid;
}; };
class dist_lock_try { class dist_lock_try {
public: public:
dist_lock_try( DistributedLock * lock , string why ) dist_lock_try( DistributedLock * lock , string why )
: _lock(lock){ : _lock(lock){
_got = _lock->lock_try( why , &_other ); _got = _lock->lock_try( why , &_other );
} }
 End of changes. 9 change blocks. 
77 lines changed or deleted 13 lines changed or added


 file_allocator.h   file_allocator.h 
skipping to change at line 126 skipping to change at line 126
#if defined(__linux__) #if defined(__linux__)
int ret = posix_fallocate(fd,0,size); int ret = posix_fallocate(fd,0,size);
if ( ret == 0 ) if ( ret == 0 )
return; return;
log() << "posix_fallocate failed: " << errnoWithDescription( re t ) << " falling back" << endl; log() << "posix_fallocate failed: " << errnoWithDescription( re t ) << " falling back" << endl;
#endif #endif
off_t filelen = lseek(fd, 0, SEEK_END); off_t filelen = lseek(fd, 0, SEEK_END);
if ( filelen < size ) { if ( filelen < size ) {
massert( 10440 , "failure creating new datafile", filelen if (filelen != 0) {
== 0 ); stringstream ss;
ss << "failure creating new datafile; lseek failed for
fd " << fd << " with errno: " << errnoWithDescription();
massert( 10440 , ss.str(), filelen == 0 );
}
// Check for end of disk. // Check for end of disk.
massert( 10441 , "Unable to allocate file of desired size" , massert( 10441 , "Unable to allocate file of desired size" ,
size - 1 == lseek(fd, size - 1, SEEK_SET) ); size - 1 == lseek(fd, size - 1, SEEK_SET) );
massert( 10442 , "Unable to allocate file of desired size" , massert( 10442 , "Unable to allocate file of desired size" ,
1 == write(fd, "", 1) ); 1 == write(fd, "", 1) );
lseek(fd, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);
long z = 256 * 1024; long z = 256 * 1024;
char buf[z]; char buf[z];
memset(buf, 0, z); memset(buf, 0, z);
 End of changes. 1 change blocks. 
2 lines changed or deleted 6 lines changed or added


 hex.h   hex.h 
skipping to change at line 35 skipping to change at line 35
if ( 'a' <= c && c <= 'f' ) if ( 'a' <= c && c <= 'f' )
return c - 'a' + 10; return c - 'a' + 10;
if ( 'A' <= c && c <= 'F' ) if ( 'A' <= c && c <= 'F' )
return c - 'A' + 10; return c - 'A' + 10;
assert( false ); assert( false );
return 0xff; return 0xff;
} }
inline char fromHex( const char *c ) { inline char fromHex( const char *c ) {
return ( fromHex( c[ 0 ] ) << 4 ) | fromHex( c[ 1 ] ); return ( fromHex( c[ 0 ] ) << 4 ) | fromHex( c[ 1 ] );
} }
inline string toHex(const void* inRaw, int len){
static const char hexchars[] = "0123456789ABCDEF";
StringBuilder out;
const char* in = reinterpret_cast<const char*>(inRaw);
for (int i=0; i<len; ++i){
char c = in[i];
char hi = hexchars[(c & 0xF0) >> 4];
char lo = hexchars[(c & 0x0F)];
out << hi << lo;
}
return out.str();
}
} }
 End of changes. 1 change blocks. 
0 lines changed or deleted 16 lines changed or added


 hostandport.h   hostandport.h 
skipping to change at line 49 skipping to change at line 49
HostAndPort(string h, int p /*= -1*/) : _host(h), _port(p) { } HostAndPort(string h, int p /*= -1*/) : _host(h), _port(p) { }
HostAndPort(const SockAddr& sock ) HostAndPort(const SockAddr& sock )
: _host( sock.getAddr() ) , _port( sock.getPort() ){ : _host( sock.getAddr() ) , _port( sock.getPort() ){
} }
static HostAndPort me() { static HostAndPort me() {
return HostAndPort("localhost", cmdLine.port); return HostAndPort("localhost", cmdLine.port);
} }
/* uses real hostname instead of localhost */
static HostAndPort Me();
bool operator<(const HostAndPort& r) const { return _host < r._host || (_host==r._host&&_port<r._port); } bool operator<(const HostAndPort& r) const { return _host < r._host || (_host==r._host&&_port<r._port); }
/* returns true if the host/port combo identifies this process inst ance. */ /* returns true if the host/port combo identifies this process inst ance. */
bool isSelf() const; bool isSelf() const;
bool isLocalHost() const; bool isLocalHost() const;
// @returns host:port // @returns host:port
string toString() const; string toString() const;
skipping to change at line 80 skipping to change at line 83
/** returns true if strings seem to be the same hostname. /** returns true if strings seem to be the same hostname.
"nyc1" and "nyc1.acme.com" are treated as the same. "nyc1" and "nyc1.acme.com" are treated as the same.
in fact "nyc1.foo.com" and "nyc1.acme.com" are treated the same - in fact "nyc1.foo.com" and "nyc1.acme.com" are treated the same -
we oly look up to the first period. we oly look up to the first period.
*/ */
inline bool sameHostname(const string& a, const string& b) { inline bool sameHostname(const string& a, const string& b) {
return str::before(a, '.') == str::before(b, '.'); return str::before(a, '.') == str::before(b, '.');
} }
inline HostAndPort HostAndPort::Me() {
string h = getHostName();
assert( !h.empty() );
assert( h != "localhost" );
return HostAndPort(h, cmdLine.port);
}
inline bool HostAndPort::isSelf() const { inline bool HostAndPort::isSelf() const {
int p = _port == -1 ? CmdLine::DefaultDBPort : _port; int p = _port == -1 ? CmdLine::DefaultDBPort : _port;
if( p != cmdLine.port ) if( p != cmdLine.port )
return false; return false;
return sameHostname(getHostName(), _host) || isLocalHost(); return sameHostname(getHostName(), _host) || isLocalHost();
} }
inline string HostAndPort::toString() const { inline string HostAndPort::toString() const {
stringstream ss; stringstream ss;
 End of changes. 2 change blocks. 
0 lines changed or deleted 10 lines changed or added


 instance.h   instance.h 
skipping to change at line 112 skipping to change at line 112
~DbResponse() { delete response; } ~DbResponse() { 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 , const string& usePath = dbpath ); void getDatabaseNames( vector< string > &names , const string& usePath = dbpath );
/* returns true if there is no data on this server. useful when starti ng replication. /* returns true if there is no data on this server. useful when starti ng replication.
local database does NOT count. local database does NOT count.
*/ */
bool haveDatabases(); bool replHasDatabases();
// --- 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 143 skipping to change at line 143
virtual void sayPiggyBack( Message &toSend ) { virtual void sayPiggyBack( Message &toSend ) {
// don't need to piggy back when connected locally // don't need to piggy back when connected locally
return say( toSend ); return say( toSend );
} }
virtual void killCursor( long long cursorID ); virtual void killCursor( long long cursorID );
}; };
extern int lockFile; extern int lockFile;
void acquirePathLock(); void acquirePathLock();
void maybeCreatePidFile();
} // namespace mongo } // namespace mongo
 End of changes. 2 change blocks. 
1 lines changed or deleted 2 lines changed or added


 jsobj.h   jsobj.h 
skipping to change at line 45 skipping to change at line 45
#include <set> #include <set>
#include "../bson/bsontypes.h" #include "../bson/bsontypes.h"
#include "../bson/oid.h" #include "../bson/oid.h"
#include "../bson/bsonelement.h" #include "../bson/bsonelement.h"
#include "../bson/bsonobj.h" #include "../bson/bsonobj.h"
#include "../bson/bsonmisc.h" #include "../bson/bsonmisc.h"
#include "../bson/bsonobjbuilder.h" #include "../bson/bsonobjbuilder.h"
#include "../bson/bsonobjiterator.h" #include "../bson/bsonobjiterator.h"
#include "../bson/bsoninlines.h" #include "../bson/bsoninlines.h"
#include "../bson/ordering.h" #include "../bson/ordering.h"
#include "../bson/stringdata.h"
#include "../bson/bson_db.h" #include "../bson/bson_db.h"
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 list.h   list.h 
skipping to change at line 53 skipping to change at line 53
T *_next; T *_next;
public: public:
T* next() const { return _next; } T* next() const { return _next; }
}; };
T* head() const { return _head; } T* head() const { return _head; }
void push(T* t) { void push(T* t) {
scoped_lock lk(_m); scoped_lock lk(_m);
t->_next = _head; t->_next = _head;
_head = t; } _head = t;
}
// intentionally leak.
void orphanAll() {
_head = 0;
}
/* t is not deleted, but is removed from the list. (orphaned) */ /* t is not deleted, but is removed from the list. (orphaned) */
void orphan(T* t) { void orphan(T* t) {
scoped_lock lk(_m); scoped_lock lk(_m);
T *&prev = _head; T *&prev = _head;
T *n = prev; T *n = prev;
while( n != t ) { while( n != t ) {
prev = n->_next; prev = n->_next;
n = prev; n = prev;
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 7 lines changed or added


 log.h   log.h 
skipping to change at line 153 skipping to change at line 153
} }
virtual void flush(Tee *t = 0) {} virtual void flush(Tee *t = 0) {}
}; };
extern Nullstream nullstream; extern Nullstream nullstream;
class Logstream : public Nullstream { class Logstream : public Nullstream {
static mongo::mutex mutex; static mongo::mutex mutex;
static int doneSetup; static int doneSetup;
stringstream ss; stringstream ss;
LogLevel logLevel; LogLevel logLevel;
static boost::scoped_ptr<ostream> stream;
static FILE* logfile;
public: public:
static void setLogFile(FILE* f){
scoped_lock lk(mutex);
logfile = f;
}
static int magicNumber(){ static int magicNumber(){
return 1717; return 1717;
} }
void flush(Tee *t = 0) { void flush(Tee *t = 0) {
// this ensures things are sane // this ensures things are sane
if ( doneSetup == 1717 ) { if ( doneSetup == 1717 ) {
BufBuilder b(512); BufBuilder b(512);
time_t_to_String( time(0) , b.grow(20) ); time_t_to_String( time(0) , b.grow(20) );
b.append( ss.str() ); b.append( ss.str() );
const char *s = b.buf(); const char *s = b.buf();
string threadName = getThreadName(); string threadName = getThreadName();
const char * type = logLevelToString(logLevel); const char * type = logLevelToString(logLevel);
skipping to change at line 168 skipping to change at line 177
// this ensures things are sane // this ensures things are sane
if ( doneSetup == 1717 ) { if ( doneSetup == 1717 ) {
BufBuilder b(512); BufBuilder b(512);
time_t_to_String( time(0) , b.grow(20) ); time_t_to_String( time(0) , b.grow(20) );
b.append( ss.str() ); b.append( ss.str() );
const char *s = b.buf(); const char *s = b.buf();
string threadName = getThreadName(); string threadName = getThreadName();
const char * type = logLevelToString(logLevel); const char * type = logLevelToString(logLevel);
StringBuilder sb;
if (!threadName.empty()){
sb << "[" << threadName << "] ";
}
sb << type << ( type[0] ? ": " : "" );
sb << s;
string out = sb.str();
scoped_lock lk(mutex); scoped_lock lk(mutex);
if( t ) t->write(logLevel,s); if( t ) t->write(logLevel,s);
#ifndef _WIN32 #ifndef _WIN32
//syslog( LOG_INFO , "%s" , cc ); //syslog( LOG_INFO , "%s" , cc );
#endif #endif
fwrite(out.data(), out.size(), 1, logfile);
if ( ! threadName.empty() ){ fflush(logfile);
cout << "[" << threadName << "] ";
}
cout << type << ( type[0] ? ": " : "" );
cout << s;
cout.flush();
} }
_init(); _init();
} }
Nullstream& setLogLevel(LogLevel l){ Nullstream& setLogLevel(LogLevel l){
logLevel = l; logLevel = l;
return *this; return *this;
} }
/** note these are virtual */ /** note these are virtual */
skipping to change at line 326 skipping to change at line 338
return l; return l;
} }
/** /**
log to a file rather than stdout log to a file rather than stdout
defined in assert_util.cpp defined in assert_util.cpp
*/ */
void initLogging( const string& logpath , bool append ); void initLogging( const string& logpath , bool append );
void rotateLogs( int signal = 0 ); void rotateLogs( int signal = 0 );
std::string toUtf8String(const std::wstring& wide);
inline string errnoWithDescription(int x = errno) { inline string errnoWithDescription(int x = errno) {
stringstream s; stringstream s;
s << "errno:" << x << ' ' << strerror(x); s << "errno:" << x << ' ';
#if defined(_WIN32)
LPTSTR errorText = NULL;
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM
|FORMAT_MESSAGE_ALLOCATE_BUFFER
|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
x, 0,
(LPTSTR) &errorText, // output
0, // minimum size for output buffer
NULL);
if( errorText ) {
string x = toUtf8String(errorText);
s << x;
LocalFree(errorText);
}
else
s << strerror(x);
/*
DWORD n = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, x,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf, 0, NULL);
*/
#else
s << strerror(x);
#endif
return s.str(); return s.str();
} }
/** output the error # and error message with prefix. /** output the error # and error message with prefix.
handy for use as parm in uassert/massert. handy for use as parm in uassert/massert.
*/ */
string errnoWithPrefix( const char * prefix = 0 ); string errnoWithPrefix( const char * prefix = 0 );
} // namespace mongo } // namespace mongo
 End of changes. 7 change blocks. 
8 lines changed or deleted 53 lines changed or added


 matcher.h   matcher.h 
skipping to change at line 31 skipping to change at line 31
#pragma once #pragma once
#include "jsobj.h" #include "jsobj.h"
#include <pcrecpp.h> #include <pcrecpp.h>
namespace mongo { namespace mongo {
class Cursor; class Cursor;
class CoveredIndexMatcher; class CoveredIndexMatcher;
class Matcher; class Matcher;
class FieldRangeVector;
class RegexMatcher { class RegexMatcher {
public: public:
const char *fieldName; const char *fieldName;
const char *regex; const char *regex;
const char *flags; const char *flags;
string prefix; string prefix;
shared_ptr< pcrecpp::RE > re; shared_ptr< pcrecpp::RE > re;
bool isNot; bool isNot;
RegexMatcher() : isNot() {} RegexMatcher() : isNot() {}
skipping to change at line 155 skipping to change at line 156
bool keyMatch() const { return !all && !haveSize && !hasArray && !h aveNeg; } 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 addOrConstraint( const BSONObj &o ) { void addOrConstraint( const shared_ptr< FieldRangeVector > &frv ) {
_norMatchers.push_back( shared_ptr< Matcher >( new Matcher( o ) _orConstraints.push_back( frv );
) );
} }
bool sameCriteriaCount( const Matcher &other ) const; bool sameCriteriaCount( const Matcher &other ) const;
private: private:
// Only specify constrainIndexKey if matches() will be called with // Only specify constrainIndexKey if matches() will be called with
// index keys having empty string field names. // index keys having empty string field names.
Matcher( const Matcher &other, const BSONObj &constrainIndexKey ); 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) {
skipping to change at line 204 skipping to change at line 205
*/ */
bool _atomic; bool _atomic;
RegexMatcher regexs[4]; RegexMatcher regexs[4];
int nRegex; int nRegex;
// so we delete the mem when we're done: // so we delete the mem when we're done:
vector< shared_ptr< BSONObjBuilder > > _builders; vector< shared_ptr< BSONObjBuilder > > _builders;
list< shared_ptr< Matcher > > _orMatchers; list< shared_ptr< Matcher > > _orMatchers;
list< shared_ptr< Matcher > > _norMatchers; list< shared_ptr< Matcher > > _norMatchers;
vector< shared_ptr< FieldRangeVector > > _orConstraints;
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 // once this is called, shouldn't use this matcher for matching any more
void addOrConstraint( const BSONObj &o ) { void addOrConstraint( const shared_ptr< FieldRangeVector > &frv ) {
_docMatcher->addOrConstraint( o ); _docMatcher->addOrConstraint( frv );
} }
CoveredIndexMatcher *nextClauseMatcher( const BSONObj &indexKeyPatt ern, bool alwaysUseRecord=false ) { CoveredIndexMatcher *nextClauseMatcher( const BSONObj &indexKeyPatt ern, bool alwaysUseRecord=false ) {
return new CoveredIndexMatcher( _docMatcher, indexKeyPattern, a lwaysUseRecord ); return new CoveredIndexMatcher( _docMatcher, indexKeyPattern, a lwaysUseRecord );
} }
private: private:
CoveredIndexMatcher(const shared_ptr< Matcher > &docMatcher, const BSONObj &indexKeyPattern , bool alwaysUseRecord=false ); CoveredIndexMatcher(const shared_ptr< Matcher > &docMatcher, const BSONObj &indexKeyPattern , bool alwaysUseRecord=false );
void init( bool alwaysUseRecord ); void init( bool alwaysUseRecord );
shared_ptr< Matcher > _docMatcher; shared_ptr< Matcher > _docMatcher;
Matcher _keyMatcher; Matcher _keyMatcher;
 End of changes. 4 change blocks. 
5 lines changed or deleted 6 lines changed or added


 misc.h   misc.h 
skipping to change at line 38 skipping to change at line 38
inline void time_t_to_String(time_t t, char *buf) { inline void time_t_to_String(time_t t, char *buf) {
#if defined(_WIN32) #if defined(_WIN32)
ctime_s(buf, 64, &t); ctime_s(buf, 64, &t);
#else #else
ctime_r(&t, buf); ctime_r(&t, buf);
#endif #endif
buf[24] = 0; // don't want the \n buf[24] = 0; // don't want the \n
} }
inline string time_t_to_String(time_t t = time(0) ){ inline string time_t_to_String(time_t t = time(0) ){
char buf[32]; char buf[64];
#if defined(_WIN32) #if defined(_WIN32)
ctime_s(buf, 64, &t); ctime_s(buf, sizeof(buf), &t);
#else #else
ctime_r(&t, buf); ctime_r(&t, buf);
#endif #endif
buf[24] = 0; // don't want the \n buf[24] = 0; // don't want the \n
return buf; return buf;
} }
inline string time_t_to_String_no_year(time_t t) {
char buf[64];
#if defined(_WIN32)
ctime_s(buf, sizeof(buf), &t);
#else
ctime_r(&t, buf);
#endif
buf[19] = 0;
return buf;
}
inline string time_t_to_String_short(time_t t) {
char buf[64];
#if defined(_WIN32)
ctime_s(buf, sizeof(buf), &t);
#else
ctime_r(&t, buf);
#endif
buf[19] = 0;
if( buf[0] && buf[1] && buf[2] && buf[3] )
return buf + 4; // skip day of week
return buf;
}
struct Date_t { struct Date_t {
// TODO: make signed (and look for related TODO's) // TODO: make signed (and look for related TODO's)
unsigned long long millis; unsigned long long millis;
Date_t(): millis(0) {} Date_t(): millis(0) {}
Date_t(unsigned long long m): millis(m) {} Date_t(unsigned long long m): millis(m) {}
operator unsigned long long&() { return millis; } operator unsigned long long&() { return millis; }
operator const unsigned long long&() const { return millis; } operator const unsigned long long&() const { return millis; }
string toString() const { string toString() const {
char buf[64]; char buf[64];
time_t_to_String(millis, buf); time_t_to_String(millis/1000, buf);
return buf; return buf;
} }
}; };
} }
 End of changes. 4 change blocks. 
3 lines changed or deleted 27 lines changed or added


 namespace.h   namespace.h 
skipping to change at line 664 skipping to change at line 664
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;
extern string lockfilepath; // --lockfilepath param extern string pidfilepath; // --pidfilepath param
// Rename a namespace within current 'client' db. // Rename a namespace within current 'client' db.
// (Arguments should include db name) // (Arguments should include db name)
void renameNamespace( const char *from, const char *to ); void renameNamespace( const char *from, const char *to );
} // namespace mongo } // namespace mongo
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 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, const std::wstr ing& serviceUser, const std::wstring& servicePassword, int argc, char* argv [] ); static bool installService( const std::wstring& serviceName, const std::wstring& displayName, const std::wstring& serviceDesc, const std::wstr ing& serviceUser, const std::wstring& servicePassword, const std::string db path, int argc, char* argv[] );
static bool removeService( const std::wstring& serviceName ); static bool removeService( const std::wstring& serviceName );
static bool startService( const std::wstring& serviceName, ServiceC allback startService ); static bool startService( const std::wstring& serviceName, ServiceC allback startService );
static bool reportStatus( DWORD reportState, DWORD waitHint = 0 ); static bool reportStatus( DWORD reportState, DWORD waitHint = 0 );
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


 oplog.h   oplog.h 
skipping to change at line 98 skipping to change at line 98
return; return;
} }
_findingStartCursor->c->advance(); _findingStartCursor->c->advance();
RARELY { RARELY {
if ( _findingStartTimer.seconds() >= __findingStart InitialTimeout ) { if ( _findingStartTimer.seconds() >= __findingStart InitialTimeout ) {
createClientCursor( startLoc( _findingStartCurs or->c->currLoc() ) ); createClientCursor( startLoc( _findingStartCurs or->c->currLoc() ) );
_findingStartMode = FindExtent; _findingStartMode = FindExtent;
return; return;
} }
} }
maybeRelease();
return; return;
} }
case FindExtent: { case FindExtent: {
if ( !_matcher->matches( _findingStartCursor->c->currKe y(), _findingStartCursor->c->currLoc() ) ) { if ( !_matcher->matches( _findingStartCursor->c->currKe y(), _findingStartCursor->c->currLoc() ) ) {
_findingStartMode = InExtent; _findingStartMode = InExtent;
return; return;
} }
DiskLoc prev = prevLoc( _findingStartCursor->c->currLoc () ); DiskLoc prev = prevLoc( _findingStartCursor->c->currLoc () );
if ( prev.isNull() ) { // hit beginning, so start scann ing from here if ( prev.isNull() ) { // hit beginning, so start scann ing from here
createClientCursor(); createClientCursor();
_findingStartMode = InExtent; _findingStartMode = InExtent;
return; return;
} }
// There might be a more efficient implementation than creating new cursor & client cursor each time, // There might be a more efficient implementation than creating new cursor & client cursor each time,
// not worrying about that for now // not worrying about that for now
createClientCursor( prev ); createClientCursor( prev );
maybeRelease();
return; return;
} }
case InExtent: { case InExtent: {
if ( _matcher->matches( _findingStartCursor->c->currKey (), _findingStartCursor->c->currLoc() ) ) { if ( _matcher->matches( _findingStartCursor->c->currKey (), _findingStartCursor->c->currLoc() ) ) {
_findingStart = false; // found first record in que ry range, so scan normally _findingStart = false; // found first record in que ry range, so scan normally
_c = _qp.newCursor( _findingStartCursor->c->currLoc () ); _c = _qp.newCursor( _findingStartCursor->c->currLoc () );
destroyClientCursor(); destroyClientCursor();
return; return;
} }
_findingStartCursor->c->advance(); _findingStartCursor->c->advance();
maybeRelease();
return; return;
} }
default: { default: {
massert( 12600, "invalid _findingStartMode", false ); massert( 12600, "invalid _findingStartMode", false );
} }
} }
} }
void prepareToYield() {
if ( _findingStartCursor ) {
_findingStartCursor->prepareToYield( _yieldData );
}
}
void recoverFromYield() {
if ( _findingStartCursor ) {
if ( !ClientCursor::recoverFromYield( _yieldData ) ) {
_findingStartCursor = 0;
}
}
}
private: private:
enum FindingStartMode { Initial, FindExtent, InExtent }; enum FindingStartMode { Initial, FindExtent, InExtent };
const QueryPlan &_qp; const QueryPlan &_qp;
bool _findingStart; bool _findingStart;
FindingStartMode _findingStartMode; FindingStartMode _findingStartMode;
auto_ptr< CoveredIndexMatcher > _matcher; auto_ptr< CoveredIndexMatcher > _matcher;
Timer _findingStartTimer; Timer _findingStartTimer;
ClientCursor * _findingStartCursor; ClientCursor * _findingStartCursor;
shared_ptr<Cursor> _c; shared_ptr<Cursor> _c;
ClientCursor::YieldData _yieldData;
DiskLoc startLoc( const DiskLoc &rec ) { DiskLoc startLoc( const DiskLoc &rec ) {
Extent *e = rec.rec()->myExtent( rec ); Extent *e = rec.rec()->myExtent( rec );
if ( !_qp.nsd()->capLooped() || ( e->myLoc != _qp.nsd()->capExt ent ) ) if ( !_qp.nsd()->capLooped() || ( e->myLoc != _qp.nsd()->capExt ent ) )
return e->firstRecord; return e->firstRecord;
// Likely we are on the fresh side of capExtent, so return firs t fresh record. // Likely we are on the fresh side of capExtent, so return firs t fresh record.
// If we are on the stale side of capExtent, then the collectio n is small and it // If we are on the stale side of capExtent, then the collectio n is small and it
// doesn't matter if we start the extent scan with capFirstNewR ecord. // doesn't matter if we start the extent scan with capFirstNewR ecord.
return _qp.nsd()->capFirstNewRecord; return _qp.nsd()->capFirstNewRecord;
} }
skipping to change at line 181 skipping to change at line 191
void createClientCursor( const DiskLoc &startLoc = DiskLoc() ) { void createClientCursor( const DiskLoc &startLoc = DiskLoc() ) {
shared_ptr<Cursor> c = _qp.newCursor( startLoc ); shared_ptr<Cursor> c = _qp.newCursor( startLoc );
_findingStartCursor = new ClientCursor(QueryOption_NoCursorTime out, c, _qp.ns()); _findingStartCursor = new ClientCursor(QueryOption_NoCursorTime out, c, _qp.ns());
} }
void destroyClientCursor() { void destroyClientCursor() {
if ( _findingStartCursor ) { if ( _findingStartCursor ) {
ClientCursor::erase( _findingStartCursor->cursorid ); ClientCursor::erase( _findingStartCursor->cursorid );
_findingStartCursor = 0; _findingStartCursor = 0;
} }
} }
void maybeRelease() {
if ( ! _findingStartCursor->yieldSometimes() ){
_findingStartCursor = 0;
}
}
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.originalQuery()[ "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()) );
} }
}; };
void pretouchOperation(const BSONObj& op); void pretouchOperation(const BSONObj& op);
void pretouchN(vector<BSONObj>&, unsigned a, unsigned b);
void applyOperation_inlock(const BSONObj& op); void applyOperation_inlock(const BSONObj& op);
} }
 End of changes. 7 change blocks. 
8 lines changed or deleted 14 lines changed or added


 optime.h   optime.h 
skipping to change at line 113 skipping to change at line 113
string toStringLong() const { string toStringLong() const {
char buf[64]; char buf[64];
time_t_to_String(secs, buf); time_t_to_String(secs, buf);
stringstream ss; stringstream ss;
ss << buf << ' '; ss << buf << ' ';
ss << hex << secs << ':' << i; ss << hex << secs << ':' << i;
return ss.str(); return ss.str();
} }
string toStringPretty() const {
stringstream ss;
ss << time_t_to_String_short(secs) << ':' << hex << i;
return ss.str();
}
string toString() const { string toString() const {
stringstream ss; stringstream ss;
ss << hex << secs << ':' << i; ss << hex << secs << ':' << i;
return ss.str(); return ss.str();
} }
operator string() const { return toString(); } operator string() const { return toString(); }
bool operator==(const OpTime& r) const { bool operator==(const OpTime& r) const {
return i == r.i && secs == r.secs; return i == r.i && secs == r.secs;
} }
bool operator!=(const OpTime& r) const { bool operator!=(const OpTime& r) const {
 End of changes. 1 change blocks. 
0 lines changed or deleted 6 lines changed or added


 pch.h   pch.h 
skipping to change at line 34 skipping to change at line 34
# define JS_C_STRINGS_ARE_UTF8 # define JS_C_STRINGS_ARE_UTF8
# undef SUPPORT_UCP # undef SUPPORT_UCP
# define SUPPORT_UCP # define SUPPORT_UCP
# undef SUPPORT_UTF8 # undef SUPPORT_UTF8
# define SUPPORT_UTF8 # define SUPPORT_UTF8
# undef _CRT_SECURE_NO_WARNINGS # undef _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS # define _CRT_SECURE_NO_WARNINGS
#endif #endif
#if defined(WIN32) #if defined(WIN32)
// so you don't have to define this yourself as the code seems to use it...
#undef _WIN32 #ifndef _WIN32
#define _WIN32 #define _WIN32
#endif #endif
#endif
#if defined(_WIN32) #if defined(_WIN32)
# ifndef NOMINMAX # ifndef NOMINMAX
# define NOMINMAX # define NOMINMAX
# endif # endif
# include <winsock2.h> //this must be included before the first windows.h i nclude # include <winsock2.h> //this must be included before the first windows.h i nclude
# include <ws2tcpip.h> # include <ws2tcpip.h>
# include <wspiapi.h> # include <wspiapi.h>
# include <windows.h> # include <windows.h>
#endif #endif
skipping to change at line 71 skipping to change at line 73
#include <sstream> #include <sstream>
#include <signal.h> #include <signal.h>
#include "targetver.h" #include "targetver.h"
#include "time.h" #include "time.h"
#include "string.h" #include "string.h"
#include "limits.h" #include "limits.h"
#include <boost/any.hpp> #include <boost/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/exception.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/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
 End of changes. 3 change blocks. 
2 lines changed or deleted 5 lines changed or added


 pdfile.h   pdfile.h 
skipping to change at line 55 skipping to change at line 55
/* low level - only drops this ns */ /* low level - only drops this ns */
void dropNS(const string& dropNs); void dropNS(const string& dropNs);
/* deletes this ns, indexes and cursors */ /* deletes this ns, indexes and cursors */
void dropCollection( const string &name, string &errmsg, BSONObjBuilder &result ); void dropCollection( const string &name, string &errmsg, BSONObjBuilder &result );
bool userCreateNS(const char *ns, BSONObj j, string& err, bool logForRe plication, bool *deferIdIndex = 0); bool userCreateNS(const char *ns, BSONObj j, string& err, bool logForRe plication, bool *deferIdIndex = 0);
shared_ptr<Cursor> findTableScan(const char *ns, const BSONObj& order, const DiskLoc &startLoc=DiskLoc()); shared_ptr<Cursor> findTableScan(const char *ns, const BSONObj& order, const DiskLoc &startLoc=DiskLoc());
// -1 if library unavailable. // -1 if library unavailable.
boost::intmax_t freeSpace(); boost::intmax_t freeSpace( const string &path = dbpath );
/*--------------------------------------------------------------------- */ /*--------------------------------------------------------------------- */
class MongoDataFile { class MongoDataFile {
friend class DataFileMgr; friend class DataFileMgr;
friend class BasicCursor; friend class BasicCursor;
public: public:
MongoDataFile(int fn) : fileNo(fn) { } MongoDataFile(int fn) : fileNo(fn) { }
void open(const char *filename, int requestedDataSize = 0, bool pre allocateOnly = false); void open(const char *filename, int requestedDataSize = 0, bool pre allocateOnly = false);
skipping to change at line 109 skipping to change at line 109
/* see if we can find an extent of the right size in the freelist. */ /* see if we can find an extent of the right size in the freelist. */
static Extent* allocFromFreeList(const char *ns, int approxSize, bo ol capped = false); static Extent* allocFromFreeList(const char *ns, int approxSize, bo ol capped = false);
/** @return DiskLoc where item ends up */ /** @return DiskLoc where item ends up */
// changedId should be initialized to false // changedId should be initialized to false
const DiskLoc updateRecord( const DiskLoc updateRecord(
const char *ns, const char *ns,
NamespaceDetails *d, NamespaceDetails *d,
NamespaceDetailsTransient *nsdt, NamespaceDetailsTransient *nsdt,
Record *toupdate, const DiskLoc& dl, Record *toupdate, const DiskLoc& dl,
const char *buf, int len, OpDebug& debug, bool &changedId); const char *buf, int len, OpDebug& debug, bool &changedId, bool
god=false);
// The object o may be updated if modified on insert. // The object o may be updated if modified on insert.
void insertAndLog( const char *ns, const BSONObj &o, bool god = fal se ); void insertAndLog( const char *ns, const BSONObj &o, bool god = fal se );
/** @param obj both and in and out param -- insert can sometimes mo dify an object (such as add _id). */ /** @param obj both and in and out param -- insert can sometimes mo dify an object (such as add _id). */
DiskLoc insertWithObjMod(const char *ns, BSONObj &o, bool god = fal se); DiskLoc insertWithObjMod(const char *ns, BSONObj &o, bool god = fal se);
/** @param obj in value only for this version. */ /** @param obj in value only for this version. */
void insertNoReturnVal(const char *ns, BSONObj o, bool god = false) ; void insertNoReturnVal(const char *ns, BSONObj o, bool god = false) ;
DiskLoc insert(const char *ns, const void *buf, int len, bool god = false, const BSONElement &writeId = BSONElement(), bool mayAddIndex = true ); DiskLoc insert(const char *ns, const void *buf, int len, bool god = false, const BSONElement &writeId = BSONElement(), bool mayAddIndex = true );
 End of changes. 2 change blocks. 
2 lines changed or deleted 4 lines changed or added


 queryoptimizer.h   queryoptimizer.h 
skipping to change at line 25 skipping to change at line 25
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "cursor.h" #include "cursor.h"
#include "jsobj.h" #include "jsobj.h"
#include "queryutil.h" #include "queryutil.h"
#include "matcher.h" #include "matcher.h"
#include "../util/message.h"
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
skipping to change at line 60 skipping to change at line 61
/* 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 originalQuery() const { return _originalQuery; } BSONObj originalQuery() const { return _originalQuery; }
BSONObj simplifiedQuery( const BSONObj& fields = BSONObj(), bool ex pandIn = false ) const { return fbs_.simplifiedQuery( fields, expandIn ); } BSONObj simplifiedQuery( const BSONObj& fields = BSONObj() ) const { return fbs_.simplifiedQuery( fields ); }
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 shared_ptr< FieldRangeVector > frv() const { return _frv; }
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 &_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_; shared_ptr< FieldRangeVector > _frv;
BSONObj _startKey;
BSONObj _endKey;
bool endKeyInclusive_; bool endKeyInclusive_;
bool unhelpful_; bool unhelpful_;
string _special; string _special;
IndexType * _type; IndexType * _type;
bool _startOrEndSpec;
}; };
// 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(), _haveOr Constraint() {} QueryOp() : _complete(), _stopRequested(), _qp(), _error() {}
// Used when handing off from one QueryOp type to another // Used when handing off from one QueryOp type to another
QueryOp( const QueryOp &other ) : QueryOp( const QueryOp &other ) :
_complete(), _stopRequested(), _qp(), _error(), _matcher( other._ma tcher ), _complete(), _stopRequested(), _qp(), _error(), _matcher( other._ma tcher ),
_haveOrConstraint( other._haveOrConstraint ), _orConstraint( other. _orConstraint ) {} _orConstraint( other._orConstraint ) {}
virtual ~QueryOp() {} virtual ~QueryOp() {}
/** these gets called after a query plan is set */ /** these gets called after a query plan is set */
void init() { void init() {
if ( _oldMatcher.get() ) { if ( _oldMatcher.get() ) {
_matcher.reset( _oldMatcher->nextClauseMatcher( qp().indexK ey() ) ); _matcher.reset( _oldMatcher->nextClauseMatcher( qp().indexK ey() ) );
} else { } else {
_matcher.reset( new CoveredIndexMatcher( qp().originalQuery (), qp().indexKey(), alwaysUseRecord() ) ); _matcher.reset( new CoveredIndexMatcher( qp().originalQuery (), qp().indexKey(), alwaysUseRecord() ) );
} }
_init(); _init();
} }
virtual void next() = 0; virtual void next() = 0;
virtual bool mayRecordPlan() const = 0; virtual bool mayRecordPlan() const = 0;
virtual void prepareToYield() { massert( 13335, "yield not supporte
d", false ); }
virtual void recoverFromYield() { massert( 13336, "yield not suppor
ted", false ); }
/** @return a copy of the inheriting class, which will be run with its own /** @return a copy of the inheriting class, which will be run with its own
query plan. If multiple plan sets are required for an $or query, query plan. If multiple plan sets are required for an $or query,
the QueryOp of the winning plan from a given set will b e cloned the QueryOp of the winning plan from a given set will b e cloned
to generate QueryOps for the subsequent plan set. This function to generate QueryOps for the subsequent plan set. This function
should only be called after the query op has completed executing. should only be called after the query op has completed executing.
*/ */
QueryOp *createChild() { QueryOp *createChild() {
if( _haveOrConstraint ) { if( _orConstraint.get() ) {
_matcher->addOrConstraint( _orConstraint ); _matcher->addOrConstraint( _orConstraint );
_haveOrConstraint = false; _orConstraint.reset();
} }
QueryOp *ret = _createChild(); QueryOp *ret = _createChild();
ret->_oldMatcher = _matcher; ret->_oldMatcher = _matcher;
return ret; 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; }
ExceptionInfo exception() const { return _exception; } ExceptionInfo exception() const { return _exception; }
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 setException( const DBException &e ) { void setException( const DBException &e ) {
_error = true; _error = true;
_exception = e.getInfo(); _exception = e.getInfo();
} }
shared_ptr< CoveredIndexMatcher > matcher() const { return _matcher ; } shared_ptr< CoveredIndexMatcher > matcher() const { return _matcher ; }
protected: protected:
void setComplete() { void setComplete() {
_haveOrConstraint = true; _orConstraint = qp().frv();
_orConstraint = qp().simplifiedQuery( qp().indexKey(), true );
_complete = true; _complete = true;
} }
void setStop() { setComplete(); _stopRequested = true; } void setStop() { setComplete(); _stopRequested = true; }
virtual void _init() = 0; virtual void _init() = 0;
virtual QueryOp *_createChild() const = 0; virtual QueryOp *_createChild() const = 0;
virtual bool alwaysUseRecord() const { return false; } virtual bool alwaysUseRecord() const { return false; }
private: private:
bool _complete; bool _complete;
bool _stopRequested; bool _stopRequested;
ExceptionInfo _exception; ExceptionInfo _exception;
const QueryPlan *_qp; const QueryPlan *_qp;
bool _error; bool _error;
shared_ptr< CoveredIndexMatcher > _matcher; shared_ptr< CoveredIndexMatcher > _matcher;
shared_ptr< CoveredIndexMatcher > _oldMatcher; shared_ptr< CoveredIndexMatcher > _oldMatcher;
bool _haveOrConstraint; shared_ptr< FieldRangeVector > _orConstraint;
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,
auto_ptr< FieldRangeSet > frs, auto_ptr< FieldRangeSet > frs,
const BSONObj &originalQuery, 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(),
bool bestGuessOnly = false ); bool bestGuessOnly = false,
bool mayYield = false);
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;
//for testing //for testing
skipping to change at line 203 skipping to change at line 208
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();
void mayYield( const vector< shared_ptr< QueryOp > > &ops );
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 );
static void prepareToYield( QueryOp &op );
static void recoverFromYield( QueryOp &op );
}; };
const char *ns; const char *ns;
BSONObj _originalQuery; BSONObj _originalQuery;
auto_ptr< 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;
bool _bestGuessOnly; bool _bestGuessOnly;
bool _mayYield;
ElapsedTracker _yieldSometimesTracker;
}; };
// Handles $or type queries by generating a QueryPlanSet for each $or c lause // Handles $or type queries by generating a QueryPlanSet for each $or c lause
// NOTE on our $or implementation: In our current qo implementation we don't // NOTE on our $or implementation: In our current qo implementation we don't
// keep statistics on our data, but we can conceptualize the problem of // keep statistics on our data, but we can conceptualize the problem of
// selecting an index when statistics exist for all index ranges. The // selecting an index when statistics exist for all index ranges. The
// d-hitting set problem on k sets and n elements can be reduced to the // d-hitting set problem on k sets and n elements can be reduced to the
// problem of index selection on k $or clauses and n index ranges (wher e // problem of index selection on k $or clauses and n index ranges (wher e
// d is the max number of indexes, and the number of ranges n is unboun ded). // d is the max number of indexes, and the number of ranges n is unboun ded).
// In light of the fact that d-hitting set is np complete, and we don't even // In light of the fact that d-hitting set is np complete, and we don't even
skipping to change at line 244 skipping to change at line 254
// at a time and treat each as a separate query for index selection pur poses. // at a time and treat each as a separate query for index selection pur poses.
// But if an index range is scanned for a particular $or clause, we eli minate // But if an index range is scanned for a particular $or clause, we eli minate
// that range from all subsequent clauses. One could imagine an opposi te // that range from all subsequent clauses. One could imagine an opposi te
// implementation where we select indexes based on the union of index r anges // implementation where we select indexes based on the union of index r anges
// for all $or clauses, but this can have much poorer worst case behavi or. // for all $or clauses, but this can have much poorer worst case behavi or.
// (An index range that suits one $or clause may not suit another, and this // (An index range that suits one $or clause may not suit another, and this
// is worse than the typical case of index range choice staleness becau se // is worse than the typical case of index range choice staleness becau se
// with $or the clauses may likely be logically distinct.) The greedy // with $or the clauses may likely be logically distinct.) The greedy
// implementation won't do any worse than all the $or clauses individua lly, // implementation won't do any worse than all the $or clauses individua lly,
// and it can often do better. In the first cut we are intentionally u sing // and it can often do better. In the first cut we are intentionally u sing
// QueryPattern tracking to record successful plans on $or queries for // QueryPattern tracking to record successful plans on $or clauses for
use by use by
// subsequent $or queries, even though there may be a significant aggre // subsequent $or clauses, even though there may be a significant aggre
gate gate
// $nor component that would not be represented in QueryPattern. // $nor component that would not be represented in QueryPattern.
class MultiPlanScanner { class MultiPlanScanner {
public: public:
MultiPlanScanner( const char *ns, MultiPlanScanner( const char *ns,
const BSONObj &query, const BSONObj &query,
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(),
bool bestGuessOnly = false ); bool bestGuessOnly = false,
bool mayYield = false);
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 _or ? !_fros.orFinished() : _i == 0; } 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; }
void mayYield( bool val ) { _mayYield = val; }
private: private:
void assertNotOr() const { void assertNotOr() const {
massert( 13266, "not implemented for $or query", !_or ); massert( 13266, "not implemented for $or query", !_or );
} }
bool uselessOr( const BSONElement &hint ) const; bool uselessOr( const BSONElement &hint ) const;
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;
bool _honorRecordedPlan; bool _honorRecordedPlan;
bool _bestGuessOnly; bool _bestGuessOnly;
BSONObj _hint; BSONObj _hint;
bool _mayYield;
}; };
class MultiCursor : public Cursor { class MultiCursor : public Cursor {
public: public:
class CursorOp : public QueryOp { class CursorOp : public QueryOp {
public: public:
CursorOp() {} CursorOp() {}
CursorOp( const QueryOp &other ) : QueryOp( other ) {} CursorOp( const QueryOp &other ) : QueryOp( other ) {}
virtual shared_ptr< Cursor > newCursor() const = 0; virtual shared_ptr< Cursor > newCursor() const = 0;
}; };
// takes ownership of 'op' // takes ownership of 'op'
MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj
&order, shared_ptr< CursorOp > op = shared_ptr< CursorOp >() ) &order, shared_ptr< CursorOp > op = shared_ptr< CursorOp >(), bool mayYield
: _mps( new MultiPlanScanner( ns, pattern, order, 0, true, BSONObj( = false )
), BSONObj(), !op.get() ) ) { : _mps( new MultiPlanScanner( ns, pattern, order, 0, true, BSONObj(
), BSONObj(), !op.get(), mayYield ) ) {
if ( op.get() ) { if ( op.get() ) {
_op = op; _op = op;
} else { } else {
_op.reset( new NoOp() ); _op.reset( new NoOp() );
} }
if ( _mps->mayRunMore() ) { if ( _mps->mayRunMore() ) {
nextClause(); nextClause();
if ( !ok() ) { if ( !ok() ) {
advance(); advance();
} }
} else { } else {
_c.reset( new BasicCursor( DiskLoc() ) ); _c.reset( new BasicCursor( DiskLoc() ) );
} }
} }
// used to handoff a query to a getMore() // used to handoff a query to a getMore()
MultiCursor( auto_ptr< MultiPlanScanner > mps, const shared_ptr< Cu rsor > &c, const shared_ptr< CoveredIndexMatcher > &matcher, const QueryOp &op ) MultiCursor( auto_ptr< MultiPlanScanner > mps, const shared_ptr< Cu rsor > &c, const shared_ptr< CoveredIndexMatcher > &matcher, const QueryOp &op )
: _op( new NoOp( op ) ), _c( c ), _mps( mps ), _matcher( matcher ) { : _op( new NoOp( op ) ), _c( c ), _mps( mps ), _matcher( matcher ) {
_mps->setBestGuessOnly(); _mps->setBestGuessOnly();
_mps->mayYield( false ); // with a NoOp, there's no need to yie ld in QueryPlanSet
if ( !ok() ) { if ( !ok() ) {
// would have been advanced by UserQueryOp if possible // would have been advanced by UserQueryOp if possible
advance(); advance();
} }
} }
virtual bool ok() { return _c->ok(); } virtual bool ok() { return _c->ok(); }
virtual Record* _current() { return _c->_current(); } virtual Record* _current() { return _c->_current(); }
virtual BSONObj current() { return _c->current(); } virtual BSONObj current() { return _c->current(); }
virtual DiskLoc currLoc() { return _c->currLoc(); } virtual DiskLoc currLoc() { return _c->currLoc(); }
virtual bool advance() { virtual bool advance() {
 End of changes. 22 change blocks. 
22 lines changed or deleted 39 lines changed or added


 queryutil.h   queryutil.h 
skipping to change at line 35 skipping to change at line 35
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; } void flipInclusive() { _inclusive = !_inclusive; }
}; };
struct FieldInterval { struct FieldInterval {
FieldInterval(){} FieldInterval() : _cachedEquality( -1 ) {}
FieldInterval( const BSONElement& e ){ FieldInterval( const BSONElement& e ) : _cachedEquality( -1 ) {
_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 strictValid() 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 bool equality() const {
ve && _lower._bound.woCompare( _upper._bound, false ) == 0; } if ( _cachedEquality == -1 ) {
_cachedEquality = ( _lower._inclusive && _upper._inclusive
&& _lower._bound.woCompare( _upper._bound, false ) == 0 );
}
return _cachedEquality;
}
mutable int _cachedEquality;
}; };
// 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 96 skipping to change at line 102
} }
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() { void setExclusiveBounds() {
for( vector< FieldInterval >::iterator i = _intervals.begin(); i != _intervals.end(); ++i ) { for( vector< FieldInterval >::iterator i = _intervals.begin(); i != _intervals.end(); ++i ) {
i->_lower._inclusive = false; i->_lower._inclusive = false;
i->_upper._inclusive = false; i->_upper._inclusive = false;
} }
} }
// reconstructs $in, regex, inequality matches // constructs a range which is the reverse of the current one
// this is a hack - we should submit FieldRange directly to a Match // note - the resulting intervals may not be strictValid()
er instead void reverse( FieldRange &ret ) const {
BSONObj simplifiedComplex() const; assert( _special.empty() );
ret._intervals.clear();
ret._objData = _objData;
for( vector< FieldInterval >::const_reverse_iterator i = _inter
vals.rbegin(); i != _intervals.rend(); ++i ) {
FieldInterval fi;
fi._lower = i->_upper;
fi._upper = i->_lower;
ret._intervals.push_back( fi );
}
}
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 184 skipping to change at line 200
// the specified direction of traversal. For example, given a simple i ndex {i:1} // the specified direction of traversal. For example, given a simple i ndex {i:1}
// 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;
friend class FieldRangeVector;
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 { bool hasRange( const char *fieldName ) const {
map< string, FieldRange >::const_iterator f = _ranges.find( fie ldName ); map< string, FieldRange >::const_iterator f = _ranges.find( fie ldName );
return f != _ranges.end(); 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;
skipping to change at line 210 skipping to change at line 227
} }
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(), bool ex pandIn = false ) const; BSONObj simplifiedQuery( const BSONObj &fields = BSONObj() ) const;
bool matchPossible() const { bool matchPossible() const {
for( map< string, FieldRange >::const_iterator i = _ranges.begi n(); i != _ranges.end(); ++i ) for( map< string, FieldRange >::const_iterator i = _ranges.begi n(); i != _ranges.end(); ++i )
if ( i->second.empty() ) if ( i->second.empty() )
return false; return false;
return true; return true;
} }
QueryPattern pattern( const BSONObj &sort = BSONObj() ) const; QueryPattern pattern( const BSONObj &sort = BSONObj() ) const;
BoundList indexBounds( const BSONObj &keyPattern, int direction ) c onst;
string getSpecial() const; string getSpecial() const;
const FieldRangeSet &operator-=( const FieldRangeSet &other ) { const FieldRangeSet &operator-=( const FieldRangeSet &other ) {
map< string, FieldRange >::iterator i = _ranges.begin(); map< string, FieldRange >::iterator i = _ranges.begin();
map< string, FieldRange >::const_iterator j = other._ranges.beg in(); map< string, FieldRange >::const_iterator j = other._ranges.beg in();
while( i != _ranges.end() && j != other._ranges.end() ) { while( i != _ranges.end() && j != other._ranges.end() ) {
int cmp = i->first.compare( j->first ); int cmp = i->first.compare( j->first );
if ( cmp == 0 ) { if ( cmp == 0 ) {
i->second -= j->second; i->second -= j->second;
++i; ++i;
++j; ++j;
} else if ( cmp < 0 ) { } else if ( cmp < 0 ) {
++i; ++i;
} else { } else {
++j; ++j;
} }
} }
appendQueries( other );
return *this; return *this;
} }
const FieldRangeSet &operator&=( const FieldRangeSet &other ) { const FieldRangeSet &operator&=( const FieldRangeSet &other ) {
map< string, FieldRange >::iterator i = _ranges.begin(); map< string, FieldRange >::iterator i = _ranges.begin();
map< string, FieldRange >::const_iterator j = other._ranges.beg in(); map< string, FieldRange >::const_iterator j = other._ranges.beg in();
while( i != _ranges.end() && j != other._ranges.end() ) { while( i != _ranges.end() && j != other._ranges.end() ) {
int cmp = i->first.compare( j->first ); int cmp = i->first.compare( j->first );
if ( cmp == 0 ) { if ( cmp == 0 ) {
i->second &= j->second; i->second &= j->second;
++i; ++i;
skipping to change at line 257 skipping to change at line 274
++i; ++i;
} else { } else {
_ranges[ j->first ] = j->second; _ranges[ j->first ] = j->second;
++j; ++j;
} }
} }
while( j != other._ranges.end() ) { while( j != other._ranges.end() ) {
_ranges[ j->first ] = j->second; _ranges[ j->first ] = j->second;
++j; ++j;
} }
appendQueries( other );
return *this; return *this;
} }
// TODO get rid of this
BoundList indexBounds( const BSONObj &keyPattern, int direction ) c
onst;
private: private:
void appendQueries( const FieldRangeSet &other ) {
for( vector< BSONObj >::const_iterator i = other._queries.begin
(); i != other._queries.end(); ++i ) {
_queries.push_back( *i );
}
}
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 // make sure memory for FieldRange BSONElements is owned
BSONObj _query; vector< BSONObj > _queries;
};
class FieldRangeVector {
public:
FieldRangeVector( const FieldRangeSet &frs, const BSONObj &keyPatte
rn, int direction )
:_keyPattern( keyPattern ), _direction( direction >= 0 ? 1 : -1 )
{
_queries = frs._queries;
BSONObjIterator i( _keyPattern );
while( i.more() ) {
BSONElement e = i.next();
int number = (int) e.number(); // returns 0.0 if not numeri
c
bool forward = ( ( number >= 0 ? 1 : -1 ) * ( direction >=
0 ? 1 : -1 ) > 0 );
if ( forward ) {
_ranges.push_back( frs.range( e.fieldName() ) );
} else {
_ranges.push_back( FieldRange() );
frs.range( e.fieldName() ).reverse( _ranges.back() );
}
assert( !_ranges.back().empty() );
}
uassert( 13385, "combinatorial limit of $in partitioning of res
ult set exceeded", size() < 1000000 );
}
long long size() {
long long ret = 1;
for( vector< FieldRange >::const_iterator i = _ranges.begin();
i != _ranges.end(); ++i ) {
ret *= i->intervals().size();
}
return ret;
}
BSONObj startKey() const {
BSONObjBuilder b;
for( vector< FieldRange >::const_iterator i = _ranges.begin();
i != _ranges.end(); ++i ) {
const FieldInterval &fi = i->intervals().front();
b.appendAs( fi._lower._bound, "" );
}
return b.obj();
}
BSONObj endKey() const {
BSONObjBuilder b;
for( vector< FieldRange >::const_iterator i = _ranges.begin();
i != _ranges.end(); ++i ) {
const FieldInterval &fi = i->intervals().back();
b.appendAs( fi._upper._bound, "" );
}
return b.obj();
}
BSONObj obj() const {
BSONObjBuilder b;
BSONObjIterator k( _keyPattern );
for( int i = 0; i < (int)_ranges.size(); ++i ) {
BSONArrayBuilder a( b.subarrayStart( k.next().fieldName() )
);
for( vector< FieldInterval >::const_iterator j = _ranges[ i
].intervals().begin();
j != _ranges[ i ].intervals().end(); ++j ) {
a << BSONArray( BSON_ARRAY( j->_lower._bound << j->_upp
er._bound ).clientReadable() );
}
a.done();
}
return b.obj();
}
bool matches( const BSONObj &obj ) const;
class Iterator {
public:
Iterator( const FieldRangeVector &v ) : _v( v ), _i( _v._ranges
.size(), -1 ), _cmp( _v._ranges.size(), 0 ), _superlative( _v._ranges.size(
), 0 ) {
static BSONObj minObj = minObject();
static BSONElement minElt = minObj.firstElement();
static BSONObj maxObj = maxObject();
static BSONElement maxElt = maxObj.firstElement();
BSONObjIterator i( _v._keyPattern );
for( int j = 0; j < (int)_superlative.size(); ++j ) {
int number = (int) i.next().number();
bool forward = ( ( number >= 0 ? 1 : -1 ) * ( _v._direc
tion >= 0 ? 1 : -1 ) > 0 );
_superlative[ j ] = forward ? &maxElt : &minElt;
}
}
static BSONObj minObject() {
BSONObjBuilder b;
b.appendMinKey( "" );
return b.obj();
}
static BSONObj maxObject() {
BSONObjBuilder b;
b.appendMaxKey( "" );
return b.obj();
}
bool advance() {
int i = _i.size() - 1;
while( i >= 0 && _i[ i ] >= ( (int)_v._ranges[ i ].interval
s().size() - 1 ) ) {
--i;
}
if( i >= 0 ) {
_i[ i ]++;
for( unsigned j = i + 1; j < _i.size(); ++j ) {
_i[ j ] = 0;
}
} else {
_i[ 0 ] = _v._ranges[ 0 ].intervals().size();
}
return ok();
}
// return value
// -2 end of iteration
// -1 no skipping
// >= 0 skip parameter
int advance( const BSONObj &curr );
const vector< const BSONElement * > &cmp() const { return _cmp;
}
void setZero( int i ) {
for( int j = i; j < (int)_i.size(); ++j ) {
_i[ j ] = 0;
}
}
void setMinus( int i ) {
for( int j = i; j < (int)_i.size(); ++j ) {
_i[ j ] = -1;
}
}
bool ok() {
return _i[ 0 ] < (int)_v._ranges[ 0 ].intervals().size();
}
BSONObj startKey() {
BSONObjBuilder b;
for( int unsigned i = 0; i < _i.size(); ++i ) {
const FieldInterval &fi = _v._ranges[ i ].intervals()[
_i[ i ] ];
b.appendAs( fi._lower._bound, "" );
}
return b.obj();
}
// temp
BSONObj endKey() {
BSONObjBuilder b;
for( int unsigned i = 0; i < _i.size(); ++i ) {
const FieldInterval &fi = _v._ranges[ i ].intervals()[
_i[ i ] ];
b.appendAs( fi._upper._bound, "" );
}
return b.obj();
}
// check
private:
const FieldRangeVector &_v;
vector< int > _i;
vector< const BSONElement* > _cmp;
vector< const BSONElement* > _superlative;
};
private:
int matchingLowElement( const BSONElement &e, int i, bool direction
) const;
bool matchesElement( const BSONElement &e, int i, bool direction )
const;
vector< FieldRange > _ranges;
BSONObj _keyPattern;
int _direction;
vector< BSONObj > _queries; // make sure mem owned
}; };
// generages FieldRangeSet objects, accounting for or clauses // generages FieldRangeSet objects, accounting for or clauses
class FieldRangeOrSet { class FieldRangeOrSet {
public: public:
FieldRangeOrSet( const char *ns, const BSONObj &query , bool optimi ze=true ); FieldRangeOrSet( const char *ns, const BSONObj &query , bool optimi ze=true );
// if there's a useless or clause, we won't use or ranges to help w ith scanning // if there's a useless or clause, we won't use or ranges to help w ith scanning
bool orFinished() const { return _orFound && _orSets.empty(); } bool orFinished() const { return _orFound && _orSets.empty(); }
// removes first or clause, and removes the field ranges it covers from all subsequent or clauses // removes first or clause, and removes the field ranges it covers from all subsequent or clauses
// this could invalidate the result of the last topFrs() // this could invalidate the result of the last topFrs()
skipping to change at line 312 skipping to change at line 486
_oldOrSets.push_front( toPop ); _oldOrSets.push_front( toPop );
_orSets.pop_front(); _orSets.pop_front();
} }
FieldRangeSet *topFrs() const { FieldRangeSet *topFrs() const {
FieldRangeSet *ret = new FieldRangeSet( _baseSet ); FieldRangeSet *ret = new FieldRangeSet( _baseSet );
*ret &= _orSets.front(); *ret &= _orSets.front();
return ret; return ret;
} }
void allClausesSimplified( vector< BSONObj > &ret ) const { void allClausesSimplified( vector< BSONObj > &ret ) const {
for( list< FieldRangeSet >::const_iterator i = _orSets.begin(); i != _orSets.end(); ++i ) { for( list< FieldRangeSet >::const_iterator i = _orSets.begin(); i != _orSets.end(); ++i ) {
ret.push_back( i->simplifiedQuery() ); if ( i->matchPossible() ) {
ret.push_back( i->simplifiedQuery() );
}
} }
} }
string getSpecial() const { return _baseSet.getSpecial(); } string getSpecial() const { return _baseSet.getSpecial(); }
private: private:
FieldRangeSet _baseSet; FieldRangeSet _baseSet;
list< FieldRangeSet > _orSets; list< FieldRangeSet > _orSets;
list< FieldRangeSet > _oldOrSets; // make sure memory is owned list< FieldRangeSet > _oldOrSets; // make sure memory is owned
bool _orFound; bool _orFound;
}; };
 End of changes. 13 change blocks. 
13 lines changed or deleted 210 lines changed or added


 repl.h   repl.h 
skipping to change at line 35 skipping to change at line 35
local.oplog.$<source> local.oplog.$<source>
*/ */
#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"
#include "oplog.h" #include "oplog.h"
#include "../util/concurrency/thread_pool.h"
namespace mongo { namespace mongo {
/* replication slave? (possibly with slave or repl pair nonmaster) /* replication slave? (possibly with slave or repl pair nonmaster)
--slave cmd line setting -> SimpleSlave --slave cmd line setting -> SimpleSlave
*/ */
typedef enum { NotSlave=0, SimpleSlave, ReplPairSlave } SlaveTypes; typedef enum { NotSlave=0, SimpleSlave, ReplPairSlave } SlaveTypes;
class ReplSettings { class ReplSettings {
public: public:
skipping to change at line 83 skipping to change at line 81
bool cloneFrom(const char *masterHost, string& errmsg, const string& fr omdb, bool logForReplication, bool cloneFrom(const char *masterHost, string& errmsg, const string& fr omdb, bool logForReplication,
bool slaveOk, bool useReplAuth, bool snap shot); bool slaveOk, bool useReplAuth, bool snap shot);
/* A replication exception */ /* A replication exception */
class SyncException : public DBException { class SyncException : public DBException {
public: public:
SyncException() : DBException( "sync exception" , 10001 ){} SyncException() : DBException( "sync exception" , 10001 ){}
}; };
/* started abstracting out the querying of the primary/master's oplog
still fairly awkward but a start.
*/
class OplogReader {
auto_ptr<DBClientConnection> _conn;
auto_ptr<DBClientCursor> cursor;
public:
void reset() {
cursor.reset();
}
void resetConnection() {
cursor.reset();
_conn.reset();
}
DBClientConnection* conn() { return _conn.get(); }
BSONObj findOne(const char *ns, Query& q) {
return conn()->findOne(ns, q);
}
/* ok to call if already connected */
bool connect(string hostname);
void getReady() {
if( cursor.get() && cursor->isDead() ) {
log() << "repl: old cursor isDead, initiating a new one" <<
endl;
reset();
}
}
bool haveCursor() { return cursor.get() != 0; }
void tailingQuery(const char *ns, BSONObj& query) {
assert( !haveCursor() );
log(2) << "repl: " << ns << ".find(" << query.toString() << ')'
<< endl;
cursor = _conn->query( ns, query, 0, 0, 0,
QueryOption_CursorTailable | QueryOption_
SlaveOk | QueryOption_OplogReplay |
QueryOption_AwaitData
);
}
bool more() {
assert( cursor.get() );
return cursor->more();
}
/* old mongod's can't do the await flag... */
bool awaitCapable() {
return cursor->hasResultFlag(QueryResult::ResultFlag_AwaitCapab
le);
}
void peek(vector<BSONObj>& v, int n) {
if( cursor.get() )
cursor->peek(v,n);
}
BSONObj next() {
return cursor->next();
}
void putBack(BSONObj op) {
cursor->putBack(op);
}
};
/* A Source is a source from which we can pull (replicate) data. /* A Source is a source from which we can pull (replicate) data.
stored in collection local.sources. stored in collection local.sources.
Can be a group of things to replicate for several databases. Can be a group of things to replicate for several databases.
{ host: ..., source: ..., only: ..., syncedTo: ..., localLogTs: . .., dbsNextPass: { ... }, incompleteCloneDbs: { ... } } { host: ..., source: ..., only: ..., syncedTo: ..., localLogTs: . .., dbsNextPass: { ... }, incompleteCloneDbs: { ... } }
'source' defaults to 'main'; support for multiple source names is 'source' defaults to 'main'; support for multiple source names is
not done (always use main for now). not done (always use main for now).
*/ */
class ReplSource { class ReplSource {
auto_ptr<ThreadPool> tp;
bool resync(string db); bool resync(string db);
/* pull some operations from the master's oplog, and apply them. */ /* pull some operations from the master's oplog, and apply them. */
int sync_pullOpLog(int& nApplied); int sync_pullOpLog(int& nApplied);
void sync_pullOpLog_applyOperation(BSONObj& op, OpTime *localLogTai l); void sync_pullOpLog_applyOperation(BSONObj& op, OpTime *localLogTai l);
auto_ptr<DBClientConnection> conn;
auto_ptr<DBClientCursor> cursor;
/* we only clone one database per pass, even if a lot need done. T his helps us /* we only clone one database per pass, even if a lot need done. T his helps us
avoid overflowing the master's transaction log by doing too much work before going avoid overflowing the master's transaction log by doing too much work before going
back to read more transactions. (Imagine a scenario of slave sta rtup where we try to back to read more transactions. (Imagine a scenario of slave sta rtup where we try to
clone 100 databases in one pass.) clone 100 databases in one pass.)
*/ */
set<string> addDbNextPass; set<string> addDbNextPass;
set<string> incompleteCloneDbs; set<string> incompleteCloneDbs;
ReplSource(); ReplSource();
// returns the dummy ns used to do the drop // returns the dummy ns used to do the drop
string resyncDrop( const char *db, const char *requester ); string resyncDrop( const char *db, const char *requester );
// returns true if connected on return
bool connect();
// returns possibly unowned id spec for the operation. // returns possibly unowned id spec for the operation.
static BSONObj idForOp( const BSONObj &op, bool &mod ); static BSONObj idForOp( const BSONObj &op, bool &mod );
static void updateSetsWithOp( const BSONObj &op, bool mayUpdateStor age ); static void updateSetsWithOp( const BSONObj &op, bool mayUpdateStor age );
// call without the db mutex // call without the db mutex
void syncToTailOfRemoteLog(); void syncToTailOfRemoteLog();
// call with the db mutex // call with the db mutex
OpTime nextLastSavedLocalTs() const; OpTime nextLastSavedLocalTs() const;
void setLastSavedLocalTs( const OpTime &nextLocalTs ); void setLastSavedLocalTs( const OpTime &nextLocalTs );
// call without the db mutex // call without the db mutex
void resetSlave(); void resetSlave();
// call with the db mutex // call with the db mutex
// returns false if the slave has been reset // returns false if the slave has been reset
bool updateSetsWithLocalOps( OpTime &localLogTail, bool mayUnlock ) ; bool updateSetsWithLocalOps( OpTime &localLogTail, bool mayUnlock ) ;
string ns() const { return string( "local.oplog.$" ) + sourceName() ; } string ns() const { return string( "local.oplog.$" ) + sourceName() ; }
unsigned _sleepAdviceTime; unsigned _sleepAdviceTime;
public: public:
OplogReader oplogReader;
static void applyOperation(const BSONObj& op); static void applyOperation(const BSONObj& op);
bool replacing; // in "replace mode" -- see CmdReplacePeer bool replacing; // in "replace mode" -- see CmdReplacePeer
bool paired; // --pair in use bool paired; // --pair in use
string hostName; // ip addr or hostname plus optionally, ":<port >" string hostName; // ip addr or hostname plus optionally, ":<port >"
string _sourceName; // a logical source name. string _sourceName; // a logical source name.
string sourceName() const { string sourceName() const {
return _sourceName.empty() ? "main" : _sourceName; return _sourceName.empty() ? "main" : _sourceName;
} }
string only; // only a certain db. note that in the sources collect ion, this may not be changed once you start replicating. string only; // only a certain db. note that in the sources collect ion, this may not be changed once you start replicating.
skipping to change at line 167 skipping to change at line 229
int nClonedThisPass; int nClonedThisPass;
typedef vector< shared_ptr< ReplSource > > SourceVector; typedef vector< shared_ptr< ReplSource > > SourceVector;
static void loadAll(SourceVector&); static void loadAll(SourceVector&);
explicit ReplSource(BSONObj); explicit ReplSource(BSONObj);
/* -1 = error */ /* -1 = error */
int sync(int& nApplied); int sync(int& nApplied);
void save(); // write ourself to local.sources void save(); // write ourself to local.sources
void resetConnection() {
cursor = auto_ptr<DBClientCursor>(0);
conn = auto_ptr<DBClientConnection>(0);
}
// make a jsobj from our member fields of the form // make a jsobj from our member fields of the form
// { host: ..., source: ..., syncedTo: ... } // { host: ..., source: ..., syncedTo: ... }
BSONObj jsobj(); BSONObj jsobj();
bool operator==(const ReplSource&r) const { bool operator==(const ReplSource&r) const {
return hostName == r.hostName && sourceName() == r.sourceName() ; return hostName == r.hostName && sourceName() == r.sourceName() ;
} }
operator string() const { return sourceName() + "@" + hostName; } operator string() const { return sourceName() + "@" + hostName; }
 End of changes. 10 change blocks. 
12 lines changed or deleted 74 lines changed or added


 rs.h   rs.h 
skipping to change at line 28 skipping to change at line 28
#pragma once #pragma once
#include "../../util/concurrency/list.h" #include "../../util/concurrency/list.h"
#include "../../util/concurrency/value.h" #include "../../util/concurrency/value.h"
#include "../../util/concurrency/msg.h" #include "../../util/concurrency/msg.h"
#include "../../util/hostandport.h" #include "../../util/hostandport.h"
#include "../commands.h" #include "../commands.h"
#include "rs_exception.h" #include "rs_exception.h"
#include "rs_optime.h" #include "rs_optime.h"
#include "rsmember.h" #include "rs_member.h"
#include "rs_config.h" #include "rs_config.h"
namespace mongo { namespace mongo {
struct Target; struct Target;
class ReplSetImpl; class ReplSetImpl;
extern bool replSet; // true if using repl sets extern bool replSet; // true if using repl sets
extern class ReplSet *theReplSet; // null until initialized extern class ReplSet *theReplSet; // null until initialized
extern Tee *rsLog; extern Tee *rsLog;
/* member of a replica set */
class Member : public List1<Member>::Base { class Member : public List1<Member>::Base {
public: public:
Member(HostAndPort h, unsigned ord, const ReplSetConfig::MemberCfg *c); Member(HostAndPort h, unsigned ord, const ReplSetConfig::MemberCfg *c);
string fullName() const { return h().toString(); } string fullName() const { return h().toString(); }
const ReplSetConfig::MemberCfg& config() const { return *_config; } const ReplSetConfig::MemberCfg& config() const { return *_config; }
const HeartbeatInfo& hbinfo() const { return _hbinfo; } const HeartbeatInfo& hbinfo() const { return _hbinfo; }
string lhb() { return _hbinfo.lastHeartbeatMsg; } string lhb() { return _hbinfo.lastHeartbeatMsg; }
MemberState state() const { return _hbinfo.hbstate; } MemberState state() const { return _hbinfo.hbstate; }
const HostAndPort& h() const { return _h; } const HostAndPort& h() const { return _h; }
skipping to change at line 97 skipping to change at line 99
Consensus(ReplSetImpl *t) : rs(*t) { Consensus(ReplSetImpl *t) : rs(*t) {
sleptLast = false; sleptLast = false;
} }
int totalVotes() const; int totalVotes() const;
bool aMajoritySeemsToBeUp() const; bool aMajoritySeemsToBeUp() const;
void electSelf(); void electSelf();
void electCmdReceived(BSONObj, BSONObjBuilder*); void electCmdReceived(BSONObj, BSONObjBuilder*);
void multiCommand(BSONObj cmd, list<Target>& L); void multiCommand(BSONObj cmd, list<Target>& L);
}; };
/** most operations on a ReplSet object should be done while locked. */ /** most operations on a ReplSet object should be done while locked. th at logic implemented here. */
class RSBase : boost::noncopyable { class RSBase : boost::noncopyable {
private: private:
mutex m; mutex m;
int _locked; int _locked;
ThreadLocalValue<bool> _lockedByMe; ThreadLocalValue<bool> _lockedByMe;
protected: protected:
RSBase() : m("RSBase"), _locked(0) { } RSBase() : m("RSBase"), _locked(0) { }
class lock : scoped_lock {
RSBase& _b; class lock {
RSBase& rsbase;
auto_ptr<scoped_lock> sl;
public: public:
lock(RSBase* b) : scoped_lock(b->m), _b(*b) { lock(RSBase* b) : rsbase(*b) {
DEV assert(_b._locked == 0); if( rsbase._lockedByMe.get() )
_b._locked++; return; // recursive is ok...
_b._lockedByMe.set(true);
cout << "RSLOCKED" << endl; sl.reset( new scoped_lock(rsbase.m) );
DEV assert(rsbase._locked == 0);
rsbase._locked++;
rsbase._lockedByMe.set(true);
} }
~lock() { ~lock() {
cout << "RSUNLOCKED" << endl; if( sl.get() ) {
assert( _b._lockedByMe.get() ); assert( rsbase._lockedByMe.get() );
DEV assert(_b._locked == 1); DEV assert(rsbase._locked == 1);
_b._lockedByMe.set(false); rsbase._lockedByMe.set(false);
_b._locked--; rsbase._locked--;
}
} }
}; };
public: public:
/* for asserts */ /* for asserts */
bool locked() const { return _locked != 0; } bool locked() const { return _locked != 0; }
/* if true, is locked, and was locked by this thread. note if false , it could be in the lock or not for another /* if true, is locked, and was locked by this thread. note if false , it could be in the lock or not for another
just for asserts & such so we can make the contracts clear on wh o locks what when. just for asserts & such so we can make the contracts clear on wh o locks what when.
we don't use these locks that frequently, so the little bit of o verhead is fine. we don't use these locks that frequently, so the little bit of o verhead is fine.
*/ */
bool lockedByMe() { return _lockedByMe.get(); } bool lockedByMe() { return _lockedByMe.get(); }
}; };
skipping to change at line 133 skipping to change at line 142
/* for asserts */ /* for asserts */
bool locked() const { return _locked != 0; } bool locked() const { return _locked != 0; }
/* if true, is locked, and was locked by this thread. note if false , it could be in the lock or not for another /* if true, is locked, and was locked by this thread. note if false , it could be in the lock or not for another
just for asserts & such so we can make the contracts clear on wh o locks what when. just for asserts & such so we can make the contracts clear on wh o locks what when.
we don't use these locks that frequently, so the little bit of o verhead is fine. we don't use these locks that frequently, so the little bit of o verhead is fine.
*/ */
bool lockedByMe() { return _lockedByMe.get(); } bool lockedByMe() { return _lockedByMe.get(); }
}; };
class ReplSetHealthPollTask;
/* information about the entire repl set, such as the various servers i n the set, and their state */ /* information about the entire repl set, such as the various servers i n the set, and their state */
/* note: We currently do not free mem when the set goes away - it is as sumed the replset is a /* note: We currently do not free mem when the set goes away - it is as sumed the replset is a
singleton and long lived. singleton and long lived.
*/ */
class ReplSetImpl : RSBase { class ReplSetImpl : protected RSBase {
public: public:
/** info on our state if the replset isn't yet "up". for example, if we are pre-initiation. */ /** info on our state if the replset isn't yet "up". for example, if we are pre-initiation. */
enum StartupStatus { enum StartupStatus {
PRESTART=0, LOADINGCONFIG=1, BADCONFIG=2, EMPTYCONFIG=3, PRESTART=0, LOADINGCONFIG=1, BADCONFIG=2, EMPTYCONFIG=3,
EMPTYUNREACHABLE=4, STARTED=5, SOON=6 EMPTYUNREACHABLE=4, STARTED=5, SOON=6
}; };
static StartupStatus startupStatus; static StartupStatus startupStatus;
static string startupStatusMsg; static string startupStatusMsg;
static string stateAsStr(MemberState state); static string stateAsStr(MemberState state);
static string stateAsHtml(MemberState state); static string stateAsHtml(MemberState state);
skipping to change at line 161 skipping to change at line 172
bool isPrimary() const { return _myState == PRIMARY; } bool isPrimary() const { return _myState == PRIMARY; }
bool isSecondary() const { return _myState == SECONDARY; } bool isSecondary() const { return _myState == SECONDARY; }
//bool initiated() const { return curOpTime.initiated(); } //bool initiated() const { return curOpTime.initiated(); }
OpTime lastOpTimeWritten; OpTime lastOpTimeWritten;
long long h; long long h;
private: private:
unsigned _selfId; // stored redundantly we hit this a lot unsigned _selfId; // stored redundantly we hit this a lot
set<ReplSetHealthPollTask*> healthTasks;
void endOldHealthTasks();
void startHealthTaskFor(Member *m);
private: private:
Consensus elect; Consensus elect;
bool ok() const { return _myState != FATAL; } bool ok() const { return _myState != FATAL; }
void relinquish(); void relinquish();
void assumePrimary(); void assumePrimary();
void loadLastOpTimeWritten(); void loadLastOpTimeWritten();
protected: protected:
// "heartbeat message"
// sent in requestHeartbeat respond in field "hbm"
char _hbmsg[256];
void sethbmsg(string s) {
assert(s.size() < sizeof(_hbmsg));
strcpy(_hbmsg, s.c_str());
}
bool initFromConfig(ReplSetConfig& c); // true if ok; throws if con
fig really bad; false if config doesn't include self
void _fillIsMaster(BSONObjBuilder&); void _fillIsMaster(BSONObjBuilder&);
void _fillIsMasterHost(const Member*, vector<string>&, vector<strin g>&, vector<string>&);
const ReplSetConfig& config() { return *_cfg; } const ReplSetConfig& config() { return *_cfg; }
string name() const { return _name; } /* @return replica set's logi cal name */ string name() const { return _name; } /* @return replica set's logi cal name */
MemberState state() const { return _myState; } MemberState state() const { return _myState; }
void _fatal(); void _fatal();
void _getOplogDiagsAsHtml(unsigned server_id, stringstream& ss) con st; void _getOplogDiagsAsHtml(unsigned server_id, stringstream& ss) con st;
void _summarizeAsHtml(stringstream&) const; void _summarizeAsHtml(stringstream&) const;
void _summarizeStatus(BSONObjBuilder&) const; // for replSetGetStat us command void _summarizeStatus(BSONObjBuilder&) const; // for replSetGetStat us command
/* cfgString format is /* cfgString format is
replsetname/host1,host2:port,... replsetname/host1,host2:port,...
where :port is optional. where :port is optional.
throws exception if a problem initializing. */ throws exception if a problem initializing. */
ReplSetImpl(string cfgString); ReplSetImpl(string cfgString);
/* call after constructing to start - returns fairly quickly after launching its threads */ /* call afer constructing to start - returns fairly quickly after l aunching its threads */
void _go(); void _go();
private: private:
MemberState _myState; MemberState _myState;
string _name; string _name;
const vector<HostAndPort> *_seeds; const vector<HostAndPort> *_seeds;
ReplSetConfig *_cfg; ReplSetConfig *_cfg;
/** load our configuration from admin.replset. try seed machines t oo. /** load our configuration from admin.replset. try seed machines t oo.
throws exception if a problem. @return true if ok; throws if config really bad; false if confi g doesn't include self
*/ */
void _loadConfigFinish(vector<ReplSetConfig>& v); bool _loadConfigFinish(vector<ReplSetConfig>& v);
void loadConfig(); void loadConfig();
void initFromConfig(ReplSetConfig& c);//, bool save);
list<HostAndPort> memberHostnames() const; list<HostAndPort> memberHostnames() const;
const Member* currentPrimary() const { return _currentPrimary; } const Member* currentPrimary() const { return _currentPrimary; }
const ReplSetConfig::MemberCfg& myConfig() const { return _self->co nfig(); } const ReplSetConfig::MemberCfg& myConfig() const { return _self->co nfig(); }
private:
const Member *_currentPrimary; const Member *_currentPrimary;
Member *_self; Member *_self;
List1<Member> _members; /* all members of the set EXCEPT self. */ List1<Member> _members; /* all members of the set EXCEPT self. */
public: public:
unsigned selfId() const { return _selfId; } unsigned selfId() const { return _selfId; }
shared_ptr<Manager> mgr; shared_ptr<Manager> mgr;
private: private:
Member* head() const { return _members.head(); } Member* head() const { return _members.head(); }
Member* findById(unsigned id) const; Member* findById(unsigned id) const;
void _getTargets(list<Target>&, int &configVersion); void _getTargets(list<Target>&, int &configVersion);
void getTargets(list<Target>&, int &configVersion); void getTargets(list<Target>&, int &configVersion);
void startThreads(); void startThreads();
friend class FeedbackThread; friend class FeedbackThread;
friend class CmdReplSetElect; friend class CmdReplSetElect;
friend class Member; friend class Member;
friend class Manager; friend class Manager;
friend class Consensus; friend class Consensus;
private:
/* pulling data from primary related - see rs_sync.cpp */
void syncDoInitialSync();
}; };
class ReplSet : public ReplSetImpl { class ReplSet : public ReplSetImpl {
public: public:
ReplSet(string cfgString) : ReplSetImpl(cfgString) { } ReplSet(string cfgString) : ReplSetImpl(cfgString) {
/* call after constructing to start - returns fairly quickly after }
launching its threads */
/* call after constructing to start - returns fairly quickly after
la[unching its threads */
void go() { _go(); } void go() { _go(); }
void fatal() { _fatal(); } void fatal() { _fatal(); }
bool isMaster(const char *client); bool isMaster(const char *client);
MemberState state() const { return ReplSetImpl::state(); } MemberState state() const { return ReplSetImpl::state(); }
string name() const { return ReplSetImpl::name(); } string name() const { return ReplSetImpl::name(); }
const ReplSetConfig& config() { return ReplSetImpl::config(); } const ReplSetConfig& config() { return ReplSetImpl::config(); }
void getOplogDiagsAsHtml(unsigned server_id, stringstream& ss) cons t { _getOplogDiagsAsHtml(server_id,ss); } void getOplogDiagsAsHtml(unsigned server_id, stringstream& ss) cons t { _getOplogDiagsAsHtml(server_id,ss); }
void summarizeAsHtml(stringstream& ss) const { _summarizeAsHtml(ss) ; } void summarizeAsHtml(stringstream& ss) const { _summarizeAsHtml(ss) ; }
void summarizeStatus(BSONObjBuilder& b) const { _summarizeStatus(b ); } void summarizeStatus(BSONObjBuilder& b) const { _summarizeStatus(b ); }
void fillIsMaster(BSONObjBuilder& b) { _fillIsMaster(b); } void fillIsMaster(BSONObjBuilder& b) { _fillIsMaster(b); }
/* we have a new config (reconfig) - apply it. */
void haveNewConfig(ReplSetConfig& c);
/* if we delete old configs, this needs to assure locking. currentl
y we don't so it is ok. */
const ReplSetConfig& getConfig() { return config(); }
bool lockedByMe() { return RSBase::lockedByMe(); }
// heartbeat msg to send to others; descriptive diagnostic info
string hbmsg() const { return _hbmsg; }
}; };
/** base class for repl set commands. checks basic things such as in r s mode before the command /** base class for repl set commands. checks basic things such as in r s mode before the command
does its real work does its real work
*/ */
class ReplSetCommand : public Command { class ReplSetCommand : public Command {
protected: protected:
ReplSetCommand(const char * s, bool show=false) : Command(s) { } ReplSetCommand(const char * s, bool show=false) : Command(s) { }
virtual bool slaveOk() const { return true; } virtual bool slaveOk() const { return true; }
virtual bool adminOnly() const { return true; } virtual bool adminOnly() const { return true; }
skipping to change at line 269 skipping to change at line 308
} }
if( theReplSet == 0 ) { if( theReplSet == 0 ) {
result.append("startupStatus", ReplSet::startupStatus); result.append("startupStatus", ReplSet::startupStatus);
errmsg = ReplSet::startupStatusMsg.empty() ? "replset unkno wn error 2" : ReplSet::startupStatusMsg; errmsg = ReplSet::startupStatusMsg.empty() ? "replset unkno wn error 2" : ReplSet::startupStatusMsg;
return false; return false;
} }
return true; return true;
} }
}; };
/** helpers ----------------- */
void parseReplsetCmdLine(string cfgString, string& setname, vector<Host
AndPort>& seeds, set<HostAndPort>& seedSet );
/** inlines ----------------- */ /** inlines ----------------- */
inline Member::Member(HostAndPort h, unsigned ord, const ReplSetConfig: :MemberCfg *c) : inline Member::Member(HostAndPort h, unsigned ord, const ReplSetConfig: :MemberCfg *c) :
_config(c), _h(h), _hbinfo(ord) { } _config(c), _h(h), _hbinfo(ord) { }
inline bool ReplSet::isMaster(const char *client) { inline bool ReplSet::isMaster(const char *client) {
/* todo replset */ /* todo replset */
return false; return isPrimary();
} }
} }
 End of changes. 22 change blocks. 
25 lines changed or deleted 70 lines changed or added


 rs_config.h   rs_config.h 
skipping to change at line 53 skipping to change at line 53
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 { bool hot() const {
return !arbiterOnly; return !arbiterOnly && priority > 0;
} }
}; };
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
/** @return true if could connect, and there is no cfg object there at all */ /** @return true if could connect, and there is no cfg object there at all */
bool empty() const { return version == EMPTYCONFIG; } bool empty() const { return version == EMPTYCONFIG; }
string toString() const { return asBson().toString(); } string toString() const { return asBson().toString(); }
/** validate the settings. does not call check() on each member, yo u have to do that separately. */ /** validate the settings. does not call check() on each member, yo u have to do that separately. */
void check() const; void check() const;
/** check if modification makes sense */
static bool legalChange(const ReplSetConfig& old, const ReplSetConf
ig& n, string& errmsg);
static void receivedNewConfig(BSONObj); static void receivedNewConfig(BSONObj);
void saveConfigLocally(BSONObj comment); // to local db void saveConfigLocally(BSONObj comment); // to local db
string saveConfigEverywhere(); // returns textual info on what happ ened string saveConfigEverywhere(); // returns textual info on what happ ened
BSONObj asBson() const; BSONObj asBson() const;
private: private:
bool _ok; bool _ok;
void from(BSONObj); void from(BSONObj);
void clear(); void clear();
 End of changes. 2 change blocks. 
1 lines changed or deleted 5 lines changed or added


 server.h   server.h 
skipping to change at line 25 skipping to change at line 25
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string> #include <string>
#include "../util/message.h" #include "../util/message.h"
#include "../db/jsobj.h" #include "../db/jsobj.h"
namespace mongo { namespace mongo {
extern std::string ourHostname;
extern OID serverID; extern OID serverID;
// from request.cpp // from request.cpp
void processRequest(Message& m, MessagingPort& p); void processRequest(Message& m, MessagingPort& p);
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 0 lines changed or added


 shard.h   shard.h 
skipping to change at line 195 skipping to change at line 195
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(); ~ShardConnection();
void done(); void done();
void kill(); void kill();
DBClientBase& conn(){ DBClientBase& conn(){
_finishInit();
assert( _conn ); assert( _conn );
return *_conn; return *_conn;
} }
DBClientBase* operator->(){ DBClientBase* operator->(){
_finishInit();
assert( _conn ); assert( _conn );
return _conn; return _conn;
} }
DBClientBase* get(){ DBClientBase* get(){
_finishInit();
assert( _conn ); assert( _conn );
return _conn; return _conn;
} }
string getHost() const { string getHost() const {
return _addr; return _addr;
} }
bool setVersion() const { bool setVersion() {
_finishInit();
return _setVersion; return _setVersion;
} }
static void sync(); static void sync();
private: private:
void _init(); void _init();
void _finishInit();
bool _finishedInit;
string _addr; string _addr;
string _ns; string _ns;
DBClientBase* _conn; DBClientBase* _conn;
bool _setVersion; bool _setVersion;
}; };
} }
 End of changes. 5 change blocks. 
1 lines changed or deleted 8 lines changed or added


 shardkey.h   shardkey.h 
skipping to change at line 71 skipping to change at line 71
*/ */
int compare( const BSONObj& l , const BSONObj& r ) const; int compare( const BSONObj& l , const BSONObj& r ) const;
/** /**
@return whether or not obj has all fields in this shard key patt ern @return whether or not obj has all fields in this shard key patt ern
e.g. e.g.
ShardKey({num:1}).hasShardKey({ name:"joe", num:3 }) is true ShardKey({num:1}).hasShardKey({ name:"joe", num:3 }) is true
*/ */
bool hasShardKey( const BSONObj& obj ) const; bool hasShardKey( const BSONObj& obj ) const;
/**
returns a query that filters results only for the range desired,
i.e. returns
{ "field" : { $gte: keyval(min), $lt: keyval(max) } }
*/
void getFilter( BSONObjBuilder& b , const BSONObj& min, const BSONO
bj& max ) const;
/**
Returns if the given sort pattern can be ordered by the shard ke
y pattern.
Example
sort: { ts: -1 }
*this: { ts:1 }
-> -1
@return
0 if sort either doesn't have all the fields or has extra fie
lds
< 0 if sort is descending
> 1 if sort is ascending
*/
int canOrder( const BSONObj& sort ) const;
BSONObj key() const { return pattern; } BSONObj key() const { return pattern; }
string toString() const; string toString() const;
BSONObj extractKey(const BSONObj& from) const; BSONObj extractKey(const BSONObj& from) const;
bool partOfShardKey(const string& key ) const { bool partOfShardKey(const string& key ) const {
return patternfields.count( key ) > 0; return patternfields.count( key ) > 0;
} }
skipping to change at line 120 skipping to change at line 100
private: private:
BSONObj pattern; BSONObj pattern;
BSONObj gMin; BSONObj gMin;
BSONObj gMax; BSONObj gMax;
/* question: better to have patternfields precomputed or not? depe nds on if we use copy constructor often. */ /* question: better to have patternfields precomputed or not? depe nds on if we use copy constructor often. */
set<string> patternfields; set<string> patternfields;
}; };
inline BSONObj ShardKeyPattern::extractKey(const BSONObj& from) const { inline BSONObj ShardKeyPattern::extractKey(const BSONObj& from) const {
return from.extractFields(pattern); BSONObj k = from.extractFields(pattern);
uassert(13334, "Shard Key must be less than 512 bytes", k.objsize()
< 512);
return k;
} }
} }
 End of changes. 2 change blocks. 
25 lines changed or deleted 4 lines changed or added


 sock.h   sock.h 
skipping to change at line 255 skipping to change at line 255
inline string getHostName() { inline string getHostName() {
char buf[256]; char buf[256];
int ec = gethostname(buf, 127); int ec = gethostname(buf, 127);
if ( ec || *buf == 0 ) { if ( ec || *buf == 0 ) {
log() << "can't get this server's hostname " << errnoWithDescri ption() << endl; log() << "can't get this server's hostname " << errnoWithDescri ption() << endl;
return ""; return "";
} }
return buf; return buf;
} }
string getHostNameCached();
class ListeningSockets { class ListeningSockets {
public: public:
ListeningSockets() : _mutex("ListeningSockets"), _sockets( new set< int>() ){ ListeningSockets() : _mutex("ListeningSockets"), _sockets( new set< int>() ){
} }
void add( int sock ){ void add( int sock ){
scoped_lock lk( _mutex ); scoped_lock lk( _mutex );
_sockets->insert( sock ); _sockets->insert( sock );
} }
void remove( int sock ){ void remove( int sock ){
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 syncclusterconnection.h   syncclusterconnection.h 
skipping to change at line 99 skipping to change at line 99
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 );
int _lockType( const string& name ); int _lockType( const string& name );
void _checkLast(); void _checkLast();
void _connect( string host ); void _connect( string host );
string _address; string _address;
vector<string> _connAddresses;
vector<DBClientConnection*> _conns; vector<DBClientConnection*> _conns;
map<string,int> _lockTypes; map<string,int> _lockTypes;
mongo::mutex _mutex; mongo::mutex _mutex;
BSONObj _lastError; vector<BSONObj> _lastErrors;
};
class UpdateNotTheSame : public UserException {
public:
UpdateNotTheSame( int code , const string& msg , const vector<strin
g>& addrs , const vector<BSONObj>& lastErrors )
: UserException( code , msg ) , _addrs( addrs ) , _lastErrors(
lastErrors ){
assert( _addrs.size() == _lastErrors.size() );
}
virtual ~UpdateNotTheSame() throw() {
}
unsigned size() const {
return _addrs.size();
}
pair<string,BSONObj> operator[](unsigned i) const {
return make_pair( _addrs[i] , _lastErrors[i] );
}
private:
vector<string> _addrs;
vector<BSONObj> _lastErrors;
}; };
}; };
#include "undef_macros.h" #include "undef_macros.h"
 End of changes. 2 change blocks. 
1 lines changed or deleted 28 lines changed or added


 task.h   task.h 
skipping to change at line 38 skipping to change at line 38
a shared_ptr is kept to the task - both by the task while runni ng and the caller. that way a shared_ptr is kept to the task - both by the task while runni ng and the caller. that way
the task object gets cleaned up once the last reference goes aw ay. the task object gets cleaned up once the last reference goes aw ay.
*/ */
class Task : private BackgroundJob { class Task : private BackgroundJob {
protected: protected:
virtual void doWork() = 0; // implement the ta sk here. virtual void doWork() = 0; // implement the ta sk here.
virtual string name() = 0; // name the threada virtual string name() = 0; // name the threada
public: public:
Task(); Task();
/** for a repeating task, stop after current invocation ends. * /** for a repeating task, stop after current invocation ends. c
/ an be called by other threads
as long as the Task is still in scope.
*/
void halt(); void halt();
private: private:
shared_ptr<Task> me; shared_ptr<Task> me;
unsigned n, repeat; unsigned n, repeat;
friend void fork(shared_ptr<Task> t); friend void fork(shared_ptr<Task> t);
friend void repeat(shared_ptr<Task> t, unsigned millis); friend void repeat(shared_ptr<Task> t, unsigned millis);
virtual void run(); virtual void run();
virtual void ending(); virtual void ending();
void begin(shared_ptr<Task>); void begin(shared_ptr<Task>);
}; };
 End of changes. 1 change blocks. 
2 lines changed or deleted 4 lines changed or added


 tool.h   tool.h 
skipping to change at line 82 skipping to change at line 82
} }
return _db + "." + _coll; return _db + "." + _coll;
} }
virtual void preSetup(){} virtual void preSetup(){}
virtual int run() = 0; virtual int run() = 0;
virtual void printHelp(ostream &out); virtual void printHelp(ostream &out);
virtual void printExtraHelp( ostream & out ); virtual void printExtraHelp( ostream & out ){}
virtual void printExtraHelpAfter( ostream & out ){}
protected: protected:
mongo::DBClientBase &conn( bool slaveIfPaired = false ); mongo::DBClientBase &conn( bool slaveIfPaired = false );
void auth( string db = "" ); void auth( string db = "" );
string _name; string _name;
string _db; string _db;
string _coll; string _coll;
 End of changes. 1 change blocks. 
1 lines changed or deleted 2 lines changed or added


 update.h   update.h 
skipping to change at line 135 skipping to change at line 135
return true; return true;
if ( strstr( fieldName , "." ) ){ if ( strstr( fieldName , "." ) ){
// check for a.0.1 // check for a.0.1
StringBuilder buf( fullName.size() + 1 ); StringBuilder buf( fullName.size() + 1 );
for ( size_t i=0; i<fullName.size(); i++ ){ for ( size_t i=0; i<fullName.size(); i++ ){
char c = fullName[i]; char c = fullName[i];
if ( c == '$' && if ( c == '$' &&
i > 0 && fullName[i-1] == '.' && i > 0 && fullName[i-1] == '.' &&
i+1<fullName.size() &&
fullName[i+1] == '.' ){ fullName[i+1] == '.' ){
i++; i++;
continue; continue;
} }
buf << c; buf << c;
if ( c != '.' ) if ( c != '.' )
continue; continue;
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 util.h   util.h 
skipping to change at line 23 skipping to change at line 23
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "../client/dbclient.h" #include "../client/dbclient.h"
#include "../db/jsobj.h"
/** /**
some generic sharding utils that can be used in mongod or mongos some generic sharding utils that can be used in mongod or mongos
*/ */
namespace mongo { namespace mongo {
struct ShardChunkVersion {
union {
struct {
int _minor;
int _major;
};
unsigned long long _combined;
};
ShardChunkVersion( int major=0, int minor=0 )
: _minor(minor),_major(major){
}
ShardChunkVersion( unsigned long long ll )
: _combined( ll ){
}
ShardChunkVersion( const BSONElement& e ){
if ( e.type() == Date || e.type() == Timestamp ){
_combined = e._numberLong();
}
else if ( e.eoo() ){
_combined = 0;
}
else {
log() << "ShardChunkVersion can't handle type (" << (int)(e
.type()) << ") " << e << endl;
assert(0);
}
}
ShardChunkVersion incMajor() const {
return ShardChunkVersion( _major + 1 , 0 );
}
void operator++(){
_minor++;
}
unsigned long long toLong() const {
return _combined;
}
bool isSet() const {
return _combined > 0;
}
string toString() const {
stringstream ss;
ss << _major << "|" << _minor;
return ss.str();
}
operator unsigned long long() const { return _combined; }
operator string() const { return toString(); }
ShardChunkVersion& operator=( const BSONElement& elem ){
switch ( elem.type() ){
case Timestamp:
case NumberLong:
case Date:
_combined = elem._numberLong();
break;
case EOO:
_combined = 0;
break;
default:
assert(0);
}
return *this;
}
};
inline ostream& operator<<( ostream &s , const ShardChunkVersion& v){
s << v._major << "|" << v._minor;
return s;
}
/** /**
* your config info for a given shard/chunk is out of date * your config info for a given shard/chunk is out of date
*/ */
class StaleConfigException : public AssertionException { class StaleConfigException : public AssertionException {
public: public:
StaleConfigException( const string& ns , const string& raw) StaleConfigException( const string& ns , const string& raw)
: AssertionException( (string)"ns: " + ns + " " + raw , 9996 ){ : AssertionException( (string)"ns: " + ns + " " + raw , 9996 ){
} }
virtual ~StaleConfigException() throw(){} virtual ~StaleConfigException() throw(){}
virtual void appendPrefix( stringstream& ss ) const { ss << "StaleC onfigException: "; } virtual void appendPrefix( stringstream& ss ) const { ss << "StaleC onfigException: "; }
private: private:
}; };
bool checkShardVersion( DBClientBase & conn , const string& ns , bool a uthoritative = false ); bool checkShardVersion( DBClientBase & conn , const string& ns , bool a uthoritative = false , int tryNumber = 1 );
} }
 End of changes. 3 change blocks. 
1 lines changed or deleted 79 lines changed or added


 v8_utils.h   v8_utils.h 
skipping to change at line 32 skipping to change at line 32
#include <cstring> #include <cstring>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <assert.h> #include <assert.h>
#include <iostream> #include <iostream>
namespace mongo { namespace mongo {
v8::Handle<v8::Value> Print(const v8::Arguments& args); v8::Handle<v8::Value> Print(const v8::Arguments& args);
v8::Handle<v8::Value> Version(const v8::Arguments& args); v8::Handle<v8::Value> Version(const v8::Arguments& args);
v8::Handle<v8::Value> GCV8(const v8::Arguments& args);
void ReportException(v8::TryCatch* handler); void ReportException(v8::TryCatch* handler);
#define jsassert(x,msg) assert(x) #define jsassert(x,msg) assert(x)
std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::Value> & o ); std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::Value> & o );
std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::TryCatc h> * try_catch ); std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::TryCatc h> * try_catch );
std::string toSTLString( const v8::Handle<v8::Value> & o ); std::string toSTLString( const v8::Handle<v8::Value> & o );
std::string toSTLString( const v8::TryCatch * try_catch ); std::string toSTLString( const v8::TryCatch * try_catch );
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added

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