bson.h   bson.h 
skipping to change at line 48 skipping to change at line 48
#if defined(MONGO_EXPOSE_MACROS) #if defined(MONGO_EXPOSE_MACROS)
#error this header is for client programs, not the mongo database itself. i nclude jsobj.h instead. #error this header is for client programs, not the mongo database itself. i nclude jsobj.h instead.
/* because we define simplistic assert helpers here that don't pull in a bu nch of util -- so that /* because we define simplistic assert helpers here that don't pull in a bu nch of util -- so that
BSON can be used header only. BSON can be used header only.
*/ */
#endif #endif
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include "util/builder.h"
namespace bson { namespace bson {
using std::string;
using std::stringstream;
class assertion : public std::exception { class assertion : public std::exception {
public: public:
virtual const char* what() const throw() { return "BsonAssertion"; assertion( unsigned u , const string& s )
} : id( u ) , msg( s ){
mongo::StringBuilder ss;
ss << "BsonAssertion id: " << u << " " << s;
full = ss.str();
}
virtual ~assertion() throw() {}
virtual const char* what() const throw() { return full.c_str(); }
unsigned id;
string msg;
string full;
}; };
} }
namespace mongo { namespace mongo {
#if !defined(assert) #if !defined(assert)
inline void assert(bool expr) { inline void assert(bool expr) {
if(!expr) { if(!expr) {
std::cout << "assertion failure in bson library" << std::endl; throw bson::assertion( 0 , "assertion failure in bson library"
throw bson::assertion(); );
} }
} }
#endif #endif
#if !defined(uassert) #if !defined(uassert)
inline void uasserted(unsigned msgid, std::string) { inline void uasserted(unsigned msgid, std::string s) {
throw bson::assertion(); throw bson::assertion( msgid , s );
} }
inline void uassert(unsigned msgid, std::string msg, bool expr) { inline void uassert(unsigned msgid, std::string msg, bool expr) {
if( !expr ) if( !expr )
uasserted( msgid , msg ); uasserted( msgid , msg );
} }
inline void msgasserted(int msgid, const char *msg) { inline void msgasserted(int msgid, const char *msg) {
throw bson::assertion(); throw bson::assertion( msgid , msg );
} }
inline void msgasserted(int msgid, const std::string &msg) { msgasserte d(msgid, msg.c_str()); } inline void msgasserted(int msgid, const std::string &msg) { msgasserte d(msgid, msg.c_str()); }
inline void massert(unsigned msgid, std::string msg, bool expr) { inline void massert(unsigned msgid, std::string msg, bool expr) {
if(!expr) { if(!expr) {
std::cout << "assertion failure in bson library: " << msgid << ' ' << msg << std::endl; std::cout << "assertion failure in bson library: " << msgid << ' ' << msg << std::endl;
throw bson::assertion(); throw bson::assertion( msgid , msg );
} }
} }
#endif #endif
} }
#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"
 End of changes. 7 change blocks. 
8 lines changed or deleted 25 lines changed or added


 bsonelement.h   bsonelement.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 <vector> #include <vector>
#include <string.h> #include <string.h>
#include "util/builder.h"
namespace bson { namespace bson {
typedef mongo::BSONElement be; typedef mongo::BSONElement be;
typedef mongo::BSONObj bo; typedef mongo::BSONObj bo;
typedef mongo::BSONObjBuilder bob; typedef mongo::BSONObjBuilder bob;
} }
namespace mongo { namespace mongo {
class OpTime; class OpTime;
skipping to change at line 88 skipping to change at line 89
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, bool full=false) const; string toString( bool includeFieldName = true, bool full=false) const;
operator string() const { return toString(); } void toString(StringBuilder& s, bool includeFieldName = true, bool full =false) const;
string jsonString( JsonStringFormat format, bool includeFieldNames = tr ue, int pretty = 0 ) const; string jsonString( JsonStringFormat format, bool includeFieldNames = tr ue, int pretty = 0 ) const;
operator string() const { return toString(); }
/** 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;
/** returns the tyoe of the element fixed for the main type /** returns the tyoe of the element fixed for the main type
skipping to change at line 392 skipping to change at line 394
if ( fieldNameSize_ == -1 ) if ( fieldNameSize_ == -1 )
fieldNameSize_ = (int)strlen( fieldName() ) + 1; fieldNameSize_ = (int)strlen( fieldName() ) + 1;
return fieldNameSize_; return fieldNameSize_;
} }
mutable int totalSize; /* caches the computed size */ mutable int totalSize; /* caches the computed size */
friend class BSONObjIterator; friend class BSONObjIterator;
friend class BSONObj; friend class BSONObj;
const BSONElement& chk(int t) const { const BSONElement& chk(int t) const {
if ( t != type() ){ if ( t != type() ){
stringstream ss; StringBuilder ss;
ss << "wrong type for BSONElement (" << fieldName() << ") " << type() << " != " << t; ss << "wrong type for BSONElement (" << fieldName() << ") " << type() << " != " << t;
uasserted(13111, ss.str() ); uasserted(13111, ss.str() );
} }
return *this; return *this;
} }
const BSONElement& chk(bool expr) const { const BSONElement& chk(bool expr) const {
uassert(13118, "unexpected or missing type value in BSON object", e xpr); uassert(13118, "unexpected or missing type value in BSON object", e xpr);
return *this; return *this;
} }
}; };
 End of changes. 4 change blocks. 
