assert_util.h   assert_util.h 
skipping to change at line 90 skipping to change at line 90
}; };
extern AssertionCount assertionCount; extern AssertionCount assertionCount;
class DBException : public std::exception { class DBException : public std::exception {
public: public:
virtual const char* what() const throw() = 0; virtual const char* what() const throw() = 0;
virtual string toString() const { virtual string toString() const {
return what(); return what();
} }
virtual int getCode() = 0; virtual int getCode() const = 0;
operator string() const { return toString(); } operator string() const { stringstream ss; ss << getCode() << " " <
< what(); return ss.str(); }
}; };
class AssertionException : public DBException { class AssertionException : public DBException {
public: public:
int code; int code;
string msg; string msg;
AssertionException() { code = 0; } AssertionException() { code = 0; }
virtual ~AssertionException() throw() { } virtual ~AssertionException() throw() { }
virtual bool severe() { virtual bool severe() {
return true; return true;
} }
virtual bool isUserAssertion() { virtual bool isUserAssertion() {
return false; return false;
} }
virtual int getCode(){ return code; } virtual int getCode() const { return code; }
virtual const char* what() const throw() { return msg.c_str(); } virtual const char* what() const throw() { return msg.c_str(); }
/* true if an interrupted exception - see KillCurrentOp */ /* true if an interrupted exception - see KillCurrentOp */
bool interrupted() { bool interrupted() {
return code == 11600 || code == 11601; return code == 11600 || code == 11601;
} }
}; };
/* UserExceptions are valid errors that a user can cause, like out of d isk space or duplicate key */ /* UserExceptions are valid errors that a user can cause, like out of d isk space or duplicate key */
class UserException : public AssertionException { class UserException : public AssertionException {
skipping to change at line 168 skipping to change at line 168
inline void msgasserted(int msgid, string msg) { msgasserted(msgid, msg .c_str()); } inline void msgasserted(int msgid, string msg) { msgasserted(msgid, msg .c_str()); }
#ifdef assert #ifdef assert
#undef assert #undef assert
#endif #endif
#define MONGO_assert(_Expression) (void)( (!!(_Expression)) || (mongo::asse rted(#_Expression, __FILE__, __LINE__), 0) ) #define MONGO_assert(_Expression) (void)( (!!(_Expression)) || (mongo::asse rted(#_Expression, __FILE__, __LINE__), 0) )
#define assert MONGO_assert #define assert MONGO_assert
/* "user assert". if asserts, user did something wrong, not our code * / /* "user assert". if asserts, user did something wrong, not our code * /
inline void uassert(unsigned msgid, string msg, bool expr) { #define MONGO_uassert(msgid, msg, expr) (void)( (!!(expr)) || (mongo::uasse
if( !expr ) uasserted(msgid, msg.c_str()); rted(msgid, msg), 0) )
} #define uassert MONGO_uassert
template<class T>
inline void uassert(unsigned msgid, string msg, const T&t , bool expr)
{
if( !expr ){
stringstream ss;
ss << msg << " " << t.toString();
uasserted(msgid, ss.str());
}
}
inline void uassert(unsigned msgid, const char * msg, bool expr) {
if( !expr ) uasserted(msgid, msg);
}
/* warning only - keeps going */ /* warning only - keeps going */
#define MONGO_wassert(_Expression) (void)( (!!(_Expression)) || (mongo::was serted(#_Expression, __FILE__, __LINE__), 0) ) #define MONGO_wassert(_Expression) (void)( (!!(_Expression)) || (mongo::was serted(#_Expression, __FILE__, __LINE__), 0) )
#define wassert MONGO_wassert #define wassert MONGO_wassert
/* display a message, no context, and throw assertionexception /* display a message, no context, and throw assertionexception
easy way to throw an exception and log something without our stack t race easy way to throw an exception and log something without our stack t race
display happening. display happening.
*/ */
inline void massert(unsigned msgid, string msg, bool expr) { #define MONGO_massert(msgid, msg, expr) (void)( (!!(expr)) || (mongo::msgas
if( !expr) msgasserted(msgid, msg.c_str()); serted(msgid, msg), 0) )
} #define massert MONGO_massert
inline void massert(unsigned msgid, const char * msg, bool expr) {
if( !expr) msgasserted(msgid, msg);
}
/* dassert is 'debug assert' -- might want to turn off for production a s these /* dassert is 'debug assert' -- might want to turn off for production a s these
could be slow. could be slow.
*/ */
#if defined(_DEBUG) #if defined(_DEBUG)
# define MONGO_dassert assert # define MONGO_dassert assert
#else #else
# define MONGO_dassert(x) # define MONGO_dassert(x)
#endif #endif
#define dassert MONGO_dassert #define dassert MONGO_dassert
 End of changes. 4 change blocks. 
26 lines changed or deleted 10 lines changed or added


 balance.h   balance.h 
skipping to change at line 29 skipping to change at line 29
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "../util/background.h" #include "../util/background.h"
#include "../client/dbclient.h" #include "../client/dbclient.h"
namespace mongo { namespace mongo {
class Balancer : public BackgroundJob { class Balancer : public BackgroundJob {
public: public:
string name() { return "Balancer"; }
Balancer(); Balancer();
void run(); void run();
private: private:
bool shouldIBalance( DBClientBase& conn ); bool shouldIBalance( DBClientBase& conn );
void balance( DBClientBase& conn );
void balance( DBClientBase& conn , const string& ns , const BSONObj /**
& data ); * @return true if everything is ok
*/
bool checkOIDs();
/**
* @return number of collections balanced
*/
int balance( DBClientBase& conn );
bool balance( DBClientBase& conn , const string& ns , const BSONObj
& data );
void ping(); void ping();
void ping( DBClientBase& conn ); void ping( DBClientBase& conn );
BSONObj pickChunk( vector<BSONObj>& from, vector<BSONObj>& to ); BSONObj pickChunk( vector<BSONObj>& from, vector<BSONObj>& to );
string _myid; string _myid;
time_t _started; time_t _started;
int _balancedLastTime;
}; };
extern Balancer balancer; extern Balancer balancer;
} }
 End of changes. 3 change blocks. 
3 lines changed or deleted 14 lines changed or added


 bson.h   bson.h 
/* NOTE: This file is not quite ready to use yet. Work in progress. /* NOTE: Standalone bson header for when not using MongoDB.
include ../db/jsobj.h for now. See also: bsondemo.
This file, however, pulls in much less code. MongoDB includes ../db/jsobj.h instead. This file, however, pulls in muc h less code / dependencies.
*/ */
/** @file bson.h /** @file bson.h
BSON classes BSON classes
*/ */
/* /*
* Copyright 2009 10gen Inc. * Copyright 2009 10gen Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
skipping to change at line 40 skipping to change at line 40
"BSON" stands for "binary JSON" -- ie a binary way to represent objects that would be "BSON" stands for "binary JSON" -- ie a binary way to represent objects that would be
represented in JSON (plus a few extensions useful for databases & other languages). represented in JSON (plus a few extensions useful for databases & other languages).
http://www.bsonspec.org/ http://www.bsonspec.org/
*/ */
#pragma once #pragma once
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <boost/utility.hpp>
namespace bson { namespace bson {
class assertion : public std::exception { class assertion : public std::exception {
public: public:
virtual const char* what() const throw() { return "BsonAssertion"; } virtual const char* what() const throw() { return "BsonAssertion"; }
}; };
} }
namespace mongo { namespace mongo {
#if !defined(assert) #if !defined(assert)
skipping to change at line 62 skipping to change at line 63
std::cout << "assertion failure in bson library" << std::endl; std::cout << "assertion failure in bson library" << std::endl;
throw bson::assertion(); throw bson::assertion();
} }
} }
#endif #endif
#if !defined(uassert) #if !defined(uassert)
inline void uassert(unsigned msgid, std::string msg, bool expr) { inline void uassert(unsigned msgid, std::string msg, bool expr) {
if( !expr ) if( !expr )
throw bson::assertion(); throw bson::assertion();
} }
inline void msgasserted(int msgid, const char *msg) {
throw bson::assertion();
}
inline void massert(unsigned msgid, std::string msg, bool expr) { inline void massert(unsigned msgid, std::string msg, bool expr) {
if(!expr) { if(!expr) {
std::cout << "assertion failure in bson library: " << msgid << ' ' << msg << std::endl; std::cout << "assertion failure in bson library: " << msgid << ' ' << msg << std::endl;
throw bson::assertion(); throw bson::assertion();
} }
} }
#endif #endif
} }
#include "../bson/bsontypes.h" #include "../bson/bsontypes.h"
 End of changes. 4 change blocks. 
3 lines changed or deleted 7 lines changed or added


 bsonelement.h   bsonelement.h 
skipping to change at line 343 skipping to change at line 343
} }
bool operator<( const BSONElement& other ) const { bool operator<( const BSONElement& other ) const {
int x = (int)canonicalType() - (int)other.canonicalType(); int x = (int)canonicalType() - (int)other.canonicalType();
if ( x < 0 ) return true; if ( x < 0 ) return true;
else if ( x > 0 ) return false; else if ( x > 0 ) return false;
return compareElementValues(*this,other) < 0; return compareElementValues(*this,other) < 0;
} }
// If maxLen is specified, don't scan more than maxLen bytes. // If maxLen is specified, don't scan more than maxLen bytes.
BSONElement(const char *d, int maxLen = -1) : data(d) { explicit BSONElement(const char *d, int maxLen = -1) : data(d) {
fieldNameSize_ = -1; fieldNameSize_ = -1;
if ( eoo() ) if ( eoo() )
fieldNameSize_ = 0; fieldNameSize_ = 0;
else { else {
if ( maxLen != -1 ) { if ( maxLen != -1 ) {
int size = (int) strnlen( fieldName(), maxLen - 1 ); int size = (int) strnlen( fieldName(), maxLen - 1 );
massert( 10333 , "Invalid field name", size != -1 ); massert( 10333 , "Invalid field name", size != -1 );
fieldNameSize_ = size + 1; fieldNameSize_ = size + 1;
} }
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 bsoninlines.h   bsoninlines.h 
skipping to change at line 25 skipping to change at line 25
* 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"
namespace mongo { namespace mongo {
inline BSONObjIterator BSONObj::begin() {
return BSONObjIterator(*this);
}
inline BSONObj BSONElement::embeddedObjectUserCheck() const { inline BSONObj BSONElement::embeddedObjectUserCheck() const {
uassert( 10065 , "invalid parameter: expected an object", isABSONO bj() ); uassert( 10065 , "invalid parameter: expected an object", isABSONO bj() );
return BSONObj(value()); return BSONObj(value());
} }
inline BSONObj BSONElement::embeddedObject() const { inline BSONObj BSONElement::embeddedObject() const {
assert( isABSONObj() ); assert( isABSONObj() );
return BSONObj(value()); return BSONObj(value());
} }
 End of changes. 1 change blocks. 
0 lines changed or deleted 4 lines changed or added


 bsonmisc.h   bsonmisc.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 <boost/utility.hpp>
namespace mongo { namespace mongo {
int getGtLtOp(const BSONElement& e); int getGtLtOp(const BSONElement& e);
struct BSONElementCmpWithoutField { struct BSONElementCmpWithoutField {
bool operator()( const BSONElement &l, const BSONElement &r ) const { bool operator()( const BSONElement &l, const BSONElement &r ) const {
return l.woCompare( r, false ) < 0; return l.woCompare( r, false ) < 0;
} }
}; };
 End of changes. 1 change blocks. 
2 lines changed or deleted 0 lines changed or added


 bsonobj.h   bsonobj.h 
skipping to change at line 304 skipping to change at line 304
/** Return new object with the field names replaced by those in the /** Return new object with the field names replaced by those in the
passed object. */ passed object. */
BSONObj replaceFieldNames( const BSONObj &obj ) const; BSONObj replaceFieldNames( const BSONObj &obj ) const;
/** true unless corrupt */ /** true unless corrupt */
bool valid() const; bool valid() const;
/** @return an md5 value for this object. */ /** @return an md5 value for this object. */
string md5() const; string md5() const;
bool operator==( const BSONObj& other ){ bool operator==( const BSONObj& other ) const{
return woCompare( other ) == 0; return woCompare( other ) == 0;
} }
enum MatchType { enum MatchType {
Equality = 0, Equality = 0,
LT = 0x1, LT = 0x1,
LTE = 0x3, LTE = 0x3,
GTE = 0x6, GTE = 0x6,
GT = 0x4, GT = 0x4,
opIN = 0x8, // { x : { $in : [1,2,3] } } opIN = 0x8, // { x : { $in : [1,2,3] } }
skipping to change at line 349 skipping to change at line 349
template <class T> template <class T>
void Vals(list<T> &) const; void Vals(list<T> &) const;
/** add all values of the object to the specified vector. If type mismatches, skip. */ /** add all values of the object to the specified vector. If type mismatches, skip. */
template <class T> template <class T>
void vals(vector<T> &) const; void vals(vector<T> &) const;
/** add all values of the object to the specified list. If type mi smatches, skip. */ /** add all values of the object to the specified list. If type mi smatches, skip. */
template <class T> template <class T>
void vals(list<T> &) const; void vals(list<T> &) const;
private:
friend class BSONObjIterator; friend class BSONObjIterator;
typedef BSONObjIterator iterator;
BSONObjIterator begin();
private:
class Holder { class Holder {
public: public:
Holder( const char *objdata ) : Holder( const char *objdata ) :
_objdata( objdata ) { _objdata( objdata ) {
} }
~Holder() { ~Holder() {
free((void *)_objdata); free((void *)_objdata);
_objdata = 0; _objdata = 0;
} }
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; stringstream ss;
ss << "Invalid BSONObj spec size: " << objsize(); ss << "Invalid BSONObj spec size: " << objsize() << " (" << hex << objsize() << dec << ")";
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 );
} }
} }
/*
#pragma pack(1)
static struct EmptyObject {
EmptyObject() {
len = 5;
jstype = EOO;
}
int len;
char jstype;
} emptyObject;
#pragma pack()
*/
}; };
ostream& operator<<( ostream &s, const BSONObj &o ); ostream& operator<<( ostream &s, const BSONObj &o );
ostream& operator<<( ostream &s, const BSONElement &e ); ostream& operator<<( ostream &s, const BSONElement &e );
struct BSONArray : BSONObj { struct BSONArray : BSONObj {
// Don't add anything other than forwarding constructors!!! // Don't add anything other than forwarding constructors!!!
BSONArray(): BSONObj() {} BSONArray(): BSONObj() {}
explicit BSONArray(const BSONObj& obj): BSONObj(obj) {} explicit BSONArray(const BSONObj& obj): BSONObj(obj) {}
}; };
 End of changes. 5 change blocks. 
15 lines changed or deleted 6 lines changed or added


 bsonobjbuilder.h   bsonobjbuilder.h 
skipping to change at line 26 skipping to change at line 26
* 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 <limits> #include <limits>
#include <cmath>
using namespace std;
namespace mongo { namespace mongo {
#if defined(_WIN32) #if defined(_WIN32)
// warning: 'this' : used in base member initializer list // warning: 'this' : used in base member initializer list
#pragma warning( disable : 4355 ) #pragma warning( disable : 4355 )
#endif #endif
/** Utility for creating a BSONObj. /** Utility for creating a BSONObj.
See also the BSON() and BSON_ARRAY() macros. See also the BSON() and BSON_ARRAY() macros.
skipping to change at line 102 skipping to change at line 104
the subobject's body */ the subobject's body */
BufBuilder &subobjStart(const char *fieldName) { BufBuilder &subobjStart(const char *fieldName) {
_b.append((char) Object); _b.append((char) Object);
_b.append(fieldName); _b.append(fieldName);
return _b; return _b;
} }
/** 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.
*/ */
BSONObjBuilder& appendArray(const char *fieldName, BSONObj subObj) { BSONObjBuilder& appendArray(const char *fieldName, const BSONObj &s ubObj) {
_b.append((char) Array); _b.append((char) Array);
_b.append(fieldName); _b.append(fieldName);
_b.append((void *) subObj.objdata(), subObj.objsize()); _b.append((void *) subObj.objdata(), subObj.objsize());
return *this; return *this;
} }
BSONObjBuilder& append(const char *fieldName, BSONArray arr) { BSONObjBuilder& append(const char *fieldName, BSONArray arr) {
return appendArray(fieldName, arr); return appendArray(fieldName, arr);
} }
/** add header for a new subarray and return bufbuilder for writing to /** add header for a new subarray and return bufbuilder for writing to
skipping to change at line 441 skipping to change at line 443
} }
/** /**
these are the min/max when comparing, not strict min/max element s for a given type these are the min/max when comparing, not strict min/max element s for a given type
*/ */
void appendMinForType( const string& field , int type ); void appendMinForType( const string& field , int type );
void appendMaxForType( const string& field , int type ); void appendMaxForType( const string& field , int type );
/** Append an array of values. */ /** Append an array of values. */
template < class T > template < class T >
BSONObjBuilder& append( const char *fieldName, const vector< T >& v BSONObjBuilder& append( const char *fieldName, const vector< T >& v
als ) { als );
BSONObjBuilder arrBuilder;
for ( unsigned int i = 0; i < vals.size(); ++i )
arrBuilder.append( numStr( i ).c_str(), vals[ i ] );
marshalArray( fieldName, arrBuilder.done() );
return *this;
}
/* Append an array of ints template < class T >
void appendArray( const char *fieldName, const vector< int >& va BSONObjBuilder& append( const char *fieldName, const list< T >& val
ls ) { s );
BSONObjBuilder arrBuilder;
for ( unsigned i = 0; i < vals.size(); ++i )
arrBuilder.append( numStr( i ).c_str(), vals[ i ] );
marshalArray( fieldName, arrBuilder.done() );
}*/
/** The returned BSONObj will free the buffer when it is finished. */ /** The returned BSONObj will free the buffer when it is finished. */
BSONObj obj() { BSONObj obj() {
bool own = owned(); bool own = owned();
massert( 10335 , "builder does not own memory", own ); massert( 10335 , "builder does not own memory", own );
int l; int l;
return BSONObj(decouple(l), true); return BSONObj(decouple(l), true);
} }
/** Fetch the object we have built. /** Fetch the object we have built.
skipping to change at line 539 skipping to change at line 529
massert( 10336 , "No subobject started", _s.subobjStarted() ); massert( 10336 , "No subobject started", _s.subobjStarted() );
return _s << l; return _s << l;
} }
/** @return true if we are using our own bufbuilder, and not an alt ernate that was given to us in our constructor */ /** @return true if we are using our own bufbuilder, and not an alt ernate that was given to us in our constructor */
bool owned() const { return &_b == &_buf; } bool owned() const { return &_b == &_buf; }
BSONObjIterator iterator() const ; BSONObjIterator iterator() const ;
private: private:
// Append the provided arr object as an array.
void marshalArray( const char *fieldName, const BSONObj &arr ) {
_b.append( (char) Array );
_b.append( fieldName );
_b.append( (void *) arr.objdata(), arr.objsize() );
}
char* _done() { char* _done() {
_s.endField(); _s.endField();
_b.append((char) EOO); _b.append((char) EOO);
char *data = _b.buf() + _offset; char *data = _b.buf() + _offset;
int size = _b.len() - _offset; int size = _b.len() - _offset;
*((int*)data) = size; *((int*)data) = size;
if ( _tracker ) if ( _tracker )
_tracker->got( size ); _tracker->got( size );
return data; return data;
} }
skipping to change at line 602 skipping to change at line 585
BSONObj done() { return _b.done(); } BSONObj done() { return _b.done(); }
template <typename T> template <typename T>
BSONArrayBuilder& append(const char *name, const T& x){ BSONArrayBuilder& append(const char *name, const T& x){
fill( name ); fill( name );
append( x ); append( x );
return *this; return *this;
} }
BufBuilder &subobjStart( const char *name ) { BufBuilder &subobjStart( const char *name = "0" ) {
fill( name ); fill( name );
return _b.subobjStart( num().c_str() ); return _b.subobjStart( num().c_str() );
} }
BufBuilder &subarrayStart( const char *name ) { BufBuilder &subarrayStart( const char *name ) {
fill( name ); fill( name );
return _b.subarrayStart( num().c_str() ); return _b.subarrayStart( num().c_str() );
} }
void appendArray( const char *name, BSONObj subObj ) { void appendArray( const char *name, BSONObj subObj ) {
skipping to change at line 647 skipping to change at line 630
BSONObjBuilder _b; BSONObjBuilder _b;
_b.appendNull( "" ); _b.appendNull( "" );
return _b.obj(); return _b.obj();
} }
string num(){ return _b.numStr(_i++); } string num(){ return _b.numStr(_i++); }
int _i; int _i;
BSONObjBuilder _b; BSONObjBuilder _b;
}; };
template < class T >
inline BSONObjBuilder& BSONObjBuilder::append( const char *fieldName, c
onst vector< T >& vals ) {
BSONObjBuilder arrBuilder;
for ( unsigned int i = 0; i < vals.size(); ++i )
arrBuilder.append( numStr( i ).c_str(), vals[ i ] );
appendArray( fieldName, arrBuilder.done() );
return *this;
}
template < class T >
inline BSONObjBuilder& BSONObjBuilder::append( const char *fieldName, c
onst list< T >& vals ) {
BSONObjBuilder arrBuilder;
int n = 0;
for( typename list< T >::const_iterator i = vals.begin(); i != vals
.end(); i++ )
arrBuilder.append( numStr(n++).c_str(), *i );
appendArray( fieldName, arrBuilder.done() );
return *this;
}
} }
 End of changes. 7 change blocks. 
25 lines changed or deleted 31 lines changed or added


 bsonobjiterator.h   bsonobjiterator.h 
skipping to change at line 63 skipping to change at line 63
bool more(){ bool more(){
return _pos < _theend && _pos[0]; return _pos < _theend && _pos[0];
} }
/** @return the next element in the object. For the final element, element.eoo() will be true. */ /** @return the next element in the object. For the final element, element.eoo() will be true. */
BSONElement next( bool checkEnd = false ) { BSONElement next( bool checkEnd = false ) {
assert( _pos < _theend ); assert( _pos < _theend );
BSONElement e( _pos, checkEnd ? (int)(_theend - _pos) : -1 ); BSONElement e( _pos, checkEnd ? (int)(_theend - _pos) : -1 );
_pos += e.size( checkEnd ? (int)(_theend - _pos) : -1 ); _pos += e.size( checkEnd ? (int)(_theend - _pos) : -1 );
return e; return e;
} }
void operator++() { next(); }
void operator++(int) { next(); }
BSONElement operator*() {
assert( _pos < _theend );
return BSONElement(_pos, -1);
}
private: private:
const char* _pos; const char* _pos;
const char* _theend; const char* _theend;
}; };
class BSONObjIteratorSorted { class BSONObjIteratorSorted {
public: public:
BSONObjIteratorSorted( const BSONObj& o ); BSONObjIteratorSorted( const BSONObj& o );
~BSONObjIteratorSorted(){ ~BSONObjIteratorSorted(){
 End of changes. 1 change blocks. 
0 lines changed or deleted 9 lines changed or added


 btree.h   btree.h 
skipping to change at line 190 skipping to change at line 187
int n; // # of keys so far. int n; // # of keys so far.
int reserved; int reserved;
const _KeyNode& k(int i) const { const _KeyNode& k(int i) const {
return ((_KeyNode*)data)[i]; return ((_KeyNode*)data)[i];
} }
_KeyNode& k(int i) { _KeyNode& k(int i) {
return ((_KeyNode*)data)[i]; return ((_KeyNode*)data)[i];
} }
char data[4]; char data[4];
}; };
#pragma pack()
#pragma pack(1)
class BtreeBucket : public BucketBasics { class BtreeBucket : public BucketBasics {
friend class BtreeCursor; friend class BtreeCursor;
public: public:
void dump(); void dump();
/* @return true if key exists in index /* @return true if key exists in index
order - indicates order of keys in the index. this is basically the index's key pattern, e.g.: order - indicates order of keys in the index. this is basically the index's key pattern, e.g.:
BSONObj order = ((IndexDetails&)idx).keyPattern(); BSONObj order = ((IndexDetails&)idx).keyPattern();
likewise below in bt_insert() etc. likewise below in bt_insert() etc.
skipping to change at line 265 skipping to change at line 264
DiskLoc lchild, DiskLoc rchild, IndexDetails&); DiskLoc lchild, DiskLoc rchild, IndexDetails&);
int _insert(DiskLoc thisLoc, DiskLoc recordLoc, int _insert(DiskLoc thisLoc, DiskLoc recordLoc,
const BSONObj& key, const Ordering &order, bool dupsAll owed, const BSONObj& key, const Ordering &order, bool dupsAll owed,
DiskLoc lChild, DiskLoc rChild, IndexDetails&); DiskLoc lChild, DiskLoc rChild, IndexDetails&);
bool find(const IndexDetails& idx, const BSONObj& key, DiskLoc reco rdLoc, const Ordering &order, int& pos, bool assertIfDup); bool find(const IndexDetails& idx, const BSONObj& key, DiskLoc reco rdLoc, const Ordering &order, int& pos, bool assertIfDup);
static void findLargestKey(const DiskLoc& thisLoc, DiskLoc& largest Loc, int& largestKey); static void findLargestKey(const DiskLoc& thisLoc, DiskLoc& largest Loc, int& largestKey);
public: public:
// simply builds and returns a dup key error message string // simply builds and returns a dup key error message string
static string dupKeyError( const IndexDetails& idx , const BSONObj& key ); static string dupKeyError( const IndexDetails& idx , const BSONObj& key );
}; };
#pragma pack()
class BtreeCursor : public Cursor { class BtreeCursor : public Cursor {
public: public:
BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int direction ); BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int direction );
BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails& _id, const BoundList &_bounds, int _direction ); BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails& _id, const BoundList &_bounds, int _direction );
~BtreeCursor(){
}
virtual bool ok() { virtual bool ok() {
return !bucket.isNull(); return !bucket.isNull();
} }
bool eof() { bool eof() {
return !ok(); return !ok();
} }
virtual bool advance(); virtual bool advance();
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; }
/* 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
*/ */
set<DiskLoc> dups;
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);
return !p.second; return !p.second;
} }
return false; return false;
} }
_KeyNode& _currKeyNode() { _KeyNode& _currKeyNode() {
assert( !bucket.isNull() ); assert( !bucket.isNull() );
skipping to change at line 345 skipping to change at line 345
string s = string("BtreeCursor ") + indexDetails.indexName(); string s = string("BtreeCursor ") + indexDetails.indexName();
if ( direction < 0 ) s += " reverse"; if ( direction < 0 ) s += " reverse";
if ( bounds_.size() > 1 ) s += " multi"; if ( bounds_.size() > 1 ) s += " multi";
return s; return s;
} }
BSONObj prettyKey( const BSONObj &key ) const { BSONObj prettyKey( const BSONObj &key ) const {
return key.replaceFieldNames( indexDetails.keyPattern() ).clien tReadable(); return key.replaceFieldNames( indexDetails.keyPattern() ).clien tReadable();
} }
virtual BSONObj prettyIndexBounds() const { virtual BSONArray prettyIndexBounds() const {
BSONArrayBuilder ba; BSONArrayBuilder ba;
if ( bounds_.size() == 0 ) { if ( bounds_.size() == 0 ) {
ba << BSON_ARRAY( prettyKey( startKey ) << prettyKey( endKe y ) ); ba << BSON_ARRAY( prettyKey( startKey ) << prettyKey( endKe y ) );
} else { } else {
for( BoundList::const_iterator i = bounds_.begin(); i != bo unds_.end(); ++i ) { for( BoundList::const_iterator i = bounds_.begin(); i != bo unds_.end(); ++i ) {
ba << BSON_ARRAY( prettyKey( i->first ) << prettyKey( i ->second ) ); ba << BSON_ARRAY( prettyKey( i->first ) << prettyKey( i ->second ) );
} }
} }
return ba.arr(); return ba.arr();
} }
void forgetEndKey() { endKey = BSONObj(); } void forgetEndKey() { endKey = BSONObj(); }
virtual CoveredIndexMatcher *matcher() const { return _matcher.get(
); }
virtual void setMatcher( auto_ptr< CoveredIndexMatcher > matcher )
{
_matcher = matcher;
}
private: private:
/* Our btrees may (rarely) have "unused" keys when items are delete d. /* Our btrees may (rarely) have "unused" keys when items are delete d.
Skip past them. Skip past them.
*/ */
void skipUnusedKeys(); void skipUnusedKeys();
/* Check if the current key is beyond endKey. */ /* Check if the current key is beyond endKey. */
void checkEnd(); void checkEnd();
// selective audits on construction // selective audits on construction
void audit(); void audit();
// set initial bucket // set initial bucket
void init(); void init();
// init start / end keys with a new range // init start / end keys with a new range
void initInterval(); void initInterval();
friend class BtreeBucket; friend class BtreeBucket;
set<DiskLoc> dups;
NamespaceDetails *d; NamespaceDetails *d;
int idxNo; int idxNo;
BSONObj startKey; BSONObj startKey;
BSONObj endKey; BSONObj endKey;
bool endKeyInclusive_; bool endKeyInclusive_;
bool multikey; // note this must be updated every getmore batch in case someone added a multikey... bool multikey; // note this must be updated every getmore batch in case someone added a multikey...
const IndexDetails& indexDetails; const IndexDetails& indexDetails;
BSONObj order; BSONObj order;
DiskLoc bucket; DiskLoc bucket;
int keyOfs; int keyOfs;
int direction; // 1=fwd,-1=reverse int direction; // 1=fwd,-1=reverse
BSONObj keyAtKeyOfs; // so we can tell if things moved around on us between the query and the getMore call BSONObj keyAtKeyOfs; // so we can tell if things moved around on us between the query and the getMore call
DiskLoc locAtKeyOfs; DiskLoc locAtKeyOfs;
BoundList bounds_; BoundList bounds_;
unsigned boundIndex_; unsigned boundIndex_;
const IndexSpec& _spec; const IndexSpec& _spec;
auto_ptr< CoveredIndexMatcher > _matcher;
}; };
#pragma pack()
inline bool IndexDetails::hasKey(const BSONObj& key) { inline bool IndexDetails::hasKey(const BSONObj& key) {
return head.btree()->exists(*this, head, key, Ordering::make(keyPat tern())); return head.btree()->exists(*this, head, key, Ordering::make(keyPat tern()));
} }
inline bool IndexDetails::wouldCreateDup(const BSONObj& key, DiskLoc se lf) { inline bool IndexDetails::wouldCreateDup(const BSONObj& key, DiskLoc se lf) {
return head.btree()->wouldCreateDup(*this, head, key, Ordering::mak e(keyPattern()), self); return head.btree()->wouldCreateDup(*this, head, key, Ordering::mak e(keyPattern()), self);
} }
/* build btree from the bottom up */ /* build btree from the bottom up */
/* _ TODO dropDups */ /* _ TODO dropDups */
class BtreeBuilder { class BtreeBuilder {
 End of changes. 10 change blocks. 
5 lines changed or deleted 16 lines changed or added


 builder.h   builder.h 
skipping to change at line 29 skipping to change at line 29
#include <string> #include <string>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
namespace mongo { namespace mongo {
class StringBuilder; class StringBuilder;
void msgasserted(int msgid, const char *msg);
class BufBuilder { class BufBuilder {
public: public:
BufBuilder(int initsize = 512) : size(initsize) { BufBuilder(int initsize = 512) : size(initsize) {
if ( size > 0 ) { if ( size > 0 ) {
data = (char *) malloc(size); data = (char *) malloc(size);
assert(data != 0); if( data == 0 )
msgasserted(10000, "out of memory BufBuilder");
} else { } else {
data = 0; data = 0;
} }
l = 0; l = 0;
} }
~BufBuilder() { ~BufBuilder() {
kill(); kill();
} }
void kill() { void kill() {
skipping to change at line 62 skipping to change at line 65
l = 0; l = 0;
if ( maxSize && size > maxSize ){ if ( maxSize && size > maxSize ){
free(data); free(data);
data = (char*)malloc(maxSize); data = (char*)malloc(maxSize);
size = maxSize; size = maxSize;
} }
} }
/* leave room for some stuff later */ /* leave room for some stuff later */
void skip(int n) { char* skip(int n) { return grow(n); }
grow(n);
}
/* note this may be deallocated (realloced) if you keep writing. */ /* note this may be deallocated (realloced) if you keep writing. */
char* buf() { char* buf() { return data; }
return data; const char* buf() const { return data; }
}
/* assume ownership of the buffer - you must then free it */ /* assume ownership of the buffer - you must then free it */
void decouple() { void decouple() {
data = 0; data = 0;
} }
template<class T> void append(T j) { template<class T> void append(T j) {
*((T*)grow(sizeof(T))) = j; *((T*)grow(sizeof(T))) = j;
} }
void append(short j) { void append(short j) {
skipping to change at line 115 skipping to change at line 115
} }
int len() const { int len() const {
return l; return l;
} }
void setlen( int newLen ){ void setlen( int newLen ){
l = newLen; l = newLen;
} }
private:
/* returns the pre-grow write position */ /* returns the pre-grow write position */
char* grow(int by) { char* grow(int by) {
int oldlen = l; int oldlen = l;
l += by; l += by;
if ( l > size ) { if ( l > size ) {
int a = size * 2; int a = size * 2;
if ( a == 0 ) if ( a == 0 )
a = 512; a = 512;
if ( l > a ) if ( l > a )
a = l + 16 * 1024; a = l + 16 * 1024;
assert( a < 64 * 1024 * 1024 ); if( a > 64 * 1024 * 1024 )
msgasserted(10000, "BufBuilder grow() > 64MB");
data = (char *) realloc(data, a); data = (char *) realloc(data, a);
size= a; size= a;
} }
return data + oldlen; return data + oldlen;
} }
private:
char *data; char *data;
int l; int l;
int size; int size;
friend class StringBuilder; friend class StringBuilder;
}; };
#if defined(_WIN32) #if defined(_WIN32)
#pragma warning( disable : 4996 ) #pragma warning( disable : 4996 )
#endif #endif
 End of changes. 7 change blocks. 
9 lines changed or deleted 10 lines changed or added