2 lines changed or deleted 4 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/misc.h"
#include "../util/hex.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() );
skipping to change at line 215 skipping to change at line 216
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, bool full ) const { inline string BSONObj::toString( bool isArray, bool full ) const {
if ( isEmpty() ) return "{}"; if ( isEmpty() ) return "{}";
StringBuilder s;
toString(s, isArray, full);
return s.str();
}
inline void BSONObj::toString(StringBuilder& s, bool isArray, bool ful
l ) const {
if ( isEmpty() ){
s << "{}";
return;
}
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 );
massert( 10329 , "Element too large", e.size() < ( 1 << 30 ) ) ; massert( 10329 , "Element too large", e.size() < ( 1 << 30 ) ) ;
int offset = (int) (e.rawdata() - this->objdata()); int offset = (int) (e.rawdata() - this->objdata());
massert( 10330 , "Element extends past end of object", massert( 10330 , "Element extends past end of object",
skipping to change at line 238 skipping to change at line 247
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, full ); e.toString(s, !isArray, full );
} }
s << ( isArray ? " ]" : " }" ); s << ( isArray ? " ]" : " }" );
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();
switch( t ) { switch( t ) {
case DBRef: case DBRef:
case Code: case Code:
case Symbol: case Symbol:
case mongo::String: { case mongo::String: {
int x = valuestrsize(); int x = valuestrsize();
if ( t == mongo::String && x + fieldNameSize() + 5 != size() ){
StringBuilder buf;
buf << "Invalid string size. element size: " << size() <<
" fieldNameSize: " << fieldNameSize() << " valuestrsize(): " << valuestrsi
ze();
cout << "ELIOT : " << buf.str() << endl;
msgasserted( 13292 , buf.str() );
}
if ( x > 0 && valuestr()[x-1] == 0 ) if ( x > 0 && valuestr()[x-1] == 0 )
return; return;
StringBuilder buf; StringBuilder buf;
buf << "Invalid dbref/code/string/symbol size: " << x << " str nlen:" << strnlen( valuestr() , x ); buf << "Invalid dbref/code/string/symbol size: " << x << " str nlen:" << mongo::strnlen( valuestr() , x );
msgasserted( 10321 , buf.str() ); msgasserted( 10321 , buf.str() );
break; break;
} }
case CodeWScope: { case CodeWScope: {
int totalSize = *( int * )( value() ); int totalSize = *( int * )( value() );
massert( 10322 , "Invalid CodeWScope size", totalSize >= 8 ); massert( 10322 , "Invalid CodeWScope size", totalSize >= 8 );
int strSizeWNull = *( int * )( value() + 4 ); int strSizeWNull = *( int * )( value() + 4 );
massert( 10323 , "Invalid CodeWScope string size", totalSize > = strSizeWNull + 4 + 4 ); massert( 10323 , "Invalid CodeWScope string size", totalSize > = strSizeWNull + 4 + 4 );
massert( 10324 , "Invalid CodeWScope string size", massert( 10324 , "Invalid CodeWScope string size",
strSizeWNull > 0 && strSizeWNull > 0 &&
(strSizeWNull - 1) == strnlen( codeWScopeCode(), strSi zeWNull ) ); (strSizeWNull - 1) == mongo::strnlen( codeWScopeCode() , strSizeWNull ) );
massert( 10325 , "Invalid CodeWScope size", totalSize >= strSi zeWNull + 4 + 4 + 4 ); massert( 10325 , "Invalid CodeWScope size", totalSize >= strSi zeWNull + 4 + 4 + 4 );
int objSize = *( int * )( value() + 4 + 4 + strSizeWNull ); int objSize = *( int * )( value() + 4 + 4 + strSizeWNull );
massert( 10326 , "Invalid CodeWScope object size", totalSize = = 4 + 4 + strSizeWNull + objSize ); massert( 10326 , "Invalid CodeWScope object size", totalSize = = 4 + 4 + strSizeWNull + objSize );
// Subobject validation handled elsewhere. // Subobject validation handled elsewhere.
} }
case Object: case Object:
// We expect Object size validation to be handled elsewhere. // We expect Object size validation to be handled elsewhere.
default: default:
break; break;
} }
skipping to change at line 345 skipping to change at line 346
massert( 10316 , "Insufficient bytes to calculate element size ", maxLen == -1 || remain > 3 ); massert( 10316 , "Insufficient bytes to calculate element size ", maxLen == -1 || remain > 3 );
x = objsize(); x = objsize();
break; break;
case BinData: case BinData:
massert( 10317 , "Insufficient bytes to calculate element size ", maxLen == -1 || remain > 3 ); massert( 10317 , "Insufficient bytes to calculate element size ", maxLen == -1 || remain > 3 );
x = valuestrsize() + 4 + 1/*subtype*/; x = valuestrsize() + 4 + 1/*subtype*/;
break; break;
case RegEx: case RegEx:
{ {
const char *p = value(); const char *p = value();
size_t len1 = ( maxLen == -1 ) ? strlen( p ) : strnlen( p, rema in ); size_t len1 = ( maxLen == -1 ) ? strlen( p ) : mongo::strnlen( p, remain );
//massert( 10318 , "Invalid regex string", len1 != -1 ); // ER H - 4/28/10 - don't think this does anything //massert( 10318 , "Invalid regex string", len1 != -1 ); // ER H - 4/28/10 - don't think this does anything
p = p + len1 + 1; p = p + len1 + 1;
size_t len2 = ( maxLen == -1 ) ? strlen( p ) : strnlen( p, rema in - len1 - 1 ); size_t len2 = ( maxLen == -1 ) ? strlen( p ) : mongo::strnlen( p, remain - len1 - 1 );
//massert( 10319 , "Invalid regex options string", len2 != -1 ); // ERH - 4/28/10 - don't think this does anything //massert( 10319 , "Invalid regex options string", len2 != -1 ); // ERH - 4/28/10 - don't think this does anything
x = (int) (len1 + 1 + len2 + 1); x = (int) (len1 + 1 + len2 + 1);
} }
break; break;
default: { default: {
stringstream ss; StringBuilder ss;
ss << "BSONElement: bad type " << (int) type(); ss << "BSONElement: bad type " << (int) type();
string msg = ss.str(); string msg = ss.str();
massert( 10320 , msg.c_str(),false); massert( 10320 , msg.c_str(),false);
} }
} }
totalSize = x + fieldNameSize() + 1; // BSONType totalSize = x + fieldNameSize() + 1; // BSONType
return totalSize; return totalSize;
} }
inline string BSONElement::toString( bool includeFieldName, bool full ) const { inline string BSONElement::toString( bool includeFieldName, bool full ) const {
stringstream s; StringBuilder s;
toString(s, includeFieldName, full);
return s.str();
}
inline void BSONElement::toString(StringBuilder& s, bool includeFieldNa
me, bool full ) const {
if ( includeFieldName && type() != EOO ) if ( includeFieldName && type() != EOO )
s << fieldName() << ": "; s << fieldName() << ": ";
switch ( type() ) { switch ( type() ) {
case EOO: case EOO:
return "EOO"; s << "EOO";
break;
case mongo::Date: case mongo::Date:
s << "new Date(" << date() << ')'; s << "new Date(" << date() << ')';
break; break;
case RegEx: case RegEx:
{ {
s << "/" << regex() << '/'; s << "/" << regex() << '/';
const char *p = regexFlags(); const char *p = regexFlags();
if ( p ) s << p; if ( p ) s << p;
} }
break; break;
skipping to change at line 404 skipping to change at line 410
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(false, full); embeddedObject().toString(s, false, full);
break; break;
case mongo::Array: case mongo::Array:
s << embeddedObject().toString(true, full); embeddedObject().toString(s, 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;
skipping to change at line 470 skipping to change at line 476
s << '(' << binDataType() << ", " << toHex(data, 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 has eoo() true if no match /* return has eoo() true if no match
supports "." notation to reach into embedded objects supports "." notation to reach into embedded objects
*/ */
inline BSONElement BSONObj::getFieldDotted(const char *name) const { inline BSONElement BSONObj::getFieldDotted(const char *name) const {
BSONElement e = getField( name ); BSONElement e = getField( name );
if ( e.eoo() ) { if ( e.eoo() ) {
const char *p = strchr(name, '.'); const char *p = strchr(name, '.');
if ( p ) { if ( p ) {
 End of changes. 16 change blocks. 
22 lines changed or deleted 27 lines changed or added


 bsonobj.h   bsonobj.h 
skipping to change at line 92 skipping to change at line 92
void appendSelfToBufBuilder(BufBuilder& b) const { void appendSelfToBufBuilder(BufBuilder& b) const {
assert( objsize() ); assert( objsize() );
b.appendBuf(reinterpret_cast<const void *>( objdata() ), objsiz e()); b.appendBuf(reinterpret_cast<const void *>( objdata() ), objsiz e());
} }
/** 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, bool full=false ) const; string toString( bool isArray = false, bool full=false ) const;
void toString(StringBuilder& s, bool isArray = false, bool full=fal se ) const;
/** 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 */
/** returns # of top level fields in the object /** returns # of top level fields in the object
skipping to change at line 145 skipping to change at line 146
*/ */
BSONElement operator[] (const char *field) const { BSONElement operator[] (const char *field) const {
return getField(field); return getField(field);
} }
BSONElement operator[] (const string& field) const { BSONElement operator[] (const string& field) const {
return getField(field); return getField(field);
} }
BSONElement operator[] (int field) const { BSONElement operator[] (int field) const {
stringstream ss; StringBuilder ss;
ss << field; ss << field;
string s = ss.str(); string s = ss.str();
return getField(s.c_str()); return getField(s.c_str());
} }
/** @return true if field exists */ /** @return true if field exists */
bool hasField( const char * name )const { bool hasField( const char * name )const {
return ! getField( name ).eoo(); return ! getField( name ).eoo();
} }
skipping to change at line 370 skipping to change at line 371
private: private:
const char *_objdata; const char *_objdata;
}; };
const char *_objdata; const char *_objdata;
boost::shared_ptr< Holder > _holder; boost::shared_ptr< Holder > _holder;
void init(const char *data, bool ifree) { void init(const char *data, bool ifree) {
if ( ifree ) if ( ifree )
_holder.reset( new Holder( data ) ); _holder.reset( new Holder( data ) );
_objdata = data; _objdata = data;
if ( ! isValid() ){ if ( ! isValid() ){
stringstream ss; StringBuilder ss;
ss << "Invalid BSONObj spec size: " << objsize() << " (" << int os = objsize();
hex << objsize() << dec << ")"; ss << "Invalid BSONObj spec size: " << os << " (" << toHex(
&os, 4 ) << ")";
try { try {
BSONElement e = firstElement(); BSONElement e = firstElement();
ss << " first element:" << e.toString() << " "; ss << " first element:" << e.toString() << " ";
} }
catch ( ... ){} catch ( ... ){}
string s = ss.str(); string s = ss.str();
massert( 10334 , s , 0 ); massert( 10334 , s , 0 );
} }
} }
}; };
 End of changes. 3 change blocks. 
4 lines changed or deleted 6 lines changed or added


 bsonobjbuilder.h   bsonobjbuilder.h 
skipping to change at line 130 skipping to change at line 130
} }
/** add a subobject as a member */ /** add a subobject as a member */
BSONObjBuilder& append(const StringData& fieldName, BSONObj subObj) { BSONObjBuilder& append(const StringData& fieldName, BSONObj subObj) {
_b.appendNum((char) Object); _b.appendNum((char) Object);
_b.appendStr(fieldName); _b.appendStr(fieldName);
_b.appendBuf((void *) subObj.objdata(), subObj.objsize()); _b.appendBuf((void *) subObj.objdata(), subObj.objsize());
return *this; return *this;
} }
/** add a subobject as a member */
BSONObjBuilder& appendObject(const StringData& fieldName, const cha
r * objdata , int size = 0 ){
assert( objdata );
if ( size == 0 ){
size = *((int*)objdata);
}
assert( size > 4 && size < 100000000 );
_b.appendNum((char) Object);
_b.appendStr(fieldName);
_b.appendBuf((void*)objdata, size );
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 StringData& fieldName) { BufBuilder &subobjStart(const StringData& fieldName) {
_b.appendNum((char) Object); _b.appendNum((char) Object);
_b.appendStr(fieldName); _b.appendStr(fieldName);
return _b; return _b;
} }
/** add a subobject as a member with type Array. Thus arr object s hould have "0", "1", ... /** add a subobject as a member with type Array. Thus arr object s hould have "0", "1", ...
style fields in it. style fields in it.
skipping to change at line 511 skipping to change at line 526
/** Fetch the object we have built. /** Fetch the object we have built.
BSONObjBuilder still frees the object when the build er goes out of BSONObjBuilder still frees the object when the build er goes out of
scope -- very important to keep in mind. Use obj() if you scope -- very important to keep in mind. Use obj() if you
would like the BSONObj to last longer than the build er. would like the BSONObj to last longer than the build er.
*/ */
BSONObj done() { BSONObj done() {
return BSONObj(_done()); return BSONObj(_done());
} }
// Like 'done' above, but does not construct a BSONObj to return to
the caller.
void doneFast() {
(void)_done();
}
/** Peek at what is in the builder, but leave the builder ready for more appends. /** Peek at what is in the builder, but leave the builder ready for more appends.
The returned object is only valid until the next modification o r destruction of the builder. The returned object is only valid until the next modification o r destruction of the builder.
Intended use case: append a field if not already there. Intended use case: append a field if not already there.
*/ */
BSONObj asTempObj() { BSONObj asTempObj() {
BSONObj temp(_done()); BSONObj temp(_done());
_b.setlen(_b.len()-1); //next append should overwrite the EOO _b.setlen(_b.len()-1); //next append should overwrite the EOO
_doneCalled = false; _doneCalled = false;
return temp; return temp;
} }
skipping to change at line 539 skipping to change at line 559
} }
void decouple() { void decouple() {
_b.decouple(); // post done() call version. be sure jsobj f rees... _b.decouple(); // post done() call version. be sure jsobj f rees...
} }
void appendKeys( const BSONObj& keyPattern , const BSONObj& values ); void appendKeys( const BSONObj& keyPattern , const BSONObj& values );
static string numStr( int i ) { static string numStr( int i ) {
if (i>=0 && i<100) if (i>=0 && i<100)
return numStrs[i]; return numStrs[i];
stringstream o; StringBuilder o;
o << i; o << i;
return o.str(); return o.str();
} }
/** Stream oriented way to add field names and values. */ /** Stream oriented way to add field names and values. */
BSONObjBuilderValueStream &operator<<(const char * name ) { BSONObjBuilderValueStream &operator<<(const char * name ) {
_s.endField( name ); _s.endField( name );
return _s; return _s;
} }
skipping to change at line 641 skipping to change at line 661
} }
void appendNull() { void appendNull() {
_b.appendNull(num().c_str()); _b.appendNull(num().c_str());
} }
BSONArray arr(){ return BSONArray(_b.obj()); } BSONArray arr(){ return BSONArray(_b.obj()); }
BSONObj done() { return _b.done(); } BSONObj done() { return _b.done(); }
void doneFast() { _b.doneFast(); }
template <typename T> template <typename T>
BSONArrayBuilder& append(const StringData& name, const T& x){ BSONArrayBuilder& append(const StringData& name, const T& x){
fill( name ); fill( name );
append( x ); append( x );
return *this; return *this;
} }
BufBuilder &subobjStart( const char *name = "0" ) { BufBuilder &subobjStart( const char *name = "0" ) {
fill( name ); fill( name );
return _b.subobjStart( num().c_str() ); return _b.subobjStart( num().c_str() );
skipping to change at line 672 skipping to change at line 694
void appendAs( const BSONElement &e, const char *name ) { void appendAs( const BSONElement &e, const char *name ) {
fill( name ); fill( name );
append( e ); append( e );
} }
private: private:
void fill( const StringData& name ) { void fill( const StringData& name ) {
char *r; char *r;
int n = strtol( name.data(), &r, 10 ); int n = strtol( name.data(), &r, 10 );
uassert( 13048, (string)"can't append to array using string fie if ( *r )
ld name [" + name.data() + "]" , !*r ); uasserted( 13048, (string)"can't append to array using stri
ng field name [" + name.data() + "]" );
while( _i < n ) while( _i < n )
append( nullElt() ); append( nullElt() );
} }
static BSONElement nullElt() { static BSONElement nullElt() {
static BSONObj n = nullObj(); static BSONObj n = nullObj();
return n.firstElement(); return n.firstElement();
} }
static BSONObj nullObj() { static BSONObj nullObj() {
 End of changes. 5 change blocks. 
3 lines changed or deleted 28 lines changed or added


 btree.h   btree.h 
skipping to change at line 289 skipping to change at line 289
return !bucket.isNull(); return !bucket.isNull();
} }
bool eof() { bool eof() {
return !ok(); return !ok();
} }
virtual bool advance(); virtual bool advance();
virtual void noteLocation(); // updates keyAtKeyOfs... virtual void noteLocation(); // updates keyAtKeyOfs...
virtual void checkLocation(); virtual void checkLocation();
virtual bool supportGetMore() { return true; } virtual bool supportGetMore() { return true; }
virtual bool supportYields() { return true; }
/* 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.
@return true if the loc has not been seen @return true if the loc has not been seen
*/ */
virtual bool getsetdup(DiskLoc loc) { virtual bool getsetdup(DiskLoc loc) {
if( multikey ) { if( multikey ) {
pair<set<DiskLoc>::iterator, bool> p = dups.insert(loc); pair<set<DiskLoc>::iterator, bool> p = dups.insert(loc);
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 builder.h   builder.h 
skipping to change at line 106 skipping to change at line 106
*((long long*)grow(sizeof(long long))) = j; *((long long*)grow(sizeof(long long))) = j;
} }
void appendNum(unsigned long long j) { void appendNum(unsigned long long j) {
*((unsigned long long*)grow(sizeof(unsigned long long))) = j; *((unsigned long long*)grow(sizeof(unsigned long long))) = j;
} }
void appendBuf(const void *src, size_t len) { void appendBuf(const void *src, size_t len) {
memcpy(grow((int) len), src, len); memcpy(grow((int) len), src, len);
} }
void appendStr(const StringData &str) { void appendStr(const StringData &str , bool includeEOO = true ) {
const int len = str.size() + 1; const int len = str.size() + ( includeEOO ? 1 : 0 );
memcpy(grow(len), str.data(), len); memcpy(grow(len), str.data(), len);
} }
int len() const { int len() const {
return l; return l;
} }
void setlen( int newLen ){ void setlen( int newLen ){
l = newLen; l = newLen;
} }
skipping to change at line 188 skipping to change at line 188
} }
StringBuilder& operator<<( short x ){ StringBuilder& operator<<( short x ){
SBNUM( x , 8 , "%hd" ); SBNUM( x , 8 , "%hd" );
} }
StringBuilder& operator<<( char c ){ StringBuilder& operator<<( char c ){
_buf.grow( 1 )[0] = c; _buf.grow( 1 )[0] = c;
return *this; return *this;
} }
#undef SBNUM #undef SBNUM
void append( const char * str ){ void write( const char* buf, int len){
int x = (int) strlen( str ); memcpy( _buf.grow( len ) , buf , len );
memcpy( _buf.grow( x ) , str , x );
} }
StringBuilder& operator<<( const char * str ){
append( str ); void append( const StringData& str ){
return *this; memcpy( _buf.grow( str.size() ) , str.data() , str.size() );
} }
StringBuilder& operator<<( const std::string& s ){ StringBuilder& operator<<( const StringData& str ){
append( s.c_str() ); append( str );
return *this; return *this;
} }
// access // access
void reset( int maxSize = 0 ){ void reset( int maxSize = 0 ){
_buf.reset( maxSize ); _buf.reset( maxSize );
} }
std::string str(){ std::string str(){
 End of changes. 4 change blocks. 
10 lines changed or deleted 9 lines changed or added


 clientcursor.h   clientcursor.h 
skipping to change at line 201 skipping to change at line 201
static int yieldSuggest(); static int yieldSuggest();
static void staticYield( int micros ); static void staticYield( int micros );
struct YieldData { CursorId _id; bool _doingDeletes; }; struct YieldData { CursorId _id; bool _doingDeletes; };
void prepareToYield( YieldData &data ); void prepareToYield( YieldData &data );
static bool recoverFromYield( const YieldData &data ); static bool recoverFromYield( const YieldData &data );
struct YieldLock : boost::noncopyable { struct YieldLock : boost::noncopyable {
explicit YieldLock( ptr<ClientCursor> cc ) explicit YieldLock( ptr<ClientCursor> cc )
: _cc( cc ) , _id( cc->cursorid ) , _doingDeletes( cc->_doi : _cc( cc ) , _id( cc->cursorid ) , _doingDeletes( cc->_doi
ngDeletes ) { ngDeletes ), _canYield(cc->c->supportYields()) {
cc->updateLocation(); if ( _canYield ){
_unlock.reset(new dbtempreleasecond()); cc->updateLocation();
_unlock.reset(new dbtempreleasecond());
}
} }
~YieldLock(){ ~YieldLock(){
if ( _unlock ){ if ( _unlock ){
log( LL_WARNING ) << "ClientCursor::YieldLock not close d properly" << endl; log( LL_WARNING ) << "ClientCursor::YieldLock not close d properly" << endl;
relock(); relock();
} }
} }
bool stillOk(){ bool stillOk(){
if ( ! _canYield )
return true;
relock(); relock();
if ( ClientCursor::find( _id , false ) == 0 ){ if ( ClientCursor::find( _id , false ) == 0 ){
// i was deleted // i was deleted
return false; return false;
} }
_cc->_doingDeletes = _doingDeletes; _cc->_doingDeletes = _doingDeletes;
return true; return true;
} }
void relock(){ void relock(){
_unlock.reset(); if ( _canYield )
_unlock.reset();
} }
private: private:
ClientCursor * _cc; ClientCursor * _cc;
CursorId _id; CursorId _id;
bool _doingDeletes; bool _doingDeletes;
bool _canYield;
scoped_ptr<dbtempreleasecond> _unlock; scoped_ptr<dbtempreleasecond> _unlock;
}; };
// --- some pass through helpers for Cursor --- // --- some pass through helpers for Cursor ---
BSONObj indexKeyPattern() { BSONObj indexKeyPattern() {
return c->indexKeyPattern(); return c->indexKeyPattern();
} }
 End of changes. 4 change blocks. 
5 lines changed or deleted 12 lines changed or added


 cmdline.h   cmdline.h 
skipping to change at line 28 skipping to change at line 28
#include "../pch.h" #include "../pch.h"
namespace mongo { namespace mongo {
/* command line options /* command line options
*/ */
/* concurrency: OK/READ */ /* concurrency: OK/READ */
struct CmdLine { struct CmdLine {
int port; // --port int port; // --port
string bind_ip; // --bind_ip
bool rest; // --rest bool rest; // --rest
string replSet; // --replSet <seedlist> string replSet; // --replSet <seedlist>
string source; // --source string source; // --source
string only; // --only string only; // --only
bool quiet; // --quiet bool quiet; // --quiet
bool notablescan; // --notablescan bool notablescan; // --notablescan
bool prealloc; // --noprealloc bool prealloc; // --noprealloc
bool smallfiles; // --smallfiles bool smallfiles; // --smallfiles
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 commands.h   commands.h 
skipping to change at line 124 skipping to change at line 124
static void logIfSlow( const Timer& cmdTimer, const string& msg); 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;
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; }
/** @return if command was found and executed */
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);
} // namespace mongo } // namespace mongo
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 core.h   core.h 
skipping to change at line 66 skipping to change at line 66
}; };
extern GeoBitSets geoBitSets; extern GeoBitSets geoBitSets;
class GeoHash { class GeoHash {
public: public:
GeoHash() GeoHash()
: _hash(0),_bits(0){ : _hash(0),_bits(0){
} }
GeoHash( const char * hash ){ explicit GeoHash( const char * hash ){
init( hash ); init( hash );
} }
GeoHash( const string& hash ){ explicit GeoHash( const string& hash ){
init( hash ); init( hash );
} }
GeoHash( const BSONElement& e , unsigned bits=32 ){ explicit GeoHash( const BSONElement& e , unsigned bits=32 ){
_bits = bits; _bits = bits;
if ( e.type() == BinData ){ if ( e.type() == BinData ){
int len = 0; int len = 0;
_copy( (char*)&_hash , e.binData( len ) ); _copy( (char*)&_hash , e.binData( len ) );
assert( len == 8 ); assert( len == 8 );
_bits = bits; _bits = bits;
} }
else { else {
cout << "GeoHash cons e : " << e << endl; cout << "GeoHash cons e : " << e << endl;
uassert(13047,"wrong type for geo index. if you're using a pre-release version, need to rebuild index",0); uassert(13047,"wrong type for geo index. if you're using a pre-release version, need to rebuild index",0);
skipping to change at line 307 skipping to change at line 307
void append( BSONObjBuilder& b , const char * name ) const { void append( BSONObjBuilder& b , const char * name ) const {
char buf[8]; char buf[8];
_copy( buf , (char*)&_hash ); _copy( buf , (char*)&_hash );
b.appendBinData( name , 8 , bdtCustom , buf ); b.appendBinData( name , 8 , bdtCustom , buf );
} }
long long getHash() const { long long getHash() const {
return _hash; return _hash;
} }
unsigned getBits() const {
return _bits;
}
GeoHash commonPrefix( const GeoHash& other ) const { GeoHash commonPrefix( const GeoHash& other ) const {
unsigned i=0; unsigned i=0;
for ( ; i<_bits && i<other._bits; i++ ){ for ( ; i<_bits && i<other._bits; i++ ){
if ( getBitX( i ) == other.getBitX( i ) && if ( getBitX( i ) == other.getBitX( i ) &&
getBitY( i ) == other.getBitY( i ) ) getBitY( i ) == other.getBitY( i ) )
continue; continue;
break; break;
} }
return GeoHash(_hash,i); return GeoHash(_hash,i);
} }
skipping to change at line 349 skipping to change at line 354
virtual GeoHash hash( double x , double y ) const = 0; virtual GeoHash hash( double x , double y ) const = 0;
}; };
class Point { class Point {
public: public:
Point( const GeoConvert * g , const GeoHash& hash ){ Point( const GeoConvert * g , const GeoHash& hash ){
g->unhash( hash , _x , _y ); g->unhash( hash , _x , _y );
} }
Point( const BSONElement& e ){ explicit Point( const BSONElement& e ){
BSONObjIterator i(e.Obj()); BSONObjIterator i(e.Obj());
_x = i.next().number(); _x = i.next().number();
_y = i.next().number(); _y = i.next().number();
} }
Point( const BSONObj& o ){ explicit Point( const BSONObj& o ){
BSONObjIterator i(o); BSONObjIterator i(o);
_x = i.next().number(); _x = i.next().number();
_y = i.next().number(); _y = i.next().number();
} }
Point( double x , double y ) Point( double x , double y )
: _x( x ) , _y( y ){ : _x( x ) , _y( y ){
} }
Point() : _x(0),_y(0){ Point() : _x(0),_y(0){
} }
GeoHash hash( const GeoConvert * g ){ GeoHash hash( const GeoConvert * g ){
return g->hash( _x , _y ); return g->hash( _x , _y );
} }
double distance( Point& p ) const { double distance( const Point& p ) const {
double a = _x - p._x; double a = _x - p._x;
double b = _y - p._y; double b = _y - p._y;
return sqrt( ( a * a ) + ( b * b ) ); return sqrt( ( a * a ) + ( b * b ) );
} }
string toString() const { string toString() const {
StringBuilder buf(32); StringBuilder buf(32);
buf << "(" << _x << "," << _y << ")"; buf << "(" << _x << "," << _y << ")";
return buf.str(); return buf.str();
 End of changes. 7 change blocks. 
6 lines changed or deleted 10 lines changed or added


 curop.h   curop.h 
skipping to change at line 84 skipping to change at line 84
_message = ""; _message = "";
_progressMeter.finished(); _progressMeter.finished();
} }
void setNS(const char *ns) { void setNS(const char *ns) {
strncpy(_ns, ns, Namespace::MaxNsLen); strncpy(_ns, ns, Namespace::MaxNsLen);
} }
public: public:
bool haveQuery() const { return *((int *) _queryBuf) != 0; } int querySize() const { return *((int *) _queryBuf); }
bool haveQuery() const { return querySize() != 0; }
BSONObj query() { BSONObj query() {
if( *((int *) _queryBuf) == 1 ) { if( querySize() == 1 ) {
return _tooBig; return _tooBig;
} }
BSONObj o(_queryBuf); BSONObj o(_queryBuf);
return o; return o;
} }
void ensureStarted(){ void ensureStarted(){
if ( _start == 0 ) if ( _start == 0 )
_start = _checkpoint = curTimeMicros64(); _start = _checkpoint = curTimeMicros64();
} }
skipping to change at line 242 skipping to change at line 243
BSONObj info() { BSONObj info() {
if( ! cc().getAuthenticationInfo()->isAuthorized("admin") ) { if( ! cc().getAuthenticationInfo()->isAuthorized("admin") ) {
BSONObjBuilder b; BSONObjBuilder b;
b.append("err", "unauthorized"); b.append("err", "unauthorized");
return b.obj(); return b.obj();
} }
return infoNoauth(); return infoNoauth();
} }
BSONObj infoNoauth(); BSONObj infoNoauth( int attempt = 0 );
string getRemoteString( bool includePort = true ){ string getRemoteString( bool includePort = true ){
return _remote.toString(includePort); return _remote.toString(includePort);
} }
ProgressMeter& setMessage( const char * msg , long long progressMet erTotal = 0 , int secondsBetween = 3 ){ ProgressMeter& setMessage( const char * msg , long long progressMet erTotal = 0 , int secondsBetween = 3 ){
if ( progressMeterTotal ){ if ( progressMeterTotal ){
if ( _progressMeter.isActive() ){ if ( _progressMeter.isActive() ){
cout << "about to assert, old _message: " << _message < < " new message:" << msg << endl; cout << "about to assert, old _message: " << _message < < " new message:" << msg << endl;
 End of changes. 3 change blocks. 
3 lines changed or deleted 4 lines changed or added


 cursor.h   cursor.h 
skipping to change at line 81 skipping to change at line 81
/* called after every query block is iterated -- i.e. between getMo re() blocks /* called after every query block is iterated -- i.e. between getMo re() blocks
so you can note where we are, if necessary. so you can note where we are, if necessary.
*/ */
virtual void noteLocation() { } virtual void noteLocation() { }
/* called before query getmore block is iterated */ /* called before query getmore block is iterated */
virtual void checkLocation() { } virtual void checkLocation() { }
virtual bool supportGetMore() = 0; virtual bool supportGetMore() = 0;
virtual bool supportYields() = 0;
virtual string toString() { return "abstract?"; } virtual string toString() { return "abstract?"; }
/* used for multikey index traversal to avoid sending back dups. se e Matcher::matches(). /* used for multikey index traversal to avoid sending back dups. se e Matcher::matches().
if a multikey index traversal: if a multikey index traversal:
if loc has already been sent, returns true. if loc has already been sent, returns true.
otherwise, marks loc as sent. otherwise, marks loc as sent.
@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
skipping to change at line 174 skipping to change at line 175
virtual void setTailable() { virtual void setTailable() {
if ( !curr.isNull() || !last.isNull() ) if ( !curr.isNull() || !last.isNull() )
tailable_ = true; tailable_ = true;
} }
virtual bool tailable() { virtual bool tailable() {
return tailable_; return tailable_;
} }
virtual bool getsetdup(DiskLoc loc) { return false; } virtual bool getsetdup(DiskLoc loc) { return false; }
virtual bool supportGetMore() { return true; } virtual bool supportGetMore() { return true; }
virtual bool supportYields() { return true; }
virtual CoveredIndexMatcher *matcher() const { return _matcher.get( ); } virtual CoveredIndexMatcher *matcher() const { return _matcher.get( ); }
virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) { virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) {
_matcher = matcher; _matcher = matcher;
} }
}; };
/* used for order { $natural: -1 } */ /* used for order { $natural: -1 } */
 End of changes. 2 change blocks. 
0 lines changed or deleted 2 lines changed or added


 d_logic.h   d_logic.h 
skipping to change at line 110 skipping to change at line 110
ShardedConnectionInfo(); ShardedConnectionInfo();
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 );
static void reset();
bool inForceMode() const { bool inForceMode() const {
return _forceMode; return _forceMode;
} }
void enterForceMode(){ _forceMode = true; } void enterForceMode(){ _forceMode = true; }
void leaveForceMode(){ _forceMode = false; } void leaveForceMode(){ _forceMode = false; }
private: private:
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 database.h   database.h 
skipping to change at line 191 skipping to change at line 191
static bool validDBName( const string& ns ); static bool validDBName( const string& ns );
long long fileSize(){ long long fileSize(){
long long size=0; long long size=0;
for (int n=0; exists(n); n++) for (int n=0; exists(n); n++)
size += boost::filesystem::file_size( fileName(n) ); size += boost::filesystem::file_size( fileName(n) );
return size; return size;
} }
void flushFiles( bool sync );
vector<MongoDataFile*> files; vector<MongoDataFile*> files;
string name; // "alleyinsider" string name; // "alleyinsider"
string path; string path;
NamespaceIndex namespaceIndex; NamespaceIndex namespaceIndex;
int profile; // 0=off. int profile; // 0=off.
string profileName; // "alleyinsider.system.profile" string profileName; // "alleyinsider.system.profile"
int magic; // used for making sure the object is still loaded in me mory int magic; // used for making sure the object is still loaded in me mory
}; };
} // namespace mongo } // namespace mongo
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 dbclient.h   dbclient.h 
skipping to change at line 101 skipping to change at line 101
RemoveOption_JustOne = 1 << 0, RemoveOption_JustOne = 1 << 0,
/** flag from mongo saying this update went everywhere */ /** flag from mongo saying this update went everywhere */
RemoveOption_Broadcast = 1 << 1 RemoveOption_Broadcast = 1 << 1
}; };
class DBClientBase; class DBClientBase;
class ConnectionString { class ConnectionString {
public: public:
enum ConnectionType { MASTER , SET , SYNC }; enum ConnectionType { INVALID , MASTER , PAIR , SET , SYNC };
ConnectionString( const HostAndPort& server ){ ConnectionString( const HostAndPort& server ){
_type = MASTER; _type = MASTER;
_servers.push_back( server ); _servers.push_back( server );
_finishInit(); _finishInit();
} }
ConnectionString( ConnectionType type , const vector<HostAndPort>& servers ) ConnectionString( ConnectionType type , const vector<HostAndPort>& servers )
: _type( type ) , _servers( servers ){ : _type( type ) , _servers( servers ){
_finishInit(); _finishInit();
} }
ConnectionString( ConnectionType type , const string& s ){ ConnectionString( ConnectionType type , const string& s , const str ing& setName = "" ){
_type = type; _type = type;
_setName = setName;
_fillServers( s ); _fillServers( s );
switch ( _type ){ switch ( _type ){
case MASTER: case MASTER:
assert( _servers.size() == 1 ); assert( _servers.size() == 1 );
break; break;
case SET:
assert( _setName.size() );
assert( _servers.size() > 1 );
break;
case PAIR:
assert( _servers.size() == 2 );
break;
default: default:
assert( _servers.size() > 0 ); assert( _servers.size() > 0 );
} }
_finishInit(); _finishInit();
} }
ConnectionString( const string& s , ConnectionType favoredMultipleT ype ){ ConnectionString( const string& s , ConnectionType favoredMultipleT ype ){
_fillServers( s ); _fillServers( s );
if ( _servers.size() == 1 ){ if ( _servers.size() == 1 ){
_type = MASTER; _type = MASTER;
} }
else { else {
_type = favoredMultipleType; _type = favoredMultipleType;
assert( _type != MASTER ); assert( _type != MASTER );
} }
_finishInit(); _finishInit();
} }
bool isValid() const { return _type != INVALID; }
string toString() const { string toString() const {
return _string; return _string;
} }
operator string() const {
return toString();
}
DBClientBase* connect( string& errmsg ) const; DBClientBase* connect( string& errmsg ) const;
static ConnectionString parse( const string& url , string& errmsg )
;
private: private:
ConnectionString(){
_type = INVALID;
}
void _fillServers( string s ){ void _fillServers( string s ){
string::size_type idx; string::size_type idx;
while ( ( idx = s.find( ',' ) ) != string::npos ){ while ( ( idx = s.find( ',' ) ) != string::npos ){
_servers.push_back( s.substr( 0 , idx ) ); _servers.push_back( s.substr( 0 , idx ) );
s = s.substr( idx + 1 ); s = s.substr( idx + 1 );
} }
_servers.push_back( s ); _servers.push_back( s );
} }
void _finishInit(){ void _finishInit(){
skipping to change at line 175 skipping to change at line 187
if ( i > 0 ) if ( i > 0 )
ss << ","; ss << ",";
ss << _servers[i].toString(); ss << _servers[i].toString();
} }
_string = ss.str(); _string = ss.str();
} }
ConnectionType _type; ConnectionType _type;
vector<HostAndPort> _servers; vector<HostAndPort> _servers;
string _string; string _string;
string _setName;
}; };
/** /**
* controls how much a clients cares about writes * controls how much a clients cares about writes
* default is NORMAL * default is NORMAL
*/ */
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
skipping to change at line 744 skipping to change at line 757
for ( unsigned i=0; i<s.size(); i++ ) for ( unsigned i=0; i<s.size(); i++ )
if ( s[i] == ',' ) if ( s[i] == ',' )
n++; n++;
return n; return n;
} }
virtual bool callRead( Message& toSend , Message& response ) = 0; virtual bool callRead( Message& toSend , Message& response ) = 0;
// virtual bool callWrite( Message& toSend , Message& response ) = 0; // TODO: add this if needed // virtual bool callWrite( Message& toSend , Message& response ) = 0; // TODO: add this if needed
virtual void say( Message& toSend ) = 0; virtual void say( Message& toSend ) = 0;
virtual ConnectionString::ConnectionType type() const = 0;
}; // DBClientBase }; // DBClientBase
class DBClientPaired; class DBClientReplicaSet;
class ConnectException : public UserException { class ConnectException : public UserException {
public: public:
ConnectException(string msg) : UserException(9000,msg) { } ConnectException(string msg) : UserException(9000,msg) { }
}; };
/** /**
A basic connection to the database. A basic connection to the database.
This is the main entry point for talking to a simple Mongo setup This is the main entry point for talking to a simple Mongo setup
*/ */
class DBClientConnection : public DBClientBase { class DBClientConnection : public DBClientBase {
DBClientPaired *clientPaired; DBClientReplicaSet *clientSet;
boost::scoped_ptr<MessagingPort> p; boost::scoped_ptr<MessagingPort> p;
boost::scoped_ptr<SockAddr> server; boost::scoped_ptr<SockAddr> server;
bool failed; // true if some sort of fatal error has ever happened bool failed; // true if some sort of fatal error has ever happened
bool autoReconnect; bool autoReconnect;
time_t lastReconnectTry; time_t lastReconnectTry;
string serverAddress; // remember for reconnects HostAndPort _server; // remember for reconnects
string _serverString;
int _port;
void _checkConnection(); void _checkConnection();
void checkConnection() { if( failed ) _checkConnection(); } void checkConnection() { if( failed ) _checkConnection(); }
map< string, pair<string,string> > authCache; map< string, pair<string,string> > authCache;
int _timeout; int _timeout;
bool _connect( string& errmsg );
public: public:
/** /**
@param _autoReconnect if true, automatically reconnect on a conn ection failure @param _autoReconnect if true, automatically reconnect on a conn ection failure
@param cp used by DBClientPaired. You do not need to specify th is parameter @param cp used by DBClientReplicaSet. You do not need to specif y this parameter
@param timeout tcp timeout in seconds - this is for read/write, not connect. @param timeout tcp timeout in seconds - this is for read/write, not connect.
Connect timeout is fixed, but short, at 5 seconds. Connect timeout is fixed, but short, at 5 seconds.
*/ */
DBClientConnection(bool _autoReconnect=false, DBClientPaired* cp=0, DBClientConnection(bool _autoReconnect=false, DBClientReplicaSet* c
int timeout=0) : p=0, int timeout=0) :
clientPaired(cp), failed(false), autoReconnect(_autoReconne clientSet(cp), failed(false), autoReconnect(_autoReconnect)
ct), lastReconnectTry(0), _timeout(timeout) { } , lastReconnectTry(0), _timeout(timeout) { }
/** Connect to a Mongo database server. /** Connect to a Mongo database server.
If autoReconnect is true, you can try to use the DBClientConnect ion even when If autoReconnect is true, you can try to use the DBClientConnect ion even when
false was returned -- it will try to connect again. false was returned -- it will try to connect again.
@param serverHostname host to connect to. can include port numb er ( 127.0.0.1 , 127.0.0.1:5555 ) @param serverHostname host to connect to. can include port numb er ( 127.0.0.1 , 127.0.0.1:5555 )
If you use IPv6 you must add a port number ( ::1:27017 ) If you use IPv6 you must add a port number ( ::1:27017 )
@param errmsg any relevant error message will appended to the st ring @param errmsg any relevant error message will appended to the st ring
@deprecated please use HostAndPort
@return false if fails to connect. @return false if fails to connect.
*/ */
virtual bool connect(const string &serverHostname, string& errmsg); virtual bool connect(const char * hostname, string& errmsg){
// TODO: remove this method
HostAndPort t( hostname );
return connect( t , errmsg );
}
/** Connect to a Mongo database server.
If autoReconnect is true, you can try to use the DBClientConnect
ion even when
false was returned -- it will try to connect again.
@param server server to connect to.
@param errmsg any relevant error message will appended to the st
ring
@return false if fails to connect.
*/
virtual bool connect(const HostAndPort& server, string& errmsg);
/** Connect to a Mongo database server. Exception throwing version . /** Connect to a Mongo database server. Exception throwing version .
Throws a UserException if cannot connect. Throws a UserException if cannot connect.
If autoReconnect is true, you can try to use the DBClientConnect ion even when If autoReconnect is true, you can try to use the DBClientConnect ion even when
false was returned -- it will try to connect again. false was returned -- it will try to connect again.
@param serverHostname host to connect to. can include port numb er ( 127.0.0.1 , 127.0.0.1:5555 ) @param serverHostname host to connect to. can include port numb er ( 127.0.0.1 , 127.0.0.1:5555 )
*/ */
void connect(string serverHostname) { void connect(const string& serverHostname) {
string errmsg; string errmsg;
if( !connect(serverHostname.c_str(), errmsg) ) if( !connect(HostAndPort(serverHostname), errmsg) )
throw ConnectException(string("can't connect ") + errmsg); throw ConnectException(string("can't connect ") + errmsg);
} }
virtual bool auth(const string &dbname, const string &username, con st string &pwd, string& errmsg, bool digestPassword = true); virtual bool auth(const string &dbname, const string &username, con st string &pwd, string& errmsg, bool digestPassword = true);
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 );
} }
skipping to change at line 833 skipping to change at line 867
bool isFailed() const { bool isFailed() const {
return failed; return failed;
} }
MessagingPort& port() { MessagingPort& port() {
return *p; return *p;
} }
string toStringLong() const { string toStringLong() const {
stringstream ss; stringstream ss;
ss << serverAddress; ss << _serverString;
if ( failed ) ss << " failed"; if ( failed ) ss << " failed";
return ss.str(); return ss.str();
} }
/** Returns the address of the server */ /** Returns the address of the server */
string toString() { string toString() {
return serverAddress; return _serverString;
} }
string getServerAddress() const { string getServerAddress() const {
return serverAddress; return _serverString;
} }
virtual void killCursor( long long cursorID ); virtual void killCursor( long long cursorID );
virtual bool callRead( Message& toSend , Message& response ){ virtual bool callRead( Message& toSend , Message& response ){
return call( toSend , response ); return call( toSend , response );
} }
virtual void say( Message &toSend ); virtual void say( Message &toSend );
virtual bool call( Message &toSend, Message &response, bool assertO k = true );
virtual ConnectionString::ConnectionType type() const { return Conn ectionString::MASTER; }
protected: protected:
friend class SyncClusterConnection; friend class SyncClusterConnection;
virtual void recv( Message& m ); virtual void recv( Message& m );
virtual bool call( Message &toSend, Message &response, bool assertO k = true );
virtual void sayPiggyBack( Message &toSend ); virtual void sayPiggyBack( Message &toSend );
virtual void checkResponse( const char *data, int nReturned ); virtual void checkResponse( const char *data, int nReturned );
}; };
/** Use this class to connect to a replica pair of servers. The class /** Use this class to connect to a replica set of servers. The class w
will manage ill manage
checking for which server in a replica pair is master, and do failov checking for which server in a replica set is master, and do failove
er automatically. r automatically.
This can also be used to connect to replica pairs since pairs are a
subset of sets
On a failover situation, expect at least one operation to return an error (throw On a failover situation, expect at least one operation to return an error (throw
an exception) before the failover is complete. Operations are no t retried. an exception) before the failover is complete. Operations are no t retried.
*/ */
class DBClientPaired : public DBClientBase { class DBClientReplicaSet : public DBClientBase {
DBClientConnection left,right; string _name;
enum State { DBClientConnection * _currentMaster;
NotSetL=0, vector<HostAndPort> _servers;
NotSetR=1, vector<DBClientConnection*> _conns;
Left, Right
} master;
void _checkMaster(); void _checkMaster();
DBClientConnection& checkMaster(); DBClientConnection * checkMaster();
public: public:
/** Call connect() after constructing. autoReconnect is always on f /** Call connect() after constructing. autoReconnect is always on f
or DBClientPaired connections. */ or DBClientReplicaSet connections. */
DBClientPaired(); DBClientReplicaSet( const string& name , const vector<HostAndPort>&
servers );
virtual ~DBClientReplicaSet();
/** Returns false is neither member of the pair were reachable, or neither is /** Returns false if nomember of the set were reachable, or neither is
master, although, master, although,
when false returned, you can still try to use this connection ob ject, it will when false returned, you can still try to use this connection ob ject, it will
try reconnects. try reconnects.
*/ */
bool connect(const string &serverHostname1, const string &serverHos bool connect();
tname2);
/** Connect to a server pair using a host pair string of the form
hostname[:port],hostname[:port]
*/
bool connect(string hostpairstring);
/** Authorize. Authorizes both sides of the pair as needed. /** Authorize. Authorizes all nodes as needed
*/ */
bool auth(const string &dbname, const string &username, const strin g &pwd, string& errmsg); virtual bool auth(const string &dbname, const string &username, con st string &pwd, string& errmsg, bool digestPassword = true );
/** throws userassertion "no master found" */ /** throws userassertion "no master found" */
virtual virtual
auto_ptr<DBClientCursor> query(const string &ns, Query query, int n ToReturn = 0, int nToSkip = 0, auto_ptr<DBClientCursor> query(const string &ns, Query query, int n ToReturn = 0, int nToSkip = 0,
const BSONObj *fieldsToReturn = 0, i nt queryOptions = 0 , int batchSize = 0 ); const BSONObj *fieldsToReturn = 0, i nt queryOptions = 0 , int batchSize = 0 );
/** throws userassertion "no master found" */ /** throws userassertion "no master found" */
virtual virtual
BSONObj findOne(const string &ns, const Query& query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0); BSONObj findOne(const string &ns, const Query& query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0);
/** insert */ /** insert */
virtual void insert( const string &ns , BSONObj obj ) { virtual void insert( const string &ns , BSONObj obj ) {
checkMaster().insert(ns, obj); checkMaster()->insert(ns, obj);
} }
/** insert multiple objects. Note that single object insert is asy nchronous, so this version /** insert multiple objects. Note that single object insert is asy nchronous, so this version
is only nominally faster and not worth a special effort to try to use. */ is only nominally faster and not worth a special effort to try to use. */
virtual void insert( const string &ns, const vector< BSONObj >& v ) { virtual void insert( const string &ns, const vector< BSONObj >& v ) {
checkMaster().insert(ns, v); checkMaster()->insert(ns, v);
} }
/** remove */ /** remove */
virtual void remove( const string &ns , Query obj , bool justOne = 0 ) { virtual void remove( const string &ns , Query obj , bool justOne = 0 ) {
checkMaster().remove(ns, obj, justOne); checkMaster()->remove(ns, obj, justOne);
} }
/** update */ /** update */
virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = 0 , bool multi = 0 ) { virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = 0 , bool multi = 0 ) {
return checkMaster().update(ns, query, obj, upsert,multi); return checkMaster()->update(ns, query, obj, upsert,multi);
} }
virtual void killCursor( long long cursorID ){ virtual void killCursor( long long cursorID ){
checkMaster().killCursor( cursorID ); checkMaster()->killCursor( cursorID );
} }
string toString(); string toString();
/* this is the callback from our underlying connections to notify u s that we got a "not master" error. /* this is the callback from our underlying connections to notify u s that we got a "not master" error.
*/ */
void isntMaster() { void isntMaster() {
master = ( ( master == Left ) ? NotSetR : NotSetL ); _currentMaster = 0;
} }
string getServerAddress() const { string getServerAddress() const;
return left.getServerAddress() + "," + right.getServerAddress()
;
}
DBClientConnection& masterConn(); DBClientConnection& masterConn();
DBClientConnection& slaveConn(); DBClientConnection& slaveConn();
/* TODO - not yet implemented. mongos may need these. */ virtual bool call( Message &toSend, Message &response, bool assertO
virtual bool call( Message &toSend, Message &response, bool assertO k=true ) { return checkMaster()->call( toSend , response , assertOk ); }
k=true ) { assert(false); return false; } virtual void say( Message &toSend ) { checkMaster()->say( toSend );
virtual void say( Message &toSend ) { assert(false); } }
virtual bool callRead( Message& toSend , Message& response ){ retur
n checkMaster()->callRead( toSend , response ); }
virtual ConnectionString::ConnectionType type() const { return Conn
ectionString::SET; }
protected:
virtual void sayPiggyBack( Message &toSend ) { assert(false); } virtual void sayPiggyBack( Message &toSend ) { assert(false); }
virtual void checkResponse( const char *data, int nReturned ) { ass ert(false); } virtual void checkResponse( const char *data, int nReturned ) { ass ert(false); }
virtual bool callRead( Message& toSend , Message& response ){
return call( toSend , response );
}
bool isFailed() const { bool isFailed() const {
// TODO: this really should check isFailed on current master as return _currentMaster == 0 || _currentMaster->isFailed();
well
return master < Left;
} }
}; };
/** pings server to check if it's up /** pings server to check if it's up
*/ */
bool serverAlive( const string &uri ); bool serverAlive( const string &uri );
DBClientBase * createDirectClient(); DBClientBase * createDirectClient();
} // namespace mongo } // namespace mongo
 End of changes. 44 change blocks. 
67 lines changed or deleted 100 lines changed or added


 dbclientcursor.h   dbclientcursor.h 
skipping to change at line 120 skipping to change at line 120
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)),
nToSkip(_nToSkip), nToSkip(_nToSkip),
fieldsToReturn(_fieldsToReturn), fieldsToReturn(_fieldsToReturn),
opts(queryOptions), opts(queryOptions),
batchSize(bs), batchSize(bs==1?2:bs),
m(new Message()), m(new Message()),
cursorId(), cursorId(),
nReturned(), nReturned(),
pos(), pos(),
data(), data(),
_ownCursor( true ){ _ownCursor( true ){
} }
DBClientCursor( DBConnector *_connector, const string &_ns, long lo ng _cursorId, int _nToReturn, int options ) : DBClientCursor( DBConnector *_connector, const string &_ns, long lo ng _cursorId, int _nToReturn, int options ) :
connector(_connector), connector(_connector),
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 goodies.h   goodies.h 
skipping to change at line 163 skipping to change at line 163
else else
gmtime_s(buf, &t); gmtime_s(buf, &t);
#else #else
if ( local ) if ( local )
localtime_r(&t, buf); localtime_r(&t, buf);
else else
gmtime_r(&t, buf); gmtime_r(&t, buf);
#endif #endif
} }
inline string terseCurrentTime(){ inline void terseCurrentTime( stringstream& ss , bool seconds = false ) {
struct tm t; struct tm t;
time_t_to_Struct( time(0) , &t ); time_t_to_Struct( time(0) , &t );
ss
<< ( 1900 + t.tm_year ) << "-" << ( 1 + t.tm_mon ) << "-" << t.
tm_mday
<< "_"
<< t.tm_hour << "-" << t.tm_min;
if ( seconds )
ss << "-" << t.tm_sec;
}
inline string terseCurrentTime(){
stringstream ss; stringstream ss;
ss << ( 1900 + t.tm_year ) << "-" terseCurrentTime(ss);
<< t.tm_mon << "-"
<< t.tm_mday << "-"
<< t.tm_hour << "-"
<< t.tm_min;
return ss.str(); return ss.str();
} }
#define MONGO_asctime _asctime_not_threadsafe_ #define MONGO_asctime _asctime_not_threadsafe_
#define asctime MONGO_asctime #define asctime MONGO_asctime
#define MONGO_gmtime _gmtime_not_threadsafe_ #define MONGO_gmtime _gmtime_not_threadsafe_
#define gmtime MONGO_gmtime #define gmtime MONGO_gmtime
#define MONGO_localtime _localtime_not_threadsafe_ #define MONGO_localtime _localtime_not_threadsafe_
#define localtime MONGO_localtime #define localtime MONGO_localtime
#define MONGO_ctime _ctime_is_not_threadsafe_ #define MONGO_ctime _ctime_is_not_threadsafe_
skipping to change at line 354 skipping to change at line 361
#if defined(BOOST_LITTLE_ENDIAN) #if defined(BOOST_LITTLE_ENDIAN)
inline unsigned long fixEndian(unsigned long x) { inline unsigned long fixEndian(unsigned long x) {
return x; return x;
} }
#else #else
inline unsigned long fixEndian(unsigned long x) { inline unsigned long fixEndian(unsigned long x) {
return swapEndian(x); return swapEndian(x);
} }
#endif #endif
// Like strlen, but only scans up to n bytes.
// Returns -1 if no '0' found.
inline int strnlen( const char *s, int n ) {
for( int i = 0; i < n; ++i )
if ( !s[ i ] )
return i;
return -1;
}
#if !defined(_WIN32) #if !defined(_WIN32)
typedef int HANDLE; typedef int HANDLE;
inline void strcpy_s(char *dst, unsigned len, const char *src) { inline void strcpy_s(char *dst, unsigned len, const char *src) {
strcpy(dst, src); strcpy(dst, src);
} }
#else #else
typedef void *HANDLE; typedef void *HANDLE;
#endif #endif
/* thread local "value" rather than a pointer /* thread local "value" rather than a pointer
 End of changes. 4 change blocks. 
15 lines changed or deleted 14 lines changed or added


 health.h   health.h 
skipping to change at line 24 skipping to change at line 24
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
namespace mongo { namespace mongo {
/* throws */ /* throws */
bool requestHeartbeat(string setname, string memberFullName, BSONObj& r esult, int myConfigVersion, int& theirConfigVersion, bool checkEmpty = fals e); bool requestHeartbeat(string setname, string fromHost, string memberFul lName, BSONObj& result, int myConfigVersion, int& theirConfigVersion, bool checkEmpty = false);
struct HealthOptions { struct HealthOptions {
HealthOptions() { HealthOptions() {
heartbeatSleepMillis = 2000; heartbeatSleepMillis = 2000;
heartbeatTimeoutMillis = 10000; heartbeatTimeoutMillis = 10000;
heartbeatConnRetries = 3; heartbeatConnRetries = 3;
} }
bool isDefault() const { bool isDefault() const {
return !( heartbeatSleepMillis != 2000 || heartbeatTimeoutMilli s != 10000 || heartbeatConnRetries != 3 ); return !( heartbeatSleepMillis != 2000 || heartbeatTimeoutMilli s != 10000 || heartbeatConnRetries != 3 );
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 hex.h   hex.h 
skipping to change at line 51 skipping to change at line 51
for (int i=0; i<len; ++i){ for (int i=0; i<len; ++i){
char c = in[i]; char c = in[i];
char hi = hexchars[(c & 0xF0) >> 4]; char hi = hexchars[(c & 0xF0) >> 4];
char lo = hexchars[(c & 0x0F)]; char lo = hexchars[(c & 0x0F)];
out << hi << lo; out << hi << lo;
} }
return out.str(); return out.str();
} }
inline string toHexLower(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 65 skipping to change at line 65
if( _host == r._host ) if( _host == r._host )
return port() < r.port(); return port() < r.port();
return false; return false;
} }
bool operator==(const HostAndPort& r) const { bool operator==(const HostAndPort& r) const {
return _host == r._host && port() == r.port(); return _host == r._host && port() == r.port();
} }
/* 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; // defined in message.cpp
bool isLocalHost() const; bool isLocalHost() const;
// @returns host:port // @returns host:port
string toString() const; string toString() const;
operator string() const { return toString(); } operator string() const { return toString(); }
string host() const { return _host; } string host() const { return _host; }
int port() const { return _port >= 0 ? _port : CmdLine::DefaultDBPo rt; } int port() const { return _port >= 0 ? _port : CmdLine::DefaultDBPo rt; }
void setPort( int port ) { _port = port; }
private: private:
// invariant (except full obj assignment): // invariant (except full obj assignment):
string _host; string _host;
int _port; // -1 indicates unspecified int _port; // -1 indicates unspecified
}; };
/** 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 -
skipping to change at line 100 skipping to change at line 101
return str::before(a, '.') == str::before(b, '.'); return str::before(a, '.') == str::before(b, '.');
} }
inline HostAndPort HostAndPort::Me() { inline HostAndPort HostAndPort::Me() {
string h = getHostName(); string h = getHostName();
assert( !h.empty() ); assert( !h.empty() );
assert( h != "localhost" ); assert( h != "localhost" );
return HostAndPort(h, cmdLine.port); return HostAndPort(h, cmdLine.port);
} }
inline bool HostAndPort::isSelf() const {
int p = _port == -1 ? CmdLine::DefaultDBPort : _port;
if( p != cmdLine.port )
return false;
return sameHostname(getHostName(), _host) || isLocalHost();
}
inline string HostAndPort::toString() const { inline string HostAndPort::toString() const {
stringstream ss; stringstream ss;
ss << _host; ss << _host;
if( _port != -1 ) ss << ':' << _port; if ( _port != -1 ){
ss << ':';
#if defined(_DEBUG)
if( _port >= 44000 && _port < 44100 ) {
log() << "warning: special debug port 44xxx used" << endl;
ss << _port+1;
}
else
ss << _port;
#else
ss << _port;
#endif
}
return ss.str(); return ss.str();
} }
inline bool HostAndPort::isLocalHost() const { inline bool HostAndPort::isLocalHost() const {
return _host == "localhost" || _host == "127.0.0.1" || _host == ":: 1"; return _host == "localhost" || startsWith(_host.c_str(), "127.") || _host == "::1";
} }
inline HostAndPort::HostAndPort(string s) { inline HostAndPort::HostAndPort(string s) {
const char *p = s.c_str(); const char *p = s.c_str();
uassert(13110, "HostAndPort: bad config string", *p); uassert(13110, "HostAndPort: bad config string", *p);
const char *colon = strrchr(p, ':'); const char *colon = strrchr(p, ':');
if( colon ) { if( colon ) {
int port = atoi(colon+1); int port = atoi(colon+1);
uassert(13095, "HostAndPort: bad port #", port > 0); uassert(13095, "HostAndPort: bad port #", port > 0);
_host = string(p,colon-p); _host = string(p,colon-p);
 End of changes. 5 change blocks. 
11 lines changed or deleted 16 lines changed or added


 html.h   html.h 
skipping to change at line 58 skipping to change at line 58
ss << "<td>" << x << "</td>"; ss << "<td>" << x << "</td>";
return ss.str(); return ss.str();
} }
inline string td(string x) { inline string td(string x) {
return "<td>" + x + "</td>"; return "<td>" + x + "</td>";
} }
inline string th(string x) { inline string th(string x) {
return "<th>" + x + "</th>"; return "<th>" + x + "</th>";
} }
inline void tablecell( stringstream& ss , bool b ){
ss << "<td>" << (b ? "<b>X</b>" : "") << "</td>";
}
template< typename T>
inline void tablecell( stringstream& ss , const T& t ){
ss << "<td>" << t << "</td>";
}
inline string table(const char *headers[] = 0, bool border = true) { inline string table(const char *headers[] = 0, bool border = true) {
stringstream ss; stringstream ss;
ss << "\n<table " ss << "\n<table "
<< (border?"border=1 ":"") << (border?"border=1 ":"")
<< "cellpadding=2 cellspacing=0>\n"; << "cellpadding=2 cellspacing=0>\n";
if( headers ) { if( headers ) {
ss << "<tr>"; ss << "<tr>";
while( *headers ) { while( *headers ) {
ss << "<th>" << *headers << "</th>"; ss << "<th>" << *headers << "</th>";
headers++; headers++;
 End of changes. 1 change blocks. 
0 lines changed or deleted 9 lines changed or added


 instance.h   instance.h 
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 );
virtual bool callRead( Message& toSend , Message& response ){ virtual bool callRead( Message& toSend , Message& response ){
return call( toSend , response ); return call( toSend , response );
} }
virtual ConnectionString::ConnectionType type() const { return Conn
ectionString::MASTER; }
}; };
extern int lockFile; extern int lockFile;
void acquirePathLock(); void acquirePathLock();
void maybeCreatePidFile(); void maybeCreatePidFile();
} // namespace mongo } // namespace mongo
 End of changes. 1 change blocks. 
0 lines changed or deleted 3 lines changed or added


 log.h   log.h 
skipping to change at line 158 skipping to change at line 158
}; };
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 FILE* logfile; static FILE* logfile;
static boost::scoped_ptr<ostream> stream; static boost::scoped_ptr<ostream> stream;
static vector<Tee*> globalTees; static vector<Tee*> * globalTees;
public: public:
static void logLockless( const char * s ){ static void logLockless( const StringData& s ){
if ( doneSetup == 1717 ){ if ( doneSetup == 1717 ){
fwrite( s , strlen( s ) , 1 , logfile ); fwrite( s.data() , s.size() , 1 , logfile );
fflush( logfile ); fflush( logfile );
} }
else { else {
cout << s << endl; cout << s.data() << endl;
} }
} }
static void setLogFile(FILE* f){ static void setLogFile(FILE* f){
scoped_lock lk(mutex); scoped_lock lk(mutex);
logfile = f; logfile = f;
} }
static int magicNumber(){ static int magicNumber(){
return 1717; return 1717;
} }
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); string msg = ss.str();
time_t_to_String( time(0) , b.grow(20) );
b.appendStr( ss.str() );
const char *s = b.buf();
string threadName = getThreadName(); string threadName = getThreadName();
const char * type = logLevelToString(logLevel); const char * type = logLevelToString(logLevel);
StringBuilder sb; int spaceNeeded = msg.size() + 64 + threadName.size();
int bufSize = 128;
while ( bufSize < spaceNeeded )
bufSize += 128;
BufBuilder b(bufSize);
time_t_to_String( time(0) , b.grow(20) );
if (!threadName.empty()){ if (!threadName.empty()){
sb << "[" << threadName << "] "; b.appendChar( '[' );
b.appendStr( threadName , false );
b.appendChar( ']' );
b.appendChar( ' ' );
} }
sb << type << ( type[0] ? ": " : "" ); if ( type[0] ){
sb << s; b.appendStr( type , false );
string out = sb.str(); b.appendStr( ": " , false );
}
b.appendStr( msg );
string out( b.buf() , b.len() - 1);
scoped_lock lk(mutex); scoped_lock lk(mutex);
if( t ) t->write(logLevel,s); if( t ) t->write(logLevel,out);
for ( unsigned i=0; i<globalTees.size(); i++ ) if ( globalTees ){
globalTees[i]->write(logLevel,s); for ( unsigned i=0; i<globalTees->size(); i++ )
(*globalTees)[i]->write(logLevel,out);
}
#ifndef _WIN32 #ifndef _WIN32
//syslog( LOG_INFO , "%s" , cc ); //syslog( LOG_INFO , "%s" , cc );
#endif #endif
fwrite(out.data(), out.size(), 1, logfile); fwrite(out.data(), out.size(), 1, logfile);
fflush(logfile); fflush(logfile);
} }
_init(); _init();
} }
skipping to change at line 270 skipping to change at line 281
else else
*this << *t; *this << *t;
return *this; return *this;
} }
Logstream& prolog() { Logstream& prolog() {
return *this; return *this;
} }
void addGlobalTee( Tee * t ){ void addGlobalTee( Tee * t ){
globalTees.push_back( t ); if ( ! globalTees )
globalTees = new vector<Tee*>();
globalTees->push_back( t );
} }
private: private:
static thread_specific_ptr<Logstream> tsp; static thread_specific_ptr<Logstream> tsp;
Logstream(){ Logstream(){
_init(); _init();
} }
void _init(){ void _init(){
ss.str(""); ss.str("");
logLevel = LL_INFO; logLevel = LL_INFO;
skipping to change at line 378 skipping to change at line 391
FORMAT_MESSAGE_FROM_SYSTEM FORMAT_MESSAGE_FROM_SYSTEM
|FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_ALLOCATE_BUFFER
|FORMAT_MESSAGE_IGNORE_INSERTS, |FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, NULL,
x, 0, x, 0,
(LPTSTR) &errorText, // output (LPTSTR) &errorText, // output
0, // minimum size for output buffer 0, // minimum size for output buffer
NULL); NULL);
if( errorText ) { if( errorText ) {
string x = toUtf8String(errorText); string x = toUtf8String(errorText);
s << x; for( string::iterator i = x.begin(); i != x.end(); i++ ) {
if( *i == '\n' || *i == '\r' )
break;
s << *i;
}
LocalFree(errorText); LocalFree(errorText);
} }
else else
s << strerror(x); s << strerror(x);
/* /*
DWORD n = FormatMessage( DWORD n = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, x, NULL, x,
 End of changes. 11 change blocks. 
19 lines changed or deleted 36 lines changed or added


 message.h   message.h 
skipping to change at line 395 skipping to change at line 395
// if just one buffer, keep it in _buf, otherwise keep a sequence o f buffers in _data // if just one buffer, keep it in _buf, otherwise keep a sequence o f buffers in _data
MsgData * _buf; MsgData * _buf;
// byte buffer(s) - the first must contain at least a full MsgData unless using _buf for storage instead // byte buffer(s) - the first must contain at least a full MsgData unless using _buf for storage instead
typedef vector< pair< char*, int > > MsgVec; typedef vector< pair< char*, int > > MsgVec;
MsgVec _data; MsgVec _data;
bool _freeIt; bool _freeIt;
}; };
class SocketException : public DBException { class SocketException : public DBException {
public: public:
SocketException() : DBException( "socket exception" , 9001 ){} enum Type { CLOSED , RECV_ERROR , SEND_ERROR } type;
SocketException( Type t ) : DBException( "socket exception" , 9001
) , type(t){}
bool shouldPrint() const {
return type != CLOSED;
}
}; };
MSGID nextMessageId(); MSGID nextMessageId();
void setClientId( int id ); void setClientId( int id );
int getClientId(); int getClientId();
extern TicketHolder connTicketHolder; extern TicketHolder connTicketHolder;
class ElapsedTracker { class ElapsedTracker {
 End of changes. 1 change blocks. 
1 lines changed or deleted 8 lines changed or added


 miniwebserver.h   miniwebserver.h 
skipping to change at line 41 skipping to change at line 41
virtual void doRequest( virtual void doRequest(
const char *rq, // the full request const char *rq, // the full request
string url, string url,
// set these and return them: // set these and return them:
string& responseMsg, string& responseMsg,
int& responseCode, int& responseCode,
vector<string>& headers, // if completely empty, content-type: text/html will be added vector<string>& headers, // if completely empty, content-type: text/html will be added
const SockAddr &from const SockAddr &from
) = 0; ) = 0;
protected: // --- static helpers ----
string parseURL( const char * buf );
string parseMethod( const char * headers ); static void parseParams( BSONObj & params , string query );
string getHeader( const char * headers , string name );
void parseParams( BSONObj & params , string query ); static string parseURL( const char * buf );
static string parseMethod( const char * headers );
static string getHeader( const char * headers , string name );
static const char *body( const char *buf ); static const char *body( const char *buf );
static string urlDecode(const char* s); static string urlDecode(const char* s);
static string urlDecode(string s) {return urlDecode(s.c_str());} static string urlDecode(string s) {return urlDecode(s.c_str());}
private: private:
void accepted(int s, const SockAddr &from); void accepted(int s, const SockAddr &from);
static bool fullReceive( const char *buf ); static bool fullReceive( const char *buf );
}; };
 End of changes. 1 change blocks. 
5 lines changed or deleted 7 lines changed or added


 misc.h   misc.h 
skipping to change at line 86 skipping to change at line 86
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/1000, buf); time_t_to_String(millis/1000, buf);
return buf; return buf;
} }
}; };
// Like strlen, but only scans up to n bytes.
// Returns -1 if no '0' found.
inline int strnlen( const char *s, int n ) {
for( int i = 0; i < n; ++i )
if ( !s[ i ] )
return i;
return -1;
}
} }
 End of changes. 1 change blocks. 
0 lines changed or deleted 8 lines changed or added


 mmap.h   mmap.h 
skipping to change at line 24 skipping to change at line 24
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
namespace mongo { namespace mongo {
/* the administrative-ish stuff here */ /* the administrative-ish stuff here */
class MongoFile : boost::noncopyable { class MongoFile : boost::noncopyable {
public:
/** Flushable has to fail nicely if the underlying object gets kill
ed */
class Flushable {
public:
virtual ~Flushable(){}
virtual void flush() = 0;
};
protected: protected:
virtual void close() = 0; virtual void close() = 0;
virtual void flush(bool sync) = 0; virtual void flush(bool sync) = 0;
/**
* returns a thread safe object that you can call flush on
* Flushable has to fail nicely if the underlying object gets kille
d
*/
virtual Flushable * prepareFlush() = 0;
void created(); /* subclass must call after create */ void created(); /* subclass must call after create */
void destroyed(); /* subclass must call in destructor */ void destroyed(); /* subclass must call in destructor */
// only supporting on posix mmap // only supporting on posix mmap
virtual void _lock() {} virtual void _lock() {}
virtual void _unlock() {} virtual void _unlock() {}
public: public:
virtual ~MongoFile() {} virtual ~MongoFile() {}
skipping to change at line 148 skipping to change at line 162
uassert(13077, "couldn't open/map file", p); uassert(13077, "couldn't open/map file", p);
return Pointer(p); return Pointer(p);
}*/ }*/
/* Creates with length if DNE, otherwise uses existing file length, /* Creates with length if DNE, otherwise uses existing file length,
passed length. passed length.
*/ */
void* map(const char *filename, long &length, int options = 0 ); void* map(const char *filename, long &length, int options = 0 );
void flush(bool sync); void flush(bool sync);
virtual Flushable * prepareFlush();
/*void* viewOfs() { /*void* viewOfs() {
return view; return view;
}*/ }*/
long length() { long length() {
return len; return len;
} }
private: private:
 End of changes. 3 change blocks. 