 chunk.h   chunk.h 
skipping to change at line 32 skipping to change at line 32
*/ */
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "../client/dbclient.h" #include "../client/dbclient.h"
#include "../client/model.h" #include "../client/model.h"
#include "../bson/util/atomic_int.h" #include "../bson/util/atomic_int.h"
#include "shardkey.h" #include "shardkey.h"
#include "shard.h" #include "shard.h"
#include "config.h"
namespace mongo { namespace mongo {
class DBConfig; class DBConfig;
class Chunk;
class ChunkRange;
class ChunkManager; class ChunkManager;
class ChunkRangeMangager;
class ChunkObjUnitTest; class ChunkObjUnitTest;
typedef unsigned long long ShardChunkVersion; typedef unsigned long long ShardChunkVersion;
typedef shared_ptr<Chunk> ChunkPtr;
// key is max for each Chunk or ChunkRange
typedef map<BSONObj,ChunkPtr,BSONObjCmp> ChunkMap;
typedef map<BSONObj,shared_ptr<ChunkRange>,BSONObjCmp> ChunkRangeMap;
/** /**
config.chunks config.chunks
{ ns : "alleyinsider.fs.chunks" , min : {} , max : {} , server : "lo calhost:30001" } { ns : "alleyinsider.fs.chunks" , min : {} , max : {} , server : "lo calhost:30001" }
x is in a shard iff x is in a shard iff
min <= x < max min <= x < max
*/ */
class Chunk : public Model , boost::noncopyable { class Chunk : public Model , boost::noncopyable {
public: public:
skipping to change at line 83 skipping to change at line 92
bool operator==(const Chunk& s) const; bool operator==(const Chunk& s) const;
bool operator!=(const Chunk& s) const{ bool operator!=(const Chunk& s) const{
return ! ( *this == s ); return ! ( *this == s );
} }
void getFilter( BSONObjBuilder& b ) const; void getFilter( BSONObjBuilder& b ) const;
BSONObj getFilter() const{ BSONObjBuilder b; getFilter( b ); return b.obj(); } BSONObj getFilter() const{ BSONObjBuilder b; getFilter( b ); return b.obj(); }
// if min/max key is pos/neg infinity
bool minIsInf() const;
bool maxIsInf() const;
BSONObj pickSplitPoint() const; BSONObj pickSplitPoint() const;
Chunk * split(); ChunkPtr split();
Chunk * split( const BSONObj& middle ); ChunkPtr split( const BSONObj& middle );
/** /**
* @return size of shard in bytes * @return size of shard in bytes
* talks to mongod to do this * talks to mongod to do this
*/ */
long getPhysicalSize() const; long getPhysicalSize() const;
long countObjects( const BSONObj& filter = BSONObj() ) const; long countObjects( const BSONObj& filter = BSONObj() ) const;
/** /**
* if the amount of data written nears the max size of a shard * if the amount of data written nears the max size of a shard
* then we check the real size, and if its too big, we split * then we check the real size, and if its too big, we split
*/ */
bool splitIfShould( long dataWritten ); bool splitIfShould( long dataWritten );
/* /*
* moves either this shard or newShard if it makes sense too * moves either this shard or newShard if it makes sense too
* @return whether or not a shard was moved * @return whether or not a shard was moved
*/ */
bool moveIfShould( Chunk * newShard = 0 ); bool moveIfShould( ChunkPtr newShard = ChunkPtr() );
bool moveAndCommit( const Shard& to , string& errmsg ); bool moveAndCommit( const Shard& to , string& errmsg );
virtual const char * getNS(){ return "config.chunks"; } virtual const char * getNS(){ return "config.chunks"; }
virtual void serialize(BSONObjBuilder& to); virtual void serialize(BSONObjBuilder& to);
virtual void unserialize(const BSONObj& from); virtual void unserialize(const BSONObj& from);
virtual string modelServer(); virtual string modelServer();
void appendShortVersion( const char * name , BSONObjBuilder& b ); void appendShortVersion( const char * name , BSONObjBuilder& b );
virtual void save( bool check=false ); virtual void save( bool check=false );
void ensureIndex(); void ensureIndex();
void _markModified(); void _markModified();
static int MaxChunkSize; static int MaxChunkSize;
static string genID( const string& ns , const BSONObj& min ); static string genID( const string& ns , const BSONObj& min );
const ChunkManager* getManager() const { return _manager; }
private: private:
// main shard info // main shard info
ChunkManager * _manager; ChunkManager * _manager;
ShardKeyPattern skey() const; ShardKeyPattern skey() const;
string _ns; string _ns;
BSONObj _min; BSONObj _min;
BSONObj _max; BSONObj _max;
Shard _shard; Shard _shard;
ShardChunkVersion _lastmod; ShardChunkVersion _lastmod;
bool _modified; bool _modified;
// transient stuff // transient stuff
long _dataWritten; long _dataWritten;
ChunkPtr _this;
// methods, etc.. // methods, etc..
void _split( BSONObj& middle ); void _split( BSONObj& middle );
friend class ChunkManager; friend class ChunkManager;
friend class ShardObjUnitTest; friend class ShardObjUnitTest;
}; };
class ChunkRange{
public:
const ChunkManager* getManager() const{ return _manager; }
Shard getShard() const{ return _shard; }
const BSONObj& getMin() const { return _min; }
const BSONObj& getMax() const { return _max; }
// clones of Chunk methods
bool contains(const BSONObj& obj) const;
void getFilter( BSONObjBuilder& b ) const;
BSONObj getFilter() const{ BSONObjBuilder b; getFilter( b ); return
b.obj(); }
long countObjects( const BSONObj& filter = BSONObj() ) const;
ChunkRange(ChunkMap::const_iterator begin, const ChunkMap::const_it
erator end)
: _manager(begin->second->getManager())
, _shard(begin->second->getShard())
, _min(begin->second->getMin())
, _max(prior(end)->second->getMax())
{
assert( begin != end );
DEV while (begin != end){
assert(begin->second->getManager() == _manager);
assert(begin->second->getShard() == _shard);
++begin;
}
}
// Merge min and max (must be adjacent ranges)
ChunkRange(const ChunkRange& min, const ChunkRange& max)
: _manager(min.getManager())
, _shard(min.getShard())
, _min(min.getMin())
, _max(max.getMax())
{
assert(min.getShard() == max.getShard());
assert(min.getManager() == max.getManager());
assert(min.getMax() == max.getMin());
}
friend ostream& operator<<(ostream& out, const ChunkRange& cr){
return (out << "ChunkRange(min=" << cr._min << ", max=" << cr._
max << ", shard=" << cr._shard <<")");
}
private:
const ChunkManager* _manager;
const Shard _shard;
const BSONObj _min;
const BSONObj _max;
};
class ChunkRangeManager {
public:
const ChunkRangeMap& ranges() const { return _ranges; }
void clear() { _ranges.clear(); }
void reloadAll(const ChunkMap& chunks);
void reloadRange(const ChunkMap& chunks, const BSONObj& min, const
BSONObj& max);
// Slow operation -- wrap with DEV
void assertValid() const;
ChunkRangeMap::const_iterator upper_bound(const BSONObj& o) const {
return _ranges.upper_bound(o); }
ChunkRangeMap::const_iterator lower_bound(const BSONObj& o) const {
return _ranges.lower_bound(o); }
private:
// assumes nothing in this range exists in _ranges
void _insertRange(ChunkMap::const_iterator begin, const ChunkMap::c
onst_iterator end);
ChunkRangeMap _ranges;
};
/* config.sharding /* config.sharding
{ ns: 'alleyinsider.fs.chunks' , { ns: 'alleyinsider.fs.chunks' ,
key: { ts : 1 } , key: { ts : 1 } ,
shards: [ { min: 1, max: 100, server: a } , { min: 101, max: 200 , server : b } ] shards: [ { min: 1, max: 100, server: a } , { min: 101, max: 200 , server : b } ]
} }
*/ */
class ChunkManager { class ChunkManager {
public: public:
ChunkManager( DBConfig * config , string ns , ShardKeyPattern patte rn , bool unique ); ChunkManager( DBConfig * config , string ns , ShardKeyPattern patte rn , bool unique );
virtual ~ChunkManager(); virtual ~ChunkManager();
string getns(){ string getns() const {
return _ns; return _ns;
} }
int numChunks(){ rwlock lk( _lock , false ); return _chunks.size(); } int numChunks(){ rwlock lk( _lock , false ); return _chunks.size(); }
Chunk* getChunk( int i ){ rwlock lk( _lock , false ); return _chunk s[i]; } ChunkPtr getChunk( int i ){ rwlock lk( _lock , false ); return _chu nks[i]; }
bool hasShardKey( const BSONObj& obj ); bool hasShardKey( const BSONObj& obj );
Chunk& findChunk( const BSONObj& obj , bool retry = false ); ChunkPtr findChunk( const BSONObj& obj , bool retry = false );
Chunk* findChunkOnServer( const Shard& shard ) const; ChunkPtr findChunkOnServer( const Shard& shard ) const;
ShardKeyPattern& getShardKey(){ return _key; } ShardKeyPattern& getShardKey(){ return _key; }
const ShardKeyPattern& getShardKey() const { return _key; }
bool isUnique(){ return _unique; } bool isUnique(){ return _unique; }
/** /**
* makes sure the shard index is on all servers * makes sure the shard index is on all servers
*/ */
void ensureIndex(); void ensureIndex();
/** /**
* @return number of Chunk added to the vector * @return number of Chunk added to the vector
*/ */
int getChunksForQuery( vector<Chunk*>& chunks , const BSONObj& quer y ); int getChunksForQuery( vector<shared_ptr<ChunkRange> >& chunks , co nst BSONObj& query );
/** /**
* @return number of Shards added to the set * @return number of Shards added to the set
*/ */
int getShardsForQuery( set<Shard>& shards , const BSONObj& query ); int getShardsForQuery( set<Shard>& shards , const BSONObj& query );
void getAllShards( set<Shard>& all ); void getAllShards( set<Shard>& all );
void save(); void save();
skipping to change at line 211 skipping to change at line 303
ShardChunkVersion getVersion( const Shard& shard ) const; ShardChunkVersion getVersion( const Shard& shard ) const;
ShardChunkVersion getVersion() const; ShardChunkVersion getVersion() const;
/** /**
* this is just an increasing number of how many ChunkManagers we h ave so we know if something has been updated * this is just an increasing number of how many ChunkManagers we h ave so we know if something has been updated
*/ */
unsigned long long getSequenceNumber(){ unsigned long long getSequenceNumber(){
return _sequenceNumber; return _sequenceNumber;
} }
void drop(); /**
* @param me - so i don't get deleted before i'm done
*/
void drop( ChunkManagerPtr me );
private: private:
void _reload(); void _reload();
void _load(); void _load();
DBConfig * _config; DBConfig * _config;
string _ns; string _ns;
ShardKeyPattern _key; ShardKeyPattern _key;
bool _unique; bool _unique;
vector<Chunk*> _chunks; vector<ChunkPtr> _chunks;
map<string,unsigned long long> _maxMarkers; map<string,unsigned long long> _maxMarkers;
typedef map<BSONObj,Chunk*,BSONObjCmp> ChunkMap; ChunkMap _chunkMap;
ChunkMap _chunkMap; // max -> Chunk ChunkRangeManager _chunkRanges;
unsigned long long _sequenceNumber; unsigned long long _sequenceNumber;
RWLock _lock; RWLock _lock;
// This should only be called from Chunk after it has been migrated
void _migrationNotification(Chunk* c);
friend class Chunk; friend class Chunk;
friend class ChunkRangeManager; // only needed for CRM::assertValid ()
static AtomicUInt NextSequenceNumber; static AtomicUInt NextSequenceNumber;
bool _isValid() const;
void _printChunks() const;
/** /**
* @return number of Chunk matching the query or -1 for all chunks. * @return number of Chunk matching the query or -1 for all chunks.
*/ */
int _getChunksForQuery( vector<Chunk*>& chunks , const BSONObj& que ry ); int _getChunksForQuery( vector<shared_ptr<ChunkRange> >& chunks , c onst BSONObj& query );
}; };
// like BSONObjCmp. for use as an STL comparison functor // like BSONObjCmp. for use as an STL comparison functor
// key-order in "order" argument must match key-order in shardkey // key-order in "order" argument must match key-order in shardkey
class ChunkCmp { class ChunkCmp {
public: public:
ChunkCmp( const BSONObj &order = BSONObj() ) : _cmp( order ) {} ChunkCmp( const BSONObj &order = BSONObj() ) : _cmp( order ) {}
bool operator()( const Chunk &l, const Chunk &r ) const { bool operator()( const Chunk &l, const Chunk &r ) const {
return _cmp(l.getMin(), r.getMin()); return _cmp(l.getMin(), r.getMin());
} }
bool operator()( const ptr<Chunk> l, const ptr<Chunk> r ) const {
return operator()(*l, *r);
}
bool operator()( const Chunk *l, const Chunk *r ) const { // Also support ChunkRanges
bool operator()( const ChunkRange &l, const ChunkRange &r ) const {
return _cmp(l.getMin(), r.getMin());
}
bool operator()( const shared_ptr<ChunkRange> l, const shared_ptr<C
hunkRange> r ) const {
return operator()(*l, *r); return operator()(*l, *r);
} }
private: private:
BSONObjCmp _cmp; BSONObjCmp _cmp;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 24 change blocks. 
14 lines changed or deleted 131 lines changed or added


 client.h   client.h 
skipping to change at line 172 skipping to change at line 172
bool _shutdown; bool _shutdown;
list<string> _tempCollections; list<string> _tempCollections;
const char *_desc; const char *_desc;
bool _god; bool _god;
AuthenticationInfo _ai; AuthenticationInfo _ai;
OpTime _lastOp; OpTime _lastOp;
BSONObj _handshake; BSONObj _handshake;
BSONObj _remoteId; BSONObj _remoteId;
public: public:
string clientAddress() const;
AuthenticationInfo * getAuthenticationInfo(){ return &_ai; } AuthenticationInfo * getAuthenticationInfo(){ return &_ai; }
bool isAdmin() { return _ai.isAuthorized( "admin" ); } bool isAdmin() { return _ai.isAuthorized( "admin" ); }
CurOp* curop() { return _curOp; } CurOp* curop() { return _curOp; }
Context* getContext(){ return _context; } Context* getContext(){ return _context; }
Database* database() { return _context ? _context->db() : 0; } Database* database() { return _context ? _context->db() : 0; }
const char *ns() { return _context->ns(); } const char *ns() const { return _context->ns(); }
const char *desc() const { return _desc; }
Client(const char *desc); Client(const char *desc);
~Client(); ~Client();
const char *desc() const { return _desc; } void addTempCollection( const string& ns ) { _tempCollections.push_
back( ns ); }
void addTempCollection( const string& ns ){ void dropTempCollectionsInDB(const string db);
_tempCollections.push_back( ns ); void dropAllTempCollectionsInDB(const string db);
}
void setLastOp( const OpTime& op ){ void setLastOp( const OpTime& op ){
_lastOp = op; _lastOp = op;
} }
OpTime getLastOp() const { OpTime getLastOp() const {
return _lastOp; return _lastOp;
} }
void appendLastOp( BSONObjBuilder& b ){ void appendLastOp( BSONObjBuilder& b ){
skipping to change at line 235 skipping to change at line 232
}; };
inline Client& cc() { inline Client& cc() {
return *currentClient.get(); return *currentClient.get();
} }
/* each thread which does db operations has a Client object in TLS. /* each thread which does db operations has a Client object in TLS.
call this when your thread starts. call this when your thread starts.
*/ */
inline void Client::initThread(const char *desc) { inline void Client::initThread(const char *desc) {
setThreadName(desc);
assert( currentClient.get() == 0 ); assert( currentClient.get() == 0 );
currentClient.reset( new Client(desc) ); currentClient.reset( new Client(desc) );
mongo::lastError.initThread();
} }
inline Client::GodScope::GodScope(){ inline Client::GodScope::GodScope(){
_prev = cc()._god; _prev = cc()._god;
cc()._god = true; cc()._god = true;
} }
inline Client::GodScope::~GodScope(){ inline Client::GodScope::~GodScope(){
cc()._god = _prev; cc()._god = _prev;
} }
 End of changes. 7 change blocks. 
9 lines changed or deleted 9 lines changed or added


 clientcursor.h   clientcursor.h 
skipping to change at line 42 skipping to change at line 42
#include "diskloc.h" #include "diskloc.h"
#include "dbhelpers.h" #include "dbhelpers.h"
#include "matcher.h" #include "matcher.h"
#include "../client/dbclient.h" #include "../client/dbclient.h"
namespace mongo { namespace mongo {
typedef long long CursorId; /* passed to the client so it can send back on getMore */ typedef long long CursorId; /* passed to the client so it can send back on getMore */
class Cursor; /* internal server cursor base class */ class Cursor; /* internal server cursor base class */
class ClientCursor; class ClientCursor;
class ParsedQuery;
/* todo: make this map be per connection. this will prevent cursor hij acking security attacks perhaps. /* todo: make this map be per connection. this will prevent cursor hij acking security attacks perhaps.
*/ */
typedef map<CursorId, ClientCursor*> CCById; typedef map<CursorId, ClientCursor*> CCById;
typedef multimap<DiskLoc, ClientCursor*> CCByLoc; typedef multimap<DiskLoc, ClientCursor*> CCByLoc;
extern BSONObj id_obj; extern BSONObj id_obj;
class ClientCursor { class ClientCursor {
skipping to change at line 105 skipping to change at line 106
_c->_pinValue += 100; _c->_pinValue += 100;
} }
} }
~Pointer() { ~Pointer() {
release(); release();
} }
}; };
/*const*/ CursorId cursorid; /*const*/ CursorId cursorid;
string ns; string ns;
auto_ptr<CoveredIndexMatcher> matcher; shared_ptr<Cursor> c;
auto_ptr<Cursor> c;
int pos; // # objects into the curs or so far int pos; // # objects into the curs or so far
BSONObj query; BSONObj query;
int _queryOptions; int _queryOptions;
OpTime _slaveReadTill; OpTime _slaveReadTill;
ClientCursor(int queryOptions, auto_ptr<Cursor>& _c, const char *_n s) : ClientCursor(int queryOptions, shared_ptr<Cursor>& _c, const char * _ns) :
_idleAgeMillis(0), _pinValue(0), _idleAgeMillis(0), _pinValue(0),
_doingDeletes(false), _doingDeletes(false),
ns(_ns), c(_c), ns(_ns), c(_c),
pos(0), _queryOptions(queryOptions) pos(0), _queryOptions(queryOptions)
{ {
if( queryOptions & QueryOption_NoCursorTimeout ) if( queryOptions & QueryOption_NoCursorTimeout )
noTimeout(); noTimeout();
recursive_scoped_lock lock(ccmutex); recursive_scoped_lock lock(ccmutex);
cursorid = allocCursorId_inlock(); cursorid = allocCursorId_inlock();
clientCursorsById.insert( make_pair(cursorid, this) ); clientCursorsById.insert( make_pair(cursorid, this) );
} }
~ClientCursor(); ~ClientCursor();
DiskLoc lastLoc() const { DiskLoc lastLoc() const {
return _lastLoc; return _lastLoc;
} }
shared_ptr< ParsedQuery > pq;
shared_ptr< FieldMatcher > fields; // which fields query wants retu rned shared_ptr< FieldMatcher > fields; // which fields query wants retu rned
Message originalMessage; // this is effectively an auto ptr for dat a the matcher points to Message originalMessage; // this is effectively an auto ptr for dat a the matcher points to
/* Get rid of cursors for namespaces that begin with nsprefix. /* Get rid of cursors for namespaces that begin with nsprefix.
Used by drop, dropIndexes, dropDatabase. Used by drop, dropIndexes, dropDatabase.
*/ */
static void invalidate(const char *nsPrefix); static void invalidate(const char *nsPrefix);
/** /**
* do a dbtemprelease * do a dbtemprelease
* note: caller should check matcher.docMatcher().atomic() first an d not yield if atomic - * note: caller should check matcher.docMatcher().atomic() first an d not yield if atomic -
* we don't do herein as this->matcher (above) is only initia lized for true queries/getmore. * we don't do herein as this->matcher (above) is only initia lized for true queries/getmore.
* (ie not set for remote/update) * (ie not set for remote/update)
* @return if the cursor is still valid. * @return if the cursor is still valid.
* if false is returned, then this ClientCursor should be c onsidered deleted - * if false is returned, then this ClientCursor should be c onsidered deleted -
* in fact, the whole database could be gone. * in fact, the whole database could be gone.
*/ */
bool yield(); bool yield();
struct YieldLock { struct YieldLock : boost::noncopyable {
YieldLock( ClientCursor * cc ) explicit YieldLock( ptr<ClientCursor> cc )
: _cc( cc ) , _id( cc->cursorid ) , _doingDeletes( cc->_doi ngDeletes ) { : _cc( cc ) , _id( cc->cursorid ) , _doingDeletes( cc->_doi ngDeletes ) {
cc->updateLocation(); cc->updateLocation();
_unlock = new dbtempreleasecond(); _unlock.reset(new dbtempreleasecond());
} }
~YieldLock(){ ~YieldLock(){
assert( ! _unlock ); assert( ! _unlock );
} }
bool stillOk(){ bool stillOk(){
delete _unlock; relock();
_unlock = 0;
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(){
_unlock.reset();
}
private:
ClientCursor * _cc; ClientCursor * _cc;
CursorId _id; CursorId _id;
bool _doingDeletes; bool _doingDeletes;
dbtempreleasecond * _unlock; scoped_ptr<dbtempreleasecond> _unlock;
}; };
YieldLock yieldHold(){
return YieldLock( this );
}
// --- some pass through helpers for Cursor --- // --- some pass through helpers for Cursor ---
BSONObj indexKeyPattern() { BSONObj indexKeyPattern() {
return c->indexKeyPattern(); return c->indexKeyPattern();
} }
bool ok(){ bool ok(){
return c->ok(); return c->ok();
} }
bool advance(){ bool advance(){
return c->advance(); return c->advance();
} }
bool currentMatches(){ bool currentMatches(){
if ( ! matcher.get() ) if ( ! c->matcher() )
return true; return true;
return matcher->matchesCurrent( c.get() ); return c->matcher()->matchesCurrent( c.get() );
} }
BSONObj current(){ BSONObj current(){
return c->current(); return c->current();
} }
private: private:
void setLastLoc_inlock(DiskLoc); void setLastLoc_inlock(DiskLoc);
static ClientCursor* find_inlock(CursorId id, bool warn = true) { static ClientCursor* find_inlock(CursorId id, bool warn = true) {
skipping to change at line 247 skipping to change at line 248
} }
return false; return false;
} }
/* call when cursor's location changes so that we can update the /* call when cursor's location changes so that we can update the
cursorsbylocation map. if you are locked and internally iterati ng, only cursorsbylocation map. if you are locked and internally iterati ng, only
need to call when you are ready to "unlock". need to call when you are ready to "unlock".
*/ */
void updateLocation(); void updateLocation();
void cleanupByLocation(DiskLoc loc);
void mayUpgradeStorage() { void mayUpgradeStorage() {
/* if ( !ids_.get() ) /* if ( !ids_.get() )
return; return;
stringstream ss; stringstream ss;
ss << ns << "." << cursorid; ss << ns << "." << cursorid;
ids_->mayUpgradeStorage( ss.str() );*/ ids_->mayUpgradeStorage( ss.str() );*/
} }
/** /**
* @param millis amount of idle passed time since last call * @param millis amount of idle passed time since last call
skipping to change at line 293 skipping to change at line 292
static unsigned byLocSize(); // just for diagnostics static unsigned byLocSize(); // just for diagnostics
static void informAboutToDeleteBucket(const DiskLoc& b); static void informAboutToDeleteBucket(const DiskLoc& b);
static void aboutToDelete(const DiskLoc& dl); static void aboutToDelete(const DiskLoc& dl);
}; };
class ClientCursorMonitor : public BackgroundJob { class ClientCursorMonitor : public BackgroundJob {
public: public:
void run(); void run();
string name() { return "ClientCursorMonitor"; }
}; };
extern ClientCursorMonitor clientCursorMonitor; extern ClientCursorMonitor clientCursorMonitor;
} // namespace mongo } // namespace mongo
 End of changes. 14 change blocks. 
17 lines changed or deleted 17 lines changed or added


 cmdline.h   cmdline.h 
skipping to change at line 73 skipping to change at line 73
*/ */
static bool store( int argc , char ** argv , static bool store( int argc , char ** argv ,
boost::program_options::options_description& vis ible, boost::program_options::options_description& vis ible,
boost::program_options::options_description& hid den, boost::program_options::options_description& hid den,
boost::program_options::positional_options_descr iption& positional, boost::program_options::positional_options_descr iption& positional,
boost::program_options::variables_map &output ); boost::program_options::variables_map &output );
}; };
extern CmdLine cmdLine; extern CmdLine cmdLine;
void setupCoreSignals();
} }
 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 48 skipping to change at line 48
const string name; const string name;
/* run the given command /* run the given command
implement this... implement this...
fromRepl - command is being invoked as part of replication synci ng. In this situation you fromRepl - command is being invoked as part of replication synci ng. In this situation you
normally do not want to log the command to the local oplog. normally do not want to log the command to the local oplog.
return value is true if succeeded. if false, set errmsg text. return value is true if succeeded. if false, set errmsg text.
*/ */
virtual bool run(const char *ns, BSONObj& cmdObj, string& errmsg, B SONObjBuilder& result, bool fromRepl) = 0; virtual bool run(const string& db, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) = 0;
/* /*
note: logTheTop() MUST be false if READ note: logTheTop() MUST be false if READ
if NONE, can't use Client::Context setup if NONE, can't use Client::Context setup
use with caution use with caution
*/ */
virtual LockType locktype() const = 0; virtual LockType locktype() const = 0;
/* Return true if only the admin ns has privileges to run this comm and. */ /* Return true if only the admin ns has privileges to run this comm and. */
virtual bool adminOnly() const { virtual bool adminOnly() const {
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 concurrency.h   concurrency.h 
skipping to change at line 32 skipping to change at line 32
name level name level
Logstream::mutex 1 Logstream::mutex 1
ClientCursor::ccmutex 2 ClientCursor::ccmutex 2
dblock 3 dblock 3
End func name with _inlock to indicate "caller must lock before callin g". End func name with _inlock to indicate "caller must lock before callin g".
*/ */
#pragma once #pragma once
#include "../util/locks.h" #include "../util/concurrency/locks.h"
namespace mongo { namespace mongo {
inline bool readLockSupported(){ inline bool readLockSupported(){
return true; return true;
} }
string sayClientState(); string sayClientState();
bool haveClient(); bool haveClient();
skipping to change at line 207 skipping to change at line 207
assert( s == -1 ); assert( s == -1 );
_state.set(0); _state.set(0);
_m.unlock_shared(); _m.unlock_shared();
} }
MutexInfo& info() { return _minfo; } MutexInfo& info() { return _minfo; }
}; };
extern MongoMutex &dbMutex; extern MongoMutex &dbMutex;
void dbunlocking_write(); inline void dbunlocking_write() { }
void dbunlocking_read(); inline void dbunlocking_read() { }
struct writelock { struct writelock {
writelock(const string& ns) { writelock(const string& ns) {
dbMutex.lock(); dbMutex.lock();
} }
~writelock() { ~writelock() {
DESTRUCTOR_GUARD( DESTRUCTOR_GUARD(
dbunlocking_write(); dbunlocking_write();
dbMutex.unlock(); dbMutex.unlock();
); );
skipping to change at line 244 skipping to change at line 244
struct readlocktry { struct readlocktry {
readlocktry( const string&ns , int tryms ){ readlocktry( const string&ns , int tryms ){
_got = dbMutex.lock_shared_try( tryms ); _got = dbMutex.lock_shared_try( tryms );
} }
~readlocktry() { ~readlocktry() {
if ( _got ){ if ( _got ){
dbunlocking_read(); dbunlocking_read();
dbMutex.unlock_shared(); dbMutex.unlock_shared();
} }
} }
bool got(){ bool got() const { return _got; }
return _got; private:
}
bool _got; bool _got;
}; };
struct readlocktryassert : public readlocktry {
readlocktryassert(const string& ns, int tryms) :
readlocktry(ns,tryms) {
uassert(13142, "timeout getting readlock", got());
}
};
/** assure we have at least a read lock - they key with this being
if you have a write lock, that's ok too.
*/
struct atleastreadlock { struct atleastreadlock {
atleastreadlock( const string& ns ){ atleastreadlock( const string& ns ){
_prev = dbMutex.getState(); _prev = dbMutex.getState();
if ( _prev == 0 ) if ( _prev == 0 )
dbMutex.lock_shared(); dbMutex.lock_shared();
} }
~atleastreadlock(){ ~atleastreadlock(){
if ( _prev == 0 ) if ( _prev == 0 )
dbMutex.unlock_shared(); dbMutex.unlock_shared();
} }
private:
int _prev; int _prev;
}; };
class mongolock { class mongolock {
bool _writelock; bool _writelock;
public: public:
mongolock(bool write) : _writelock(write) { mongolock(bool write) : _writelock(write) {
if( _writelock ) { if( _writelock ) {
dbMutex.lock(); dbMutex.lock();
} }
skipping to change at line 289 skipping to change at line 298
} else { } else {
dbunlocking_read(); dbunlocking_read();
dbMutex.unlock_shared(); dbMutex.unlock_shared();
} }
); );
} }
/* this unlocks, does NOT upgrade. that works for our current usage */ /* this unlocks, does NOT upgrade. that works for our current usage */
void releaseAndWriteLock(); void releaseAndWriteLock();
}; };
/* use writelock and readlock instead */ /* use writelock and readlock instead */
struct dblock : public writelock { struct dblock : public writelock {
dblock() : writelock("") { } dblock() : writelock("") { }
~dblock() {
}
}; };
// eliminate // eliminate
inline void assertInWriteLock() { dbMutex.assertWriteLocked(); } inline void assertInWriteLock() { dbMutex.assertWriteLocked(); }
} }
 End of changes. 7 change blocks. 
10 lines changed or deleted 17 lines changed or added


 config.h   config.h 
skipping to change at line 213 skipping to change at line 213
"configure" can be used to override this default. */ "configure" can be used to override this default. */
#define POSIX_MALLOC_THRESHOLD 10 #define POSIX_MALLOC_THRESHOLD 10
/* Define to 1 if you have the ANSI C header files. */ /* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1 #define STDC_HEADERS 1
/* Define to enable support for Unicode properties */ /* Define to enable support for Unicode properties */
/* #undef SUPPORT_UCP */ /* #undef SUPPORT_UCP */
/* Define to enable support for the UTF-8 Unicode encoding. */ /* Define to enable support for the UTF-8 Unicode encoding. */
#if( !defined(SUPPORT_UTF8) )
#define SUPPORT_UTF8 #define SUPPORT_UTF8
#endif
/* Version number of package */ /* Version number of package */
#define VERSION "7.4" #define VERSION "7.4"
/* Define to empty if `const' does not conform to ANSI C. */ /* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */ /* #undef const */
/* Define to `unsigned int' if <sys/types.h> does not define. */ /* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */ /* #undef size_t */
 End of changes. 2 change blocks. 
0 lines changed or deleted 2 lines changed or added


 connpool.h   connpool.h 
skipping to change at line 26 skipping to change at line 26
*/ */
#pragma once #pragma once
#include <stack> #include <stack>
#include "dbclient.h" #include "dbclient.h"
#include "redef_macros.h" #include "redef_macros.h"
namespace mongo { namespace mongo {
class Shard;
struct PoolForHost { struct PoolForHost {
PoolForHost() PoolForHost()
: created(0){} : created(0){}
std::stack<DBClientBase*> pool; std::stack<DBClientBase*> pool;
long long created; long long created;
}; };
class DBConnectionHook { class DBConnectionHook {
public: public:
virtual ~DBConnectionHook(){} virtual ~DBConnectionHook(){}
skipping to change at line 62 skipping to change at line 62
{ {
ScopedDbConnection c("myserver"); ScopedDbConnection c("myserver");
c.conn()... c.conn()...
} }
*/ */
class DBConnectionPool { class DBConnectionPool {
mongo::mutex _mutex; mongo::mutex _mutex;
map<string,PoolForHost*> _pools; // servername -> pool map<string,PoolForHost*> _pools; // servername -> pool
list<DBConnectionHook*> _hooks; list<DBConnectionHook*> _hooks;
public:
DBConnectionPool() : _mutex("DBConnectionPool") { }
void onCreate( DBClientBase * conn ); void onCreate( DBClientBase * conn );
void onHandedOut( DBClientBase * conn ); void onHandedOut( DBClientBase * conn );
public:
void flush(); void flush();
DBClientBase *get(const string& host); DBClientBase *get(const string& host);
void release(const string& host, DBClientBase *c) { void release(const string& host, DBClientBase *c) {
if ( c->isFailed() ){ if ( c->isFailed() ){
delete c; delete c;
return; return;
} }
scoped_lock L(_mutex); scoped_lock L(_mutex);
_pools[host]->pool.push(c); _pools[host]->pool.push(c);
} }
skipping to change at line 119 skipping to change at line 122
/** throws UserException if can't connect */ /** throws UserException if can't connect */
ScopedDbConnection(const string& host) ScopedDbConnection(const string& host)
: _host(host), _conn( pool.get(host) ) { : _host(host), _conn( pool.get(host) ) {
} }
ScopedDbConnection(const string& host, DBClientBase* conn ) ScopedDbConnection(const string& host, DBClientBase* conn )
: _host( host ) , _conn( conn ){ : _host( host ) , _conn( conn ){
} }
ScopedDbConnection(const Shard& shard );
ScopedDbConnection(const Shard* shard );
string getHost() const { return _host; } string getHost() const { return _host; }
/** Force closure of the connection. You should call this if you l eave it in /** Force closure of the connection. You should call this if you l eave it in
a bad state. Destructor will do this too, but it is verbose. a bad state. Destructor will do this too, but it is verbose.
*/ */
void kill() { void kill() {
delete _conn; delete _conn;
_conn = 0; _conn = 0;
} }
 End of changes. 4 change blocks. 
1 lines changed or deleted 9 lines changed or added


 counters.h   counters.h 
skipping to change at line 36 skipping to change at line 36
/** /**
* for storing operation counters * for storing operation counters
* note: not thread safe. ok with that for speed * note: not thread safe. ok with that for speed
*/ */
class OpCounters { class OpCounters {
public: public:
OpCounters(); OpCounters();
int * getInsert(){ return _insert; } AtomicUInt * getInsert(){ return _insert; }
int * getQuery(){ return _query; } AtomicUInt * getQuery(){ return _query; }
int * getUpdate(){ return _update; } AtomicUInt * getUpdate(){ return _update; }
int * getDelete(){ return _delete; } AtomicUInt * getDelete(){ return _delete; }
int * getGetMore(){ return _getmore; } AtomicUInt * getGetMore(){ return _getmore; }
int * getCommand(){ return _command; } AtomicUInt * getCommand(){ return _command; }
void gotInsert(){ _insert[0]++; } void gotInsert(){ _insert[0]++; }
void gotQuery(){ _query[0]++; } void gotQuery(){ _query[0]++; }
void gotUpdate(){ _update[0]++; } void gotUpdate(){ _update[0]++; }
void gotDelete(){ _delete[0]++; } void gotDelete(){ _delete[0]++; }
void gotGetMore(){ _getmore[0]++; } void gotGetMore(){ _getmore[0]++; }
void gotCommand(){ _command[0]++; } void gotCommand(){ _command[0]++; }
void gotOp( int op , bool isCommand ); void gotOp( int op , bool isCommand );
BSONObj& getObj(){ return _obj; } BSONObj& getObj(){ return _obj; }
private: private:
BSONObj _obj; BSONObj _obj;
int * _insert; AtomicUInt * _insert;
int * _query; AtomicUInt * _query;
int * _update; AtomicUInt * _update;
int * _delete; AtomicUInt * _delete;
int * _getmore; AtomicUInt * _getmore;
int * _command; AtomicUInt * _command;
}; };
extern OpCounters globalOpCounters; extern OpCounters globalOpCounters;
class IndexCounters { class IndexCounters {
public: public:
IndexCounters(); IndexCounters();
void btree( char * node ){ void btree( char * node ){
if ( ! _memSupported ) if ( ! _memSupported )
skipping to change at line 125 skipping to change at line 125
long long _total_time; long long _total_time;
long long _flushes; long long _flushes;
int _last_time; int _last_time;
Date_t _last; Date_t _last;
}; };
extern FlushCounters globalFlushCounters; extern FlushCounters globalFlushCounters;
class GenericCounter { class GenericCounter {
public: public:
GenericCounter() : _mutex("GenericCounter") { }
void hit( const string& name , int count=0 ); void hit( const string& name , int count=0 );
BSONObj getObj(); BSONObj getObj();
private: private:
map<string,long long> _counts; // TODO: replace with thread safe ma p map<string,long long> _counts; // TODO: replace with thread safe ma p
mongo::mutex _mutex; mongo::mutex _mutex;
}; };
} }
 End of changes. 3 change blocks. 
12 lines changed or deleted 13 lines changed or added


 curop.h   curop.h 
skipping to change at line 244 skipping to change at line 243
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();
string getRemoteString( bool incPort = true ){ string getRemoteString( bool includePort = true ){
return _remote.toString(incPort); 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 < < endl; cout << "about to assert, old _message: " << _message < < " new message:" << msg << endl;
assert( ! _progressMeter.isActive() ); assert( ! _progressMeter.isActive() );
} }
_progressMeter.reset( progressMeterTotal , secondsBetween ) ; _progressMeter.reset( progressMeterTotal , secondsBetween ) ;
} }
else { else {
_progressMeter.finished(); _progressMeter.finished();
} }
_message = msg; _message = msg;
return _progressMeter; return _progressMeter;
} }
string getMessage() const { return _message; } string getMessage() const { return _message; }
ProgressMeter getProgressMeter() { return _progressMeter; } ProgressMeter& getProgressMeter() { return _progressMeter; }
friend class Client; friend class Client;
}; };
/* 0 = ok /* 0 = ok
1 = kill current operation and reset this to 0 1 = kill current operation and reset this to 0
future: maybe use this as a "going away" thing on process terminatio n with a higher flag value future: maybe use this as a "going away" thing on process terminatio n with a higher flag value
*/ */
extern class KillCurrentOp { extern class KillCurrentOp {
enum { Off, On, All } state; enum { Off, On, All } state;
 End of changes. 3 change blocks. 
4 lines changed or deleted 4 lines changed or added


 cursor.h   cursor.h 
skipping to change at line 23 skipping to change at line 23
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "jsobj.h" #include "jsobj.h"
#include "diskloc.h" #include "diskloc.h"
#include "matcher.h"
namespace mongo { namespace mongo {
class Record; class Record;
class CoveredIndexMatcher;
/* Query cursors, base class. This is for our internal cursors. "Clie ntCursor" is a separate /* Query cursors, base class. This is for our internal cursors. "Clie ntCursor" is a separate
concept and is for the user's cursor. concept and is for the user's cursor.
WARNING concurrency: the vfunctions below are called back from withi n a WARNING concurrency: the vfunctions below are called back from withi n a
ClientCursor::ccmutex. Don't cause a deadlock, you've been warned. ClientCursor::ccmutex. Don't cause a deadlock, you've been warned.
*/ */
class Cursor { class Cursor : boost::noncopyable {
public: public:
virtual ~Cursor() {} virtual ~Cursor() {}
virtual bool ok() = 0; virtual bool ok() = 0;
bool eof() { bool eof() { return !ok(); }
return !ok();
}
virtual Record* _current() = 0; virtual Record* _current() = 0;
virtual BSONObj current() = 0; virtual BSONObj current() = 0;
virtual DiskLoc currLoc() = 0; virtual DiskLoc currLoc() = 0;
virtual bool advance() = 0; /*true=ok*/ virtual bool advance() = 0; /*true=ok*/
virtual BSONObj currKey() const { return BSONObj(); } virtual BSONObj currKey() const { return BSONObj(); }
// DiskLoc the cursor requires for continued operation. Before thi s // DiskLoc the cursor requires for continued operation. Before thi s
// DiskLoc is deleted, the cursor must be incremented or destroyed. // DiskLoc is deleted, the cursor must be incremented or destroyed.
virtual DiskLoc refLoc() = 0; virtual DiskLoc refLoc() = 0;
skipping to change at line 82 skipping to change at line 82
/* 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 string toString() { virtual string toString() { return "abstract?"; }
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
*/ */
virtual bool getsetdup(DiskLoc loc) = 0; virtual bool getsetdup(DiskLoc loc) = 0;
virtual BSONObj prettyIndexBounds() const { return BSONObj(); } virtual BSONArray prettyIndexBounds() const { return BSONArray(); }
virtual bool capped() const { return false; } virtual bool capped() const { return false; }
// The implementation may return different matchers depending on th
e
// position of the cursor. If matcher() is nonzero at the start,
// matcher() should be checked each time advance() is called.
virtual CoveredIndexMatcher *matcher() const { return 0; }
// A convenience function for setting the value of matcher() manual
ly
// so it may accessed later. Implementations which must generate
// their own matcher() should assert here.
virtual void setMatcher( auto_ptr< CoveredIndexMatcher > matcher )
{
massert( 13285, "manual matcher config not allowed", false );
}
}; };
// strategy object implementing direction of traversal. // strategy object implementing direction of traversal.
class AdvanceStrategy { class AdvanceStrategy {
public: public:
virtual ~AdvanceStrategy() { } virtual ~AdvanceStrategy() { }
virtual DiskLoc next( const DiskLoc &prev ) const = 0; virtual DiskLoc next( const DiskLoc &prev ) const = 0;
}; };
const AdvanceStrategy *forward(); const AdvanceStrategy *forward();
const AdvanceStrategy *reverse(); const AdvanceStrategy *reverse();
/* table-scan style cursor */ /* table-scan style cursor */
class BasicCursor : public Cursor { class BasicCursor : public Cursor {
protected: protected:
DiskLoc curr, last; DiskLoc curr, last;
const AdvanceStrategy *s; const AdvanceStrategy *s;
private: private:
bool tailable_; bool tailable_;
auto_ptr< CoveredIndexMatcher > _matcher;
void init() { void init() {
tailable_ = false; tailable_ = false;
} }
public: public:
bool ok() { bool ok() {
return !curr.isNull(); return !curr.isNull();
} }
Record* _current() { Record* _current() {
assert( ok() ); assert( ok() );
return curr.rec(); return curr.rec();
skipping to change at line 164 skipping to change at line 174
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 CoveredIndexMatcher *matcher() const { return _matcher.get(
); }
virtual void setMatcher( auto_ptr< CoveredIndexMatcher > matcher )
{
_matcher = matcher;
}
}; };
/* used for order { $natural: -1 } */ /* used for order { $natural: -1 } */
class ReverseCursor : public BasicCursor { class ReverseCursor : public BasicCursor {
public: public:
ReverseCursor(DiskLoc dl) : BasicCursor( dl, reverse() ) { } ReverseCursor(DiskLoc dl) : BasicCursor( dl, reverse() ) { }
ReverseCursor() : BasicCursor( reverse() ) { } ReverseCursor() : BasicCursor( reverse() ) { }
virtual string toString() { virtual string toString() {
return "ReverseCursor"; return "ReverseCursor";
} }
 End of changes. 9 change blocks. 
8 lines changed or deleted 30 lines changed or added


 database.h   database.h 
skipping to change at line 116 skipping to change at line 116
files.pop_back(); files.pop_back();
} }
} }
MongoDataFile* getFile( int n, int sizeNeeded = 0, bool preallocate Only = false ) { MongoDataFile* getFile( int n, int sizeNeeded = 0, bool preallocate Only = false ) {
assert(this); assert(this);
namespaceIndex.init(); namespaceIndex.init();
if ( n < 0 || n >= DiskLoc::MaxFiles ) { if ( n < 0 || n >= DiskLoc::MaxFiles ) {
out() << "getFile(): n=" << n << endl; out() << "getFile(): n=" << n << endl;
#if !defined(_RECSTORE) #if 0
if( n >= RecCache::Base && n <= RecCache::Base+1000 ) if( n >= RecCache::Base && n <= RecCache::Base+1000 )
massert( 10294 , "getFile(): bad file number - using re cstore db w/nonrecstore db build?", false); massert( 10294 , "getFile(): bad file number - using re cstore db w/nonrecstore db build?", false);
#endif #endif
massert( 10295 , "getFile(): bad file number value (corrupt db?): run repair", false); massert( 10295 , "getFile(): bad file number value (corrupt db?): run repair", false);
} }
DEV { DEV {
if ( n > 100 ) if ( n > 100 )
out() << "getFile(): n=" << n << "?" << endl; out() << "getFile(): n=" << n << "?" << endl;
} }
MongoDataFile* p = 0; MongoDataFile* p = 0;
skipping to change at line 156 skipping to change at line 156
throw; throw;
} }
if ( preallocateOnly ) if ( preallocateOnly )
delete p; delete p;
else else
files[n] = p; files[n] = p;
} }
return preallocateOnly ? 0 : p; return preallocateOnly ? 0 : p;
} }
MongoDataFile* addAFile( int sizeNeeded = 0, bool preallocateNextFi le = false ) { MongoDataFile* addAFile( int sizeNeeded, bool preallocateNextFile ) {
int n = (int) files.size(); int n = (int) files.size();
MongoDataFile *ret = getFile( n, sizeNeeded ); MongoDataFile *ret = getFile( n, sizeNeeded );
if ( preallocateNextFile ) if ( preallocateNextFile )
preallocateAFile(); preallocateAFile();
return ret; return ret;
} }
// safe to call this multiple times - the implementation will only preallocate one file // safe to call this multiple times - the implementation will only preallocate one file
void preallocateAFile() { void preallocateAFile() {
int n = (int) files.size(); int n = (int) files.size();
getFile( n, 0, true ); getFile( n, 0, true );
} }
MongoDataFile* suitableFile( int sizeNeeded ) { MongoDataFile* suitableFile( int sizeNeeded, bool preallocate ) {
MongoDataFile* f = newestFile(); MongoDataFile* f = newestFile();
if ( !f ) {
f = addAFile( sizeNeeded, preallocate );
}
for ( int i = 0; i < 8; i++ ) { for ( int i = 0; i < 8; i++ ) {
if ( f->getHeader()->unusedLength >= sizeNeeded ) if ( f->getHeader()->unusedLength >= sizeNeeded )
break; break;
f = addAFile( sizeNeeded ); f = addAFile( sizeNeeded, preallocate );
if ( f->getHeader()->fileLength >= MongoDataFile::maxSize() ) // this is as big as they get so might as well stop if ( f->getHeader()->fileLength >= MongoDataFile::maxSize() ) // this is as big as they get so might as well stop
break; break;
} }
return f; return f;
} }
Extent* allocExtent( const char *ns, int size, bool capped ) { Extent* allocExtent( const char *ns, int size, bool capped ) {
Extent *e = DataFileMgr::allocFromFreeList( ns, size, capped ); Extent *e = DataFileMgr::allocFromFreeList( ns, size, capped );
if( e ) return e; if( e ) return e;
return suitableFile( size )->createExtent( ns, size, capped ); return suitableFile( size, !capped )->createExtent( ns, size, c apped );
} }
MongoDataFile* newestFile() { MongoDataFile* newestFile() {
int n = (int) files.size(); int n = (int) files.size();
if ( n > 0 ) n--; if ( n > 0 ) {
n--;
} else {
return 0;
}
return getFile(n); return getFile(n);
} }
/** /**
* @return true if success, false otherwise * @return true if success, false otherwise
*/ */
bool setProfilingLevel( int newLevel , string& errmsg ); bool setProfilingLevel( int newLevel , string& errmsg );
void finishInit(); void finishInit();
static bool validDBName( const string& ns );
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. 8 change blocks. 
6 lines changed or deleted 15 lines changed or added


 db.h   db.h 
skipping to change at line 21 skipping to change at line 21
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "../util/message.h" #include "../util/message.h"
#include "boost/version.hpp"
#include "concurrency.h" #include "concurrency.h"
#include "pdfile.h" #include "pdfile.h"
#include "client.h" #include "client.h"
namespace mongo { namespace mongo {
// void jniCallback(Message& m, Message& out); // void jniCallback(Message& m, Message& out);
/* Note the limit here is rather arbitrary and is simply a standard. ge nerally the code works /* Note the limit here is rather arbitrary and is simply a standard. ge nerally the code works
with any object that fits in ram. with any object that fits in ram.
skipping to change at line 139 skipping to change at line 138
DBs m = i->second; DBs m = i->second;
for( DBs::const_iterator j=m.begin(); j!=m.end(); j++ ){ for( DBs::const_iterator j=m.begin(); j!=m.end(); j++ ){
all.insert( j->first ); all.insert( j->first );
} }
} }
} }
private: private:
string _todb( const string& ns ) const { string _todb( const string& ns ) const {
string d = __todb( ns );
uassert( 13280 , (string)"invalid db name: " + ns , Database::v
alidDBName( d ) );
return d;
}
string __todb( const string& ns ) const {
size_t i = ns.find( '.' ); size_t i = ns.find( '.' );
if ( i == string::npos ){ if ( i == string::npos ){
uassert( 13074 , "db name can't be empty" , ns.size() ); uassert( 13074 , "db name can't be empty" , ns.size() );
return ns; return ns;
} }
uassert( 13075 , "db name can't be empty" , i > 0 ); uassert( 13075 , "db name can't be empty" , i > 0 );
return ns.substr( 0 , i ); return ns.substr( 0 , i );
} }
Paths _paths; Paths _paths;
 End of changes. 2 change blocks. 
1 lines changed or deleted 7 lines changed or added


 dbclient.h   dbclient.h 
skipping to change at line 253 skipping to change at line 253
Basically just invocations of connection.$cmd.findOne({...}); Basically just invocations of connection.$cmd.findOne({...});
*/ */
class DBClientWithCommands : public DBClientInterface { class DBClientWithCommands : public DBClientInterface {
set<string> _seenIndexes; set<string> _seenIndexes;
public: public:
/** controls how chatty the client is about network errors & such. See log.h */ /** controls how chatty the client is about network errors & such. See log.h */
int _logLevel; int _logLevel;
DBClientWithCommands() : _logLevel(0) { } DBClientWithCommands() : _logLevel(0) { }
/** helper function. run a simple command where the command /** helper function. run a simple command where the command expres
expression is simply sion is simply
{ command : 1 } { command : 1 }
@param info -- where to put result object. may be null if call er doesn't need that info @param info -- where to put result object. may be null if call er doesn't need that info
@param command -- command name @param command -- command name
@return true if the command returned "ok". @return true if the command returned "ok".
*/ */
bool simpleCommand(const string &dbname, BSONObj *info, const strin g &command); bool simpleCommand(const string &dbname, BSONObj *info, const strin g &command);
/** Run a database command. Database commands are represented as B SON objects. Common database /** Run a database command. Database commands are represented as B SON objects. Common database
commands have prebuilt helper functions -- see below. If a hel per is not available you can commands have prebuilt helper functions -- see below. If a hel per is not available you can
directly call runCommand. directly call runCommand.
@param dbname database name. Use "admin" for global administra tive commands. @param dbname database name. Use "admin" for global administra tive commands.
@param cmd the command object to execute. For exam ple, { ismaster : 1 } @param cmd the command object to execute. For exam ple, { ismaster : 1 }
@param info the result object the database returns. Typically has { ok : ..., errmsg : ... } fields @param info the result object the database returns. Typically has { ok : ..., errmsg : ... } fields
set. set.
@param options see enum QueryOptions - normally not needed to r un a command @param options see enum QueryOptions - normally not needed to r un a command
@return true if the command returned "ok". @return true if the command returned "ok".
*/ */
virtual bool runCommand(const string &dbname, const BSONObj& cmd, B SONObj &info, int options=0); virtual bool runCommand(const string &dbname, const BSONObj& cmd, B SONObj &info, int options=0);
/** Authorize access to a particular database. /** Authorize access to a particular database.
Authentication is separate for each database on the Authentication is separate for each database on the server -- y
server -- you may authenticate for any ou may authenticate for any
number of databases on a single connection. number of databases on a single connection.
The "admin" database is special and once authenticat The "admin" database is special and once authenticated provides
ed provides access to all databases on the access to all databases on the
server. server.
@param digestPassword if password is plain text, set @param digestPassword if password is plain text, set this to tr
this to true. otherwise assumed to be pre-digested ue. otherwise assumed to be pre-digested
@return true if successful @return true if successful
*/ */
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);
/** count number of objects in collection ns that match the query c riteria specified /** count number of objects in collection ns that match the query c riteria specified
throws UserAssertion if database returns an error throws UserAssertion if database returns an error
*/ */
unsigned long long count(const string &ns, const BSONObj& query = B SONObj(), int options=0 ); unsigned long long count(const string &ns, const BSONObj& query = B SONObj(), int options=0 );
string createPasswordDigest( const string &username , const string &clearTextPassword ); string createPasswordDigest( const string &username , const string &clearTextPassword );
 End of changes. 5 change blocks. 
15 lines changed or deleted 15 lines changed or added