0 lines changed or deleted 17 lines changed or added


 mockdbclient.h   mockdbclient.h 
skipping to change at line 33 skipping to change at line 33
#include "../db/replpair.h" #include "../db/replpair.h"
class MockDBClientConnection : public DBClientConnection { class MockDBClientConnection : public DBClientConnection {
public: public:
MockDBClientConnection() : connect_() {} MockDBClientConnection() : connect_() {}
virtual virtual
BSONObj findOne(const string &ns, const Query& query, const BSONObj *fi eldsToReturn = 0, int queryOptions = 0) { BSONObj findOne(const string &ns, const Query& query, const BSONObj *fi eldsToReturn = 0, int queryOptions = 0) {
return one_; return one_;
} }
virtual virtual
bool connect(const string &serverHostname, string& errmsg) { bool connect(const char * serverHostname, string& errmsg) {
return connect_;
}
virtual
bool connect(const HostAndPort& , string& errmsg) {
return connect_; return connect_;
} }
virtual virtual
bool isMaster(bool& isMaster, BSONObj *info=0) { bool isMaster(bool& isMaster, BSONObj *info=0) {
return isMaster_; return isMaster_;
} }
void one( const BSONObj &one ) { void one( const BSONObj &one ) {
one_ = one; one_ = one;
} }
void connect( bool val ) { void connect( bool val ) {
 End of changes. 1 change blocks. 
1 lines changed or deleted 5 lines changed or added


 msg.h   msg.h 
skipping to change at line 30 skipping to change at line 30
#include <deque> #include <deque>
#include "task.h" #include "task.h"
namespace mongo { namespace mongo {
namespace task { namespace task {
typedef boost::function<void()> lam; typedef boost::function<void()> lam;
class Server : private Task { /** typical usage is: task::fork( serverPtr ); */
class Server : public Task {
public: public:
/** send a message to the port */ /** send a message to the port */
void send(lam); void send(lam);
/** typical usage is: task::fork( foo.task() ); */
shared_ptr<Task> taskPtr() { return shared_ptr<Task>(static_cas
t<Task*>(this)); }
Server(string name) : _name(name) { } Server(string name) : _name(name) { }
virtual ~Server() { } virtual ~Server() { }
/** send message but block until function completes */ /** send message but block until function completes */
void call(const lam&); void call(const lam&);
void requeue() { rq = true; } void requeue() { rq = true; }
protected: protected:
/* this needn't be abstract; i left it that way for now so i re member /* this needn't be abstract; i left it that way for now so i re member
 End of changes. 2 change blocks. 
5 lines changed or deleted 2 lines changed or added


 namespace.h   namespace.h 
skipping to change at line 242 skipping to change at line 242
/* called when loaded from disk */ /* called when loaded from disk */
void onLoad(const Namespace& k); void onLoad(const Namespace& k);
NamespaceDetails( const DiskLoc &loc, bool _capped ); NamespaceDetails( const DiskLoc &loc, bool _capped );
DiskLoc firstExtent; DiskLoc firstExtent;
DiskLoc lastExtent; DiskLoc lastExtent;
/* NOTE: capped collections override the meaning of deleted list. /* NOTE: capped collections override the meaning of deleted list.
deletedList[0] points to a list of free records (DeletedRe cord's) for all extents in deletedList[0] points to a list of free records (DeletedRe cord's) for all extents in
the namespace. the capped namespace.
deletedList[1] points to the last record in the prev exten t. When the "current extent" deletedList[1] points to the last record in the prev exten t. When the "current extent"
changes, this value is updated. !deletedList[1].isValid() when this value is not changes, this value is updated. !deletedList[1].isValid() when this value is not
yet computed. yet computed.
*/ */
DiskLoc deletedList[Buckets]; DiskLoc deletedList[Buckets];
void dumpExtents();
long long datasize; long long datasize;
long long nrecords; long long nrecords;
int lastExtentSize; int lastExtentSize;
int nIndexes; int nIndexes;
private: private:
IndexDetails _indexes[NIndexesBase]; IndexDetails _indexes[NIndexesBase];
private:
Extent *theCapExtent() const { return capExtent.ext(); }
void advanceCapExtent( const char *ns );
DiskLoc __capAlloc(int len);
DiskLoc cappedAlloc(const char *ns, int len);
DiskLoc &cappedFirstDeletedInCurExtent();
bool nextIsInCapExtent( const DiskLoc &dl ) const;
public: public:
DiskLoc& cappedListOfAllDeletedRecords() { return deletedList[0]; }
DiskLoc& cappedLastDelRecLastExtent() { return deletedList[1]; }
void cappedDumpDelInfo();
bool capLooped() const { return capped && capFirstNewRecord.isValid
(); }
bool inCapExtent( const DiskLoc &dl ) const;
void cappedCheckMigrate();
void cappedTruncateAfter(const char *ns, DiskLoc after, bool inclus
ive); /** remove rest of the capped collection from this point onward */
int capped; int capped;
int max; // max # of objects for a capped table. TODO: should this be 64 bit? int max; // max # of objects for a capped table. TODO: should this be 64 bit?
double paddingFactor; // 1.0 = no padding. double paddingFactor; // 1.0 = no padding.
int flags; int flags;
DiskLoc capExtent; DiskLoc capExtent;
DiskLoc capFirstNewRecord; DiskLoc capFirstNewRecord;
/* NamespaceDetails version. So we can do backward compatibility i n the future. /* NamespaceDetails version. So we can do backward compatibility i n the future.
See filever.h See filever.h
*/ */
unsigned short dataFileVersion; unsigned short dataFileVersion;
unsigned short indexFileVersion; unsigned short indexFileVersion;
unsigned long long multiKeyIndexBits; unsigned long long multiKeyIndexBits;
skipping to change at line 429 skipping to change at line 450
return Buckets-1; return Buckets-1;
} }
/* allocate a new record. lenToAlloc includes headers. */ /* allocate a new record. lenToAlloc includes headers. */
DiskLoc alloc(const char *ns, int lenToAlloc, DiskLoc& extentLoc); DiskLoc alloc(const char *ns, int lenToAlloc, DiskLoc& extentLoc);
/* add a given record to the deleted chains for this NS */ /* add a given record to the deleted chains for this NS */
void addDeletedRec(DeletedRecord *d, DiskLoc dloc); void addDeletedRec(DeletedRecord *d, DiskLoc dloc);
void dumpDeleted(set<DiskLoc> *extents = 0); void dumpDeleted(set<DiskLoc> *extents = 0);
bool capLooped() const { return capped && capFirstNewRecord.isValid (); }
// Start from firstExtent by default. // Start from firstExtent by default.
DiskLoc firstRecord( const DiskLoc &startExtent = DiskLoc() ) const ; DiskLoc firstRecord( const DiskLoc &startExtent = DiskLoc() ) const ;
// Start from lastExtent by default. // Start from lastExtent by default.
DiskLoc lastRecord( const DiskLoc &startExtent = DiskLoc() ) const; DiskLoc lastRecord( const DiskLoc &startExtent = DiskLoc() ) const;
bool inCapExtent( const DiskLoc &dl ) const;
void cappedCheckMigrate();
long long storageSize( int * numExtents = 0 ); long long storageSize( int * numExtents = 0 );
private: private:
/** This prevents deletion from a capped collection upon wrap aroun DiskLoc _alloc(const char *ns, int len);
d -
so there will be no wrap around, just an exception. Used to be
used by the temp oplogs that were part of the cloneCollection i
mplementation.
*/
Extent *theCapExtent() const { return capExtent.ext(); }
void advanceCapExtent( const char *ns );
void maybeComplain( const char *ns, int len ) const; void maybeComplain( const char *ns, int len ) const;
DiskLoc __stdAlloc(int len); DiskLoc __stdAlloc(int len);
DiskLoc __capAlloc(int len);
DiskLoc _alloc(const char *ns, int len);
DiskLoc cappedAlloc(const char *ns, int len); // capped collections
void compact(); // combine adjacent deleted records void compact(); // combine adjacent deleted records
DiskLoc &firstDeletedInCapExtent();
bool nextIsInCapExtent( const DiskLoc &dl ) const;
}; // NamespaceDetails }; // NamespaceDetails
#pragma pack() #pragma pack()
void cappedTruncateAfter(const char *n, DiskLoc);
/* NamespaceDetailsTransient /* NamespaceDetailsTransient
these are things we know / compute about a namespace that are transi ent -- things these are things we know / compute about a namespace that are transi ent -- things
we don't actually store in the .ns file. so mainly caching of frequ ently used we don't actually store in the .ns file. so mainly caching of frequ ently used
information. information.
CAUTION: Are you maintaining this properly on a collection drop()? A dropdatabase()? Be careful. CAUTION: Are you maintaining this properly on a collection drop()? A dropdatabase()? Be careful.
The current field "allIndexKeys" may have too many keys in it on such an occurrence; The current field "allIndexKeys" may have too many keys in it on such an occurrence;
as currently used that does not cause anything terrible to happen. as currently used that does not cause anything terrible to happen.
skipping to change at line 658 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 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. 14 change blocks. 
20 lines changed or deleted 25 lines changed or added


 oid.h   oid.h 
skipping to change at line 20 skipping to change at line 20
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "../util/hex.h"
namespace mongo { namespace mongo {
#pragma pack(1) #pragma pack(1)
/** Object ID type. /** Object ID type.
BSON objects typically have an _id field for the object id. This f ield should be the first BSON objects typically have an _id field for the object id. This f ield should be the first
member of the object when present. class OID is a special type tha t is a 12 byte id which member of the object when present. class OID is a special type tha t is a 12 byte id which
is likely to be unique to the system. You may also use other types for _id's. is likely to be unique to the system. You may also use other types for _id's.
When _id field is missing from a BSON object, on an insert the data base may insert one When _id field is missing from a BSON object, on an insert the data base may insert one
automatically in certain circumstances. automatically in certain circumstances.
skipping to change at line 59 skipping to change at line 61
bool operator==(const OID& r) { bool operator==(const OID& r) {
return a==r.a&&b==r.b; return a==r.a&&b==r.b;
} }
bool operator!=(const OID& r) { bool operator!=(const OID& r) {
return a!=r.a||b!=r.b; return a!=r.a||b!=r.b;
} }
/** The object ID output as 24 hex digits. */ /** The object ID output as 24 hex digits. */
string str() const { string str() const {
stringstream s; return toHexLower(data, 12);
s << hex;
// s.fill( '0' );
// s.width( 2 );
// fill wasn't working so doing manually...
for( int i = 0; i < 8; i++ ) {
unsigned u = data[i];
if( u < 16 ) s << '0';
s << u;
}
const unsigned char * raw = (const unsigned char*)&b;
for( int i = 0; i < 4; i++ ) {
unsigned u = raw[i];
if( u < 16 ) s << '0';
s << u;
}
/*
s.width( 16 );
s << a;
s.width( 8 );
s << b;
s << dec;
*/
return s.str();
} }
string toString() const { return str(); } string toString() const { return str(); }
static OID gen() { OID o; o.init(); return o; } static OID gen() { OID o; o.init(); return o; }
static unsigned staticMachine(){ return _machine; } static unsigned staticMachine(){ return _machine; }
/** /**
sets the contents to a new oid / randomized value sets the contents to a new oid / randomized value
*/ */
skipping to change at line 113 skipping to change at line 92
bool isSet() const { return a || b; } bool isSet() const { return a || b; }
int compare( const OID& other ) const { return memcmp( data , other .data , 12 ); } int compare( const OID& other ) const { return memcmp( data , other .data , 12 ); }
bool operator<( const OID& other ) const { return compare( other ) < 0; } bool operator<( const OID& other ) const { return compare( other ) < 0; }
}; };
#pragma pack() #pragma pack()
ostream& operator<<( ostream &s, const OID &o ); ostream& operator<<( ostream &s, const OID &o );
inline StringBuilder& operator<< (StringBuilder& s, const OID& o) { ret urn (s << o.str()); }
/** Formatting mode for generating JSON from BSON. /** Formatting mode for generating JSON from BSON.
See <http://mongodb.onconfluence.com/display/DOCS/Mongo+Extended+JS ON> See <http://mongodb.onconfluence.com/display/DOCS/Mongo+Extended+JS ON>
for details. for details.
*/ */
enum JsonStringFormat { enum JsonStringFormat {
/** strict RFC format */ /** strict RFC format */
Strict, Strict,
/** 10gen format, which is close to JS format. This form is unders tandable by /** 10gen format, which is close to JS format. This form is unders tandable by
javascript running inside the Mongo server via eval() */ javascript running inside the Mongo server via eval() */
 End of changes. 3 change blocks. 
24 lines changed or deleted 4 lines changed or added


 oplogreader.h   oplogreader.h 
skipping to change at line 19 skipping to change at line 19
namespace mongo { namespace mongo {
/* started abstracting out the querying of the primary/master's oplog /* started abstracting out the querying of the primary/master's oplog
still fairly awkward but a start. still fairly awkward but a start.
*/ */
class OplogReader { class OplogReader {
auto_ptr<DBClientConnection> _conn; auto_ptr<DBClientConnection> _conn;
auto_ptr<DBClientCursor> cursor; auto_ptr<DBClientCursor> cursor;
public: public:
OplogReader() {
DEV log() << "TEMP *** OplogReader()" << endl;
}
~OplogReader() {
DEV log() << "TEMP *** ~OplogReader()" << endl;
}
void resetCursor() { void resetCursor() {
DEV log() << "TEMP *** OplogReader::resetCursor" << endl;
cursor.reset(); cursor.reset();
} }
void resetConnection() { void resetConnection() {
DEV log() << "TEMP *** OplogReader::resetConnection" << endl;
cursor.reset(); cursor.reset();
_conn.reset(); _conn.reset();
} }
DBClientConnection* conn() { return _conn.get(); } DBClientConnection* conn() { return _conn.get(); }
BSONObj findOne(const char *ns, const Query& q) { BSONObj findOne(const char *ns, const Query& q) {
return conn()->findOne(ns, q); return conn()->findOne(ns, q);
} }
BSONObj getLastOp(const char *ns) { BSONObj getLastOp(const char *ns) {
return findOne(ns, Query().sort(reverseNaturalObj)); return findOne(ns, Query().sort(reverseNaturalObj));
 End of changes. 3 change blocks. 
0 lines changed or deleted 9 lines changed or added


 optime.h   optime.h 
skipping to change at line 95 skipping to change at line 95
return last; return last;
} }
/* We store OpTime's in the database as BSON Date datatype -- we ne eded some sort of /* We store OpTime's in the database as BSON Date datatype -- we ne eded some sort of
64 bit "container" for these values. While these are not really " Dates", that seems a 64 bit "container" for these values. While these are not really " Dates", that seems a
better choice for now than say, Number, which is floating point. Note the BinData type better choice for now than say, Number, which is floating point. Note the BinData type
is perhaps the cleanest choice, lacking a true unsigned64 datatype , but BinData has 5 is perhaps the cleanest choice, lacking a true unsigned64 datatype , but BinData has 5
bytes of overhead. bytes of overhead.
*/ */
unsigned long long asDate() const { unsigned long long asDate() const {
return *((unsigned long long *) &i); return reinterpret_cast<const unsigned long long*>(&i)[0];
} }
long long asLL() const { long long asLL() const {
return *((long long *) &i); return reinterpret_cast<const long long*>(&i)[0];
} }
// unsigned long long& asDate() { return *((unsigned long lon g *) &i); }
bool isNull() const { return secs == 0; } bool isNull() const { return secs == 0; }
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();
 End of changes. 3 change blocks. 
3 lines changed or deleted 2 lines changed or added


 parallel.h   parallel.h 
skipping to change at line 75 skipping to change at line 75
/** /**
* this is a cursor that works over a set of servers * this is a cursor that works over a set of servers
* can be used in serial/paralellel as controlled by sub classes * can be used in serial/paralellel as controlled by sub classes
*/ */
class ClusteredCursor { class ClusteredCursor {
public: public:
ClusteredCursor( QueryMessage& q ); ClusteredCursor( QueryMessage& q );
ClusteredCursor( const string& ns , const BSONObj& q , int options= 0 , const BSONObj& fields=BSONObj() ); ClusteredCursor( const string& ns , const BSONObj& q , int options= 0 , const BSONObj& fields=BSONObj() );
virtual ~ClusteredCursor(); virtual ~ClusteredCursor();
/** call before using */
void init();
virtual bool more() = 0; virtual bool more() = 0;
virtual BSONObj next() = 0; virtual BSONObj next() = 0;
static BSONObj concatQuery( const BSONObj& query , const BSONObj& e xtraFilter ); static BSONObj concatQuery( const BSONObj& query , const BSONObj& e xtraFilter );
virtual string type() const = 0; virtual string type() const = 0;
virtual BSONObj explain(); virtual BSONObj explain();
protected: protected:
auto_ptr<DBClientCursor> query( const string& server , int num = 0
, BSONObj extraFilter = BSONObj() ); virtual void _init() = 0;
auto_ptr<DBClientCursor> query( const string& server , int num = 0
, BSONObj extraFilter = BSONObj() , int skipLeft = 0 );
BSONObj explain( const string& server , BSONObj extraFilter = BSONO bj() ); BSONObj explain( const string& server , BSONObj extraFilter = BSONO bj() );
static BSONObj _concatFilter( const BSONObj& filter , const BSONObj & extraFilter ); static BSONObj _concatFilter( const BSONObj& filter , const BSONObj & extraFilter );
virtual void _explain( map< string,list<BSONObj> >& out ) = 0; virtual void _explain( map< string,list<BSONObj> >& out ) = 0;
string _ns; string _ns;
BSONObj _query; BSONObj _query;
int _options; int _options;
BSONObj _fields; BSONObj _fields;
int _batchSize; int _batchSize;
bool _didInit;
bool _done; bool _done;
}; };
class FilteringClientCursor { class FilteringClientCursor {
public: public:
FilteringClientCursor( const BSONObj filter = BSONObj() ); FilteringClientCursor( const BSONObj filter = BSONObj() );
FilteringClientCursor( auto_ptr<DBClientCursor> cursor , const BSON Obj filter = BSONObj() ); FilteringClientCursor( auto_ptr<DBClientCursor> cursor , const BSON Obj filter = BSONObj() );
~FilteringClientCursor(); ~FilteringClientCursor();
void reset( auto_ptr<DBClientCursor> cursor ); void reset( auto_ptr<DBClientCursor> cursor );
skipping to change at line 189 skipping to change at line 197
class SerialServerClusteredCursor : public ClusteredCursor { class SerialServerClusteredCursor : public ClusteredCursor {
public: public:
SerialServerClusteredCursor( const set<ServerAndQuery>& servers , Q ueryMessage& q , int sortOrder=0); SerialServerClusteredCursor( const set<ServerAndQuery>& servers , Q ueryMessage& q , int sortOrder=0);
virtual bool more(); virtual bool more();
virtual BSONObj next(); virtual BSONObj next();
virtual string type() const { return "SerialServer"; } virtual string type() const { return "SerialServer"; }
private: private:
virtual void _explain( map< string,list<BSONObj> >& out ); virtual void _explain( map< string,list<BSONObj> >& out );
void _init(){}
vector<ServerAndQuery> _servers; vector<ServerAndQuery> _servers;
unsigned _serverIndex; unsigned _serverIndex;
FilteringClientCursor _current; FilteringClientCursor _current;
int _needToSkip; int _needToSkip;
}; };
/** /**
* runs a query in parellel across N servers * runs a query in parellel across N servers
skipping to change at line 210 skipping to change at line 220
*/ */
class ParallelSortClusteredCursor : public ClusteredCursor { class ParallelSortClusteredCursor : public ClusteredCursor {
public: public:
ParallelSortClusteredCursor( const set<ServerAndQuery>& servers , Q ueryMessage& q , const BSONObj& sortKey ); ParallelSortClusteredCursor( const set<ServerAndQuery>& servers , Q ueryMessage& q , const BSONObj& sortKey );
ParallelSortClusteredCursor( const set<ServerAndQuery>& servers , c onst string& ns , ParallelSortClusteredCursor( const set<ServerAndQuery>& servers , c onst string& ns ,
const Query& q , int options=0, const BSONObj& fields=BSONObj() ); const Query& q , int options=0, const BSONObj& fields=BSONObj() );
virtual ~ParallelSortClusteredCursor(); virtual ~ParallelSortClusteredCursor();
virtual bool more(); virtual bool more();
virtual BSONObj next(); virtual BSONObj next();
virtual string type() const { return "ParallelSort"; } virtual string type() const { return "ParallelSort"; }
private: protected:
void _init(); void _init();
virtual void _explain( map< string,list<BSONObj> >& out ); virtual void _explain( map< string,list<BSONObj> >& out );
int _numServers; int _numServers;
set<ServerAndQuery> _servers; set<ServerAndQuery> _servers;
BSONObj _sortKey; BSONObj _sortKey;
FilteringClientCursor * _cursors; FilteringClientCursor * _cursors;
int _needToSkip; int _needToSkip;
 End of changes. 5 change blocks. 
3 lines changed or deleted 13 lines changed or added


 pch.h   pch.h 
skipping to change at line 21 skipping to change at line 21
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #ifndef MONGO_PCH_H
#define MONGO_PCH_H
#if defined(MONGO_EXPOSE_MACROS) #if defined(MONGO_EXPOSE_MACROS)
# 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
skipping to change at line 168 skipping to change at line 169
} // namespace mongo } // namespace mongo
namespace mongo { namespace mongo {
typedef char _TCHAR; typedef char _TCHAR;
using boost::uint32_t; using boost::uint32_t;
using boost::uint64_t; using boost::uint64_t;
} // namespace mongo } // namespace mongo
#endif // MONGO_PCH_H
 End of changes. 2 change blocks. 
1 lines changed or deleted 2 lines changed or added


 pdfile.h   pdfile.h 
skipping to change at line 79 skipping to change at line 79
*/ */
Extent* createExtent(const char *ns, int approxSize, bool capped = false, int loops = 0); Extent* createExtent(const char *ns, int approxSize, bool capped = false, int loops = 0);
DataFileHeader *getHeader() { DataFileHeader *getHeader() {
return header; return header;
} }
/* return max size an extent may be */ /* return max size an extent may be */
static int maxSize(); static int maxSize();
void flush( bool sync );
private: private:
int defaultSize( const char *filename ) const; int defaultSize( const char *filename ) const;
Extent* getExtent(DiskLoc loc); Extent* getExtent(DiskLoc loc);
Extent* _getExtent(DiskLoc loc); Extent* _getExtent(DiskLoc loc);
Record* recordAt(DiskLoc dl); Record* recordAt(DiskLoc dl);
Record* makeRecord(DiskLoc dl, int size); Record* makeRecord(DiskLoc dl, int size);
void grow(DiskLoc dl, int size); void grow(DiskLoc dl, int size);
MMF mmf; MMF mmf;
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 processinfo.h   processinfo.h 
skipping to change at line 21 skipping to change at line 21
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include <sys/types.h> #include <sys/types.h>
#include <string>
#ifndef _WIN32 #ifndef _WIN32
#include <unistd.h> #include <unistd.h>
#else #else
typedef int pid_t; typedef int pid_t;
int getpid(); int getpid();
#endif #endif
namespace mongo { namespace mongo {
skipping to change at line 62 skipping to change at line 63
bool supported(); bool supported();
bool blockCheckSupported(); bool blockCheckSupported();
bool blockInMemory( char * start ); bool blockInMemory( char * start );
private: private:
pid_t _pid; pid_t _pid;
}; };
void writePidFile( const std::string& path );
} }
 End of changes. 2 change blocks. 
0 lines changed or deleted 3 lines changed or added


 queryoptimizer.h   queryoptimizer.h 
skipping to change at line 360 skipping to change at line 360
} }
virtual BSONObj currKey() const { return _c->currKey(); } virtual BSONObj currKey() const { return _c->currKey(); }
virtual DiskLoc refLoc() { return _c->refLoc(); } virtual DiskLoc refLoc() { return _c->refLoc(); }
virtual void noteLocation() { virtual void noteLocation() {
_c->noteLocation(); _c->noteLocation();
} }
virtual void checkLocation() { virtual void checkLocation() {
_c->checkLocation(); _c->checkLocation();
} }
virtual bool supportGetMore() { return true; } virtual bool supportGetMore() { return true; }
virtual bool supportYields() { return _c->supportYields(); }
// with update we could potentially get the same document on multip le // with update we could potentially get the same document on multip le
// indexes, but update appears to already handle this with seenObje cts // indexes, but update appears to already handle this with seenObje cts
// so we don't have to do anything special here. // so we don't have to do anything special here.
virtual bool getsetdup(DiskLoc loc) { virtual bool getsetdup(DiskLoc loc) {
return _c->getsetdup( loc ); return _c->getsetdup( loc );
} }
virtual CoveredIndexMatcher *matcher() const { return _matcher.get( ); } virtual CoveredIndexMatcher *matcher() const { return _matcher.get( ); }
// just for testing // just for testing
shared_ptr< Cursor > sub_c() const { return _c; } shared_ptr< Cursor > sub_c() const { return _c; }
private: private:
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 ramlog.h   ramlog.h 
skipping to change at line 50 skipping to change at line 50
virtual void write(LogLevel ll, const string& str) { virtual void write(LogLevel ll, const string& str) {
char *p = lines[(h+n)%N]; char *p = lines[(h+n)%N];
if( str.size() < C ) if( str.size() < C )
strcpy(p, str.c_str()); strcpy(p, str.c_str());
else else
memcpy(p, str.c_str(), C-1); memcpy(p, str.c_str(), C-1);
if( n < N ) n++; if( n < N ) n++;
else h = (h+1) % N; else h = (h+1) % N;
} }
vector<const char *> get() const { void get( vector<const char*>& v) const {
vector<const char *> v;
for( unsigned x=0, i=h; x++ < n; i=(i+1)%N ) for( unsigned x=0, i=h; x++ < n; i=(i+1)%N )
v.push_back(lines[i]); v.push_back(lines[i]);
return v;
} }
static int repeats(const vector<const char *>& v, int i) { static int repeats(const vector<const char *>& v, int i) {
for( int j = i-1; j >= 0 && j+8 > i; j-- ) { for( int j = i-1; j >= 0 && j+8 > i; j-- ) {
if( strcmp(v[i]+20,v[j]+20) == 0 ) { if( strcmp(v[i]+20,v[j]+20) == 0 ) {
for( int x = 1; ; x++ ) { for( int x = 1; ; x++ ) {
if( j+x == i ) return j; if( j+x == i ) return j;
if( i+x>=(int) v.size() ) return -1; if( i+x>=(int) v.size() ) return -1;
if( strcmp(v[i+x]+20,v[j+x]+20) ) return -1; if( strcmp(v[i+x]+20,v[j+x]+20) ) return -1;
} }
skipping to change at line 93 skipping to change at line 91
if( str::endsWith(s, " up\n") ) if( str::endsWith(s, " up\n") )
return html::green(line); return html::green(line);
else if( str::contains(s, " down ") || str::endsWith(s, " d own\n") ) else if( str::contains(s, " down ") || str::endsWith(s, " d own\n") )
return html::yellow(line); return html::yellow(line);
return line; //html::blue(line); return line; //html::blue(line);
} }
return line; return line;
} }
/* turn http:... into an anchor */ /* turn http:... into an anchor */
string linkify(const char *s) { string linkify(const char *s) {
const char *p = s; const char *p = s;
const char *h = strstr(p, "http://"); const char *h = strstr(p, "http://");
if( h == 0 ) return s; if( h == 0 ) return s;
const char *sp = h + 7; const char *sp = h + 7;
while( *sp && *sp != ' ' ) sp++; while( *sp && *sp != ' ' ) sp++;
string url(h, sp-h); string url(h, sp-h);
stringstream ss; stringstream ss;
ss << string(s, h-s) << "<a href=\"" << url << "\">" << url << "</ ss << string(s, h-s) << "<a href=\"" << url << "\">" << url <<
a>" << sp; "</a>" << sp;
return ss.str(); return ss.str();
} }
void toHTML(stringstream& s) { void toHTML(stringstream& s) {
vector<const char*> v;
get( v );
bool first = true; bool first = true;
s << "<pre>\n"; s << "<pre>\n";
vector<const char *> v = get();
for( int i = 0; i < (int)v.size(); i++ ) { for( int i = 0; i < (int)v.size(); i++ ) {
assert( strlen(v[i]) > 20 ); assert( strlen(v[i]) > 20 );
int r = repeats(v, i); int r = repeats(v, i);
if( r < 0 ) { if( r < 0 ) {
s << color( linkify( clean(v,i).c_str() ) ); s << color( linkify( clean(v,i).c_str() ) );
} }
else { else {
stringstream x; stringstream x;
x << string(v[i], 0, 20); x << string(v[i], 0, 20);
int nr = (i-r); int nr = (i-r);
int last = i+nr-1; int last = i+nr-1;
for( ; r < i ; r++ ) x << '.'; for( ; r < i ; r++ ) x << '.';
if( 1 ) { if( 1 ) {
stringstream r; stringstream r;
if( nr == 1 ) r << "repeat last line"; if( nr == 1 ) r << "repeat last line";
 End of changes. 8 change blocks. 
18 lines changed or deleted 18 lines changed or added


 rs.h   rs.h 
skipping to change at line 72 skipping to change at line 72
class Manager : public task::Server { class Manager : public task::Server {
ReplSetImpl *rs; ReplSetImpl *rs;
bool busyWithElectSelf; bool busyWithElectSelf;
int _primary; int _primary;
const Member* findOtherPrimary(); const Member* findOtherPrimary();
void noteARemoteIsPrimary(const Member *); void noteARemoteIsPrimary(const Member *);
virtual void starting(); virtual void starting();
public: public:
Manager(ReplSetImpl *rs); Manager(ReplSetImpl *rs);
~Manager();
void msgReceivedNewConfig(BSONObj); void msgReceivedNewConfig(BSONObj);
void msgCheckNewState(); void msgCheckNewState();
}; };
struct Target; struct Target;
class Consensus { class Consensus {
ReplSetImpl &rs; ReplSetImpl &rs;
struct LastYea { struct LastYea {
LastYea() : when(0), who(0xffffffff) { } LastYea() : when(0), who(0xffffffff) { }
skipping to change at line 111 skipping to change at line 112
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. th at logic implemented here. */ /** most operations on a ReplSet object should be done while locked. th at logic implemented here. */
class RSBase : boost::noncopyable { class RSBase : boost::noncopyable {
public:
const unsigned magic;
void assertValid() { assert( magic == 0x12345677 ); }
private: private:
mutex m; mutex m;
int _locked; int _locked;
ThreadLocalValue<bool> _lockedByMe; ThreadLocalValue<bool> _lockedByMe;
protected: protected:
RSBase() : m("RSBase"), _locked(0) { } RSBase() : magic(0x12345677), m("RSBase"), _locked(0) { }
~RSBase() {
log() << "~RSBase should never be called?" << rsLog;
assert(false);
}
class lock { class lock {
RSBase& rsbase; RSBase& rsbase;
auto_ptr<scoped_lock> sl; auto_ptr<scoped_lock> sl;
public: public:
lock(RSBase* b) : rsbase(*b) { lock(RSBase* b) : rsbase(*b) {
if( rsbase._lockedByMe.get() ) if( rsbase._lockedByMe.get() )
return; // recursive is ok... return; // recursive is ok...
sl.reset( new scoped_lock(rsbase.m) ); sl.reset( new scoped_lock(rsbase.m) );
skipping to change at line 168 skipping to change at line 176
SP() : state(MemberState::RS_STARTUP), primary(0) { } SP() : state(MemberState::RS_STARTUP), primary(0) { }
MemberState state; MemberState state;
const Member *primary; const Member *primary;
}; };
const SP get() { const SP get() {
scoped_lock lk(m); scoped_lock lk(m);
return sp; return sp;
} }
MemberState getState() const { return sp.state; } MemberState getState() const { return sp.state; }
const Member* getPrimary() const { return sp.primary; } const Member* getPrimary() const { return sp.primary; }
void change(MemberState s) { void change(MemberState s, const Member *self) {
scoped_lock lk(m); scoped_lock lk(m);
sp.state = s; sp.state = s;
// note : we don't correct primary if RS_PRIMARY was set here. if( s.primary() ) {
that must be done upstream. sp.primary = self;
}
else {
if( self == sp.primary )
sp.primary = 0;
}
} }
void set(MemberState s, const Member *p) { void set(MemberState s, const Member *p) {
scoped_lock lk(m); scoped_lock lk(m);
sp.state = s; sp.primary = p; sp.state = s; sp.primary = p;
} }
void setSelfPrimary(const Member *self) { void setSelfPrimary(const Member *self) { change(MemberState::RS_PR
scoped_lock lk(m); IMARY, self); }
sp.state = MemberState::RS_PRIMARY;
sp.primary = self;
}
void setOtherPrimary(const Member *mem) { void setOtherPrimary(const Member *mem) {
scoped_lock lk(m); scoped_lock lk(m);
assert( !sp.state.primary() ); assert( !sp.state.primary() );
sp.primary = mem; sp.primary = mem;
} }
StateBox() : m("StateBox") { } StateBox() : m("StateBox") { }
private: private:
mutex m; mutex m;
SP sp; SP sp;
}; };
void parseReplsetCmdLine(string cfgString, string& setname, vector<Host
AndPort>& seeds, set<HostAndPort>& seedSet );
/** Parameter given to the --replSet command line option (parsed).
Syntax is "<setname>/<seedhost1>,<seedhost2>"
where setname is a name and seedhost is "<host>[:<port>]" */
class ReplSetCmdline {
public:
ReplSetCmdline(string cfgString) { parseReplsetCmdLine(cfgString, s
etname, seeds, seedSet); }
string setname;
vector<HostAndPort> seeds;
set<HostAndPort> seedSet;
};
/* 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 : protected 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
skipping to change at line 226 skipping to change at line 249
private: private:
set<ReplSetHealthPollTask*> healthTasks; set<ReplSetHealthPollTask*> healthTasks;
void endOldHealthTasks(); void endOldHealthTasks();
void startHealthTaskFor(Member *m); void startHealthTaskFor(Member *m);
private: private:
Consensus elect; Consensus elect;
bool ok() const { return !box.getState().fatal(); } bool ok() const { return !box.getState().fatal(); }
void relinquish(); void relinquish();
void forgetPrimary();
protected: protected:
bool _stepDown(); bool _stepDown();
private: private:
void assumePrimary(); void assumePrimary();
void loadLastOpTimeWritten(); void loadLastOpTimeWritten();
void changeState(MemberState s); void changeState(MemberState s);
protected: protected:
// "heartbeat message" // "heartbeat message"
// sent in requestHeartbeat respond in field "hbm" // sent in requestHeartbeat respond in field "hbm"
char _hbmsg[256]; // we change this unocked, thus not a c++ string char _hbmsg[256]; // we change this unocked, thus not a c++ string
public: public:
void sethbmsg(string s, int logLevel = 0) { void sethbmsg(string s, int logLevel = 0) {
unsigned sz = s.size(); unsigned sz = s.size();
if( sz >= 256 ) if( sz >= 256 )
memcpy(_hbmsg, s.c_str(), 255); memcpy(_hbmsg, s.c_str(), 255);
else { else {
_hbmsg[sz] = 0; _hbmsg[sz] = 0;
memcpy(_hbmsg, s.c_str(), sz); memcpy(_hbmsg, s.c_str(), sz);
} }
log(logLevel) << "replSet " << s << rsLog; if( !s.empty() )
log(logLevel) << "replSet " << s << rsLog;
} }
protected: protected:
bool initFromConfig(ReplSetConfig& c); // true if ok; throws if con fig really bad; false if config doesn't include self 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>&); 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 box.getState(); } MemberState state() const { return box.getState(); }
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 /* throws exception if a problem initializing. */
replsetname/host1,host2:port,... ReplSetImpl(ReplSetCmdline&);
where :port is optional.
throws exception if a problem initializing. */
ReplSetImpl(string cfgString);
/* call afer constructing to start - returns fairly quickly after l aunching its threads */ /* call afer constructing to start - returns fairly quickly after l aunching its threads */
void _go(); void _go();
private: private:
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.
@return true if ok; throws if config really bad; false if confi g doesn't include self @return true if ok; throws if config really bad; false if confi g doesn't include self
*/ */
bool _loadConfigFinish(vector<ReplSetConfig>& v); bool _loadConfigFinish(vector<ReplSetConfig>& v);
void loadConfig(); void loadConfig();
list<HostAndPort> memberHostnames() const; list<HostAndPort> memberHostnames() const;
const ReplSetConfig::MemberCfg& myConfig() const { return _self->co nfig(); } const ReplSetConfig::MemberCfg& myConfig() const { return _self->co nfig(); }
bool iAmArbiterOnly() const { return myConfig().arbiterOnly; } bool iAmArbiterOnly() const { return myConfig().arbiterOnly; }
bool iAmPotentiallyHot() const { return myConfig().potentiallyHot() ; } bool iAmPotentiallyHot() const { return myConfig().potentiallyHot() ; }
protected:
Member *_self; Member *_self;
private:
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 _self->id(); } unsigned selfId() const { return _self->id(); }
shared_ptr<Manager> mgr; 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;
skipping to change at line 311 skipping to change at line 336
friend class Consensus; friend class Consensus;
private: private:
/* pulling data from primary related - see rs_sync.cpp */ /* pulling data from primary related - see rs_sync.cpp */
void _syncDoInitialSync(); void _syncDoInitialSync();
void syncDoInitialSync(); void syncDoInitialSync();
void _syncThread(); void _syncThread();
void syncTail(); void syncTail();
void syncApply(const BSONObj &o); void syncApply(const BSONObj &o);
void syncRollback(OplogReader& r); void syncRollback(OplogReader& r);
void syncFixUp(HowToFixUp& h, DBClientConnection*); void syncFixUp(HowToFixUp& h, OplogReader& r);
public: public:
void syncThread(); void syncThread();
}; };
class ReplSet : public ReplSetImpl { class ReplSet : public ReplSetImpl {
public: public:
ReplSet(string cfgString) : ReplSetImpl(cfgString) { } ReplSet(ReplSetCmdline& replSetCmdline) : ReplSetImpl(replSetCmdlin e) { }
bool stepDown() { return _stepDown(); } bool stepDown() { return _stepDown(); }
string selfFullName() {
lock lk(this);
return _self->fullName();
}
/* call after constructing to start - returns fairly quickly after la[unching its threads */ /* call after constructing to start - returns fairly quickly after la[unching its threads */
void go() { _go(); } void go() { _go(); }
void fatal() { _fatal(); } void fatal() { _fatal(); }
bool 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 ); }
skipping to change at line 373 skipping to change at line 403
} }
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, bool self) : inline Member::Member(HostAndPort h, unsigned ord, const ReplSetConfig: :MemberCfg *c, bool self) :
_config(c), _h(h), _hbinfo(ord) { _config(c), _h(h), _hbinfo(ord) {
if( self ) { if( self ) {
_hbinfo.health = 1.0; _hbinfo.health = 1.0;
} }
} }
inline bool ReplSet::isMaster(const char *client) { inline bool ReplSet::isMaster(const char *client) {
 End of changes. 17 change blocks. 
23 lines changed or deleted 50 lines changed or added


 rs_member.h   rs_member.h 
skipping to change at line 63 skipping to change at line 63
bool operator==(const MemberState& r) const { return s == r.s; } bool operator==(const MemberState& r) const { return s == r.s; }
bool operator!=(const MemberState& r) const { return s != r.s; } bool operator!=(const MemberState& r) const { return s != r.s; }
}; };
/* this is supposed to be just basic information on a member, /* this is supposed to be just basic information on a member,
and copy constructable. */ and copy constructable. */
class HeartbeatInfo { class HeartbeatInfo {
unsigned _id; unsigned _id;
public: public:
HeartbeatInfo() : _id(0xffffffff) { } HeartbeatInfo() : _id(0xffffffff),skew(INT_MIN) { }
HeartbeatInfo(unsigned id); HeartbeatInfo(unsigned id);
bool up() const { return health > 0; } bool up() const { return health > 0; }
unsigned id() const { return _id; } unsigned id() const { return _id; }
MemberState hbstate; MemberState hbstate;
double health; double health;
time_t upSince; time_t upSince;
time_t lastHeartbeat; time_t lastHeartbeat;
string lastHeartbeatMsg; string lastHeartbeatMsg;
OpTime opTime; OpTime opTime;
int skew;
/* true if changed in a way of interest to the repl set manager. */
bool changed(const HeartbeatInfo& old) const; bool changed(const HeartbeatInfo& old) const;
}; };
inline HeartbeatInfo::HeartbeatInfo(unsigned id) : _id(id) { inline HeartbeatInfo::HeartbeatInfo(unsigned id) : _id(id) {
health = -1.0; health = -1.0;
lastHeartbeat = upSince = 0; lastHeartbeat = upSince = 0;
skew = INT_MIN;
} }
inline bool HeartbeatInfo::changed(const HeartbeatInfo& old) const { inline bool HeartbeatInfo::changed(const HeartbeatInfo& old) const {
return health != old.health || return health != old.health ||
hbstate != old.hbstate; hbstate != old.hbstate;
} }
} }
 End of changes. 3 change blocks. 
1 lines changed or deleted 5 lines changed or added


 stringdata.h   stringdata.h 
skipping to change at line 41 skipping to change at line 41
: _data(c), _size((unsigned) strlen(c)) {} : _data(c), _size((unsigned) strlen(c)) {}
StringData( const string& s ) StringData( const string& s )
: _data(s.c_str()), _size((unsigned) s.size()) {} : _data(s.c_str()), _size((unsigned) s.size()) {}
struct LiteralTag {}; struct LiteralTag {};
template<size_t N> template<size_t N>
StringData( const char (&val)[N], LiteralTag ) StringData( const char (&val)[N], LiteralTag )
: _data(&val[0]), _size(N-1) {} : _data(&val[0]), _size(N-1) {}
// Construct a StringData explicitly, for the case where the
// length of the string is already known. 'c' must be a
// pointer to a null-terminated string, and strlenOfc must be
// the length that std::strlen(c) would return, a.k.a the
// index of the terminator in c.
StringData( const char* c, size_t strlenOfc )
: _data(c), _size((unsigned) strlenOfc) {}
const char* const data() const { return _data; } const char* const data() const { return _data; }
const unsigned size() const { return _size; } const unsigned size() const { return _size; }
private: private:
// TODO - Hook this class up in the BSON machinery // TODO - Hook this class up in the BSON machinery
// There are two assumptions here that we may want to review then. // There are two assumptions here that we may want to review then.
// '_data' *always* finishes with a null terminator // '_data' *always* finishes with a null terminator
// 'size' does *not* account for the null terminator // 'size' does *not* account for the null terminator
// These assumptions may make it easier to minimize changes to exis ting code // These assumptions may make it easier to minimize changes to exis ting code
const char* const _data; const char* const _data;
 End of changes. 1 change blocks. 
0 lines changed or deleted 8 lines changed or added


 syncclusterconnection.h   syncclusterconnection.h 
skipping to change at line 90 skipping to change at line 90
virtual void killCursor( long long cursorID ); virtual void killCursor( long long cursorID );
virtual string getServerAddress() const { return _address; } virtual string getServerAddress() const { return _address; }
virtual bool isFailed() const { return false; } virtual bool isFailed() const { return false; }
virtual string toString() { return _toString(); } virtual string toString() { return _toString(); }
virtual BSONObj getLastErrorDetailed(); virtual BSONObj getLastErrorDetailed();
virtual bool callRead( Message& toSend , Message& response ); virtual bool callRead( Message& toSend , Message& response );
virtual ConnectionString::ConnectionType type() const { return Conn
ectionString::SYNC; }
private: private:
SyncClusterConnection( SyncClusterConnection& prev ); SyncClusterConnection( SyncClusterConnection& prev );
string _toString() const; string _toString() const;
bool _commandOnActive(const string &dbname, const BSONObj& cmd, BSO NObj &info, int options=0); bool _commandOnActive(const string &dbname, const BSONObj& cmd, BSO NObj &info, int options=0);
auto_ptr<DBClientCursor> _queryOnActive(const string &ns, Query que ry, int nToReturn, int nToSkip, auto_ptr<DBClientCursor> _queryOnActive(const string &ns, Query que ry, int nToReturn, int nToSkip,
const BSONObj *fieldsToRetu rn, int queryOptions, int batchSize ); const BSONObj *fieldsToRetu rn, int queryOptions, int batchSize );
int _lockType( const string& name ); int _lockType( const string& name );
void _checkLast(); void _checkLast();
void _connect( string host ); void _connect( string host );
 End of changes. 1 change blocks. 
0 lines changed or deleted 3 lines changed or added


 task.h   task.h 
skipping to change at line 28 skipping to change at line 28
#pragma once #pragma once
#include "../background.h" #include "../background.h"
namespace mongo { namespace mongo {
namespace task { namespace task {
/** abstraction around threads. simpler than BackgroundJob which i s used behind the scenes. /** abstraction around threads. simpler than BackgroundJob which i s used behind the scenes.
a shared_ptr is kept to the task - both by the task while runni allocate the Task dynamically. when the thread terminates, the
ng and the caller. that way Task object will delete itself.
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. c an be called by other threads /** 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. as long as the Task is still in scope.
*/ */
void halt(); void halt();
private: private:
shared_ptr<Task> me;
unsigned n, repeat; unsigned n, repeat;
friend void fork(shared_ptr<Task> t); friend void fork(Task* t);
friend void repeat(shared_ptr<Task> t, unsigned millis); friend void repeat(Task* t, unsigned millis);
virtual void run(); virtual void run();
virtual void ending(); virtual void ending() { }
void begin(shared_ptr<Task>); void begin();
}; };
/** run once */ /** run once */
void fork(shared_ptr<Task> t); void fork(Task *t);
/** run doWork() over and over, with a pause between runs of millis */ /** run doWork() over and over, with a pause between runs of millis */
void repeat(shared_ptr<Task> t, unsigned millis); void repeat(Task *t, unsigned millis);
/*** Example *** /*** Example ***
inline void sample() { inline void sample() {
class Sample : public Task { class Sample : public Task {
public: public:
int result; int result;
virtual void doWork() { result = 1234; } virtual void doWork() { result = 1234; }
Sample() : result(0) { } Sample() : result(0) { }
}; };
shared_ptr<Sample> q( new Sample() ); shared_ptr<Sample> q( new Sample() );
 End of changes. 6 change blocks. 
11 lines changed or deleted 8 lines changed or added


 util.h   util.h 
skipping to change at line 143 skipping to change at line 143
ns = big.substr( start + 1 , ( end - start ) - 1 ); ns = big.substr( start + 1 , ( end - start ) - 1 );
raw = big.substr( end + 1 ); raw = big.substr( end + 1 );
return true; return true;
} }
private: private:
bool _justConnection; bool _justConnection;
string _ns; string _ns;
}; };
bool checkShardVersion( DBClientBase & conn , const string& ns , bool a uthoritative = false , int tryNumber = 1 ); bool checkShardVersion( DBClientBase & conn , const string& ns , bool a uthoritative = false , int tryNumber = 1 );
void resetShardVersion( DBClientBase * conn );
} }
 End of changes. 1 change blocks. 
1 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/