 dbclientcursor.h   dbclientcursor.h 
skipping to change at line 28 skipping to change at line 28
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "../util/message.h" #include "../util/message.h"
#include "../db/jsobj.h" #include "../db/jsobj.h"
#include "../db/json.h" #include "../db/json.h"
#include <stack> #include <stack>
namespace mongo { namespace mongo {
class ShardConnection;
/** Queries return a cursor object */ /** Queries return a cursor object */
class DBClientCursor : boost::noncopyable { class DBClientCursor : boost::noncopyable {
public: public:
/** If true, safe to call next(). Requests more from server if necessary. */ /** If true, safe to call next(). Requests more from server if necessary. */
bool more(); bool more();
/** If true, there is more in our local buffers to be fetched via n ext(). Returns /** If true, there is more in our local buffers to be fetched via n ext(). Returns
false when a getMore request back to server would be required. You can use this false when a getMore request back to server would be required. You can use this
if you want to exhaust whatever data has been fetched to the cl ient already but if you want to exhaust whatever data has been fetched to the cl ient already but
then perhaps stop. then perhaps stop.
skipping to change at line 61 skipping to change at line 63
*/ */
void putBack( const BSONObj &o ) { _putBack.push( o.getOwned() ); } void putBack( const BSONObj &o ) { _putBack.push( o.getOwned() ); }
/** throws AssertionException if get back { $err : ... } */ /** throws AssertionException if get back { $err : ... } */
BSONObj nextSafe() { BSONObj nextSafe() {
BSONObj o = next(); BSONObj o = next();
BSONElement e = o.firstElement(); BSONElement e = o.firstElement();
if( strcmp(e.fieldName(), "$err") == 0 ) { if( strcmp(e.fieldName(), "$err") == 0 ) {
if( logLevel >= 5 ) if( logLevel >= 5 )
log() << "nextSafe() error " << o.toString() << endl; log() << "nextSafe() error " << o.toString() << endl;
uassert(13106, "nextSafe() returns: " + o.toString(), false ); uassert(13106, "nextSafe(): " + o.toString(), false);
} }
return o; return o;
} }
/** /**
iterate the rest of the cursor and return the number if items iterate the rest of the cursor and return the number if items
*/ */
int itcount(){ int itcount(){
int c = 0; int c = 0;
while ( more() ){ while ( more() ){
skipping to change at line 142 skipping to change at line 144
virtual ~DBClientCursor(); virtual ~DBClientCursor();
long long getCursorId() const { return cursorId; } long long getCursorId() const { return cursorId; }
/** by default we "own" the cursor and will send the server a KillC ursor /** by default we "own" the cursor and will send the server a KillC ursor
message when ~DBClientCursor() is called. This function overrid es that. message when ~DBClientCursor() is called. This function overrid es that.
*/ */
void decouple() { _ownCursor = false; } void decouple() { _ownCursor = false; }
void attach( ScopedDbConnection * conn ); void attach( ScopedDbConnection * conn );
void attach( ShardConnection * conn );
private: private:
friend class DBClientBase; friend class DBClientBase;
bool init(); bool init();
int nextBatchSize(); int nextBatchSize();
DBConnector *connector; DBConnector *connector;
string ns; string ns;
BSONObj query; BSONObj query;
int nToReturn; int nToReturn;
bool haveLimit; bool haveLimit;
 End of changes. 3 change blocks. 
1 lines changed or deleted 4 lines changed or added


 dbhelpers.h   dbhelpers.h 
skipping to change at line 36 skipping to change at line 36
#include "client.h" #include "client.h"
#include "db.h" #include "db.h"
namespace mongo { namespace mongo {
class Cursor; class Cursor;
class CoveredIndexMatcher; class CoveredIndexMatcher;
class CursorIterator { class CursorIterator {
public: public:
CursorIterator( auto_ptr<Cursor> c , BSONObj filter = BSONObj() ); CursorIterator( shared_ptr<Cursor> c , BSONObj filter = BSONObj() ) ;
BSONObj next(); BSONObj next();
bool hasNext(); bool hasNext();
private: private:
void _advance(); void _advance();
auto_ptr<Cursor> _cursor; shared_ptr<Cursor> _cursor;
auto_ptr<CoveredIndexMatcher> _matcher; auto_ptr<CoveredIndexMatcher> _matcher;
BSONObj _o; BSONObj _o;
}; };
/** /**
all helpers assume locking is handled above them all helpers assume locking is handled above them
*/ */
struct Helpers { struct Helpers {
/* ensure the specified index exists. /* ensure the specified index exists.
skipping to change at line 85 skipping to change at line 85
/** /**
* @param foundIndex if passed in will be set to 1 if ns and index found * @param foundIndex if passed in will be set to 1 if ns and index found
* @return true if object found * @return true if object found
*/ */
static bool findById(Client&, const char *ns, BSONObj query, BSONOb j& result , static bool findById(Client&, const char *ns, BSONObj query, BSONOb j& result ,
bool * nsFound = 0 , bool * indexFound = 0 ); bool * nsFound = 0 , bool * indexFound = 0 );
static auto_ptr<CursorIterator> find( const char *ns , BSONObj quer y = BSONObj() , bool requireIndex = false ); static auto_ptr<CursorIterator> find( const char *ns , BSONObj quer y = BSONObj() , bool requireIndex = false );
/* Get/put the first object from a collection. Generally only usef /** Get/put the first object from a collection. Generally only use
ul if the collection ful if the collection
only ever has a single object -- which is a "singleton collectio only ever has a single object -- which is a "singleton collecti
n". on".
You do not need to set the database before calling. You do not need to set the database before calling.
Returns: true if object exists. @return true if object exists.
*/ */
static bool getSingleton(const char *ns, BSONObj& result); static bool getSingleton(const char *ns, BSONObj& result);
static void putSingleton(const char *ns, BSONObj obj); static void putSingleton(const char *ns, BSONObj obj);
static void putSingletonGod(const char *ns, BSONObj obj, bool logTh eOp); static void putSingletonGod(const char *ns, BSONObj obj, bool logTh eOp);
/** You do not need to set the database before calling.
@return true if collection is empty.
*/
static bool isEmpty(const char *ns);
/* Remove all objects from a collection. /* Remove all objects from a collection.
You do not need to set the database before calling. You do not need to set the database before calling.
*/ */
static void emptyCollection(const char *ns); static void emptyCollection(const char *ns);
}; };
class Database; class Database;
// manage a set using collection backed storage // manage a set using collection backed storage
 End of changes. 6 change blocks. 
8 lines changed or deleted 13 lines changed or added


 dbmessage.h   dbmessage.h 
skipping to change at line 83 skipping to change at line 83
}; };
#pragma pack() #pragma pack()
/* For the database/server protocol, these objects and functions encaps ulate /* For the database/server protocol, these objects and functions encaps ulate
the various messages transmitted over the connection. the various messages transmitted over the connection.
*/ */
class DbMessage { class DbMessage {
public: public:
DbMessage(const Message& _m) : m(_m) { DbMessage(const Message& _m) : m(_m) {
theEnd = _m.data->_data + _m.data->dataLen(); // for received messages, Message has only one buffer
int *r = (int *) _m.data->_data; theEnd = _m.singleData()->_data + _m.header()->dataLen();
int *r = (int *) _m.singleData()->_data;
reserved = *r; reserved = *r;
r++; r++;
data = (const char *) r; data = (const char *) r;
nextjsobj = data; nextjsobj = data;
} }
const char * getns() const { const char * getns() const {
return data; return data;
} }
void getns(Namespace& ns) const { void getns(Namespace& ns) const {
skipping to change at line 207 skipping to change at line 208
/* parses the message into the above fields */ /* parses the message into the above fields */
QueryMessage(DbMessage& d) { QueryMessage(DbMessage& d) {
ns = d.getns(); ns = d.getns();
ntoskip = d.pullInt(); ntoskip = d.pullInt();
ntoreturn = d.pullInt(); ntoreturn = d.pullInt();
query = d.nextJsObj(); query = d.nextJsObj();
if ( d.moreJSObjs() ) { if ( d.moreJSObjs() ) {
fields = d.nextJsObj(); fields = d.nextJsObj();
} }
queryOptions = d.msg().data->dataAsInt(); queryOptions = d.msg().header()->dataAsInt();
} }
}; };
} // namespace mongo } // namespace mongo
#include "../client/dbclient.h" #include "../client/dbclient.h"
namespace mongo { namespace mongo {
inline void replyToQuery(int queryResultFlags, inline void replyToQuery(int queryResultFlags,
skipping to change at line 235 skipping to change at line 236
b.append(data, size); b.append(data, size);
QueryResult *qr = (QueryResult *) b.buf(); QueryResult *qr = (QueryResult *) b.buf();
qr->_resultFlags() = queryResultFlags; qr->_resultFlags() = queryResultFlags;
qr->len = b.len(); qr->len = b.len();
qr->setOperation(opReply); qr->setOperation(opReply);
qr->cursorId = cursorId; qr->cursorId = cursorId;
qr->startingFrom = startingFrom; qr->startingFrom = startingFrom;
qr->nReturned = nReturned; qr->nReturned = nReturned;
b.decouple(); b.decouple();
Message resp(qr, true); Message resp(qr, true);
p->reply(requestMsg, resp, requestMsg.data->id); p->reply(requestMsg, resp, requestMsg.header()->id);
} }
} // namespace mongo } // namespace mongo
//#include "bsonobj.h" //#include "bsonobj.h"
#include "instance.h" #include "instance.h"
namespace mongo { namespace mongo {
/* object reply helper. */ /* object reply helper. */
skipping to change at line 272 skipping to change at line 273
QueryResult *qr = msgdata; QueryResult *qr = msgdata;
qr->_resultFlags() = queryResultFlags; qr->_resultFlags() = queryResultFlags;
qr->len = b.len(); qr->len = b.len();
qr->setOperation(opReply); qr->setOperation(opReply);
qr->cursorId = 0; qr->cursorId = 0;
qr->startingFrom = 0; qr->startingFrom = 0;
qr->nReturned = 1; qr->nReturned = 1;
Message *resp = new Message(); Message *resp = new Message();
resp->setData(msgdata, true); // transport will free resp->setData(msgdata, true); // transport will free
dbresponse.response = resp; dbresponse.response = resp;
dbresponse.responseTo = m.data->id; dbresponse.responseTo = m.header()->id;
} }
} // namespace mongo } // namespace mongo
 End of changes. 4 change blocks. 
5 lines changed or deleted 6 lines changed or added


 diskloc.h   diskloc.h 
skipping to change at line 25 skipping to change at line 25
*/ */
/* storage.h /* storage.h
Storage subsystem management. Storage subsystem management.
Lays out our datafiles on disk, manages disk space. Lays out our datafiles on disk, manages disk space.
*/ */
#pragma once #pragma once
namespace mongo { #include "jsobj.h"
#pragma pack(1) namespace mongo {
class Record; class Record;
class DeletedRecord; class DeletedRecord;
class Extent; class Extent;
class BtreeBucket; class BtreeBucket;
class BSONObj;
class MongoDataFile; class MongoDataFile;
#pragma pack(1)
class DiskLoc { class DiskLoc {
int fileNo; /* this will be volume, file #, etc. */ int fileNo; /* this will be volume, file #, etc. */
int ofs; int ofs;
public: public:
// Note: MaxFiles imposes a limit of about 32TB of data per process // Note: MaxFiles imposes a limit of about 32TB of data per process
enum SentinelValues { MaxFiles=16000, NullOfs = -1 }; enum SentinelValues { MaxFiles=16000, NullOfs = -1 };
int a() const { int a() const {
return fileNo; return fileNo;
} }
skipping to change at line 90 skipping to change at line 90
string toString() const { string toString() const {
if ( isNull() ) if ( isNull() )
return "null"; return "null";
stringstream ss; stringstream ss;
ss << hex << fileNo << ':' << ofs; ss << hex << fileNo << ':' << ofs;
return ss.str(); return ss.str();
} }
operator string() const { return toString(); } operator string() const { return toString(); }
BSONObj toBSONObj() const {
return BSON( "file" << fileNo << "offset" << ofs );
}
int& GETOFS() { int& GETOFS() {
return ofs; return ofs;
} }
int getOfs() const { int getOfs() const {
return ofs; return ofs;
} }
void set(int a, int b) { void set(int a, int b) {
fileNo=a; fileNo=a;
ofs=b; ofs=b;
} }
 End of changes. 5 change blocks. 
3 lines changed or deleted 7 lines changed or added


 engine_java.h   engine_java.h 
skipping to change at line 25 skipping to change at line 25
* limitations under the License. * limitations under the License.
*/ */
/* this file contains code to call into java (into the 10gen sandbox) from inside the database */ /* this file contains code to call into java (into the 10gen sandbox) from inside the database */
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include <jni.h> #include <jni.h>
#include <boost/thread/tss.hpp>
#include <errno.h> #include <errno.h>
#include <sys/types.h> #include <sys/types.h>
#if !defined(_WIN32) #if !defined(_WIN32)
#include <dirent.h> #include <dirent.h>
#endif #endif
#include "../db/jsobj.h" #include "../db/jsobj.h"
#include "engine.h" #include "engine.h"
 End of changes. 1 change blocks. 
1 lines changed or deleted 0 lines changed or added


 file.h   file.h 
skipping to change at line 140 skipping to change at line 140
if( is_open() ) ::close(fd); if( is_open() ) ::close(fd);
fd = -1; fd = -1;
} }
#ifndef O_NOATIME #ifndef O_NOATIME
#define O_NOATIME 0 #define O_NOATIME 0
#define lseek64 lseek #define lseek64 lseek
#endif #endif
void open(const char *filename, bool readOnly=false ) { void open(const char *filename, bool readOnly=false ) {
fd = ::open(filename, O_CREAT | ( readOnly ? 0 : O_RDWR ) | O_NOATI fd = ::open(filename,
ME, S_IRUSR | S_IWUSR); O_CREAT | ( readOnly ? 0 : ( O_RDWR | O_NOATIME ) ) ,
S_IRUSR | S_IWUSR);
if ( fd <= 0 ) { if ( fd <= 0 ) {
out() << "couldn't open " << filename << ' ' << errnoWithDescri ption() << endl; out() << "couldn't open " << filename << ' ' << errnoWithDescri ption() << endl;
return; return;
} }
_bad = false; _bad = false;
} }
void write(fileofs o, const char *data, unsigned len) { void write(fileofs o, const char *data, unsigned len) {
lseek64(fd, o, SEEK_SET); lseek64(fd, o, SEEK_SET);
err( ::write(fd, data, len) == (int) len ); err( ::write(fd, data, len) == (int) len );
} }
 End of changes. 1 change blocks. 
2 lines changed or deleted 3 lines changed or added


 file_allocator.h   file_allocator.h 
skipping to change at line 41 skipping to change at line 41
/* Handles allocation of contiguous files on disk. Allocation may be /* Handles allocation of contiguous files on disk. Allocation may be
requested asynchronously or synchronously. requested asynchronously or synchronously.
*/ */
class FileAllocator { class FileAllocator {
/* The public functions may not be called concurrently. The alloca tion /* The public functions may not be called concurrently. The alloca tion
functions may be called multiple times per file, but only the fi rst functions may be called multiple times per file, but only the fi rst
size specified per file will be used. size specified per file will be used.
*/ */
public: public:
#if !defined(_WIN32) #if !defined(_WIN32)
FileAllocator() : failed_() {} FileAllocator() : pendingMutex_("FileAllocator"), failed_() {}
#endif #endif
void start() { void start() {
#if !defined(_WIN32) #if !defined(_WIN32)
Runner r( *this ); Runner r( *this );
boost::thread t( r ); boost::thread t( r );
#endif #endif
} }
// May be called if file exists. If file exists, or its allocation has // May be called if file exists. If file exists, or its allocation has
// been requested, size is updated to match existing file size. // been requested, size is updated to match existing file size.
void requestAllocation( const string &name, long &size ) { void requestAllocation( const string &name, long &size ) {
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 framework.h   framework.h 
skipping to change at line 35 skipping to change at line 35
#define ASSERT_EXCEPTION(a,b) \ #define ASSERT_EXCEPTION(a,b) \
try { \ try { \
a; \ a; \
mongo::regression::assert_fail( #a , __FILE__ , __LINE__ ); \ mongo::regression::assert_fail( #a , __FILE__ , __LINE__ ); \
} catch ( b& ){ \ } catch ( b& ){ \
mongo::regression::assert_pass(); \ mongo::regression::assert_pass(); \
} }
#define ASSERT_EQUALS(a,b) (mongo::regression::MyAsserts( #a , #b , __FILE_ _ , __LINE__ ) ).ae( (a) , (b) ) #define ASSERT_EQUALS(a,b) (mongo::regression::MyAsserts( #a , #b , __FILE_ _ , __LINE__ ) ).ae( (a) , (b) )
#define ASSERT_NOT_EQUALS(a,b) (mongo::regression::MyAsserts( #a , #b , __F
ILE__ , __LINE__ ) ).nae( (a) , (b) )
#define ASSERT(x) (void)( (!(!(x))) ? mongo::regression::assert_pass() : mo ngo::regression::assert_fail( #x , __FILE__ , __LINE__ ) ) #define ASSERT(x) (void)( (!(!(x))) ? mongo::regression::assert_pass() : mo ngo::regression::assert_fail( #x , __FILE__ , __LINE__ ) )
#define FAIL(x) mongo::regression::fail( #x , __FILE__ , __LINE__ ) #define FAIL(x) mongo::regression::fail( #x , __FILE__ , __LINE__ )
#include "../db/instance.h" #include "../db/instance.h"
namespace mongo { namespace mongo {
namespace regression { namespace regression {
class Result; class Result;
skipping to change at line 162 skipping to change at line 164
return; return;
printLocation(); printLocation();
MyAssertionException * e = getBase(); MyAssertionException * e = getBase();
e->ss << a << " != " << b << endl; e->ss << a << " != " << b << endl;
log() << e->ss.str() << endl; log() << e->ss.str() << endl;
throw e; throw e;
} }
template<typename A,typename B>
void nae( A a , B b ){
_gotAssert();
if ( a != b )
return;
printLocation();
MyAssertionException * e = getBase();
e->ss << a << " == " << b << endl;
log() << e->ss.str() << endl;
throw e;
}
void printLocation(); void printLocation();
private: private:
void _gotAssert(); void _gotAssert();
MyAssertionException * getBase(); MyAssertionException * getBase();
string _aexp; string _aexp;
string _bexp; string _bexp;
 End of changes. 2 change blocks. 
0 lines changed or deleted 17 lines changed or added


 goodies.h   goodies.h 
// goodies.h // @file goodies.h
// miscellaneous junk // miscellaneous junk
/* Copyright 2009 10gen Inc. /* Copyright 2009 10gen Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* 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 "../bson/util/misc.h" #include "../bson/util/misc.h"
#include "concurrency/mutex.h"
namespace mongo { namespace mongo {
void setThreadName(const char * name);
template<class T>
inline string ToString(const T& t) {
stringstream s;
s << t;
return s.str();
}
#if !defined(_WIN32) && !defined(NOEXECINFO) && !defined(__freebsd__) && !d efined(__sun__) #if !defined(_WIN32) && !defined(NOEXECINFO) && !defined(__freebsd__) && !d efined(__sun__)
} // namespace mongo } // namespace mongo
#include <pthread.h> #include <pthread.h>
#include <execinfo.h> #include <execinfo.h>
namespace mongo { namespace mongo {
inline pthread_t GetCurrentThreadId() { inline pthread_t GetCurrentThreadId() {
skipping to change at line 138 skipping to change at line 148
bool operator<=(WrappingInt r) { bool operator<=(WrappingInt r) {
// platform dependent // platform dependent
int df = (r.x - x); int df = (r.x - x);
return df >= 0; return df >= 0;
} }
bool operator>(WrappingInt r) { bool operator>(WrappingInt r) {
return !(r<=*this); return !(r<=*this);
} }
}; };
} // namespace mongo
#include <ctime>
namespace mongo {
inline void time_t_to_Struct(time_t t, struct tm * buf , bool local = f alse ) { inline void time_t_to_Struct(time_t t, struct tm * buf , bool local = f alse ) {
#if defined(_WIN32) #if defined(_WIN32)
if ( local ) if ( local )
localtime_s( buf , &t ); localtime_s( buf , &t );
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
skipping to change at line 186 skipping to change at line 190
#define MONGO_ctime _ctime_is_not_threadsafe_ #define MONGO_ctime _ctime_is_not_threadsafe_
#define ctime MONGO_ctime #define ctime MONGO_ctime
#if defined(_WIN32) || defined(__sunos__) #if defined(_WIN32) || defined(__sunos__)
inline void sleepsecs(int s) { inline void sleepsecs(int s) {
boost::xtime xt; boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC); boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += s; xt.sec += s;
boost::thread::sleep(xt); boost::thread::sleep(xt);
} }
inline void sleepmillis(int s) { inline void sleepmillis(long long s) {
boost::xtime xt; boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC); boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += ( s / 1000 ); xt.sec += (int)( s / 1000 );
xt.nsec += ( s % 1000 ) * 1000000; xt.nsec += (int)(( s % 1000 ) * 1000000);
if ( xt.nsec >= 1000000000 ) { if ( xt.nsec >= 1000000000 ) {
xt.nsec -= 1000000000; xt.nsec -= 1000000000;
xt.sec++; xt.sec++;
} }
boost::thread::sleep(xt); boost::thread::sleep(xt);
} }
inline void sleepmicros(int s) { inline void sleepmicros(long long s) {
if ( s <= 0 ) if ( s <= 0 )
return; return;
boost::xtime xt; boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC); boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += ( s / 1000000 ); xt.sec += (int)( s / 1000000 );
xt.nsec += ( s % 1000000 ) * 1000; xt.nsec += (int)(( s % 1000000 ) * 1000);
if ( xt.nsec >= 1000000000 ) { if ( xt.nsec >= 1000000000 ) {
xt.nsec -= 1000000000; xt.nsec -= 1000000000;
xt.sec++; xt.sec++;
} }
boost::thread::sleep(xt); boost::thread::sleep(xt);
} }
#else #else
inline void sleepsecs(int s) { inline void sleepsecs(int s) {
struct timespec t; struct timespec t;
t.tv_sec = s; t.tv_sec = s;
t.tv_nsec = 0; t.tv_nsec = 0;
if ( nanosleep( &t , 0 ) ){ if ( nanosleep( &t , 0 ) ){
cout << "nanosleep failed" << endl; cout << "nanosleep failed" << endl;
} }
} }
inline void sleepmicros(int s) { inline void sleepmicros(long long s) {
if ( s <= 0 ) if ( s <= 0 )
return; return;
struct timespec t; struct timespec t;
t.tv_sec = (int)(s / 1000000); t.tv_sec = (int)(s / 1000000);
t.tv_nsec = 1000 * ( s % 1000000 ); t.tv_nsec = 1000 * ( s % 1000000 );
struct timespec out; struct timespec out;
if ( nanosleep( &t , &out ) ){ if ( nanosleep( &t , &out ) ){
cout << "nanosleep failed" << endl; cout << "nanosleep failed" << endl;
} }
} }
inline void sleepmillis(int s) { inline void sleepmillis(long long s) {
sleepmicros( s * 1000 ); sleepmicros( s * 1000 );
} }
#endif #endif
// note this wraps // note this wraps
inline int tdiff(unsigned told, unsigned tnew) { inline int tdiff(unsigned told, unsigned tnew) {
return WrappingInt::diff(tnew, told); return WrappingInt::diff(tnew, told);
} }
inline unsigned curTimeMillis() { inline unsigned curTimeMillis() {
boost::xtime xt; boost::xtime xt;
skipping to change at line 268 skipping to change at line 272
} }
// measures up to 1024 seconds. or, 512 seconds with tdiff that is... // measures up to 1024 seconds. or, 512 seconds with tdiff that is...
inline unsigned curTimeMicros() { inline unsigned curTimeMicros() {
boost::xtime xt; boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC); boost::xtime_get(&xt, boost::TIME_UTC);
unsigned t = xt.nsec / 1000; unsigned t = xt.nsec / 1000;
unsigned secs = xt.sec % 1024; unsigned secs = xt.sec % 1024;
return secs*1000000 + t; return secs*1000000 + t;
} }
using namespace boost;
extern bool __destroyingStatics;
// If you create a local static instance of this class, that instance w
ill be destroyed
// before all global static objects are destroyed, so __destroyingStati
cs will be set
// to true before the global static variables are destroyed.
class StaticObserver : boost::noncopyable {
public:
~StaticObserver() { __destroyingStatics = true; }
};
// On pthread systems, it is an error to destroy a mutex while held. S
tatic global
// mutexes may be held upon shutdown in our implementation, and this wa
y we avoid
// destroying them.
class mutex : boost::noncopyable {
public:
mutex() { _m = new boost::mutex(); }
~mutex() {
if( !__destroyingStatics ) {
delete _m;
}
}
class scoped_lock : boost::noncopyable {
public:
scoped_lock( mongo::mutex &m ) : _l( m.boost() ) {}
boost::mutex::scoped_lock &boost() { return _l; }
private:
boost::mutex::scoped_lock _l;
};
private:
boost::mutex &boost() { return *_m; }
boost::mutex *_m;
};
typedef mongo::mutex::scoped_lock scoped_lock;
typedef boost::recursive_mutex::scoped_lock recursive_scoped_lock;
// simple scoped timer // simple scoped timer
class Timer { class Timer {
public: public:
Timer() { Timer() {
reset(); reset();
} }
Timer( unsigned long long start ) { Timer( unsigned long long start ) {
old = start; old = start;
} }
skipping to change at line 368 skipping to change at line 335
} }
inline bool startsWith(string s, string p) { return startsWith(s.c_str( ), p.c_str()); } inline bool startsWith(string s, string p) { return startsWith(s.c_str( ), p.c_str()); }
inline bool endsWith(const char *p, const char *suffix) { inline bool endsWith(const char *p, const char *suffix) {
size_t a = strlen(p); size_t a = strlen(p);
size_t b = strlen(suffix); size_t b = strlen(suffix);
if ( b > a ) return false; if ( b > a ) return false;
return strcmp(p + a - b, suffix) == 0; return strcmp(p + a - b, suffix) == 0;
} }
} // namespace mongo
#include "boost/detail/endian.hpp"
namespace mongo {
inline unsigned long swapEndian(unsigned long x) { inline unsigned long swapEndian(unsigned long x) {
return return
((x & 0xff) << 24) | ((x & 0xff) << 24) |
((x & 0xff00) << 8) | ((x & 0xff00) << 8) |
((x & 0xff0000) >> 8) | ((x & 0xff0000) >> 8) |
((x & 0xff000000) >> 24); ((x & 0xff000000) >> 24);
} }
#if defined(BOOST_LITTLE_ENDIAN) #if defined(BOOST_LITTLE_ENDIAN)
inline unsigned long fixEndian(unsigned long x) { inline unsigned long fixEndian(unsigned long x) {
skipping to change at line 442 skipping to change at line 403
} }
v = new T(i); v = new T(i);
_val.reset( v ); _val.reset( v );
} }
private: private:
T _default; T _default;
boost::thread_specific_ptr<T> _val; boost::thread_specific_ptr<T> _val;
}; };
class ProgressMeter { class ProgressMeter : boost::noncopyable {
public: public:
ProgressMeter( long long total , int secondsBetween = 3 , int check Interval = 100 ){ ProgressMeter( long long total , int secondsBetween = 3 , int check Interval = 100 ){
reset( total , secondsBetween , checkInterval ); reset( total , secondsBetween , checkInterval );
} }
ProgressMeter(){ ProgressMeter(){
_active = 0; _active = 0;
} }
void reset( long long total , int secondsBetween = 3 , int checkInt erval = 100 ){ void reset( long long total , int secondsBetween = 3 , int checkInt erval = 100 ){
skipping to change at line 509 skipping to change at line 470
return _hits; return _hits;
} }
string toString() const { string toString() const {
if ( ! _active ) if ( ! _active )
return ""; return "";
stringstream buf; stringstream buf;
buf << _done << "/" << _total << " " << (_done*100)/_total << " %"; buf << _done << "/" << _total << " " << (_done*100)/_total << " %";
return buf.str(); return buf.str();
} }
bool operator==( const ProgressMeter& other ) const {
return this == &other;
}
private: private:
bool _active; bool _active;
long long _total; long long _total;
int _secondsBetween; int _secondsBetween;
int _checkInterval; int _checkInterval;
long long _done; long long _done;
long long _hits; long long _hits;
int _lastTime; int _lastTime;
}; };
class ProgressMeterHolder : boost::noncopyable {
public:
ProgressMeterHolder( ProgressMeter& pm )
: _pm( pm ){
}
~ProgressMeterHolder(){
_pm.finished();
}
ProgressMeter* operator->(){
return &_pm;
}
bool hit( int n = 1 ){
return _pm.hit( n );
}
void finished(){
_pm.finished();
}
bool operator==( const ProgressMeter& other ){
return _pm == other;
}
private:
ProgressMeter& _pm;
};
class TicketHolder { class TicketHolder {
public: public:
TicketHolder( int num ){ TicketHolder( int num ) : _mutex("TicketHolder") {
_outof = num; _outof = num;
_num = num; _num = num;
} }
bool tryAcquire(){ bool tryAcquire(){
scoped_lock lk( _mutex ); scoped_lock lk( _mutex );
if ( _num <= 0 ){ if ( _num <= 0 ){
if ( _num < 0 ){ if ( _num < 0 ){
cerr << "DISASTER! in TicketHolder" << endl; cerr << "DISASTER! in TicketHolder" << endl;
} }
skipping to change at line 713 skipping to change at line 708
s1++; s2++; s1++; s2++;
} }
if ( *s1 ) if ( *s1 )
return 1; return 1;
if ( *s2 ) if ( *s2 )
return -1; return -1;
return 0; return 0;
} }
/** A generic pointer type for function arguments.
* It will convert from any pointer type except auto_ptr.
* Semantics are the same as passing the pointer returned from get()
* const ptr<T> => T * const
* ptr<const T> => T const * or const T*
*/
template <typename T>
struct ptr{
ptr() : _p(NULL) {}
// convert to ptr<T>
ptr(T* p) : _p(p) {} // needed for NULL
template<typename U> ptr(U* p) : _p(p) {}
template<typename U> ptr(const ptr<U>& p) : _p(p) {}
template<typename U> ptr(const boost::shared_ptr<U>& p) : _p(p.get(
)) {}
template<typename U> ptr(const boost::scoped_ptr<U>& p) : _p(p.get(
)) {}
//template<typename U> ptr(const auto_ptr<U>& p) : _p(p.get()) {}
// assign to ptr<T>
ptr& operator= (T* p) { _p = p; return *this; } // needed for NULL
template<typename U> ptr& operator= (U* p) { _p = p; return *this;
}
template<typename U> ptr& operator= (const ptr<U>& p) { _p = p; ret
urn *this; }
template<typename U> ptr& operator= (const boost::shared_ptr<U>& p)
{ _p = p.get(); return *this; }
template<typename U> ptr& operator= (const boost::scoped_ptr<U>& p)
{ _p = p.get(); return *this; }
//template<typename U> ptr& operator= (const auto_ptr<U>& p) { _p =
p.get(); return *this; }
// use
T* operator->() const { return _p; }
T& operator*() const { return *_p; }
// convert from ptr<T>
operator T* () const { return _p; }
private:
T* _p;
};
/** Hmmmm */
using namespace boost;
} // namespace mongo } // namespace mongo
 End of changes. 17 change blocks. 
64 lines changed or deleted 103 lines changed or added


 hashtab.h   hashtab.h 
skipping to change at line 111 skipping to change at line 111
HashTable(PTR buf, int buflen, const char *_name) : name(_name) { HashTable(PTR buf, int buflen, const char *_name) : name(_name) {
int m = sizeof(Node); int m = sizeof(Node);
// out() << "hashtab init, buflen:" << buflen << " m:" << m << endl; // out() << "hashtab init, buflen:" << buflen << " m:" << m << endl;
n = buflen / m; n = buflen / m;
if ( (n & 1) == 0 ) if ( (n & 1) == 0 )
n--; n--;
maxChain = (int) (n * 0.05); maxChain = (int) (n * 0.05);
_buf = buf; _buf = buf;
//nodes = (Node *) buf; //nodes = (Node *) buf;
assert( sizeof(Node) == 628 ); if ( sizeof(Node) != 628 ){
//out() << "HashTable() " << _name << " sizeof(node):" << sizeo out() << "HashTable() " << _name << " sizeof(node):" << siz
f(Node) << " n:" << n << endl; eof(Node) << " n:" << n << " sizeof(Key): " << sizeof(Key) << " sizeof(Type
):" << sizeof(Type) << endl;
assert( sizeof(Node) == 628 );
}
} }
Type* get(const Key& k) { Type* get(const Key& k) {
bool found; bool found;
int i = _find(k, found); int i = _find(k, found);
if ( found ) if ( found )
return &nodes(i).value; return &nodes(i).value;
return 0; return 0;
} }
 End of changes. 1 change blocks. 
3 lines changed or deleted 7 lines changed or added


 health.h   health.h 
skipping to change at line 23 skipping to change at line 23
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
namespace mongo { namespace mongo {
/* throws */
bool requestHeartbeat(string setname, string memberFullName, BSONObj& r
esult, int myConfigVersion, int& theirConfigVersion);
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. 
0 lines changed or deleted 4 lines changed or added


 hostandport.h   hostandport.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 "sock.h" #include "sock.h"
#include "../db/cmdline.h" #include "../db/cmdline.h"
#include "mongoutils/str.h"
namespace mongo { namespace mongo {
using namespace mongoutils;
/** helper for manipulating host:port connection endpoints. /** helper for manipulating host:port connection endpoints.
*/ */
struct HostAndPort { struct HostAndPort {
HostAndPort() : _port(-1) { } HostAndPort() : _port(-1) { }
HostAndPort(string h, int p = -1) : _host(h), _port(p) { } /** From a string hostname[:portnumber]
Throws user assertion if bad config string or bad port #.
*/
HostAndPort(string s);
/** @param p port number. -1 is ok to use default. */
HostAndPort(string h, int p /*= -1*/) : _host(h), _port(p) { }
HostAndPort(const SockAddr& sock ) HostAndPort(const SockAddr& sock )
: _host( sock.getAddr() ) , _port( sock.getPort() ){ : _host( sock.getAddr() ) , _port( sock.getPort() ){
} }
static HostAndPort me() { static HostAndPort me() {
return HostAndPort("localhost", cmdLine.port); return HostAndPort("localhost", cmdLine.port);
} }
static HostAndPort fromString(string s) {
const char *p = s.c_str();
uassert(13110, "HostAndPort: bad config string", *p);
const char *colon = strchr(p, ':');
HostAndPort m;
if( colon ) {
int port = atoi(colon+1);
uassert(13095, "HostAndPort: bad port #", port > 0);
return HostAndPort(string(p,colon-p),port);
}
// no port specified.
return HostAndPort(p);
}
bool operator<(const HostAndPort& r) const { return _host < r._host || (_host==r._host&&_port<r._port); } bool operator<(const HostAndPort& r) const { return _host < r._host || (_host==r._host&&_port<r._port); }
/* returns true if the host/port combo identifies this process inst ance. */ /* returns true if the host/port combo identifies this process inst ance. */
bool isSelf() const; bool isSelf() const;
bool isLocalHost() const; bool isLocalHost() const;
// @returns host:port // @returns host:port
string toString() const; string toString() const;
skipping to change at line 65 skipping to change at line 60
/* returns true if the host/port combo identifies this process inst ance. */ /* returns true if the host/port combo identifies this process inst ance. */
bool isSelf() const; bool isSelf() const;
bool isLocalHost() const; bool isLocalHost() const;
// @returns host:port // @returns host:port
string toString() const; string toString() const;
string host() const { return _host; } string host() const { return _host; }
int port() const { return _port >= 0 ? _port : cmdLine.port; } int port() const { return _port >= 0 ? _port : cmdLine.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 share a common starting prefix */ /** returns true if strings seem to be the same hostname.
inline bool sameStart(const char *p, const char *q) { "nyc1" and "nyc1.acme.com" are treated as the same.
while( 1 ) { in fact "nyc1.foo.com" and "nyc1.acme.com" are treated the same -
if( *p == 0 || *q == 0 ) we oly look up to the first period.
return true; */
if( *p != *q ) inline bool sameHostname(const string& a, const string& b) {
break; return str::before(a, '.') == str::before(b, '.');
p++; q++;
}
return false;
} }
inline bool HostAndPort::isSelf() const { inline bool HostAndPort::isSelf() const {
int p = _port == -1 ? CmdLine::DefaultDBPort : _port; int p = _port == -1 ? CmdLine::DefaultDBPort : _port;
if( p != cmdLine.port ) if( p != cmdLine.port )
return false; return false;
assert( _host != "localhost" && _host != "127.0.0.1" );
return sameStart(getHostName().c_str(), _host.c_str()); 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 << ':' << _port;
return ss.str(); return ss.str();
} }
inline bool HostAndPort::isLocalHost() const { inline bool HostAndPort::isLocalHost() const {
return _host == "localhost" || _host == "127.0.0.1"; return _host == "localhost" || _host == "127.0.0.1" || _host == "::
1";
}
inline HostAndPort::HostAndPort(string s) {
const char *p = s.c_str();
uassert(13110, "HostAndPort: bad config string", *p);
const char *colon = strrchr(p, ':');
if( colon ) {
int port = atoi(colon+1);
uassert(13095, "HostAndPort: bad port #", port > 0);
_host = string(p,colon-p);
_port = port;
}
else {
// no port specified.
_host = p;
_port = -1;
}
} }
} }
 End of changes. 8 change blocks. 
28 lines changed or deleted 39 lines changed or added


 html.h   html.h 
skipping to change at line 12 skipping to change at line 12
#pragma once #pragma once
/* Things in the mongoutils namespace /* Things in the mongoutils namespace
(1) are not database specific, rather, true utilities (1) are not database specific, rather, true utilities
(2) are cross platform (2) are cross platform
(3) may require boost headers, but not libs (3) may require boost headers, but not libs
(4) are clean and easy to use in any c++ project without pulling in lots of other stuff (4) are clean and easy to use in any c++ project without pulling in lots of other stuff
*/ */
/* Copyright 2010 10gen Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli
ed.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <sstream> #include <sstream>
namespace mongoutils { namespace mongoutils {
namespace html { namespace html {
using namespace std; using namespace std;
inline string _end() { return "</body></html>"; }
inline string _table() { return "</table>\n\n"; }
inline string _tr() { return "</tr>\n"; }
inline string tr() { return "<tr>"; }
inline string tr(string a, string b) {
stringstream ss;
ss << "<tr><td>" << a << "</td><td>" << b << "</td></tr>\n";
return ss.str();
}
template <class T>
inline string td(T x) {
stringstream ss;
ss << "<td>" << x << "</td>";
return ss.str();
}
inline string td(string x) {
return "<td>" + x + "</td>";
}
inline string table(const char *headers[] = 0, bool border = true)
{
stringstream ss;
ss << "\n<table "
<< (border?"border=1 ":"")
<< "cellpadding=2 cellspacing=0>\n";
if( headers ) {
ss << "<tr>";
while( *headers ) {
ss << "<th>" << *headers << "</th>";
headers++;
}
ss << "</tr>\n";
}
return ss.str();
}
inline string start(string title) {
stringstream ss;
ss << "<html><head>\n<title>";
ss << title;
ss << "</title>\n";
ss << "<style type=\"text/css\" media=\"screen\">"
"body { font-family: helvetica, arial, san-serif }\n"
"table { border-collapse:collapse; border-color:#999; margi
n-top:.5em }\n"
"th { background-color:#bbb; color:#000 }\n"
"td,th { padding:.25em }\n"
"</style>\n";
ss << "</head>\n<body>\n";
return ss.str();
}
inline string red(string contentHtml, bool color=true) {
if( !color ) return contentHtml;
stringstream ss;
ss << "<span style=\"color:#A00;\">" << contentHtml << "</span>
";
return ss.str();
}
inline string blue(string contentHtml, bool color=true) {
if( !color ) return contentHtml;
stringstream ss;
ss << "<span style=\"color:#00A;\">" << contentHtml << "</span>
";
return ss.str();
}
inline string yellow(string contentHtml, bool color=true) {
if( !color ) return contentHtml;
stringstream ss;
ss << "<span style=\"color:#A80;\">" << contentHtml << "</span>
";
return ss.str();
}
inline string green(string contentHtml, bool color=true) {
if( !color ) return contentHtml;
stringstream ss;
ss << "<span style=\"color:#0A0;\">" << contentHtml << "</span>
";
return ss.str();
}
inline string p(string contentHtml) { inline string p(string contentHtml) {
stringstream ss; stringstream ss;
ss << "<p>" << contentHtml << "</p>\n"; ss << "<p>" << contentHtml << "</p>\n";
return ss.str(); return ss.str();
} }
inline string h2(string contentHtml) {
stringstream ss;
ss << "<h2>" << contentHtml << "</h2>\n";
return ss.str();
}
/* does NOT escape the strings. */ /* does NOT escape the strings. */
inline string a(string href, string title="", string contentHtml = "") { inline string a(string href, string title="", string contentHtml = "") {
stringstream ss; stringstream ss;
ss << "<a"; ss << "<a";
if( !href.empty() ) ss << " href=\"" << href << '"'; if( !href.empty() ) ss << " href=\"" << href << '"';
if( !title.empty() ) ss << " title=\"" << title << '"'; if( !title.empty() ) ss << " title=\"" << title << '"';
ss << '>'; ss << '>';
if( !contentHtml.empty() ) { if( !contentHtml.empty() ) {
ss << contentHtml << "</a>"; ss << contentHtml << "</a>";
} }
 End of changes. 3 change blocks. 
0 lines changed or deleted 106 lines changed or added


 indexkey.h   indexkey.h 
skipping to change at line 28 skipping to change at line 28
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "diskloc.h" #include "diskloc.h"
#include "jsobj.h" #include "jsobj.h"
#include <map> #include <map>
namespace mongo { namespace mongo {
class Cursor;
class IndexSpec; class IndexSpec;
class IndexType; // TODO: this name sucks class IndexType; // TODO: this name sucks
class IndexPlugin; class IndexPlugin;
class IndexDetails; class IndexDetails;
enum IndexSuitability { USELESS = 0 , HELPFUL = 1 , OPTIMAL = 2 }; enum IndexSuitability { USELESS = 0 , HELPFUL = 1 , OPTIMAL = 2 };
/** /**
* this represents an instance of a index plugin * this represents an instance of a index plugin
* done this way so parsing, etc... can be cached * done this way so parsing, etc... can be cached
* so if there is a FTS IndexPlugin, for each index using FTS * so if there is a FTS IndexPlugin, for each index using FTS
* there will be 1 of these, and it can have things pre-parsed, etc... * there will be 1 of these, and it can have things pre-parsed, etc...
*/ */
class IndexType : boost::noncopyable { class IndexType : boost::noncopyable {
public: public:
IndexType( const IndexPlugin * plugin , const IndexSpec * spec ); IndexType( const IndexPlugin * plugin , const IndexSpec * spec );
virtual ~IndexType(); virtual ~IndexType();
virtual void getKeys( const BSONObj &obj, BSONObjSetDefaultOrder &k eys ) const = 0; virtual void getKeys( const BSONObj &obj, BSONObjSetDefaultOrder &k eys ) const = 0;
virtual auto_ptr<Cursor> newCursor( const BSONObj& query , const BS ONObj& order , int numWanted ) const = 0; virtual shared_ptr<Cursor> newCursor( const BSONObj& query , const BSONObj& order , int numWanted ) const = 0;
/** optional op : changes query to match what's in the index */ /** optional op : changes query to match what's in the index */
virtual BSONObj fixKey( const BSONObj& in ) { return in; } virtual BSONObj fixKey( const BSONObj& in ) { return in; }
/** optional op : compare 2 objects with regards to this index */ /** optional op : compare 2 objects with regards to this index */
virtual int compare( const BSONObj& l , const BSONObj& r ) const; virtual int compare( const BSONObj& l , const BSONObj& r ) const;
/** @return plugin */ /** @return plugin */
const IndexPlugin * getPlugin() const { return _plugin; } const IndexPlugin * getPlugin() const { return _plugin; }
 End of changes. 2 change blocks. 
1 lines changed or deleted 2 lines changed or added


 instance.h   instance.h 
skipping to change at line 40 skipping to change at line 40
extern string dbExecCommand; extern string dbExecCommand;
struct DiagLog { struct DiagLog {
ofstream *f; ofstream *f;
/* 0 = off; 1 = writes, 2 = reads, 3 = both /* 0 = off; 1 = writes, 2 = reads, 3 = both
7 = log a few reads, and all writes. 7 = log a few reads, and all writes.
*/ */
int level; int level;
mongo::mutex mutex; mongo::mutex mutex;
DiagLog() : f(0) , level(0) { } DiagLog() : f(0) , level(0), mutex("DiagLog") { }
void init() { void init() {
if ( ! f && level ){ if ( ! f && level ){
log() << "diagLogging = " << level << endl; log() << "diagLogging = " << level << endl;
stringstream ss; stringstream ss;
ss << dbpath << "/diaglog." << hex << time(0); ss << dbpath << "/diaglog." << hex << time(0);
string name = ss.str(); string name = ss.str();
f = new ofstream(name.c_str(), ios::out | ios::binary); f = new ofstream(name.c_str(), ios::out | ios::binary);
if ( ! f->good() ) { if ( ! f->good() ) {
problem() << "couldn't open log stream" << endl; problem() << "couldn't open log stream" << endl;
throw 1717; throw 1717;
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 lasterror.h   lasterror.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 <boost/thread/tss.hpp>
#undef assert
#define assert MONGO_assert
namespace mongo { namespace mongo {
class BSONObjBuilder; class BSONObjBuilder;
class Message; class Message;
struct LastError { struct LastError {
int code; int code;
string msg; string msg;
enum UpdatedExistingType { NotUpdate, True, False } updatedExisting ; enum UpdatedExistingType { NotUpdate, True, False } updatedExisting ;
/* todo: nObjects should be 64 bit */ /* todo: nObjects should be 64 bit */
long long nObjects; long long nObjects;
skipping to change at line 79 skipping to change at line 75
extern class LastErrorHolder { extern class LastErrorHolder {
public: public:
LastErrorHolder() : _id( 0 ) {} LastErrorHolder() : _id( 0 ) {}
LastError * get( bool create = false ); LastError * get( bool create = false );
LastError * _get( bool create = false ); // may return a disabled L astError LastError * _get( bool create = false ); // may return a disabled L astError
void reset( LastError * le ); void reset( LastError * le );
/** ok to call more than once. */
void initThread();
/** /**
* id of 0 means should use thread local management * id of 0 means should use thread local management
*/ */
void setID( int id ); void setID( int id );
int getID(); int getID();
void remove( int id ); void remove( int id );
void release(); void release();
/** when db receives a message/request, call this */ /** when db receives a message/request, call this */
skipping to change at line 110 skipping to change at line 109
time_t time; time_t time;
LastError *lerr; LastError *lerr;
}; };
static mongo::mutex _idsmutex; static mongo::mutex _idsmutex;
map<int,Status> _ids; map<int,Status> _ids;
} lastError; } lastError;
inline void raiseError(int code , const char *msg) { inline void raiseError(int code , const char *msg) {
LastError *le = lastError.get(); LastError *le = lastError.get();
if ( le == 0 ) { if ( le == 0 ) {
DEV log() << "warning: lastError==0 can't report:" << msg << '\ /* might be intentional (non-user thread) */
n'; DEV log() << "warning dev: lastError==0 won't report:" << msg <
< endl;
} else if ( le->disabled ) { } else if ( le->disabled ) {
log() << "lastError disabled, can't report: " << msg << endl; log() << "lastError disabled, can't report: " << msg << endl;
} else { } else {
le->raiseError(code, msg); le->raiseError(code, msg);
} }
} }
inline void recordUpdate( bool updatedExisting, int nChanged ) { inline void recordUpdate( bool updatedExisting, int nChanged ) {
LastError *le = lastError.get(); LastError *le = lastError.get();
if ( le ) if ( le )
 End of changes. 3 change blocks. 
6 lines changed or deleted 6 lines changed or added


 list.h   list.h 
skipping to change at line 26 skipping to change at line 26
* 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 {
/* this class uses a mutex for writes, but not for reads. /* this class uses a mutex for writes, but not for reads.
we can get fancier later... we can get fancier later...
struct MemberInfo : public List1<MemberInfo>::Base { struct Member : public List1<Member>::Base {
const char *host; const char *host;
int port; int port;
}; };
List1<MemberInfo> _members; List1<Member> _members;
_members.head()->next(); _members.head()->next();
*/ */
template<typename T> template<typename T>
class List1 : boost::noncopyable{ class List1 : boost::noncopyable {
public: public:
/* next() and head() return 0 at end of list */ /* next() and head() return 0 at end of list */
List1() : _head(0), _m("List1"), _orphans(0) { }
class Base { class Base {
friend class List1; friend class List1;
T *_next; T *_next;
public: public:
T* next() const { return _next; } T* next() const { return _next; }
}; };
T* head() const { return _head; } T* head() const { return _head; }
void push(T* t) { void push(T* t) {
boost::mutex::scoped_lock lk(_m); scoped_lock lk(_m);
t->_next = _head; t->_next = _head;
_head = t; _head = t; }
}
/* t is not deleted, but is removed from the list. (orphaned) */ /* t is not deleted, but is removed from the list. (orphaned) */
void orphan(T* t) { void orphan(T* t) {
boost::mutex::scoped_lock lk(_m); scoped_lock lk(_m);
T *&prev = _head; T *&prev = _head;
T *n = prev; T *n = prev;
while( n != t ) { while( n != t ) {
prev = n->_next; prev = n->_next;
n = prev; n = prev;
} }
prev = t->_next; prev = t->_next;
if( ++_orphans > 500 ) if( ++_orphans > 500 )
log() << "warning orphans=" << _orphans << '\n'; log() << "warning orphans=" << _orphans << '\n';
} }
List1() : _head(0), _orphans(0) { }
private: private:
T *_head; T *_head;
boost::mutex _m; mutex _m;
int _orphans; int _orphans;
}; };
}; };
 End of changes. 9 change blocks. 
10 lines changed or deleted 9 lines changed or added


 locks.h   locks.h 
skipping to change at line 23 skipping to change at line 23
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Lice nse * You should have received a copy of the GNU Affero General Public Lice nse
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//#include "../pch.h" //#include "../pch.h"
#pragma once #pragma once
#if defined(_WIN32)
#if BOOST_VERSION >= 103500 #if BOOST_VERSION >= 103500
#include <boost/thread/shared_mutex.hpp> #define BOOST_RWLOCK
#undef assert
#define assert MONGO_assert
#else #else
#error need boost >= 1.35 for windows
#endif
#define BOOST_RWLOCK #if defined(_WIN32)
#error need boost >= 1.35 for windows
#endif
#else #include <pthread.h>
#include <pthread.h> #endif
#ifdef BOOST_RWLOCK
#include <boost/thread/shared_mutex.hpp>
#undef assert
#define assert MONGO_assert
#endif #endif
namespace mongo { namespace mongo {
#ifdef BOOST_RWLOCK #ifdef BOOST_RWLOCK
class RWLock { class RWLock {
boost::shared_mutex _m; boost::shared_mutex _m;
public: public:
void lock(){ void lock(){
 End of changes. 7 change blocks. 
10 lines changed or deleted 10 lines changed or added


 log.h   log.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 <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include "../bson/util/builder.h"
#ifndef _WIN32
//#include <syslog.h>
#endif
namespace mongo { namespace mongo {
using boost::shared_ptr; using boost::shared_ptr;
// Utility interface for stringifying object only when val() called. // Utility interface for stringifying object only when val() called.
class LazyString { class LazyString {
public: public:
virtual ~LazyString() {} virtual ~LazyString() {}
virtual string val() const = 0; virtual string val() const = 0;
skipping to change at line 44 skipping to change at line 49
// Utility class for stringifying object only when val() called. // Utility class for stringifying object only when val() called.
template< class T > template< class T >
class LazyStringImpl : public LazyString { class LazyStringImpl : public LazyString {
public: public:
LazyStringImpl( const T &t ) : t_( t ) {} LazyStringImpl( const T &t ) : t_( t ) {}
virtual string val() const { return (string)t_; } virtual string val() const { return (string)t_; }
private: private:
const T& t_; const T& t_;
}; };
class Tee {
public:
virtual ~Tee(){}
virtual void write(const string& str) = 0;
};
class Nullstream { class Nullstream {
public: public:
virtual Nullstream& operator<< (Tee* tee) {
return *this;
}
virtual ~Nullstream() {} virtual ~Nullstream() {}
virtual Nullstream& operator<<(const char *) { virtual Nullstream& operator<<(const char *) {
return *this; return *this;
} }
virtual Nullstream& operator<<(char *) { virtual Nullstream& operator<<(char *) {
return *this; return *this;
} }
virtual Nullstream& operator<<(char) { virtual Nullstream& operator<<(char) {
return *this; return *this;
} }
skipping to change at line 114 skipping to change at line 128
template< class T > template< class T >
Nullstream& operator<<(const T &t) { Nullstream& operator<<(const T &t) {
return operator<<( static_cast<const LazyString&>( LazyStringIm pl< T >( t ) ) ); return operator<<( static_cast<const LazyString&>( LazyStringIm pl< T >( t ) ) );
} }
virtual Nullstream& operator<< (ostream& ( *endl )(ostream&)) { virtual Nullstream& operator<< (ostream& ( *endl )(ostream&)) {
return *this; return *this;
} }
virtual Nullstream& operator<< (ios_base& (*hex)(ios_base&)) { virtual Nullstream& operator<< (ios_base& (*hex)(ios_base&)) {
return *this; return *this;
} }
virtual void flush(){} virtual void flush(Tee *t = 0) {}
}; };
extern Nullstream nullstream; extern Nullstream nullstream;
class Logstream : public Nullstream { class Logstream : public Nullstream {
static mongo::mutex mutex; static mongo::mutex mutex;
static int doneSetup; static int doneSetup;
stringstream ss; stringstream ss;
public: public:
static int magicNumber(){ static int magicNumber(){
return 1717; return 1717;
} }
void flush() { void flush(Tee *t = 0) {
// this ensures things are sane // this ensures things are sane
if ( doneSetup == 1717 ){ if ( doneSetup == 1717 ) {
BufBuilder b(512);
time_t_to_String( time(0) , b.grow(20) );
b.append( ss.str() );
const char *s = b.buf();
scoped_lock lk(mutex); scoped_lock lk(mutex);
cout << ss.str();
if( t ) t->write(s);
#ifndef _WIN32
//syslog( LOG_INFO , "%s" , cc );
#endif
cout << s;
cout.flush(); cout.flush();
} }
ss.str(""); _init();
} }
/** note these are virtual */ /** note these are virtual */
Logstream& operator<<(const char *x) { ss << x; return *this; } Logstream& operator<<(const char *x) { ss << x; return *this; }
Logstream& operator<<(char *x) { ss << x; return *this; } Logstream& operator<<(char *x) { ss << x; return *this; }
Logstream& operator<<(char x) { ss << x; return *this; } Logstream& operator<<(char x) { ss << x; return *this; }
Logstream& operator<<(int x) { ss << x; return *this; } Logstream& operator<<(int x) { ss << x; return *this; }
Logstream& operator<<(ExitCode x) { ss << x; return *this; } Logstream& operator<<(ExitCode x) { ss << x; return *this; }
Logstream& operator<<(long x) { ss << x; return *this; } Logstream& operator<<(long x) { ss << x; return *this; }
Logstream& operator<<(unsigned long x) { ss << x; return *this; } Logstream& operator<<(unsigned long x) { ss << x; return *this; }
skipping to change at line 156 skipping to change at line 180
Logstream& operator<<(void *x) { ss << x; return *this; } Logstream& operator<<(void *x) { ss << x; return *this; }
Logstream& operator<<(const void *x) { ss << x; return *this; } Logstream& operator<<(const void *x) { ss << x; return *this; }
Logstream& operator<<(long long x) { ss << x; return *this; } Logstream& operator<<(long long x) { ss << x; return *this; }
Logstream& operator<<(unsigned long long x) { ss << x; return *this ; } Logstream& operator<<(unsigned long long x) { ss << x; return *this ; }
Logstream& operator<<(bool x) { ss << x; return *this ; } Logstream& operator<<(bool x) { ss << x; return *this ; }
Logstream& operator<<(const LazyString& x) { Logstream& operator<<(const LazyString& x) {
ss << x.val(); ss << x.val();
return *this; return *this;
} }
Nullstream& operator<< (Tee* tee) {
ss << '\n';
flush(tee);
return *this;
}
Logstream& operator<< (ostream& ( *_endl )(ostream&)) { Logstream& operator<< (ostream& ( *_endl )(ostream&)) {
ss << '\n'; ss << '\n';
flush(); flush(0);
return *this; return *this;
} }
Logstream& operator<< (ios_base& (*_hex)(ios_base&)) { Logstream& operator<< (ios_base& (*_hex)(ios_base&)) {
ss << _hex; ss << _hex;
return *this; return *this;
} }
template< class T > template< class T >
Nullstream& operator<<(const shared_ptr<T> p ){ Nullstream& operator<<(const shared_ptr<T> p ){
T * t = p.get(); T * t = p.get();
if ( ! t ) if ( ! t )
*this << "null"; *this << "null";
else else
*this << t; *this << *t;
return *this; return *this;
} }
Logstream& prolog() { Logstream& prolog() {
char now[64];
time_t_to_String(time(0), now);
now[20] = 0;
ss << now;
return *this; return *this;
} }
private: private:
static thread_specific_ptr<Logstream> tsp; static thread_specific_ptr<Logstream> tsp;
Logstream(){
_init();
}
void _init(){
ss.str("");
}
public: public:
static Logstream& get() { static Logstream& get() {
Logstream *p = tsp.get(); Logstream *p = tsp.get();
if( p == 0 ) if( p == 0 )
tsp.reset( p = new Logstream() ); tsp.reset( p = new Logstream() );
return *p; return *p;
} }
}; };
extern int logLevel; extern int logLevel;
extern int tlogLevel;
inline Nullstream& out( int level = 0 ) { inline Nullstream& out( int level = 0 ) {
if ( level > logLevel ) if ( level > logLevel )
return nullstream; return nullstream;
return Logstream::get(); return Logstream::get();
} }
/* flush the log stream if the log level is /* flush the log stream if the log level is
at the specified level or higher. */ at the specified level or higher. */
inline void logflush(int level = 0) { inline void logflush(int level = 0) {
if( level > logLevel ) if( level > logLevel )
Logstream::get().flush(); Logstream::get().flush(0);
} }
/* without prolog */ /* without prolog */
inline Nullstream& _log( int level = 0 ){ inline Nullstream& _log( int level = 0 ){
if ( level > logLevel ) if ( level > logLevel )
return nullstream; return nullstream;
return Logstream::get(); return Logstream::get();
} }
inline Nullstream& log( int level = 0 ) { /** logging which we may not want during unit tests runs.
set tlogLevel to -1 to suppress tlog() output in a test program. */
inline Nullstream& tlog( int level = 0 ) {
if ( level > tlogLevel || level > logLevel )
return nullstream;
return Logstream::get().prolog();
}
inline Nullstream& log( int level ) {
if ( level > logLevel ) if ( level > logLevel )
return nullstream; return nullstream;
return Logstream::get().prolog(); return Logstream::get().prolog();
} }
inline Nullstream& log() {
return Logstream::get().prolog();
}
/* TODOCONCURRENCY */ /* TODOCONCURRENCY */
inline ostream& stdcout() { inline ostream& stdcout() {
return cout; return cout;
} }
/* default impl returns "" -- mongod overrides */ /* default impl returns "" -- mongod overrides */
extern const char * (*getcurns)(); extern const char * (*getcurns)();
inline Nullstream& problem( int level = 0 ) { inline Nullstream& problem( int level = 0 ) {
if ( level > logLevel ) if ( level > logLevel )
 End of changes. 17 change blocks. 
13 lines changed or deleted 57 lines changed or added


 matcher.h   matcher.h 
skipping to change at line 155 skipping to change at line 155
bool keyMatch() const { return !all && !haveSize && !hasArray && !h aveNeg && _orMatchers.size() == 0; } bool keyMatch() const { return !all && !haveSize && !hasArray && !h aveNeg && _orMatchers.size() == 0; }
bool atomic() const { return _atomic; } bool atomic() const { return _atomic; }
bool hasType( BSONObj::MatchType type ) const; bool hasType( BSONObj::MatchType type ) const;
string toString() const { string toString() const {
return jsobj.toString(); return jsobj.toString();
} }
// void popOr() {
// massert( 13261, "no or to pop", !_orMatchers.empty() );
// _norMatchers.push_back( _orMatchers.front() );
// _orMatchers.pop_front();
// }
private: private:
void addBasic(const BSONElement &e, int c, bool isNot) { void addBasic(const BSONElement &e, int c, bool isNot) {
// TODO May want to selectively ignore these element types base d on op type. // TODO May want to selectively ignore these element types base d on op type.
if ( e.type() == MinKey || e.type() == MaxKey ) if ( e.type() == MinKey || e.type() == MaxKey )
return; return;
basics.push_back( ElementMatcher( e , c, isNot ) ); basics.push_back( ElementMatcher( e , c, isNot ) );
} }
void addRegex(const char *fieldName, const char *regex, const char *flags, bool isNot = false); void addRegex(const char *fieldName, const char *regex, const char *flags, bool isNot = false);
bool addOp( const BSONElement &e, const BSONElement &fe, bool isNot , const char *& regex, const char *&flags ); bool addOp( const BSONElement &e, const BSONElement &fe, bool isNot , const char *& regex, const char *&flags );
int valuesMatch(const BSONElement& l, const BSONElement& r, int op, const ElementMatcher& bm); int valuesMatch(const BSONElement& l, const BSONElement& r, int op, const ElementMatcher& bm);
bool parseOrNor( const BSONElement &e, bool subMatcher ); bool parseOrNor( const BSONElement &e, bool subMatcher );
void parseOr( const BSONElement &e, bool subMatcher, vector< shared _ptr< Matcher > > &matchers ); void parseOr( const BSONElement &e, bool subMatcher, list< shared_p tr< Matcher > > &matchers );
Where *where; // set if query uses $where Where *where; // set if query uses $where
BSONObj jsobj; // the query pattern. e.g., { name : "joe" } BSONObj jsobj; // the query pattern. e.g., { name : "joe" }
BSONObj constrainIndexKey_; BSONObj constrainIndexKey_;
vector<ElementMatcher> basics; vector<ElementMatcher> basics;
bool haveSize; bool haveSize;
bool all; bool all;
bool hasArray; bool hasArray;
bool haveNeg; bool haveNeg;
skipping to change at line 192 skipping to change at line 198
i.e. we stay locked the whole time. i.e. we stay locked the whole time.
http://www.mongodb.org/display/DOCS/Removing[ http://www.mongodb.org/display/DOCS/Removing[
*/ */
bool _atomic; bool _atomic;
RegexMatcher regexs[4]; RegexMatcher regexs[4];
int nRegex; int nRegex;
// so we delete the mem when we're done: // so we delete the mem when we're done:
vector< shared_ptr< BSONObjBuilder > > _builders; vector< shared_ptr< BSONObjBuilder > > _builders;
vector< shared_ptr< Matcher > > _orMatchers; list< shared_ptr< Matcher > > _orMatchers;
vector< shared_ptr< Matcher > > _norMatchers; list< shared_ptr< Matcher > > _norMatchers;
friend class CoveredIndexMatcher; friend class CoveredIndexMatcher;
}; };
// If match succeeds on index key, then attempt to match full document. // If match succeeds on index key, then attempt to match full document.
class CoveredIndexMatcher : boost::noncopyable { class CoveredIndexMatcher : boost::noncopyable {
public: public:
CoveredIndexMatcher(const BSONObj &pattern, const BSONObj &indexKey Pattern); CoveredIndexMatcher(const BSONObj &pattern, const BSONObj &indexKey Pattern , bool alwaysUseRecord=false );
bool matches(const BSONObj &o){ return _docMatcher.matches( o ); } bool matches(const BSONObj &o){ return _docMatcher.matches( o ); }
bool matches(const BSONObj &key, const DiskLoc &recLoc , MatchDetai ls * details = 0 ); bool matches(const BSONObj &key, const DiskLoc &recLoc , MatchDetai ls * details = 0 );
bool matchesCurrent( Cursor * cursor , MatchDetails * details = 0 ) ; bool matchesCurrent( Cursor * cursor , MatchDetails * details = 0 ) ;
bool needRecord(){ return _needRecord; } bool needRecord(){ return _needRecord; }
Matcher& docMatcher() { return _docMatcher; } Matcher& docMatcher() { return _docMatcher; }
private: private:
Matcher _keyMatcher; Matcher _keyMatcher;
Matcher _docMatcher; Matcher _docMatcher;
bool _needRecord; bool _needRecord;
 End of changes. 4 change blocks. 
4 lines changed or deleted 10 lines changed or added


 message.h   message.h 
skipping to change at line 93 skipping to change at line 93
bool call(Message& toSend, Message& response); bool call(Message& toSend, Message& response);
void say(Message& toSend, int responseTo = -1); void say(Message& toSend, int responseTo = -1);
void piggyBack( Message& toSend , int responseTo = -1 ); void piggyBack( Message& toSend , int responseTo = -1 );
virtual unsigned remotePort() const; virtual unsigned remotePort() const;
virtual HostAndPort remote() const; virtual HostAndPort remote() const;
// send len or throw SocketException // send len or throw SocketException
void send( const char * data , int len, const char *context ); void send( const char * data , int len, const char *context );
void send( const vector< pair< char *, int > > &data, const char *c
ontext );
// recv len or throw SocketException // recv len or throw SocketException
void recv( char * data , int len ); void recv( char * data , int len );
int unsafe_recv( char *buf, int max ); int unsafe_recv( char *buf, int max );
private: private:
int sock; int sock;
PiggyBackData * piggyBackData; PiggyBackData * piggyBackData;
public: public:
SockAddr farEnd; SockAddr farEnd;
int _timeout; int _timeout;
skipping to change at line 179 skipping to change at line 181
}; };
const int MsgDataHeaderSize = sizeof(MsgData) - 4; const int MsgDataHeaderSize = sizeof(MsgData) - 4;
inline int MsgData::dataLen() { inline int MsgData::dataLen() {
return len - MsgDataHeaderSize; return len - MsgDataHeaderSize;
} }
#pragma pack() #pragma pack()
class Message { class Message {
public: public:
Message() { // we assume here that a vector with initial size 0 does no allocat
data = 0; ion (0 is the default, but wanted to make it explicit).
freeIt = false; Message() : _buf( 0 ), _data( 0 ), _freeIt( false ) {}
} Message( void * data , bool freeIt ) :
Message( void * _data , bool _freeIt ) { _buf( 0 ), _data( 0 ), _freeIt( false ) {
data = (MsgData*)_data; _setData( reinterpret_cast< MsgData* >( data ), freeIt );
freeIt = _freeIt;
}; };
Message(Message& r) : _buf( 0 ), _data( 0 ), _freeIt( false ) {
*this = r;
}
~Message() { ~Message() {
reset(); reset();
} }
SockAddr from; SockAddr _from;
MsgData *data;
int operation() const { MsgData *header() const {
return data->operation(); assert( !empty() );
return _buf ? _buf : reinterpret_cast< MsgData* > ( _data[ 0 ].
first );
}
int operation() const { return header()->operation(); }
MsgData *singleData() const {
massert( 13273, "single data buffer expected", _buf );
return header();
} }
bool empty() const { return !_buf && _data.empty(); }
// concat multiple buffers - noop if <2 buffers already, otherwise
can be expensive copy
// can get rid of this if we make response handling smarter
void concat() {
if ( _buf || empty() ) {
return;
}
assert( _freeIt );
int totalSize = 0;
for( vector< pair< char *, int > >::const_iterator i = _data.be
gin(); i != _data.end(); ++i ) {
totalSize += i->second;
}
char *buf = (char*)malloc( totalSize );
char *p = buf;
for( vector< pair< char *, int > >::const_iterator i = _data.be
gin(); i != _data.end(); ++i ) {
memcpy( p, i->first, i->second );
p += i->second;
}
reset();
_setData( (MsgData*)buf, true );
}
// vector swap() so this is fast
Message& operator=(Message& r) { Message& operator=(Message& r) {
assert( data == 0 ); assert( empty() );
data = r.data; assert( r._freeIt );
assert( r.freeIt ); _buf = r._buf;
r.freeIt = false; r._buf = 0;
r.data = 0; if ( r._data.size() > 0 ) {
freeIt = true; _data.swap( r._data );
}
r._freeIt = false;
_freeIt = true;
return *this; return *this;
} }
void reset() { void reset() {
if ( freeIt && data ) if ( _freeIt ) {
free(data); if ( _buf ) {
data = 0; free( _buf );
freeIt = false; }
for( vector< pair< char *, int > >::const_iterator i = _dat
a.begin(); i != _data.end(); ++i ) {
free(i->first);
}
}
_buf = 0;
_data.clear();
_freeIt = false;
} }
void setData(MsgData *d, bool _freeIt) { // use to add a buffer
assert( data == 0 ); // assumes message will free everything
freeIt = _freeIt; void appendData(char *d, int size) {
data = d; if ( size <= 0 ) {
return;
}
if ( empty() ) {
MsgData *md = (MsgData*)d;
md->len = size; // can be updated later if more buffers add
ed
_setData( md, true );
return;
}
assert( _freeIt );
if ( _buf ) {
_data.push_back( make_pair( (char*)_buf, _buf->len ) );
_buf = 0;
}
_data.push_back( make_pair( d, size ) );
header()->len += size;
}
// use to set first buffer if empty
void setData(MsgData *d, bool freeIt) {
assert( empty() );
_setData( d, freeIt );
} }
void setData(int operation, const char *msgtxt) { void setData(int operation, const char *msgtxt) {
setData(operation, msgtxt, strlen(msgtxt)+1); setData(operation, msgtxt, strlen(msgtxt)+1);
} }
void setData(int operation, const char *msgdata, size_t len) { void setData(int operation, const char *msgdata, size_t len) {
assert(data == 0); assert( empty() );
size_t dataLen = len + sizeof(MsgData) - 4; size_t dataLen = len + sizeof(MsgData) - 4;
MsgData *d = (MsgData *) malloc(dataLen); MsgData *d = (MsgData *) malloc(dataLen);
memcpy(d->_data, msgdata, len); memcpy(d->_data, msgdata, len);
d->len = fixEndian(dataLen); d->len = fixEndian(dataLen);
d->setOperation(operation); d->setOperation(operation);
freeIt= true; _setData( d, true );
data = d;
} }
bool doIFreeIt() { bool doIFreeIt() {
return freeIt; return _freeIt;
}
void send( MessagingPort &p, const char *context ) {
if ( empty() ) {
return;
}
if ( _buf != 0 ) {
p.send( (char*)_buf, _buf->len, context );
} else {
p.send( _data, context );
}
} }
private: private:
bool freeIt; void _setData( MsgData *d, bool freeIt ) {
_freeIt = freeIt;
_buf = d;
}
// if just one buffer, keep it in _buf, otherwise keep a sequence o
f buffers in _data
MsgData * _buf;
// byte buffer(s) - the first must contain at least a full MsgData
unless using _buf for storage instead
vector< pair< char*, int > > _data;
bool _freeIt;
}; };
class SocketException : public DBException { class SocketException : public DBException {
public: public:
virtual const char* what() const throw() { return "socket exception "; } virtual const char* what() const throw() { return "socket exception "; }
virtual int getCode(){ return 9001; } virtual int getCode() const { return 9001; }
}; };
MSGID nextMessageId(); MSGID nextMessageId();
void setClientId( int id ); void setClientId( int id );
int getClientId(); int getClientId();
extern TicketHolder connTicketHolder; extern TicketHolder connTicketHolder;
} // namespace mongo } // namespace mongo
 End of changes. 14 change blocks. 
31 lines changed or deleted 124 lines changed or added


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


 mmap.h   mmap.h 
skipping to change at line 23 skipping to change at line 23
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
namespace mongo { namespace mongo {
/* the administrative-ish stuff here */ /* the administrative-ish stuff here */
class MongoFile { class MongoFile : boost::noncopyable {
protected: protected:
virtual void close() = 0; virtual void close() = 0;
virtual void flush(bool sync) = 0; virtual void flush(bool sync) = 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 */
public: public:
virtual ~MongoFile() {}
virtual long length() = 0; virtual long length() = 0;
enum Options { enum Options {
SEQUENTIAL = 1 // hint - e.g. FILE_FLAG_SEQUENTIAL_SCAN on wind ows SEQUENTIAL = 1 // hint - e.g. FILE_FLAG_SEQUENTIAL_SCAN on wind ows
}; };
virtual ~MongoFile() {}
static int flushAll( bool sync ); // returns n flushed static int flushAll( bool sync ); // returns n flushed
static long long totalMappedLength(); static long long totalMappedLength();
static void closeAllFiles( stringstream &message ); static void closeAllFiles( stringstream &message );
/* can be "overriden" if necessary */ /* can be "overriden" if necessary */
static bool exists(boost::filesystem::path p) { static bool exists(boost::filesystem::path p) {
return boost::filesystem::exists(p); return boost::filesystem::exists(p);
} }
}; };
class MFTemplate : public MongoFile { /** template for what a new storage engine's class definition must impl
ement
PRELIMINARY - subject to change.
*/
class StorageContainerTemplate : public MongoFile {
protected: protected:
virtual void close(); virtual void close();
virtual void flush(bool sync); virtual void flush(bool sync);
public: public:
virtual long length(); virtual long length();
/** pointer to a range of space in this storage unit */
class Pointer { class Pointer {
public: public:
/** retried address of buffer at offset 'offset' withing the st
orage unit. returned range is a contiguous
buffer reflecting what is in storage. caller will not read
or write past 'len'.
note calls may be received that are at different points in
a range and different lengths. however
for now assume that on writes, if a call is made, previousl
y returned addresses are no longer valid. i.e.
p = at(10000, 500);
q = at(10000, 600);
after the second call it is ok if p is invalid.
*/
void* at(int offset, int len); void* at(int offset, int len);
void grow(int offset, int len);
/** indicate that we wrote to the range (from a previous at() c
all) and that it needs
flushing to disk.
*/
void written(int offset, int len);
bool isNull() const; bool isNull() const;
}; };
Pointer map( const char *filename ); /** commit written() calls from above. */
Pointer map(const char *_filename, long &length, int options=0); void commit();
Pointer open(const char *filename);
Pointer open(const char *_filename, long &length, int options=0);
}; };
class MemoryMappedFile : public MongoFile { class MemoryMappedFile : public MongoFile {
public: public:
class Pointer { class Pointer {
char *_base; char *_base;
public: public:
Pointer() : _base(0) { } Pointer() : _base(0) { }
Pointer(void *p) : _base((char*) p) { } Pointer(void *p) : _base((char*) p) { }
void* at(int offset, int maxLen) { return _base + offset; } void* at(int offset, int maxLen) { return _base + offset; }
skipping to change at line 88 skipping to change at line 108
MemoryMappedFile(); MemoryMappedFile();
~MemoryMappedFile() { ~MemoryMappedFile() {
destroyed(); destroyed();
close(); close();
} }
void close(); void close();
// Throws exception if file doesn't exist. (dm may2010: not sure if this is always true?) // Throws exception if file doesn't exist. (dm may2010: not sure if this is always true?)
void* map( const char *filename ); void* map( const char *filename );
/*Pointer pmap( const char *filename ) {
/*To replace map():
Pointer open( const char *filename ) {
void *p = map(filename); void *p = map(filename);
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 );
skipping to change at line 116 skipping to change at line 139
return len; return len;
} }
private: private:
static void updateLength( const char *filename, long &length ); static void updateLength( const char *filename, long &length );
HANDLE fd; HANDLE fd;
HANDLE maphandle; HANDLE maphandle;
void *view; void *view;
long len; long len;
string _filename;
}; };
void printMemInfo( const char * where ); void printMemInfo( const char * where );
#include "ramstore.h" #include "ramstore.h"
//#define _RAMSTORE //#define _RAMSTORE
#if defined(_RAMSTORE) #if defined(_RAMSTORE)
typedef RamStoreFile MMF; typedef RamStoreFile MMF;
#else #else
 End of changes. 10 change blocks. 
8 lines changed or deleted 38 lines changed or added


 namespace.h   namespace.h 
skipping to change at line 30 skipping to change at line 30
#include "../pch.h" #include "../pch.h"
#include "jsobj.h" #include "jsobj.h"
#include "queryutil.h" #include "queryutil.h"
#include "diskloc.h" #include "diskloc.h"
#include "../util/hashtab.h" #include "../util/hashtab.h"
#include "../util/mmap.h" #include "../util/mmap.h"
namespace mongo { namespace mongo {
class Cursor;
#pragma pack(1)
/* in the mongo source code, "client" means "database". */ /* in the mongo source code, "client" means "database". */
const int MaxDatabaseLen = 256; // max str len for the db name, includi ng null char const int MaxDatabaseLen = 256; // max str len for the db name, includi ng null char
// "database.a.b.c" -> "database" // "database.a.b.c" -> "database"
inline void nsToDatabase(const char *ns, char *database) { inline void nsToDatabase(const char *ns, char *database) {
const char *p = ns; const char *p = ns;
char *q = database; char *q = database;
while ( *p != '.' ) { while ( *p != '.' ) {
if ( *p == 0 ) if ( *p == 0 )
skipping to change at line 58 skipping to change at line 54
if (q-database>=MaxDatabaseLen) { if (q-database>=MaxDatabaseLen) {
log() << "nsToDatabase: ns too long. terminating, buf overrun c ondition" << endl; log() << "nsToDatabase: ns too long. terminating, buf overrun c ondition" << endl;
dbexit( EXIT_POSSIBLE_CORRUPTION ); dbexit( EXIT_POSSIBLE_CORRUPTION );
} }
} }
inline string nsToDatabase(const char *ns) { inline string nsToDatabase(const char *ns) {
char buf[MaxDatabaseLen]; char buf[MaxDatabaseLen];
nsToDatabase(ns, buf); nsToDatabase(ns, buf);
return buf; return buf;
} }
inline string nsToDatabase(const string& ns) {
size_t i = ns.find( '.' );
if ( i == string::npos )
return ns;
return ns.substr( 0 , i );
}
/* e.g. /* e.g.
NamespaceString ns("acme.orders"); NamespaceString ns("acme.orders");
cout << ns.coll; // "orders" cout << ns.coll; // "orders"
*/ */
class NamespaceString { class NamespaceString {
public: public:
string db; string db;
string coll; // note collection names can have periods in them for organizing purposes (e.g. "system.indexes") string coll; // note collection names can have periods in them for organizing purposes (e.g. "system.indexes")
private: private:
skipping to change at line 87 skipping to change at line 89
string ns() const { string ns() const {
return db + '.' + coll; return db + '.' + coll;
} }
bool isSystem() { bool isSystem() {
return strncmp(coll.c_str(), "system.", 7) == 0; return strncmp(coll.c_str(), "system.", 7) == 0;
} }
}; };
#pragma pack(1)
/* This helper class is used to make the HashMap below in NamespaceD etails */ /* This helper class is used to make the HashMap below in NamespaceD etails */
class Namespace { class Namespace {
public: public:
enum MaxNsLenValue { MaxNsLen = 128 }; enum MaxNsLenValue { MaxNsLen = 128 };
Namespace(const char *ns) { Namespace(const char *ns) {
*this = ns; *this = ns;
} }
Namespace& operator=(const char *ns) { Namespace& operator=(const char *ns) {
uassert( 10080 , "ns name too long, max size is 128", strlen(ns ) < MaxNsLen); uassert( 10080 , "ns name too long, max size is 128", strlen(ns ) < MaxNsLen);
//memset(buf, 0, MaxNsLen); /* this is just to keep stuff clean in the files for easy dumping and reading */ //memset(buf, 0, MaxNsLen); /* this is just to keep stuff clean in the files for easy dumping and reading */
strcpy_s(buf, MaxNsLen, ns); strcpy_s(buf, MaxNsLen, ns);
return *this; return *this;
} }
/* for more than 10 indexes -- see NamespaceDetails::Extra */ /* for more than 10 indexes -- see NamespaceDetails::Extra */
string extraName() { string extraName(int i) {
string s = string(buf) + "$extra"; char ex[] = "$extra";
massert( 10348 , "ns name too long", s.size() < MaxNsLen); ex[5] += i;
string s = string(buf) + ex;
massert( 10348 , "$extra: ns name too long", s.size() < MaxNsLe
n);
return s; return s;
} }
bool isExtra() const { bool isExtra() const {
const char *p = strstr(buf, "$extra"); const char *p = strstr(buf, "$extr");
return p && p[6] == 0; //==0 important in case an index uses na return p && p[5] && p[6] == 0; //==0 important in case an index
me "$extra_1" for example uses name "$extra_1" for example
}
bool hasDollarSign() const {
return strstr( buf , "$" ) > 0;
}
void kill() {
buf[0] = 0x7f;
}
bool operator==(const char *r) {
return strcmp(buf, r) == 0;
}
bool operator==(const Namespace& r) {
return strcmp(buf, r.buf) == 0;
} }
bool hasDollarSign() const { return strchr( buf , '$' ) > 0; }
void kill() { buf[0] = 0x7f; }
bool operator==(const char *r) const { return strcmp(buf, r) == 0;
}
bool operator==(const Namespace& r) const { return strcmp(buf, r.bu
f) == 0; }
int hash() const { int hash() const {
unsigned x = 0; unsigned x = 0;
const char *p = buf; const char *p = buf;
while ( *p ) { while ( *p ) {
x = x * 131 + *p; x = x * 131 + *p;
p++; p++;
} }
return (x & 0x7fffffff) | 0x8000000; // must be > 0 return (x & 0x7fffffff) | 0x8000000; // must be > 0
} }
skipping to change at line 153 skipping to change at line 148
old = old.substr( 0 , old.find( "." ) ); old = old.substr( 0 , old.find( "." ) );
return old + "." + local; return old + "." + local;
} }
operator string() const { operator string() const {
return (string)buf; return (string)buf;
} }
char buf[MaxNsLen]; char buf[MaxNsLen];
}; };
#pragma pack()
} } // namespace mongo
#include "index.h" #include "index.h"
namespace mongo { namespace mongo {
/** /** @return true if a client can modify this namespace
@return true if a client can modify this namespace things like *.system.users */
things like *.system.users
*/
bool legalClientSystemNS( const string& ns , bool write ); bool legalClientSystemNS( const string& ns , bool write );
/* deleted lists -- linked lists of deleted records -- are placed in 'b uckets' of various sizes /* deleted lists -- linked lists of deleted records -- are placed in 'b uckets' of various sizes
so you can look for a deleterecord about the right size. so you can look for a deleterecord about the right size.
*/ */
const int Buckets = 19; const int Buckets = 19;
const int MaxBucket = 18; const int MaxBucket = 18;
extern int bucketSizes[]; extern int bucketSizes[];
#pragma pack(1)
/* this is the "header" for a collection that has all its details. in the .ns file. /* this is the "header" for a collection that has all its details. in the .ns file.
*/ */
class NamespaceDetails { class NamespaceDetails {
friend class NamespaceIndex; friend class NamespaceIndex;
enum { NIndexesExtra = 30, enum { NIndexesExtra = 30,
NIndexesBase = 10 NIndexesBase = 10
}; };
struct Extra { public:
struct ExtraOld {
// note we could use this field for more chaining later, so don 't waste it: // note we could use this field for more chaining later, so don 't waste it:
unsigned long long reserved1; unsigned long long reserved1;
IndexDetails details[NIndexesExtra]; IndexDetails details[NIndexesExtra];
unsigned reserved2; unsigned reserved2;
unsigned reserved3; unsigned reserved3;
}; };
class Extra {
long long _next;
public:
IndexDetails details[NIndexesExtra];
private:
unsigned reserved2;
unsigned reserved3;
Extra(const Extra&) { assert(false); }
Extra& operator=(const Extra& r) { assert(false); re
turn *this; }
public:
Extra() { }
long ofsFrom(NamespaceDetails *d) {
return ((char *) this) - ((char *) d);
}
void init() { memset(this, 0, sizeof(Extra)); }
Extra* next(NamespaceDetails *d) {
if( _next == 0 ) return 0;
return (Extra*) (((char *) d) + _next);
}
void setNext(long ofs) { _next = ofs; }
void copy(NamespaceDetails *d, const Extra& e) {
memcpy(this, &e, sizeof(Extra));
_next = 0;
}
}; // Extra
Extra* extra() { Extra* extra() {
assert( extraOffset ); if( extraOffset == 0 ) return 0;
return (Extra *) (((char *) this) + extraOffset); return (Extra *) (((char *) this) + extraOffset);
} }
public: public:
/* add extra space for indexes when more than 10 */
Extra* allocExtra(const char *ns, int nindexessofar);
void copyingFrom(const char *thisns, NamespaceDetails *src); // mus t be called when renaming a NS to fix up extra void copyingFrom(const char *thisns, NamespaceDetails *src); // mus t be called when renaming a NS to fix up extra
enum { NIndexesMax = 40 }; enum { NIndexesMax = 64 };
BOOST_STATIC_ASSERT( NIndexesMax == NIndexesBase + NIndexesExtra ); BOOST_STATIC_ASSERT( NIndexesMax <= NIndexesBase + NIndexesExtra*2
);
BOOST_STATIC_ASSERT( NIndexesMax <= 64 ); // multiKey bits
BOOST_STATIC_ASSERT( sizeof(NamespaceDetails::ExtraOld) == 4
96 );
BOOST_STATIC_ASSERT( sizeof(NamespaceDetails::Extra) == 496
);
/* 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 );
/* be sure to initialize new fields here -- doesn't default to
zeroes the way we use it */
firstExtent = lastExtent = capExtent = loc;
datasize = nrecords = 0;
lastExtentSize = 0;
nIndexes = 0;
capped = _capped;
max = 0x7fffffff;
paddingFactor = 1.0;
flags = 0;
capFirstNewRecord = DiskLoc();
// Signal that we are on first allocation iteration through ext
ents.
capFirstNewRecord.setInvalid();
// For capped case, signal that we are doing initial extent all
ocation.
if ( capped )
deletedList[ 1 ].setInvalid();
assert( sizeof(dataFileVersion) == 2 );
dataFileVersion = 0;
indexFileVersion = 0;
multiKeyIndexBits = 0;
reservedA = 0;
extraOffset = 0;
backgroundIndexBuildInProgress = 0;
memset(reserved, 0, sizeof(reserved));
}
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 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.
*/ */
skipping to change at line 270 skipping to change at line 276
private: private:
unsigned long long reservedA; unsigned long long reservedA;
long long extraOffset; // where the $extra info is located (bytes r elative to this) long long extraOffset; // where the $extra info is located (bytes r elative to this)
public: public:
int backgroundIndexBuildInProgress; // 1 if in prog int backgroundIndexBuildInProgress; // 1 if in prog
char reserved[76]; char reserved[76];
/* when a background index build is in progress, we don't count the index in nIndexes until /* when a background index build is in progress, we don't count the index in nIndexes until
complete, yet need to still use it in _indexRecord() - thus we u se this function for that. complete, yet need to still use it in _indexRecord() - thus we u se this function for that.
*/ */
int nIndexesBeingBuilt() const { int nIndexesBeingBuilt() const { return nIndexes + backgroundIndexB
return nIndexes + backgroundIndexBuildInProgress; uildInProgress; }
}
/* NOTE: be careful with flags. are we manipulating them in read l ocks? if so, /* NOTE: be careful with flags. are we manipulating them in read l ocks? if so,
this isn't thread safe. TODO this isn't thread safe. TODO
*/ */
enum NamespaceFlags { enum NamespaceFlags {
Flag_HaveIdIndex = 1 << 0, // set when we have _id index (ONLY if ensureIdIndex was called -- 0 if that has never been called) Flag_HaveIdIndex = 1 << 0, // set when we have _id index (ONLY if ensureIdIndex was called -- 0 if that has never been called)
Flag_CappedDisallowDelete = 1 << 1 // set when deletes not allo wed during capped table allocation. Flag_CappedDisallowDelete = 1 << 1 // set when deletes not allo wed during capped table allocation.
}; };
IndexDetails& idx(int idxNo) { IndexDetails& idx(int idxNo) {
if( idxNo < NIndexesBase ) if( idxNo < NIndexesBase )
return _indexes[idxNo]; return _indexes[idxNo];
return extra()->details[idxNo-NIndexesBase]; Extra *e = extra();
massert(13282, "missing Extra", e);
int i = idxNo - NIndexesBase;
if( i >= NIndexesExtra ) {
e = e->next(this);
massert(13283, "missing Extra", e);
i -= NIndexesExtra;
}
return e->details[i];
} }
IndexDetails& backgroundIdx() { IndexDetails& backgroundIdx() {
DEV assert(backgroundIndexBuildInProgress); DEV assert(backgroundIndexBuildInProgress);
return idx(nIndexes); return idx(nIndexes);
} }
class IndexIterator { class IndexIterator {
friend class NamespaceDetails; friend class NamespaceDetails;
int i; int i;
int n; int n;
NamespaceDetails *d; NamespaceDetails *d;
Extra *e;
IndexIterator(NamespaceDetails *_d) { IndexIterator(NamespaceDetails *_d) {
d = _d; d = _d;
i = 0; i = 0;
n = d->nIndexes; n = d->nIndexes;
if( n > NIndexesBase )
e = d->extra();
} }
public: public:
int pos() { return i; } // note this is the next one to come int pos() { return i; } // note this is the next one to come
bool more() { return i < n; } bool more() { return i < n; }
IndexDetails& next() { IndexDetails& next() { return d->idx(i++); }
int k = i; }; // IndexIterator
i++;
return k < NIndexesBase ? d->_indexes[k] :
e->details[k-10];
}
};
IndexIterator ii() { IndexIterator ii() { return IndexIterator(this); }
return IndexIterator(this);
}
/* hackish - find our index # in the indexes array /* hackish - find our index # in the indexes array
*/ */
int idxNo(IndexDetails& idx) { int idxNo(IndexDetails& idx) {
IndexIterator i = ii(); IndexIterator i = ii();
while( i.more() ) { while( i.more() ) {
if( &i.next() == &idx ) if( &i.next() == &idx )
return i.pos()-1; return i.pos()-1;
} }
massert( 10349 , "E12000 idxNo fails", false); massert( 10349 , "E12000 idxNo fails", false);
skipping to change at line 353 skipping to change at line 355
void clearIndexIsMultikey(int i) { void clearIndexIsMultikey(int i) {
dassert( i < NIndexesMax ); dassert( i < NIndexesMax );
multiKeyIndexBits &= ~(((unsigned long long) 1) << i); multiKeyIndexBits &= ~(((unsigned long long) 1) << i);
} }
/* add a new index. does not add to system.indexes etc. - just to NamespaceDetails. /* add a new index. does not add to system.indexes etc. - just to NamespaceDetails.
caller must populate returned object. caller must populate returned object.
*/ */
IndexDetails& addIndex(const char *thisns, bool resetTransient=true ); IndexDetails& addIndex(const char *thisns, bool resetTransient=true );
void aboutToDeleteAnIndex() { void aboutToDeleteAnIndex() { flags &= ~Flag_HaveIdIndex; }
flags &= ~Flag_HaveIdIndex;
}
void cappedDisallowDelete() { void cappedDisallowDelete() { flags |= Flag_CappedDisallowDelete; }
flags |= Flag_CappedDisallowDelete;
}
/* returns index of the first index in which the field is present. -1 if not present. */ /* returns index of the first index in which the field is present. -1 if not present. */
int fieldIsIndexed(const char *fieldName); int fieldIsIndexed(const char *fieldName);
void paddingFits() { void paddingFits() {
double x = paddingFactor - 0.01; double x = paddingFactor - 0.01;
if ( x >= 1.0 ) if ( x >= 1.0 )
paddingFactor = x; paddingFactor = x;
} }
void paddingTooSmall() { void paddingTooSmall() {
skipping to change at line 422 skipping to change at line 420
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
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; bool inCapExtent( const DiskLoc &dl ) const;
void checkMigrate(); void checkMigrate();
long long storageSize( int * numExtents = 0 ); long long storageSize( int * numExtents = 0 );
private: private:
bool cappedMayDelete() const { bool cappedMayDelete() const { return !( flags & Flag_CappedDisallo
return !( flags & Flag_CappedDisallowDelete ); wDelete ); }
} Extent *theCapExtent() const { return capExtent.ext(); }
Extent *theCapExtent() const {
return capExtent.ext();
}
void advanceCapExtent( const char *ns ); 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 __capAlloc(int len);
DiskLoc _alloc(const char *ns, int len); DiskLoc _alloc(const char *ns, int len);
void compact(); // combine adjacent deleted records void compact(); // combine adjacent deleted records
DiskLoc &firstDeletedInCapExtent(); DiskLoc &firstDeletedInCapExtent();
bool nextIsInCapExtent( const DiskLoc &dl ) const; bool nextIsInCapExtent( const DiskLoc &dl ) const;
}; }; // NamespaceDetails
#pragma pack() #pragma pack()
/* these are things we know / compute about a namespace that are transi /* NamespaceDetailsTransient
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.
todo: cleanup code, need abstractions and separation todo: cleanup code, need abstractions and separation
*/ */
class NamespaceDetailsTransient : boost::noncopyable { class NamespaceDetailsTransient : boost::noncopyable {
BOOST_STATIC_ASSERT( sizeof(NamespaceDetails) == 496 );
/* general -------------------------------------------------------- ----- */ /* general -------------------------------------------------------- ----- */
private: private:
string _ns; string _ns;
void reset(); void reset();
static std::map< string, shared_ptr< NamespaceDetailsTransient > > _map; static std::map< string, shared_ptr< NamespaceDetailsTransient > > _map;
public: public:
NamespaceDetailsTransient(const char *ns) : _ns(ns), _keysComputed( false), _qcWriteCount(), _cll_enabled() { } NamespaceDetailsTransient(const char *ns) : _ns(ns), _keysComputed( false), _qcWriteCount(), _cll_enabled() { }
/* _get() is not threadsafe -- see get_inlock() comments */ /* _get() is not threadsafe -- see get_inlock() comments */
static NamespaceDetailsTransient& _get(const char *ns); static NamespaceDetailsTransient& _get(const char *ns);
/* use get_w() when doing write operations */ /* use get_w() when doing write operations */
skipping to change at line 583 skipping to change at line 574
if ( t.get() == 0 ) if ( t.get() == 0 )
t.reset( new NamespaceDetailsTransient(ns) ); t.reset( new NamespaceDetailsTransient(ns) );
return *t; return *t;
} }
/* NamespaceIndex is the ".ns" file you see in the data directory. It is the "system catalog" /* NamespaceIndex is the ".ns" file you see in the data directory. It is the "system catalog"
if you will: at least the core parts. (Additional info in system.* collections.) if you will: at least the core parts. (Additional info in system.* collections.)
*/ */
class NamespaceIndex { class NamespaceIndex {
friend class NamespaceCursor; friend class NamespaceCursor;
BOOST_STATIC_ASSERT( sizeof(NamespaceDetails::Extra) <= sizeof(Name
spaceDetails) );
public:
public:
NamespaceIndex(const string &dir, const string &database) : NamespaceIndex(const string &dir, const string &database) :
ht( 0 ), ht( 0 ), dir_( dir ), database_( database ) {}
dir_( dir ),
database_( database ) {}
/* returns true if new db will be created if we init lazily */ /* returns true if new db will be created if we init lazily */
bool exists() const; bool exists() const;
void init(); void init();
void add_ns(const char *ns, DiskLoc& loc, bool capped) { void add_ns(const char *ns, DiskLoc& loc, bool capped) {
NamespaceDetails details( loc, capped ); NamespaceDetails details( loc, capped );
add_ns( ns, details ); add_ns( ns, details );
} }
skipping to change at line 614 skipping to change at line 601
uassert( 10081 , "too many namespaces/collections", ht->put(n, details)); uassert( 10081 , "too many namespaces/collections", ht->put(n, details));
} }
/* just for diagnostics */ /* just for diagnostics */
/*size_t detailsOffset(NamespaceDetails *d) { /*size_t detailsOffset(NamespaceDetails *d) {
if ( !ht ) if ( !ht )
return -1; return -1;
return ((char *) d) - (char *) ht->nodes; return ((char *) d) - (char *) ht->nodes;
}*/ }*/
/* extra space for indexes when more than 10 */
NamespaceDetails::Extra* allocExtra(const char *ns) {
Namespace n(ns);
Namespace extra(n.extraName().c_str()); // throws userexception
if ns name too long
NamespaceDetails *d = details(ns);
massert( 10350 , "allocExtra: base ns missing?", d );
assert( d->extraOffset == 0 );
massert( 10351 , "allocExtra: extra already exists", ht->get(e
xtra) == 0 );
NamespaceDetails::Extra temp;
memset(&temp, 0, sizeof(temp));
uassert( 10082 , "allocExtra: too many namespaces/collections"
, ht->put(extra, (NamespaceDetails&) temp));
NamespaceDetails::Extra *e = (NamespaceDetails::Extra *) ht->ge
t(extra);
d->extraOffset = ((char *) e) - ((char *) d);
assert( d->extra() == e );
return e;
}
NamespaceDetails* details(const char *ns) { NamespaceDetails* details(const char *ns) {
if ( !ht ) if ( !ht )
return 0; return 0;
Namespace n(ns); Namespace n(ns);
NamespaceDetails *d = ht->get(n); NamespaceDetails *d = ht->get(n);
if ( d ) if ( d )
d->checkMigrate(); d->checkMigrate();
return d; return d;
} }
void kill_ns(const char *ns) { void kill_ns(const char *ns) {
if ( !ht ) if ( !ht )
return; return;
Namespace n(ns); Namespace n(ns);
ht->kill(n); ht->kill(n);
try { for( int i = 0; i<=1; i++ ) {
Namespace extra(n.extraName().c_str()); try {
ht->kill(extra); Namespace extra(n.extraName(i).c_str());
ht->kill(extra);
}
catch(DBException&) { }
} }
catch(DBException&) { }
} }
bool find(const char *ns, DiskLoc& loc) { bool find(const char *ns, DiskLoc& loc) {
NamespaceDetails *l = details(ns); NamespaceDetails *l = details(ns);
if ( l ) { if ( l ) {
loc = l->firstExtent; loc = l->firstExtent;
return true; return true;
} }
return false; return false;
} }
bool allocated() const { bool allocated() const {
return ht != 0; return ht != 0;
} }
void getNamespaces( list<string>& tofill , bool onlyCollections = t rue ) const; void getNamespaces( list<string>& tofill , bool onlyCollections = t rue ) const;
NamespaceDetails::Extra* newExtra(const char *ns, int n, NamespaceD
etails *d);
private: private:
boost::filesystem::path path() const; boost::filesystem::path path() const;
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_;
}; };
 End of changes. 41 change blocks. 
132 lines changed or deleted 110 lines changed or added


 oid.h   oid.h 
skipping to change at line 88 skipping to change at line 87
s << a; s << a;
s.width( 8 ); s.width( 8 );
s << b; s << b;
s << dec; s << dec;
*/ */
return s.str(); return s.str();
} }
static OID gen() { OID o; o.init(); return o; } static OID gen() { OID o; o.init(); return o; }
static unsigned staticMachine(){ return _machine; }
/** /**
sets the contents to a new oid / randomized value sets the contents to a new oid / randomized value
*/ */
void init(); void init();
/** Set to the hex string value specified. */ /** Set to the hex string value specified. */
void init( string s ); void init( string s );
/** Set to the min/max OID that could be generated at given timesta mp. */ /** Set to the min/max OID that could be generated at given timesta mp. */
void init( Date_t date, bool max=false ); void init( Date_t date, bool max=false );
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 oplog.h   oplog.h 
skipping to change at line 65 skipping to change at line 65
class FindingStartCursor { class FindingStartCursor {
public: public:
FindingStartCursor( const QueryPlan & qp ) : FindingStartCursor( const QueryPlan & qp ) :
_qp( qp ), _qp( qp ),
_findingStart( true ), _findingStart( true ),
_findingStartMode(), _findingStartMode(),
_findingStartTimer( 0 ), _findingStartTimer( 0 ),
_findingStartCursor( 0 ) _findingStartCursor( 0 )
{ init(); } { init(); }
bool done() const { return !_findingStart; } bool done() const { return !_findingStart; }
auto_ptr< Cursor > cRelease() { return _c; } shared_ptr<Cursor> cRelease() { return _c; }
void next() { void next() {
if ( !_findingStartCursor || !_findingStartCursor->c->ok() ) { if ( !_findingStartCursor || !_findingStartCursor->c->ok() ) {
_findingStart = false; _findingStart = false;
_c = _qp.newCursor(); // on error, start from beginning _c = _qp.newCursor(); // on error, start from beginning
destroyClientCursor(); destroyClientCursor();
return; return;
} }
switch( _findingStartMode ) { switch( _findingStartMode ) {
case Initial: { case Initial: {
if ( !_matcher->matches( _findingStartCursor->c->currKe y(), _findingStartCursor->c->currLoc() ) ) { if ( !_matcher->matches( _findingStartCursor->c->currKe y(), _findingStartCursor->c->currLoc() ) ) {
skipping to change at line 133 skipping to change at line 133
} }
} }
private: private:
enum FindingStartMode { Initial, FindExtent, InExtent }; enum FindingStartMode { Initial, FindExtent, InExtent };
const QueryPlan &_qp; const QueryPlan &_qp;
bool _findingStart; bool _findingStart;
FindingStartMode _findingStartMode; FindingStartMode _findingStartMode;
auto_ptr< CoveredIndexMatcher > _matcher; auto_ptr< CoveredIndexMatcher > _matcher;
Timer _findingStartTimer; Timer _findingStartTimer;
ClientCursor * _findingStartCursor; ClientCursor * _findingStartCursor;
auto_ptr< Cursor > _c; shared_ptr<Cursor> _c;
DiskLoc startLoc( const DiskLoc &rec ) { DiskLoc startLoc( const DiskLoc &rec ) {
Extent *e = rec.rec()->myExtent( rec ); Extent *e = rec.rec()->myExtent( rec );
if ( e->myLoc != _qp.nsd()->capExtent ) if ( !_qp.nsd()->capLooped() || ( e->myLoc != _qp.nsd()->capExt ent ) )
return e->firstRecord; return e->firstRecord;
// Likely we are on the fresh side of capExtent, so return firs t fresh record. // Likely we are on the fresh side of capExtent, so return firs t fresh record.
// If we are on the stale side of capExtent, then the collectio n is small and it // If we are on the stale side of capExtent, then the collectio n is small and it
// doesn't matter if we start the extent scan with capFirstNewR ecord. // doesn't matter if we start the extent scan with capFirstNewR ecord.
return _qp.nsd()->capFirstNewRecord; return _qp.nsd()->capFirstNewRecord;
} }
// should never have an empty extent in the oplog, so don't worry a bout that case
DiskLoc prevLoc( const DiskLoc &rec ) { DiskLoc prevLoc( const DiskLoc &rec ) {
Extent *e = rec.rec()->myExtent( rec ); Extent *e = rec.rec()->myExtent( rec );
if ( e->xprev.isNull() ) if ( _qp.nsd()->capLooped() ) {
e = _qp.nsd()->lastExtent.ext(); if ( e->xprev.isNull() )
else e = _qp.nsd()->lastExtent.ext();
e = e->xprev.ext(); else
if ( e->myLoc != _qp.nsd()->capExtent ) e = e->xprev.ext();
return e->firstRecord; if ( e->myLoc != _qp.nsd()->capExtent )
return e->firstRecord;
} else {
if ( !e->xprev.isNull() ) {
e = e->xprev.ext();
return e->firstRecord;
}
}
return DiskLoc(); // reached beginning of collection return DiskLoc(); // reached beginning of collection
} }
void createClientCursor( const DiskLoc &startLoc = DiskLoc() ) { void createClientCursor( const DiskLoc &startLoc = DiskLoc() ) {
auto_ptr<Cursor> c = _qp.newCursor( startLoc ); shared_ptr<Cursor> c = _qp.newCursor( startLoc );
_findingStartCursor = new ClientCursor(QueryOption_NoCursorTime out, c, _qp.ns()); _findingStartCursor = new ClientCursor(QueryOption_NoCursorTime out, c, _qp.ns());
} }
void destroyClientCursor() { void destroyClientCursor() {
if ( _findingStartCursor ) { if ( _findingStartCursor ) {
ClientCursor::erase( _findingStartCursor->cursorid ); ClientCursor::erase( _findingStartCursor->cursorid );
_findingStartCursor = 0; _findingStartCursor = 0;
} }
} }
void maybeRelease() { void maybeRelease() {
RARELY { RARELY {
skipping to change at line 177 skipping to change at line 185
_findingStartCursor->updateLocation(); _findingStartCursor->updateLocation();
{ {
dbtemprelease t; dbtemprelease t;
} }
_findingStartCursor = ClientCursor::find( id, false ); _findingStartCursor = ClientCursor::find( id, false );
} }
} }
void init() { void init() {
// Use a ClientCursor here so we can release db mutex while sca nning // Use a ClientCursor here so we can release db mutex while sca nning
// oplog (can take quite a while with large oplogs). // oplog (can take quite a while with large oplogs).
auto_ptr<Cursor> c = _qp.newReverseCursor(); shared_ptr<Cursor> c = _qp.newReverseCursor();
_findingStartCursor = new ClientCursor(QueryOption_NoCursorTime out, c, _qp.ns()); _findingStartCursor = new ClientCursor(QueryOption_NoCursorTime out, c, _qp.ns());
_findingStartTimer.reset(); _findingStartTimer.reset();
_findingStartMode = Initial; _findingStartMode = Initial;
BSONElement tsElt = _qp.query()[ "ts" ]; BSONElement tsElt = _qp.query()[ "ts" ];
massert( 13044, "no ts field in query", !tsElt.eoo() ); massert( 13044, "no ts field in query", !tsElt.eoo() );
BSONObjBuilder b; BSONObjBuilder b;
b.append( tsElt ); b.append( tsElt );
BSONObj tsQuery = b.obj(); BSONObj tsQuery = b.obj();
_matcher.reset(new CoveredIndexMatcher(tsQuery, _qp.indexKey()) ); _matcher.reset(new CoveredIndexMatcher(tsQuery, _qp.indexKey()) );
} }
 End of changes. 7 change blocks. 
11 lines changed or deleted 19 lines changed or added


 optime.h   optime.h 
skipping to change at line 25 skipping to change at line 25
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "../db/concurrency.h" #include "../db/concurrency.h"
namespace mongo { namespace mongo {
void exitCleanly( int code ); void exitCleanly( int code );
/* Operation sequence #. A combination of current second plus an ordin
al value.
*/
struct ClockSkewException : public DBException { struct ClockSkewException : public DBException {
virtual const char* what() const throw() { return "clock skew excep tion"; } virtual const char* what() const throw() { return "clock skew excep tion"; }
virtual int getCode(){ return 20001; } virtual int getCode() const { return 20001; }
}; };
/* Operation sequence #. A combination of current second plus an ordin
al value.
*/
#pragma pack(4) #pragma pack(4)
class OpTime { class OpTime {
unsigned i; unsigned i;
unsigned secs; unsigned secs;
static OpTime last; static OpTime last;
public: public:
static void setLast(const Date_t &date) { static void setLast(const Date_t &date) {
last = OpTime(date); last = OpTime(date);
} }
unsigned getSecs() const { unsigned getSecs() const {
 End of changes. 3 change blocks. 
4 lines changed or deleted 4 lines changed or added


 parallel.h   parallel.h 
skipping to change at line 32 skipping to change at line 32
#include "../pch.h" #include "../pch.h"
#include "dbclient.h" #include "dbclient.h"
#include "redef_macros.h" #include "redef_macros.h"
#include "../db/dbmessage.h" #include "../db/dbmessage.h"
#include "../db/matcher.h" #include "../db/matcher.h"
namespace mongo { namespace mongo {
/** /**
* this is a cursor that works over a set of servers
* can be used in serial/paralellel as controlled by sub classes
*/
class ClusteredCursor {
public:
ClusteredCursor( QueryMessage& q );
ClusteredCursor( const string& ns , const BSONObj& q , int options=
0 , const BSONObj& fields=BSONObj() );
virtual ~ClusteredCursor();
virtual bool more() = 0;
virtual BSONObj next() = 0;
static BSONObj concatQuery( const BSONObj& query , const BSONObj& e
xtraFilter );
virtual string type() const = 0;
protected:
auto_ptr<DBClientCursor> query( const string& server , int num = 0
, BSONObj extraFilter = BSONObj() );
static BSONObj _concatFilter( const BSONObj& filter , const BSONObj
& extraFilter );
string _ns;
BSONObj _query;
int _options;
BSONObj _fields;
bool _done;
};
/**
* holder for a server address and a query to run * holder for a server address and a query to run
*/ */
class ServerAndQuery { class ServerAndQuery {
public: public:
ServerAndQuery( const string& server , BSONObj extra = BSONObj() , BSONObj orderObject = BSONObj() ) : ServerAndQuery( const string& server , BSONObj extra = BSONObj() , BSONObj orderObject = BSONObj() ) :
_server( server ) , _extra( extra.getOwned() ) , _orderObject( orderObject.getOwned() ){ _server( server ) , _extra( extra.getOwned() ) , _orderObject( orderObject.getOwned() ){
} }
bool operator<( const ServerAndQuery& other ) const{ bool operator<( const ServerAndQuery& other ) const{
if ( ! _orderObject.isEmpty() ) if ( ! _orderObject.isEmpty() )
skipping to change at line 96 skipping to change at line 66
operator string() const { operator string() const {
return toString(); return toString();
} }
string _server; string _server;
BSONObj _extra; BSONObj _extra;
BSONObj _orderObject; BSONObj _orderObject;
}; };
/**
* this is a cursor that works over a set of servers
* can be used in serial/paralellel as controlled by sub classes
*/
class ClusteredCursor {
public:
ClusteredCursor( QueryMessage& q );
ClusteredCursor( const string& ns , const BSONObj& q , int options=
0 , const BSONObj& fields=BSONObj() );
virtual ~ClusteredCursor();
virtual bool more() = 0;
virtual BSONObj next() = 0;
static BSONObj concatQuery( const BSONObj& query , const BSONObj& e
xtraFilter );
virtual string type() const = 0;
virtual BSONObj explain();
protected:
auto_ptr<DBClientCursor> query( const string& server , int num = 0
, BSONObj extraFilter = BSONObj() );
BSONObj explain( const string& server , BSONObj extraFilter = BSONO
bj() );
static BSONObj _concatFilter( const BSONObj& filter , const BSONObj
& extraFilter );
virtual void _explain( map< string,list<BSONObj> >& out ) = 0;
string _ns;
BSONObj _query;
int _options;
BSONObj _fields;
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 );
bool more(); bool more();
BSONObj next(); BSONObj next();
skipping to change at line 180 skipping to change at line 185
/** /**
* runs a query in serial across any number of servers * runs a query in serial across any number of servers
* returns all results from 1 server, then the next, etc... * returns all results from 1 server, then the next, etc...
*/ */
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 );
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 205 skipping to change at line 213
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: private:
void _init(); void _init();
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;
}; };
/** /**
* tools for doing asynchronous operations * tools for doing asynchronous operations
 End of changes. 5 change blocks. 
34 lines changed or deleted 45 lines changed or added


 pch.h   pch.h 
skipping to change at line 30 skipping to change at line 30
#pragma once #pragma once
#if defined(_WIN32) #if defined(_WIN32)
# define NOMINMAX # define NOMINMAX
# include <winsock2.h> //this must be included before the first windows.h include # include <winsock2.h> //this must be included before the first windows.h include
# include <ws2tcpip.h> # include <ws2tcpip.h>
# include <windows.h> # include <windows.h>
#endif #endif
#include <ctime>
#include <sstream>
#include <string>
#include <memory>
#include <string> #include <string>
#include <iostream>
#include <fstream>
#include <map>
#include <vector>
#include <set>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <signal.h>
#include "targetver.h"
#include "time.h"
#include "string.h"
#include "limits.h"
#include <boost/any.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/program_options.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/smart_ptr.hpp>
#include "boost/bind.hpp"
#include "boost/function.hpp"
#include <boost/thread/tss.hpp>
#include "boost/detail/endian.hpp"
#define BOOST_SPIRIT_THREADSAFE
#include <boost/version.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/xtime.hpp>
#undef assert
#define assert MONGO_assert
namespace mongo { namespace mongo {
using namespace std; using namespace std;
#if defined(_WIN32) #if defined(_DEBUG)
const bool debug=true; const bool debug=true;
#else #else
const bool debug=false; const bool debug=false;
#endif #endif
// pdfile versions // pdfile versions
const int VERSION = 4; const int VERSION = 4;
const int VERSION_MINOR = 5; const int VERSION_MINOR = 5;
// mongo version // mongo version
skipping to change at line 80 skipping to change at line 119
/** /**
this is here so you can't just type exit() to quit the program this is here so you can't just type exit() to quit the program
you should either use dbexit to shutdown cleanly, or ::exit to tell the system to quiy you should either use dbexit to shutdown cleanly, or ::exit to tell the system to quiy
if you use this, you'll get a link error since mongo::exit isn't def ined if you use this, you'll get a link error since mongo::exit isn't def ined
*/ */
void exit( ExitCode returnCode ); void exit( ExitCode returnCode );
bool inShutdown(); bool inShutdown();
} // namespace mongo } // namespace mongo
#include <memory>
#include <string>
#include <iostream>
#include <fstream>
#include <map>
#include <vector>
#include <set>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <signal.h>
#include "targetver.h"
#include "time.h"
#include "string.h"
#include "limits.h"
///using namespace std;
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/program_options.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/smart_ptr.hpp>
#define BOOST_SPIRIT_THREADSAFE
#include <boost/version.hpp>
#if BOOST_VERSION >= 103800
#define BOOST_SPIRIT_USE_OLD_NAMESPACE
#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_loops.hpp>
#include <boost/spirit/include/classic_lists.hpp>
#else
#include <boost/spirit/core.hpp>
#include <boost/spirit/utility/loops.hpp>
#include <boost/spirit/utility/lists.hpp>
#endif
#include <boost/tuple/tuple.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/xtime.hpp>
#undef assert
#define assert MONGO_assert
namespace mongo { namespace mongo {
using namespace boost::filesystem; using namespace boost::filesystem;
void asserted(const char *msg, const char *file, unsigned line);
} }
#define MONGO_assert(_Expression) (void)( (!!(_Expression)) || (mongo::asse
rted(#_Expression, __FILE__, __LINE__), 0) )
#include "util/debug_util.h" #include "util/debug_util.h"
#include "util/goodies.h" #include "util/goodies.h"
#include "util/log.h" #include "util/log.h"
#include "util/allocator.h" #include "util/allocator.h"
#include "util/assert_util.h" #include "util/assert_util.h"
namespace mongo { namespace mongo {
void sayDbContext(const char *msg = 0); void sayDbContext(const char *msg = 0);
void rawOut( const string &s ); void rawOut( const string &s );
 End of changes. 6 change blocks. 
51 lines changed or deleted 44 lines changed or added


 pdfile.h   pdfile.h 
skipping to change at line 43 skipping to change at line 43
#include "client.h" #include "client.h"
namespace mongo { namespace mongo {
class DataFileHeader; class DataFileHeader;
class Extent; class Extent;
class Record; class Record;
class Cursor; class Cursor;
class OpDebug; class OpDebug;
void dropDatabase(const char *ns); void dropDatabase(string db);
bool repairDatabase(const char *ns, string &errmsg, bool preserveCloned bool repairDatabase(string db, string &errmsg, bool preserveClonedFiles
FilesOnFailure = false, bool backupOriginalFiles = false); OnFailure = false, bool backupOriginalFiles = false);
/* low level - only drops this ns */ /* low level - only drops this ns */
void dropNS(const string& dropNs); void dropNS(const string& dropNs);
/* deletes this ns, indexes and cursors */ /* deletes this ns, indexes and cursors */
void dropCollection( const string &name, string &errmsg, BSONObjBuilder &result ); void dropCollection( const string &name, string &errmsg, BSONObjBuilder &result );
bool userCreateNS(const char *ns, BSONObj j, string& err, bool logForRe plication); bool userCreateNS(const char *ns, BSONObj j, string& err, bool logForRe plication);
auto_ptr<Cursor> findTableScan(const char *ns, const BSONObj& order, co nst DiskLoc &startLoc=DiskLoc()); shared_ptr<Cursor> findTableScan(const char *ns, const BSONObj& order, const DiskLoc &startLoc=DiskLoc());
// -1 if library unavailable. // -1 if library unavailable.
boost::intmax_t freeSpace(); boost::intmax_t freeSpace();
/*--------------------------------------------------------------------- */ /*--------------------------------------------------------------------- */
class MongoDataFile { class MongoDataFile {
friend class DataFileMgr; friend class DataFileMgr;
friend class BasicCursor; friend class BasicCursor;
public: public:
skipping to change at line 121 skipping to change at line 121
void insertAndLog( const char *ns, const BSONObj &o, bool god = fal se ); void insertAndLog( const char *ns, const BSONObj &o, bool god = fal se );
/** @param obj both and in and out param -- insert can sometimes mo dify an object (such as add _id). */ /** @param obj both and in and out param -- insert can sometimes mo dify an object (such as add _id). */
DiskLoc insertWithObjMod(const char *ns, BSONObj &o, bool god = fal se); DiskLoc insertWithObjMod(const char *ns, BSONObj &o, bool god = fal se);
/** @param obj in value only for this version. */ /** @param obj in value only for this version. */
void insertNoReturnVal(const char *ns, BSONObj o, bool god = false) ; void insertNoReturnVal(const char *ns, BSONObj o, bool god = false) ;
DiskLoc insert(const char *ns, const void *buf, int len, bool god = false, const BSONElement &writeId = BSONElement(), bool mayAddIndex = true ); DiskLoc insert(const char *ns, const void *buf, int len, bool god = false, const BSONElement &writeId = BSONElement(), bool mayAddIndex = true );
void deleteRecord(const char *ns, Record *todelete, const DiskLoc& dl, bool cappedOK = false, bool noWarn = false); void deleteRecord(const char *ns, Record *todelete, const DiskLoc& dl, bool cappedOK = false, bool noWarn = false);
static auto_ptr<Cursor> findAll(const char *ns, const DiskLoc &star tLoc = DiskLoc()); static shared_ptr<Cursor> findAll(const char *ns, const DiskLoc &st artLoc = DiskLoc());
/* special version of insert for transaction logging -- streamlined a bit. /* special version of insert for transaction logging -- streamlined a bit.
assumes ns is capped and no indexes assumes ns is capped and no indexes
no _id field check no _id field check
*/ */
Record* fast_oplog_insert(NamespaceDetails *d, const char *ns, int len); Record* fast_oplog_insert(NamespaceDetails *d, const char *ns, int len);
static Extent* getExtent(const DiskLoc& dl); static Extent* getExtent(const DiskLoc& dl);
static Record* getRecord(const DiskLoc& dl); static Record* getRecord(const DiskLoc& dl);
static DeletedRecord* makeDeletedRecord(const DiskLoc& dl, int len) ; static DeletedRecord* makeDeletedRecord(const DiskLoc& dl, int len) ;
 End of changes. 3 change blocks. 
5 lines changed or deleted 5 lines changed or added


 query.h   query.h 
skipping to change at line 117 skipping to change at line 117
god - allow access to system namespaces god - allow access to system namespaces
*/ */
UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BS ONObj pattern, bool upsert, bool multi , bool logop , OpDebug& debug ); UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BS ONObj pattern, bool upsert, bool multi , bool logop , OpDebug& debug );
UpdateResult _updateObjects(bool god, const char *ns, const BSONObj& up dateobj, BSONObj pattern, bool upsert, bool multi , bool logop , OpDebug& d ebug ); UpdateResult _updateObjects(bool god, const char *ns, const BSONObj& up dateobj, BSONObj pattern, bool upsert, bool multi , bool logop , OpDebug& d ebug );
// If justOne is true, deletedId is set to the id of the deleted object . // If justOne is true, deletedId is set to the id of the deleted object .
long long deleteObjects(const char *ns, BSONObj pattern, bool justOne, bool logop = false, bool god=false); long long deleteObjects(const char *ns, BSONObj pattern, bool justOne, bool logop = false, bool god=false);
long long runCount(const char *ns, const BSONObj& cmd, string& err); long long runCount(const char *ns, const BSONObj& cmd, string& err);
auto_ptr< QueryResult > runQuery(Message& m, QueryMessage& q, CurOp& cu rop ); void runQuery(Message& m, QueryMessage& q, CurOp& curop, Message &resul t);
/* This is for languages whose "objects" are not well ordered (JSON is well ordered). /* This is for languages whose "objects" are not well ordered (JSON is well ordered).
[ { a : ... } , { b : ... } ] -> { a : ..., b : ... } [ { a : ... } , { b : ... } ] -> { a : ..., b : ... }
*/ */
inline BSONObj transformOrderFromArrayFormat(BSONObj order) { inline BSONObj transformOrderFromArrayFormat(BSONObj order) {
/* note: this is slow, but that is ok as order will have very few p ieces */ /* note: this is slow, but that is ok as order will have very few p ieces */
BSONObjBuilder b; BSONObjBuilder b;
char p[2] = "0"; char p[2] = "0";
while ( 1 ) { while ( 1 ) {
skipping to change at line 178 skipping to change at line 178
int getSkip() const { return _ntoskip; } int getSkip() const { return _ntoskip; }
int getNumToReturn() const { return _ntoreturn; } int getNumToReturn() const { return _ntoreturn; }
bool wantMore() const { return _wantMore; } bool wantMore() const { return _wantMore; }
int getOptions() const { return _options; } int getOptions() const { return _options; }
bool hasOption( int x ) const { return x & _options; } bool hasOption( int x ) const { return x & _options; }
bool isExplain() const { return _explain; } bool isExplain() const { return _explain; }
bool isSnapshot() const { return _snapshot; } bool isSnapshot() const { return _snapshot; }
bool returnKey() const { return _returnKey; } bool returnKey() const { return _returnKey; }
bool showDiskLoc() const { return _showDiskLoc; }
const BSONObj& getMin() const { return _min; } const BSONObj& getMin() const { return _min; }
const BSONObj& getMax() const { return _max; } const BSONObj& getMax() const { return _max; }
const BSONObj& getOrder() const { return _order; } const BSONObj& getOrder() const { return _order; }
const BSONElement& getHint() const { return _hint; } const BSONElement& getHint() const { return _hint; }
int getMaxScan() const { return _maxScan; } int getMaxScan() const { return _maxScan; }
bool couldBeCommand() const { bool couldBeCommand() const {
/* we assume you are using findOne() for running a cmd... */ /* we assume you are using findOne() for running a cmd... */
return _ntoreturn == 1 && strstr( _ns , ".$cmd" ); return _ntoreturn == 1 && strstr( _ns , ".$cmd" );
skipping to change at line 245 skipping to change at line 246
else { else {
_filter = q; _filter = q;
} }
} }
void _reset(){ void _reset(){
_wantMore = true; _wantMore = true;
_explain = false; _explain = false;
_snapshot = false; _snapshot = false;
_returnKey = false; _returnKey = false;
_showDiskLoc = false;
_maxScan = 0; _maxScan = 0;
} }
void _initTop( const BSONObj& top ){ void _initTop( const BSONObj& top ){
BSONObjIterator i( top ); BSONObjIterator i( top );
while ( i.more() ){ while ( i.more() ){
BSONElement e = i.next(); BSONElement e = i.next();
const char * name = e.fieldName(); const char * name = e.fieldName();
if ( strcmp( "$orderby" , name ) == 0 || if ( strcmp( "$orderby" , name ) == 0 ||
skipping to change at line 277 skipping to change at line 279
else if ( strcmp( "$min" , name ) == 0 ) else if ( strcmp( "$min" , name ) == 0 )
_min = e.embeddedObject(); _min = e.embeddedObject();
else if ( strcmp( "$max" , name ) == 0 ) else if ( strcmp( "$max" , name ) == 0 )
_max = e.embeddedObject(); _max = e.embeddedObject();
else if ( strcmp( "$hint" , name ) == 0 ) else if ( strcmp( "$hint" , name ) == 0 )
_hint = e; _hint = e;
else if ( strcmp( "$returnKey" , name ) == 0 ) else if ( strcmp( "$returnKey" , name ) == 0 )
_returnKey = e.trueValue(); _returnKey = e.trueValue();
else if ( strcmp( "$maxScan" , name ) == 0 ) else if ( strcmp( "$maxScan" , name ) == 0 )
_maxScan = e.numberInt(); _maxScan = e.numberInt();
else if ( strcmp( "$showDiskLoc" , name ) == 0 )
_showDiskLoc = e.trueValue();
} }
if ( _snapshot ){ if ( _snapshot ){
uassert( 12001 , "E12001 can't sort with $snapshot", _order .isEmpty() ); uassert( 12001 , "E12001 can't sort with $snapshot", _order .isEmpty() );
uassert( 12002 , "E12002 can't use hint with $snapshot", _h int.eoo() ); uassert( 12002 , "E12002 can't use hint with $snapshot", _h int.eoo() );
} }
} }
skipping to change at line 311 skipping to change at line 315
int _options; int _options;
BSONObj _filter; BSONObj _filter;
shared_ptr< FieldMatcher > _fields; shared_ptr< FieldMatcher > _fields;
bool _wantMore; bool _wantMore;
bool _explain; bool _explain;
bool _snapshot; bool _snapshot;
bool _returnKey; bool _returnKey;
bool _showDiskLoc;
BSONObj _min; BSONObj _min;
BSONObj _max; BSONObj _max;
BSONElement _hint; BSONElement _hint;
BSONObj _order; BSONObj _order;
int _maxScan; int _maxScan;
}; };
} // namespace mongo } // namespace mongo
#include "clientcursor.h" #include "clientcursor.h"
 End of changes. 5 change blocks. 
1 lines changed or deleted 6 lines changed or added


 queryoptimizer.h   queryoptimizer.h 
skipping to change at line 24 skipping to change at line 24
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "cursor.h" #include "cursor.h"
#include "jsobj.h" #include "jsobj.h"
#include "queryutil.h" #include "queryutil.h"
#include "matcher.h"
namespace mongo { namespace mongo {
class IndexDetails; class IndexDetails;
class IndexType; class IndexType;
class QueryPlan : boost::noncopyable { class QueryPlan : boost::noncopyable {
public: public:
QueryPlan(NamespaceDetails *_d, QueryPlan(NamespaceDetails *_d,
int _idxNo, // -1 = no index int _idxNo, // -1 = no index
skipping to change at line 52 skipping to change at line 53
/* ScanAndOrder processing will be required if true */ /* ScanAndOrder processing will be required if true */
bool scanAndOrderRequired() const { return scanAndOrderRequired_; } bool scanAndOrderRequired() const { return scanAndOrderRequired_; }
/* When true, the index we are using has keys such that it can comp letely resolve the /* When true, the index we are using has keys such that it can comp letely resolve the
query expression to match by itself without ever checking the main object. query expression to match by itself without ever checking the main object.
*/ */
bool exactKeyMatch() const { return exactKeyMatch_; } bool exactKeyMatch() const { return exactKeyMatch_; }
/* If true, the startKey and endKey are unhelpful and the index ord er doesn't match the /* If true, the startKey and endKey are unhelpful and the index ord er doesn't match the
requested sort order */ requested sort order */
bool unhelpful() const { return unhelpful_; } bool unhelpful() const { return unhelpful_; }
int direction() const { return direction_; } int direction() const { return direction_; }
auto_ptr< Cursor > newCursor( const DiskLoc &startLoc = DiskLoc() , shared_ptr<Cursor> newCursor( const DiskLoc &startLoc = DiskLoc() ,
int numWanted=0 ) const; int numWanted=0 ) const;
auto_ptr< Cursor > newReverseCursor() const; shared_ptr<Cursor> newReverseCursor() const;
BSONObj indexKey() const; BSONObj indexKey() const;
const char *ns() const { return fbs_.ns(); } const char *ns() const { return fbs_.ns(); }
NamespaceDetails *nsd() const { return d; } NamespaceDetails *nsd() const { return d; }
BSONObj query() const { return fbs_.query(); } BSONObj query() const { return fbs_.query(); }
BSONObj simplifiedQuery( const BSONObj& fields = BSONObj() ) const { return fbs_.simplifiedQuery( fields ); } BSONObj simplifiedQuery( const BSONObj& fields = BSONObj() ) const { return fbs_.simplifiedQuery( fields ); }
const FieldRange &range( const char *fieldName ) const { return fbs _.range( fieldName ); } const FieldRange &range( const char *fieldName ) const { return fbs _.range( fieldName ); }
void registerSelf( long long nScanned ) const; void registerSelf( long long nScanned ) const;
// just for testing // just for testing
BoundList indexBounds() const { return indexBounds_; } BoundList indexBounds() const { return indexBounds_; }
private: private:
skipping to change at line 85 skipping to change at line 86
bool unhelpful_; bool unhelpful_;
string _special; string _special;
IndexType * _type; IndexType * _type;
}; };
// Inherit from this interface to implement a new query operation. // Inherit from this interface to implement a new query operation.
// The query optimizer will clone the QueryOp that is provided, giving // The query optimizer will clone the QueryOp that is provided, giving
// each clone its own query plan. // each clone its own query plan.
class QueryOp { class QueryOp {
public: public:
QueryOp() : complete_(), qp_(), error_() {} QueryOp() : _complete(), _stopRequested(), _qp(), _error() {}
virtual ~QueryOp() {} virtual ~QueryOp() {}
/** this gets called after a query plan is set? ERH 2/16/10 */ /** this gets called after a query plan is set? ERH 2/16/10 */
virtual void init() = 0; virtual void init() = 0;
virtual void next() = 0; virtual void next() = 0;
virtual bool mayRecordPlan() const = 0; virtual bool mayRecordPlan() const = 0;
/** @return a copy of the inheriting class, which will be run with its own /** @return a copy of the inheriting class, which will be run with its own
query plan. query plan. If multiple plan sets are required for an
$or query,
the QueryOp of the winning plan from a given set will b
e cloned
to generate QueryOps for the subsequent plan set.
*/ */
virtual QueryOp *clone() const = 0; virtual QueryOp *clone() const = 0;
bool complete() const { return complete_; } bool complete() const { return _complete; }
bool error() const { return error_; } bool error() const { return _error; }
string exceptionMessage() const { return exceptionMessage_; } bool stopRequested() const { return _stopRequested; }
const QueryPlan &qp() const { return *qp_; } string exceptionMessage() const { return _exceptionMessage; }
const QueryPlan &qp() const { return *_qp; }
// To be called by QueryPlanSet::Runner only. // To be called by QueryPlanSet::Runner only.
void setQueryPlan( const QueryPlan *qp ) { qp_ = qp; } void setQueryPlan( const QueryPlan *qp ) { _qp = qp; }
void setExceptionMessage( const string &exceptionMessage ) { void setExceptionMessage( const string &exceptionMessage ) {
error_ = true; _error = true;
exceptionMessage_ = exceptionMessage; _exceptionMessage = exceptionMessage;
} }
protected: protected:
void setComplete() { complete_ = true; } void setComplete() { _complete = true; }
void setStop() { setComplete(); _stopRequested = true; }
private: private:
bool complete_; bool _complete;
string exceptionMessage_; bool _stopRequested;
const QueryPlan *qp_; string _exceptionMessage;
bool error_; const QueryPlan *_qp;
bool _error;
}; };
// Set of candidate query plans for a particular query. Used for runni ng // Set of candidate query plans for a particular query. Used for runni ng
// a QueryOp on these plans. // a QueryOp on these plans.
class QueryPlanSet { class QueryPlanSet {
public: public:
typedef boost::shared_ptr< QueryPlan > PlanPtr; typedef boost::shared_ptr< QueryPlan > PlanPtr;
typedef vector< PlanPtr > PlanSet; typedef vector< PlanPtr > PlanSet;
skipping to change at line 137 skipping to change at line 143
const BSONElement *hint = 0, const BSONElement *hint = 0,
bool honorRecordedPlan = true, bool honorRecordedPlan = true,
const BSONObj &min = BSONObj(), const BSONObj &min = BSONObj(),
const BSONObj &max = BSONObj() ); const BSONObj &max = BSONObj() );
int nPlans() const { return plans_.size(); } int nPlans() const { return plans_.size(); }
shared_ptr< QueryOp > runOp( QueryOp &op ); shared_ptr< QueryOp > runOp( QueryOp &op );
template< class T > template< class T >
shared_ptr< T > runOp( T &op ) { shared_ptr< T > runOp( T &op ) {
return dynamic_pointer_cast< T >( runOp( static_cast< QueryOp& >( op ) ) ); return dynamic_pointer_cast< T >( runOp( static_cast< QueryOp& >( op ) ) );
} }
const FieldRangeSet &fbs() const { return fbs_; }
BSONObj explain() const; BSONObj explain() const;
bool usingPrerecordedPlan() const { return usingPrerecordedPlan_; } bool usingPrerecordedPlan() const { return usingPrerecordedPlan_; }
PlanPtr getBestGuess() const; PlanPtr getBestGuess() const;
void setBestGuessOnly() { _bestGuessOnly = true; }
//for testing
const FieldRangeSet &fbs() const { return fbs_; }
private: private:
void addOtherPlans( bool checkFirst ); void addOtherPlans( bool checkFirst );
void addPlan( PlanPtr plan, bool checkFirst ) { void addPlan( PlanPtr plan, bool checkFirst ) {
if ( checkFirst && plan->indexKey().woCompare( plans_[ 0 ]->ind exKey() ) == 0 ) if ( checkFirst && plan->indexKey().woCompare( plans_[ 0 ]->ind exKey() ) == 0 )
return; return;
plans_.push_back( plan ); plans_.push_back( plan );
} }
void init(); void init();
void addHint( IndexDetails &id ); void addHint( IndexDetails &id );
struct Runner { struct Runner {
skipping to change at line 171 skipping to change at line 179
PlanSet plans_; PlanSet plans_;
bool mayRecordPlan_; bool mayRecordPlan_;
bool usingPrerecordedPlan_; bool usingPrerecordedPlan_;
BSONObj hint_; BSONObj hint_;
BSONObj order_; BSONObj order_;
long long oldNScanned_; long long oldNScanned_;
bool honorRecordedPlan_; bool honorRecordedPlan_;
BSONObj min_; BSONObj min_;
BSONObj max_; BSONObj max_;
string _special; string _special;
bool _bestGuessOnly;
};
// Handles $or type queries by generating a QueryPlanSet for each $or c
lause
// NOTE on our $or implementation: In our current qo implementation we
don't
// keep statistics on our data, but we can conceptualize the problem of
// selecting an index when statistics exist for all index ranges. The
// d-hitting set problem on k sets and n elements can be reduced to the
// problem of index selection on k $or clauses and n index ranges (wher
e
// d is the max number of indexes, and the number of ranges n is unboun
ded).
// In light of the fact that d-hitting set is np complete, and we don't
even
// track statistics (so cost calculations are expensive) our first
// implementation uses the following greedy approach: We take one $or c
lause
// at a time and treat each as a separate query for index selection pur
poses.
// But if an index range is scanned for a particular $or clause, we eli
minate
// that range from all subsequent clauses. One could imagine an opposi
te
// implementation where we select indexes based on the union of index r
anges
// for all $or clauses, but this can have much poorer worst case behavi
or.
// (An index range that suits one $or clause may not suit another, and
this
// is worse than the typical case of index range choice staleness becau
se
// with $or the clauses may likely be logically distinct.) The greedy
// implementation won't do any worse than all the $or clauses individua
lly,
// and it can often do better. In the first cut we are intentionally u
sing
// QueryPattern tracking to record successful plans on $or queries for
use by
// subsequent $or queries, even though there may be a significant aggre
gate
// $nor component that would not be represented in QueryPattern.
class MultiPlanScanner {
public:
MultiPlanScanner( const char *ns,
const BSONObj &query,
const BSONObj &order,
const BSONElement *hint = 0,
bool honorRecordedPlan = true,
const BSONObj &min = BSONObj(),
const BSONObj &max = BSONObj() );
shared_ptr< QueryOp > runOp( QueryOp &op );
template< class T >
shared_ptr< T > runOp( T &op ) {
return dynamic_pointer_cast< T >( runOp( static_cast< QueryOp&
>( op ) ) );
}
shared_ptr< QueryOp > runOpOnce( QueryOp &op );
template< class T >
shared_ptr< T > runOpOnce( T &op ) {
return dynamic_pointer_cast< T >( runOpOnce( static_cast< Query
Op& >( op ) ) );
}
bool mayRunMore() const { return _i < _n; }
BSONObj oldExplain() const { assertNotOr(); return _currentQps->exp
lain(); }
// just report this when only one query op
bool usingPrerecordedPlan() const {
return !_or && _currentQps->usingPrerecordedPlan();
}
void setBestGuessOnly() { _bestGuessOnly = true; }
private:
//temp
void assertNotOr() const {
massert( 13266, "not implemented for $or query", !_or );
}
// temp (and yucky)
BSONObj nextSimpleQuery() {
massert( 13267, "only generate simple query if $or", _or );
massert( 13270, "no more simple queries", mayRunMore() );
BSONObjBuilder b;
BSONArrayBuilder norb;
BSONObjIterator i( _query );
while( i.more() ) {
BSONElement e = i.next();
if ( strcmp( e.fieldName(), "$nor" ) == 0 ) {
massert( 13269, "$nor must be array", e.type() == Array
);
BSONObjIterator j( e.embeddedObject() );
while( j.more() ) {
norb << j.next();
}
} else if ( strcmp( e.fieldName(), "$or" ) == 0 ) {
BSONObjIterator j( e.embeddedObject() );
for( int k = 0; k < _i; ++k ) {
norb << j.next();
}
b << "$or" << BSON_ARRAY( j.next() );
} else {
b.append( e );
}
}
BSONArray nor = norb.arr();
if ( !nor.isEmpty() ) {
b << "$nor" << nor;
}
++_i;
BSONObj ret = b.obj();
return ret;
}
const char * _ns;
bool _or;
BSONObj _query;
// FieldRangeOrSet _fros;
auto_ptr< QueryPlanSet > _currentQps;
int _i;
int _n;
bool _honorRecordedPlan;
bool _bestGuessOnly;
};
class MultiCursor : public Cursor {
public:
class CursorOp : public QueryOp {
public:
virtual shared_ptr< Cursor > newCursor() const = 0;
virtual auto_ptr< CoveredIndexMatcher > newMatcher() const = 0;
};
// takes ownership of 'op'
MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj
&order, auto_ptr< CursorOp > op = auto_ptr< CursorOp >( 0 ) )
: _mps( new MultiPlanScanner( ns, pattern, order ) ) {
if ( op.get() ) {
_op = op;
} else {
_op.reset( new NoOp() );
_mps->setBestGuessOnly();
}
if ( _mps->mayRunMore() ) {
nextClause();
if ( !ok() ) {
advance();
}
} else {
_c.reset( new BasicCursor( DiskLoc() ) );
}
}
// used to handoff a query to a getMore()
MultiCursor( auto_ptr< MultiPlanScanner > mps, const shared_ptr< Cu
rsor > &c, auto_ptr< CoveredIndexMatcher > matcher )
: _op( new NoOp() ), _c( c ), _mps( mps ), _matcher( matcher ) {
_mps->setBestGuessOnly();
}
virtual bool ok() { return _c->ok(); }
virtual Record* _current() { return _c->_current(); }
virtual BSONObj current() { return _c->current(); }
virtual DiskLoc currLoc() { return _c->currLoc(); }
virtual bool advance() {
_c->advance();
while( !ok() && _mps->mayRunMore() ) {
nextClause();
}
return ok();
}
virtual BSONObj currKey() const { return _c->currKey(); }
virtual DiskLoc refLoc() { return _c->refLoc(); }
virtual void noteLocation() { _c->noteLocation(); }
virtual void checkLocation() {
_c->checkLocation();
if ( !ok() ) {
advance();
}
}
virtual bool supportGetMore() { return true; }
// with update we could potentially get the same document on multip
le
// indexes, but update appears to already handle this with seenObje
cts
// so we don't have to do anything special here.
virtual bool getsetdup(DiskLoc loc) {
return _c->getsetdup( loc );
}
virtual CoveredIndexMatcher *matcher() const { return _matcher.get(
); }
private:
class NoOp : public CursorOp {
virtual void init() { setComplete(); }
virtual void next() {}
virtual bool mayRecordPlan() const { return false; }
virtual QueryOp *clone() const { return new NoOp(); }
virtual shared_ptr< Cursor > newCursor() const { return qp().ne
wCursor(); }
virtual auto_ptr< CoveredIndexMatcher > newMatcher() const {
return auto_ptr< CoveredIndexMatcher >( new CoveredIndexMat
cher( qp().query(), qp().indexKey() ) );
}
};
void nextClause() {
shared_ptr< CursorOp > best = _mps->runOpOnce( *_op );
massert( 10401 , best->exceptionMessage(), best->complete() );
_c = best->newCursor();
_matcher = best->newMatcher();
}
auto_ptr< CursorOp > _op;
shared_ptr< Cursor > _c;
auto_ptr< MultiPlanScanner > _mps;
auto_ptr< CoveredIndexMatcher > _matcher;
}; };
// NOTE min, max, and keyPattern will be updated to be consistent with the selected index. // NOTE min, max, and keyPattern will be updated to be consistent with the selected index.
IndexDetails *indexDetailsForRange( const char *ns, string &errmsg, BSO NObj &min, BSONObj &max, BSONObj &keyPattern ); IndexDetails *indexDetailsForRange( const char *ns, string &errmsg, BSO NObj &min, BSONObj &max, BSONObj &keyPattern );
inline bool isSimpleIdQuery( const BSONObj& query ){ inline bool isSimpleIdQuery( const BSONObj& query ){
return return
strcmp( query.firstElement().fieldName() , "_id" ) == 0 && strcmp( query.firstElement().fieldName() , "_id" ) == 0 &&
query.nFields() == 1 && query.nFields() == 1 &&
query.firstElement().isSimpleType(); query.firstElement().isSimpleType();
} }
// matcher() will always work on the returned cursor
inline shared_ptr< Cursor > bestGuessCursor( const char *ns, const BSON
Obj &query, const BSONObj &sort ) {
if( !query.getField( "$or" ).eoo() ) {
return shared_ptr< Cursor >( new MultiCursor( ns, query, sort )
);
} else {
shared_ptr< Cursor > ret = QueryPlanSet( ns, query, sort ).getB
estGuess()->newCursor();
if ( !query.isEmpty() ) {
auto_ptr< CoveredIndexMatcher > matcher( new CoveredIndexMa
tcher( query, ret->indexKeyPattern() ) );
ret->setMatcher( matcher );
}
return ret;
}
}
} // namespace mongo } // namespace mongo
 End of changes. 13 change blocks. 
18 lines changed or deleted 254 lines changed or added


 queryutil.h   queryutil.h 
skipping to change at line 25 skipping to change at line 25
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "jsobj.h" #include "jsobj.h"
namespace mongo { namespace mongo {
struct FieldBound { struct FieldBound {
BSONElement bound_; BSONElement _bound;
bool inclusive_; bool _inclusive;
bool operator==( const FieldBound &other ) const { bool operator==( const FieldBound &other ) const {
return bound_.woCompare( other.bound_ ) == 0 && return _bound.woCompare( other._bound ) == 0 &&
inclusive_ == other.inclusive_; _inclusive == other._inclusive;
} }
}; };
struct FieldInterval { struct FieldInterval {
FieldInterval(){} FieldInterval(){}
FieldInterval( const BSONElement& e ){ FieldInterval( const BSONElement& e ){
lower_.bound_ = upper_.bound_ = e; _lower._bound = _upper._bound = e;
lower_.inclusive_ = upper_.inclusive_ = true; _lower._inclusive = _upper._inclusive = true;
} }
FieldBound lower_; FieldBound _lower;
FieldBound upper_; FieldBound _upper;
bool valid() const { bool valid() const {
int cmp = lower_.bound_.woCompare( upper_.bound_, false ); int cmp = _lower._bound.woCompare( _upper._bound, false );
return ( cmp < 0 || ( cmp == 0 && lower_.inclusive_ && upper_.i return ( cmp < 0 || ( cmp == 0 && _lower._inclusive && _upper._
nclusive_ ) ); inclusive ) );
} }
}; };
// range of a field's value that may be determined from query -- used t o // range of a field's value that may be determined from query -- used t o
// determine index limits // determine index limits
class FieldRange { class FieldRange {
public: public:
FieldRange( const BSONElement &e = BSONObj().firstElement() , bool isNot=false , bool optimize=true ); FieldRange( const BSONElement &e = BSONObj().firstElement() , bool isNot=false , bool optimize=true );
const FieldRange &operator&=( const FieldRange &other ); const FieldRange &operator&=( const FieldRange &other );
const FieldRange &operator|=( const FieldRange &other ); const FieldRange &operator|=( const FieldRange &other );
BSONElement min() const { assert( !empty() ); return intervals_[ 0 // does not remove fully contained ranges (eg [1,3] - [2,2] doesn't
].lower_.bound_; } remove anything)
BSONElement max() const { assert( !empty() ); return intervals_[ in // in future we can change so that an or on $in:[3] combined with $
tervals_.size() - 1 ].upper_.bound_; } in:{$gt:2} doesn't scan 3 a second time
bool minInclusive() const { assert( !empty() ); return intervals_[ const FieldRange &operator-=( const FieldRange &other );
0 ].lower_.inclusive_; } BSONElement min() const { assert( !empty() ); return _intervals[ 0
bool maxInclusive() const { assert( !empty() ); return intervals_[ ]._lower._bound; }
intervals_.size() - 1 ].upper_.inclusive_; } BSONElement max() const { assert( !empty() ); return _intervals[ _i
ntervals.size() - 1 ]._upper._bound; }
bool minInclusive() const { assert( !empty() ); return _intervals[
0 ]._lower._inclusive; }
bool maxInclusive() const { assert( !empty() ); return _intervals[
_intervals.size() - 1 ]._upper._inclusive; }
bool equality() const { bool equality() const {
return return
!empty() && !empty() &&
min().woCompare( max(), false ) == 0 && min().woCompare( max(), false ) == 0 &&
maxInclusive() && maxInclusive() &&
minInclusive(); minInclusive();
} }
bool nontrivial() const { bool nontrivial() const {
return return
! empty() && ! empty() &&
( minKey.firstElement().woCompare( min(), false ) != 0 || ( minKey.firstElement().woCompare( min(), false ) != 0 ||
maxKey.firstElement().woCompare( max(), false ) != 0 ); maxKey.firstElement().woCompare( max(), false ) != 0 );
} }
bool empty() const { return intervals_.empty(); } bool empty() const { return _intervals.empty(); }
const vector< FieldInterval > &intervals() const { return in const vector< FieldInterval > &intervals() const { return _i
tervals_; } ntervals; }
string getSpecial() const { return _special; } string getSpecial() const { return _special; }
private: private:
BSONObj addObj( const BSONObj &o ); BSONObj addObj( const BSONObj &o );
vector< FieldInterval > intervals_; void finishOperation( const vector< FieldInterval > &newIntervals,
vector< BSONObj > objData_; const FieldRange &other );
vector< FieldInterval > _intervals;
vector< BSONObj > _objData;
string _special; string _special;
}; };
// implements query pattern matching, used to determine if a query is // implements query pattern matching, used to determine if a query is
// similar to an earlier query and should use the same plan // similar to an earlier query and should use the same plan
class QueryPattern { class QueryPattern {
public: public:
friend class FieldRangeSet; friend class FieldRangeSet;
enum Type { enum Type {
Equality, Equality,
skipping to change at line 104 skipping to change at line 108
bool operator==( const QueryPattern &other ) const { bool operator==( const QueryPattern &other ) const {
bool less = operator<( other ); bool less = operator<( other );
bool more = other.operator<( *this ); bool more = other.operator<( *this );
assert( !( less && more ) ); assert( !( less && more ) );
return !( less || more ); return !( less || more );
} }
bool operator!=( const QueryPattern &other ) const { bool operator!=( const QueryPattern &other ) const {
return !operator==( other ); return !operator==( other );
} }
bool operator<( const QueryPattern &other ) const { bool operator<( const QueryPattern &other ) const {
map< string, Type >::const_iterator i = fieldTypes_.begin(); map< string, Type >::const_iterator i = _fieldTypes.begin();
map< string, Type >::const_iterator j = other.fieldTypes_.begin map< string, Type >::const_iterator j = other._fieldTypes.begin
(); ();
while( i != fieldTypes_.end() ) { while( i != _fieldTypes.end() ) {
if ( j == other.fieldTypes_.end() ) if ( j == other._fieldTypes.end() )
return false; return false;
if ( i->first < j->first ) if ( i->first < j->first )
return true; return true;
else if ( i->first > j->first ) else if ( i->first > j->first )
return false; return false;
if ( i->second < j->second ) if ( i->second < j->second )
return true; return true;
else if ( i->second > j->second ) else if ( i->second > j->second )
return false; return false;
++i; ++i;
++j; ++j;
} }
if ( j != other.fieldTypes_.end() ) if ( j != other._fieldTypes.end() )
return true; return true;
return sort_.woCompare( other.sort_ ) < 0; return _sort.woCompare( other._sort ) < 0;
} }
private: private:
QueryPattern() {} QueryPattern() {}
void setSort( const BSONObj sort ) { void setSort( const BSONObj sort ) {
sort_ = normalizeSort( sort ); _sort = normalizeSort( sort );
} }
BSONObj static normalizeSort( const BSONObj &spec ) { BSONObj static normalizeSort( const BSONObj &spec ) {
if ( spec.isEmpty() ) if ( spec.isEmpty() )
return spec; return spec;
int direction = ( spec.firstElement().number() >= 0 ) ? 1 : -1; int direction = ( spec.firstElement().number() >= 0 ) ? 1 : -1;
BSONObjIterator i( spec ); BSONObjIterator i( spec );
BSONObjBuilder b; BSONObjBuilder b;
while( i.moreWithEOO() ) { while( i.moreWithEOO() ) {
BSONElement e = i.next(); BSONElement e = i.next();
if ( e.eoo() ) if ( e.eoo() )
break; break;
b.append( e.fieldName(), direction * ( ( e.number() >= 0 ) ? -1 : 1 ) ); b.append( e.fieldName(), direction * ( ( e.number() >= 0 ) ? -1 : 1 ) );
} }
return b.obj(); return b.obj();
} }
map< string, Type > fieldTypes_; map< string, Type > _fieldTypes;
BSONObj sort_; BSONObj _sort;
}; };
// a BoundList contains intervals specified by inclusive start // a BoundList contains intervals specified by inclusive start
// and end bounds. The intervals should be nonoverlapping and occur in // and end bounds. The intervals should be nonoverlapping and occur in
// the specified direction of traversal. For example, given a simple i ndex {i:1} // the specified direction of traversal. For example, given a simple i ndex {i:1}
// and direction +1, one valid BoundList is: (1, 2); (4, 6). The same BoundList // and direction +1, one valid BoundList is: (1, 2); (4, 6). The same BoundList
// would be valid for index {i:-1} with direction -1. // would be valid for index {i:-1} with direction -1.
typedef vector< pair< BSONObj, BSONObj > > BoundList; typedef vector< pair< BSONObj, BSONObj > > BoundList;
// ranges of fields' value that may be determined from query -- used to // ranges of fields' value that may be determined from query -- used to
// determine index limits // determine index limits
class FieldRangeSet { class FieldRangeSet {
public: public:
friend class FieldRangeOrSet;
FieldRangeSet( const char *ns, const BSONObj &query , bool optimize =true ); FieldRangeSet( const char *ns, const BSONObj &query , bool optimize =true );
const FieldRange &range( const char *fieldName ) const { const FieldRange &range( const char *fieldName ) const {
map< string, FieldRange >::const_iterator f = ranges_.find( fie map< string, FieldRange >::const_iterator f = _ranges.find( fie
ldName ); ldName );
if ( f == ranges_.end() ) if ( f == _ranges.end() )
return trivialRange(); return trivialRange();
return f->second; return f->second;
} }
int nNontrivialRanges() const { int nNontrivialRanges() const {
int count = 0; int count = 0;
for( map< string, FieldRange >::const_iterator i = ranges_.begi n(); i != ranges_.end(); ++i ) for( map< string, FieldRange >::const_iterator i = _ranges.begi n(); i != _ranges.end(); ++i )
if ( i->second.nontrivial() ) if ( i->second.nontrivial() )
++count; ++count;
return count; return count;
} }
const char *ns() const { return ns_; } const char *ns() const { return _ns; }
BSONObj query() const { return query_; }
// if fields is specified, order fields of returned object to match those of 'fields' // if fields is specified, order fields of returned object to match those of 'fields'
BSONObj simplifiedQuery( const BSONObj &fields = BSONObj() ) const; BSONObj simplifiedQuery( const BSONObj &fields = BSONObj() ) const;
bool matchPossible() const { bool matchPossible() const {
for( map< string, FieldRange >::const_iterator i = ranges_.begi n(); i != ranges_.end(); ++i ) for( map< string, FieldRange >::const_iterator i = _ranges.begi n(); i != _ranges.end(); ++i )
if ( i->second.empty() ) if ( i->second.empty() )
return false; return false;
return true; return true;
} }
QueryPattern pattern( const BSONObj &sort = BSONObj() ) const; QueryPattern pattern( const BSONObj &sort = BSONObj() ) const;
BoundList indexBounds( const BSONObj &keyPattern, int direction ) c onst; BoundList indexBounds( const BSONObj &keyPattern, int direction ) c onst;
string getSpecial() const; string getSpecial() const;
// intended to handle sets without _orSets
const FieldRangeSet &operator-=( const FieldRangeSet &other ) {
for( map< string, FieldRange >::const_iterator i = other._range
s.begin();
i != other._ranges.end(); ++i ) {
map< string, FieldRange >::iterator f = _ranges.find( i->fi
rst.c_str() );
if ( f != _ranges.end() )
f->second -= i->second;
}
return *this;
}
BSONObj query() const { return _query; }
private: private:
void processQueryField( const BSONElement &e, bool optimize );
void processOpElement( const char *fieldName, const BSONElement &f, bool isNot, bool optimize ); void processOpElement( const char *fieldName, const BSONElement &f, bool isNot, bool optimize );
static FieldRange *trivialRange_; static FieldRange *trivialRange_;
static FieldRange &trivialRange(); static FieldRange &trivialRange();
mutable map< string, FieldRange > ranges_; mutable map< string, FieldRange > _ranges;
const char *ns_; const char *_ns;
BSONObj query_; BSONObj _query;
}; };
// generages FieldRangeSet objects, accounting for or clauses
// class FieldRangeOrSet {
// public:
// FieldRangeOrSet( const char *ns, const BSONObj &query , bool opti
mize=true );
// // if there's a trivial or clause, we won't use or ranges to help
with scanning
// bool trivialOr() const {
// for( list< FieldRangeSet >::const_iterator i = _orSets.begin(
); i != _orSets.end(); ++i ) {
// if ( i->nNontrivialRanges() == 0 ) {
// return true;
// }
// }
// return false;
// }
// bool orFinished() const { return _orFound && _orSets.empty(); }
// // removes first or clause, and removes the field ranges it cover
s from all subsequent or clauses
// void popOrClause() {
// massert( 13274, "no or clause to pop", !orFinished() );
// const FieldRangeSet &toPop = _orSets.front();
// list< FieldRangeSet >::iterator i = _orSets.begin();
// ++i;
// while( i != _orSets.end() ) {
// *i -= toPop;
// if( !i->matchPossible() ) {
// i = _orSets.erase( i );
// } else {
// ++i;
// }
// }
// _orSets.pop_front();
// }
// private:
// FieldRangeSet _baseSet;
// list< FieldRangeSet > _orSets;
// bool _orFound;
// };
/** /**
used for doing field limiting used for doing field limiting
*/ */
class FieldMatcher { class FieldMatcher {
public: public:
FieldMatcher() FieldMatcher()
: _include(true) : _include(true)
, _special(false) , _special(false)
, _includeID(true) , _includeID(true)
, _skip(0) , _skip(0)
skipping to change at line 217 skipping to change at line 269
void add( const BSONObj& o ); void add( const BSONObj& o );
void append( BSONObjBuilder& b , const BSONElement& e ) const; void append( BSONObjBuilder& b , const BSONElement& e ) const;
BSONObj getSpec() const; BSONObj getSpec() const;
bool includeID() { return _includeID; } bool includeID() { return _includeID; }
private: private:
void add( const string& field, bool include ); void add( const string& field, bool include );
void add( const string& field, int skip, int limit ); void add( const string& field, int skip, int limit );
void appendArray( BSONObjBuilder& b , const BSONObj& a ) const; void appendArray( BSONObjBuilder& b , const BSONObj& a , bool neste d=false) const;
bool _include; // true if default at this level is to include bool _include; // true if default at this level is to include
bool _special; // true if this level can't be skipped or included w ithout recursing bool _special; // true if this level can't be skipped or included w ithout recursing
//TODO: benchmark vector<pair> vs map //TODO: benchmark vector<pair> vs map
typedef map<string, boost::shared_ptr<FieldMatcher> > FieldMap; typedef map<string, boost::shared_ptr<FieldMatcher> > FieldMap;
FieldMap _fields; FieldMap _fields;
BSONObj _source; BSONObj _source;
bool _includeID; bool _includeID;
// used for $slice operator // used for $slice operator
 End of changes. 23 change blocks. 
46 lines changed or deleted 107 lines changed or added


 queue.h   queue.h 
skipping to change at line 32 skipping to change at line 32
#include <queue> #include <queue>
namespace mongo { namespace mongo {
/** /**
* simple blocking queue * simple blocking queue
*/ */
template<typename T> class BlockingQueue : boost::noncopyable { template<typename T> class BlockingQueue : boost::noncopyable {
public: public:
BlockingQueue() : _lock("BlockingQueue") { }
void push(T const& t){ void push(T const& t){
scoped_lock l( _lock ); scoped_lock l( _lock );
_queue.push( t ); _queue.push( t );
_condition.notify_one(); _condition.notify_one();
} }
bool empty() const { bool empty() const {
scoped_lock l( _lock ); scoped_lock l( _lock );
return _queue.empty(); return _queue.empty();
} }
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 rec.h   rec.h 
skipping to change at line 30 skipping to change at line 30
_ support > 2GB data per file _ support > 2GB data per file
_ multiple files, not just indexes.dat _ multiple files, not just indexes.dat
_ lazier writes? (may be done?) _ lazier writes? (may be done?)
_ configurable cache size _ configurable cache size
_ fix on abnormal terminations to be able to restart some _ fix on abnormal terminations to be able to restart some
*/ */
#pragma once #pragma once
#include "reci.h" #include "reci.h"
#include "reccache.h" //#include "reccache.h"
namespace mongo { namespace mongo {
/* ------------------------------------------------------------------------ -- /* ------------------------------------------------------------------------ --
A RecStoreInterface for the normal mongo mem mapped file (MongoDataFile) A RecStoreInterface for the normal mongo mem mapped file (MongoDataFile)
storage storage
*/ */
NamespaceDetails* nsdetails_notinline(const char *ns); NamespaceDetails* nsdetails_notinline(const char *ns);
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 reccache.h   reccache.h 
skipping to change at line 34 skipping to change at line 34
dblock dblock
RecCache::rcmutex RecCache::rcmutex
i.e. always lock dblock first if you lock both i.e. always lock dblock first if you lock both
*/ */
#pragma once #pragma once
#error deprecated
#include "reci.h" #include "reci.h"
#include "recstore.h" #include "recstore.h"
namespace mongo { namespace mongo {
class RecCache { class RecCache {
struct Node { struct Node {
Node(void* _data) : data((char *) _data) { dirty = false; newer = 0 ; } Node(void* _data) : data((char *) _data) { dirty = false; newer = 0 ; }
~Node() { ~Node() {
free(data); free(data);
skipping to change at line 246 skipping to change at line 248
VIRT void closeFiles(string dbname, string path) { VIRT void closeFiles(string dbname, string path) {
theRecCache.closeFiles(dbname, dbpath); theRecCache.closeFiles(dbname, dbpath);
} }
}; };
/* see concurrency.h - note on a lock reset from read->write we don't /* see concurrency.h - note on a lock reset from read->write we don't
call dbunlocking_read, we just wait for the final dbunlocking_write call dbunlocking_read, we just wait for the final dbunlocking_write
call call
*/ */
inline void dbunlocking_read() { //inline void dbunlocking_read() {
/* /*
Client *c = currentClient.get(); Client *c = currentClient.get();
if ( c ) if ( c )
c->top.clientStop(); c->top.clientStop();
*/ */
} //}
inline void dbunlocking_write() { //inline void dbunlocking_write() {
theRecCache.ejectOld(); //theRecCache.ejectOld();
dbunlocking_read(); // dbunlocking_read();
} //}
} /*namespace*/ } /*namespace*/
 End of changes. 4 change blocks. 
6 lines changed or deleted 8 lines changed or added


 recstore.h   recstore.h 
skipping to change at line 20 skipping to change at line 20
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Lice nse * You should have received a copy of the GNU Affero General Public Lice nse
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#error deprecated
#include "../util/file.h" #include "../util/file.h"
namespace mongo { namespace mongo {
using boost::uint32_t; using boost::uint32_t;
using boost::uint64_t; using boost::uint64_t;
/* Current version supports only consistent record sizes within a store. */ /* Current version supports only consistent record sizes within a store. */
class BasicRecStore { class BasicRecStore {
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 redef_macros.h   redef_macros.h 
skipping to change at line 32 skipping to change at line 32
#if defined(MONGO_MACROS_CLEANED) #if defined(MONGO_MACROS_CLEANED)
// util/allocator.h // util/allocator.h
#define malloc MONGO_malloc #define malloc MONGO_malloc
#define realloc MONGO_realloc #define realloc MONGO_realloc
// util/assert_util.h // util/assert_util.h
#define assert MONGO_assert #define assert MONGO_assert
#define dassert MONGO_dassert #define dassert MONGO_dassert
#define wassert MONGO_wassert #define wassert MONGO_wassert
#define massert MONGO_massert
#define uassert MONGO_uassert
#define BOOST_CHECK_EXCEPTION MONGO_BOOST_CHECK_EXCEPTION #define BOOST_CHECK_EXCEPTION MONGO_BOOST_CHECK_EXCEPTION
#define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD #define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD
// util/goodies.h // util/goodies.h
#define PRINT MONGO_PRINT #define PRINT MONGO_PRINT
#define PRINTFL MONGO_PRINTFL #define PRINTFL MONGO_PRINTFL
#define asctime MONGO_asctime #define asctime MONGO_asctime
#define gmtime MONGO_gmtime #define gmtime MONGO_gmtime
#define localtime MONGO_localtime #define localtime MONGO_localtime
#define ctime MONGO_ctime #define ctime MONGO_ctime
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 repl.h   repl.h 
skipping to change at line 81 skipping to change at line 81
extern ReplSettings replSettings; extern ReplSettings replSettings;
bool cloneFrom(const char *masterHost, string& errmsg, const string& fr omdb, bool logForReplication, bool cloneFrom(const char *masterHost, string& errmsg, const string& fr omdb, bool logForReplication,
bool slaveOk, bool useReplAuth, bool snap shot); bool slaveOk, bool useReplAuth, bool snap shot);
/* A replication exception */ /* A replication exception */
class SyncException : public DBException { class SyncException : public DBException {
public: public:
virtual const char* what() const throw() { return "sync exception"; } virtual const char* what() const throw() { return "sync exception"; }
virtual int getCode(){ return 10001; } virtual int getCode() const { return 10001; }
}; };
/* A Source is a source from which we can pull (replicate) data. /* A Source is a source from which we can pull (replicate) data.
stored in collection local.sources. stored in collection local.sources.
Can be a group of things to replicate for several databases. Can be a group of things to replicate for several databases.
{ host: ..., source: ..., only: ..., syncedTo: ..., localLogTs: . .., dbsNextPass: { ... }, incompleteCloneDbs: { ... } } { host: ..., source: ..., only: ..., syncedTo: ..., localLogTs: . .., dbsNextPass: { ... }, incompleteCloneDbs: { ... } }
'source' defaults to 'main'; support for multiple source names is 'source' defaults to 'main'; support for multiple source names is
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 replpair.h   replpair.h 
skipping to change at line 121 skipping to change at line 121
If 'client' is not specified, the current client is used. If 'client' is not specified, the current client is used.
*/ */
inline bool _isMaster( const char *client = 0 ) { inline bool _isMaster( const char *client = 0 ) {
if( replSet ) { if( replSet ) {
if( theReplSet ) if( theReplSet )
return theReplSet->isMaster(client); return theReplSet->isMaster(client);
return false; return false;
} }
if( ! replSettings.slave ) if( ! replSettings.slave )
return true; return true;
if ( replAllDead ) if ( replAllDead )
return false; return false;
if ( replPair ) { if ( replPair ) {
if( replPair->state == ReplPair::State_Master ) if( replPair->state == ReplPair::State_Master )
return true; return true;
} }
else { else {
if( replSettings.master ) { if( replSettings.master ) {
// if running with --master --slave, allow. note that mast er is also true // if running with --master --slave, allow. note that mast er is also true
// for repl pairs so the check for replPair above is import ant. // for repl pairs so the check for replPair above is import ant.
return true; return true;
} }
} }
if ( cc().isGod() ) if ( cc().isGod() )
return true; return true;
skipping to change at line 165 skipping to change at line 165
inline void notMasterUnless(bool expr) { inline void notMasterUnless(bool expr) {
uassert( 10107 , "not master" , expr ); uassert( 10107 , "not master" , expr );
} }
/* we allow queries to SimpleSlave's -- but not to the slave (nonmaster ) member of a replica pair /* we allow queries to SimpleSlave's -- but not to the slave (nonmaster ) member of a replica pair
so that queries to a pair are realtime consistent as much as possibl e. use setSlaveOk() to so that queries to a pair are realtime consistent as much as possibl e. use setSlaveOk() to
query the nonmaster member of a replica pair. query the nonmaster member of a replica pair.
*/ */
inline void replVerifyReadsOk(ParsedQuery& pq) { inline void replVerifyReadsOk(ParsedQuery& pq) {
if( replSet ) if( replSet )
notMasterUnless(isMaster()); notMasterUnless(isMaster() || pq.hasOption(QueryOption_SlaveOk) );
else else
notMasterUnless(isMaster() || pq.hasOption( QueryOption_SlaveOk ) || replSettings.slave == SimpleSlave ); notMasterUnless(isMaster() || pq.hasOption(QueryOption_SlaveOk) || replSettings.slave == SimpleSlave );
} }
inline bool isMasterNs( const char *ns ) { inline bool isMasterNs( const char *ns ) {
char cl[ 256 ]; char cl[ 256 ];
nsToDatabase( ns, cl ); nsToDatabase( ns, cl );
return isMaster( cl ); return isMaster( cl );
} }
inline ReplPair::ReplPair(const char *remoteEnd, const char *arb) { inline ReplPair::ReplPair(const char *remoteEnd, const char *arb) {
state = -1; state = -1;
 End of changes. 4 change blocks. 
7 lines changed or deleted 7 lines changed or added


 replset.h   replset.h 
skipping to change at line 23 skipping to change at line 23
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "../../util/concurrency/list.h" #include "../../util/concurrency/list.h"
#include "../../util/concurrency/value.h" #include "../../util/concurrency/value.h"
#include "../../util/concurrency/msg.h"
#include "../../util/hostandport.h" #include "../../util/hostandport.h"
#include "../commands.h"
#include "rstime.h"
#include "rsmember.h"
#include "rs_config.h"
namespace mongo { namespace mongo {
struct Target;
extern bool replSet; // true if using repl sets extern bool replSet; // true if using repl sets
extern class ReplSet *theReplSet; // null until initialized extern class ReplSet *theReplSet; // null until initialized
extern Tee *rsLog;
/** most operations on a ReplSet object should be done while locked. */
class RSBase : boost::noncopyable {
private:
mutex m;
int _locked;
protected:
RSBase() : m("RSBase"), _locked(0) { }
class lock : scoped_lock {
RSBase& _b;
public:
lock(RSBase* b) : scoped_lock(b->m), _b(*b) { b->_locked++; }
~lock() { _b._locked--; }
};
bool locked() const { return _locked; }
};
/* 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 ReplSet { class ReplSet : RSBase {
public: public:
bool isMaster(const char *client) { /** info on our state if the replset isn't yet "up". for example,
//zzz if we are pre-initiation. */
return false; enum StartupStatus {
} PRESTART=0, LOADINGCONFIG=1, BADCONFIG=2, EMPTYCONFIG=3,
void fillIsMaster(BSONObjBuilder&); EMPTYUNREACHABLE=4, STARTED=5, SOON=6
};
static enum StartupStatus { PRESTART=0, LOADINGCONFIG=1, BADCONFIG= static StartupStatus startupStatus;
2, EMPTYCONFIG=3, EMPTYUNREACHABLE=4, FINISHME=5 } startupStatus;
static string startupStatusMsg; static string startupStatusMsg;
bool fatal;
bool ok() const { return !fatal; } void fatal();
bool isMaster(const char *client);
void fillIsMaster(BSONObjBuilder&);
bool ok() const { return _myState != FATAL; }
MemberState state() const { return _myState; }
string name() const { return _name; } /* @return replica set's logi
cal name */
/* @return replica set's logical name */ void relinquish();
string getName() const { return _name; } void assumePrimary();
/* cfgString format is /* cfgString format is
replsetname/host1,host2:port,... replsetname/host1,host2:port,...
where :port is optional. where :port is optional.
throws exception if a problem initializing. */
throws exception if a problem initializing.
*/
ReplSet(string cfgString); ReplSet(string cfgString);
/* call after constructing to start - returns fairly quickly after
launching its threads */
void go() { _myState = STARTUP2; startThreads(); }
// for replSetGetStatus command // for replSetGetStatus command
void summarizeStatus(BSONObjBuilder&) const; void summarizeStatus(BSONObjBuilder&) const;
void summarizeAsHtml(stringstream&) const;
const ReplSetConfig& config() { return *_cfg; }
private: private:
MemberState _myState;
string _name; string _name;
const vector<HostAndPort> *_seeds; const vector<HostAndPort> *_seeds;
ReplSetConfig *_cfg;
/** load our configuration from admin.replset. try seed machines t oo. /** load our configuration from admin.replset. try seed machines t oo.
throws exception if a problem. throws exception if a problem.
*/ */
void _loadConfigFinish(vector<ReplSetConfig>& v);
void loadConfig(); void loadConfig();
void initFromConfig(ReplSetConfig& c);//, bool save);
// void addMemberIfMissing(const HostAndPort& p); class Consensus {
ReplSet &rs;
struct LastYea {
LastYea() : when(0), who(0xffffffff) { }
time_t when;
unsigned who;
};
Atomic<LastYea> ly;
unsigned yea(unsigned memberId); // throws VoteException
void _electSelf();
bool weAreFreshest();
public:
Consensus(ReplSet *t) : rs(*t) { }
int totalVotes() const;
bool aMajoritySeemsToBeUp() const;
void electSelf();
void electCmdReceived(BSONObj, BSONObjBuilder*);
} elect;
struct MemberInfo : public List1<MemberInfo>::Base { public:
MemberInfo(string h, int p) : _port(p), _host(h) { class Member : public List1<Member>::Base {
_dead = false; public:
_lastHeartbeat = 0; Member(HostAndPort h, unsigned ord, const ReplSetConfig::Member
_upSince = 0; Cfg *c);
_health = -1.0;
} string fullName() const { return h().toString(); }
string fullName() const { const ReplSetConfig::MemberCfg& config() const { return *_confi
if( _port < 0 ) return _host; g; }
stringstream ss; const HeartbeatInfo& hbinfo() const { return _hbinfo; }
ss << _host << ':' << _port; string lhb() { return _hbinfo.lastHeartbeatMsg; }
return ss.str(); MemberState state() const { return _hbinfo.hbstate; }
} const HostAndPort& h() const { return _h; }
double health() const { return _health; } unsigned id() const { return _hbinfo.id(); }
time_t upSince() const { return _upSince; }
time_t lastHeartbeat() const { return _lastHeartbeat; } void summarizeAsHtml(stringstream& s) const;
friend class ReplSet;
private: private:
friend class FeedbackThread; // feedbackthread is the primary w const ReplSetConfig::MemberCfg *_config; /* todo: when this cha
riter to these objects nges??? */
HostAndPort _h;
HeartbeatInfo _hbinfo;
};
list<HostAndPort> memberHostnames() const;
const Member* currentPrimary() const { return _currentPrimary; }
bool primary() const { return _myState == PRIMARY; }
const ReplSetConfig::MemberCfg& myConfig() const { return _self->co
nfig(); }
void msgUpdateHBInfo(HeartbeatInfo);
bool _dead; private:
const int _port; const Member *_currentPrimary;
const string _host; Member *_self;
double _health; List1<Member> _members; /* all members of the set EXCEPT self. */
time_t _lastHeartbeat;
time_t _upSince; public:
class Manager : public task::Server {
bool got(const any&);
ReplSet *rs;
int _primary;
const Member* findOtherPrimary();
void noteARemoteIsPrimary(const Member *);
public: public:
DiagStr _lastHeartbeatErrMsg; Manager(ReplSet *rs);
void msgReceivedNewConfig(BSONObj) { assert(false); }
void msgCheckNewState();
}; };
/* all members of the set EXCEPT SELF. */ shared_ptr<Manager> mgr;
List1<MemberInfo> _members;
void startHealthThreads(); private:
Member* head() const { return _members.head(); }
void getTargets(list<Target>&);
static string stateAsStr(MemberState state);
static string stateAsHtml(MemberState state);
void startThreads();
friend class FeedbackThread; friend class FeedbackThread;
friend class CmdReplSetElect;
};
inline void ReplSet::fatal()
{
lock l(this);
_myState = FATAL;
log() << "replSet error fatal error, stopping replication" << rsLog
;
}
inline ReplSet::Member::Member(HostAndPort h, unsigned ord, const ReplS
etConfig::MemberCfg *c) :
_config(c), _h(h), _hbinfo(ord) { }
inline bool ReplSet::isMaster(const char *client) {
/* todo replset */
return false;
}
class ReplSetCommand : public Command {
protected:
ReplSetCommand(const char * s) : Command(s) { }
virtual bool slaveOk() const { return true; }
virtual bool adminOnly() const { return true; }
virtual bool logTheOp() { return false; }
virtual LockType locktype() const { return NONE; }
virtual void help( stringstream &help ) const { help << "internal";
}
bool check(string& errmsg, BSONObjBuilder& result) {
if( !replSet ) {
errmsg = "not running with --replSet";
return false;
}
if( theReplSet == 0 ) {
result.append("startupStatus", ReplSet::startupStatus);
errmsg = ReplSet::startupStatusMsg.empty() ? "replset unkno
wn error 2" : ReplSet::startupStatusMsg;
return false;
}
return true;
}
}; };
} }
 End of changes. 24 change blocks. 
45 lines changed or deleted 161 lines changed or added


 request.h   request.h 
skipping to change at line 28 skipping to change at line 28
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "../util/message.h" #include "../util/message.h"
#include "../db/dbmessage.h" #include "../db/dbmessage.h"
#include "config.h" #include "config.h"
#include "util.h" #include "util.h"
namespace mongo { namespace mongo {
class OpCounters;
class ClientInfo; class ClientInfo;
class Request : boost::noncopyable { class Request : boost::noncopyable {
public: public:
Request( Message& m, AbstractMessagingPort* p ); Request( Message& m, AbstractMessagingPort* p );
// ---- message info ----- // ---- message info -----
const char * getns() const { const char * getns() const {
return _d.getns(); return _d.getns();
} }
int op() const { int op() const {
return _m.data->operation(); return _m.operation();
} }
bool expectResponse() const { bool expectResponse() const {
return op() == dbQuery || op() == dbGetMore; return op() == dbQuery || op() == dbGetMore;
} }
bool isCommand() const; bool isCommand() const;
MSGID id() const { MSGID id() const {
return _id; return _id;
} }
DBConfig * getConfig() const { DBConfig * getConfig() const {
return _config; return _config;
} }
bool isShardingEnabled() const { bool isShardingEnabled() const {
return _config->isShardingEnabled(); return _config->isShardingEnabled();
} }
ChunkManager * getChunkManager() const { ChunkManagerPtr getChunkManager() const {
return _chunkManager; return _chunkManager;
} }
int getClientId() const { int getClientId() const {
return _clientId; return _clientId;
} }
ClientInfo * getClientInfo() const { ClientInfo * getClientInfo() const {
return _clientInfo; return _clientInfo;
} }
skipping to change at line 85 skipping to change at line 86
void reply( Message & response ){ void reply( Message & response ){
_p->reply( _m , response , _id ); _p->reply( _m , response , _id );
} }
Message& m() { return _m; } Message& m() { return _m; }
DbMessage& d() { return _d; } DbMessage& d() { return _d; }
AbstractMessagingPort* p() const { return _p; } AbstractMessagingPort* p() const { return _p; }
void process( int attempt = 0 ); void process( int attempt = 0 );
void gotInsert();
private: private:
void reset( bool reload=false ); void reset( bool reload=false );
Message& _m; Message& _m;
DbMessage _d; DbMessage _d;
AbstractMessagingPort* _p; AbstractMessagingPort* _p;
MSGID _id; MSGID _id;
DBConfig * _config; DBConfig * _config;
ChunkManager * _chunkManager; ChunkManagerPtr _chunkManager;
int _clientId; int _clientId;
ClientInfo * _clientInfo; ClientInfo * _clientInfo;
OpCounters* _counter;
}; };
typedef map<int,ClientInfo*> ClientCache; typedef map<int,ClientInfo*> ClientCache;
class ClientInfo { class ClientInfo {
public: public:
ClientInfo( int clientId ); ClientInfo( int clientId );
~ClientInfo(); ~ClientInfo();
string getRemote() const { return _remote; } string getRemote() const { return _remote; }
 End of changes. 6 change blocks. 
3 lines changed or deleted 8 lines changed or added


 resource.h   resource.h 
//{{NO_DEPENDENCIES}} //{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file. // Microsoft Visual C++ generated include file.
// Used by db.rc // Used by db.rc
//
/** #define IDI_ICON2 102
* Copyright (C) 2008 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3
,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public Licen
se
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace mongo {
// Next default values for new objects // Next default values for new objects
// //
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101 #define _APS_NEXT_RESOURCE_VALUE 103
#define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101
#endif #endif
#endif #endif
} // namespace mongo
 End of changes. 3 change blocks. 
21 lines changed or deleted 3 lines changed or added


 rs_config.h   rs_config.h 
skipping to change at line 28 skipping to change at line 28
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "../../util/hostandport.h" #include "../../util/hostandport.h"
#include "health.h" #include "health.h"
namespace mongo { namespace mongo {
/** const string rsConfigNs = "local.system.replset";
local.system.replset
This collection has one object per server in the set.
See "Replical Sets Configuration" on mongodb.org wiki for details on th
e format.
*/
class ReplSetConfig { class ReplSetConfig {
enum { EMPTYCONFIG = -2 };
public: public:
/* if something is misconfigured, throws an exception. /* if something is misconfigured, throws an exception.
if couldn't be queried or is just blank, ok() will be false. if couldn't be queried or is just blank, ok() will be false.
*/ */
ReplSetConfig(const HostAndPort& h); ReplSetConfig(const HostAndPort& h);
ReplSetConfig(BSONObj cfg); ReplSetConfig(BSONObj cfg);
bool ok() const { return _ok; } bool ok() const { return _ok; }
struct Member { struct MemberCfg {
Member() : _id(-1), votes(1), priority(1.0), arbiterOnly(false) MemberCfg() : _id(-1), votes(1), priority(1.0), arbiterOnly(fal
{ } se) { }
int _id; /* ordinal */ int _id; /* ordinal */
unsigned votes; /* how many votes this node gets. default 1. */ unsigned votes; /* how many votes this node gets. default 1. */
HostAndPort h; HostAndPort h;
double priority; /* 0 means can never be primary */ double priority; /* 0 means can never be primary */
bool arbiterOnly; bool arbiterOnly;
void check() const; /* check validity, assert if not. */ void check() const; /* check validity, assert if not. */
BSONObj asBson() const; BSONObj asBson() const;
}; };
vector<Member> members; vector<MemberCfg> members;
string _id; string _id;
int version; int version;
HealthOptions ho; HealthOptions ho;
string md5; string md5;
BSONObj getLastErrorDefaults; BSONObj getLastErrorDefaults;
// true if could connect, and there is no cfg object there at all list<HostAndPort> otherMemberHostnames() const; // except self
bool empty() const { return version == -2; }
/** @return true if could connect, and there is no cfg object there
at all */
bool empty() const { return version == EMPTYCONFIG; }
string toString() const { return asBson().toString(); } string toString() const { return asBson().toString(); }
/** validate the settings. does not call check() on each member, yo u have to do that separately. */ /** validate the settings. does not call check() on each member, yo u have to do that separately. */
void check() const; void check() const;
void save(); // to local db static void receivedNewConfig(BSONObj);
void saveConfigLocally(); // to local db
string saveConfigEverywhere(); // returns textual info on what happ
ened
BSONObj asBson() const;
private: private:
bool _ok; bool _ok;
void from(BSONObj); void from(BSONObj);
void clear(); void clear();
BSONObj asBson() const;
}; };
} }
 End of changes. 7 change blocks. 
16 lines changed or deleted 17 lines changed or added


 scanandorder.h   scanandorder.h 
skipping to change at line 53 skipping to change at line 53
return o.extractFields(pattern,true); return o.extractFields(pattern,true);
} }
}; };
/* todo: /* todo:
_ respect limit _ respect limit
_ check for excess mem usage _ check for excess mem usage
_ response size limit from runquery; push it up a bit. _ response size limit from runquery; push it up a bit.
*/ */
inline void fillQueryResultFromObj(BufBuilder& bb, FieldMatcher *filter , BSONObj& js) { inline void fillQueryResultFromObj(BufBuilder& bb, FieldMatcher *filter , BSONObj& js, DiskLoc* loc=NULL) {
if ( filter ) { if ( filter ) {
BSONObjBuilder b( bb ); BSONObjBuilder b( bb );
BSONObjIterator i( js ); BSONObjIterator i( js );
while ( i.more() ){ while ( i.more() ){
BSONElement e = i.next(); BSONElement e = i.next();
const char * fname = e.fieldName(); const char * fname = e.fieldName();
if ( strcmp( fname , "_id" ) == 0 ){ if ( strcmp( fname , "_id" ) == 0 ){
if (filter->includeID()) if (filter->includeID())
b.append( e ); b.append( e );
} else { } else {
filter->append( b , e ); filter->append( b , e );
} }
} }
if (loc)
b.append("$diskLoc", loc->toBSONObj());
b.done();
} else if (loc) {
BSONObjBuilder b( bb );
b.appendElements(js);
b.append("$diskLoc", loc->toBSONObj());
b.done(); b.done();
} else { } else {
bb.append((void*) js.objdata(), js.objsize()); bb.append((void*) js.objdata(), js.objsize());
} }
} }
typedef multimap<BSONObj,BSONObj,BSONObjCmp> BestMap; typedef multimap<BSONObj,BSONObj,BSONObjCmp> BestMap;
class ScanAndOrder { class ScanAndOrder {
BestMap best; // key -> full object BestMap best; // key -> full object
int startFrom; int startFrom;
int limit; // max to send back. int limit; // max to send back.
KeyType order; KeyType order;
unsigned approxSize; unsigned approxSize;
void _add(BSONObj& k, BSONObj o) { void _add(BSONObj& k, BSONObj o, DiskLoc* loc) {
best.insert(make_pair(k,o)); if (!loc){
best.insert(make_pair(k,o));
} else {
BSONObjBuilder b;
b.appendElements(o);
b.append("$diskLoc", loc->toBSONObj());
best.insert(make_pair(k, b.obj()));
}
} }
void _addIfBetter(BSONObj& k, BSONObj o, BestMap::iterator i) { void _addIfBetter(BSONObj& k, BSONObj o, BestMap::iterator i, DiskL oc* loc) {
const BSONObj& worstBestKey = i->first; const BSONObj& worstBestKey = i->first;
int c = worstBestKey.woCompare(k, order.pattern); int c = worstBestKey.woCompare(k, order.pattern);
if ( c > 0 ) { if ( c > 0 ) {
// k is better, 'upgrade' // k is better, 'upgrade'
best.erase(i); best.erase(i);
_add(k, o); _add(k, o, loc);
} }
} }
public: public:
ScanAndOrder(int _startFrom, int _limit, BSONObj _order) : ScanAndOrder(int _startFrom, int _limit, BSONObj _order) :
best( BSONObjCmp( _order ) ), best( BSONObjCmp( _order ) ),
startFrom(_startFrom), order(_order) { startFrom(_startFrom), order(_order) {
limit = _limit > 0 ? _limit + startFrom : 0x7fffffff; limit = _limit > 0 ? _limit + startFrom : 0x7fffffff;
approxSize = 0; approxSize = 0;
} }
int size() const { int size() const {
return best.size(); return best.size();
} }
void add(BSONObj o) { void add(BSONObj o, DiskLoc* loc) {
assert( o.isValid() ); assert( o.isValid() );
BSONObj k = order.getKeyFromObject(o); BSONObj k = order.getKeyFromObject(o);
if ( (int) best.size() < limit ) { if ( (int) best.size() < limit ) {
approxSize += k.objsize(); approxSize += k.objsize();
uassert( 10128 , "too much key data for sort() with no ind ex. add an index or specify a smaller limit", approxSize < 1 * 1024 * 1024 ); uassert( 10128 , "too much key data for sort() with no ind ex. add an index or specify a smaller limit", approxSize < 1 * 1024 * 1024 );
_add(k, o); _add(k, o, loc);
return; return;
} }
BestMap::iterator i; BestMap::iterator i;
assert( best.end() != best.begin() ); assert( best.end() != best.begin() );
i = best.end(); i = best.end();
i--; i--;
_addIfBetter(k, o, i); _addIfBetter(k, o, i, loc);
} }
void _fill(BufBuilder& b, FieldMatcher *filter, int& nout, BestMap: :iterator begin, BestMap::iterator end) { void _fill(BufBuilder& b, FieldMatcher *filter, int& nout, BestMap: :iterator begin, BestMap::iterator end) {
int n = 0; int n = 0;
int nFilled = 0; int nFilled = 0;
for ( BestMap::iterator i = begin; i != end; i++ ) { for ( BestMap::iterator i = begin; i != end; i++ ) {
n++; n++;
if ( n <= startFrom ) if ( n <= startFrom )
continue; continue;
BSONObj& o = i->second; BSONObj& o = i->second;
 End of changes. 8 change blocks. 
8 lines changed or deleted 22 lines changed or added


 security.h   security.h 
skipping to change at line 21 skipping to change at line 21
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <boost/thread/tss.hpp>
#undef assert
#define assert MONGO_assert
#include "nonce.h" #include "nonce.h"
#include "concurrency.h" #include "concurrency.h"
namespace mongo { namespace mongo {
// --noauth cmd line option // --noauth cmd line option
extern bool noauth; extern bool noauth;
/* for a particular db */ /* for a particular db */
struct Auth { struct Auth {
Auth() { level = 0; } Auth() { level = 0; }
int level; int level;
}; };
class AuthenticationInfo : boost::noncopyable { class AuthenticationInfo : boost::noncopyable {
mongo::mutex _lock; mongo::mutex _lock;
map<string, Auth> m; // dbname -> auth map<string, Auth> m; // dbname -> auth
static int warned; static int warned;
public: public:
bool isLocalHost; bool isLocalHost;
AuthenticationInfo() { isLocalHost = false; } AuthenticationInfo() : _lock("AuthenticationInfo") { isLocalHost = false; }
~AuthenticationInfo() { ~AuthenticationInfo() {
} }
void logout(const string& dbname ) { void logout(const string& dbname ) {
scoped_lock lk(_lock); scoped_lock lk(_lock);
m.erase(dbname); m.erase(dbname);
} }
void authorize(const string& dbname ) { void authorize(const string& dbname ) {
scoped_lock lk(_lock); scoped_lock lk(_lock);
m[dbname].level = 2; m[dbname].level = 2;
} }
 End of changes. 2 change blocks. 
5 lines changed or deleted 1 lines changed or added


 shard.h   shard.h 
skipping to change at line 38 skipping to change at line 38
class Shard { class Shard {
public: public:
Shard() Shard()
: _name(""),_addr(""){ : _name(""),_addr(""){
} }
Shard( const string& name , const string& addr ) Shard( const string& name , const string& addr )
: _name(name), _addr( addr ){ : _name(name), _addr( addr ){
} }
Shard( const string& ident ){
reset( ident );
}
Shard( const Shard& other ) Shard( const Shard& other )
: _name( other._name ) , _addr( other._addr ){ : _name( other._name ) , _addr( other._addr ){
} }
Shard( const Shard* other ) Shard( const Shard* other )
: _name( other->_name ) ,_addr( other->_addr ){ : _name( other->_name ) ,_addr( other->_addr ){
} }
static Shard make( const string& ident ){ static Shard make( const string& ident ){
Shard s; Shard s;
skipping to change at line 162 skipping to change at line 166
} }
private: private:
Shard _shard; Shard _shard;
long long _mapped; long long _mapped;
double _writeLock; double _writeLock;
}; };
class ShardConnection { class ShardConnection {
public: public:
ShardConnection( const Shard * s ) ShardConnection( const Shard * s , const string& ns );
: _conn( s->getConnString() ){ ShardConnection( const Shard& s , const string& ns );
} ShardConnection( const string& addr , const string& ns );
ShardConnection( const Shard& s ) void done();
: _conn( s.getConnString() ){ void kill();
}
ShardConnection( const string& addr ) DBClientBase& conn(){
: _conn( addr ){ assert( _conn );
return *_conn;
} }
void done(){ DBClientBase* operator->(){
_conn.done(); assert( _conn );
return _conn;
} }
void kill(){ DBClientBase* get(){
_conn.kill(); assert( _conn );
return _conn;
} }
DBClientBase& conn(){ string getHost() const {
return _conn.conn(); return _addr;
} }
DBClientBase* operator->(){ static void sync();
return _conn.get();
}
private: private:
ScopedDbConnection _conn; void _init();
string _addr;
string _ns;
DBClientBase* _conn;
}; };
} }
 End of changes. 9 change blocks. 
18 lines changed or deleted 26 lines changed or added


 shardkey.h   shardkey.h 
skipping to change at line 45 skipping to change at line 45
global min is the lowest possible value for this key global min is the lowest possible value for this key
e.g. { num : MinKey } e.g. { num : MinKey }
*/ */
BSONObj globalMin() const { return gMin; } BSONObj globalMin() const { return gMin; }
/** /**
global max is the highest possible value for this key global max is the highest possible value for this key
*/ */
BSONObj globalMax() const { return gMax; } BSONObj globalMax() const { return gMax; }
bool isGlobalMin( const BSONObj& k ){ bool isGlobalMin( const BSONObj& k ) const{
return k.woCompare( globalMin() ) == 0; return k.woCompare( globalMin() ) == 0;
} }
bool isGlobalMax( const BSONObj& k ){ bool isGlobalMax( const BSONObj& k ) const{
return k.woCompare( globalMax() ) == 0; return k.woCompare( globalMax() ) == 0;
} }
bool isGlobal( const BSONObj& k ){ bool isGlobal( const BSONObj& k ) const{
return isGlobalMin( k ) || isGlobalMax( k ); return isGlobalMin( k ) || isGlobalMax( k );
} }
/** compare shard keys from the objects specified /** compare shard keys from the objects specified
l < r negative l < r negative
l == r 0 l == r 0
l > r positive l > r positive
*/ */
int compare( const BSONObj& l , const BSONObj& r ); int compare( const BSONObj& l , const BSONObj& r ) const;
/** /**
@return whether or not obj has all fields in this shard key patt ern @return whether or not obj has all fields in this shard key patt ern
e.g. e.g.
ShardKey({num:1}).hasShardKey({ name:"joe", num:3 }) is true ShardKey({num:1}).hasShardKey({ name:"joe", num:3 }) is true
*/ */
bool hasShardKey( const BSONObj& obj ); bool hasShardKey( const BSONObj& obj ) const;
/** /**
returns a query that filters results only for the range desired, i.e. returns returns a query that filters results only for the range desired, i.e. returns
{ "field" : { $gte: keyval(min), $lt: keyval(max) } } { "field" : { $gte: keyval(min), $lt: keyval(max) } }
*/ */
void getFilter( BSONObjBuilder& b , const BSONObj& min, const BSONO bj& max ); void getFilter( BSONObjBuilder& b , const BSONObj& min, const BSONO bj& max ) const;
/** /**
Returns if the given sort pattern can be ordered by the shard ke y pattern. Returns if the given sort pattern can be ordered by the shard ke y pattern.
Example Example
sort: { ts: -1 } sort: { ts: -1 }
*this: { ts:1 } *this: { ts:1 }
-> -1 -> -1
@return @return
0 if sort either doesn't have all the fields or has extra fie lds 0 if sort either doesn't have all the fields or has extra fie lds
< 0 if sort is descending < 0 if sort is descending
> 1 if sort is ascending > 1 if sort is ascending
*/ */
int canOrder( const BSONObj& sort ); int canOrder( const BSONObj& sort ) const;
BSONObj key() { return pattern; } BSONObj key() const { return pattern; }
string toString() const; string toString() const;
BSONObj extractKey(const BSONObj& from) const; BSONObj extractKey(const BSONObj& from) const;
bool partOfShardKey(const string& key ) const { bool partOfShardKey(const string& key ) const {
return patternfields.count( key ) > 0; return patternfields.count( key ) > 0;
} }
bool uniqueAllowd( const BSONObj& otherPattern ) const; bool uniqueAllowd( const BSONObj& otherPattern ) const;
 End of changes. 8 change blocks. 
8 lines changed or deleted 8 lines changed or added


 snapshots.h   snapshots.h 
skipping to change at line 105 skipping to change at line 105
private: private:
mongo::mutex _lock; mongo::mutex _lock;
int _n; int _n;
boost::scoped_array<SnapshotData> _snapshots; boost::scoped_array<SnapshotData> _snapshots;
int _loc; int _loc;
int _stored; int _stored;
}; };
class SnapshotThread : public BackgroundJob { class SnapshotThread : public BackgroundJob {
public: public:
string name() { return "snapshot"; }
void run(); void run();
}; };
extern Snapshots statsSnapshots; extern Snapshots statsSnapshots;
extern SnapshotThread snapshotThread; extern SnapshotThread snapshotThread;
} }
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 sock.h   sock.h 
skipping to change at line 45 skipping to change at line 45
inline int getLastError() { inline int getLastError() {
return WSAGetLastError(); return WSAGetLastError();
} }
inline const char* gai_strerror(int code) { inline const char* gai_strerror(int code) {
return ::gai_strerrorA(code); return ::gai_strerrorA(code);
} }
inline void disableNagle(int sock) { inline void disableNagle(int sock) {
int x = 1; int x = 1;
if ( setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &x, sizeof (x)) ) if ( setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &x, sizeof (x)) )
out() << "ERROR: disableNagle failed" << endl; out() << "ERROR: disableNagle failed" << endl;
if ( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &x, sizeof
(x)) )
out() << "ERROR: SO_KEEPALIVE failed" << endl;
} }
inline void prebindOptions( int sock ) { inline void prebindOptions( int sock ) {
} }
// This won't actually be used on windows // This won't actually be used on windows
struct sockaddr_un { struct sockaddr_un {
short sun_family; short sun_family;
char sun_path[108]; // length from unix header char sun_path[108]; // length from unix header
}; };
skipping to change at line 87 skipping to change at line 89
inline void disableNagle(int sock) { inline void disableNagle(int sock) {
int x = 1; int x = 1;
#ifdef SOL_TCP #ifdef SOL_TCP
int level = SOL_TCP; int level = SOL_TCP;
#else #else
int level = SOL_SOCKET; int level = SOL_SOCKET;
#endif #endif
if ( setsockopt(sock, level, TCP_NODELAY, (char *) &x, sizeof(x)) ) if ( setsockopt(sock, level, TCP_NODELAY, (char *) &x, sizeof(x)) )
log() << "ERROR: disableNagle failed" << endl; log() << "ERROR: disableNagle failed: " << errnoWithDescription
() << endl;
#ifdef SO_KEEPALIVE
if ( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &x, sizeof
(x)) )
log() << "ERROR: SO_KEEPALIVE failed: " << errnoWithDescription
() << endl;
#endif
} }
inline void prebindOptions( int sock ) { inline void prebindOptions( int sock ) {
DEV log() << "doing prebind option" << endl; DEV log() << "doing prebind option" << endl;
int x = 1; int x = 1;
if ( setsockopt( sock , SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)) < 0 ) if ( setsockopt( sock , SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)) < 0 )
out() << "Failed to set socket opt, SO_REUSEADDR" << endl; out() << "Failed to set socket opt, SO_REUSEADDR" << endl;
} }
#endif #endif
skipping to change at line 241 skipping to change at line 248
int ec = gethostname(buf, 127); int ec = gethostname(buf, 127);
if ( ec || *buf == 0 ) { if ( ec || *buf == 0 ) {
log() << "can't get this server's hostname " << errnoWithDescri ption() << endl; log() << "can't get this server's hostname " << errnoWithDescri ption() << endl;
return ""; return "";
} }
return buf; return buf;
} }
class ListeningSockets { class ListeningSockets {
public: public:
ListeningSockets() : _sockets( new set<int>() ){ ListeningSockets() : _mutex("ListeningSockets"), _sockets( new set< int>() ){
} }
void add( int sock ){ void add( int sock ){
scoped_lock lk( _mutex ); scoped_lock lk( _mutex );
_sockets->insert( sock ); _sockets->insert( sock );
} }
void remove( int sock ){ void remove( int sock ){
scoped_lock lk( _mutex ); scoped_lock lk( _mutex );
_sockets->erase( sock ); _sockets->erase( sock );
} }
 End of changes. 3 change blocks. 
2 lines changed or deleted 13 lines changed or added


 syncclusterconnection.h   syncclusterconnection.h 
// syncclusterconnection.h // @file syncclusterconnection.h
/* /*
* Copyright 2010 10gen Inc. * Copyright 2010 10gen Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
skipping to change at line 25 skipping to change at line 26
* limitations under the License. * limitations under the License.
*/ */
#include "../pch.h" #include "../pch.h"
#include "dbclient.h" #include "dbclient.h"
#include "redef_macros.h" #include "redef_macros.h"
namespace mongo { namespace mongo {
/** /**
* this is a connection to a cluster of servers that operate as one * This is a connection to a cluster of servers that operate as one
* for super high durability * for super high durability.
*
* Write operations are two-phase. First, all nodes are asked to fsync
. If successful
* everywhere, the write is sent everywhere and then followed by an fsy
nc. There is no
* rollback if a problem occurs during the second phase. Naturally, wi
th all these fsyncs,
* these operations will be quite slow -- use sparingly.
*
* Read operations are sent to a single random node.
*
* The class checks if a command is read or write style, and sends to a
single
* node if a read lock command and to all in two phases with a write st
yle command.
*/ */
class SyncClusterConnection : public DBClientBase { class SyncClusterConnection : public DBClientBase {
public: public:
/** /**
* @param commaSeperated should be 3 hosts comma seperated * @param commaSeparated should be 3 hosts comma separated
*/ */
SyncClusterConnection( string commaSeperated ); SyncClusterConnection( const list<HostAndPort> & );
SyncClusterConnection( string commaSeparated );
SyncClusterConnection( string a , string b , string c ); SyncClusterConnection( string a , string b , string c );
~SyncClusterConnection(); ~SyncClusterConnection();
/** /**
* @return true if all servers are up and ready for writes * @return true if all servers are up and ready for writes
*/ */
bool prepare( string& errmsg ); bool prepare( string& errmsg );
/** /**
* runs fsync on all servers * runs fsync on all servers
skipping to change at line 64 skipping to change at line 76
virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo ng cursorId, int nToReturn, int options ); virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo ng cursorId, int nToReturn, int options );
virtual void insert( const string &ns, BSONObj obj ); virtual void insert( const string &ns, BSONObj obj );
virtual void insert( const string &ns, const vector< BSONObj >& v ) ; virtual void insert( const string &ns, const vector< BSONObj >& v ) ;
virtual void remove( const string &ns , Query query, bool justOne ) ; virtual void remove( const string &ns , Query query, bool justOne ) ;
virtual void update( const string &ns , Query query , BSONObj obj , bool upsert , bool multi ); virtual void update( const string &ns , Query query , BSONObj obj , bool upsert , bool multi );
virtual string toString(){
return _toString();
}
virtual bool call( Message &toSend, Message &response, bool assertO k ); virtual bool call( Message &toSend, Message &response, bool assertO k );
virtual void say( Message &toSend ); virtual void say( Message &toSend );
virtual void sayPiggyBack( Message &toSend ); virtual void sayPiggyBack( Message &toSend );
virtual string getServerAddress() const { return _address; } virtual string getServerAddress() const { return _address; }
virtual bool isFailed() const { return false; }
virtual bool isFailed() const { virtual string toString() { return _toString(); }
return false;
}
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 );
string _address; string _address;
vector<DBClientConnection*> _conns; vector<DBClientConnection*> _conns;
map<string,int> _lockTypes; map<string,int> _lockTypes;
mongo::mutex _mutex; mongo::mutex _mutex;
}; };
}; };
#include "undef_macros.h" #include "undef_macros.h"
 End of changes. 14 change blocks. 
21 lines changed or deleted 24 lines changed or added


 thread_pool.h   thread_pool.h 
skipping to change at line 32 skipping to change at line 32
namespace mongo { namespace mongo {
namespace threadpool { namespace threadpool {
class Worker; class Worker;
typedef boost::function<void(void)> Task; //nullary function or functor typedef boost::function<void(void)> Task; //nullary function or functor
// exported to the mongo namespace // exported to the mongo namespace
class ThreadPool : boost::noncopyable{ class ThreadPool : boost::noncopyable{
public: public:
explicit ThreadPool(int nThreads=8); explicit ThreadPool(int nThreads=8);
// blocks until all tasks are complete (tasks_remaining() == 0) // blocks until all tasks are complete (tasks_remaining() == 0)
// You should not call schedule while in the destructor // You should not call schedule while in the destructor
~ThreadPool(); ~ThreadPool();
// blocks until all tasks are complete (tasks_remaining() == 0) // blocks until all tasks are complete (tasks_remaining() == 0)
// does not prevent new tasks from being scheduled so could wait fo rever. // does not prevent new tasks from being scheduled so could wait fo rever.
// Also, new tasks could be scheduled after this returns. // Also, new tasks could be scheduled after this returns.
void join(); void join();
skipping to change at line 62 skipping to change at line 62
void schedule(F f, A a, B b){ schedule(boost::bind(f,a,b)); } void schedule(F f, A a, B b){ schedule(boost::bind(f,a,b)); }
template<typename F, typename A, typename B, typename C> template<typename F, typename A, typename B, typename C>
void schedule(F f, A a, B b, C c){ schedule(boost::bind(f,a,b,c)); } void schedule(F f, A a, B b, C c){ schedule(boost::bind(f,a,b,c)); }
template<typename F, typename A, typename B, typename C, typename D > template<typename F, typename A, typename B, typename C, typename D >
void schedule(F f, A a, B b, C c, D d){ schedule(boost::bind(f,a,b, c,d)); } void schedule(F f, A a, B b, C c, D d){ schedule(boost::bind(f,a,b, c,d)); }
template<typename F, typename A, typename B, typename C, typename D , typename E> template<typename F, typename A, typename B, typename C, typename D , typename E>
void schedule(F f, A a, B b, C c, D d, E e){ schedule(boost::bind(f ,a,b,c,d,e)); } void schedule(F f, A a, B b, C c, D d, E e){ schedule(boost::bind(f ,a,b,c,d,e)); }
int tasks_remaining() { return _tasksRemaining; } int tasks_remaining() { return _tasksRemaining; }
private: private:
mongo::mutex _mutex; mongo::mutex _mutex;
boost::condition _condition; boost::condition _condition;
list<Worker*> _freeWorkers; //used as LIFO stack (always front) list<Worker*> _freeWorkers; //used as LIFO stack (always front)
list<Task> _tasks; //used as FIFO queue (push_back, pop_front) list<Task> _tasks; //used as FIFO queue (push_back, pop_front)
int _tasksRemaining; // in queue + currently processing int _tasksRemaining; // in queue + currently processing
int _nThreads; // only used for sanity checking. could be removed i n the future. int _nThreads; // only used for sanity checking. could be removed i n the future.
// should only be called by a worker from the worker's thread // should only be called by a worker from the worker's thread
void task_done(Worker* worker); void task_done(Worker* worker);
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 top.h   top.h 
skipping to change at line 32 skipping to change at line 32
#define assert MONGO_assert #define assert MONGO_assert
namespace mongo { namespace mongo {
/** /**
* tracks usage by collection * tracks usage by collection
*/ */
class Top { class Top {
public: public:
Top() : _lock("Top") { }
class UsageData { class UsageData {
public: public:
UsageData() : time(0) , count(0){} UsageData() : time(0) , count(0){}
UsageData( const UsageData& older , const UsageData& newer ); UsageData( const UsageData& older , const UsageData& newer );
long long time; long long time;
long long count; long long count;
void inc( long long micros ){ void inc( long long micros ){
count++; count++;
time += micros; time += micros;
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 undef_macros.h   undef_macros.h 
skipping to change at line 35 skipping to change at line 35
#if !defined(MONGO_EXPOSE_MACROS) && !defined(MONGO_MACROS_CLEANED) #if !defined(MONGO_EXPOSE_MACROS) && !defined(MONGO_MACROS_CLEANED)
// util/allocator.h // util/allocator.h
#undef malloc #undef malloc
#undef realloc #undef realloc
// util/assert_util.h // util/assert_util.h
#undef assert #undef assert
#undef dassert #undef dassert
#undef wassert #undef wassert
#undef massert
#undef uassert
#undef BOOST_CHECK_EXCEPTION #undef BOOST_CHECK_EXCEPTION
#undef DESTRUCTOR_GUARD #undef DESTRUCTOR_GUARD
// util/goodies.h // util/goodies.h
#undef PRINT #undef PRINT
#undef PRINTFL #undef PRINTFL
#undef asctime #undef asctime
#undef gmtime #undef gmtime
#undef localtime #undef localtime
#undef ctime #undef ctime
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 update.h   update.h 
skipping to change at line 103 skipping to change at line 103
switch (op){ switch (op){
case PUSH: case PUSH:
case PUSH_ALL: case PUSH_ALL:
case POP: case POP:
return true; return true;
default: default:
return false; return false;
} }
} }
bool isIndexed( const set<string>& idxKeys ) const { static bool isIndexed( const string& fullName , const set<string>&
idxKeys ){
const char * fieldName = fullName.c_str();
// check if there is an index key that is a parent of mod // check if there is an index key that is a parent of mod
for( const char *dot = strchr( fieldName, '.' ); dot; dot = str chr( dot + 1, '.' ) ) for( const char *dot = strchr( fieldName, '.' ); dot; dot = str chr( dot + 1, '.' ) )
if ( idxKeys.count( string( fieldName, dot - fieldName ) ) ) if ( idxKeys.count( string( fieldName, dot - fieldName ) ) )
return true; return true;
string fullName = fieldName;
// check if there is an index key equal to mod // check if there is an index key equal to mod
if ( idxKeys.count(fullName) ) if ( idxKeys.count(fullName) )
return true; return true;
// check if there is an index key that is a child of mod // check if there is an index key that is a child of mod
set< string >::const_iterator j = idxKeys.upper_bound( fullName ); set< string >::const_iterator j = idxKeys.upper_bound( fullName );
if ( j != idxKeys.end() && j->find( fullName ) == 0 && (*j)[ful lName.size()] == '.' ) if ( j != idxKeys.end() && j->find( fullName ) == 0 && (*j)[ful lName.size()] == '.' )
return true; return true;
return false;
}
bool isIndexed( const set<string>& idxKeys ) const {
string fullName = fieldName;
if ( isIndexed( fullName , idxKeys ) )
return true;
if ( strstr( fieldName , "." ) ){
// check for a.0.1
StringBuilder buf( fullName.size() + 1 );
for ( size_t i=0; i<fullName.size(); i++ ){
char c = fullName[i];
buf << c;
if ( c != '.' )
continue;
if ( ! isdigit( fullName[i+1] ) )
continue;
bool possible = true;
size_t j=i+2;
for ( ; j<fullName.size(); j++ ){
char d = fullName[j];
if ( d == '.' )
break;
if ( isdigit( d ) )
continue;
possible = false;
break;
}
if ( possible )
i = j;
}
string x = buf.str();
if ( isIndexed( x , idxKeys ) )
return true;
}
return false; return false;
} }
template< class Builder > template< class Builder >
void apply( Builder& b , BSONElement in , ModState& ms ) const; void apply( Builder& b , BSONElement in , ModState& ms ) const;
/** /**
* @return true iff toMatch should be removed from the array * @return true iff toMatch should be removed from the array
*/ */
bool _pullElementMatch( BSONElement& toMatch ) const; bool _pullElementMatch( BSONElement& toMatch ) const;
skipping to change at line 368 skipping to change at line 412
case Mod::BIT: case Mod::BIT:
case Mod::BITAND: case Mod::BITAND:
case Mod::BITOR: case Mod::BITOR:
// TODO: should we convert this to $set? // TODO: should we convert this to $set?
return false; return false;
default: default:
return false; return false;
} }
} }
void appendForOpLog( BSONObjBuilder& b ) const { void appendForOpLog( BSONObjBuilder& b ) const;
if ( incType ){
BSONObjBuilder bb( b.subobjStart( "$set" ) );
appendIncValue( bb );
bb.done();
return;
}
const char * name = fixedOpName ? fixedOpName : Mod::modNames[o
p()];
BSONObjBuilder bb( b.subobjStart( name ) );
if ( fixed )
bb.appendAs( *fixed , m->fieldName );
else
bb.appendAs( m->elt , m->fieldName );
bb.done();
}
template< class Builder > template< class Builder >
void apply( Builder& b , BSONElement in ){ void apply( Builder& b , BSONElement in ){
m->apply( b , in , *this ); m->apply( b , in , *this );
} }
template< class Builder > template< class Builder >
void appendIncValue( Builder& b ) const { void appendIncValue( Builder& b , bool useFullName ) const {
const char * n = useFullName ? m->fieldName : m->shortFieldName
;
switch ( incType ){ switch ( incType ){
case NumberDouble: case NumberDouble:
b.append( m->shortFieldName , incdouble ); break; b.append( n , incdouble ); break;
case NumberLong: case NumberLong:
b.append( m->shortFieldName , inclong ); break; b.append( n , inclong ); break;
case NumberInt: case NumberInt:
b.append( m->shortFieldName , incint ); break; b.append( n , incint ); break;
default: default:
assert(0); assert(0);
} }
} }
string toString() const;
}; };
/** /**
* this is used to hold state, meta data while applying a ModSet to a B SONObj * this is used to hold state, meta data while applying a ModSet to a B SONObj
* the goal is to make ModSet const so its re-usable * the goal is to make ModSet const so its re-usable
*/ */
class ModSetState : boost::noncopyable { class ModSetState : boost::noncopyable {
struct FieldCmp { struct FieldCmp {
bool operator()( const string &l, const string &r ) const { bool operator()( const string &l, const string &r ) const {
return lexNumCmp( l.c_str(), r.c_str() ) < 0; return lexNumCmp( l.c_str(), r.c_str() ) < 0;
skipping to change at line 534 skipping to change at line 566
const ModState& m = i->second; const ModState& m = i->second;
if ( m.m->arrayDep() ){ if ( m.m->arrayDep() ){
if ( m.pushStartSize == -1 ) if ( m.pushStartSize == -1 )
b.appendNull( m.fieldName() ); b.appendNull( m.fieldName() );
else else
b << m.fieldName() << BSON( "$size" << m.pushStartS ize ); b << m.fieldName() << BSON( "$size" << m.pushStartS ize );
} }
} }
} }
string toString() const;
friend class ModSet; friend class ModSet;
}; };
} }
 End of changes. 10 change blocks. 
24 lines changed or deleted 59 lines changed or added


 util.h   util.h 
skipping to change at line 31 skipping to change at line 31
#include "../pch.h" #include "../pch.h"
#include "../client/dbclient.h" #include "../client/dbclient.h"
/** /**
some generic sharding utils that can be used in mongod or mongos some generic sharding utils that can be used in mongod or mongos
*/ */
namespace mongo { namespace mongo {
/** /**
your config info for a given shard/chunk is out of date */ * your config info for a given shard/chunk is out of date
class StaleConfigException : public std::exception { */
class StaleConfigException : public AssertionException {
public: public:
StaleConfigException( const string& ns , const string& msg){ StaleConfigException( const string& ns , const string& raw){
code = 9996;
stringstream s; stringstream s;
s << "StaleConfigException ns: " << ns << " " << msg; s << "StaleConfigException ns: " << ns << " " << raw;
_msg = s.str(); msg = s.str();
log(1) << _msg << endl; log(1) << msg << endl;
} }
virtual ~StaleConfigException() throw(){} virtual ~StaleConfigException() throw(){}
virtual const char* what() const throw(){
return _msg.c_str();
}
private: private:
string _msg;
}; };
void checkShardVersion( DBClientBase & conn , const string& ns , bool a uthoritative = false ); void checkShardVersion( DBClientBase & conn , const string& ns , bool a uthoritative = false );
} }
 End of changes. 5 change blocks. 
10 lines changed or deleted 8 lines changed or added


 value.h   value.h 
skipping to change at line 23 skipping to change at line 23
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
namespace mongo { namespace mongo {
/** this string COULD be mangled but with the double buffering, assuming wr ites /** this string COULD be mangled but with the double buffering, assumin g writes
are infrequent, it's unlikely. thus, this is reasonable for lockless s etting of are infrequent, it's unlikely. thus, this is reasonable for lockless s etting of
diagnostic strings, where their content isn't critical. diagnostic strings, where their content isn't critical.
*/ */
class DiagStr { class DiagStr {
char buf1[256]; char buf1[256];
char buf2[256]; char buf2[256];
char *p; char *p;
public: public:
DiagStr() { DiagStr() {
memset(buf1, 0, 256); memset(buf1, 0, 256);
memset(buf2, 0, 256); memset(buf2, 0, 256);
p = buf1; p = buf1;
} }
const char * get() const { return p; } const char * get() const { return p; }
void set(const char *s) { void set(const char *s) {
char *q = (p==buf1) ? buf2 : buf1; char *q = (p==buf1) ? buf2 : buf1;
strncpy(q, s, 255); strncpy(q, s, 255);
p = q; p = q;
} }
}; };
extern mutex _atomicMutex;
/** atomic wrapper for a value. enters a mutex on each access. must
be copyable.
*/
template<typename T>
class Atomic : boost::noncopyable {
T val;
public:
Atomic<T>() { }
void operator=(const T& a) {
scoped_lock lk(_atomicMutex);
val = a; }
operator T() const {
scoped_lock lk(_atomicMutex);
return val; }
class tran : private scoped_lock {
Atomic<T>& _a;
public:
tran(Atomic<T>& a) : scoped_lock(_atomicMutex), _a(a) { }
T& ref() { return _a.val; }
};
};
} }
 End of changes. 4 change blocks. 
18 lines changed or deleted 45 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/