accumulator.h   accumulator.h 
skipping to change at line 35 skipping to change at line 35
namespace mongo { namespace mongo {
class ExpressionContext; class ExpressionContext;
class Accumulator : class Accumulator :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n); virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n);
virtual void addToBsonObj( virtual void addToBsonObj(
BSONObjBuilder *pBuilder, string fieldName, unsigned depth) con BSONObjBuilder *pBuilder, string fieldName,
st; bool requireExpression) const;
virtual void addToBsonArray( virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const;
BSONArrayBuilder *pBuilder, unsigned depth) const;
/* /*
Get the accumulated value. Get the accumulated value.
@returns the accumulated value @returns the accumulated value
*/ */
virtual intrusive_ptr<const Value> getValue() const = 0; virtual intrusive_ptr<const Value> getValue() const = 0;
protected: protected:
Accumulator(); Accumulator();
skipping to change at line 59 skipping to change at line 59
/* /*
Convenience method for doing this for accumulators. The pattern Convenience method for doing this for accumulators. The pattern
is always the same, so a common implementation works, but require s is always the same, so a common implementation works, but require s
knowing the operator name. knowing the operator name.
@param pBuilder the builder to add to @param pBuilder the builder to add to
@param fieldName the projected name @param fieldName the projected name
@param opName the operator name @param opName the operator name
*/ */
void opToBson( void opToBson(
BSONObjBuilder *pBuilder, string fieldName, string opName, BSONObjBuilder *pBuilder, string fieldName, string opName) cons
unsigned depth) const; t;
}; };
class AccumulatorAddToSet : class AccumulatorAddToSet :
public Accumulator { public Accumulator {
public: public:
// virtuals from Expression // virtuals from Expression
virtual intrusive_ptr<const Value> evaluate( virtual intrusive_ptr<const Value> evaluate(
const intrusive_ptr<Document> &pDocument) const; const intrusive_ptr<Document> &pDocument) const;
virtual intrusive_ptr<const Value> getValue() const; virtual intrusive_ptr<const Value> getValue() const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
 End of changes. 2 change blocks. 
6 lines changed or deleted 5 lines changed or added


 alignedbuilder.h   alignedbuilder.h 
skipping to change at line 90 skipping to change at line 90
*((unsigned long long*)grow(sizeof(unsigned long long))) = j; *((unsigned long long*)grow(sizeof(unsigned long long))) = j;
} }
void appendBuf(const void *src, size_t len) { memcpy(grow((unsigned ) len), src, len); } void appendBuf(const void *src, size_t len) { memcpy(grow((unsigned ) len), src, len); }
template<class T> template<class T>
void appendStruct(const T& s) { appendBuf(&s, sizeof(T)); } void appendStruct(const T& s) { appendBuf(&s, sizeof(T)); }
void appendStr(const StringData &str , bool includeEOO = true ) { void appendStr(const StringData &str , bool includeEOO = true ) {
const unsigned len = str.size() + ( includeEOO ? 1 : 0 ); const unsigned len = str.size() + ( includeEOO ? 1 : 0 );
assert( len < (unsigned) BSONObjMaxUserSize ); verify( len < (unsigned) BSONObjMaxUserSize );
memcpy(grow(len), str.data(), len); memcpy(grow(len), str.data(), len);
} }
/** @return the in-use length */ /** @return the in-use length */
unsigned len() const { return _len; } unsigned len() const { return _len; }
private: private:
static const unsigned Alignment = 8192; static const unsigned Alignment = 8192;
/** returns the pre-grow write position */ /** returns the pre-grow write position */
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 allocator.h   allocator.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 "mongo/util/signal_handlers.h"
// we need the "real" malloc here
#include "mongo/client/undef_macros.h"
namespace mongo { namespace mongo {
inline void * ourmalloc(size_t size) { inline void * ourmalloc(size_t size) {
void *x = malloc(size); void *x = malloc(size);
if ( x == 0 ) dbexit( EXIT_OOM_MALLOC , "malloc fails"); if ( x == 0 ) printStackAndExit(0);
return x; return x;
} }
inline void * ourrealloc(void *ptr, size_t size) { inline void * ourrealloc(void *ptr, size_t size) {
void *x = realloc(ptr, size); void *x = realloc(ptr, size);
if ( x == 0 ) dbexit( EXIT_OOM_REALLOC , "realloc fails"); if ( x == 0 ) printStackAndExit(0);
return x; return x;
} }
#define MONGO_malloc mongo::ourmalloc #define MONGO_malloc mongo::ourmalloc
#define malloc MONGO_malloc
#define MONGO_realloc mongo::ourrealloc #define MONGO_realloc mongo::ourrealloc
#define realloc MONGO_realloc
// this redefines 'malloc' to 'MONGO_malloc', etc
#include "mongo/client/redef_macros.h"
} // namespace mongo } // namespace mongo
 End of changes. 5 change blocks. 
4 lines changed or deleted 10 lines changed or added


 array.h   array.h 
skipping to change at line 44 skipping to change at line 44
~FastArray() { ~FastArray() {
delete[] _data; delete[] _data;
} }
void clear() { void clear() {
_size = 0; _size = 0;
} }
T& operator[]( int x ) { T& operator[]( int x ) {
assert( x >= 0 && x < _capacity ); verify( x >= 0 && x < _capacity );
return _data[x]; return _data[x];
} }
T& getNext() { T& getNext() {
return _data[_size++]; return _data[_size++];
} }
void push_back( const T& t ) { void push_back( const T& t ) {
assert( _size < _capacity ); verify( _size < _capacity );
_data[_size++] = t; _data[_size++] = t;
} }
void sort( int (*comp)(const void *, const void *) ) { void sort( int (*comp)(const void *, const void *) ) {
qsort( _data , _size , sizeof(T) , comp ); qsort( _data , _size , sizeof(T) , comp );
} }
int size() { int size() {
return _size; return _size;
} }
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 assert_util.h   assert_util.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 "../bson/inline_decls.h" #include <iostream>
#include <typeinfo>
// MONGO_NORETURN undefed at end of file #include "mongo/bson/inline_decls.h"
#ifdef __GNUC__ #include "mongo/platform/compiler.h"
# define MONGO_NORETURN __attribute__((__noreturn__))
#else
# define MONGO_NORETURN
#endif
namespace mongo { namespace mongo {
enum CommonErrorCodes { enum CommonErrorCodes {
DatabaseDifferCaseCode = 13297 , DatabaseDifferCaseCode = 13297 ,
SendStaleConfigCode = 13388 , SendStaleConfigCode = 13388 ,
RecvStaleConfigCode = 9996 RecvStaleConfigCode = 9996
}; };
class AssertionCount { class AssertionCount {
skipping to change at line 153 skipping to change at line 150
}; };
class MsgAssertionException : public AssertionException { class MsgAssertionException : public AssertionException {
public: public:
MsgAssertionException( const ExceptionInfo& ei ) : AssertionExcepti on( ei ) {} MsgAssertionException( const ExceptionInfo& ei ) : AssertionExcepti on( ei ) {}
MsgAssertionException(int c, const std::string& m) : AssertionExcep tion( m , c ) {} MsgAssertionException(int c, const std::string& m) : AssertionExcep tion( m , c ) {}
virtual bool severe() { return false; } virtual bool severe() { return false; }
virtual void appendPrefix( std::stringstream& ss ) const; virtual void appendPrefix( std::stringstream& ss ) const;
}; };
void asserted(const char *msg, const char *file, unsigned line) MONGO_N ORETURN; MONGO_COMPILER_NORETURN void verifyFailed(const char *msg, const char * file, unsigned line);
void wasserted(const char *msg, const char *file, unsigned line); void wasserted(const char *msg, const char *file, unsigned line);
void verifyFailed( int msgid ); MONGO_COMPILER_NORETURN void fassertFailed( int msgid );
void fassertFailed( int msgid );
/** a "user assertion". throws UserAssertion. logs. typically used f or errors that a user /** a "user assertion". throws UserAssertion. logs. typically used f or errors that a user
could cause, such as duplicate key, disk full, etc. could cause, such as duplicate key, disk full, etc.
*/ */
void uasserted(int msgid, const char *msg) MONGO_NORETURN; MONGO_COMPILER_NORETURN void uasserted(int msgid, const char *msg);
void uasserted(int msgid , const std::string &msg); MONGO_COMPILER_NORETURN void uasserted(int msgid , const std::string &m
sg);
/** reported via lasterror, but don't throw exception */
void uassert_nothrow(const char *msg);
/** msgassert and massert are for errors that are internal but have a w ell defined error text std::string. /** msgassert and massert are for errors that are internal but have a w ell defined error text std::string.
a stack trace is logged. a stack trace is logged.
*/ */
void msgassertedNoTrace(int msgid, const char *msg) MONGO_NORETURN; MONGO_COMPILER_NORETURN void msgassertedNoTrace(int msgid, const char * msg);
inline void msgassertedNoTrace(int msgid, const std::string& msg) { msg assertedNoTrace( msgid , msg.c_str() ); } inline void msgassertedNoTrace(int msgid, const std::string& msg) { msg assertedNoTrace( msgid , msg.c_str() ); }
void msgasserted(int msgid, const char *msg) MONGO_NORETURN; MONGO_COMPILER_NORETURN void msgasserted(int msgid, const char *msg);
void msgasserted(int msgid, const std::string &msg); MONGO_COMPILER_NORETURN void msgasserted(int msgid, const std::string &
msg);
/* convert various types of exceptions to strings */ /* convert various types of exceptions to strings */
inline std::string causedBy( const char* e ){ return (std::string)" :: caused by :: " + e; } inline std::string causedBy( const char* e ){ return (std::string)" :: caused by :: " + e; }
inline std::string causedBy( const DBException& e ){ return causedBy( e .toString().c_str() ); } inline std::string causedBy( const DBException& e ){ return causedBy( e .toString().c_str() ); }
inline std::string causedBy( const std::exception& e ){ return causedBy ( e.what() ); } inline std::string causedBy( const std::exception& e ){ return causedBy ( e.what() ); }
inline std::string causedBy( const std::string& e ){ return causedBy( e .c_str() ); } inline std::string causedBy( const std::string& e ){ return causedBy( e .c_str() ); }
/** in the mongodb source, use verify() instead of assert(). verify is
always evaluated even in release builds. */
inline void verify( int msgid , bool testOK ) { if ( ! testOK ) verifyF
ailed( msgid ); }
/** abends on condition failure */ /** abends on condition failure */
inline void fassert( int msgid , bool testOK ) { if ( ! testOK ) fasser tFailed( msgid ); } inline void fassert( int msgid , bool testOK ) { if ( ! testOK ) fasser tFailed( msgid ); }
#ifdef assert
#undef assert
#endif
#define MONGO_assert(_Expression) (void)( MONGO_likely(!!(_Expression)) ||
(mongo::asserted(#_Expression, __FILE__, __LINE__), 0) )
#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 * /
#define MONGO_uassert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || ( mongo::uasserted(msgid, msg), 0) ) #define MONGO_uassert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || ( mongo::uasserted(msgid, msg), 0) )
#define uassert MONGO_uassert
/* warning only - keeps going */ /* warning only - keeps going */
#define MONGO_wassert(_Expression) (void)( MONGO_likely(!!(_Expression)) || (mongo::wasserted(#_Expression, __FILE__, __LINE__), 0) ) #define MONGO_wassert(_Expression) (void)( MONGO_likely(!!(_Expression)) || (mongo::wasserted(#_Expression, __FILE__, __LINE__), 0) )
#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.
*/ */
#define MONGO_massert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || ( mongo::msgasserted(msgid, msg), 0) ) #define MONGO_massert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || ( mongo::msgasserted(msgid, msg), 0) )
#define massert MONGO_massert /* same as massert except no msgid */
#define MONGO_verify(_Expression) (void)( MONGO_likely(!!(_Expression)) ||
(mongo::verifyFailed(#_Expression, __FILE__, __LINE__), 0) )
/* 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 verify
#else #else
# define MONGO_dassert(x) # define MONGO_dassert(x)
#endif #endif
#define dassert MONGO_dassert
#ifdef MONGO_EXPOSE_MACROS
# define dassert MONGO_dassert
# define verify MONGO_verify
# define uassert MONGO_uassert
# define wassert MONGO_wassert
# define massert MONGO_massert
#endif
// some special ids that we want to duplicate // some special ids that we want to duplicate
// > 10000 asserts // > 10000 asserts
// < 10000 UserException // < 10000 UserException
enum { ASSERT_ID_DUPKEY = 11000 }; enum { ASSERT_ID_DUPKEY = 11000 };
/* throws a uassertion with an appropriate msg */ /* throws a uassertion with an appropriate msg */
void streamNotGood( int code , std::string msg , std::ios& myios ) MONG O_NORETURN; MONGO_COMPILER_NORETURN void streamNotGood( int code , std::string msg , std::ios& myios );
inline void assertStreamGood(unsigned msgid, std::string msg, std::ios& myios) { inline void assertStreamGood(unsigned msgid, std::string msg, std::ios& myios) {
if( !myios.good() ) streamNotGood(msgid, msg, myios); if( !myios.good() ) streamNotGood(msgid, msg, myios);
} }
std::string demangleName( const type_info& typeinfo ); std::string demangleName( const std::type_info& typeinfo );
} // namespace mongo } // namespace mongo
#define BOOST_CHECK_EXCEPTION MONGO_BOOST_CHECK_EXCEPTION #define MONGO_ASSERT_ON_EXCEPTION( expression ) \
#define MONGO_BOOST_CHECK_EXCEPTION( expression ) \
try { \ try { \
expression; \ expression; \
} catch ( const std::exception &e ) { \ } catch ( const std::exception &e ) { \
stringstream ss; \ stringstream ss; \
ss << "caught boost exception: " << e.what() << ' ' << __FILE__ << ' ' << __LINE__; \ ss << "caught exception: " << e.what() << ' ' << __FILE__ << ' ' << __LINE__; \
msgasserted( 13294 , ss.str() ); \ msgasserted( 13294 , ss.str() ); \
} catch ( ... ) { \ } catch ( ... ) { \
massert( 10437 , "unknown boost failed" , false ); \ massert( 10437 , "unknown exception" , false ); \
} }
#define MONGO_BOOST_CHECK_EXCEPTION_WITH_MSG( expression, msg ) \ #define MONGO_ASSERT_ON_EXCEPTION_WITH_MSG( expression, msg ) \
try { \ try { \
expression; \ expression; \
} catch ( const std::exception &e ) { \ } catch ( const std::exception &e ) { \
stringstream ss; \ stringstream ss; \
ss << msg << " caught boost exception: " << e.what(); \ ss << msg << " caught exception exception: " << e.what(); \
msgasserted( 14043 , ss.str() ); \ msgasserted( 14043 , ss.str() ); \
} catch ( ... ) { \ } catch ( ... ) { \
msgasserted( 14044 , std::string("unknown boost failed ") + msg ); \ msgasserted( 14044 , std::string("unknown exception") + msg ); \
} }
#define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD #define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD
#define MONGO_DESTRUCTOR_GUARD( expression ) \ #define MONGO_DESTRUCTOR_GUARD( expression ) \
try { \ try { \
expression; \ expression; \
} catch ( const std::exception &e ) { \ } catch ( const std::exception &e ) { \
problem() << "caught exception (" << e.what() << ") in destructor ( " << __FUNCTION__ << ")" << endl; \ problem() << "caught exception (" << e.what() << ") in destructor ( " << __FUNCTION__ << ")" << endl; \
} catch ( ... ) { \ } catch ( ... ) { \
problem() << "caught unknown exception in destructor (" << __FUNCTI ON__ << ")" << endl; \ problem() << "caught unknown exception in destructor (" << __FUNCTI ON__ << ")" << endl; \
} }
#undef MONGO_NORETURN
 End of changes. 23 change blocks. 
45 lines changed or deleted 33 lines changed or added


 atomic_int.h   atomic_int.h 
skipping to change at line 25 skipping to change at line 25
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#if defined(_WIN32) #if defined(_WIN32)
# include <windows.h> # include <windows.h>
#endif #endif
#include "mongo/platform/compiler.h"
namespace mongo { namespace mongo {
struct AtomicUInt { /**
* An unsigned integer supporting atomic read-modify-write operations.
*
* Many operations on these types depend on natural alignment (4 byte a
lignment for 4-byte
* words, i.e.).
*/
struct MONGO_COMPILER_ALIGN_TYPE( 4 ) AtomicUInt {
AtomicUInt() : x(0) {} AtomicUInt() : x(0) {}
AtomicUInt(unsigned z) : x(z) { } AtomicUInt(unsigned z) : x(z) { }
operator unsigned() const { return x; } operator unsigned() const { return x; }
unsigned get() const { return x; } unsigned get() const { return x; }
inline void set(unsigned newX);
inline AtomicUInt operator++(); // ++prefix inline AtomicUInt operator++(); // ++prefix
inline AtomicUInt operator++(int);// postfix++ inline AtomicUInt operator++(int);// postfix++
inline AtomicUInt operator--(); // --prefix inline AtomicUInt operator--(); // --prefix
inline AtomicUInt operator--(int); // postfix-- inline AtomicUInt operator--(int); // postfix--
inline void signedAdd(int by);
inline void zero(); inline void zero() { set(0); }
volatile unsigned x; volatile unsigned x;
}; };
#if defined(_WIN32) #if defined(_WIN32)
void AtomicUInt::zero() { void AtomicUInt::set(unsigned newX) {
InterlockedExchange((volatile long*)&x, 0); InterlockedExchange((volatile long *)&x, newX);
} }
AtomicUInt AtomicUInt::operator++() { AtomicUInt AtomicUInt::operator++() {
return InterlockedIncrement((volatile long*)&x); return InterlockedIncrement((volatile long*)&x);
} }
AtomicUInt AtomicUInt::operator++(int) { AtomicUInt AtomicUInt::operator++(int) {
return InterlockedIncrement((volatile long*)&x)-1; return InterlockedIncrement((volatile long*)&x)-1;
} }
AtomicUInt AtomicUInt::operator--() { AtomicUInt AtomicUInt::operator--() {
return InterlockedDecrement((volatile long*)&x); return InterlockedDecrement((volatile long*)&x);
} }
AtomicUInt AtomicUInt::operator--(int) { AtomicUInt AtomicUInt::operator--(int) {
return InterlockedDecrement((volatile long*)&x)+1; return InterlockedDecrement((volatile long*)&x)+1;
} }
# if defined(_WIN64)
// don't see an InterlockedAdd for _WIN32...hmmm
void AtomicUInt::signedAdd(int by) {
InterlockedAdd((volatile long *)&x,by);
}
# endif
#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
// this is in GCC >= 4.1 // this is in GCC >= 4.1
inline void AtomicUInt::zero() { x = 0; } // TODO: this isn't thread sa fe - maybe inline void AtomicUInt::set(unsigned newX) { __sync_synchronize(); x = newX; }
AtomicUInt AtomicUInt::operator++() { AtomicUInt AtomicUInt::operator++() {
return __sync_add_and_fetch(&x, 1); return __sync_add_and_fetch(&x, 1);
} }
AtomicUInt AtomicUInt::operator++(int) { AtomicUInt AtomicUInt::operator++(int) {
return __sync_fetch_and_add(&x, 1); return __sync_fetch_and_add(&x, 1);
} }
AtomicUInt AtomicUInt::operator--() { AtomicUInt AtomicUInt::operator--() {
return __sync_add_and_fetch(&x, -1); return __sync_add_and_fetch(&x, -1);
} }
AtomicUInt AtomicUInt::operator--(int) { AtomicUInt AtomicUInt::operator--(int) {
return __sync_fetch_and_add(&x, -1); return __sync_fetch_and_add(&x, -1);
} }
void AtomicUInt::signedAdd(int by) {
__sync_fetch_and_add(&x, by);
}
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
inline void AtomicUInt::zero() { x = 0; } // TODO: this isn't thread sa inline void AtomicUInt::set(unsigned newX) {
fe asm volatile("mfence" ::: "memory");
x = newX;
}
// from boost 1.39 interprocess/detail/atomic.hpp // from boost 1.39 interprocess/detail/atomic.hpp
inline unsigned atomic_int_helper(volatile unsigned *x, int val) { inline unsigned atomic_int_helper(volatile unsigned *x, int val) {
int r; int r;
asm volatile asm volatile
( (
"lock\n\t" "lock\n\t"
"xadd %1, %0": "xadd %1, %0":
"+m"( *x ), "=r"( r ): // outputs (%0, %1) "+m"( *x ), "=r"( r ): // outputs (%0, %1)
"1"( val ): // inputs (%2 == %1) "1"( val ): // inputs (%2 == %1)
"memory", "cc" // clobbers "memory", "cc" // clobbers
skipping to change at line 102 skipping to change at line 124
} }
AtomicUInt AtomicUInt::operator++(int) { AtomicUInt AtomicUInt::operator++(int) {
return atomic_int_helper(&x, 1); return atomic_int_helper(&x, 1);
} }
AtomicUInt AtomicUInt::operator--() { AtomicUInt AtomicUInt::operator--() {
return atomic_int_helper(&x, -1)-1; return atomic_int_helper(&x, -1)-1;
} }
AtomicUInt AtomicUInt::operator--(int) { AtomicUInt AtomicUInt::operator--(int) {
return atomic_int_helper(&x, -1); return atomic_int_helper(&x, -1);
} }
void AtomicUInt::signedAdd(int by) {
atomic_int_helper(&x, by);
}
#else #else
# error "unsupported compiler or platform" # error "unsupported compiler or platform"
#endif #endif
} // namespace mongo } // namespace mongo
 End of changes. 11 change blocks. 
9 lines changed or deleted 34 lines changed or added


 background.h   background.h 
skipping to change at line 53 skipping to change at line 53
/* check for in progress before instantiating */ /* check for in progress before instantiating */
BackgroundOperation(const char *ns); BackgroundOperation(const char *ns);
virtual ~BackgroundOperation(); virtual ~BackgroundOperation();
private: private:
NamespaceString _ns; NamespaceString _ns;
static map<string, unsigned> dbsInProg; static map<string, unsigned> dbsInProg;
static set<string> nsInProg; static set<string> nsInProg;
static SimpleMutex m;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 balance.h   balance.h 
skipping to change at line 23 skipping to change at line 23
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "../util/background.h" #include "../util/background.h"
#include "../client/dbclient.h"
#include "balancer_policy.h" #include "balancer_policy.h"
namespace mongo { namespace mongo {
/** /**
* The balancer is a background task that tries to keep the number of c hunks across all servers of the cluster even. Although * The balancer is a background task that tries to keep the number of c hunks across all servers of the cluster even. Although
* every mongos will have one balancer running, only one of them will b e active at the any given point in time. The balancer * every mongos will have one balancer running, only one of them will b e active at the any given point in time. The balancer
* uses a 'DistributedLock' for that coordination. * uses a 'DistributedLock' for that coordination.
* *
* The balancer does act continuously but in "rounds". At a given round , it would decide if there is an imbalance by * The balancer does act continuously but in "rounds". At a given round , it would decide if there is an imbalance by
 End of changes. 1 change blocks. 
1 lines changed or deleted 0 lines changed or added


 base64.h   base64.h 
skipping to change at line 40 skipping to change at line 40
"+/") "+/")
, decode(new unsigned char[257]) { , decode(new unsigned char[257]) {
memset( decode.get() , 0 , 256 ); memset( decode.get() , 0 , 256 );
for ( int i=0; i<64; i++ ) { for ( int i=0; i<64; i++ ) {
decode[ encode[i] ] = i; decode[ encode[i] ] = i;
} }
test(); test();
} }
void test() { void test() {
assert( strlen( (char*)encode ) == 64 ); verify( strlen( (char*)encode ) == 64 );
for ( int i=0; i<26; i++ ) for ( int i=0; i<26; i++ )
assert( encode[i] == toupper( encode[i+26] ) ); verify( encode[i] == toupper( encode[i+26] ) );
} }
char e( int x ) { char e( int x ) {
return encode[x&0x3f]; return encode[x&0x3f];
} }
private: private:
const unsigned char * encode; const unsigned char * encode;
public: public:
boost::scoped_array<unsigned char> decode; boost::scoped_array<unsigned char> decode;
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 bson-inl.h   bson-inl.h 
skipping to change at line 124 skipping to change at line 124
case jstOID: case jstOID:
return memcmp(l.value(), r.value(), 12); return memcmp(l.value(), r.value(), 12);
case Code: case Code:
case Symbol: case Symbol:
case String: case String:
/* todo: a utf sort order version one day... */ /* todo: a utf sort order version one day... */
{ {
// we use memcmp as we allow zeros in UTF8 strings // we use memcmp as we allow zeros in UTF8 strings
int lsz = l.valuestrsize(); int lsz = l.valuestrsize();
int rsz = r.valuestrsize(); int rsz = r.valuestrsize();
int common = min(lsz, rsz); int common = std::min(lsz, rsz);
int res = memcmp(l.valuestr(), r.valuestr(), common); int res = memcmp(l.valuestr(), r.valuestr(), common);
if( res ) if( res )
return res; return res;
// longer string is the greater one // longer string is the greater one
return lsz-rsz; return lsz-rsz;
} }
case Object: case Object:
case Array: case Array:
return l.embeddedObject().woCompare( r.embeddedObject() ); return l.embeddedObject().woCompare( r.embeddedObject() );
case DBRef: { case DBRef: {
skipping to change at line 165 skipping to change at line 165
return f; return f;
f = strcmp( l.codeWScopeCode() , r.codeWScopeCode() ); f = strcmp( l.codeWScopeCode() , r.codeWScopeCode() );
if ( f ) if ( f )
return f; return f;
f = strcmp( l.codeWScopeScopeData() , r.codeWScopeScopeData() ) ; f = strcmp( l.codeWScopeScopeData() , r.codeWScopeScopeData() ) ;
if ( f ) if ( f )
return f; return f;
return 0; return 0;
} }
default: default:
assert( false); verify( false);
} }
return -1; return -1;
} }
/* wo = "well ordered" /* wo = "well ordered"
note: (mongodb related) : this can only change in behavior when inde x version # changes note: (mongodb related) : this can only change in behavior when inde x version # changes
*/ */
inline int BSONElement::woCompare( const BSONElement &e, inline int BSONElement::woCompare( const BSONElement &e,
bool considerFieldName ) const { bool considerFieldName ) const {
int lt = (int) canonicalType(); int lt = (int) canonicalType();
skipping to change at line 196 skipping to change at line 196
return x; return x;
} }
inline BSONObjIterator BSONObj::begin() const { inline BSONObjIterator BSONObj::begin() const {
return BSONObjIterator(*this); return BSONObjIterator(*this);
} }
inline BSONObj BSONElement::embeddedObjectUserCheck() const { inline BSONObj BSONElement::embeddedObjectUserCheck() const {
if ( MONGO_likely(isABSONObj()) ) if ( MONGO_likely(isABSONObj()) )
return BSONObj(value()); return BSONObj(value());
stringstream ss; std::stringstream ss;
ss << "invalid parameter: expected an object (" << fieldName() << " )"; ss << "invalid parameter: expected an object (" << fieldName() << " )";
uasserted( 10065 , ss.str() ); uasserted( 10065 , ss.str() );
return BSONObj(); // never reachable return BSONObj(); // never reachable
} }
inline BSONObj BSONElement::embeddedObject() const { inline BSONObj BSONElement::embeddedObject() const {
assert( isABSONObj() ); verify( isABSONObj() );
return BSONObj(value()); return BSONObj(value());
} }
inline BSONObj BSONElement::codeWScopeObject() const { inline BSONObj BSONElement::codeWScopeObject() const {
assert( type() == CodeWScope ); verify( type() == CodeWScope );
int strSizeWNull = *(int *)( value() + 4 ); int strSizeWNull = *(int *)( value() + 4 );
return BSONObj( value() + 4 + 4 + strSizeWNull ); return BSONObj( value() + 4 + 4 + strSizeWNull );
} }
// deep (full) equality // deep (full) equality
inline bool BSONObj::equal(const BSONObj &rhs) const { inline bool BSONObj::equal(const BSONObj &rhs) const {
BSONObjIterator i(*this); BSONObjIterator i(*this);
BSONObjIterator j(rhs); BSONObjIterator j(rhs);
BSONElement l,r; BSONElement l,r;
do { do {
skipping to change at line 321 skipping to change at line 321
while ( it.moreWithEOO() ) { while ( it.moreWithEOO() ) {
BSONElement e = it.next(); BSONElement e = it.next();
if ( e.eoo() ) break; if ( e.eoo() ) break;
append(e); append(e);
} }
return *this; return *this;
} }
/* add all the fields from the object specified to this object if they don't exist */ /* add all the fields from the object specified to this object if they don't exist */
inline BSONObjBuilder& BSONObjBuilder::appendElementsUnique(BSONObj x) { inline BSONObjBuilder& BSONObjBuilder::appendElementsUnique(BSONObj x) {
set<string> have; std::set<std::string> have;
{ {
BSONObjIterator i = iterator(); BSONObjIterator i = iterator();
while ( i.more() ) while ( i.more() )
have.insert( i.next().fieldName() ); have.insert( i.next().fieldName() );
} }
BSONObjIterator it(x); BSONObjIterator it(x);
while ( it.more() ) { while ( it.more() ) {
BSONElement e = it.next(); BSONElement e = it.next();
if ( have.count( e.fieldName() ) ) if ( have.count( e.fieldName() ) )
skipping to change at line 401 skipping to change at line 401
return *s_->_builder; return *s_->_builder;
} }
inline inline
BSONObjBuilder& Labeler::operator<<( const BSONElement& e ) { BSONObjBuilder& Labeler::operator<<( const BSONElement& e ) {
s_->subobj()->appendAs( e, l_.l_ ); s_->subobj()->appendAs( e, l_.l_ );
return *s_->_builder; return *s_->_builder;
} }
// {a: {b:1}} -> {a.b:1} // {a: {b:1}} -> {a.b:1}
void nested2dotted(BSONObjBuilder& b, const BSONObj& obj, const string& base=""); void nested2dotted(BSONObjBuilder& b, const BSONObj& obj, const std::st ring& base="");
inline BSONObj nested2dotted(const BSONObj& obj) { inline BSONObj nested2dotted(const BSONObj& obj) {
BSONObjBuilder b; BSONObjBuilder b;
nested2dotted(b, obj); nested2dotted(b, obj);
return b.obj(); return b.obj();
} }
// {a.b:1} -> {a: {b:1}} // {a.b:1} -> {a: {b:1}}
void dotted2nested(BSONObjBuilder& b, const BSONObj& obj); void dotted2nested(BSONObjBuilder& b, const BSONObj& obj);
inline BSONObj dotted2nested(const BSONObj& obj) { inline BSONObj dotted2nested(const BSONObj& obj) {
BSONObjBuilder b; BSONObjBuilder b;
skipping to change at line 435 skipping to change at line 435
if ( strcmp( name.data() , i.next().fieldName() ) == 0 ) if ( strcmp( name.data() , i.next().fieldName() ) == 0 )
return true; return true;
return false; return false;
} }
/* WARNING: nested/dotted conversions are not 100% reversible /* WARNING: nested/dotted conversions are not 100% reversible
* nested2dotted(dotted2nested({a.b: {c:1}})) -> {a.b.c: 1} * nested2dotted(dotted2nested({a.b: {c:1}})) -> {a.b.c: 1}
* also, dotted2nested ignores order * also, dotted2nested ignores order
*/ */
typedef map<string, BSONElement> BSONMap; typedef std::map<std::string, BSONElement> BSONMap;
inline BSONMap bson2map(const BSONObj& obj) { inline BSONMap bson2map(const BSONObj& obj) {
BSONMap m; BSONMap m;
BSONObjIterator it(obj); BSONObjIterator it(obj);
while (it.more()) { while (it.more()) {
BSONElement e = it.next(); BSONElement e = it.next();
m[e.fieldName()] = e; m[e.fieldName()] = e;
} }
return m; return m;
} }
struct BSONElementFieldNameCmp { struct BSONElementFieldNameCmp {
bool operator()( const BSONElement &l, const BSONElement &r ) const { bool operator()( const BSONElement &l, const BSONElement &r ) const {
return strcmp( l.fieldName() , r.fieldName() ) <= 0; return strcmp( l.fieldName() , r.fieldName() ) <= 0;
} }
}; };
typedef set<BSONElement, BSONElementFieldNameCmp> BSONSortedElements; typedef std::set<BSONElement, BSONElementFieldNameCmp> BSONSortedElemen ts;
inline BSONSortedElements bson2set( const BSONObj& obj ) { inline BSONSortedElements bson2set( const BSONObj& obj ) {
BSONSortedElements s; BSONSortedElements s;
BSONObjIterator it(obj); BSONObjIterator it(obj);
while ( it.more() ) while ( it.more() )
s.insert( it.next() ); s.insert( it.next() );
return s; return s;
} }
inline string BSONObj::toString( bool isArray, bool full ) const { inline std::string BSONObj::toString( bool isArray, bool full ) const {
if ( isEmpty() ) return "{}"; if ( isEmpty() ) return "{}";
StringBuilder s; StringBuilder s;
toString(s, isArray, full); toString(s, isArray, full);
return s.str(); return s.str();
} }
inline void BSONObj::toString(StringBuilder& s, bool isArray, bool ful l ) const { inline void BSONObj::toString( StringBuilder& s, bool isArray, bool fu ll, int depth ) const {
if ( isEmpty() ) { if ( isEmpty() ) {
s << "{}"; s << "{}";
return; return;
} }
s << ( isArray ? "[ " : "{ " ); s << ( isArray ? "[ " : "{ " );
BSONObjIterator i(*this); BSONObjIterator i(*this);
bool first = true; bool first = true;
while ( 1 ) { while ( 1 ) {
massert( 10327 , "Object does not end with EOO", i.moreWithEOO () ); massert( 10327 , "Object does not end with EOO", i.moreWithEOO () );
skipping to change at line 494 skipping to change at line 494
e.validate(); e.validate();
bool end = ( e.size() + offset == this->objsize() ); bool end = ( e.size() + offset == this->objsize() );
if ( e.eoo() ) { if ( e.eoo() ) {
massert( 10331 , "EOO Before end of object", end ); massert( 10331 , "EOO Before end of object", end );
break; break;
} }
if ( first ) if ( first )
first = false; first = false;
else else
s << ", "; s << ", ";
e.toString(s, !isArray, full ); e.toString( s, !isArray, full, depth );
} }
s << ( isArray ? " ]" : " }" ); s << ( isArray ? " ]" : " }" );
} }
inline void BSONElement::validate() const { inline void BSONElement::validate() const {
const BSONType t = type(); const BSONType t = type();
switch( t ) { switch( t ) {
case DBRef: case DBRef:
case Code: case Code:
skipping to change at line 601 skipping to change at line 601
case RegEx: { case RegEx: {
const char *p = value(); const char *p = value();
size_t len1 = ( maxLen == -1 ) ? strlen( p ) : (size_t)mongo::s trnlen( p, remain ); size_t len1 = ( maxLen == -1 ) ? strlen( p ) : (size_t)mongo::s trnlen( p, remain );
//massert( 10318 , "Invalid regex string", len1 != -1 ); // ER H - 4/28/10 - don't think this does anything //massert( 10318 , "Invalid regex string", len1 != -1 ); // ER H - 4/28/10 - don't think this does anything
p = p + len1 + 1; p = p + len1 + 1;
size_t len2; size_t len2;
if( maxLen == -1 ) if( maxLen == -1 )
len2 = strlen( p ); len2 = strlen( p );
else { else {
size_t x = remain - len1 - 1; size_t x = remain - len1 - 1;
assert( x <= 0x7fffffff ); verify( x <= 0x7fffffff );
len2 = mongo::strnlen( p, (int) x ); len2 = mongo::strnlen( p, (int) x );
} }
//massert( 10319 , "Invalid regex options string", len2 != -1 ); // ERH - 4/28/10 - don't think this does anything //massert( 10319 , "Invalid regex options string", len2 != -1 ); // ERH - 4/28/10 - don't think this does anything
x = (int) (len1 + 1 + len2 + 1); x = (int) (len1 + 1 + len2 + 1);
} }
break; break;
default: { default: {
StringBuilder ss; StringBuilder ss;
ss << "BSONElement: bad type " << (int) type(); ss << "BSONElement: bad type " << (int) type();
string msg = ss.str(); std::string msg = ss.str();
massert( 13655 , msg.c_str(),false); massert( 13655 , msg.c_str(),false);
} }
} }
totalSize = x + fieldNameSize() + 1; // BSONType totalSize = x + fieldNameSize() + 1; // BSONType
return totalSize; return totalSize;
} }
inline int BSONElement::size() const { inline int BSONElement::size() const {
if ( totalSize >= 0 ) if ( totalSize >= 0 )
skipping to change at line 677 skipping to change at line 677
p = p + len1 + 1; p = p + len1 + 1;
size_t len2; size_t len2;
len2 = strlen( p ); len2 = strlen( p );
x = (int) (len1 + 1 + len2 + 1); x = (int) (len1 + 1 + len2 + 1);
} }
break; break;
default: default:
{ {
StringBuilder ss; StringBuilder ss;
ss << "BSONElement: bad type " << (int) type(); ss << "BSONElement: bad type " << (int) type();
string msg = ss.str(); std::string msg = ss.str();
massert(10320 , msg.c_str(),false); massert(10320 , msg.c_str(),false);
} }
} }
totalSize = x + fieldNameSize() + 1; // BSONType totalSize = x + fieldNameSize() + 1; // BSONType
return totalSize; return totalSize;
} }
inline string BSONElement::toString( bool includeFieldName, bool full ) const { inline std::string BSONElement::toString( bool includeFieldName, bool f ull ) const {
StringBuilder s; StringBuilder s;
toString(s, includeFieldName, full); toString(s, includeFieldName, full);
return s.str(); return s.str();
} }
inline void BSONElement::toString(StringBuilder& s, bool includeFieldNa inline void BSONElement::toString( StringBuilder& s, bool includeFieldN
me, bool full ) const { ame, bool full, int depth ) const {
if ( depth > BSONObj::maxToStringRecursionDepth ) {
// check if we want the full/complete string
if ( full ) {
StringBuilder s;
s << "Reached maximum recursion depth of ";
s << BSONObj::maxToStringRecursionDepth;
uassert(16150, s.str(), full != true);
}
s << "...";
return;
}
if ( includeFieldName && type() != EOO ) if ( includeFieldName && type() != EOO )
s << fieldName() << ": "; s << fieldName() << ": ";
switch ( type() ) { switch ( type() ) {
case EOO: case EOO:
s << "EOO"; s << "EOO";
break; break;
case mongo::Date: case mongo::Date:
s << "new Date(" << (long long) date() << ')'; s << "new Date(" << (long long) date() << ')';
break; break;
case RegEx: { case RegEx: {
skipping to change at line 720 skipping to change at line 733
case NumberLong: case NumberLong:
s << _numberLong(); s << _numberLong();
break; break;
case NumberInt: case NumberInt:
s << _numberInt(); s << _numberInt();
break; break;
case mongo::Bool: case mongo::Bool:
s << ( boolean() ? "true" : "false" ); s << ( boolean() ? "true" : "false" );
break; break;
case Object: case Object:
embeddedObject().toString(s, false, full); embeddedObject().toString(s, false, full, depth+1);
break; break;
case mongo::Array: case mongo::Array:
embeddedObject().toString(s, true, full); embeddedObject().toString(s, true, full, depth+1);
break; break;
case Undefined: case Undefined:
s << "undefined"; s << "undefined";
break; break;
case jstNULL: case jstNULL:
s << "null"; s << "null";
break; break;
case MaxKey: case MaxKey:
s << "MaxKey"; s << "MaxKey";
break; break;
skipping to change at line 798 skipping to change at line 811
} }
/* return has eoo() true if no match /* return has eoo() true if no match
supports "." notation to reach into embedded objects supports "." notation to reach into embedded objects
*/ */
inline BSONElement BSONObj::getFieldDotted(const char *name) const { inline BSONElement BSONObj::getFieldDotted(const char *name) const {
BSONElement e = getField( name ); BSONElement e = getField( name );
if ( e.eoo() ) { if ( e.eoo() ) {
const char *p = strchr(name, '.'); const char *p = strchr(name, '.');
if ( p ) { if ( p ) {
string left(name, p-name); std::string left(name, p-name);
BSONObj sub = getObjectField(left.c_str()); BSONObj sub = getObjectField(left.c_str());
return sub.isEmpty() ? BSONElement() : sub.getFieldDotted(p +1); return sub.isEmpty() ? BSONElement() : sub.getFieldDotted(p +1);
} }
} }
return e; return e;
} }
inline BSONObj BSONObj::getObjectField(const char *name) const { inline BSONObj BSONObj::getObjectField(const char *name) const {
BSONElement e = getField(name); BSONElement e = getField(name);
skipping to change at line 836 skipping to change at line 849
/* little endian ordering here, but perhaps that is ok regardless a s BSON is spec'd /* little endian ordering here, but perhaps that is ok regardless a s BSON is spec'd
to be little endian external to the system. (i.e. the rest of th e implementation of bson, to be little endian external to the system. (i.e. the rest of th e implementation of bson,
not this part, fails to support big endian) not this part, fails to support big endian)
*/ */
static char p[] = { /*size*/5, 0, 0, 0, /*eoo*/0 }; static char p[] = { /*size*/5, 0, 0, 0, /*eoo*/0 };
_objdata = p; _objdata = p;
} }
inline BSONObj BSONElement::Obj() const { return embeddedObjectUserChec k(); } inline BSONObj BSONElement::Obj() const { return embeddedObjectUserChec k(); }
inline BSONElement BSONElement::operator[] (const string& field) const { inline BSONElement BSONElement::operator[] (const std::string& field) c onst {
BSONObj o = Obj(); BSONObj o = Obj();
return o[field]; return o[field];
} }
inline void BSONObj::elems(vector<BSONElement> &v) const { inline void BSONObj::elems(std::vector<BSONElement> &v) const {
BSONObjIterator i(*this); BSONObjIterator i(*this);
while( i.more() ) while( i.more() )
v.push_back(i.next()); v.push_back(i.next());
} }
inline void BSONObj::elems(list<BSONElement> &v) const { inline void BSONObj::elems(std::list<BSONElement> &v) const {
BSONObjIterator i(*this); BSONObjIterator i(*this);
while( i.more() ) while( i.more() )
v.push_back(i.next()); v.push_back(i.next());
} }
template <class T> template <class T>
void BSONObj::Vals(vector<T>& v) const { void BSONObj::Vals(std::vector<T>& v) const {
BSONObjIterator i(*this); BSONObjIterator i(*this);
while( i.more() ) { while( i.more() ) {
T t; T t;
i.next().Val(t); i.next().Val(t);
v.push_back(t); v.push_back(t);
} }
} }
template <class T> template <class T>
void BSONObj::Vals(list<T>& v) const { void BSONObj::Vals(std::list<T>& v) const {
BSONObjIterator i(*this); BSONObjIterator i(*this);
while( i.more() ) { while( i.more() ) {
T t; T t;
i.next().Val(t); i.next().Val(t);
v.push_back(t); v.push_back(t);
} }
} }
template <class T> template <class T>
void BSONObj::vals(vector<T>& v) const { void BSONObj::vals(std::vector<T>& v) const {
BSONObjIterator i(*this); BSONObjIterator i(*this);
while( i.more() ) { while( i.more() ) {
try { try {
T t; T t;
i.next().Val(t); i.next().Val(t);
v.push_back(t); v.push_back(t);
} }
catch(...) { } catch(...) { }
} }
} }
template <class T> template <class T>
void BSONObj::vals(list<T>& v) const { void BSONObj::vals(std::list<T>& v) const {
BSONObjIterator i(*this); BSONObjIterator i(*this);
while( i.more() ) { while( i.more() ) {
try { try {
T t; T t;
i.next().Val(t); i.next().Val(t);
v.push_back(t); v.push_back(t);
} }
catch(...) { } catch(...) { }
} }
} }
inline ostream& operator<<( ostream &s, const BSONObj &o ) { inline std::ostream& operator<<( std::ostream &s, const BSONObj &o ) {
return s << o.toString(); return s << o.toString();
} }
inline ostream& operator<<( ostream &s, const BSONElement &e ) { inline std::ostream& operator<<( std::ostream &s, const BSONElement &e ) {
return s << e.toString(); return s << e.toString();
} }
inline StringBuilder& operator<<( StringBuilder &s, const BSONObj &o ) { inline StringBuilder& operator<<( StringBuilder &s, const BSONObj &o ) {
o.toString( s ); o.toString( s );
return s; return s;
} }
inline StringBuilder& operator<<( StringBuilder &s, const BSONElement & e ) { inline StringBuilder& operator<<( StringBuilder &s, const BSONElement & e ) {
e.toString( s ); e.toString( s );
return s; return s;
skipping to change at line 924 skipping to change at line 937
inline void BSONElement::Val(BSONObj& v) const { v = Obj(); } inline void BSONElement::Val(BSONObj& v) const { v = Obj(); }
template<typename T> template<typename T>
inline BSONFieldValue<BSONObj> BSONField<T>::query( const char * q , co nst T& t ) const { inline BSONFieldValue<BSONObj> BSONField<T>::query( const char * q , co nst T& t ) const {
BSONObjBuilder b; BSONObjBuilder b;
b.append( q , t ); b.append( q , t );
return BSONFieldValue<BSONObj>( _name , b.obj() ); return BSONFieldValue<BSONObj>( _name , b.obj() );
} }
// used by jsonString() // used by jsonString()
inline string escape( string s , bool escape_slash=false) { inline std::string escape( std::string s , bool escape_slash=false) {
StringBuilder ret; StringBuilder ret;
for ( string::iterator i = s.begin(); i != s.end(); ++i ) { for ( std::string::iterator i = s.begin(); i != s.end(); ++i ) {
switch ( *i ) { switch ( *i ) {
case '"': case '"':
ret << "\\\""; ret << "\\\"";
break; break;
case '\\': case '\\':
ret << "\\\\"; ret << "\\\\";
break; break;
case '/': case '/':
ret << (escape_slash ? "\\/" : "/"); ret << (escape_slash ? "\\/" : "/");
break; break;
skipping to change at line 966 skipping to change at line 979
ret << "\\u00" << toHexLower(&c, 1); ret << "\\u00" << toHexLower(&c, 1);
} }
else { else {
ret << *i; ret << *i;
} }
} }
} }
return ret.str(); return ret.str();
} }
inline string BSONObj::hexDump() const { inline std::string BSONObj::hexDump() const {
stringstream ss; std::stringstream ss;
const char *d = objdata(); const char *d = objdata();
int size = objsize(); int size = objsize();
for( int i = 0; i < size; ++i ) { for( int i = 0; i < size; ++i ) {
ss.width( 2 ); ss.width( 2 );
ss.fill( '0' ); ss.fill( '0' );
ss << hex << (unsigned)(unsigned char)( d[ i ] ) << dec; ss << std::hex << (unsigned)(unsigned char)( d[ i ] ) << std::d ec;
if ( ( d[ i ] >= '0' && d[ i ] <= '9' ) || ( d[ i ] >= 'A' && d [ i ] <= 'z' ) ) if ( ( d[ i ] >= '0' && d[ i ] <= '9' ) || ( d[ i ] >= 'A' && d [ i ] <= 'z' ) )
ss << '\'' << d[ i ] << '\''; ss << '\'' << d[ i ] << '\'';
if ( i != size - 1 ) if ( i != size - 1 )
ss << ' '; ss << ' ';
} }
return ss.str(); return ss.str();
} }
inline void BSONObjBuilder::appendKeys( const BSONObj& keyPattern , con st BSONObj& values ) { inline void BSONObjBuilder::appendKeys( const BSONObj& keyPattern , con st BSONObj& values ) {
BSONObjIterator i(keyPattern); BSONObjIterator i(keyPattern);
BSONObjIterator j(values); BSONObjIterator j(values);
while ( i.more() && j.more() ) { while ( i.more() && j.more() ) {
appendAs( j.next() , i.next().fieldName() ); appendAs( j.next() , i.next().fieldName() );
} }
assert( ! i.more() ); verify( ! i.more() );
assert( ! j.more() ); verify( ! j.more() );
} }
inline BSONObj BSONObj::removeField(const StringData& name) const { inline BSONObj BSONObj::removeField(const StringData& name) const {
BSONObjBuilder b; BSONObjBuilder b;
BSONObjIterator i(*this); BSONObjIterator i(*this);
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(name.data(), fname) ) if( strcmp(name.data(), fname) )
b.append(e); b.append(e);
 End of changes. 34 change blocks. 
37 lines changed or deleted 50 lines changed or added


 bson.h   bson.h 
skipping to change at line 56 skipping to change at line 56
#include <sstream> #include <sstream>
//#include <boost/utility.hpp> //#include <boost/utility.hpp>
namespace bson { namespace bson {
using std::string; using std::string;
using std::stringstream; using std::stringstream;
class assertion : public std::exception { class assertion : public std::exception {
public: public:
assertion( unsigned u , const string& s ) assertion( unsigned u , const std::string& s )
: id( u ) , msg( s ) { : id( u ) , msg( s ) {
stringstream ss; std::stringstream ss;
ss << "BsonAssertion id: " << u << " " << s; ss << "BsonAssertion id: " << u << " " << s;
full = ss.str(); full = ss.str();
} }
virtual ~assertion() throw() {} virtual ~assertion() throw() {}
virtual const char* what() const throw() { return full.c_str(); } virtual const char* what() const throw() { return full.c_str(); }
unsigned id; unsigned id;
string msg; std::string msg;
string full; std::string full;
}; };
} }
namespace mongo { namespace mongo {
#if !defined(assert) #if !defined(verify)
inline void assert(bool expr) { inline void verify(bool expr) {
if(!expr) { if(!expr) {
throw bson::assertion( 0 , "assertion failure in bson library" ); throw bson::assertion( 0 , "assertion failure in bson library" );
} }
} }
#endif #endif
#if !defined(uassert) #if !defined(uassert)
inline void uasserted(unsigned msgid, std::string s) { inline void uasserted(unsigned msgid, std::string s) {
throw bson::assertion( msgid , s ); throw bson::assertion( msgid , s );
} }
 End of changes. 4 change blocks. 
6 lines changed or deleted 6 lines changed or added


 bson_db.h   bson_db.h 
skipping to change at line 50 skipping to change at line 50
appendTimestamp( fieldName , t.asDate() ); appendTimestamp( fieldName , t.asDate() );
return *this; return *this;
} }
inline OpTime BSONElement::_opTime() const { inline OpTime BSONElement::_opTime() const {
if( type() == mongo::Date || type() == Timestamp ) if( type() == mongo::Date || type() == Timestamp )
return OpTime( *reinterpret_cast< const unsigned long long* >( value() ) ); return OpTime( *reinterpret_cast< const unsigned long long* >( value() ) );
return OpTime(); return OpTime();
} }
inline string BSONElement::_asCode() const { inline std::string BSONElement::_asCode() const {
switch( type() ) { switch( type() ) {
case mongo::String: case mongo::String:
case Code: case Code:
return string(valuestr(), valuestrsize()-1); return std::string(valuestr(), valuestrsize()-1);
case CodeWScope: case CodeWScope:
return string(codeWScopeCode(), *(int*)(valuestr())-1); return std::string(codeWScopeCode(), *(int*)(valuestr())-1);
default: default:
log() << "can't convert type: " << (int)(type()) << " to code" << endl; log() << "can't convert type: " << (int)(type()) << " to code" << std::endl;
} }
uassert( 10062 , "not code" , 0 ); uassert( 10062 , "not code" , 0 );
return ""; return "";
} }
inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(DateNowLab eler& id) { inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(DateNowLab eler& id) {
_builder->appendDate(_fieldName, jsTime()); _builder->appendDate(_fieldName, jsTime());
_fieldName = 0; _fieldName = 0;
return *_builder; return *_builder;
} }
 End of changes. 4 change blocks. 
4 lines changed or deleted 4 lines changed or added


 bsonelement.h   bsonelement.h 
skipping to change at line 62 skipping to change at line 62
-------- size() ------------ -------- size() ------------
-fieldNameSize- -fieldNameSize-
value() value()
type() type()
*/ */
class BSONElement { class BSONElement {
public: public:
/** These functions, which start with a capital letter, throw a Use rException if the /** These functions, which start with a capital letter, throw a Use rException if the
element is not of the required type. Example: element is not of the required type. Example:
string foo = obj["foo"].String(); // exception if not a string type or DNE std::string foo = obj["foo"].String(); // std::exception if not a std::string type or DNE
*/ */
string String() const { return chk(mongo::String).value str(); } std::string String() const { return chk(mongo::String).value str(); }
Date_t Date() const { return chk(mongo::Date).date(); } Date_t Date() const { return chk(mongo::Date).date(); }
double Number() const { return chk(isNumber()).number() ; } double Number() const { return chk(isNumber()).number() ; }
double Double() const { return chk(NumberDouble)._numbe rDouble(); } double Double() const { return chk(NumberDouble)._numbe rDouble(); }
long long Long() const { return chk(NumberLong)._numberL ong(); } long long Long() const { return chk(NumberLong)._numberL ong(); }
int Int() const { return chk(NumberInt)._numberIn t(); } int Int() const { return chk(NumberInt)._numberIn t(); }
bool Bool() const { return chk(mongo::Bool).boolean (); } bool Bool() const { return chk(mongo::Bool).boolean (); }
vector<BSONElement> Array() const; // see implementation for detail ed comments std::vector<BSONElement> Array() const; // see implementation for d etailed comments
mongo::OID OID() const { return chk(jstOID).__oid(); } mongo::OID OID() const { return chk(jstOID).__oid(); }
void Null() const { chk(isNull()); } // throw UserE xception if not null void Null() const { chk(isNull()); } // throw UserE xception if not null
void OK() const { chk(ok()); } // throw UserE xception if element DNE void OK() const { chk(ok()); } // throw UserE xception if element DNE
/** @return the embedded object associated with this field. /** @return the embedded object associated with this field.
Note the returned object is a reference to within the parent bs on object. If that Note the returned object is a reference to within the parent bs on object. If that
object is out of scope, this pointer will no longer be valid. Ca ll getOwned() on the object is out of scope, this pointer will no longer be valid. Ca ll getOwned() on the
returned BSONObj if you need your own copy. returned BSONObj if you need your own copy.
throws UserException if the element is not of type object. throws UserException if the element is not of type object.
*/ */
skipping to change at line 94 skipping to change at line 94
/** populate v with the value of the element. If type does not mat ch, throw exception. /** populate v with the value of the element. If type does not mat ch, throw exception.
useful in templates -- see also BSONObj::Vals(). useful in templates -- see also BSONObj::Vals().
*/ */
void Val(Date_t& v) const { v = Date(); } void Val(Date_t& v) const { v = Date(); }
void Val(long long& v) const { v = Long(); } void Val(long long& v) const { v = Long(); }
void Val(bool& v) const { v = Bool(); } void Val(bool& v) const { v = Bool(); }
void Val(BSONObj& v) const; void Val(BSONObj& v) const;
void Val(mongo::OID& v) const { v = OID(); } void Val(mongo::OID& v) const { v = OID(); }
void Val(int& v) const { v = Int(); } void Val(int& v) const { v = Int(); }
void Val(double& v) const { v = Double(); } void Val(double& v) const { v = Double(); }
void Val(string& v) const { v = String(); } void Val(std::string& v) const { v = String(); }
/** Use ok() to check if a value is assigned: /** Use ok() to check if a value is assigned:
if( myObj["foo"].ok() ) ... if( myObj["foo"].ok() ) ...
*/ */
bool ok() const { return !eoo(); } bool ok() const { return !eoo(); }
string toString( bool includeFieldName = true, bool full=false) con std::string toString( bool includeFieldName = true, bool full=false
st; ) const;
void toString(StringBuilder& s, bool includeFieldName = true, bool void toString(StringBuilder& s, bool includeFieldName = true, bool
full=false) const; full=false, int depth=0) const;
string jsonString( JsonStringFormat format, bool includeFieldNames std::string jsonString( JsonStringFormat format, bool includeFieldN
= true, int pretty = 0 ) const; ames = true, int pretty = 0 ) const;
operator string() const { return toString(); } operator std::string() const { return toString(); }
/** Returns the type of the element */ /** Returns the type of the element */
BSONType type() const { return (BSONType) *data; } BSONType type() const { return (BSONType) *reinterpret_cast< const signed char * >(data); }
/** retrieve a field within this element /** retrieve a field within this element
throws exception if *this is not an embedded object throws exception if *this is not an embedded object
*/ */
BSONElement operator[] (const string& field) const; BSONElement operator[] (const std::string& field) const;
/** returns the tyoe of the element fixed for the main type /** returns the tyoe of the element fixed for the main type
the main purpose is numbers. any numeric type will return Numb erDouble the main purpose is numbers. any numeric type will return Numb erDouble
Note: if the order changes, indexes have to be re-built or than can be corruption Note: if the order changes, indexes have to be re-built or than can be corruption
*/ */
int canonicalType() const; int canonicalType() const;
/** Indicates if it is the end-of-object element, which is present at the end of /** Indicates if it is the end-of-object element, which is present at the end of
every BSON object. every BSON object.
*/ */
skipping to change at line 186 skipping to change at line 186
*/ */
bool trueValue() const; bool trueValue() const;
/** True if number, string, bool, date, OID */ /** True if number, string, bool, date, OID */
bool isSimpleType() const; bool isSimpleType() const;
/** True if element is of a numeric type. */ /** True if element is of a numeric type. */
bool isNumber() const; bool isNumber() const;
/** Return double value for this field. MUST be NumberDouble type. */ /** Return double value for this field. MUST be NumberDouble type. */
double _numberDouble() const {return *reinterpret_cast< const doubl e* >( value() ); } double _numberDouble() const {return (reinterpret_cast< const Packe dDouble* >( value() ))->d; }
/** Return int value for this field. MUST be NumberInt type. */ /** Return int value for this field. MUST be NumberInt type. */
int _numberInt() const {return *reinterpret_cast< const int* >( val ue() ); } int _numberInt() const {return *reinterpret_cast< const int* >( val ue() ); }
/** Return long long value for this field. MUST be NumberLong type. */ /** Return long long value for this field. MUST be NumberLong type. */
long long _numberLong() const {return *reinterpret_cast< const long long* >( value() ); } long long _numberLong() const {return *reinterpret_cast< const long long* >( value() ); }
/** Retrieve int value for the element safely. Zero returned if no t a number. */ /** Retrieve int value for the element safely. Zero returned if no t a number. */
int numberInt() const; int numberInt() const;
/** Retrieve long value for the element safely. Zero returned if n ot a number. */ /** Retrieve long value for the element safely. Zero returned if n ot a number. */
long long numberLong() const; long long numberLong() const;
/** Retrieve the numeric value of the element. If not of a numeric type, returns 0. /** Retrieve the numeric value of the element. If not of a numeric type, returns 0.
skipping to change at line 239 skipping to change at line 239
*/ */
const char * valuestr() const { const char * valuestr() const {
return value() + 4; return value() + 4;
} }
/** Get the string value of the element. If not a string returns " ". */ /** Get the string value of the element. If not a string returns " ". */
const char *valuestrsafe() const { const char *valuestrsafe() const {
return type() == mongo::String ? valuestr() : ""; return type() == mongo::String ? valuestr() : "";
} }
/** Get the string value of the element. If not a string returns " ". */ /** Get the string value of the element. If not a string returns " ". */
string str() const { std::string str() const {
return type() == mongo::String ? string(valuestr(), valuestrsiz return type() == mongo::String ? std::string(valuestr(), values
e()-1) : string(); trsize()-1) : std::string();
} }
/** Get javascript code of a CodeWScope data element. */ /** Get javascript code of a CodeWScope data element. */
const char * codeWScopeCode() const { const char * codeWScopeCode() const {
return value() + 8; return value() + 8;
} }
/** Get the scope SavedContext of a CodeWScope data element. */ /** Get the scope SavedContext of a CodeWScope data element. */
const char * codeWScopeScopeData() const { const char * codeWScopeScopeData() const {
// TODO fix // TODO fix
return codeWScopeCode() + strlen( codeWScopeCode() ) + 1; return codeWScopeCode() + strlen( codeWScopeCode() ) + 1;
skipping to change at line 264 skipping to change at line 264
BSONObj embeddedObject() const; BSONObj embeddedObject() const;
/* uasserts if not an object */ /* uasserts if not an object */
BSONObj embeddedObjectUserCheck() const; BSONObj embeddedObjectUserCheck() const;
BSONObj codeWScopeObject() const; BSONObj codeWScopeObject() const;
/** Get raw binary data. Element must be of type BinData. Doesn't handle type 2 specially */ /** Get raw binary data. Element must be of type BinData. Doesn't handle type 2 specially */
const char *binData(int& len) const { const char *binData(int& len) const {
// BinData: <int len> <byte subtype> <byte[len] data> // BinData: <int len> <byte subtype> <byte[len] data>
assert( type() == BinData ); verify( type() == BinData );
len = valuestrsize(); len = valuestrsize();
return value() + 5; return value() + 5;
} }
/** Get binary data. Element must be of type BinData. Handles type 2 */ /** Get binary data. Element must be of type BinData. Handles type 2 */
const char *binDataClean(int& len) const { const char *binDataClean(int& len) const {
// BinData: <int len> <byte subtype> <byte[len] data> // BinData: <int len> <byte subtype> <byte[len] data>
if (binDataType() != ByteArrayDeprecated) { if (binDataType() != ByteArrayDeprecated) {
return binData(len); return binData(len);
} }
else { else {
// Skip extra size // Skip extra size
len = valuestrsize() - 4; len = valuestrsize() - 4;
return value() + 5 + 4; return value() + 5 + 4;
} }
} }
BinDataType binDataType() const { BinDataType binDataType() const {
// BinData: <int len> <byte subtype> <byte[len] data> // BinData: <int len> <byte subtype> <byte[len] data>
assert( type() == BinData ); verify( type() == BinData );
unsigned char c = (value() + 4)[0]; unsigned char c = (value() + 4)[0];
return (BinDataType)c; return (BinDataType)c;
} }
/** Retrieve the regex string for a Regex element */ /** Retrieve the regex string for a Regex element */
const char *regex() const { const char *regex() const {
assert(type() == RegEx); verify(type() == RegEx);
return value(); return value();
} }
/** Retrieve the regex flags (options) for a Regex element */ /** Retrieve the regex flags (options) for a Regex element */
const char *regexFlags() const { const char *regexFlags() const {
const char *p = regex(); const char *p = regex();
return p + strlen(p) + 1; return p + strlen(p) + 1;
} }
/** like operator== but doesn't check the fieldname, /** like operator== but doesn't check the fieldname,
skipping to change at line 409 skipping to change at line 409
explicit BSONElement(const char *d) : data(d) { explicit BSONElement(const char *d) : data(d) {
fieldNameSize_ = -1; fieldNameSize_ = -1;
totalSize = -1; totalSize = -1;
if ( eoo() ) { if ( eoo() ) {
fieldNameSize_ = 0; fieldNameSize_ = 0;
totalSize = 1; totalSize = 1;
} }
} }
string _asCode() const; std::string _asCode() const;
OpTime _opTime() const; OpTime _opTime() const;
private: private:
const char *data; const char *data;
mutable int fieldNameSize_; // cached value mutable int fieldNameSize_; // cached value
int fieldNameSize() const { int fieldNameSize() const {
if ( fieldNameSize_ == -1 ) if ( fieldNameSize_ == -1 )
fieldNameSize_ = (int)strlen( fieldName() ) + 1; fieldNameSize_ = (int)strlen( fieldName() ) + 1;
return fieldNameSize_; return fieldNameSize_;
} }
skipping to change at line 481 skipping to change at line 481
return 45; return 45;
case RegEx: case RegEx:
return 50; return 50;
case DBRef: case DBRef:
return 55; return 55;
case Code: case Code:
return 60; return 60;
case CodeWScope: case CodeWScope:
return 65; return 65;
default: default:
assert(0); verify(0);
return -1; return -1;
} }
} }
inline bool BSONElement::trueValue() const { inline bool BSONElement::trueValue() const {
switch( type() ) { switch( type() ) {
case NumberLong: case NumberLong:
return *reinterpret_cast< const long long* >( value() ) != 0; return *reinterpret_cast< const long long* >( value() ) != 0;
case NumberDouble: case NumberDouble:
return *reinterpret_cast< const double* >( value() ) != 0; return (reinterpret_cast < const PackedDouble* >(value ()))->d != 0;
case NumberInt: case NumberInt:
return *reinterpret_cast< const int* >( value() ) != 0; return *reinterpret_cast< const int* >( value() ) != 0;
case mongo::Bool: case mongo::Bool:
return boolean(); return boolean();
case EOO: case EOO:
case jstNULL: case jstNULL:
case Undefined: case Undefined:
return false; return false;
default: default:
 End of changes. 15 change blocks. 
23 lines changed or deleted 23 lines changed or added


 bsonmisc.h   bsonmisc.h 
skipping to change at line 41 skipping to change at line 41
public: public:
BSONObjCmp( const BSONObj &order = BSONObj() ) : _order( order ) {} BSONObjCmp( const BSONObj &order = BSONObj() ) : _order( order ) {}
bool operator()( const BSONObj &l, const BSONObj &r ) const { bool operator()( const BSONObj &l, const BSONObj &r ) const {
return l.woCompare( r, _order ) < 0; return l.woCompare( r, _order ) < 0;
} }
BSONObj order() const { return _order; } BSONObj order() const { return _order; }
private: private:
BSONObj _order; BSONObj _order;
}; };
typedef set<BSONObj,BSONObjCmp> BSONObjSet; typedef std::set<BSONObj,BSONObjCmp> BSONObjSet;
enum FieldCompareResult { enum FieldCompareResult {
LEFT_SUBFIELD = -2, LEFT_SUBFIELD = -2,
LEFT_BEFORE = -1, LEFT_BEFORE = -1,
SAME = 0, SAME = 0,
RIGHT_BEFORE = 1 , RIGHT_BEFORE = 1 ,
RIGHT_SUBFIELD = 2 RIGHT_SUBFIELD = 2
}; };
FieldCompareResult compareDottedFieldNames( const string& l , const str class LexNumCmp;
ing& r ); FieldCompareResult compareDottedFieldNames( const std::string& l , cons
t std::string& r ,
const LexNumCmp& cmp );
/** Use BSON macro to build a BSONObj from a stream /** Use BSON macro to build a BSONObj from a stream
e.g., e.g.,
BSON( "name" << "joe" << "age" << 33 ) BSON( "name" << "joe" << "age" << 33 )
with auto-generated object id: with auto-generated object id:
BSON( GENOID << "name" << "joe" << "age" << 33 ) BSON( GENOID << "name" << "joe" << "age" << 33 )
The labels GT, GTE, LT, LTE, NE can be helpful for stream-oriented construction The labels GT, GTE, LT, LTE, NE can be helpful for stream-oriented construction
skipping to change at line 77 skipping to change at line 79
/** Use BSON_ARRAY macro like BSON macro, but without keys /** Use BSON_ARRAY macro like BSON macro, but without keys
BSONArray arr = BSON_ARRAY( "hello" << 1 << BSON( "foo" << BSON_ARR AY( "bar" << "baz" << "qux" ) ) ); BSONArray arr = BSON_ARRAY( "hello" << 1 << BSON( "foo" << BSON_ARR AY( "bar" << "baz" << "qux" ) ) );
*/ */
#define BSON_ARRAY(x) (( mongo::BSONArrayBuilder() << x ).arr()) #define BSON_ARRAY(x) (( mongo::BSONArrayBuilder() << x ).arr())
/* Utility class to auto assign object IDs. /* Utility class to auto assign object IDs.
Example: Example:
cout << BSON( GENOID << "z" << 3 ); // { _id : ..., z : 3 } std::cout << BSON( GENOID << "z" << 3 ); // { _id : ..., z : 3 }
*/ */
extern struct GENOIDLabeler { } GENOID; extern struct GENOIDLabeler { } GENOID;
/* Utility class to add a Date element with the current time /* Utility class to add a Date element with the current time
Example: Example:
cout << BSON( "created" << DATENOW ); // { created : "2009-10-09 1 1:41:42" } std::cout << BSON( "created" << DATENOW ); // { created : "2009-10 -09 11:41:42" }
*/ */
extern struct DateNowLabeler { } DATENOW; extern struct DateNowLabeler { } DATENOW;
/* Utility class to assign a NULL value to a given attribute /* Utility class to assign a NULL value to a given attribute
Example: Example:
cout << BSON( "a" << BSONNULL ); // { a : null } std::cout << BSON( "a" << BSONNULL ); // { a : null }
*/ */
extern struct NullLabeler { } BSONNULL; extern struct NullLabeler { } BSONNULL;
/* Utility class to add the minKey (minus infinity) to a given attribut e /* Utility class to add the minKey (minus infinity) to a given attribut e
Example: Example:
cout << BSON( "a" << MINKEY ); // { "a" : { "$minKey" : 1 } } std::cout << BSON( "a" << MINKEY ); // { "a" : { "$minKey" : 1 } }
*/ */
extern struct MinKeyLabeler { } MINKEY; extern struct MinKeyLabeler { } MINKEY;
extern struct MaxKeyLabeler { } MAXKEY; extern struct MaxKeyLabeler { } MAXKEY;
// Utility class to implement GT, GTE, etc as described above. // Utility class to implement GT, GTE, etc as described above.
class Labeler { class Labeler {
public: public:
struct Label { struct Label {
Label( const char *l ) : l_( l ) {} Label( const char *l ) : l_( l ) {}
const char *l_; const char *l_;
skipping to change at line 127 skipping to change at line 129
private: private:
const Label &l_; const Label &l_;
BSONObjBuilderValueStream *s_; BSONObjBuilderValueStream *s_;
}; };
extern Labeler::Label GT; extern Labeler::Label GT;
extern Labeler::Label GTE; extern Labeler::Label GTE;
extern Labeler::Label LT; extern Labeler::Label LT;
extern Labeler::Label LTE; extern Labeler::Label LTE;
extern Labeler::Label NE; extern Labeler::Label NE;
extern Labeler::Label SIZE; extern Labeler::Label NIN;
extern Labeler::Label BSIZE;
// $or helper: OR(BSON("x" << GT << 7), BSON("y" << LT << 6)); // $or helper: OR(BSON("x" << GT << 7), BSON("y" << LT << 6));
// becomes : {$or: [{x: {$gt: 7}}, {y: {$lt: 6}}]} // becomes : {$or: [{x: {$gt: 7}}, {y: {$lt: 6}}]}
inline BSONObj OR(const BSONObj& a, const BSONObj& b); inline BSONObj OR(const BSONObj& a, const BSONObj& b);
inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c) ; inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c) ;
inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d); inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d);
inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e); inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e);
inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e, const BSONObj& f); inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e, const BSONObj& f);
// definitions in bsonobjbuilder.h b/c of incomplete types // definitions in bsonobjbuilder.h b/c of incomplete types
skipping to change at line 167 skipping to change at line 170
void endField( const char *nextFieldName = 0 ); void endField( const char *nextFieldName = 0 );
bool subobjStarted() const { return _fieldName != 0; } bool subobjStarted() const { return _fieldName != 0; }
private: private:
const char * _fieldName; const char * _fieldName;
BSONObjBuilder * _builder; BSONObjBuilder * _builder;
bool haveSubobj() const { return _subobj.get() != 0; } bool haveSubobj() const { return _subobj.get() != 0; }
BSONObjBuilder *subobj(); BSONObjBuilder *subobj();
auto_ptr< BSONObjBuilder > _subobj; std::auto_ptr< BSONObjBuilder > _subobj;
}; };
/** /**
used in conjuction with BSONObjBuilder, allows for proper buffer siz e to prevent crazy memory usage used in conjuction with BSONObjBuilder, allows for proper buffer siz e to prevent crazy memory usage
*/ */
class BSONSizeTracker { class BSONSizeTracker {
public: public:
BSONSizeTracker() { BSONSizeTracker() {
_pos = 0; _pos = 0;
for ( int i=0; i<SIZE; i++ ) for ( int i=0; i<SIZE; i++ )
 End of changes. 8 change blocks. 
9 lines changed or deleted 12 lines changed or added


 bsonobj.h   bsonobj.h 
skipping to change at line 31 skipping to change at line 31
#include <boost/intrusive_ptr.hpp> #include <boost/intrusive_ptr.hpp>
#include <set> #include <set>
#include <list> #include <list>
#include <vector> #include <vector>
#include "util/atomic_int.h" #include "util/atomic_int.h"
#include "util/builder.h" #include "util/builder.h"
#include "stringdata.h" #include "stringdata.h"
namespace mongo { namespace mongo {
typedef set< BSONElement, BSONElementCmpWithoutField > BSONElementSet; typedef std::set< BSONElement, BSONElementCmpWithoutField > BSONElement
typedef multiset< BSONElement, BSONElementCmpWithoutField > BSONElement Set;
MSet; typedef std::multiset< BSONElement, BSONElementCmpWithoutField > BSONEl
ementMSet;
/** /**
C++ representation of a "BSON" object -- that is, an extended JSON-s tyle C++ representation of a "BSON" object -- that is, an extended JSON-s tyle
object in a binary representation. object in a binary representation.
See bsonspec.org. See bsonspec.org.
Note that BSONObj's have a smart pointer capability built in -- so y ou can Note that BSONObj's have a smart pointer capability built in -- so y ou can
pass them around by value. The reference counts used to implement t his pass them around by value. The reference counts used to implement t his
do not use locking, so copying and destroying BSONObj's are not thre ad-safe do not use locking, so copying and destroying BSONObj's are not thre ad-safe
skipping to change at line 141 skipping to change at line 141
@see isOwned() @see isOwned()
*/ */
BSONObj getOwned() const; BSONObj getOwned() const;
/** @return a new full (and owned) copy of the object. */ /** @return a new full (and owned) copy of the object. */
BSONObj copy() const; BSONObj copy() const;
/** Readable representation of a BSON object in an extended JSON-st yle notation. /** Readable representation of a BSON object in an extended JSON-st yle notation.
This is an abbreviated representation which might be used for l ogging. This is an abbreviated representation which might be used for l ogging.
*/ */
string toString( bool isArray = false, bool full=false ) const; enum { maxToStringRecursionDepth = 100 };
void toString(StringBuilder& s, bool isArray = false, bool full=fal
se ) const; std::string toString( bool isArray = false, bool full=false ) const
;
void toString( StringBuilder& s, bool isArray = false, bool full=fa
lse, int depth=0 ) const;
/** Properly formatted JSON string. /** Properly formatted JSON string.
@param pretty if true we try to add some lf's and indentation @param pretty if true we try to add some lf's and indentation
*/ */
string jsonString( JsonStringFormat format = Strict, int pretty = 0 ) const; std::string jsonString( JsonStringFormat format = Strict, int prett y = 0 ) const;
/** note: addFields always adds _id even if not specified */ /** note: addFields always adds _id even if not specified */
int addFields(BSONObj& from, set<string>& fields); /* returns n add ed */ int addFields(BSONObj& from, std::set<std::string>& fields); /* ret urns n added */
/** remove specified field and return a new object with the remaini ng fields. /** remove specified field and return a new object with the remaini ng fields.
slowish as builds a full new object slowish as builds a full new object
*/ */
BSONObj removeField(const StringData& name) const; BSONObj removeField(const StringData& name) const;
/** returns # of top level fields in the object /** returns # of top level fields in the object
note: iterates to count the fields note: iterates to count the fields
*/ */
int nFields() const; int nFields() const;
/** adds the field names to the fields set. does NOT clear it (app ends). */ /** adds the field names to the fields set. does NOT clear it (app ends). */
int getFieldNames(set<string>& fields) const; int getFieldNames(std::set<std::string>& fields) const;
/** @return the specified element. element.eoo() will be true if n ot found. /** @return the specified element. element.eoo() will be true if n ot found.
@param name field to find. supports dot (".") notation to reach into embedded objects. @param name field to find. supports dot (".") notation to reach into embedded objects.
for example "x.y" means "in the nested object in field x, retr ieve field y" for example "x.y" means "in the nested object in field x, retr ieve field y"
*/ */
BSONElement getFieldDotted(const char *name) const; BSONElement getFieldDotted(const char *name) const;
/** @return the specified element. element.eoo() will be true if n ot found. /** @return the specified element. element.eoo() will be true if n ot found.
@param name field to find. supports dot (".") notation to reach into embedded objects. @param name field to find. supports dot (".") notation to reach into embedded objects.
for example "x.y" means "in the nested object in field x, retr ieve field y" for example "x.y" means "in the nested object in field x, retr ieve field y"
*/ */
BSONElement getFieldDotted(const string& name) const { BSONElement getFieldDotted(const std::string& name) const {
return getFieldDotted( name.c_str() ); return getFieldDotted( name.c_str() );
} }
/** Like getFieldDotted(), but expands arrays and returns all match ing objects. /** Like getFieldDotted(), but expands arrays and returns all match ing objects.
* Turning off expandLastArray allows you to retrieve nested array objects instead of * Turning off expandLastArray allows you to retrieve nested array objects instead of
* their contents. * their contents.
*/ */
void getFieldsDotted(const StringData& name, BSONElementSet &ret, b ool expandLastArray = true ) const; void getFieldsDotted(const StringData& name, BSONElementSet &ret, b ool expandLastArray = true ) const;
void getFieldsDotted(const StringData& name, BSONElementMSet &ret, bool expandLastArray = true ) const; void getFieldsDotted(const StringData& name, BSONElementMSet &ret, bool expandLastArray = true ) const;
skipping to change at line 210 skipping to change at line 212
*/ */
void getFields(unsigned n, const char **fieldNames, BSONElement *fi elds) const; void getFields(unsigned n, const char **fieldNames, BSONElement *fi elds) const;
/** Get the field of the specified name. eoo() is true on the retur ned /** Get the field of the specified name. eoo() is true on the retur ned
element if not found. element if not found.
*/ */
BSONElement operator[] (const char *field) const { BSONElement operator[] (const char *field) const {
return getField(field); return getField(field);
} }
BSONElement operator[] (const string& field) const { BSONElement operator[] (const std::string& field) const {
return getField(field); return getField(field);
} }
BSONElement operator[] (int field) const { BSONElement operator[] (int field) const {
StringBuilder ss; StringBuilder ss;
ss << field; ss << field;
string s = ss.str(); std::string s = ss.str();
return getField(s.c_str()); return getField(s.c_str());
} }
/** @return true if field exists */ /** @return true if field exists */
bool hasField( const char * name ) const { return !getField(name).e oo(); } bool hasField( const char * name ) const { return !getField(name).e oo(); }
/** @return true if field exists */ /** @return true if field exists */
bool hasElement(const char *name) const { return hasField(name); } bool hasElement(const char *name) const { return hasField(name); }
/** @return "" if DNE or wrong type */ /** @return "" if DNE or wrong type */
const char * getStringField(const char *name) const; const char * getStringField(const char *name) const;
skipping to change at line 284 skipping to change at line 286
criter: isValid() no . or $ field names criter: isValid() no . or $ field names
*/ */
bool okForStorage() const; bool okForStorage() const;
/** @return true if object is empty -- i.e., {} */ /** @return true if object is empty -- i.e., {} */
bool isEmpty() const { return objsize() <= 5; } bool isEmpty() const { return objsize() <= 5; }
void dump() const; void dump() const;
/** Alternative output format */ /** Alternative output format */
string hexDump() const; std::string hexDump() const;
/**wo='well ordered'. fields must be in same order in each object. /**wo='well ordered'. fields must be in same order in each object.
Ordering is with respect to the signs of the elements Ordering is with respect to the signs of the elements
and allows ascending / descending key mixing. and allows ascending / descending key mixing.
@return <0 if l<r. 0 if l==r. >0 if l>r @return <0 if l<r. 0 if l==r. >0 if l>r
*/ */
int woCompare(const BSONObj& r, const Ordering &o, int woCompare(const BSONObj& r, const Ordering &o,
bool considerFieldName=true) const; bool considerFieldName=true) const;
/**wo='well ordered'. fields must be in same order in each object. /**wo='well ordered'. fields must be in same order in each object.
skipping to change at line 371 skipping to change at line 373
BSONObj clientReadable() const; BSONObj clientReadable() const;
/** 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; std::string md5() const;
bool operator==( const BSONObj& other ) const { return equal( other ); } bool operator==( const BSONObj& other ) const { return equal( other ); }
bool operator!=(const BSONObj& other) const { return !operator==( o ther); } bool operator!=(const BSONObj& other) const { return !operator==( o ther); }
enum MatchType { enum MatchType {
Equality = 0, Equality = 0,
LT = 0x1, LT = 0x1,
LTE = 0x3, LTE = 0x3,
GTE = 0x6, GTE = 0x6,
GT = 0x4, GT = 0x4,
skipping to change at line 399 skipping to change at line 401
opTYPE = 0x0F, opTYPE = 0x0F,
opREGEX = 0x10, opREGEX = 0x10,
opOPTIONS = 0x11, opOPTIONS = 0x11,
opELEM_MATCH = 0x12, opELEM_MATCH = 0x12,
opNEAR = 0x13, opNEAR = 0x13,
opWITHIN = 0x14, opWITHIN = 0x14,
opMAX_DISTANCE=0x15 opMAX_DISTANCE=0x15
}; };
/** add all elements of the object to the specified vector */ /** add all elements of the object to the specified vector */
void elems(vector<BSONElement> &) const; void elems(std::vector<BSONElement> &) const;
/** add all elements of the object to the specified list */ /** add all elements of the object to the specified list */
void elems(list<BSONElement> &) const; void elems(std::list<BSONElement> &) const;
/** add all values of the object to the specified vector. If type mismatches, exception. /** add all values of the object to the specified vector. If type mismatches, exception.
this is most useful when the BSONObj is an array, but can be us ed with non-arrays too in theory. this is most useful when the BSONObj is an array, but can be us ed with non-arrays too in theory.
example: example:
bo sub = y["subobj"].Obj(); bo sub = y["subobj"].Obj();
vector<int> myints; std::vector<int> myints;
sub.Vals(myints); sub.Vals(myints);
*/ */
template <class T> template <class T>
void Vals(vector<T> &) const; void Vals(std::vector<T> &) const;
/** add all values of the object to the specified list. If type mi smatches, exception. */ /** add all values of the object to the specified list. If type mi smatches, exception. */
template <class T> template <class T>
void Vals(list<T> &) const; void Vals(std::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(std::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(std::list<T> &) const;
friend class BSONObjIterator; friend class BSONObjIterator;
typedef BSONObjIterator iterator; typedef BSONObjIterator iterator;
/** use something like this: /** use something like this:
for( BSONObj::iterator i = myObj.begin(); i.more(); ) { for( BSONObj::iterator i = myObj.begin(); i.more(); ) {
BSONElement e = i.next(); BSONElement e = i.next();
... ...
} }
*/ */
BSONObjIterator begin() const; BSONObjIterator begin() const;
void appendSelfToBufBuilder(BufBuilder& b) const { void appendSelfToBufBuilder(BufBuilder& b) const {
assert( objsize() ); verify( objsize() );
b.appendBuf(reinterpret_cast<const void *>( objdata() ), objsiz e()); b.appendBuf(reinterpret_cast<const void *>( objdata() ), objsiz e());
} }
#pragma pack(1) #pragma pack(1)
class Holder : boost::noncopyable { class Holder : boost::noncopyable {
private: private:
Holder(); // this class should never be explicitly created Holder(); // this class should never be explicitly created
AtomicUInt refCount; AtomicUInt refCount;
public: public:
char data[4]; // start of object char data[4]; // start of object
void zero() { refCount.zero(); } void zero() { refCount.zero(); }
// these are called automatically by boost::intrusive_ptr // these are called automatically by boost::intrusive_ptr
friend void intrusive_ptr_add_ref(Holder* h) { h->refCount++; } friend void intrusive_ptr_add_ref(Holder* h) { h->refCount++; }
friend void intrusive_ptr_release(Holder* h) { friend void intrusive_ptr_release(Holder* h) {
#if defined(_DEBUG) // cant use dassert or DEV here #if defined(_DEBUG) // cant use dassert or DEV here
assert((int)h->refCount > 0); // make sure we haven't alrea dy freed the buffer verify((int)h->refCount > 0); // make sure we haven't alrea dy freed the buffer
#endif #endif
if(--(h->refCount) == 0){ if(--(h->refCount) == 0){
#if defined(_DEBUG) #if defined(_DEBUG)
unsigned sz = (unsigned&) *h->data; unsigned sz = (unsigned&) *h->data;
assert(sz < BSONObjMaxInternalSize * 3); verify(sz < BSONObjMaxInternalSize * 3);
memset(h->data, 0xdd, sz); memset(h->data, 0xdd, sz);
#endif #endif
free(h); free(h);
} }
} }
}; };
#pragma pack() #pragma pack()
BSONObj(const BSONObj &rO):
_objdata(rO._objdata), _holder(rO._holder) {
}
BSONObj &operator=(const BSONObj &rRHS) {
if (this != &rRHS) {
_objdata = rRHS._objdata;
_holder = rRHS._holder;
}
return *this;
}
private: private:
const char *_objdata; const char *_objdata;
boost::intrusive_ptr< Holder > _holder; boost::intrusive_ptr< Holder > _holder;
void _assertInvalid() const; void _assertInvalid() const;
void init(Holder *holder) { void init(Holder *holder) {
_holder = holder; // holder is now managed by intrusive_ptr _holder = holder; // holder is now managed by intrusive_ptr
init(holder->data); init(holder->data);
} }
void init(const char *data) { void init(const char *data) {
_objdata = data; _objdata = data;
if ( !isValid() ) if ( !isValid() )
_assertInvalid(); _assertInvalid();
} }
}; };
ostream& operator<<( ostream &s, const BSONObj &o ); std::ostream& operator<<( std::ostream &s, const BSONObj &o );
ostream& operator<<( ostream &s, const BSONElement &e ); std::ostream& operator<<( std::ostream &s, const BSONElement &e );
StringBuilder& operator<<( StringBuilder &s, const BSONObj &o ); StringBuilder& operator<<( StringBuilder &s, const BSONObj &o );
StringBuilder& operator<<( StringBuilder &s, const BSONElement &e ); StringBuilder& operator<<( StringBuilder &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. 22 change blocks. 
26 lines changed or deleted 42 lines changed or added


 bsonobjbuilder.h   bsonobjbuilder.h 
skipping to change at line 29 skipping to change at line 29
* 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> #include <cmath>
#include <boost/static_assert.hpp> #include <boost/static_assert.hpp>
#if defined(MONGO_EXPOSE_MACROS) #if defined(MONGO_EXPOSE_MACROS)
// boost changed it #define verify MONGO_verify
#undef assert
#define assert MONGO_assert
#endif #endif
#include "bsonelement.h" #include "bsonelement.h"
#include "bsonobj.h" #include "bsonobj.h"
#include "bsonmisc.h" #include "bsonmisc.h"
#if defined(_DEBUG) && defined(MONGO_EXPOSE_MACROS) #if defined(_DEBUG) && defined(MONGO_EXPOSE_MACROS)
#include "../util/log.h" #include "../util/log.h"
#endif #endif
namespace mongo { namespace mongo {
using namespace std;
#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
template<typename T> template<typename T>
class BSONFieldValue { class BSONFieldValue {
public: public:
BSONFieldValue( const string& name , const T& t ) { BSONFieldValue( const std::string& name , const T& t ) {
_name = name; _name = name;
_t = t; _t = t;
} }
const T& value() const { return _t; } const T& value() const { return _t; }
const string& name() const { return _name; } const std::string& name() const { return _name; }
private: private:
string _name; std::string _name;
T _t; T _t;
}; };
template<typename T> template<typename T>
class BSONField { class BSONField {
public: public:
BSONField( const string& name , const string& longName="" ) BSONField( const std::string& name , const std::string& longName="" )
: _name(name), _longName(longName) {} : _name(name), _longName(longName) {}
const string& name() const { return _name; } const std::string& name() const { return _name; }
operator string() const { return _name; } operator std::string() const { return _name; }
BSONFieldValue<T> make( const T& t ) const { BSONFieldValue<T> make( const T& t ) const {
return BSONFieldValue<T>( _name , t ); return BSONFieldValue<T>( _name , t );
} }
BSONFieldValue<BSONObj> gt( const T& t ) const { return query( "$gt " , t ); } BSONFieldValue<BSONObj> gt( const T& t ) const { return query( "$gt " , t ); }
BSONFieldValue<BSONObj> lt( const T& t ) const { return query( "$lt " , t ); } BSONFieldValue<BSONObj> lt( const T& t ) const { return query( "$lt " , t ); }
BSONFieldValue<BSONObj> query( const char * q , const T& t ) const; BSONFieldValue<BSONObj> query( const char * q , const T& t ) const;
BSONFieldValue<T> operator()( const T& t ) const { BSONFieldValue<T> operator()( const T& t ) const {
return BSONFieldValue<T>( _name , t ); return BSONFieldValue<T>( _name , t );
} }
private: private:
string _name; std::string _name;
string _longName; std::string _longName;
}; };
/** Utility for creating a BSONObj. /** Utility for creating a BSONObj.
See also the BSON() and BSON_ARRAY() macros. See also the BSON() and BSON_ARRAY() macros.
*/ */
class BSONObjBuilder : boost::noncopyable { class BSONObjBuilder : boost::noncopyable {
public: public:
/** @param initsize this is just a hint as to the final size of the object */ /** @param initsize this is just a hint as to the final size of the object */
BSONObjBuilder(int initsize=512) : _b(_buf), _buf(initsize + sizeof (unsigned)), _offset( sizeof(unsigned) ), _s( this ) , _tracker(0) , _doneC alled(false) { BSONObjBuilder(int initsize=512) : _b(_buf), _buf(initsize + sizeof (unsigned)), _offset( sizeof(unsigned) ), _s( this ) , _tracker(0) , _doneC alled(false) {
_b.appendNum((unsigned)0); // ref-count _b.appendNum((unsigned)0); // ref-count
skipping to change at line 128 skipping to change at line 124
} }
/** add all the fields from the object specified to this object */ /** add all the fields from the object specified to this object */
BSONObjBuilder& appendElements(BSONObj x); BSONObjBuilder& appendElements(BSONObj x);
/** add all the fields from the object specified to this object if they don't exist already */ /** add all the fields from the object specified to this object if they don't exist already */
BSONObjBuilder& appendElementsUnique( BSONObj x ); BSONObjBuilder& appendElementsUnique( BSONObj x );
/** append element to the object we are building */ /** append element to the object we are building */
BSONObjBuilder& append( const BSONElement& e) { BSONObjBuilder& append( const BSONElement& e) {
assert( !e.eoo() ); // do not append eoo, that would corrupt us . the builder auto appends when done() is called. verify( !e.eoo() ); // do not append eoo, that would corrupt us . the builder auto appends when done() is called.
_b.appendBuf((void*) e.rawdata(), e.size()); _b.appendBuf((void*) e.rawdata(), e.size());
return *this; return *this;
} }
/** append an element but with a new name */ /** append an element but with a new name */
BSONObjBuilder& appendAs(const BSONElement& e, const StringData& fi eldName) { BSONObjBuilder& appendAs(const BSONElement& e, const StringData& fi eldName) {
assert( !e.eoo() ); // do not append eoo, that would corrupt us . the builder auto appends when done() is called. verify( !e.eoo() ); // do not append eoo, that would corrupt us . the builder auto appends when done() is called.
_b.appendNum((char) e.type()); _b.appendNum((char) e.type());
_b.appendStr(fieldName); _b.appendStr(fieldName);
_b.appendBuf((void *) e.value(), e.valuesize()); _b.appendBuf((void *) e.value(), e.valuesize());
return *this; return *this;
} }
/** add a subobject as a member */ /** add a subobject as a member */
BSONObjBuilder& append(const StringData& fieldName, BSONObj subObj) { BSONObjBuilder& append(const StringData& fieldName, BSONObj subObj) {
_b.appendNum((char) Object); _b.appendNum((char) Object);
_b.appendStr(fieldName); _b.appendStr(fieldName);
_b.appendBuf((void *) subObj.objdata(), subObj.objsize()); _b.appendBuf((void *) subObj.objdata(), subObj.objsize());
return *this; return *this;
} }
/** add a subobject as a member */ /** add a subobject as a member */
BSONObjBuilder& appendObject(const StringData& fieldName, const cha r * objdata , int size = 0 ) { BSONObjBuilder& appendObject(const StringData& fieldName, const cha r * objdata , int size = 0 ) {
assert( objdata ); verify( objdata );
if ( size == 0 ) { if ( size == 0 ) {
size = *((int*)objdata); size = *((int*)objdata);
} }
assert( size > 4 && size < 100000000 ); verify( size > 4 && size < 100000000 );
_b.appendNum((char) Object); _b.appendNum((char) Object);
_b.appendStr(fieldName); _b.appendStr(fieldName);
_b.appendBuf((void*)objdata, size ); _b.appendBuf((void*)objdata, size );
return *this; return *this;
} }
/** add header for a new subobject and return bufbuilder for writin g to /** add header for a new subobject and return bufbuilder for writin g to
* the subobject's body * the subobject's body
* *
skipping to change at line 245 skipping to change at line 241
_b.appendStr(fieldName); _b.appendStr(fieldName);
_b.appendNum(n); _b.appendNum(n);
return *this; return *this;
} }
/** appends a number. if n < max(int)/2 then uses int, otherwise l ong long */ /** appends a number. if n < max(int)/2 then uses int, otherwise l ong long */
BSONObjBuilder& appendIntOrLL( const StringData& fieldName , long l ong n ) { BSONObjBuilder& appendIntOrLL( const StringData& fieldName , long l ong n ) {
long long x = n; long long x = n;
if ( x < 0 ) if ( x < 0 )
x = x * -1; x = x * -1;
if ( x < ( (numeric_limits<int>::max)() / 2 ) ) // extra () to avoid max macro on windows if ( x < ( (std::numeric_limits<int>::max)() / 2 ) ) // extra ( ) to avoid max macro on windows
append( fieldName , (int)n ); append( fieldName , (int)n );
else else
append( fieldName , n ); append( fieldName , n );
return *this; return *this;
} }
/** /**
* appendNumber is a series of method for appending the smallest se nsible type * appendNumber is a series of method for appending the smallest se nsible type
* mostly for JS * mostly for JS
*/ */
skipping to change at line 298 skipping to change at line 294
BSONObjBuilder& append(const StringData& fieldName, double n) { BSONObjBuilder& append(const StringData& fieldName, double n) {
_b.appendNum((char) NumberDouble); _b.appendNum((char) NumberDouble);
_b.appendStr(fieldName); _b.appendStr(fieldName);
_b.appendNum(n); _b.appendNum(n);
return *this; return *this;
} }
/** tries to append the data as a number /** tries to append the data as a number
* @return true if the data was able to be converted to a number * @return true if the data was able to be converted to a number
*/ */
bool appendAsNumber( const StringData& fieldName , const string& da ta ); bool appendAsNumber( const StringData& fieldName , const std::strin g& data );
/** Append a BSON Object ID (OID type). /** Append a BSON Object ID (OID type).
@deprecated Generally, it is preferred to use the append append (name, oid) @deprecated Generally, it is preferred to use the append append (name, oid)
method for this. method for this.
*/ */
BSONObjBuilder& appendOID(const StringData& fieldName, OID *oid = 0 , bool generateIfBlank = false ) { BSONObjBuilder& appendOID(const StringData& fieldName, OID *oid = 0 , bool generateIfBlank = false ) {
_b.appendNum((char) jstOID); _b.appendNum((char) jstOID);
_b.appendStr(fieldName); _b.appendStr(fieldName);
if ( oid ) if ( oid )
_b.appendBuf( (void *) oid, 12 ); _b.appendBuf( (void *) oid, 12 );
skipping to change at line 360 skipping to change at line 356
/** Append a date. /** Append a date.
@param dt a Java-style 64 bit date value, that is @param dt a Java-style 64 bit date value, that is
the number of milliseconds since January 1, 1970, 00:00:00 GMT the number of milliseconds since January 1, 1970, 00:00:00 GMT
*/ */
BSONObjBuilder& appendDate(const StringData& fieldName, Date_t dt) { BSONObjBuilder& appendDate(const StringData& fieldName, Date_t dt) {
/* easy to pass a time_t to this and get a bad result. thus th is warning. */ /* easy to pass a time_t to this and get a bad result. thus th is warning. */
#if defined(_DEBUG) && defined(MONGO_EXPOSE_MACROS) #if defined(_DEBUG) && defined(MONGO_EXPOSE_MACROS)
if( dt > 0 && dt <= 0xffffffff ) { if( dt > 0 && dt <= 0xffffffff ) {
static int n; static int n;
if( n++ == 0 ) if( n++ == 0 )
log() << "DEV WARNING appendDate() called with a tiny ( but nonzero) date" << endl; log() << "DEV WARNING appendDate() called with a tiny ( but nonzero) date" << std::endl;
} }
#endif #endif
_b.appendNum((char) Date); _b.appendNum((char) Date);
_b.appendStr(fieldName); _b.appendStr(fieldName);
_b.appendNum(dt); _b.appendNum(dt);
return *this; return *this;
} }
BSONObjBuilder& append(const StringData& fieldName, Date_t dt) { BSONObjBuilder& append(const StringData& fieldName, Date_t dt) {
return appendDate(fieldName, dt); return appendDate(fieldName, dt);
} }
skipping to change at line 406 skipping to change at line 402
_b.appendStr(fieldName); _b.appendStr(fieldName);
_b.appendNum((int)sz); _b.appendNum((int)sz);
_b.appendBuf(str, sz); _b.appendBuf(str, sz);
return *this; return *this;
} }
/** Append a string element */ /** Append a string element */
BSONObjBuilder& append(const StringData& fieldName, const char *str ) { BSONObjBuilder& append(const StringData& fieldName, const char *str ) {
return append(fieldName, str, (int) strlen(str)+1); return append(fieldName, str, (int) strlen(str)+1);
} }
/** Append a string element */ /** Append a string element */
BSONObjBuilder& append(const StringData& fieldName, const string& s tr) { BSONObjBuilder& append(const StringData& fieldName, const std::stri ng& str) {
return append(fieldName, str.c_str(), (int) str.size()+1); return append(fieldName, str.c_str(), (int) str.size()+1);
} }
BSONObjBuilder& appendSymbol(const StringData& fieldName, const Str ingData& symbol) { BSONObjBuilder& appendSymbol(const StringData& fieldName, const Str ingData& symbol) {
_b.appendNum((char) Symbol); _b.appendNum((char) Symbol);
_b.appendStr(fieldName); _b.appendStr(fieldName);
_b.appendNum((int) symbol.size()+1); _b.appendNum((int) symbol.size()+1);
_b.appendStr(symbol); _b.appendStr(symbol);
return *this; return *this;
} }
skipping to change at line 536 skipping to change at line 532
} }
/** /**
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 StringData& fieldName , int type ); void appendMinForType( const StringData& fieldName , int type );
void appendMaxForType( const StringData& fieldName , int type ); void appendMaxForType( const StringData& fieldName , int type );
/** Append an array of values. */ /** Append an array of values. */
template < class T > template < class T >
BSONObjBuilder& append( const StringData& fieldName, const vector< T >& vals ); BSONObjBuilder& append( const StringData& fieldName, const std::vec tor< T >& vals );
template < class T > template < class T >
BSONObjBuilder& append( const StringData& fieldName, const list< T >& vals ); BSONObjBuilder& append( const StringData& fieldName, const std::lis t< T >& vals );
/** Append a set of values. */ /** Append a set of values. */
template < class T > template < class T >
BSONObjBuilder& append( const StringData& fieldName, const set< T > & vals ); BSONObjBuilder& append( const StringData& fieldName, const std::set < T >& vals );
/** /**
* destructive * destructive
* The returned BSONObj will free the buffer when it is finished. * The returned BSONObj will free the buffer when it is finished.
* @return owned BSONObj * @return owned BSONObj
*/ */
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 );
doneFast(); doneFast();
skipping to change at line 587 skipping to change at line 583
BSONObj asTempObj() { BSONObj asTempObj() {
BSONObj temp(_done()); BSONObj temp(_done());
_b.setlen(_b.len()-1); //next append should overwrite the EOO _b.setlen(_b.len()-1); //next append should overwrite the EOO
_doneCalled = false; _doneCalled = false;
return temp; return temp;
} }
/* assume ownership of the buffer - you must then free it (with fre e()) */ /* assume ownership of the buffer - you must then free it (with fre e()) */
char* decouple(int& l) { char* decouple(int& l) {
char *x = _done(); char *x = _done();
assert( x ); verify( x );
l = _b.len(); l = _b.len();
_b.decouple(); _b.decouple();
return x; return x;
} }
void decouple() { void decouple() {
_b.decouple(); // post done() call version. be sure jsobj f rees... _b.decouple(); // post done() call version. be sure jsobj f rees...
} }
void appendKeys( const BSONObj& keyPattern , const BSONObj& values ); void appendKeys( const BSONObj& keyPattern , const BSONObj& values );
static string numStr( int i ) { static std::string numStr( int i ) {
if (i>=0 && i<100 && numStrsReady) if (i>=0 && i<100 && numStrsReady)
return numStrs[i]; return numStrs[i];
StringBuilder o; StringBuilder o;
o << i; o << i;
return o.str(); return o.str();
} }
/** Stream oriented way to add field names and values. */ /** Stream oriented way to add field names and values. */
BSONObjBuilderValueStream &operator<<(const char * name ) { BSONObjBuilderValueStream &operator<<(const char * name ) {
_s.endField( name ); _s.endField( name );
return _s; return _s;
} }
/** Stream oriented way to add field names and values. */ /** Stream oriented way to add field names and values. */
BSONObjBuilder& operator<<( GENOIDLabeler ) { return genOID(); } BSONObjBuilder& operator<<( GENOIDLabeler ) { return genOID(); }
// prevent implicit string conversions which would allow bad things like BSON( BSON( "foo" << 1 ) << 2 ) // prevent implicit string conversions which would allow bad things like BSON( BSON( "foo" << 1 ) << 2 )
struct ForceExplicitString { struct ForceExplicitString {
ForceExplicitString( const string &str ) : str_( str ) {} ForceExplicitString( const std::string &str ) : str_( str ) {}
string str_; std::string str_;
}; };
/** Stream oriented way to add field names and values. */ /** Stream oriented way to add field names and values. */
BSONObjBuilderValueStream &operator<<( const ForceExplicitString& n ame ) { BSONObjBuilderValueStream &operator<<( const ForceExplicitString& n ame ) {
return operator<<( name.str_.c_str() ); return operator<<( name.str_.c_str() );
} }
Labeler operator<<( const Labeler::Label &l ) { Labeler operator<<( const Labeler::Label &l ) {
massert( 10336 , "No subobject started", _s.subobjStarted() ); massert( 10336 , "No subobject started", _s.subobjStarted() );
return _s << l; return _s << l;
skipping to change at line 682 skipping to change at line 678
return data; return data;
} }
BufBuilder &_b; BufBuilder &_b;
BufBuilder _buf; BufBuilder _buf;
int _offset; int _offset;
BSONObjBuilderValueStream _s; BSONObjBuilderValueStream _s;
BSONSizeTracker * _tracker; BSONSizeTracker * _tracker;
bool _doneCalled; bool _doneCalled;
static const string numStrs[100]; // cache of 0 to 99 inclusive static const std::string numStrs[100]; // cache of 0 to 99 inclusiv e
static bool numStrsReady; // for static init safety. see comments i n db/jsobj.cpp static bool numStrsReady; // for static init safety. see comments i n db/jsobj.cpp
}; };
class BSONArrayBuilder : boost::noncopyable { class BSONArrayBuilder : boost::noncopyable {
public: public:
BSONArrayBuilder() : _i(0), _b() {} BSONArrayBuilder() : _i(0), _b() {}
BSONArrayBuilder( BufBuilder &_b ) : _i(0), _b(_b) {} BSONArrayBuilder( BufBuilder &_b ) : _i(0), _b(_b) {}
BSONArrayBuilder( int initialSize ) : _i(0), _b(initialSize) {} BSONArrayBuilder( int initialSize ) : _i(0), _b(initialSize) {}
template <typename T> template <typename T>
skipping to change at line 729 skipping to change at line 725
void doneFast() { _b.doneFast(); } void doneFast() { _b.doneFast(); }
template <typename T> template <typename T>
BSONArrayBuilder& append(const StringData& name, const T& x) { BSONArrayBuilder& append(const StringData& name, const T& x) {
fill( name ); fill( name );
append( x ); append( x );
return *this; return *this;
} }
template < class T >
BSONArrayBuilder& append( const std::list< T >& vals );
template < class T >
BSONArrayBuilder& append( const std::set< T >& vals );
// These two just use next position // These two just use next position
BufBuilder &subobjStart() { return _b.subobjStart( num() ); } BufBuilder &subobjStart() { return _b.subobjStart( num() ); }
BufBuilder &subarrayStart() { return _b.subarrayStart( num() ); } BufBuilder &subarrayStart() { return _b.subarrayStart( num() ); }
// These fill missing entries up to pos. if pos is < next pos is ig nored // These fill missing entries up to pos. if pos is < next pos is ig nored
BufBuilder &subobjStart(int pos) { BufBuilder &subobjStart(int pos) {
fill(pos); fill(pos);
return _b.subobjStart( num() ); return _b.subobjStart( num() );
} }
BufBuilder &subarrayStart(int pos) { BufBuilder &subarrayStart(int pos) {
skipping to change at line 778 skipping to change at line 780
private: private:
// These two are undefined privates to prevent their accidental // These two are undefined privates to prevent their accidental
// use as we don't support unsigned ints in BSON // use as we don't support unsigned ints in BSON
BSONObjBuilder& append(const StringData& fieldName, unsigned int va l); BSONObjBuilder& append(const StringData& fieldName, unsigned int va l);
BSONObjBuilder& append(const StringData& fieldName, unsigned long l ong val); BSONObjBuilder& append(const StringData& fieldName, unsigned long l ong val);
void fill( const StringData& name ) { void fill( const StringData& name ) {
char *r; char *r;
long int n = strtol( name.data(), &r, 10 ); long int n = strtol( name.data(), &r, 10 );
if ( *r ) if ( *r )
uasserted( 13048, (string)"can't append to array using stri ng field name [" + name.data() + "]" ); uasserted( 13048, (std::string)"can't append to array using string field name [" + name.data() + "]" );
fill(n); fill(n);
} }
void fill (int upTo){ void fill (int upTo){
// if this is changed make sure to update error message and jst ests/set7.js // if this is changed make sure to update error message and jst ests/set7.js
const int maxElems = 1500000; const int maxElems = 1500000;
BOOST_STATIC_ASSERT(maxElems < (BSONObjMaxUserSize/10)); BOOST_STATIC_ASSERT(maxElems < (BSONObjMaxUserSize/10));
uassert(15891, "can't backfill array to larger than 1,500,000 e lements", upTo <= maxElems); uassert(15891, "can't backfill array to larger than 1,500,000 e lements", upTo <= maxElems);
while( _i < upTo ) while( _i < upTo )
skipping to change at line 803 skipping to change at line 805
static BSONObj n = nullObj(); static BSONObj n = nullObj();
return n.firstElement(); return n.firstElement();
} }
static BSONObj nullObj() { static BSONObj nullObj() {
BSONObjBuilder _b; BSONObjBuilder _b;
_b.appendNull( "" ); _b.appendNull( "" );
return _b.obj(); return _b.obj();
} }
string num() { return _b.numStr(_i++); } std::string num() { return _b.numStr(_i++); }
int _i; int _i;
BSONObjBuilder _b; BSONObjBuilder _b;
}; };
template < class T > template < class T >
inline BSONObjBuilder& BSONObjBuilder::append( const StringData& fieldN ame, const vector< T >& vals ) { inline BSONObjBuilder& BSONObjBuilder::append( const StringData& fieldN ame, const std::vector< T >& vals ) {
BSONObjBuilder arrBuilder; BSONObjBuilder arrBuilder;
for ( unsigned int i = 0; i < vals.size(); ++i ) for ( unsigned int i = 0; i < vals.size(); ++i )
arrBuilder.append( numStr( i ), vals[ i ] ); arrBuilder.append( numStr( i ), vals[ i ] );
appendArray( fieldName, arrBuilder.done() ); appendArray( fieldName, arrBuilder.done() );
return *this; return *this;
} }
template < class L > template < class L >
inline BSONObjBuilder& _appendIt( BSONObjBuilder& _this, const StringDa ta& fieldName, const L& vals ) { inline BSONObjBuilder& _appendIt( BSONObjBuilder& _this, const StringDa ta& fieldName, const L& vals ) {
BSONObjBuilder arrBuilder; BSONObjBuilder arrBuilder;
int n = 0; int n = 0;
for( typename L::const_iterator i = vals.begin(); i != vals.end(); i++ ) for( typename L::const_iterator i = vals.begin(); i != vals.end(); i++ )
arrBuilder.append( BSONObjBuilder::numStr(n++), *i ); arrBuilder.append( BSONObjBuilder::numStr(n++), *i );
_this.appendArray( fieldName, arrBuilder.done() ); _this.appendArray( fieldName, arrBuilder.done() );
return _this; return _this;
} }
template < class T > template < class T >
inline BSONObjBuilder& BSONObjBuilder::append( const StringData& fieldN inline BSONObjBuilder& BSONObjBuilder::append( const StringData& fieldN
ame, const list< T >& vals ) { ame, const std::list< T >& vals ) {
return _appendIt< list< T > >( *this, fieldName, vals ); return _appendIt< std::list< T > >( *this, fieldName, vals );
}
template < class T >
inline BSONObjBuilder& BSONObjBuilder::append( const StringData& fieldN
ame, const std::set< T >& vals ) {
return _appendIt< std::set< T > >( *this, fieldName, vals );
}
template < class L >
inline BSONArrayBuilder& _appendArrayIt( BSONArrayBuilder& _this, const
L& vals ) {
for( typename L::const_iterator i = vals.begin(); i != vals.end();
i++ )
_this.append( *i );
return _this;
}
template < class T >
inline BSONArrayBuilder& BSONArrayBuilder::append( const std::list< T >
& vals ) {
return _appendArrayIt< std::list< T > >( *this, vals );
} }
template < class T > template < class T >
inline BSONObjBuilder& BSONObjBuilder::append( const StringData& fieldN inline BSONArrayBuilder& BSONArrayBuilder::append( const std::set< T >&
ame, const set< T >& vals ) { vals ) {
return _appendIt< set< T > >( *this, fieldName, vals ); return _appendArrayIt< std::set< T > >( *this, vals );
} }
// $or helper: OR(BSON("x" << GT << 7), BSON("y" << LT 6)); // $or helper: OR(BSON("x" << GT << 7), BSON("y" << LT 6));
inline BSONObj OR(const BSONObj& a, const BSONObj& b) inline BSONObj OR(const BSONObj& a, const BSONObj& b)
{ return BSON( "$or" << BSON_ARRAY(a << b) ); } { return BSON( "$or" << BSON_ARRAY(a << b) ); }
inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c) inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c)
{ return BSON( "$or" << BSON_ARRAY(a << b << c) ); } { return BSON( "$or" << BSON_ARRAY(a << b << c) ); }
inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d) inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d)
{ return BSON( "$or" << BSON_ARRAY(a << b << c << d) ); } { return BSON( "$or" << BSON_ARRAY(a << b << c << d) ); }
inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e) inline BSONObj OR(const BSONObj& a, const BSONObj& b, const BSONObj& c, const BSONObj& d, const BSONObj& e)
 End of changes. 29 change blocks. 
38 lines changed or deleted 61 lines changed or added


 bsonobjiterator.h   bsonobjiterator.h 
skipping to change at line 61 skipping to change at line 61
} }
/** @return true if more elements exist to be enumerated. */ /** @return true if more elements exist to be enumerated. */
bool more() { return _pos < _theend; } bool more() { return _pos < _theend; }
/** @return true if more elements exist to be enumerated INCLUDING the EOO element which is always at the end. */ /** @return true if more elements exist to be enumerated INCLUDING the EOO element which is always at the end. */
bool moreWithEOO() { return _pos <= _theend; } bool moreWithEOO() { return _pos <= _theend; }
/** @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 ) { BSONElement next( bool checkEnd ) {
assert( _pos <= _theend ); verify( _pos <= _theend );
BSONElement e( _pos, checkEnd ? (int)(_theend + 1 - _pos) : -1 ); BSONElement e( _pos, checkEnd ? (int)(_theend + 1 - _pos) : -1 );
_pos += e.size( checkEnd ? (int)(_theend + 1 - _pos) : -1 ); _pos += e.size( checkEnd ? (int)(_theend + 1 - _pos) : -1 );
return e; return e;
} }
BSONElement next() { BSONElement next() {
assert( _pos <= _theend ); verify( _pos <= _theend );
BSONElement e(_pos); BSONElement e(_pos);
_pos += e.size(); _pos += e.size();
return e; return e;
} }
void operator++() { next(); } void operator++() { next(); }
void operator++(int) { next(); } void operator++(int) { next(); }
BSONElement operator*() { BSONElement operator*() {
assert( _pos <= _theend ); verify( _pos <= _theend );
return BSONElement(_pos); return BSONElement(_pos);
} }
private: private:
const char* _pos; const char* _pos;
const char* _theend; const char* _theend;
}; };
class BSONObjIteratorSorted { /** Base class implementing ordered iteration through BSONElements. */
class BSONIteratorSorted {
public: public:
BSONObjIteratorSorted( const BSONObj& o ); ~BSONIteratorSorted() {
verify( _fields );
~BSONObjIteratorSorted() {
assert( _fields );
delete[] _fields; delete[] _fields;
_fields = 0; _fields = 0;
} }
bool more() { bool more() {
return _cur < _nfields; return _cur < _nfields;
} }
BSONElement next() { BSONElement next() {
assert( _fields ); verify( _fields );
if ( _cur < _nfields ) if ( _cur < _nfields )
return BSONElement( _fields[_cur++] ); return BSONElement( _fields[_cur++] );
return BSONElement(); return BSONElement();
} }
protected:
class ElementFieldCmp;
BSONIteratorSorted( const BSONObj &o, const ElementFieldCmp &cmp );
private: private:
const char ** _fields; const char ** _fields;
int _nfields; int _nfields;
int _cur; int _cur;
}; };
/** Provides iteration of a BSONObj's BSONElements in lexical field ord
er. */
class BSONObjIteratorSorted : public BSONIteratorSorted {
public:
BSONObjIteratorSorted( const BSONObj &object );
};
/**
* Provides iteration of a BSONArray's BSONElements in numeric field or
der.
* The elements of a bson array should always be numerically ordered by
field name, but this
* implementation re-sorts them anyway.
*/
class BSONArrayIteratorSorted : public BSONIteratorSorted {
public:
BSONArrayIteratorSorted( const BSONArray &array );
};
/** transform a BSON array into a vector of BSONElements. /** transform a BSON array into a vector of BSONElements.
we match array # positions with their vector position, and ignore we match array # positions with their vector position, and ignore
any fields with non-numeric field names. any fields with non-numeric field names.
*/ */
inline vector<BSONElement> BSONElement::Array() const { inline std::vector<BSONElement> BSONElement::Array() const {
chk(mongo::Array); chk(mongo::Array);
vector<BSONElement> v; std::vector<BSONElement> v;
BSONObjIterator i(Obj()); BSONObjIterator i(Obj());
while( i.more() ) { while( i.more() ) {
BSONElement e = i.next(); BSONElement e = i.next();
const char *f = e.fieldName(); const char *f = e.fieldName();
try { try {
unsigned u = stringToNum(f); unsigned u = stringToNum(f);
assert( u < 1000000 ); verify( u < 1000000 );
if( u >= v.size() ) if( u >= v.size() )
v.resize(u+1); v.resize(u+1);
v[u] = e; v[u] = e;
} }
catch(unsigned) { } catch(unsigned) { }
} }
return v; return v;
} }
/** Similar to BOOST_FOREACH /** Similar to BOOST_FOREACH
 End of changes. 11 change blocks. 
12 lines changed or deleted 34 lines changed or added


 bsontypes.h   bsontypes.h 
skipping to change at line 26 skipping to change at line 26
*/ */
#pragma once #pragma once
#include "util/misc.h" #include "util/misc.h"
namespace bson { } namespace bson { }
namespace mongo { namespace mongo {
using namespace std;
class BSONArrayBuilder; class BSONArrayBuilder;
class BSONElement; class BSONElement;
class BSONObj; class BSONObj;
class BSONObjBuilder; class BSONObjBuilder;
class BSONObjBuilderValueStream; class BSONObjBuilderValueStream;
class BSONObjIterator; class BSONObjIterator;
class Ordering; class Ordering;
class Record; class Record;
struct BSONArray; // empty subclass of BSONObj useful for overloading struct BSONArray; // empty subclass of BSONObj useful for overloading
struct BSONElementCmpWithoutField; struct BSONElementCmpWithoutField;
 End of changes. 1 change blocks. 
2 lines changed or deleted 0 lines changed or added


 btree.h   btree.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 "../pch.h" #include "pch.h"
#include "jsobj.h" #include "mongo/db/jsobj.h"
#include "diskloc.h" #include "mongo/db/diskloc.h"
#include "pdfile.h" #include "mongo/db/pdfile.h"
#include "key.h" #include "mongo/db/key.h"
namespace mongo { namespace mongo {
/** /**
* Our btree implementation generally follows the standard btree algori thm, * Our btree implementation generally follows the standard btree algori thm,
* which is described in many places. The nodes of our btree are refer red to * which is described in many places. The nodes of our btree are refer red to
* as buckets below. These buckets are of size BucketSize and their bo dy is * as buckets below. These buckets are of size BucketSize and their bo dy is
* an ordered array of <bson key, disk loc> pairs, where disk loc is th e disk * an ordered array of <bson key, disk loc> pairs, where disk loc is th e disk
* location of a document and bson key is a projection of this document into * location of a document and bson key is a projection of this document into
* the schema of the index for this btree. Ordering is determined on t he * the schema of the index for this btree. Ordering is determined on t he
skipping to change at line 93 skipping to change at line 93
*/ */
Loc prevChildBucket; Loc prevChildBucket;
/** The location of the record associated with this key. */ /** The location of the record associated with this key. */
Loc recordLoc; Loc recordLoc;
short keyDataOfs() const { return (short) _kdo; } short keyDataOfs() const { return (short) _kdo; }
/** Offset within current bucket of the variable width bson key for this _KeyNode. */ /** Offset within current bucket of the variable width bson key for this _KeyNode. */
unsigned short _kdo; unsigned short _kdo;
void setKeyDataOfs(short s) { void setKeyDataOfs(short s) {
_kdo = s; _kdo = s;
assert(s>=0); verify(s>=0);
} }
/** Seems to be redundant. */ /** Seems to be redundant. */
void setKeyDataOfsSavingUse(short s) { void setKeyDataOfsSavingUse(short s) {
_kdo = s; _kdo = s;
assert(s>=0); verify(s>=0);
} }
/** /**
* Unused keys are not returned by read operations. Keys may be ma rked * Unused keys are not returned by read operations. Keys may be ma rked
* as unused in cases where it is difficult to delete them while * as unused in cases where it is difficult to delete them while
* maintaining the constraints required of a btree. * maintaining the constraints required of a btree.
* *
* Setting ofs to odd is the sentinel for unused, as real recordLoc 's * Setting ofs to odd is the sentinel for unused, as real recordLoc 's
* are always even numbers. Note we need to keep its value basical ly * are always even numbers. Note we need to keep its value basical ly
* the same as we use the recordLoc as part of the key in the index * the same as we use the recordLoc as part of the key in the index
* (to handle duplicate keys efficiently). * (to handle duplicate keys efficiently).
skipping to change at line 183 skipping to change at line 183
public: public:
typedef __KeyNode<DiskLoc> _KeyNode; typedef __KeyNode<DiskLoc> _KeyNode;
typedef DiskLoc Loc; typedef DiskLoc Loc;
typedef KeyBson Key; typedef KeyBson Key;
typedef KeyBson KeyOwned; typedef KeyBson KeyOwned;
enum { BucketSize = 8192 }; enum { BucketSize = 8192 };
// largest key size we allow. note we very much need to support bi gger keys (somehow) in the future. // largest key size we allow. note we very much need to support bi gger keys (somehow) in the future.
static const int KeyMax = OldBucketSize / 10; static const int KeyMax = OldBucketSize / 10;
// A sentinel value sometimes used to identify a deallocated bucket
.
static const int INVALID_N_SENTINEL = -1;
}; };
// a a a ofs ofs ofs ofs // a a a ofs ofs ofs ofs
class DiskLoc56Bit { class DiskLoc56Bit {
int ofs; int ofs;
unsigned char _a[3]; unsigned char _a[3];
unsigned long long Z() const { unsigned long long Z() const {
// endian // endian
return *((unsigned long long*)this) & 0x00ffffffffffffffULL; return *((unsigned long long*)this) & 0x00ffffffffffffffULL;
} }
skipping to change at line 241 skipping to change at line 243
bool operator!=(const DiskLoc& rhs) const { return !(*this==rhs); } bool operator!=(const DiskLoc& rhs) const { return !(*this==rhs); }
bool isNull() const { return ofs < 0; } bool isNull() const { return ofs < 0; }
void Null() { void Null() {
ofs = OurNullOfs; ofs = OurNullOfs;
_a[0] = _a[1] = _a[2] = 0; _a[0] = _a[1] = _a[2] = 0;
} }
string toString() const { return DiskLoc(*this).toString(); } string toString() const { return DiskLoc(*this).toString(); }
void operator=(const DiskLoc& loc) { void operator=(const DiskLoc& loc) {
ofs = loc.getOfs(); ofs = loc.getOfs();
int la = loc.a(); int la = loc.a();
assert( la <= 0xffffff ); // must fit in 3 bytes verify( la <= 0xffffff ); // must fit in 3 bytes
if( la < 0 ) { if( la < 0 ) {
assert( la == -1 ); if ( la != -1 ) {
log() << "btree diskloc isn't negative 1: " << la << en
dl;
verify ( la == -1 );
}
la = 0; la = 0;
ofs = OurNullOfs; ofs = OurNullOfs;
} }
memcpy(_a, &la, 3); // endian memcpy(_a, &la, 3); // endian
dassert( ofs != 0 ); dassert( ofs != 0 );
} }
DiskLoc56Bit& writing() const { DiskLoc56Bit& writing() const {
return *((DiskLoc56Bit*) getDur().writingPtr((void*)this, 7)); return *((DiskLoc56Bit*) getDur().writingPtr((void*)this, 7));
} }
}; };
skipping to change at line 265 skipping to change at line 270
class BtreeData_V1 { class BtreeData_V1 {
public: public:
typedef DiskLoc56Bit Loc; typedef DiskLoc56Bit Loc;
//typedef DiskLoc Loc; //typedef DiskLoc Loc;
typedef __KeyNode<Loc> _KeyNode; typedef __KeyNode<Loc> _KeyNode;
typedef KeyV1 Key; typedef KeyV1 Key;
typedef KeyV1Owned KeyOwned; typedef KeyV1Owned KeyOwned;
enum { BucketSize = 8192-16 }; // leave room for Record header enum { BucketSize = 8192-16 }; // leave room for Record header
// largest key size we allow. note we very much need to support bi gger keys (somehow) in the future. // largest key size we allow. note we very much need to support bi gger keys (somehow) in the future.
static const int KeyMax = 1024; static const int KeyMax = 1024;
// A sentinel value sometimes used to identify a deallocated bucket
.
static const unsigned short INVALID_N_SENTINEL = 0xffff;
protected: protected:
/** Parent bucket of this bucket, which isNull() for the root bucke t. */ /** Parent bucket of this bucket, which isNull() for the root bucke t. */
Loc parent; Loc parent;
/** Given that there are n keys, this is the n index child. */ /** Given that there are n keys, this is the n index child. */
Loc nextChild; Loc nextChild;
unsigned short flags; unsigned short flags;
/** basicInsert() assumes the next three members are consecutive an d in this order: */ /** basicInsert() assumes the next three members are consecutive an d in this order: */
skipping to change at line 411 skipping to change at line 418
* keys and 'key'. * keys and 'key'.
* Postconditions: * Postconditions:
* - If there is space for key without packing, it is inserted as the * - If there is space for key without packing, it is inserted as the
* last key with specified prevChild and true is returned. * last key with specified prevChild and true is returned.
* Importantly, nextChild is not updated! * Importantly, nextChild is not updated!
* - Otherwise false is returned and there is no change. * - Otherwise false is returned and there is no change.
*/ */
bool _pushBack(const DiskLoc recordLoc, const Key& key, const Order ing &order, const DiskLoc prevChild); bool _pushBack(const DiskLoc recordLoc, const Key& key, const Order ing &order, const DiskLoc prevChild);
void pushBack(const DiskLoc recordLoc, const Key& key, const Orderi ng &order, const DiskLoc prevChild) { void pushBack(const DiskLoc recordLoc, const Key& key, const Orderi ng &order, const DiskLoc prevChild) {
bool ok = _pushBack( recordLoc , key , order , prevChild ); bool ok = _pushBack( recordLoc , key , order , prevChild );
assert(ok); verify(ok);
} }
/** /**
* This is a special purpose function used by BtreeBuilder. The * This is a special purpose function used by BtreeBuilder. The
* interface is quite dangerous if you're not careful. The bson ke y * interface is quite dangerous if you're not careful. The bson ke y
* returned here points to bucket memory that has been invalidated but * returned here points to bucket memory that has been invalidated but
* not yet reclaimed. * not yet reclaimed.
* *
* TODO Maybe this could be replaced with two functions, one which * TODO Maybe this could be replaced with two functions, one which
* returns the last key without deleting it and another which simpl y * returns the last key without deleting it and another which simpl y
skipping to change at line 575 skipping to change at line 582
* - The bson 'key' must fit in the bucket without packing. * - The bson 'key' must fit in the bucket without packing.
* - If 'key' and 'prevChildBucket' are set at index i, the btree * - If 'key' and 'prevChildBucket' are set at index i, the btree
* ordering properties will be maintained. * ordering properties will be maintained.
* Postconditions: * Postconditions:
* - The specified key is set at index i, replacing the existing * - The specified key is set at index i, replacing the existing
* _KeyNode data and without shifting any other _KeyNode objects . * _KeyNode data and without shifting any other _KeyNode objects .
*/ */
void setKey( int i, const DiskLoc recordLoc, const Key& key, const DiskLoc prevChildBucket ); void setKey( int i, const DiskLoc recordLoc, const Key& key, const DiskLoc prevChildBucket );
}; };
class IndexInsertionContinuation;
template< class V> template< class V>
struct Continuation; struct IndexInsertionContinuationImpl;
/** /**
* This class adds functionality for manipulating buckets that are asse mbled * This class adds functionality for manipulating buckets that are asse mbled
* in a tree. The requirements for const and non const functions and * in a tree. The requirements for const and non const functions and
* arguments are generally the same as in BtreeBucket. Because this cl ass * arguments are generally the same as in BtreeBucket. Because this cl ass
* deals with tree structure, some functions that are marked const may * deals with tree structure, some functions that are marked const may
* trigger modification of another node in the btree or potentially of the * trigger modification of another node in the btree or potentially of the
* current node. In such cases, the function's implementation explicit ly * current node. In such cases, the function's implementation explicit ly
* casts away const when indicating an intent to write to the durabilit y * casts away const when indicating an intent to write to the durabilit y
* layer. The DiskLocs provided to such functions should be passed by * layer. The DiskLocs provided to such functions should be passed by
skipping to change at line 609 skipping to change at line 618
* *
* TODO There are several cases in which the 'this' pointer is invalida ted * TODO There are several cases in which the 'this' pointer is invalida ted
* as a result of deallocation. A seperate class representing a btree would * as a result of deallocation. A seperate class representing a btree would
* alleviate some fragile cases where the implementation must currently * alleviate some fragile cases where the implementation must currently
* behave correctly if the 'this' pointer is suddenly invalidated by a * behave correctly if the 'this' pointer is suddenly invalidated by a
* callee. * callee.
*/ */
template< class V > template< class V >
class BtreeBucket : public BucketBasics<V> { class BtreeBucket : public BucketBasics<V> {
friend class BtreeCursor; friend class BtreeCursor;
friend struct Continuation<V>; friend struct IndexInsertionContinuationImpl<V>;
public: public:
// make compiler happy: // make compiler happy:
typedef typename V::Key Key; typedef typename V::Key Key;
typedef typename V::KeyOwned KeyOwned; typedef typename V::KeyOwned KeyOwned;
typedef typename BucketBasics<V>::KeyNode KeyNode; typedef typename BucketBasics<V>::KeyNode KeyNode;
typedef typename BucketBasics<V>::_KeyNode _KeyNode; typedef typename BucketBasics<V>::_KeyNode _KeyNode;
typedef typename BucketBasics<V>::Loc Loc; typedef typename BucketBasics<V>::Loc Loc;
const _KeyNode& k(int i) const { return static_cast< const Buck etBasics<V> * >(this)->k(i); } const _KeyNode& k(int i) const { return static_cast< const Buck etBasics<V> * >(this)->k(i); }
protected: protected:
_KeyNode& k(int i) { return static_cast< BucketBasi cs<V> * >(this)->_k(i); } _KeyNode& k(int i) { return static_cast< BucketBasi cs<V> * >(this)->_k(i); }
skipping to change at line 689 skipping to change at line 698
* and @return 0. The root of the btree may be changed, so * and @return 0. The root of the btree may be changed, so
* 'this'/thisLoc may no longer be the root upon return. * 'this'/thisLoc may no longer be the root upon return.
*/ */
int bt_insert(const DiskLoc thisLoc, const DiskLoc recordLoc, int bt_insert(const DiskLoc thisLoc, const DiskLoc recordLoc,
const BSONObj& key, const Ordering &order, bool dupsA llowed, const BSONObj& key, const Ordering &order, bool dupsA llowed,
IndexDetails& idx, bool toplevel = true) const; IndexDetails& idx, bool toplevel = true) const;
/** does the insert in two steps - can then use an upgradable lock for step 1, which /** does the insert in two steps - can then use an upgradable lock for step 1, which
is the part which may have page faults. also that step is most of the computational work. is the part which may have page faults. also that step is most of the computational work.
*/ */
void twoStepInsert(DiskLoc thisLoc, Continuation<V> &c, bool dupsAl lowed) const; void twoStepInsert(DiskLoc thisLoc, IndexInsertionContinuationImpl< V> &c, bool dupsAllowed) const;
/** /**
* Preconditions: * Preconditions:
* - 'key' has a valid schema for this index, and may have objsize () > KeyMax. * - 'key' has a valid schema for this index, and may have objsize () > KeyMax.
* Postconditions: * Postconditions:
* - If key / recordLoc are in the btree, they are removed (possib ly * - If key / recordLoc are in the btree, they are removed (possib ly
* by being marked as an unused key), @return true, and potentia lly * by being marked as an unused key), @return true, and potentia lly
* invalidate 'this' / thisLoc and change the head. * invalidate 'this' / thisLoc and change the head.
* - If key / recordLoc are not in the btree, @return false and do nothing. * - If key / recordLoc are not in the btree, @return false and do nothing.
*/ */
skipping to change at line 943 skipping to change at line 952
*/ */
void insertHere(const DiskLoc thisLoc, int keypos, void insertHere(const DiskLoc thisLoc, int keypos,
const DiskLoc recordLoc, const Key& key, const Orde ring &order, const DiskLoc recordLoc, const Key& key, const Orde ring &order,
const DiskLoc lchild, const DiskLoc rchild, IndexDe tails &idx) const; const DiskLoc lchild, const DiskLoc rchild, IndexDe tails &idx) const;
/** bt_insert() is basically just a wrapper around this. */ /** bt_insert() is basically just a wrapper around this. */
int _insert(const DiskLoc thisLoc, const DiskLoc recordLoc, int _insert(const DiskLoc thisLoc, const DiskLoc recordLoc,
const Key& key, const Ordering &order, bool dupsAllowed , const Key& key, const Ordering &order, bool dupsAllowed ,
const DiskLoc lChild, const DiskLoc rChild, IndexDetail s &idx) const; const DiskLoc lChild, const DiskLoc rChild, IndexDetail s &idx) const;
void insertStepOne(DiskLoc thisLoc, Continuation<V>& c, bool dupsAl void insertStepOne(
lowed) const; DiskLoc thisLoc, IndexInsertionContinuationImpl<V>& c, bool
dupsAllowed) const;
bool find(const IndexDetails& idx, const Key& key, const DiskLoc &r ecordLoc, const Ordering &order, int& pos, bool assertIfDup) const; bool find(const IndexDetails& idx, const Key& key, const DiskLoc &r ecordLoc, const Ordering &order, int& pos, bool assertIfDup) const;
static bool customFind( int l, int h, const BSONObj &keyBegin, int keyBeginLen, bool afterKey, const vector< const BSONElement * > &keyEnd, co nst vector< bool > &keyEndInclusive, const Ordering &order, int direction, DiskLoc &thisLoc, int &keyOfs, pair< DiskLoc, int > &bestParent ) ; static bool customFind( int l, int h, const BSONObj &keyBegin, int keyBeginLen, bool afterKey, const vector< const BSONElement * > &keyEnd, co nst vector< bool > &keyEndInclusive, const Ordering &order, int direction, DiskLoc &thisLoc, int &keyOfs, pair< DiskLoc, int > &bestParent ) ;
static void findLargestKey(const DiskLoc& thisLoc, DiskLoc& largest Loc, int& largestKey); static void findLargestKey(const DiskLoc& thisLoc, DiskLoc& largest Loc, int& largestKey);
static int customBSONCmp( const BSONObj &l, const BSONObj &rBegin, int rBeginLen, bool rSup, const vector< const BSONElement * > &rEnd, const vector< bool > &rEndInclusive, const Ordering &o, int direction ); static int customBSONCmp( const BSONObj &l, const BSONObj &rBegin, int rBeginLen, bool rSup, const vector< const BSONElement * > &rEnd, const vector< bool > &rEndInclusive, const Ordering &o, int direction );
/** If child is non null, set its parent to thisLoc */ /** If child is non null, set its parent to thisLoc */
static void fix(const DiskLoc thisLoc, const DiskLoc child); static void fix(const DiskLoc thisLoc, const DiskLoc child);
/** /**
skipping to change at line 994 skipping to change at line 1004
void deleteInternalKey( const DiskLoc thisLoc, int keypos, IndexDet ails &id, const Ordering &order ); void deleteInternalKey( const DiskLoc thisLoc, int keypos, IndexDet ails &id, const Ordering &order );
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 Key& key ); static string dupKeyError( const IndexDetails& idx , const Key& key );
}; };
#pragma pack() #pragma pack()
class FieldRangeVector; class FieldRangeVector;
class FieldRangeVectorIterator; class FieldRangeVectorIterator;
/**
* A Cursor class for Btree iteration.
*
* A BtreeCursor can record its current btree position (noteLoc()) and
then relocate this
* position after a write (checkLoc()). A recorded btree position cons
ists of a btree bucket,
* bucket key offset, and unique btree key. To relocate a unique btree
key, a BtreeCursor first
* checks the btree key at its recorded btree bucket and bucket key off
set. If the key at that
* location does not match the recorded btree key, and an adjacent key
also fails to match,
* the recorded key (or the next existing key following it) is located
in the btree using binary
* search. If the recorded btree bucket is invalidated, the initial re
corded bucket check is
* not attempted (see SERVER-4575).
*/
class BtreeCursor : public Cursor { class BtreeCursor : public Cursor {
protected: protected:
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& BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails&
_id, const shared_ptr< FieldRangeVector > &_bounds, int _direction ); _id,
const shared_ptr< FieldRangeVector > &_bounds, int sing
leIntervalLimit,
int _direction );
public: public:
virtual ~BtreeCursor(); virtual ~BtreeCursor();
/** makes an appropriate subclass depending on the index version */ /** makes an appropriate subclass depending on the index version */
static BtreeCursor* make( NamespaceDetails *_d, const IndexDetails& , const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int direction ); static BtreeCursor* make( NamespaceDetails *_d, const IndexDetails& , const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int direction );
static BtreeCursor* make( NamespaceDetails *_d, const IndexDetails& _id, const shared_ptr< FieldRangeVector > &_bounds, int _direction ); static BtreeCursor* make( NamespaceDetails *_d, const IndexDetails& _id, const shared_ptr< FieldRangeVector > &_bounds, int _direction );
static BtreeCursor* make( NamespaceDetails *_d, int _idxNo, const I ndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyIn clusive, int direction ); static BtreeCursor* make( NamespaceDetails *_d, int _idxNo, const I ndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyIn clusive, int direction );
static BtreeCursor* make( NamespaceDetails *_d, int _idxNo, const I static BtreeCursor* make( NamespaceDetails *_d, int _idxNo, const I
ndexDetails& _id, const shared_ptr< FieldRangeVector > &_bounds, int _direc ndexDetails& _id,
tion ); const shared_ptr< FieldRangeVector > &_bou
nds,
int singleIntervalLimit, int _direction );
virtual bool ok() { return !bucket.isNull(); } virtual bool ok() { return !bucket.isNull(); }
virtual bool advance(); virtual bool advance();
virtual void noteLocation(); // updates keyAtKeyOfs... virtual void noteLocation(); // updates keyAtKeyOfs...
virtual void checkLocation() = 0; virtual void checkLocation() = 0;
virtual bool supportGetMore() { return true; } virtual bool supportGetMore() { return true; }
virtual bool supportYields() { return true; } virtual bool supportYields() { return true; }
/** /**
* used for multikey index traversal to avoid sending back dups. se e Matcher::matches(). * used for multikey index traversal to avoid sending back dups. se e Matcher::matches().
skipping to change at line 1032 skipping to change at line 1058
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;
} }
virtual bool modifiedKeys() const { return _multikey; } virtual bool modifiedKeys() const { return _multikey; }
virtual bool isMultiKey() const { return _multikey; } virtual bool isMultiKey() const { return _multikey; }
/*const _KeyNode& _currKeyNode() const { /*const _KeyNode& _currKeyNode() const {
assert( !bucket.isNull() ); verify( !bucket.isNull() );
const _KeyNode& kn = keyNode(keyOfs); const _KeyNode& kn = keyNode(keyOfs);
assert( kn.isUsed() ); verify( kn.isUsed() );
return kn; return kn;
}*/ }*/
/** returns BSONObj() if ofs is out of range */ /** returns BSONObj() if ofs is out of range */
virtual BSONObj keyAt(int ofs) const = 0; virtual BSONObj keyAt(int ofs) const = 0;
virtual BSONObj currKey() const = 0; virtual BSONObj currKey() const = 0;
virtual BSONObj indexKeyPattern() { return indexDetails.keyPattern( ); } virtual BSONObj indexKeyPattern() { return indexDetails.keyPattern( ); }
virtual void aboutToDeleteBucket(const DiskLoc& b) { virtual void aboutToDeleteBucket(const DiskLoc& b) {
skipping to change at line 1066 skipping to change at line 1092
return key.replaceFieldNames( indexDetails.keyPattern() ).clien tReadable(); return key.replaceFieldNames( indexDetails.keyPattern() ).clien tReadable();
} }
virtual BSONObj prettyIndexBounds() const; virtual BSONObj prettyIndexBounds() const;
virtual CoveredIndexMatcher *matcher() const { return _matcher.get( ); } virtual CoveredIndexMatcher *matcher() const { return _matcher.get( ); }
virtual shared_ptr< CoveredIndexMatcher > matcherPtr() const { retu rn _matcher; } virtual shared_ptr< CoveredIndexMatcher > matcherPtr() const { retu rn _matcher; }
virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) { _matcher = matcher; } virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) { _matcher = matcher; }
virtual const Projection::KeyOnly *keyFieldsOnly() const { return _
keyFieldsOnly.get(); }
virtual void setKeyFieldsOnly( const shared_ptr<Projection::KeyOnly
> &keyFieldsOnly ) {
_keyFieldsOnly = keyFieldsOnly;
}
virtual long long nscanned() { return _nscanned; } virtual long long nscanned() { return _nscanned; }
/** for debugging only */ /** for debugging only */
const DiskLoc getBucket() const { return bucket; } const DiskLoc getBucket() const { return bucket; }
int getKeyOfs() const { return keyOfs; } int getKeyOfs() const { return keyOfs; }
// just for unit tests // just for unit tests
virtual bool curKeyHasChild() = 0; virtual bool curKeyHasChild() = 0;
protected: protected:
skipping to change at line 1118 skipping to change at line 1150
const BSONObj _order; const BSONObj _order;
const Ordering _ordering; const Ordering _ordering;
DiskLoc bucket; DiskLoc bucket;
int keyOfs; int keyOfs;
const int _direction; // 1=fwd,-1=reverse const 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;
const shared_ptr< FieldRangeVector > _bounds; const shared_ptr< FieldRangeVector > _bounds;
auto_ptr< FieldRangeVectorIterator > _boundsIterator; auto_ptr< FieldRangeVectorIterator > _boundsIterator;
shared_ptr< CoveredIndexMatcher > _matcher; shared_ptr< CoveredIndexMatcher > _matcher;
shared_ptr<Projection::KeyOnly> _keyFieldsOnly;
bool _independentFieldRanges; bool _independentFieldRanges;
long long _nscanned; long long _nscanned;
}; };
template< class V >
struct Continuation {
//Continuation(const typename V::Key & k);
Continuation(DiskLoc thisLoc, DiskLoc _recordLoc, const BSONObj &_k
ey,
Ordering _order, IndexDetails& _idx) :
bLoc(thisLoc), recordLoc(_recordLoc), key(_key), order(_order),
idx(_idx) {
op = Nothing;
}
DiskLoc bLoc;
DiskLoc recordLoc;
typename V::KeyOwned key;
const Ordering order;
IndexDetails& idx;
enum Op { Nothing, SetUsed, InsertHere } op;
int pos;
const BtreeBucket<V> *b;
void stepTwo() {
if( op == Nothing )
return;
else if( op == SetUsed ) {
const typename V::_KeyNode& kn = b->k(pos);
kn.writing().setUsed();
}
else {
b->insertHere(bLoc, pos, recordLoc, key, order, DiskLoc(),
DiskLoc(), idx);
}
}
};
/** Renames the index namespace for this btree's index. */ /** Renames the index namespace for this btree's index. */
void renameIndexNamespace(const char *oldNs, const char *newNs); void renameIndexNamespace(const char *oldNs, const char *newNs);
/** /**
* give us a writable version of the btree bucket (declares write inten t). * give us a writable version of the btree bucket (declares write inten t).
* note it is likely more efficient to declare write intent on somethin g smaller when you can. * note it is likely more efficient to declare write intent on somethin g smaller when you can.
*/ */
template< class V > template< class V >
BtreeBucket<V> * DiskLoc::btreemod() const { BtreeBucket<V> * DiskLoc::btreemod() const {
assert( _a != -1 ); verify( _a != -1 );
BtreeBucket<V> *b = const_cast< BtreeBucket<V> * >( btree<V>() ); BtreeBucket<V> *b = const_cast< BtreeBucket<V> * >( btree<V>() );
return static_cast< BtreeBucket<V>* >( getDur().writingPtr( b, V::B ucketSize ) ); return static_cast< BtreeBucket<V>* >( getDur().writingPtr( b, V::B ucketSize ) );
} }
template< class V > template< class V >
BucketBasics<V>::KeyNode::KeyNode(const BucketBasics<V>& bb, const _Key Node &k) : BucketBasics<V>::KeyNode::KeyNode(const BucketBasics<V>& bb, const _Key Node &k) :
prevChildBucket(k.prevChildBucket), prevChildBucket(k.prevChildBucket),
recordLoc(k.recordLoc), key(bb.data+k.keyDataOfs()) recordLoc(k.recordLoc), key(bb.data+k.keyDataOfs())
{ } { }
 End of changes. 22 change blocks. 
58 lines changed or deleted 69 lines changed or added


 bufreader.h   bufreader.h 
skipping to change at line 67 skipping to change at line 67
/** return current offset into buffer */ /** return current offset into buffer */
unsigned offset() const { return (char*)_pos - (char*)_start; } unsigned offset() const { return (char*)_pos - (char*)_start; }
/** return remaining bytes */ /** return remaining bytes */
unsigned remaining() const { return (char*)_end -(char*)_pos; } unsigned remaining() const { return (char*)_end -(char*)_pos; }
/** back up by nbytes */ /** back up by nbytes */
void rewind(unsigned nbytes) { void rewind(unsigned nbytes) {
_pos = ((char *) _pos) - nbytes; _pos = ((char *) _pos) - nbytes;
assert( _pos >= _start ); verify( _pos >= _start );
} }
/** return current position pointer, and advance by len */ /** return current position pointer, and advance by len */
const void* skip(unsigned len) { const void* skip(unsigned len) {
const char *nxt = ((char *) _pos) + len; const char *nxt = ((char *) _pos) + len;
if( _end < nxt ) throw eof(); if( _end < nxt ) throw eof();
const void *p = _pos; const void *p = _pos;
_pos = nxt; _pos = nxt;
return p; return p;
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 builder.h   builder.h 
skipping to change at line 30 skipping to change at line 30
#include <cfloat> #include <cfloat>
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <iostream> #include <iostream>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include "../inline_decls.h" #include "../inline_decls.h"
#include "../stringdata.h" #include "../stringdata.h"
namespace mongo { namespace mongo {
/* Accessing unaligned doubles on ARM generates an alignment trap and a
borts with SIGBUS on Linux.
Wrapping the double in a packed struct forces gcc to generate code t
hat works with unaligned values too.
The generated code for other architectures (which already allow unal
igned accesses) is the same as if
there was a direct pointer access.
*/
struct PackedDouble {
double d;
} PACKED_DECL;
/* 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.
Also note that the server has some basic checks to enforce this limi t but those checks are not exhaustive Also note that the server has some basic checks to enforce this limi t but those checks are not exhaustive
for example need to check for size too big after for example need to check for size too big after
update $push (append) operation update $push (append) operation
various db.eval() type operations various db.eval() type operations
*/ */
const int BSONObjMaxUserSize = 16 * 1024 * 1024; const int BSONObjMaxUserSize = 16 * 1024 * 1024;
/* /*
Sometimes we need objects slightly larger - an object in the replica tion local.oplog Sometimes we need objects slightly larger - an object in the replica tion local.oplog
is slightly larger than a user object for example. is slightly larger than a user object for example.
*/ */
const int BSONObjMaxInternalSize = BSONObjMaxUserSize + ( 16 * 1024 ); const int BSONObjMaxInternalSize = BSONObjMaxUserSize + ( 16 * 1024 );
const int BufferMaxSize = 64 * 1024 * 1024; const int BufferMaxSize = 64 * 1024 * 1024;
class StringBuilder;
void msgasserted(int msgid, const char *msg); void msgasserted(int msgid, const char *msg);
template <typename Allocator>
class StringBuilderImpl;
class TrivialAllocator { class TrivialAllocator {
public: public:
void* Malloc(size_t sz) { return malloc(sz); } void* Malloc(size_t sz) { return malloc(sz); }
void* Realloc(void *p, size_t sz) { return realloc(p, sz); } void* Realloc(void *p, size_t sz) { return realloc(p, sz); }
void Free(void *p) { free(p); } void Free(void *p) { free(p); }
}; };
class StackAllocator { class StackAllocator {
public: public:
enum { SZ = 512 }; enum { SZ = 512 };
skipping to change at line 161 skipping to change at line 170
void appendNum(int j) { void appendNum(int j) {
*((int*)grow(sizeof(int))) = j; *((int*)grow(sizeof(int))) = j;
} }
void appendNum(unsigned j) { void appendNum(unsigned j) {
*((unsigned*)grow(sizeof(unsigned))) = j; *((unsigned*)grow(sizeof(unsigned))) = j;
} }
void appendNum(bool j) { void appendNum(bool j) {
*((bool*)grow(sizeof(bool))) = j; *((bool*)grow(sizeof(bool))) = j;
} }
void appendNum(double j) { void appendNum(double j) {
*((double*)grow(sizeof(double))) = j; (reinterpret_cast< PackedDouble* >(grow(sizeof(double))))->d = j;
} }
void appendNum(long long j) { void appendNum(long long j) {
*((long long*)grow(sizeof(long long))) = j; *((long long*)grow(sizeof(long long))) = j;
} }
void appendNum(unsigned long long j) { void appendNum(unsigned long long j) {
*((unsigned long long*)grow(sizeof(unsigned long long))) = j; *((unsigned long long*)grow(sizeof(unsigned long long))) = j;
} }
void appendBuf(const void *src, size_t len) { void appendBuf(const void *src, size_t len) {
memcpy(grow((int) len), src, len); memcpy(grow((int) len), src, len);
skipping to change at line 212 skipping to change at line 221
void NOINLINE_DECL grow_reallocate() { void NOINLINE_DECL grow_reallocate() {
int a = 64; int a = 64;
while( a < l ) while( a < l )
a = a * 2; a = a * 2;
if ( a > BufferMaxSize ) { if ( a > BufferMaxSize ) {
std::stringstream ss; std::stringstream ss;
ss << "BufBuilder attempted to grow() to " << a << " bytes, past the 64MB limit."; ss << "BufBuilder attempted to grow() to " << a << " bytes, past the 64MB limit.";
msgasserted(13548, ss.str().c_str()); msgasserted(13548, ss.str().c_str());
} }
data = (char *) al.Realloc(data, a); data = (char *) al.Realloc(data, a);
size= a; if ( data == NULL )
msgasserted( 16070 , "out of memory BufBuilder::grow_reallo
cate" );
size = a;
} }
char *data; char *data;
int l; int l;
int size; int size;
friend class StringBuilder; friend class StringBuilderImpl<Allocator>;
}; };
typedef _BufBuilder<TrivialAllocator> BufBuilder; typedef _BufBuilder<TrivialAllocator> BufBuilder;
/** The StackBufBuilder builds smaller datasets on the stack instead of using malloc. /** The StackBufBuilder builds smaller datasets on the stack instead of using malloc.
this can be significantly faster for small bufs. However, you ca n not decouple() the this can be significantly faster for small bufs. However, you ca n not decouple() the
buffer with StackBufBuilder. buffer with StackBufBuilder.
While designed to be a variable on the stack, if you were to dynami cally allocate one, While designed to be a variable on the stack, if you were to dynami cally allocate one,
nothing bad would happen. In fact in some circumstances this mig ht make sense, say, nothing bad would happen. In fact in some circumstances this mig ht make sense, say,
embedded in some other object. embedded in some other object.
skipping to change at line 246 skipping to change at line 257
namespace { namespace {
#if defined(_WIN32) #if defined(_WIN32)
int (*mongo_snprintf)(char *str, size_t size, const char *format, . ..) = &sprintf_s; int (*mongo_snprintf)(char *str, size_t size, const char *format, . ..) = &sprintf_s;
#else #else
int (*mongo_snprintf)(char *str, size_t size, const char *format, . ..) = &snprintf; int (*mongo_snprintf)(char *str, size_t size, const char *format, . ..) = &snprintf;
#endif #endif
} }
/** stringstream deals with locale so this is a lot faster than std::st ringstream for UTF8 */ /** stringstream deals with locale so this is a lot faster than std::st ringstream for UTF8 */
class StringBuilder { template <typename Allocator>
class StringBuilderImpl {
public: public:
static const size_t MONGO_DBL_SIZE = 3 + DBL_MANT_DIG - DBL_MIN_EXP ; static const size_t MONGO_DBL_SIZE = 3 + DBL_MANT_DIG - DBL_MIN_EXP ;
static const size_t MONGO_S32_SIZE = 12; static const size_t MONGO_S32_SIZE = 12;
static const size_t MONGO_U32_SIZE = 11; static const size_t MONGO_U32_SIZE = 11;
static const size_t MONGO_S64_SIZE = 23; static const size_t MONGO_S64_SIZE = 23;
static const size_t MONGO_U64_SIZE = 22; static const size_t MONGO_U64_SIZE = 22;
static const size_t MONGO_S16_SIZE = 7; static const size_t MONGO_S16_SIZE = 7;
StringBuilder() { } StringBuilderImpl() { }
StringBuilder& operator<<( double x ) { StringBuilderImpl& operator<<( double x ) {
return SBNUM( x , MONGO_DBL_SIZE , "%g" ); return SBNUM( x , MONGO_DBL_SIZE , "%g" );
} }
StringBuilder& operator<<( int x ) { StringBuilderImpl& operator<<( int x ) {
return SBNUM( x , MONGO_S32_SIZE , "%d" ); return SBNUM( x , MONGO_S32_SIZE , "%d" );
} }
StringBuilder& operator<<( unsigned x ) { StringBuilderImpl& operator<<( unsigned x ) {
return SBNUM( x , MONGO_U32_SIZE , "%u" ); return SBNUM( x , MONGO_U32_SIZE , "%u" );
} }
StringBuilder& operator<<( long x ) { StringBuilderImpl& operator<<( long x ) {
return SBNUM( x , MONGO_S64_SIZE , "%ld" ); return SBNUM( x , MONGO_S64_SIZE , "%ld" );
} }
StringBuilder& operator<<( unsigned long x ) { StringBuilderImpl& operator<<( unsigned long x ) {
return SBNUM( x , MONGO_U64_SIZE , "%lu" ); return SBNUM( x , MONGO_U64_SIZE , "%lu" );
} }
StringBuilder& operator<<( long long x ) { StringBuilderImpl& operator<<( long long x ) {
return SBNUM( x , MONGO_S64_SIZE , "%lld" ); return SBNUM( x , MONGO_S64_SIZE , "%lld" );
} }
StringBuilder& operator<<( unsigned long long x ) { StringBuilderImpl& operator<<( unsigned long long x ) {
return SBNUM( x , MONGO_U64_SIZE , "%llu" ); return SBNUM( x , MONGO_U64_SIZE , "%llu" );
} }
StringBuilder& operator<<( short x ) { StringBuilderImpl& operator<<( short x ) {
return SBNUM( x , MONGO_S16_SIZE , "%hd" ); return SBNUM( x , MONGO_S16_SIZE , "%hd" );
} }
StringBuilder& operator<<( char c ) { StringBuilderImpl& operator<<( char c ) {
_buf.grow( 1 )[0] = c; _buf.grow( 1 )[0] = c;
return *this; return *this;
} }
void appendDoubleNice( double x ) { void appendDoubleNice( double x ) {
const int prev = _buf.l; const int prev = _buf.l;
const int maxSize = 32; const int maxSize = 32;
char * start = _buf.grow( maxSize ); char * start = _buf.grow( maxSize );
int z = mongo_snprintf( start , maxSize , "%.16g" , x ); int z = mongo_snprintf( start , maxSize , "%.16g" , x );
assert( z >= 0 ); verify( z >= 0 );
assert( z < maxSize ); verify( z < maxSize );
_buf.l = prev + z; _buf.l = prev + z;
if( strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strch r(start, 'N') == 0 ) { if( strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strch r(start, 'N') == 0 ) {
write( ".0" , 2 ); write( ".0" , 2 );
} }
} }
void write( const char* buf, int len) { memcpy( _buf.grow( len ) , buf , len ); } void write( const char* buf, int len) { memcpy( _buf.grow( len ) , buf , len ); }
void append( const StringData& str ) { memcpy( _buf.grow( str.size( ) ) , str.data() , str.size() ); } void append( const StringData& str ) { memcpy( _buf.grow( str.size( ) ) , str.data() , str.size() ); }
StringBuilder& operator<<( const StringData& str ) { StringBuilderImpl& operator<<( const StringData& str ) {
append( str ); append( str );
return *this; return *this;
} }
void reset( int maxSize = 0 ) { _buf.reset( maxSize ); } void reset( int maxSize = 0 ) { _buf.reset( maxSize ); }
std::string str() const { return std::string(_buf.data, _buf.l); } std::string str() const { return std::string(_buf.data, _buf.l); }
int len() const { return _buf.l; } int len() const { return _buf.l; }
private: private:
StackBufBuilder _buf; _BufBuilder<Allocator> _buf;
// non-copyable, non-assignable // non-copyable, non-assignable
StringBuilder( const StringBuilder& ); StringBuilderImpl( const StringBuilderImpl& );
StringBuilder& operator=( const StringBuilder& ); StringBuilderImpl& operator=( const StringBuilderImpl& );
template <typename T> template <typename T>
StringBuilder& SBNUM(T val,int maxSize,const char *macro) { StringBuilderImpl& SBNUM(T val,int maxSize,const char *macro) {
int prev = _buf.l; int prev = _buf.l;
int z = mongo_snprintf( _buf.grow(maxSize) , maxSize , macro , (val) ); int z = mongo_snprintf( _buf.grow(maxSize) , maxSize , macro , (val) );
assert( z >= 0 ); verify( z >= 0 );
assert( z < maxSize ); verify( z < maxSize );
_buf.l = prev + z; _buf.l = prev + z;
return *this; return *this;
} }
}; };
typedef StringBuilderImpl<TrivialAllocator> StringBuilder;
typedef StringBuilderImpl<StackAllocator> StackStringBuilder;
} // namespace mongo } // namespace mongo
 End of changes. 24 change blocks. 
25 lines changed or deleted 44 lines changed or added


 chunk.h   chunk.h 
skipping to change at line 24 skipping to change at line 24
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "../bson/util/atomic_int.h" #include "../bson/util/atomic_int.h"
#include "../client/dbclient.h"
#include "../client/distlock.h" #include "../client/distlock.h"
#include "shardkey.h" #include "shardkey.h"
#include "shard.h" #include "shard.h"
#include "util.h" #include "util.h"
#include "mongo/util/concurrency/ticketholder.h"
namespace mongo { namespace mongo {
class DBConfig; class DBConfig;
class Chunk; class Chunk;
class ChunkRange; class ChunkRange;
class ChunkManager; class ChunkManager;
class ChunkObjUnitTest; class ChunkObjUnitTest;
typedef shared_ptr<const Chunk> ChunkPtr; typedef shared_ptr<const Chunk> ChunkPtr;
skipping to change at line 237 skipping to change at line 237
const BSONObj& getMax() const { return _max; } const BSONObj& getMax() const { return _max; }
// clones of Chunk methods // clones of Chunk methods
bool contains(const BSONObj& obj) const; bool contains(const BSONObj& obj) const;
ChunkRange(ChunkMap::const_iterator begin, const ChunkMap::const_it erator end) ChunkRange(ChunkMap::const_iterator begin, const ChunkMap::const_it erator end)
: _manager(begin->second->getManager()) : _manager(begin->second->getManager())
, _shard(begin->second->getShard()) , _shard(begin->second->getShard())
, _min(begin->second->getMin()) , _min(begin->second->getMin())
, _max(boost::prior(end)->second->getMax()) { , _max(boost::prior(end)->second->getMax()) {
assert( begin != end ); verify( begin != end );
DEV while (begin != end) { DEV while (begin != end) {
assert(begin->second->getManager() == _manager); verify(begin->second->getManager() == _manager);
assert(begin->second->getShard() == _shard); verify(begin->second->getShard() == _shard);
++begin; ++begin;
} }
} }
// Merge min and max (must be adjacent ranges) // Merge min and max (must be adjacent ranges)
ChunkRange(const ChunkRange& min, const ChunkRange& max) ChunkRange(const ChunkRange& min, const ChunkRange& max)
: _manager(min.getManager()) : _manager(min.getManager())
, _shard(min.getShard()) , _shard(min.getShard())
, _min(min.getMin()) , _min(min.getMin())
, _max(max.getMax()) { , _max(max.getMax()) {
assert(min.getShard() == max.getShard()); verify(min.getShard() == max.getShard());
assert(min.getManager() == max.getManager()); verify(min.getManager() == max.getManager());
assert(min.getMax() == max.getMin()); verify(min.getMax() == max.getMin());
} }
friend ostream& operator<<(ostream& out, const ChunkRange& cr) { friend ostream& operator<<(ostream& out, const ChunkRange& cr) {
return (out << "ChunkRange(min=" << cr._min << ", max=" << cr._ max << ", shard=" << cr._shard <<")"); return (out << "ChunkRange(min=" << cr._min << ", max=" << cr._ max << ", shard=" << cr._shard <<")");
} }
private: private:
const ChunkManager* _manager; const ChunkManager* _manager;
const Shard _shard; const Shard _shard;
const BSONObj _min; const BSONObj _min;
skipping to change at line 315 skipping to change at line 315
void createFirstChunks( const Shard& primary , vector<BSONObj>* ini tPoints , vector<Shard>* initShards ) const; // only call from DBConfig::sh ardCollection void createFirstChunks( const Shard& primary , vector<BSONObj>* ini tPoints , vector<Shard>* initShards ) const; // only call from DBConfig::sh ardCollection
ChunkPtr findChunk( const BSONObj& obj ) const; ChunkPtr findChunk( const BSONObj& obj ) const;
ChunkPtr findChunkOnServer( const Shard& shard ) const; ChunkPtr findChunkOnServer( const Shard& shard ) const;
const ShardKeyPattern& getShardKey() const { return _key; } const ShardKeyPattern& getShardKey() const { return _key; }
bool isUnique() const { return _unique; } bool isUnique() const { return _unique; }
void getShardsForQuery( set<Shard>& shards , const BSONObj& query ) const; void getShardsForQuery( set<Shard>& shards , const BSONObj& query ) const;
void getAllShards( set<Shard>& all ) const; void getAllShards( set<Shard>& all ) const;
void getShardsForRange(set<Shard>& shards, const BSONObj& min, cons /** @param shards set to the shards covered by the interval [min, m
t BSONObj& max, bool fullKeyReq = true) const; // [min, max) ax], see SERVER-4791 */
void getShardsForRange(set<Shard>& shards, const BSONObj& min, cons
t BSONObj& max, bool fullKeyReq = true) const;
ChunkMap getChunkMap() const { return _chunkMap; } ChunkMap getChunkMap() const { return _chunkMap; }
/** /**
* Returns true if, for this shard, the chunks are identical in bot h chunk managers * Returns true if, for this shard, the chunks are identical in bot h chunk managers
*/ */
bool compatibleWith( const ChunkManager& other, const Shard& shard ) const; bool compatibleWith( const ChunkManager& other, const Shard& shard ) const;
bool compatibleWith( ChunkManagerPtr other, const Shard& shard ) co nst { if( ! other ) return false; return compatibleWith( *other, shard ); } bool compatibleWith( ChunkManagerPtr other, const Shard& shard ) co nst { if( ! other ) return false; return compatibleWith( *other, shard ); }
bool compatibleWith( const Chunk& other ) const; bool compatibleWith( const Chunk& other ) const;
skipping to change at line 383 skipping to change at line 384
mutable mutex _mutex; // only used with _nsLock mutable mutex _mutex; // only used with _nsLock
mutable DistributedLock _nsLock; mutable DistributedLock _nsLock;
const unsigned long long _sequenceNumber; const unsigned long long _sequenceNumber;
mutable TicketHolder _splitTickets; // number of concurrent splitVe ctor we can do from a splitIfShould per collection mutable TicketHolder _splitTickets; // number of concurrent splitVe ctor we can do from a splitIfShould per collection
friend class Chunk; friend class Chunk;
friend class ChunkRangeManager; // only needed for CRM::assertValid () friend class ChunkRangeManager; // only needed for CRM::assertValid ()
static AtomicUInt NextSequenceNumber; static AtomicUInt NextSequenceNumber;
/** Just for testing */
friend class TestableChunkManager;
ChunkManager();
}; };
// 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());
} }
 End of changes. 7 change blocks. 
9 lines changed or deleted 15 lines changed or added


 client.h   client.h 
skipping to change at line 37 skipping to change at line 37
#include "../pch.h" #include "../pch.h"
#include "security.h" #include "security.h"
#include "namespace-inl.h" #include "namespace-inl.h"
#include "lasterror.h" #include "lasterror.h"
#include "stats/top.h" #include "stats/top.h"
#include "../db/client_common.h" #include "../db/client_common.h"
#include "../util/concurrency/threadlocal.h" #include "../util/concurrency/threadlocal.h"
#include "../util/net/message_port.h" #include "../util/net/message_port.h"
#include "../util/concurrency/rwlock.h" #include "../util/concurrency/rwlock.h"
#include "d_concurrency.h" #include "d_concurrency.h"
#include "mongo/util/paths.h"
namespace mongo { namespace mongo {
extern class ReplSet *theReplSet; extern class ReplSet *theReplSet;
class AuthenticationInfo; class AuthenticationInfo;
class Database; class Database;
class CurOp; class CurOp;
class Command; class Command;
class Client; class Client;
class AbstractMessagingPort; class AbstractMessagingPort;
class LockCollectionForReading; class LockCollectionForReading;
class PageFaultRetryableSection; class PageFaultRetryableSection;
#if defined(CLC)
typedef LockCollectionForReading _LockCollectionForReading;
#else
typedef readlock _LockCollectionForReading;
#endif
TSP_DECLARE(Client, currentClient) TSP_DECLARE(Client, currentClient)
typedef long long ConnectionId; typedef long long ConnectionId;
/** the database's concept of an outside "client" */ /** the database's concept of an outside "client" */
class Client : public ClientBasic { class Client : public ClientBasic {
static Client *syncThread; static Client *syncThread;
public: public:
LockState _ls;
// always be in clientsMutex when manipulating this. killop stuff u ses these. // always be in clientsMutex when manipulating this. killop stuff u ses these.
static set<Client*> clients; static set<Client*>& clients;
static mongo::mutex clientsMutex; static mongo::mutex& clientsMutex;
static int getActiveClientCount( int& writers , int& readers ); static int getActiveClientCount( int& writers , int& readers );
class Context; class Context;
~Client(); ~Client();
static int recommendedYieldMicros( int * writers = 0 , int * reader s = 0 ); static int recommendedYieldMicros( int * writers = 0 , int * reader s = 0 );
/** each thread which does db operations has a Client object in TLS . /** each thread which does db operations has a Client object in TLS .
* call this when your thread starts. * call this when your thread starts.
*/ */
static Client& initThread(const char *desc, AbstractMessagingPort * mp = 0); static Client& initThread(const char *desc, AbstractMessagingPort * mp = 0);
skipping to change at line 104 skipping to change at line 101
bool isSyncThread() const { return this == syncThread; } bool isSyncThread() const { return this == syncThread; }
string clientAddress(bool includePort=false) const; string clientAddress(bool includePort=false) const;
const AuthenticationInfo * getAuthenticationInfo() const { return & _ai; } const AuthenticationInfo * getAuthenticationInfo() const { return & _ai; }
AuthenticationInfo * getAuthenticationInfo() { return &_ai; } AuthenticationInfo * getAuthenticationInfo() { return &_ai; }
bool isAdmin() { return _ai.isAuthorized( "admin" ); } bool isAdmin() { return _ai.isAuthorized( "admin" ); }
CurOp* curop() const { return _curOp; } CurOp* curop() const { return _curOp; }
Context* getContext() const { return _context; } Context* getContext() const { return _context; }
Database* database() const { return _context ? _context->db() : 0; } Database* database() const { return _context ? _context->db() : 0; }
const char *ns() const { return _context->ns(); } const char *ns() const { return _context->ns(); }
const char *desc() const { return _desc; } const std::string desc() const { return _desc; }
void setLastOp( OpTime op ) { _lastOp = op; } void setLastOp( OpTime op ) { _lastOp = op; }
OpTime getLastOp() const { return _lastOp; } OpTime getLastOp() const { return _lastOp; }
/** caution -- use Context class instead */ /** caution -- use Context class instead */
void setContext(Context *c) { _context = c; } void setContext(Context *c) { _context = c; }
/* report what the last operation was. used by getlasterror */ /* report what the last operation was. used by getlasterror */
void appendLastOp( BSONObjBuilder& b ) const; void appendLastOp( BSONObjBuilder& b ) const;
bool isGod() const { return _god; } /* this is for map/reduce write s */ bool isGod() const { return _god; } /* this is for map/reduce write s */
string toString() const; string toString() const;
void gotHandshake( const BSONObj& o ); void gotHandshake( const BSONObj& o );
bool hasRemote() const { return _mp; } bool hasRemote() const { return _mp; }
HostAndPort getRemote() const { assert( _mp ); return _mp->remote() ; } HostAndPort getRemote() const { verify( _mp ); return _mp->remote() ; }
BSONObj getRemoteID() const { return _remoteId; } BSONObj getRemoteID() const { return _remoteId; }
BSONObj getHandshake() const { return _handshake; } BSONObj getHandshake() const { return _handshake; }
AbstractMessagingPort * port() const { return _mp; } AbstractMessagingPort * port() const { return _mp; }
ConnectionId getConnectionId() const { return _connectionId; } ConnectionId getConnectionId() const { return _connectionId; }
bool inPageFaultRetryableSection() const { return _pageFaultRetryab leSection != 0; } bool inPageFaultRetryableSection() const { return _pageFaultRetryab leSection != 0; }
PageFaultRetryableSection* getPageFaultRetryableSection() const { r eturn _pageFaultRetryableSection; } PageFaultRetryableSection* getPageFaultRetryableSection() const { r eturn _pageFaultRetryableSection; }
bool hasWrittenThisPass() const { return _hasWrittenThisPass; } bool hasWrittenThisPass() const { return _hasWrittenThisPass; }
void writeHappened() { _hasWrittenThisPass = true; } void writeHappened() { _hasWrittenThisPass = true; }
void newTopLevelRequest() { _hasWrittenThisPass = false; }
bool allowedToThrowPageFaultException() const; bool allowedToThrowPageFaultException() const;
private: private:
Client(const char *desc, AbstractMessagingPort *p = 0); Client(const char *desc, AbstractMessagingPort *p = 0);
friend class CurOp; friend class CurOp;
ConnectionId _connectionId; // > 0 for things "conn", 0 otherwise ConnectionId _connectionId; // > 0 for things "conn", 0 otherwise
string _threadId; // "" on non support systems string _threadId; // "" on non support systems
CurOp * _curOp; CurOp * _curOp;
Context * _context; Context * _context;
bool _shutdown; // to track if Client::shutdown() gets called bool _shutdown; // to track if Client::shutdown() gets called
const char * const _desc; const std::string _desc;
bool _god; bool _god;
AuthenticationInfo _ai; AuthenticationInfo _ai;
OpTime _lastOp; OpTime _lastOp;
BSONObj _handshake; BSONObj _handshake;
BSONObj _remoteId; BSONObj _remoteId;
AbstractMessagingPort * const _mp; AbstractMessagingPort * const _mp;
unsigned _sometimes; unsigned _sometimes;
bool _hasWrittenThisPass; bool _hasWrittenThisPass;
PageFaultRetryableSection *_pageFaultRetryableSection; PageFaultRetryableSection *_pageFaultRetryableSection;
skipping to change at line 180 skipping to change at line 178
//static void assureDatabaseIsOpen(const string& ns, string path=db path); //static void assureDatabaseIsOpen(const string& ns, string path=db path);
/** "read lock, and set my context, all in one operation" /** "read lock, and set my context, all in one operation"
* This handles (if not recursively locked) opening an unopened da tabase. * This handles (if not recursively locked) opening an unopened da tabase.
*/ */
class ReadContext : boost::noncopyable { class ReadContext : boost::noncopyable {
public: public:
ReadContext(const string& ns, string path=dbpath, bool doauth=t rue ); ReadContext(const string& ns, string path=dbpath, bool doauth=t rue );
Context& ctx() { return *c.get(); } Context& ctx() { return *c.get(); }
private: private:
scoped_ptr<_LockCollectionForReading> lk; scoped_ptr<Lock::DBRead> lk;
scoped_ptr<Context> c; scoped_ptr<Context> c;
}; };
/* Set database we want to use, then, restores when we finish (are out of scope) /* Set database we want to use, then, restores when we finish (are out of scope)
Note this is also helpful if an exception happens as the state i f fixed up. Note this is also helpful if an exception happens as the state i f fixed up.
*/ */
class Context : boost::noncopyable { class Context : boost::noncopyable {
public: public:
/** this is probably what you want */ /** this is probably what you want */
Context(const string& ns, string path=dbpath, bool doauth=true, bool doVersion=true ); Context(const string& ns, string path=dbpath, bool doauth=true, bool doVersion=true );
skipping to change at line 214 skipping to change at line 212
const char * ns() const { return _ns.c_str(); } const char * ns() const { return _ns.c_str(); }
bool equals( const string& ns , const string& path=dbpath ) con st { return _ns == ns && _path == path; } bool equals( const string& ns , const string& path=dbpath ) con st { return _ns == ns && _path == path; }
/** @return if the db was created by this Context */ /** @return if the db was created by this Context */
bool justCreated() const { return _justCreated; } bool justCreated() const { return _justCreated; }
/** @return true iff the current Context is using db/path */ /** @return true iff the current Context is using db/path */
bool inDB( const string& db , const string& path=dbpath ) const ; bool inDB( const string& db , const string& path=dbpath ) const ;
void _clear() { // this is sort of an "early destruct" indicati on, _ns can never be uncleared void _clear() { // this is sort of an "early destruct" indicati on, _ns can never be uncleared
const_cast<string&>(_ns).empty(); const_cast<string&>(_ns).clear();
_db = 0; _db = 0;
} }
/** call before unlocking, so clear any non-thread safe state /** call before unlocking, so clear any non-thread safe state
* _db gets restored on the relock * _db gets restored on the relock
*/ */
void unlocked() { _db = 0; } void unlocked() { _db = 0; }
/** call after going back into the lock, will re-establish non- thread safe stuff */ /** call after going back into the lock, will re-establish non- thread safe stuff */
void relocked() { _finishInit(); } void relocked() { _finishInit(); }
private: private:
friend class CurOp; friend class CurOp;
void _finishInit( bool doauth=true); void _finishInit( bool doauth=true);
void _auth( int lockState ); void _auth( int lockState );
void checkNotStale() const; void checkNotStale() const;
void checkNsAccess( bool doauth, int lockState = d.dbMutex.getS void checkNsAccess( bool doauth );
tate() ); void checkNsAccess( bool doauth, int lockState );
Client * const _client; Client * const _client;
Context * const _oldContext; Context * const _oldContext;
const string _path; const string _path;
bool _justCreated; bool _justCreated;
bool _doVersion; bool _doVersion;
const string _ns; const string _ns;
Database * _db; Database * _db;
}; // class Client::Context }; // class Client::Context
struct LockStatus { class WriteContext : boost::noncopyable {
LockStatus(); public:
string whichCollection; WriteContext(const string& ns, string path=dbpath, bool doauth=
unsigned excluder, global, collection; true );
string toString() const; Context& ctx() { return _c; }
} lockStatus; private:
Lock::DBWrite _lk;
#if defined(CLC) Context _c;
void checkLocks() const; };
#else
void checkLocks() const { }
#endif
}; // class Client }; // class Client
/** get the Client object for this thread. */ /** get the Client object for this thread. */
inline Client& cc() { inline Client& cc() {
Client * c = currentClient.get(); Client * c = currentClient.get();
assert( c ); verify( c );
return *c; return *c;
} }
inline Client::GodScope::GodScope() { inline Client::GodScope::GodScope() {
_prev = cc()._god; _prev = cc()._god;
cc()._god = true; cc()._god = true;
} }
inline Client::GodScope::~GodScope() { cc()._god = _prev; } inline Client::GodScope::~GodScope() { cc()._god = _prev; }
/* this unreadlocks and then writelocks; i.e. it does NOT upgrade insid
e the
lock (and is thus wrong to use if you need that, which is usually).
that said we use it today for a specific case where the usage is cor
rect.
*/
#if 0
inline void mongolock::releaseAndWriteLock() {
if( !_writelock ) {
#if BOOST_VERSION >= 103500
int s = d.dbMutex.getState();
if( s != -1 ) {
log() << "error: releaseAndWriteLock() s == " << s << endl;
msgasserted( 12600, "releaseAndWriteLock: unlock_shared fai
led, probably recursive" );
}
#endif
_writelock = true;
d.dbMutex.unlock_shared();
d.dbMutex.lock();
// todo: unlocked() method says to call it before unlocking, no
t after. so fix this here,
// or fix the doc there.
if ( cc().getContext() )
cc().getContext()->unlocked();
}
}
#endif
inline bool haveClient() { return currentClient.get() > 0; } inline bool haveClient() { return currentClient.get() > 0; }
}; };
 End of changes. 14 change blocks. 
60 lines changed or deleted 23 lines changed or added


 clientOnly-private.h   clientOnly-private.h 
#pragma once #pragma once
#include "db/mongomutex.h" #include "db/mongomutex.h"
namespace mongo { namespace mongo {
namespace shellUtils { namespace shell_utils {
extern mongo::mutex &mongoProgramOutputMutex; extern mongo::mutex &mongoProgramOutputMutex;
} }
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 clientcursor.h   clientcursor.h 
skipping to change at line 27 skipping to change at line 27
*/ */
/* Cursor -- and its derived classes -- are our internal cursors. /* Cursor -- and its derived classes -- are our internal cursors.
ClientCursor is a wrapper that represents a cursorid from our database ClientCursor is a wrapper that represents a cursorid from our database
application's perspective. application's perspective.
*/ */
#pragma once #pragma once
#include "../pch.h" #include "pch.h"
#include <boost/thread/recursive_mutex.hpp>
#include "cursor.h" #include "cursor.h"
#include "jsobj.h" #include "jsobj.h"
#include "../util/net/message.h" #include "../util/net/message.h"
#include "../util/net/listen.h" #include "../util/net/listen.h"
#include "../util/background.h" #include "../util/background.h"
#include "diskloc.h" #include "diskloc.h"
#include "dbhelpers.h" #include "dbhelpers.h"
#include "matcher.h" #include "matcher.h"
#include "../client/dbclient.h"
#include "projection.h" #include "projection.h"
#include "s/d_chunk_manager.h" #include "s/d_chunk_manager.h"
namespace mongo { namespace mongo {
typedef boost::recursive_mutex::scoped_lock recursive_scoped_lock;
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; class ParsedQuery;
struct ByLocKey { struct ByLocKey {
ByLocKey( const DiskLoc & l , const CursorId& i ) : loc(l), id(i) { } ByLocKey( const DiskLoc & l , const CursorId& i ) : loc(l), id(i) { }
static ByLocKey min( const DiskLoc& l ) { return ByLocKey( l , nume ric_limits<long long>::min() ); } static ByLocKey min( const DiskLoc& l ) { return ByLocKey( l , nume ric_limits<long long>::min() ); }
skipping to change at line 74 skipping to change at line 77
}; };
/* 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.
* ERH: 9/2010 this may not work since some drivers send getMore over a different connection * ERH: 9/2010 this may not work since some drivers send getMore over a different connection
*/ */
typedef map<CursorId, ClientCursor*> CCById; typedef map<CursorId, ClientCursor*> CCById;
typedef map<ByLocKey, ClientCursor*> CCByLoc; typedef map<ByLocKey, ClientCursor*> CCByLoc;
extern BSONObj id_obj; extern BSONObj id_obj;
class ClientCursor { class ClientCursor : private boost::noncopyable {
friend class CmdCursorInfo; friend class CmdCursorInfo;
public: public:
static void assertNoCursors(); static void assertNoCursors();
/* use this to assure we don't in the background time out cursor wh ile it is under use. /* use this to assure we don't in the background time out cursor wh ile it is under use.
if you are using noTimeout() already, there is no risk anyway. if you are using noTimeout() already, there is no risk anyway.
Further, this mechanism guards against two getMore requests on t he same cursor executing Further, this mechanism guards against two getMore requests on t he same cursor executing
at the same time - which might be bad. That should never happen , but if a client driver at the same time - which might be bad. That should never happen , but if a client driver
had a bug, it could (or perhaps some sort of attack situation). had a bug, it could (or perhaps some sort of attack situation).
*/ */
class Pointer : boost::noncopyable { class Pointer : boost::noncopyable {
ClientCursor *_c; ClientCursor *_c;
public: public:
ClientCursor * c() { return _c; } ClientCursor * c() { return _c; }
void release() { void release() {
if( _c ) { if( _c ) {
assert( _c->_pinValue >= 100 ); verify( _c->_pinValue >= 100 );
_c->_pinValue -= 100; _c->_pinValue -= 100;
_c = 0; _c = 0;
} }
} }
/** /**
* call this if during a yield, the cursor got deleted * call this if during a yield, the cursor got deleted
* if so, we don't want to use the point address * if so, we don't want to use the point address
*/ */
void deleted() { void deleted() {
_c = 0; _c = 0;
skipping to change at line 142 skipping to change at line 145
else { else {
_c = 0; _c = 0;
_id = -1; _id = -1;
} }
} }
~CleanupPointer() { ~CleanupPointer() {
DESTRUCTOR_GUARD ( reset(); ); DESTRUCTOR_GUARD ( reset(); );
} }
operator bool() { return _c; } operator bool() { return _c; }
ClientCursor * operator-> () { return _c; } ClientCursor * operator-> () { return _c; }
/** Release ownership of the ClientCursor. */
void release() {
_c = 0;
_id = -1;
}
private: private:
ClientCursor *_c; ClientCursor *_c;
CursorId _id; CursorId _id;
}; };
/** /**
* Iterates through all ClientCursors, under its own ccmutex lock. * Iterates through all ClientCursors, under its own ccmutex lock.
* Also supports deletion on the fly. * Also supports deletion on the fly.
*/ */
class LockedIterator : boost::noncopyable { class LockedIterator : boost::noncopyable {
skipping to change at line 220 skipping to change at line 228
bool yieldSometimes( RecordNeeds need, bool *yielded = 0 ); bool yieldSometimes( RecordNeeds need, bool *yielded = 0 );
static int suggestYieldMicros(); static int suggestYieldMicros();
static void staticYield( int micros , const StringData& ns , Record * rec ); static void staticYield( int micros , const StringData& ns , Record * rec );
struct YieldData { CursorId _id; bool _doingDeletes; }; struct YieldData { CursorId _id; bool _doingDeletes; };
bool prepareToYield( YieldData &data ); bool prepareToYield( YieldData &data );
static bool recoverFromYield( const YieldData &data ); static bool recoverFromYield( const YieldData &data );
struct YieldLock : boost::noncopyable { struct YieldLock : boost::noncopyable {
explicit YieldLock( ptr<ClientCursor> cc )
: _canYield(cc->_c->supportYields()) { explicit YieldLock( ptr<ClientCursor> cc );
if ( _canYield ) {
cc->prepareToYield( _data ); ~YieldLock();
_unlock.reset(new dbtempreleasecond());
} /**
} * @return if the cursor is still ok
~YieldLock() { * if it is, we also relock
if ( _unlock ) { */
log( LL_WARNING ) << "ClientCursor::YieldLock not close bool stillOk();
d properly" << endl;
relock(); void relock();
}
}
bool stillOk() {
if ( ! _canYield )
return true;
relock();
return ClientCursor::recoverFromYield( _data );
}
void relock() {
_unlock.reset();
}
private: private:
const bool _canYield; const bool _canYield;
YieldData _data; YieldData _data;
scoped_ptr<dbtempreleasecond> _unlock; scoped_ptr<dbtempreleasecond> _unlock;
}; };
// --- some pass through helpers for Cursor --- // --- some pass through helpers for Cursor ---
Cursor* c() const { return _c.get(); } Cursor* c() const { return _c.get(); }
int pos() const { return _pos; } int pos() const { return _pos; }
skipping to change at line 290 skipping to change at line 289
BSONElement getFieldDotted( const string& name , BSONObj& holder , bool * fromKey = 0 ) ; BSONElement getFieldDotted( const string& name , BSONObj& holder , bool * fromKey = 0 ) ;
/** extract items from object which match a pattern object. /** extract items from object which match a pattern object.
* e.g., if pattern is { x : 1, y : 1 }, builds an object with * e.g., if pattern is { x : 1, y : 1 }, builds an object with
* x and y elements of this object, if they are present. * x and y elements of this object, if they are present.
* returns elements with original field names * returns elements with original field names
* NOTE: copied from BSONObj::extractFields * NOTE: copied from BSONObj::extractFields
*/ */
BSONObj extractFields(const BSONObj &pattern , bool fillWithNull = false) ; BSONObj extractFields(const BSONObj &pattern , bool fillWithNull = false) ;
void fillQueryResultFromObj( BufBuilder &b ) const;
bool currentIsDup() { return _c->getsetdup( _c->currLoc() ); } bool currentIsDup() { return _c->getsetdup( _c->currLoc() ); }
bool currentMatches() { bool currentMatches() {
if ( ! _c->matcher() ) if ( ! _c->matcher() )
return true; return true;
return _c->matcher()->matchesCurrent( _c.get() ); return _c->matcher()->matchesCurrent( _c.get() );
} }
void setChunkManager( ShardChunkManagerPtr manager ){ _chunkManager = manager; } void setChunkManager( ShardChunkManagerPtr manager ){ _chunkManager = manager; }
ShardChunkManagerPtr getChunkManager(){ return _chunkManager; } ShardChunkManagerPtr getChunkManager(){ return _chunkManager; }
skipping to change at line 313 skipping to change at line 314
static ClientCursor* find_inlock(CursorId id, bool warn = true) { static ClientCursor* find_inlock(CursorId id, bool warn = true) {
CCById::iterator it = clientCursorsById.find(id); CCById::iterator it = clientCursorsById.find(id);
if ( it == clientCursorsById.end() ) { if ( it == clientCursorsById.end() ) {
if ( warn ) if ( warn )
OCCASIONALLY out() << "ClientCursor::find(): cursor not found in map " << id << " (ok after a drop)\n"; OCCASIONALLY out() << "ClientCursor::find(): cursor not found in map " << id << " (ok after a drop)\n";
return 0; return 0;
} }
return it->second; return it->second;
} }
/* call when cursor's location changes so that we can update the
cursorsbylocation map. if you are locked and internally iterating
, only
need to call when you are ready to "unlock".
*/
void updateLocation();
public: public:
static ClientCursor* find(CursorId id, bool warn = true) { static ClientCursor* find(CursorId id, bool warn = true) {
recursive_scoped_lock lock(ccmutex); recursive_scoped_lock lock(ccmutex);
ClientCursor *c = find_inlock(id, warn); ClientCursor *c = find_inlock(id, warn);
// if this asserts, your code was not thread safe - you either need to set no timeout // if this asserts, your code was not thread safe - you either need to set no timeout
// for the cursor or keep a ClientCursor::Pointer in scope for it. // for the cursor or keep a ClientCursor::Pointer in scope for it.
massert( 12521, "internal error: use of an unlocked ClientCurso r", c == 0 || c->_pinValue ); massert( 12521, "internal error: use of an unlocked ClientCurso r", c == 0 || c->_pinValue );
return c; return c;
} }
/** /**
* Deletes the cursor with the provided @param 'id' if one exists. * Deletes the cursor with the provided @param 'id' if one exists.
* @throw if the cursor with the provided id is pinned. * @throw if the cursor with the provided id is pinned.
*/ */
static bool erase(CursorId id) { static bool erase(CursorId id);
recursive_scoped_lock lock(ccmutex);
ClientCursor *cc = find_inlock(id);
if ( cc ) {
assert( cc->_pinValue < 100 ); // you can't still have an a
ctive ClientCursor::Pointer
delete cc;
return true;
}
return false;
}
/** /**
* @return number of cursors found * @return number of cursors found
*/ */
static int erase( int n , long long * ids ); static int erase( int n , long long * ids );
/* call when cursor's location changes so that we can update the
cursorsbylocation map. if you are locked and internally iterati
ng, only
need to call when you are ready to "unlock".
*/
void updateLocation();
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 371 skipping to change at line 364
void storeOpForSlave( DiskLoc last ); void storeOpForSlave( DiskLoc last );
void updateSlaveLocation( CurOp& curop ); void updateSlaveLocation( CurOp& curop );
unsigned idleTime() const { return _idleAgeMillis; } unsigned idleTime() const { return _idleAgeMillis; }
void setDoingDeletes( bool doingDeletes ) {_doingDeletes = doingDel etes; } void setDoingDeletes( bool doingDeletes ) {_doingDeletes = doingDel etes; }
void slaveReadTill( const OpTime& t ) { _slaveReadTill = t; } void slaveReadTill( const OpTime& t ) { _slaveReadTill = t; }
/** Just for testing. */
OpTime getSlaveReadTill() const { return _slaveReadTill; }
public: // static methods public: // static methods
static void idleTimeReport(unsigned millis); static void idleTimeReport(unsigned millis);
static void appendStats( BSONObjBuilder& result ); static void appendStats( BSONObjBuilder& result );
static unsigned numCursors() { return clientCursorsById.size(); } static unsigned numCursors() { return clientCursorsById.size(); }
static void informAboutToDeleteBucket(const DiskLoc& b); static void informAboutToDeleteBucket(const DiskLoc& b);
static void aboutToDelete(const DiskLoc& dl); static void aboutToDelete(const DiskLoc& dl);
static void find( const string& ns , set<CursorId>& all ); static void find( const string& ns , set<CursorId>& all );
skipping to change at line 448 skipping to change at line 444
public: public:
string name() const { return "ClientCursorMonitor"; } string name() const { return "ClientCursorMonitor"; }
void run(); void run();
}; };
} // namespace mongo } // namespace mongo
// ClientCursor should only be used with auto_ptr because it needs to be // ClientCursor should only be used with auto_ptr because it needs to be
// release()ed after a yield if stillOk() returns false and these pointer t ypes // release()ed after a yield if stillOk() returns false and these pointer t ypes
// do not support releasing. This will prevent them from being used acciden tally // do not support releasing. This will prevent them from being used acciden tally
// Instead of auto_ptr<>, which still requires some degree of manual manage
ment
// of this, consider using ClientCursor::CleanupPointer which handles
// ClientCursor's unusual self-deletion mechanics
namespace boost{ namespace boost{
template<> class scoped_ptr<mongo::ClientCursor> {}; template<> class scoped_ptr<mongo::ClientCursor> {};
template<> class shared_ptr<mongo::ClientCursor> {}; template<> class shared_ptr<mongo::ClientCursor> {};
} }
 End of changes. 13 change blocks. 
45 lines changed or deleted 43 lines changed or added


 commands.h   commands.h 
skipping to change at line 40 skipping to change at line 40
/** mongodb "commands" (sent via db.$cmd.findOne(...)) /** mongodb "commands" (sent via db.$cmd.findOne(...))
subclass to make a command. define a singleton object for it. subclass to make a command. define a singleton object for it.
*/ */
class Command { class Command {
protected: protected:
string parseNsFullyQualified(const string& dbname, const BSONObj& c mdObj) const; string parseNsFullyQualified(const string& dbname, const BSONObj& c mdObj) const;
public: public:
// only makes sense for commands where 1st parm is the collection. // only makes sense for commands where 1st parm is the collection.
virtual string parseNs(const string& dbname, const BSONObj& cmdObj) const; virtual string parseNs(const string& dbname, const BSONObj& cmdObj) const;
// warning: isAuthorized uses the lockType() return values, and val
ues are being passed
// around as ints so be careful as it isn't really typesafe and wil
l need cleanup later
enum LockType { READ = -1 , NONE = 0 , WRITE = 1 }; enum LockType { READ = -1 , NONE = 0 , WRITE = 1 };
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 string& db, BSONObj& cmdObj, int options, st ring& errmsg, BSONObjBuilder& result, bool fromRepl = false ) = 0; virtual bool run(const string& db, BSONObj& cmdObj, int options, st ring& errmsg, BSONObjBuilder& result, bool fromRepl = false ) = 0;
/* /*
note: logTheTop() MUST be false if READ note: logTheOp() 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;
/** if true, lock globally instead of just the one database. by def
ault only the one
database will be locked.
*/
virtual bool lockGlobally() const { return false; }
/* 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 {
return false; return false;
} }
void htmlHelp(stringstream&) const; void htmlHelp(stringstream&) const;
/* Like adminOnly, but even stricter: we must either be authenticat ed for admin db, /* Like adminOnly, but even stricter: we must either be authenticat ed for admin db,
or, if running without auth, on the local interface. Used for t hings which or, if running without auth, on the local interface. Used for t hings which
are so major that remote invocation may not make sense (e.g., sh utdownServer). are so major that remote invocation may not make sense (e.g., sh utdownServer).
 End of changes. 3 change blocks. 
1 lines changed or deleted 11 lines changed or added


 config.h   config.h 
skipping to change at line 27 skipping to change at line 27
*/ */
/* This file is things related to the "grid configuration": /* This file is things related to the "grid configuration":
- what machines make up the db component of our cloud - what machines make up the db component of our cloud
- where various ranges of things live - where various ranges of things live
*/ */
#pragma once #pragma once
#include "../db/namespace.h" #include "../db/namespace.h"
#include "../client/dbclient.h"
#include "../client/model.h" #include "../client/model.h"
#include "chunk.h" #include "chunk.h"
#include "shard.h" #include "shard.h"
#include "shardkey.h" #include "shardkey.h"
namespace mongo { namespace mongo {
struct ShardNS { struct ShardNS {
static string shard; static string shard;
skipping to change at line 86 skipping to change at line 85
bool isSharded() const { bool isSharded() const {
return _cm.get(); return _cm.get();
} }
ChunkManagerPtr getCM() const { ChunkManagerPtr getCM() const {
return _cm; return _cm;
} }
void resetCM( ChunkManager * cm ) { void resetCM( ChunkManager * cm ) {
assert(cm); verify(cm);
assert(_cm); // this has to be already sharded verify(_cm); // this has to be already sharded
_cm.reset( cm ); _cm.reset( cm );
} }
void shard( const string& ns , const ShardKeyPattern& key , boo l unique ); void shard( const string& ns , const ShardKeyPattern& key , boo l unique );
void unshard(); void unshard();
bool isDirty() const { return _dirty; } bool isDirty() const { return _dirty; }
bool wasDropped() const { return _dropped; } bool wasDropped() const { return _dropped; }
void save( const string& ns , DBClientBase* conn ); void save( const string& ns , DBClientBase* conn );
skipping to change at line 120 skipping to change at line 119
typedef map<string,CollectionInfo> Collections; typedef map<string,CollectionInfo> Collections;
public: public:
DBConfig( string name ) DBConfig( string name )
: _name( name ) , : _name( name ) ,
_primary("config","") , _primary("config","") ,
_shardingEnabled(false), _shardingEnabled(false),
_lock("DBConfig") , _lock("DBConfig") ,
_hitConfigServerLock( "DBConfig::_hitConfigServerLock" ) { _hitConfigServerLock( "DBConfig::_hitConfigServerLock" ) {
assert( name.size() ); verify( name.size() );
} }
virtual ~DBConfig() {} virtual ~DBConfig() {}
string getName() { return _name; }; string getName() { return _name; };
/** /**
* @return if anything in this db is partitioned or not * @return if anything in this db is partitioned or not
*/ */
bool isShardingEnabled() { bool isShardingEnabled() {
return _shardingEnabled; return _shardingEnabled;
skipping to change at line 146 skipping to change at line 145
/** /**
@return true if there was sharding info to remove @return true if there was sharding info to remove
*/ */
bool removeSharding( const string& ns ); bool removeSharding( const string& ns );
/** /**
* @return whether or not the 'ns' collection is partitioned * @return whether or not the 'ns' collection is partitioned
*/ */
bool isSharded( const string& ns ); bool isSharded( const string& ns );
// Atomically returns *either* the chunk manager *or* the primary s
hard for the collection,
// neither if the collection doesn't exist.
void getChunkManagerOrPrimary( const string& ns, ChunkManagerPtr& m
anager, ShardPtr& primary );
ChunkManagerPtr getChunkManager( const string& ns , bool reload = f alse, bool forceReload = false ); ChunkManagerPtr getChunkManager( const string& ns , bool reload = f alse, bool forceReload = false );
ChunkManagerPtr getChunkManagerIfExists( const string& ns , bool re load = false, bool forceReload = false ); ChunkManagerPtr getChunkManagerIfExists( const string& ns , bool re load = false, bool forceReload = false );
const Shard& getShard( const string& ns ); const Shard& getShard( const string& ns );
/** /**
* @return the correct for shard for the ns * @return the correct for shard for the ns
* if the namespace is sharded, will return NULL * if the namespace is sharded, will return NULL
*/ */
ShardPtr getShardIfExists( const string& ns ); ShardPtr getShardIfExists( const string& ns );
skipping to change at line 177 skipping to change at line 180
// model stuff // model stuff
// lockless loading // lockless loading
void serialize(BSONObjBuilder& to); void serialize(BSONObjBuilder& to);
void unserialize(const BSONObj& from); void unserialize(const BSONObj& from);
void getAllShards(set<Shard>& shards) const; void getAllShards(set<Shard>& shards) const;
void getAllShardedCollections(set<string>& namespaces) const;
protected: protected:
/** /**
lockless lockless
*/ */
bool _isSharded( const string& ns ); bool _isSharded( const string& ns );
bool _dropShardedCollections( int& num, set<Shard>& allServers , st ring& errmsg ); bool _dropShardedCollections( int& num, set<Shard>& allServers , st ring& errmsg );
bool _load(); bool _load();
 End of changes. 5 change blocks. 
4 lines changed or deleted 11 lines changed or added


 connections.h   connections.h 
skipping to change at line 22 skipping to change at line 22
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Lice nse * You should have received a copy of the GNU Affero General Public Lice nse
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <map> #include <map>
#include "../../client/dbclient.h"
#include "../security_common.h" #include "../security_common.h"
namespace mongo { namespace mongo {
/** here we keep a single connection (with reconnect) for a set of host s, /** here we keep a single connection (with reconnect) for a set of host s,
one each, and allow one user at a time per host. if in use already for that one each, and allow one user at a time per host. if in use already for that
host, we block. so this is an easy way to keep a 1-deep pool of co nnections host, we block. so this is an easy way to keep a 1-deep pool of co nnections
that many threads can share. that many threads can share.
thread-safe. thread-safe.
skipping to change at line 51 skipping to change at line 50
scopedconn object for same host). scopedconn object for same host).
*/ */
class ScopedConn { class ScopedConn {
public: public:
/** throws assertions if connect failure etc. */ /** throws assertions if connect failure etc. */
ScopedConn(string hostport); ScopedConn(string hostport);
~ScopedConn() { ~ScopedConn() {
// conLock releases... // conLock releases...
} }
void reconnect() { void reconnect() {
conn().reset(new DBClientConnection(true, 0, 10)); x->cc.reset(new DBClientConnection(true, 0, 10));
x->cc->_logLevel = 2;
x->connected = false; x->connected = false;
connect(); connect();
} }
/* If we were to run a query and not exhaust the cursor, future use of the connection would be problematic. /* If we were to run a query and not exhaust the cursor, future use of the connection would be problematic.
So here what we do is wrapper known safe methods and not allow c ursor-style queries at all. This makes So here what we do is wrapper known safe methods and not allow c ursor-style queries at all. This makes
ScopedConn limited in functionality but very safe. More non-cur sor wrappers can be added here if needed. ScopedConn limited in functionality but very safe. More non-cur sor wrappers can be added here if needed.
*/ */
bool runCommand(const string &dbname, const BSONObj& cmd, BSONObj & info, int options=0) { bool runCommand(const string &dbname, const BSONObj& cmd, BSONObj & info, int options=0) {
return conn()->runCommand(dbname, cmd, info, options); return conn()->runCommand(dbname, cmd, info, options);
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 connpool.h   connpool.h 
skipping to change at line 21 skipping to change at line 21
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include <stack> #include <stack>
#include "dbclient.h"
#include "redef_macros.h"
#include "../util/background.h" #include "mongo/util/background.h"
#include "mongo/client/dbclientinterface.h"
namespace mongo { namespace mongo {
class Shard; class Shard;
class DBConnectionPool; class DBConnectionPool;
/** /**
* not thread safe * not thread safe
* thread safety is handled by DBConnectionPool * thread safety is handled by DBConnectionPool
*/ */
class PoolForHost { class PoolForHost {
public: public:
PoolForHost() PoolForHost()
: _created(0) {} : _created(0) {}
PoolForHost( const PoolForHost& other ) { PoolForHost( const PoolForHost& other ) {
assert(other._pool.size() == 0); verify(other._pool.size() == 0);
_created = other._created; _created = other._created;
assert( _created == 0 ); verify( _created == 0 );
} }
~PoolForHost(); ~PoolForHost();
int numAvailable() const { return (int)_pool.size(); } int numAvailable() const { return (int)_pool.size(); }
void createdOne( DBClientBase * base ); void createdOne( DBClientBase * base );
long long numCreated() const { return _created; } long long numCreated() const { return _created; }
ConnectionString::ConnectionType type() const { assert(_created); r eturn _type; } ConnectionString::ConnectionType type() const { verify(_created); r eturn _type; }
/** /**
* gets a connection or return NULL * gets a connection or return NULL
*/ */
DBClientBase * get( DBConnectionPool * pool , double socketTimeout ); DBClientBase * get( DBConnectionPool * pool , double socketTimeout );
void done( DBConnectionPool * pool , DBClientBase * c ); void done( DBConnectionPool * pool , DBClientBase * c );
void flush(); void flush();
skipping to change at line 290 skipping to change at line 289
void _setSocketTimeout(); void _setSocketTimeout();
const string _host; const string _host;
DBClientBase *_conn; DBClientBase *_conn;
const double _socketTimeout; const double _socketTimeout;
}; };
} // namespace mongo } // namespace mongo
#include "undef_macros.h"
 End of changes. 6 change blocks. 
6 lines changed or deleted 5 lines changed or added


 core.h   core.h 
skipping to change at line 101 skipping to change at line 101
h._copy( (char*)&h._hash , bindata ); h._copy( (char*)&h._hash , bindata );
h._fix(); h._fix();
return h; return h;
} }
explicit GeoHash( const BSONElement& e , unsigned bits=32 ) { explicit GeoHash( const BSONElement& e , unsigned bits=32 ) {
_bits = bits; _bits = bits;
if ( e.type() == BinData ) { if ( e.type() == BinData ) {
int len = 0; int len = 0;
_copy( (char*)&_hash , e.binData( len ) ); _copy( (char*)&_hash , e.binData( len ) );
assert( len == 8 ); verify( len == 8 );
_bits = bits; _bits = bits;
} }
else { else {
cout << "GeoHash bad element: " << e << endl; cout << "GeoHash bad element: " << e << endl;
uassert(13047,"wrong type for geo index. if you're using a pre-release version, need to rebuild index",0); uassert(13047,"wrong type for geo index. if you're using a pre-release version, need to rebuild index",0);
} }
_fix(); _fix();
} }
GeoHash( unsigned x , unsigned y , unsigned bits=32) { GeoHash( unsigned x , unsigned y , unsigned bits=32) {
skipping to change at line 126 skipping to change at line 126
_hash = old._hash; _hash = old._hash;
_bits = old._bits; _bits = old._bits;
} }
GeoHash( long long hash , unsigned bits ) GeoHash( long long hash , unsigned bits )
: _hash( hash ) , _bits( bits ) { : _hash( hash ) , _bits( bits ) {
_fix(); _fix();
} }
void init( unsigned x , unsigned y , unsigned bits ) { void init( unsigned x , unsigned y , unsigned bits ) {
assert( bits <= 32 ); verify( bits <= 32 );
_hash = 0; _hash = 0;
_bits = bits; _bits = bits;
for ( unsigned i=0; i<bits; i++ ) { for ( unsigned i=0; i<bits; i++ ) {
if ( isBitSet( x , i ) ) _hash |= geoBitSets.masks64[i*2]; if ( isBitSet( x , i ) ) _hash |= geoBitSets.masks64[i*2];
if ( isBitSet( y , i ) ) _hash |= geoBitSets.masks64[(i*2)+ 1]; if ( isBitSet( y , i ) ) _hash |= geoBitSets.masks64[(i*2)+ 1];
} }
} }
void unhash_fast( unsigned& x , unsigned& y ) const { void unhash_fast( unsigned& x , unsigned& y ) const {
x = 0; x = 0;
skipping to change at line 175 skipping to change at line 175
*/ */
static bool isBitSet( unsigned val , unsigned bit ) { static bool isBitSet( unsigned val , unsigned bit ) {
return geoBitSets.masks32[bit] & val; return geoBitSets.masks32[bit] & val;
} }
GeoHash up() const { GeoHash up() const {
return GeoHash( _hash , _bits - 1 ); return GeoHash( _hash , _bits - 1 );
} }
bool hasPrefix( const GeoHash& other ) const { bool hasPrefix( const GeoHash& other ) const {
assert( other._bits <= _bits ); verify( other._bits <= _bits );
if ( other._bits == 0 ) if ( other._bits == 0 )
return true; return true;
long long x = other._hash ^ _hash; long long x = other._hash ^ _hash;
x = x >> (64-(other._bits*2)); x = x >> (64-(other._bits*2));
return x == 0; return x == 0;
} }
string toString() const { string toString() const {
StringBuilder buf; StringBuilder buf;
for ( unsigned x=0; x<_bits*2; x++ ) for ( unsigned x=0; x<_bits*2; x++ )
skipping to change at line 205 skipping to change at line 205
void init( const string& s ) { void init( const string& s ) {
_hash = 0; _hash = 0;
_bits = s.size() / 2; _bits = s.size() / 2;
for ( unsigned pos=0; pos<s.size(); pos++ ) for ( unsigned pos=0; pos<s.size(); pos++ )
if ( s[pos] == '1' ) if ( s[pos] == '1' )
setBit( pos , 1 ); setBit( pos , 1 );
} }
void setBit( unsigned pos , bool one ) { void setBit( unsigned pos , bool one ) {
assert( pos < _bits * 2 ); verify( pos < _bits * 2 );
if ( one ) if ( one )
_hash |= geoBitSets.masks64[pos]; _hash |= geoBitSets.masks64[pos];
else if ( _hash & geoBitSets.masks64[pos] ) else if ( _hash & geoBitSets.masks64[pos] )
_hash &= ~geoBitSets.masks64[pos]; _hash &= ~geoBitSets.masks64[pos];
} }
bool getBit( unsigned pos ) const { bool getBit( unsigned pos ) const {
return _hash & geoBitSets.masks64[pos]; return _hash & geoBitSets.masks64[pos];
} }
bool getBitX( unsigned pos ) const { bool getBitX( unsigned pos ) const {
assert( pos < 32 ); verify( pos < 32 );
return getBit( pos * 2 ); return getBit( pos * 2 );
} }
bool getBitY( unsigned pos ) const { bool getBitY( unsigned pos ) const {
assert( pos < 32 ); verify( pos < 32 );
return getBit( ( pos * 2 ) + 1 ); return getBit( ( pos * 2 ) + 1 );
} }
BSONObj wrap( const char* name = "" ) const { BSONObj wrap( const char* name = "" ) const {
BSONObjBuilder b(20); BSONObjBuilder b(20);
append( b , name ); append( b , name );
BSONObj o = b.obj(); BSONObj o = b.obj();
if( ! strlen( name ) ) assert( o.objsize() == 20 ); if( ! strlen( name ) ) verify( o.objsize() == 20 );
return o; return o;
} }
bool constrains() const { bool constrains() const {
return _bits > 0; return _bits > 0;
} }
bool canRefine() const { bool canRefine() const {
return _bits < 32; return _bits < 32;
} }
skipping to change at line 260 skipping to change at line 260
bool atMaxX() const { bool atMaxX() const {
return ( _hash & geoBitSets.allX[ _bits ] ) == geoBitSets.allX[ _bits ]; return ( _hash & geoBitSets.allX[ _bits ] ) == geoBitSets.allX[ _bits ];
} }
bool atMaxY() const { bool atMaxY() const {
return ( _hash & geoBitSets.allY[ _bits ] ) == geoBitSets.allY[ _bits ]; return ( _hash & geoBitSets.allY[ _bits ] ) == geoBitSets.allY[ _bits ];
} }
void move( int x , int y ) { void move( int x , int y ) {
assert( _bits ); verify( _bits );
_move( 0 , x ); _move( 0 , x );
_move( 1 , y ); _move( 1 , y );
} }
void _move( unsigned offset , int d ) { void _move( unsigned offset , int d ) {
if ( d == 0 ) if ( d == 0 )
return; return;
assert( d <= 1 && d>= -1 ); // TEMP verify( d <= 1 && d>= -1 ); // TEMP
bool from, to; bool from, to;
if ( d > 0 ) { if ( d > 0 ) {
from = 0; from = 0;
to = 1; to = 1;
} }
else { else {
from = 1; from = 1;
to = 0; to = 0;
} }
skipping to change at line 301 skipping to change at line 301
for ( ; pos < ( _bits * 2 ) ; pos += 2 ) { for ( ; pos < ( _bits * 2 ) ; pos += 2 ) {
setBit( pos , from ); setBit( pos , from );
} }
return; return;
} }
setBit( pos , from ); setBit( pos , from );
pos -= 2; pos -= 2;
} }
assert(0); verify(0);
} }
GeoHash& operator=(const GeoHash& h) { GeoHash& operator=(const GeoHash& h) {
_hash = h._hash; _hash = h._hash;
_bits = h._bits; _bits = h._bits;
return *this; return *this;
} }
bool operator==(const GeoHash& h ) const { bool operator==(const GeoHash& h ) const {
return _hash == h._hash && _bits == h._bits; return _hash == h._hash && _bits == h._bits;
skipping to change at line 326 skipping to change at line 326
} }
bool operator<(const GeoHash& h ) const { bool operator<(const GeoHash& h ) const {
if( _hash != h._hash ) return _hash < h._hash; if( _hash != h._hash ) return _hash < h._hash;
return _bits < h._bits; return _bits < h._bits;
} }
GeoHash& operator+=( const char * s ) { GeoHash& operator+=( const char * s ) {
unsigned pos = _bits * 2; unsigned pos = _bits * 2;
_bits += strlen(s) / 2; _bits += strlen(s) / 2;
assert( _bits <= 32 ); verify( _bits <= 32 );
while ( s[0] ) { while ( s[0] ) {
if ( s[0] == '1' ) if ( s[0] == '1' )
setBit( pos , 1 ); setBit( pos , 1 );
pos++; pos++;
s++; s++;
} }
return *this; return *this;
} }
skipping to change at line 533 skipping to change at line 533
double sin_x2(sin(p2._x)), cos_x2(cos(p2._x)); double sin_x2(sin(p2._x)), cos_x2(cos(p2._x));
double sin_y2(sin(p2._y)), cos_y2(cos(p2._y)); double sin_y2(sin(p2._y)), cos_y2(cos(p2._y));
double cross_prod = double cross_prod =
(cos_y1*cos_x1 * cos_y2*cos_x2) + (cos_y1*cos_x1 * cos_y2*cos_x2) +
(cos_y1*sin_x1 * cos_y2*sin_x2) + (cos_y1*sin_x1 * cos_y2*sin_x2) +
(sin_y1 * sin_y2); (sin_y1 * sin_y2);
if (cross_prod >= 1 || cross_prod <= -1) { if (cross_prod >= 1 || cross_prod <= -1) {
// fun with floats // fun with floats
assert( fabs(cross_prod)-1 < 1e-6 ); verify( fabs(cross_prod)-1 < 1e-6 );
return cross_prod > 0 ? 0 : M_PI; return cross_prod > 0 ? 0 : M_PI;
} }
return acos(cross_prod); return acos(cross_prod);
} }
// note: return is still in radians as that can be multiplied by radius to get arc length // note: return is still in radians as that can be multiplied by radius to get arc length
inline double spheredist_deg( const Point& p1, const Point& p2 ) { inline double spheredist_deg( const Point& p1, const Point& p2 ) {
return spheredist_rad( return spheredist_rad(
Point( deg2rad(p1._x), deg2rad(p1._y) ), Point( deg2rad(p1._x), deg2rad(p1._y) ),
 End of changes. 12 change blocks. 
12 lines changed or deleted 12 lines changed or added


 counters.h   counters.h 
skipping to change at line 36 skipping to change at line 36
namespace mongo { namespace mongo {
/** /**
* 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();
void incInsertInWriteLock(int n) { _insert.x += n; }
AtomicUInt * getInsert() { return _insert; } void gotInsert() { _insert++; }
AtomicUInt * getQuery() { return _query; } void gotQuery() { _query++; }
AtomicUInt * getUpdate() { return _update; } void gotUpdate() { _update++; }
AtomicUInt * getDelete() { return _delete; } void gotDelete() { _delete++; }
AtomicUInt * getGetMore() { return _getmore; } void gotGetMore() { _getmore++; }
AtomicUInt * getCommand() { return _command; } void gotCommand() { _command++; }
void incInsertInWriteLock(int n) { _insert->x += n; }
void gotInsert() { _insert[0]++; }
void gotQuery() { _query[0]++; }
void gotUpdate() { _update[0]++; }
void gotDelete() { _delete[0]++; }
void gotGetMore() { _getmore[0]++; }
void gotCommand() { _command[0]++; }
void gotOp( int op , bool isCommand ); void gotOp( int op , bool isCommand );
BSONObj& getObj(); BSONObj getObj();
private: private:
BSONObj _obj;
// todo: there will be a lot of cache line contention on these. ne ed to do something // todo: there will be a lot of cache line contention on these. ne ed to do something
// else eventually. // else eventually.
AtomicUInt * _insert; AtomicUInt _insert;
AtomicUInt * _query; AtomicUInt _query;
AtomicUInt * _update; AtomicUInt _update;
AtomicUInt * _delete; AtomicUInt _delete;
AtomicUInt * _getmore; AtomicUInt _getmore;
AtomicUInt * _command; AtomicUInt _command;
}; };
extern OpCounters globalOpCounters; extern OpCounters globalOpCounters;
extern OpCounters replOpCounters; extern OpCounters replOpCounters;
class IndexCounters { class IndexCounters {
public: public:
IndexCounters(); IndexCounters();
// used without a mutex intentionally (can race) // used without a mutex intentionally (can race)
 End of changes. 4 change blocks. 
23 lines changed or deleted 14 lines changed or added


 curop.h   curop.h 
skipping to change at line 27 skipping to change at line 27
*/ */
#pragma once #pragma once
#include "namespace-inl.h" #include "namespace-inl.h"
#include "client.h" #include "client.h"
#include "../bson/util/atomic_int.h" #include "../bson/util/atomic_int.h"
#include "../util/concurrency/spin_lock.h" #include "../util/concurrency/spin_lock.h"
#include "../util/time_support.h" #include "../util/time_support.h"
#include "../util/net/hostandport.h" #include "../util/net/hostandport.h"
#include "../util/progress_meter.h"
namespace mongo { namespace mongo {
class CurOp; class CurOp;
/* lifespan is different than CurOp because of recursives with DBDirect Client */ /* lifespan is different than CurOp because of recursives with DBDirect Client */
class OpDebug { class OpDebug {
public: public:
OpDebug() : ns(""){ reset(); } OpDebug() : ns(""){ reset(); }
skipping to change at line 60 skipping to change at line 61
BSONObj query; BSONObj query;
BSONObj updateobj; BSONObj updateobj;
// detailed options // detailed options
long long cursorid; long long cursorid;
int ntoreturn; int ntoreturn;
int ntoskip; int ntoskip;
bool exhaust; bool exhaust;
// debugging/profile info // debugging/profile info
int nscanned; long long nscanned;
bool idhack; // indicates short circuited code path on an u pdate to make the update faster bool idhack; // indicates short circuited code path on an u pdate to make the update faster
bool scanAndOrder; // scanandorder query plan aspect was used bool scanAndOrder; // scanandorder query plan aspect was used
bool moved; // update resulted in a move (moves are expens long long nupdated; // number of records updated
ive) long long nmoved; // updates resulted in a move (moves are expen
sive)
bool fastmod; bool fastmod;
bool fastmodinsert; // upsert of an $operation. builds a default o bject bool fastmodinsert; // upsert of an $operation. builds a default o bject
bool upsert; // true if the update actually did an insert bool upsert; // true if the update actually did an insert
int keyUpdates; int keyUpdates;
// error handling // error handling
ExceptionInfo exceptionInfo; ExceptionInfo exceptionInfo;
// response info // response info
int executionTime; int executionTime;
skipping to change at line 165 skipping to change at line 167
void ensureStarted() { void ensureStarted() {
if ( _start == 0 ) if ( _start == 0 )
_start = _checkpoint = curTimeMicros64(); _start = _checkpoint = curTimeMicros64();
} }
bool isStarted() const { return _start > 0; } bool isStarted() const { return _start > 0; }
void enter( Client::Context * context ); void enter( Client::Context * context );
void leave( Client::Context * context ); void leave( Client::Context * context );
void reset(); void reset();
void reset( const HostAndPort& remote, int op ); void reset( const HostAndPort& remote, int op );
void markCommand() { _command = true; } void markCommand() { _command = true; }
void waitingForLock( char type ) {
void waitingForLock( int type ) {
_waitingForLock = true; _waitingForLock = true;
if ( type > 0 ) _lockType = type;
_lockType = 1;
else
_lockType = -1;
} }
void gotLock() { _waitingForLock = false; } void gotLock() { _waitingForLock = false; }
OpDebug& debug() { return _debug; } OpDebug& debug() { return _debug; }
int profileLevel() const { return _dbprofile; } int profileLevel() const { return _dbprofile; }
const char * getNS() const { return _ns; } const char * getNS() const { return _ns; }
bool shouldDBProfile( int ms ) const { bool shouldDBProfile( int ms ) const {
if ( _dbprofile <= 0 ) if ( _dbprofile <= 0 )
return false; return false;
return _dbprofile >= 2 || ms >= cmdLine.slowMS; return _dbprofile >= 2 || ms >= cmdLine.slowMS;
} }
AtomicUInt opNum() const { return _opNum; } AtomicUInt opNum() const { return _opNum; }
/** if this op is running */ /** if this op is running */
bool active() const { return _active; } bool active() const { return _active; }
int getLockType() const { return _lockType; } char lockType() const { return _lockType; }
bool displayInCurop() const { return _active && ! _suppressFromCuro
p; }
bool isWaitingForLock() const { return _waitingForLock; } bool isWaitingForLock() const { return _waitingForLock; }
int getOp() const { return _op; } int getOp() const { return _op; }
unsigned long long startTime() { // micros unsigned long long startTime() { // micros
ensureStarted(); ensureStarted();
return _start; return _start;
} }
void done() { void done() {
_active = false; _active = false;
_end = curTimeMicros64(); _end = curTimeMicros64();
} }
skipping to change at line 228 skipping to change at line 227
ProgressMeter& getProgressMeter() { return _progressMeter; } ProgressMeter& getProgressMeter() { return _progressMeter; }
CurOp *parent() const { return _wrapped; } CurOp *parent() const { return _wrapped; }
void kill() { _killed = true; } void kill() { _killed = true; }
bool killed() const { return _killed; } bool killed() const { return _killed; }
void yielded() { _numYields++; } void yielded() { _numYields++; }
void setNS(const char *ns) { void setNS(const char *ns) {
strncpy(_ns, ns, Namespace::MaxNsLen); strncpy(_ns, ns, Namespace::MaxNsLen);
_ns[Namespace::MaxNsLen] = 0; _ns[Namespace::MaxNsLen] = 0;
} }
void suppressFromCurop() { _suppressFromCurop = true; }
long long getExpectedLatencyMs() const { return _expectedLatencyMs;
}
void setExpectedLatencyMs( long long latency ) { _expectedLatencyMs
= latency; }
private: private:
friend class Client; friend class Client;
void _reset(); void _reset();
static AtomicUInt _nextOpNum; static AtomicUInt _nextOpNum;
Client * _client; Client * _client;
CurOp * _wrapped; CurOp * _wrapped;
unsigned long long _start; unsigned long long _start;
unsigned long long _checkpoint; unsigned long long _checkpoint;
unsigned long long _end; unsigned long long _end;
bool _active; bool _active;
bool _suppressFromCurop; // unless $all is set
int _op; int _op;
bool _command; bool _command;
int _lockType; // see concurrency.h for values char _lockType; // r w R W
bool _waitingForLock; bool _waitingForLock;
int _dbprofile; // 0=off, 1=slow, 2=all int _dbprofile; // 0=off, 1=slow, 2=all
AtomicUInt _opNum; // todo: simple being "unsigned" m ay make more sense here AtomicUInt _opNum; // todo: simple being "unsigned" m ay make more sense here
char _ns[Namespace::MaxNsLen+2]; char _ns[Namespace::MaxNsLen+2];
HostAndPort _remote; // CAREFUL here with thread safety HostAndPort _remote; // CAREFUL here with thread safety
CachedBSONObj _query; // CachedBSONObj is thread safe CachedBSONObj _query; // CachedBSONObj is thread safe
OpDebug _debug; OpDebug _debug;
ThreadSafeString _message; ThreadSafeString _message;
ProgressMeter _progressMeter; ProgressMeter _progressMeter;
volatile bool _killed; volatile bool _killed;
int _numYields; int _numYields;
// this is how much "extra" time a query might take
// a writebacklisten for example will block for 30s
// so this should be 30000 in that case
long long _expectedLatencyMs;
}; };
/* _globalKill: we are shutting down /* _globalKill: we are shutting down
otherwise kill attribute set on specified CurOp otherwise kill attribute set on specified CurOp
this class does not handle races between interruptJs and the checkFo rInterrupt functions - those must be this class does not handle races between interruptJs and the checkFo rInterrupt functions - those must be
handled by the client of this class handled by the client of this class
*/ */
extern class KillCurrentOp { extern class KillCurrentOp {
public: public:
void killAll(); void killAll();
void kill(AtomicUInt i); void kill(AtomicUInt i);
/** @return true if global interrupt and should terminate the opera tion */ /** @return true if global interrupt and should terminate the opera tion */
bool globalInterruptCheck() const { return _globalKill; } bool globalInterruptCheck() const { return _globalKill; }
void checkForInterrupt( bool heedMutex = true ) { /**
Client& c = cc(); * @param heedMutex if true and have a write lock, won't kill op si
if ( heedMutex && d.dbMutex.isWriteLocked() ) nce it might be unsafe
return; */
if( _globalKill ) void checkForInterrupt( bool heedMutex = true );
uasserted(11600,"interrupted at shutdown");
if( c.curop()->killed() )
uasserted(11601,"interrupted");
if( c.sometimes(1024) ) {
AbstractMessagingPort *p = cc().port();
if( p )
p->assertStillConnected();
}
}
/** @return "" if not interrupted. otherwise, you should stop. */ /** @return "" if not interrupted. otherwise, you should stop. */
const char *checkForInterruptNoAssert( /*bool heedMutex = true*/ ) const char *checkForInterruptNoAssert();
{
Client& c = cc();
// always called withi false so commented out:
/*if ( heedMutex && d.dbMutex.isWriteLocked() )
return "";*/
if( _globalKill )
return "interrupted at shutdown";
if( c.curop()->killed() )
return "interrupted";
if( c.sometimes(1024) ) {
try {
AbstractMessagingPort *p = cc().port();
if( p )
p->assertStillConnected();
}
catch(...) {
log() << "no longer connected to client";
return "no longer connected to client";
}
}
return "";
}
private: private:
void interruptJs( AtomicUInt *op ); void interruptJs( AtomicUInt *op );
volatile bool _globalKill; volatile bool _globalKill;
} killCurrentOp; } killCurrentOp;
} }
 End of changes. 12 change blocks. 
48 lines changed or deleted 31 lines changed or added


 cursor.h   cursor.h 
skipping to change at line 24 skipping to change at line 24
* 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" #include "matcher.h"
#include "mongo/db/projection.h"
namespace mongo { namespace mongo {
class NamespaceDetails; class NamespaceDetails;
class Record; class Record;
class CoveredIndexMatcher; 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
concept and is for the user's cursor. ntCursor" is a separate
* 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
ClientCursor::ccmutex. Don't cause a deadlock, you've been warned. n a
*/ * ClientCursor::ccmutex. Don't cause a deadlock, you've been warned.
*
* Two general techniques may be used to ensure a Cursor is in a consis
tent state after a write.
* - The Cursor may be advanced before the document at its current
position is deleted.
* - The Cursor may record its position and then relocate this posi
tion.
* A particular Cursor may potentially utilize only one of the above te
chniques, but a client
* that is Cursor subclass agnostic must implement a pattern handling b
oth techniques.
*
* When the document at a Cursor's current position is deleted (or move
d to a new location) the
* following pattern is used:
* DiskLoc toDelete = cursor->currLoc();
* cursor->advance();
* cursor->prepareToTouchEarlierIterate();
* delete( toDelete );
* cursor->recoverFromTouchingEarlierIterate();
*
* When a cursor yields, the following pattern is used:
* cursor->prepareToYield();
* while( Op theOp = nextOp() ) {
* if ( theOp.type() == INSERT || theOp.type() == UPDATE_IN_PLA
CE ) {
* theOp.run();
* }
* else if ( theOp.type() == DELETE ) {
* if ( cursor->refLoc() == theOp.toDelete() ) {
* cursor->recoverFromYield();
* cursor->advance();
* cursor->prepareToYield();
* }
* theOp.run();
* }
* }
* cursor->recoverFromYield();
*
* The break before a getMore request is typically treated as a yield,
but if a Cursor supports
* getMore but not yield the following pattern is currently used:
* cursor->noteLocation();
* runOtherOps();
* cursor->checkLocation();
*
* A Cursor may rely on additional callbacks not listed above to reloca
te its position after a
* write.
*/
class Cursor : boost::noncopyable { class Cursor : boost::noncopyable {
public: public:
virtual ~Cursor() {} virtual ~Cursor() {}
virtual bool ok() = 0; virtual bool ok() = 0;
bool eof() { return !ok(); } bool eof() { 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(); }
skipping to change at line 95 skipping to change at line 137
* modified. It is ok if the current iterate also points to the do cument to be modified. * modified. It is ok if the current iterate also points to the do cument to be modified.
*/ */
virtual void prepareToTouchEarlierIterate() { noteLocation(); } virtual void prepareToTouchEarlierIterate() { noteLocation(); }
/** Recover from a previous call to prepareToTouchEarlierIterate(). */ /** Recover from a previous call to prepareToTouchEarlierIterate(). */
virtual void recoverFromTouchingEarlierIterate() { checkLocation(); } virtual void recoverFromTouchingEarlierIterate() { checkLocation(); }
virtual bool supportYields() = 0; virtual bool supportYields() = 0;
/** Called before a ClientCursor yield. */ /** Called before a ClientCursor yield. */
virtual bool prepareToYield() { noteLocation(); return supportYield s(); } virtual void prepareToYield() { noteLocation(); }
/** Called after a ClientCursor yield. Recovers from a previous ca ll to prepareToYield(). */ /** Called after a ClientCursor yield. Recovers from a previous ca ll to prepareToYield(). */
virtual void recoverFromYield() { checkLocation(); } virtual void recoverFromYield() { checkLocation(); }
virtual string toString() { return "abstract?"; } virtual string toString() { return "abstract?"; }
/* used for multikey index traversal to avoid sending back dups. se e Matcher::matches(). /* used for multikey index traversal to avoid sending back dups. se e Matcher::matches().
if a multikey index traversal: if a multikey index traversal:
if loc has already been sent, returns true. if loc has already been sent, returns true.
otherwise, marks loc as sent. otherwise, marks loc as sent.
skipping to change at line 149 skipping to change at line 191
// Used when we want fast matcher lookup // Used when we want fast matcher lookup
virtual CoveredIndexMatcher *matcher() const { return 0; } virtual CoveredIndexMatcher *matcher() const { return 0; }
// Used when we need to share this matcher with someone else // Used when we need to share this matcher with someone else
virtual shared_ptr< CoveredIndexMatcher > matcherPtr() const { retu rn shared_ptr< CoveredIndexMatcher >(); } virtual shared_ptr< CoveredIndexMatcher > matcherPtr() const { retu rn shared_ptr< CoveredIndexMatcher >(); }
virtual bool currentMatches( MatchDetails *details = 0 ) { virtual bool currentMatches( MatchDetails *details = 0 ) {
return !matcher() || matcher()->matchesCurrent( this, details ) ; return !matcher() || matcher()->matchesCurrent( this, details ) ;
} }
// A convenience function for setting the value of matcher() manual ly // A convenience function for setting the value of matcher() manual ly
// so it may accessed later. Implementations which must generate // so it may be accessed later. Implementations which must generat e
// their own matcher() should assert here. // their own matcher() should assert here.
virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) { virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) {
massert( 13285, "manual matcher config not allowed", false ); massert( 13285, "manual matcher config not allowed", false );
} }
/** @return the covered index projector for the current iterate, if
any. */
virtual const Projection::KeyOnly *keyFieldsOnly() const { return 0
; }
/**
* Manually set the value of keyFieldsOnly() so it may be accessed
later. Implementations
* that generate their own keyFieldsOnly() must assert.
*/
virtual void setKeyFieldsOnly( const shared_ptr<Projection::KeyOnly
> &keyFieldsOnly ) {
massert( 16159, "manual keyFieldsOnly config not allowed", fals
e );
}
virtual void explainDetails( BSONObjBuilder& b ) { return; } virtual void explainDetails( BSONObjBuilder& b ) { return; }
}; };
// 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
*
* A BasicCursor relies on advance() to ensure it is in a consistent st
ate after a write. If
* the document at a BasicCursor's current position will be deleted or
relocated, the cursor
* must first be advanced. The same is true of BasicCursor subclasses.
*/
class BasicCursor : public Cursor { class BasicCursor : public Cursor {
public: public:
BasicCursor(DiskLoc dl, const AdvanceStrategy *_s = forward()) : cu rr(dl), s( _s ), _nscanned() { BasicCursor(DiskLoc dl, const AdvanceStrategy *_s = forward()) : cu rr(dl), s( _s ), _nscanned() {
incNscanned(); incNscanned();
init(); init();
} }
BasicCursor(const AdvanceStrategy *_s = forward()) : s( _s ), _nsca nned() { BasicCursor(const AdvanceStrategy *_s = forward()) : s( _s ), _nsca nned() {
init(); init();
} }
bool ok() { return !curr.isNull(); } bool ok() { return !curr.isNull(); }
Record* _current() { Record* _current() {
assert( ok() ); verify( ok() );
return curr.rec(); return curr.rec();
} }
BSONObj current() { BSONObj current() {
Record *r = _current(); Record *r = _current();
BSONObj j(r); BSONObj j(r);
return j; return j;
} }
virtual DiskLoc currLoc() { return curr; } virtual DiskLoc currLoc() { return curr; }
virtual DiskLoc refLoc() { return curr.isNull() ? last : curr; } virtual DiskLoc refLoc() { return curr.isNull() ? last : curr; }
bool advance(); bool advance();
skipping to change at line 205 skipping to change at line 264
} }
virtual bool tailable() { return tailable_; } virtual bool tailable() { return tailable_; }
virtual bool getsetdup(DiskLoc loc) { return false; } virtual bool getsetdup(DiskLoc loc) { return false; }
virtual bool isMultiKey() const { return false; } virtual bool isMultiKey() const { return false; }
virtual bool modifiedKeys() const { return false; } virtual bool modifiedKeys() const { return false; }
virtual bool supportGetMore() { return true; } virtual bool supportGetMore() { return true; }
virtual bool supportYields() { return true; } virtual bool supportYields() { return true; }
virtual CoveredIndexMatcher *matcher() const { return _matcher.get( ); } virtual CoveredIndexMatcher *matcher() const { return _matcher.get( ); }
virtual shared_ptr< CoveredIndexMatcher > matcherPtr() const { retu rn _matcher; } virtual shared_ptr< CoveredIndexMatcher > matcherPtr() const { retu rn _matcher; }
virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) { _matcher = matcher; } virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher ) { _matcher = matcher; }
virtual const Projection::KeyOnly *keyFieldsOnly() const { return _
keyFieldsOnly.get(); }
virtual void setKeyFieldsOnly( const shared_ptr<Projection::KeyOnly
> &keyFieldsOnly ) {
_keyFieldsOnly = keyFieldsOnly;
}
virtual long long nscanned() { return _nscanned; } virtual long long nscanned() { return _nscanned; }
protected: protected:
DiskLoc curr, last; DiskLoc curr, last;
const AdvanceStrategy *s; const AdvanceStrategy *s;
void incNscanned() { if ( !curr.isNull() ) { ++_nscanned; } } void incNscanned() { if ( !curr.isNull() ) { ++_nscanned; } }
private: private:
bool tailable_; bool tailable_;
shared_ptr< CoveredIndexMatcher > _matcher; shared_ptr< CoveredIndexMatcher > _matcher;
shared_ptr<Projection::KeyOnly> _keyFieldsOnly;
long long _nscanned; long long _nscanned;
void init() { tailable_ = false; } void init() { tailable_ = false; }
}; };
/* 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() { return "ReverseCursor"; } virtual string toString() { return "ReverseCursor"; }
 End of changes. 9 change blocks. 
12 lines changed or deleted 94 lines changed or added


 cursors.h   cursors.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 Lice nse * You should have received a copy of the GNU Affero General Public Lice nse
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "../db/jsobj.h" #include "../db/jsobj.h"
#include "../db/dbmessage.h" #include "../db/dbmessage.h"
#include "../client/dbclient.h"
#include "../client/parallel.h" #include "../client/parallel.h"
#include "request.h" #include "request.h"
namespace mongo { namespace mongo {
class ShardedClientCursor : boost::noncopyable { class ShardedClientCursor : boost::noncopyable {
public: public:
ShardedClientCursor( QueryMessage& q , ClusteredCursor * cursor ); ShardedClientCursor( QueryMessage& q , ClusteredCursor * cursor );
virtual ~ShardedClientCursor(); virtual ~ShardedClientCursor();
long long getId(); long long getId();
/** /**
* @return the cumulative number of documents seen by this cursor.
*/
int getTotalSent() const;
/**
* Sends queries to the shards, gather the result for this batch an
d sends the response
* to the socket.
*
* @return whether there is more data left * @return whether there is more data left
*/ */
bool sendNextBatch( Request& r ) { return sendNextBatch( r , _ntore bool sendNextBatchAndReply( Request& r );
turn ); }
bool sendNextBatch( Request& r , int ntoreturn ); /**
* Sends queries to the shards and gather the result for this batch
.
*
* @param r The request object from the client
* @param ntoreturn Number of documents to return
* @param buffer The buffer to use to store the results.
* @param docCount This will contain the number of documents gather
ed for this batch after
* a successful call.
*
* @return true if this is not the final batch.
*/
bool sendNextBatch( Request& r, int ntoreturn, BufBuilder& buffer,
int& docCount );
void accessed(); void accessed();
/** @return idle time in ms */ /** @return idle time in ms */
long long idleTime( long long now ); long long idleTime( long long now );
// The default initial buffer size for sending responses.
static const int INIT_REPLY_BUFFER_SIZE;
protected: protected:
ClusteredCursor * _cursor; ClusteredCursor * _cursor;
int _skip; int _skip;
int _ntoreturn; int _ntoreturn;
int _totalSent; int _totalSent;
bool _done; bool _done;
 End of changes. 4 change blocks. 
4 lines changed or deleted 29 lines changed or added


 d_chunk_manager.h   d_chunk_manager.h 
skipping to change at line 29 skipping to change at line 29
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "../db/jsobj.h" #include "../db/jsobj.h"
#include "util.h" #include "util.h"
namespace mongo { namespace mongo {
class ClientCursor; class ClientCursor;
class DBClientCursorInterface;
/** /**
* Controls the boundaries of all the chunks for a given collection tha t live in this shard. * Controls the boundaries of all the chunks for a given collection tha t live in this shard.
* *
* ShardChunkManager instances never change after construction. There a re methods provided that would generate a * ShardChunkManager instances never change after construction. There a re methods provided that would generate a
* new manager if new chunks are added, subtracted, or split. * new manager if new chunks are added, subtracted, or split.
* *
* TODO * TODO
* The responsibility of maintaining the version for a shard is still shared between this class and its caller. The * The responsibility of maintaining the version for a shard is still shared between this class and its caller. The
* manager does check corner cases (e.g. cloning out the last chunk g enerates a manager with version 0) but ultimately * manager does check corner cases (e.g. cloning out the last chunk g enerates a manager with version 0) but ultimately
* still cannot be responsible to set all versions. Currently, they a re a function of the global state as opposed to * still cannot be responsible to set all versions. Currently, they a re a function of the global state as opposed to
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 d_concurrency.h   d_concurrency.h 
// @file d_concurrency.h // @file d_concurrency.h
// only used by mongod, thus the name ('d')
// (also used by dbtests test binary, which is running mongod test code)
#pragma once #pragma once
#include "../util/concurrency/rwlock.h" #include "mongo/util/concurrency/qlock.h"
#include "db/mongomutex.h" #include "mongo/util/concurrency/mutex.h"
#include "mongo/bson/stringdata.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/lockstat.h"
namespace mongo { namespace mongo {
namespace clcimpl { class WrapperForRWLock;
enum LockStates { Unlocked, AcquireShared=1, LockedShared=2, Acquir class LockState;
eExclusive=4, LockedExclusive=8 };
class Shared : boost::noncopyable { class Lock : boost::noncopyable {
unsigned& state; public:
RWLock *rw; enum Nestable { notnestable=0, local, admin };
public: static int isLocked(); // true if *anything* is locked (by us)
Shared(unsigned& state, RWLock& lock); static int isReadLocked(); // r or R
~Shared(); static int somethingWriteLocked(); // w or W
bool recursed() const { return rw == 0; } static bool isW(); // W
}; static bool isR();
class Exclusive : boost::noncopyable { static bool isRW(); // R or W. i.e., we are write-exclusive
unsigned& state; static bool nested();
RWLock *rw; static bool isWriteLocked(const StringData& ns);
public: static bool atLeastReadLocked(const StringData& ns); // true if thi
Exclusive(unsigned& state, RWLock& lock); s db is locked
~Exclusive(); static void assertAtLeastReadLocked(const StringData& ns);
}; static void assertWriteLocked(const StringData& ns);
}
static bool dbLevelLockingEnabled();
typedef readlock GlobalSharedLock;
class ScopedLock;
class ExcludeAllWrites : boost::noncopyable {
clcimpl::Exclusive lk; // note: avoid TempRelease when possible. not a good thing.
GlobalSharedLock gslk; struct TempRelease {
TempRelease();
~TempRelease();
const bool cant; // true if couldn't because of recursive locki
ng
ScopedLock *scopedLk;
};
class ScopedLock : boost::noncopyable {
protected:
friend struct TempRelease;
ScopedLock();
virtual void tempRelease() = 0;
virtual void relock() = 0;
public:
virtual ~ScopedLock();
};
// note that for these classes recursive locking is ok if the recur
sive locking "makes sense"
// i.e. you could grab globalread after globalwrite.
class GlobalWrite : public ScopedLock {
bool stoppedGreed;
bool noop;
protected:
void tempRelease();
void relock();
public:
/** @param stopGreed after acquisition stop greediness of other
threads for write locks. this
should generally not be used it is for exceptional circumst
ances. journaling uses it.
perhaps this should go away it makes the software more comp
licated.
*/
// timeoutms is only for writelocktry -- deprecated -- do not u
se
GlobalWrite(bool stopGreed = false, int timeoutms = -1 );
virtual ~GlobalWrite();
void downgrade(); // W -> R
bool upgrade(); // caution see notes
};
class GlobalRead : public ScopedLock { // recursive is ok
public:
bool noop;
protected:
void tempRelease();
void relock();
public:
// timeoutms is only for readlocktry -- deprecated -- do not us
e
GlobalRead( int timeoutms = -1 );
virtual ~GlobalRead();
};
// lock this database. do not shared_lock globally first, that is h
andledin herein.
class DBWrite : public ScopedLock {
bool isW(LockState&) const;
void lockTop(LockState&);
void lockNestable(Nestable db);
void lockOther(const string& db);
bool locked_w;
bool locked_W;
WrapperForRWLock *weLocked;
const string what;
bool _nested;
void lockDB(const string& ns);
void unlockDB();
protected:
void tempRelease();
void relock();
public:
DBWrite(const StringData& dbOrNs);
virtual ~DBWrite();
};
// lock this database for reading. do not shared_lock globally firs
t, that is handledin herein.
class DBRead : public ScopedLock {
bool isRW(LockState&) const;
void lockTop(LockState&);
void lockNestable(Nestable db);
void lockOther(const string& db);
bool locked_r;
WrapperForRWLock *weLocked;
string what;
bool _nested;
void lockDB(const string& ns);
void unlockDB();
protected:
void tempRelease();
void relock();
public:
DBRead(const StringData& dbOrNs);
virtual ~DBRead();
};
};
class readlocktry : boost::noncopyable {
bool _got;
scoped_ptr<Lock::GlobalRead> _dbrlock;
public: public:
ExcludeAllWrites(); readlocktry( int tryms );
~ExcludeAllWrites(); ~readlocktry();
bool got() const { return _got; }
}; };
class todoGlobalWriteLock : boost::noncopyable { class writelocktry : boost::noncopyable {
bool _got;
scoped_ptr<Lock::GlobalWrite> _dbwlock;
public: public:
writelocktry( int tryms );
~writelocktry();
bool got() const { return _got; }
}; };
class LockCollectionForReading : boost::noncopyable { /** a mutex, but reported in curop() - thus a "high level" (HL) one
GlobalSharedLock gslk; some overhead so we don't use this for everything. the externalobj
clcimpl::Shared clk; sort mutex
uses this, as it can be held for eons. implementation still needed.
*/
class HLMutex : public SimpleMutex {
LockStat ls;
public: public:
LockCollectionForReading(string coll); HLMutex(const char *name);
~LockCollectionForReading();
}; };
#if defined(CLC) // implementation stuff
class LockCollectionForWriting : boost::noncopyable { // per thread
struct Locks { class LockState {
Locks(string ns);
SimpleRWLock::Shared excluder;
GlobalSharedLock gslk;
rwlock clk;
};
scoped_ptr<Locks> locks;
public: public:
LockCollectionForWriting(string db); LockState();
~LockCollectionForWriting(); void dump();
static void Dump();
void reportState(BSONObjBuilder& b);
unsigned recursiveCount() const { return _recursive; }
/**
* @return 0 rwRW
*/
char threadState() const { return _threadState; }
void locked( char newState ); // RWrw
void unlocked(); // _threadState = 0
/**
* you have to be locked already to call this
* this is mostly for W_to_R or R_to_W
*/
void changeLockState( char newstate );
Lock::Nestable whichNestable() const { return _whichNestable; }
int nestableCount() const { return _nestableCount; }
int otherCount() const { return _otherCount; }
string otherName() const { return _otherName; }
WrapperForRWLock* otherLock() const { return _otherLock; }
void enterScopedLock( Lock::ScopedLock* lock );
Lock::ScopedLock* leaveScopedLock();
void lockedNestable( Lock::Nestable what , int type );
void unlockedNestable();
void lockedOther( const string& db , int type , WrapperForRWLock* l
ock );
void unlockedOther();
private:
unsigned _recursive; // we allow recursively asking for a
lock; we track that here
// global lock related
char _threadState; // 0, 'r', 'w', 'R', 'W'
// db level locking related
Lock::Nestable _whichNestable;
int _nestableCount; // recursive lock count on local or
admin db XXX - change name
int _otherCount; // >0 means write lock, <0 read lo
ck - XXX change name
string _otherName; // which database are we locking and
working with (besides local/admin)
WrapperForRWLock* _otherLock; // so we don't have to check the map
too often (the map has a mutex)
// for temprelease
// for the nonrecursive case. otherwise there would be many
// the first lock goes here, which is ok since we can't yield recur
sive locks
Lock::ScopedLock* _scopedLk;
}; };
#else
#endif
} }
 End of changes. 11 change blocks. 
48 lines changed or deleted 214 lines changed or added


 d_globals.h   d_globals.h 
// @file d_globals.h // @file d_globals.h
// //
// these are global variables used in mongod ("d"). also used in test bina ry as that is effectively a variation on mongod code. // these are global variables used in mongod ("d"). also used in test bina ry as that is effectively a variation on mongod code.
// that is, these are not in mongos. // that is, these are not in mongos.
// //
#pragma once #pragma once
namespace mongo { namespace mongo {
class RWLock; class RWLockRecursive;
class MongoMutex; class MongoMutex;
class ClientCursorMonitor; class ClientCursorMonitor;
struct DGlobals : boost::noncopyable { struct DGlobals : boost::noncopyable {
DGlobals(); DGlobals();
// these are intentionally never deleted: // these are intentionally never deleted:
RWLock& writeExcluder;
MongoMutex &dbMutex; MongoMutex &dbMutex;
ClientCursorMonitor& clientCursorMonitor; ClientCursorMonitor& clientCursorMonitor;
}; };
extern DGlobals d; extern DGlobals d;
}; };
 End of changes. 2 change blocks. 
2 lines changed or deleted 1 lines changed or added


 d_logic.h   d_logic.h 
skipping to change at line 26 skipping to change at line 26
*/ */
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "../db/jsobj.h" #include "../db/jsobj.h"
#include "d_chunk_manager.h" #include "d_chunk_manager.h"
#include "util.h" #include "util.h"
#include "mongo/util/concurrency/ticketholder.h"
namespace mongo { namespace mongo {
class Database; class Database;
class DiskLoc; class DiskLoc;
typedef ShardChunkVersion ConfigVersion; typedef ShardChunkVersion ConfigVersion;
// -------------- // --------------
// --- global state --- // --- global state ---
skipping to change at line 151 skipping to change at line 152
private: private:
bool _enabled; bool _enabled;
string _configServer; string _configServer;
string _shardName; string _shardName;
string _shardHost; string _shardHost;
// protects state below // protects state below
mutable mongo::mutex _mutex; mutable mongo::mutex _mutex;
// protects accessing the config server
// Using a ticket holder so we can have multiple redundant tries at
any given time
mutable TicketHolder _configServerTickets;
// map from a namespace into the ensemble of chunk ranges that are stored in this mongod // map from a namespace into the ensemble of chunk ranges that are stored in this mongod
// a ShardChunkManager carries all state we need for a collection a t this shard, including its version information // a ShardChunkManager carries all state we need for a collection a t this shard, including its version information
typedef map<string,ShardChunkManagerPtr> ChunkManagersMap; typedef map<string,ShardChunkManagerPtr> ChunkManagersMap;
ChunkManagersMap _chunks; ChunkManagersMap _chunks;
}; };
extern ShardingState shardingState; extern ShardingState shardingState;
/** /**
skipping to change at line 224 skipping to change at line 228
unsigned long long extractVersion( BSONElement e , string& errmsg ); unsigned long long extractVersion( BSONElement e , string& errmsg );
/** /**
* @return true if we have any shard info for the ns * @return true if we have any shard info for the ns
*/ */
bool haveLocalShardingInfo( const string& ns ); bool haveLocalShardingInfo( const string& ns );
/** /**
* @return true if the current threads shard version is ok, or not in s harded version * @return true if the current threads shard version is ok, or not in s harded version
* Also returns an error message and the Config/ShardChunkVersions caus ing conflicts
*/ */
bool shardVersionOk( const string& ns , string& errmsg ); bool shardVersionOk( const string& ns , string& errmsg, ConfigVersion& received, ConfigVersion& wanted );
/** /**
* @return true if we took care of the message and nothing else should be done * @return true if we took care of the message and nothing else should be done
*/ */
struct DbResponse; struct DbResponse;
bool _handlePossibleShardedMessage( Message &m, DbResponse * dbresponse ); bool _handlePossibleShardedMessage( Message &m, DbResponse * dbresponse );
/** What does this do? document please? */ /** What does this do? document please? */
inline bool handlePossibleShardedMessage( Message &m, DbResponse * dbre sponse ) { inline bool handlePossibleShardedMessage( Message &m, DbResponse * dbre sponse ) {
 End of changes. 4 change blocks. 
1 lines changed or deleted 7 lines changed or added


 database.h   database.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 "cmdline.h" #include "mongo/db/cmdline.h"
#include "namespace.h" #include "mongo/db/namespace_details.h"
namespace mongo { namespace mongo {
class Extent; class Extent;
class MongoDataFile; class MongoDataFile;
class ClientCursor; class ClientCursor;
struct ByLocKey; struct ByLocKey;
typedef map<ByLocKey, ClientCursor*> CCByLoc; typedef map<ByLocKey, ClientCursor*> CCByLoc;
/** /**
 End of changes. 1 change blocks. 
2 lines changed or deleted 2 lines changed or added


 databaseholder.h   databaseholder.h 
skipping to change at line 13 skipping to change at line 13
#pragma once #pragma once
namespace mongo { namespace mongo {
/** /**
* path + dbname -> Database * path + dbname -> Database
*/ */
class DatabaseHolder { class DatabaseHolder {
typedef map<string,Database*> DBs; typedef map<string,Database*> DBs;
typedef map<string,DBs> Paths; typedef map<string,DBs> Paths;
// todo: we want something faster than this if called a lot:
mutable SimpleMutex _m;
Paths _paths;
int _size;
public: public:
DatabaseHolder() : _size(0) { } DatabaseHolder() : _m("dbholder"),_size(0) { }
bool __isLoaded( const string& ns , const string& path ) const { bool __isLoaded( const string& ns , const string& path ) const {
SimpleMutex::scoped_lock lk(_m);
Paths::const_iterator x = _paths.find( path ); Paths::const_iterator x = _paths.find( path );
if ( x == _paths.end() ) if ( x == _paths.end() )
return false; return false;
const DBs& m = x->second; const DBs& m = x->second;
string db = _todb( ns ); string db = _todb( ns );
DBs::const_iterator it = m.find(db); DBs::const_iterator it = m.find(db);
return it != m.end(); return it != m.end();
} }
// must be write locked as otherwise isLoaded could go false->true on you // must be write locked as otherwise isLoaded could go false->true on you
// in the background and you might not expect that. // in the background and you might not expect that.
bool _isLoaded( const string& ns , const string& path ) const { bool _isLoaded( const string& ns , const string& path ) const {
d.dbMutex.assertWriteLocked(); Lock::assertWriteLocked(ns);
return __isLoaded(ns,path); return __isLoaded(ns,path);
} }
Database * get( const string& ns , const string& path ) const { Database * get( const string& ns , const string& path ) const {
d.dbMutex.assertAtLeastReadLocked(); SimpleMutex::scoped_lock lk(_m);
Lock::assertAtLeastReadLocked(ns);
Paths::const_iterator x = _paths.find( path ); Paths::const_iterator x = _paths.find( path );
if ( x == _paths.end() ) if ( x == _paths.end() )
return 0; return 0;
const DBs& m = x->second; const DBs& m = x->second;
string db = _todb( ns ); string db = _todb( ns );
DBs::const_iterator it = m.find(db); DBs::const_iterator it = m.find(db);
if ( it != m.end() ) if ( it != m.end() )
return it->second; return it->second;
return 0; return 0;
} }
void _put( const string& ns , const string& path , Database * db )
{
d.dbMutex.assertAtLeastReadLocked();
DBs& m = _paths[path];
Database*& d = m[_todb(ns)];
if( d ) {
dlog(2) << "info dbholder put db was already set " << ns <<
endl;
}
else {
_size++;
}
d = db;
}
Database* getOrCreate( const string& ns , const string& path , bool & justCreated ); Database* getOrCreate( const string& ns , const string& path , bool & justCreated );
void erase( const string& ns , const string& path ) { void erase( const string& ns , const string& path ) {
d.dbMutex.assertWriteLocked(); // write lock req'd as a Databas SimpleMutex::scoped_lock lk(_m);
e obj can be in use dbHolderMutex is mainly just to control the holder itse verify( Lock::isW() );
lf
DBs& m = _paths[path]; DBs& m = _paths[path];
_size -= (int)m.erase( _todb( ns ) ); _size -= (int)m.erase( _todb( ns ) );
} }
/** @param force - force close even if something underway - use at shutdown */ /** @param force - force close even if something underway - use at shutdown */
bool closeAll( const string& path , BSONObjBuilder& result, bool fo rce ); bool closeAll( const string& path , BSONObjBuilder& result, bool fo rce );
// "info" as this is informational only could change on you if you are not write locked // "info" as this is informational only could change on you if you are not write locked
int sizeInfo() const { return _size; } int sizeInfo() const { return _size; }
void forEach(boost::function<void(Database *)> f) const {
d.dbMutex.assertWriteLocked();
for ( Paths::const_iterator i=_paths.begin(); i!=_paths.end();
i++ ) {
DBs m = i->second;
for( DBs::const_iterator j=m.begin(); j!=m.end(); j++ ) {
f(j->second);
}
}
}
/** /**
* gets all unique db names, ignoring paths * gets all unique db names, ignoring paths
*/ */
void getAllShortNames( bool locked, set<string>& all ) const { void getAllShortNames( bool locked, set<string>& all ) const {
d.dbMutex.assertAtLeastReadLocked(); SimpleMutex::scoped_lock lk(_m);
for ( Paths::const_iterator i=_paths.begin(); i!=_paths.end(); i++ ) { for ( Paths::const_iterator i=_paths.begin(); i!=_paths.end(); i++ ) {
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:
static string _todb( const string& ns ) { static string _todb( const string& ns ) {
skipping to change at line 112 skipping to change at line 96
} }
static string __todb( const string& ns ) { static string __todb( const string& ns ) {
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;
int _size;
}; };
DatabaseHolder& dbHolderUnchecked(); DatabaseHolder& dbHolderUnchecked();
inline const DatabaseHolder& dbHolder() { inline const DatabaseHolder& dbHolder() {
dassert( d.dbMutex.atLeastReadLocked() ); dassert( Lock::isLocked() );
return dbHolderUnchecked(); return dbHolderUnchecked();
} }
inline DatabaseHolder& dbHolderW() { inline DatabaseHolder& dbHolderW() {
dassert( d.dbMutex.isWriteLocked() ); dassert( Lock::isW() );
return dbHolderUnchecked(); return dbHolderUnchecked();
} }
} }
 End of changes. 12 change blocks. 
37 lines changed or deleted 14 lines changed or added


 db.h   db.h 
skipping to change at line 29 skipping to change at line 29
#include "../pch.h" #include "../pch.h"
#include "../util/net/message.h" #include "../util/net/message.h"
#include "mongomutex.h" #include "mongomutex.h"
#include "pdfile.h" #include "pdfile.h"
#include "curop.h" #include "curop.h"
#include "client.h" #include "client.h"
#include "databaseholder.h" #include "databaseholder.h"
namespace mongo { namespace mongo {
// todo: relocked is being called when there was no unlock below.
// that is weird.
struct dbtemprelease { struct dbtemprelease {
Client::Context * _context; Client::Context * _context;
int _locktype; scoped_ptr<Lock::TempRelease> tr;
dbtemprelease() { dbtemprelease() {
const Client& c = cc(); const Client& c = cc();
_context = c.getContext(); _context = c.getContext();
_locktype = d.dbMutex.getState(); verify( Lock::isLocked() );
assert( _locktype ); if( Lock::nested() ) {
Lock::nested();
if ( _locktype > 0 ) { massert(10298 , "can't temprelease nested lock", false);
massert( 10298 , "can't temprelease nested write lock", _lo
cktype == 1);
if ( _context ) _context->unlocked();
d.dbMutex.unlock();
} }
else { if ( _context ) {
massert( 10299 , "can't temprelease nested read lock", _loc _context->unlocked();
ktype == -1);
if ( _context ) _context->unlocked();
d.dbMutex.unlock_shared();
} }
tr.reset(new Lock::TempRelease);
verify( 14814 , c.curop() ); verify( c.curop() );
c.curop()->yielded(); c.curop()->yielded();
} }
~dbtemprelease() { ~dbtemprelease() {
if ( _locktype > 0 ) tr.reset();
d.dbMutex.lock(); if ( _context )
else _context->relocked();
d.dbMutex.lock_shared();
if ( _context ) _context->relocked();
} }
}; };
/** must be write locked /** must be write locked
no assert (and no release) if nested write lock no verify(and no release) if nested write lock
a lot like dbtempreleasecond but no malloc so should be a tiny bit a lot like dbtempreleasecond, eliminate?
faster
*/ */
struct dbtempreleasewritelock { struct dbtempreleasewritelock {
Client::Context * _context; Client::Context * _context;
int _locktype; int _locktype;
scoped_ptr<Lock::TempRelease> tr;
dbtempreleasewritelock() { dbtempreleasewritelock() {
const Client& c = cc(); const Client& c = cc();
_context = c.getContext(); _context = c.getContext();
_locktype = d.dbMutex.getState(); verify( Lock::isW() );
assert( _locktype >= 1 ); if( Lock::nested() )
if( _locktype > 1 ) return;
return; // nested
if ( _context ) if ( _context )
_context->unlocked(); _context->unlocked();
d.dbMutex.unlock(); tr.reset(new Lock::TempRelease);
verify( 14845 , c.curop() ); verify( c.curop() );
c.curop()->yielded(); c.curop()->yielded();
} }
~dbtempreleasewritelock() { ~dbtempreleasewritelock() {
if ( _locktype == 1 ) tr.reset();
d.dbMutex.lock();
if ( _context ) if ( _context )
_context->relocked(); _context->relocked();
} }
}; };
/** /**
only does a temp release if we're not nested and have a lock only does a temp release if we're not nested and have a lock
*/ */
struct dbtempreleasecond { class dbtempreleasecond : boost::noncopyable {
dbtemprelease * real; dbtemprelease * real;
int locktype; public:
dbtempreleasecond() { dbtempreleasecond() {
real = 0; real = 0;
locktype = d.dbMutex.getState(); if( Lock::isLocked() ) {
if ( locktype == 1 || locktype == -1 ) // if nested don't temprelease, and we don't complain eithe
real = new dbtemprelease(); r for this class
if( !Lock::nested() ) {
real = new dbtemprelease();
}
}
} }
~dbtempreleasecond() { ~dbtempreleasecond() {
if ( real ) { if ( real ) {
delete real; delete real;
real = 0; real = 0;
} }
} }
bool unlocked() const { return real != 0; }
bool unlocked() {
return real != 0;
}
}; };
} // namespace mongo } // namespace mongo
 End of changes. 17 change blocks. 
46 lines changed or deleted 34 lines changed or added


 dbclient.h   dbclient.h 
/** @file dbclient.h /** @file dbclient.h
Core MongoDB C++ driver interfaces are defined here. Include this file when writing client C++ applications, to get access t
o the
mongod C++ driver.
*/ */
/* 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 "../pch.h" #ifdef MONGO_EXPOSE_MACROS
#include "../util/net/message.h" #error dbclient.h is for C++ driver consumer use only
#include "../util/net/message_port.h"
#include "../db/jsobj.h"
#include "../db/json.h"
#include "../db/security.h"
#include <stack>
namespace mongo {
/** the query field 'options' can have these bits set: */
enum QueryOptions {
/** Tailable means cursor is not closed when the last data is retri
eved. rather, the cursor marks
the final object's position. you can resume using the cursor la
ter, from where it was located,
if more data were received. Set on dbQuery and dbGetMore.
like any "latent cursor", the cursor may become invalid at some
point -- for example if that
final object it references were deleted. Thus, you should be pr
epared to requery if you get back
ResultFlag_CursorNotFound.
*/
QueryOption_CursorTailable = 1 << 1,
/** allow query of replica slave. normally these return an error e
xcept for namespace "local".
*/
QueryOption_SlaveOk = 1 << 2,
// findingStart mode is used to find the first operation of interes
t when
// we are scanning through a repl log. For efficiency in the commo
n case,
// where the first operation of interest is closer to the tail than
the head,
// we start from the tail of the log and work backwards until we fi
nd the
// first operation of interest. Then we scan forward from that fir
st operation,
// actually returning results to the client. During the findingSta
rt phase,
// we release the db mutex occasionally to avoid blocking the db pr
ocess for
// an extended period of time.
QueryOption_OplogReplay = 1 << 3,
/** The server normally times out idle cursors after an inactivy pe
riod to prevent excess memory uses
Set this option to prevent that.
*/
QueryOption_NoCursorTimeout = 1 << 4,
/** Use with QueryOption_CursorTailable. If we are at the end of t
he data, block for a while rather
than returning no data. After a timeout period, we do return as
normal.
*/
QueryOption_AwaitData = 1 << 5,
/** Stream the data down full blast in multiple "more" packages, on
the assumption that the client
will fully read all data queried. Faster when you are pulling
a lot of data and know you want to
pull it all down. Note: it is not allowed to not read all the
data unless you close the connection.
Use the query( boost::function<void(const BSONObj&)> f, ... ) v
ersion of the connection's query()
method, and it will take care of all the details for you.
*/
QueryOption_Exhaust = 1 << 6,
/** When sharded, this means its ok to return partial results
Usually we will fail a query if all required shards aren't up
If this is set, it'll be a partial result set
*/
QueryOption_PartialResults = 1 << 7 ,
QueryOption_AllSupported = QueryOption_CursorTailable | QueryOption
_SlaveOk | QueryOption_OplogReplay | QueryOption_NoCursorTimeout | QueryOpt
ion_AwaitData | QueryOption_Exhaust | QueryOption_PartialResults
};
enum UpdateOptions {
/** Upsert - that is, insert the item if no matching item is found.
*/
UpdateOption_Upsert = 1 << 0,
/** Update multiple documents (if multiple documents match query ex
pression).
(Default is update a single document and stop.) */
UpdateOption_Multi = 1 << 1,
/** flag from mongo saying this update went everywhere */
UpdateOption_Broadcast = 1 << 2
};
enum RemoveOptions {
/** only delete one option */
RemoveOption_JustOne = 1 << 0,
/** flag from mongo saying this update went everywhere */
RemoveOption_Broadcast = 1 << 1
};
/**
* need to put in DbMesssage::ReservedOptions as well
*/
enum InsertOptions {
/** With muli-insert keep processing inserts if one fails */
InsertOption_ContinueOnError = 1 << 0
};
class DBClientBase;
/**
* ConnectionString handles parsing different ways to connect to mongo
and determining method
* samples:
* server
* server:port
* foo/server:port,server:port SET
* server,server,server SYNC
*
* tyipcal use
* string errmsg,
* ConnectionString cs = ConnectionString::parse( url , errmsg );
* if ( ! cs.isValid() ) throw "bad: " + errmsg;
* DBClientBase * conn = cs.connect( errmsg );
*/
class ConnectionString {
public:
enum ConnectionType { INVALID , MASTER , PAIR , SET , SYNC };
ConnectionString() {
_type = INVALID;
}
ConnectionString( const HostAndPort& server ) {
_type = MASTER;
_servers.push_back( server );
_finishInit();
}
ConnectionString( ConnectionType type , const string& s , const str
ing& setName = "" ) {
_type = type;
_setName = setName;
_fillServers( s );
switch ( _type ) {
case MASTER:
assert( _servers.size() == 1 );
break;
case SET:
assert( _setName.size() );
assert( _servers.size() >= 1 ); // 1 is ok since we can der
ive
break;
case PAIR:
assert( _servers.size() == 2 );
break;
default:
assert( _servers.size() > 0 );
}
_finishInit();
}
ConnectionString( const string& s , ConnectionType favoredMultipleT
ype ) {
_type = INVALID;
_fillServers( s );
if ( _type != INVALID ) {
// set already
}
else if ( _servers.size() == 1 ) {
_type = MASTER;
}
else {
_type = favoredMultipleType;
assert( _type == SET || _type == SYNC );
}
_finishInit();
}
bool isValid() const { return _type != INVALID; }
string toString() const { return _string; }
DBClientBase* connect( string& errmsg, double socketTimeout = 0 ) c
onst;
string getSetName() const { return _setName; }
vector<HostAndPort> getServers() const { return _servers; }
ConnectionType type() const { return _type; }
static ConnectionString parse( const string& url , string& errmsg )
;
static string typeToString( ConnectionType type );
private:
void _fillServers( string s );
void _finishInit();
ConnectionType _type;
vector<HostAndPort> _servers;
string _string;
string _setName;
};
/**
* controls how much a clients cares about writes
* default is NORMAL
*/
enum WriteConcern {
W_NONE = 0 , // TODO: not every connection type fully supports this
W_NORMAL = 1
// TODO SAFE = 2
};
class BSONObj;
class ScopedDbConnection;
class DBClientCursor;
class DBClientCursorBatchIterator;
/** Represents a Mongo query expression. Typically one uses the QUERY(
...) macro to construct a Query object.
Examples:
QUERY( "age" << 33 << "school" << "UCLA" ).sort("name")
QUERY( "age" << GT << 30 << LT << 50 )
*/
class Query {
public:
BSONObj obj;
Query() : obj(BSONObj()) { }
Query(const BSONObj& b) : obj(b) { }
Query(const string &json) :
obj(fromjson(json)) { }
Query(const char * json) :
obj(fromjson(json)) { }
/** Add a sort (ORDER BY) criteria to the query expression.
@param sortPattern the sort order template. For example to ord
er by name ascending, time descending:
{ name : 1, ts : -1 }
i.e.
BSON( "name" << 1 << "ts" << -1 )
or
fromjson(" name : 1, ts : -1 ")
*/
Query& sort(const BSONObj& sortPattern);
/** Add a sort (ORDER BY) criteria to the query expression.
This version of sort() assumes you want to sort on a single fie
ld.
@param asc = 1 for ascending order
asc = -1 for descending order
*/
Query& sort(const string &field, int asc = 1) { sort( BSON( field <
< asc ) ); return *this; }
/** Provide a hint to the query.
@param keyPattern Key pattern for the index to use.
Example:
hint("{ts:1}")
*/
Query& hint(BSONObj keyPattern);
Query& hint(const string &jsonKeyPatt) { return hint(fromjson(jsonK
eyPatt)); }
/** Provide min and/or max index limits for the query.
min <= x < max
*/
Query& minKey(const BSONObj &val);
/**
max is exclusive
*/
Query& maxKey(const BSONObj &val);
/** Return explain information about execution of this query instea
d of the actual query results.
Normally it is easier to use the mongo shell to run db.find(...
).explain().
*/
Query& explain();
/** Use snapshot mode for the query. Snapshot mode assures no dupl
icates are returned, or objects missed, which were
present at both the start and end of the query's execution (if
an object is new during the query, or deleted during
the query, it may or may not be returned, even with snapshot mo
de).
Note that short query responses (less than 1MB) are always effe
ctively snapshotted.
Currently, snapshot mode may not be used with sorting or explic
it hints.
*/
Query& snapshot();
/** Queries to the Mongo database support a $where parameter option
which contains
a javascript function that is evaluated to see whether objects
being queried match
its criteria. Use this helper to append such a function to a q
uery object.
Your query may also contain other traditional Mongo query terms
.
@param jscode The javascript function to evaluate against each
potential object
match. The function must return true for matched object
s. Use the this
variable to inspect the current object.
@param scope SavedContext for the javascript object. List in a
BSON object any
variables you would like defined when the jscode execute
s. One can think
of these as "bind variables".
Examples:
conn.findOne("test.coll", Query("{a:3}").where("this.b == 2 |
| this.c == 3"));
Query badBalance = Query().where("this.debits - this.credits
< 0");
*/
Query& where(const string &jscode, BSONObj scope);
Query& where(const string &jscode) { return where(jscode, BSONObj()
); }
/**
* @return true if this query has an orderby, hint, or some other f
ield
*/
bool isComplex( bool * hasDollar = 0 ) const;
BSONObj getFilter() const;
BSONObj getSort() const;
BSONObj getHint() const;
bool isExplain() const;
string toString() const;
operator string() const { return toString(); }
private:
void makeComplex();
template< class T >
void appendComplex( const char *fieldName, const T& val ) {
makeComplex();
BSONObjBuilder b;
b.appendElements(obj);
b.append(fieldName, val);
obj = b.obj();
}
};
/**
* Represents a full query description, including all options required
for the query to be passed on
* to other hosts
*/
class QuerySpec {
string _ns;
int _ntoskip;
int _ntoreturn;
int _options;
BSONObj _query;
BSONObj _fields;
Query _queryObj;
public:
QuerySpec( const string& ns,
const BSONObj& query, const BSONObj& fields,
int ntoskip, int ntoreturn, int options )
: _ns( ns ), _ntoskip( ntoskip ), _ntoreturn( ntoreturn ), _opt
ions( options ),
_query( query.getOwned() ), _fields( fields.getOwned() ) , _q
ueryObj( _query ) {
}
QuerySpec() {}
bool isEmpty() const { return _ns.size() == 0; }
bool isExplain() const { return _queryObj.isExplain(); }
BSONObj filter() const { return _queryObj.getFilter(); }
BSONObj hint() const { return _queryObj.getHint(); }
BSONObj sort() const { return _queryObj.getSort(); }
BSONObj query() const { return _query; }
BSONObj fields() const { return _fields; }
BSONObj* fieldsData() { return &_fields; }
// don't love this, but needed downstrem
const BSONObj* fieldsPtr() const { return &_fields; }
string ns() const { return _ns; }
int ntoskip() const { return _ntoskip; }
int ntoreturn() const { return _ntoreturn; }
int options() const { return _options; }
void setFields( BSONObj& o ) { _fields = o.getOwned(); }
string toString() const {
return str::stream() << "QSpec " <<
BSON( "ns" << _ns << "n2skip" << _ntoskip << "n2return" <<
_ntoreturn << "options" << _options
<< "query" << _query << "fields" << _fields );
}
};
/** Typically one uses the QUERY(...) macro to construct a Query object
.
Example: QUERY( "age" << 33 << "school" << "UCLA" )
*/
#define QUERY(x) mongo::Query( BSON(x) )
// Useful utilities for namespaces
/** @return the database name portion of an ns string */
string nsGetDB( const string &ns );
/** @return the collection name portion of an ns string */
string nsGetCollection( const string &ns );
/**
interface that handles communication with the db
*/
class DBConnector {
public:
virtual ~DBConnector() {}
/** actualServer is set to the actual server where they call went i
f there was a choice (SlaveOk) */
virtual bool call( Message &toSend, Message &response, bool assertO
k=true , string * actualServer = 0 ) = 0;
virtual void say( Message &toSend, bool isRetry = false , string *
actualServer = 0 ) = 0;
virtual void sayPiggyBack( Message &toSend ) = 0;
/* used by QueryOption_Exhaust. To use that your subclass must imp
lement this. */
virtual bool recv( Message& m ) { assert(false); return false; }
// In general, for lazy queries, we'll need to say, recv, then chec
kResponse
virtual void checkResponse( const char* data, int nReturned, bool*
retry = NULL, string* targetHost = NULL ) {
if( retry ) *retry = false; if( targetHost ) *targetHost = "";
}
virtual bool lazySupported() const = 0;
};
/**
The interface that any db connection should implement
*/
class DBClientInterface : boost::noncopyable {
public:
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer
y, int nToReturn = 0, int nToSkip = 0,
const BSONObj *fieldsToRetur
n = 0, int queryOptions = 0 , int batchSize = 0 ) = 0;
virtual void insert( const string &ns, BSONObj obj , int flags=0) =
0;
virtual void insert( const string &ns, const vector< BSONObj >& v ,
int flags=0) = 0;
virtual void remove( const string &ns , Query query, bool justOne =
0 ) = 0;
virtual void update( const string &ns , Query query , BSONObj obj ,
bool upsert = 0 , bool multi = 0 ) = 0;
virtual ~DBClientInterface() { }
/**
@return a single object that matches the query. if none do, the
n the object is empty
@throws AssertionException
*/
virtual BSONObj findOne(const string &ns, const Query& query, const
BSONObj *fieldsToReturn = 0, int queryOptions = 0);
/** query N objects from the database into an array. makes sense m
ostly when you want a small number of results. if a huge number, use
query() and iterate the cursor.
*/
void findN(vector<BSONObj>& out, const string&ns, Query query, int
nToReturn, int nToSkip = 0, const BSONObj *fieldsToReturn = 0, int queryOpt
ions = 0);
virtual string getServerAddress() const = 0;
/** don't use this - called automatically by DBClientCursor for you
*/
virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo
ng cursorId, int nToReturn = 0, int options = 0 ) = 0;
};
/**
DB "commands"
Basically just invocations of connection.$cmd.findOne({...});
*/
class DBClientWithCommands : public DBClientInterface {
set<string> _seenIndexes;
public:
/** controls how chatty the client is about network errors & such.
See log.h */
int _logLevel;
DBClientWithCommands() : _logLevel(0), _cachedAvailableOptions( (en
um QueryOptions)0 ), _haveCachedAvailableOptions(false) { }
/** helper function. run a simple command where the command expres
sion is simply
{ command : 1 }
@param info -- where to put result object. may be null if call
er doesn't need that info
@param command -- command name
@return true if the command returned "ok".
*/
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
commands have prebuilt helper functions -- see below. If a hel
per is not available you can
directly call runCommand.
@param dbname database name. Use "admin" for global administra
tive commands.
@param cmd the command object to execute. For example, { isma
ster : 1 }
@param info the result object the database returns. Typically h
as { ok : ..., errmsg : ... } fields
set.
@param options see enum QueryOptions - normally not needed to r
un a command
@return true if the command returned "ok".
*/
virtual bool runCommand(const string &dbname, const BSONObj& cmd, B
SONObj &info, int options=0);
/** Authorize access to a particular database.
Authentication is separate for each database on the server -- y
ou may authenticate for any
number of databases on a single connection.
The "admin" database is special and once authenticated provides
access to all databases on the
server.
@param digestPassword if password is plain text, set this
to true. otherwise assumed to be pre-digested
@param[out] authLevel level of authentication for the giv
en user
@return true if successful
*/
virtual bool auth(const string &dbname, const string &username, con
st string &pwd, string& errmsg, bool digestPassword = true, Auth::Level * l
evel = NULL);
/** count number of objects in collection ns that match the query c
riteria specified
throws UserAssertion if database returns an error
*/
virtual unsigned long long count(const string &ns, const BSONObj& q
uery = BSONObj(), int options=0, int limit=0, int skip=0 );
string createPasswordDigest( const string &username , const string
&clearTextPassword );
/** returns true in isMaster parm if this db is the current master
of a replica pair.
pass in info for more details e.g.:
{ "ismaster" : 1.0 , "msg" : "not paired" , "ok" : 1.0 }
returns true if command invoked successfully.
*/
virtual bool isMaster(bool& isMaster, BSONObj *info=0);
/**
Create a new collection in the database. Normally, collection c
reation is automatic. You would
use this function if you wish to specify special options on crea
tion.
If the collection already exists, no action occurs.
@param ns fully qualified collection name
@param size desired initial extent size for the collection.
Must be <= 1000000000 for normal collections.
For fixed size (capped) collections, this size is
the total/max size of the
collection.
@param capped if true, this is a fixed size collection (where ol
d data rolls out).
@param max maximum number of objects if capped (optional).
returns true if successful.
*/
bool createCollection(const string &ns, long long size = 0, bool ca
pped = false, int max = 0, BSONObj *info = 0);
/** Get error result from the last write operation (insert/update/d
elete) on this connection.
@return error message text, or empty string if no error.
*/
string getLastError(bool fsync = false, bool j = false, int w = 0,
int wtimeout = 0);
/** Get error result from the last write operation (insert/update/d
elete) on this connection.
@return full error object.
If "w" is -1, wait for propagation to majority of nodes.
If "wtimeout" is 0, the operation will block indefinitely if ne
eded.
*/
virtual BSONObj getLastErrorDetailed(bool fsync = false, bool j = f
alse, int w = 0, int wtimeout = 0);
/** Can be called with the returned value from getLastErrorDetailed
to extract an error string.
If all you need is the string, just call getLastError() instead
.
*/
static string getLastErrorString( const BSONObj& res );
/** Return the last error which has occurred, even if not the very
last operation.
@return { err : <error message>, nPrev : <how_many_ops_back_occu
rred>, ok : 1 }
result.err will be null if no error has occurred.
*/
BSONObj getPrevError();
/** Reset the previous error state for this connection (accessed vi
a getLastError and
getPrevError). Useful when performing several operations at on
ce and then checking
for an error after attempting all operations.
*/
bool resetError() { return simpleCommand("admin", 0, "reseterror");
}
/** Delete the specified collection. */
virtual bool dropCollection( const string &ns ) {
string db = nsGetDB( ns );
string coll = nsGetCollection( ns );
uassert( 10011 , "no collection name", coll.size() );
BSONObj info;
bool res = runCommand( db.c_str() , BSON( "drop" << coll ) , in
fo );
resetIndexCache();
return res;
}
/** Perform a repair and compaction of the specified database. May
take a long time to run. Disk space
must be available equal to the size of the database while repair
ing.
*/
bool repairDatabase(const string &dbname, BSONObj *info = 0) {
return simpleCommand(dbname, info, "repairDatabase");
}
/** Copy database from one server or name to another server or name
.
Generally, you should dropDatabase() first as otherwise the copi
ed information will MERGE
into whatever data is already present in this database.
For security reasons this function only works when you are autho
rized to access the "admin" db. However,
if you have access to said db, you can copy any database from on
e place to another.
TODO: this needs enhancement to be more flexible in terms of sec
urity.
This method provides a way to "rename" a database by copying it
to a new db name and
location. The copy is "repaired" and compacted.
fromdb database name from which to copy.
todb database name to copy to.
fromhost hostname of the database (and optionally, ":port") from
which to
copy the data. copies from self if "".
returns true if successful
*/
bool copyDatabase(const string &fromdb, const string &todb, const s
tring &fromhost = "", BSONObj *info = 0);
/** The Mongo database provides built-in performance profiling capa
bilities. Uset setDbProfilingLevel()
to enable. Profiling information is then written to the system.
profiling collection, which one can
then query.
*/
enum ProfilingLevel {
ProfileOff = 0,
ProfileSlow = 1, // log very slow (>100ms) operations
ProfileAll = 2
};
bool setDbProfilingLevel(const string &dbname, ProfilingLevel level
, BSONObj *info = 0);
bool getDbProfilingLevel(const string &dbname, ProfilingLevel& leve
l, BSONObj *info = 0);
/** This implicitly converts from char*, string, and BSONObj to be
an argument to mapreduce
You shouldn't need to explicitly construct this
*/
struct MROutput {
MROutput(const char* collection) : out(BSON("replace" << collec
tion)) {}
MROutput(const string& collection) : out(BSON("replace" << coll
ection)) {}
MROutput(const BSONObj& obj) : out(obj) {}
BSONObj out;
};
static MROutput MRInline;
/** Run a map/reduce job on the server.
See http://www.mongodb.org/display/DOCS/MapReduce
ns namespace (db+collection name) of input data
jsmapf javascript map function code
jsreducef javascript reduce function code.
query optional query filter for the input
output either a string collection name or an object represen
ting output type
if not specified uses inline output type
returns a result object which contains:
{ result : <collection_name>,
numObjects : <number_of_objects_scanned>,
timeMillis : <job_time>,
ok : <1_if_ok>,
[, err : <errmsg_if_error>]
}
For example one might call:
result.getField("ok").trueValue()
on the result to check if ok.
*/
BSONObj mapreduce(const string &ns, const string &jsmapf, const str
ing &jsreducef, BSONObj query = BSONObj(), MROutput output = MRInline);
/** Run javascript code on the database server.
dbname database SavedContext in which the code runs. The java
script variable 'db' will be assigned
to this database when the function is invoked.
jscode source code for a javascript function.
info the command object which contains any information on t
he invocation result including
the return value and other information. If an error
occurs running the jscode, error
information will be in info. (try "out() << info.toSt
ring()")
retValue return value from the jscode function.
args args to pass to the jscode function. when invoked, th
e 'args' variable will be defined
for use by the jscode.
returns true if runs ok.
See testDbEval() in dbclient.cpp for an example of usage.
*/
bool eval(const string &dbname, const string &jscode, BSONObj& info
, BSONElement& retValue, BSONObj *args = 0);
/** validate a collection, checking for errors and reporting back s
tatistics.
this operation is slow and blocking.
*/
bool validate( const string &ns , bool scandata=true ) {
BSONObj cmd = BSON( "validate" << nsGetCollection( ns ) << "sca
ndata" << scandata );
BSONObj info;
return runCommand( nsGetDB( ns ).c_str() , cmd , info );
}
/* The following helpers are simply more convenient forms of eval()
for certain common cases */
/* invocation with no return value of interest -- with or without o
ne simple parameter */
bool eval(const string &dbname, const string &jscode);
template< class T >
bool eval(const string &dbname, const string &jscode, T parm1) {
BSONObj info;
BSONElement retValue;
BSONObjBuilder b;
b.append("0", parm1);
BSONObj args = b.done();
return eval(dbname, jscode, info, retValue, &args);
}
/** eval invocation with one parm to server and one numeric field (
either int or double) returned */
template< class T, class NumType >
bool eval(const string &dbname, const string &jscode, T parm1, NumT
ype& ret) {
BSONObj info;
BSONElement retValue;
BSONObjBuilder b;
b.append("0", parm1);
BSONObj args = b.done();
if ( !eval(dbname, jscode, info, retValue, &args) )
return false;
ret = (NumType) retValue.number();
return true;
}
/**
get a list of all the current databases
uses the { listDatabases : 1 } command.
throws on error
*/
list<string> getDatabaseNames();
/**
get a list of all the current collections in db
*/
list<string> getCollectionNames( const string& db );
bool exists( const string& ns );
/** Create an index if it does not already exist.
ensureIndex calls are remembered so it is safe/fast to call thi
s function many
times in your code.
@param ns collection to be indexed
@param keys the "key pattern" for the index. e.g., { name : 1 }
@param unique if true, indicates that key uniqueness should be e
nforced for this index
@param name if not specified, it will be created from the keys a
utomatically (which is recommended)
@param cache if set to false, the index cache for the connection
won't remember this call
@param background build index in the background (see mongodb doc
s/wiki for details)
@param v index version. leave at default value. (unit tests set
this parameter.)
@return whether or not sent message to db.
should be true on first call, false on subsequent unless reset
IndexCache was called
*/
virtual bool ensureIndex( const string &ns , BSONObj keys , bool un
ique = false, const string &name = "",
bool cache = true, bool background = fals
e, int v = -1 );
/**
clears the index cache, so the subsequent call to ensureIndex fo
r any index will go to the server
*/
virtual void resetIndexCache();
virtual auto_ptr<DBClientCursor> getIndexes( const string &ns );
virtual void dropIndex( const string& ns , BSONObj keys );
virtual void dropIndex( const string& ns , const string& indexName
);
/**
drops all indexes for the collection
*/
virtual void dropIndexes( const string& ns );
virtual void reIndex( const string& ns );
string genIndexName( const BSONObj& keys );
/** Erase / drop an entire database */
virtual bool dropDatabase(const string &dbname, BSONObj *info = 0)
{
bool ret = simpleCommand(dbname, info, "dropDatabase");
resetIndexCache();
return ret;
}
virtual string toString() = 0;
protected:
/** if the result of a command is ok*/
bool isOk(const BSONObj&);
/** if the element contains a not master error */
bool isNotMasterErrorString( const BSONElement& e );
BSONObj _countCmd(const string &ns, const BSONObj& query, int optio
ns, int limit, int skip );
enum QueryOptions availableOptions();
private:
enum QueryOptions _cachedAvailableOptions;
bool _haveCachedAvailableOptions;
};
/**
abstract class that implements the core db operations
*/
class DBClientBase : public DBClientWithCommands, public DBConnector {
protected:
WriteConcern _writeConcern;
public:
DBClientBase() {
_writeConcern = W_NORMAL;
}
WriteConcern getWriteConcern() const { return _writeConcern; }
void setWriteConcern( WriteConcern w ) { _writeConcern = w; }
/** send a query to the database.
@param ns namespace to query, format is <dbname>.<collectname>[.<c
ollectname>]*
@param query query to perform on the collection. this is a BSONOb
j (binary JSON)
You may format as
{ query: { ... }, orderby: { ... } }
to specify a sort order.
@param nToReturn n to return (i.e., limit). 0 = unlimited
@param nToSkip start with the nth item
@param fieldsToReturn optional template of which fields to select.
if unspecified, returns all fields
@param queryOptions see options enum at top of this file
@return cursor. 0 if error (connection failure)
@throws AssertionException
*/
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer
y, int nToReturn = 0, int nToSkip = 0,
const BSONObj *fieldsToRetur
n = 0, int queryOptions = 0 , int batchSize = 0 );
/** don't use this - called automatically by DBClientCursor for you
@param cursorId id of cursor to retrieve
@return an handle to a previously allocated cursor
@throws AssertionException
*/
virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo
ng cursorId, int nToReturn = 0, int options = 0 );
/**
insert an object into the database
*/
virtual void insert( const string &ns , BSONObj obj , int flags=0);
/**
insert a vector of objects into the database
*/
virtual void insert( const string &ns, const vector< BSONObj >& v ,
int flags=0);
/**
remove matching objects from the database
@param justOne if this true, then once a single match is found w
ill stop
*/
virtual void remove( const string &ns , Query q , bool justOne = 0
);
/**
updates objects matching query
*/
virtual void update( const string &ns , Query query , BSONObj obj ,
bool upsert = false , bool multi = false );
virtual bool isFailed() const = 0;
virtual void killCursor( long long cursorID ) = 0;
virtual bool callRead( Message& toSend , Message& response ) = 0;
// virtual bool callWrite( Message& toSend , Message& response ) =
0; // TODO: add this if needed
virtual ConnectionString::ConnectionType type() const = 0;
virtual double getSoTimeout() const = 0;
}; // DBClientBase
class DBClientReplicaSet;
class ConnectException : public UserException {
public:
ConnectException(string msg) : UserException(9000,msg) { }
};
/**
A basic connection to the database.
This is the main entry point for talking to a simple Mongo setup
*/
class DBClientConnection : public DBClientBase {
public:
/**
@param _autoReconnect if true, automatically reconnect on a conn
ection failure
@param cp used by DBClientReplicaSet. You do not need to specif
y this parameter
@param timeout tcp timeout in seconds - this is for read/write,
not connect.
Connect timeout is fixed, but short, at 5 seconds.
*/
DBClientConnection(bool _autoReconnect=false, DBClientReplicaSet* c
p=0, double so_timeout=0) :
clientSet(cp), _failed(false), autoReconnect(_autoReconnect), l
astReconnectTry(0), _so_timeout(so_timeout) {
_numConnections++;
}
virtual ~DBClientConnection() {
_numConnections--;
}
/** Connect to a Mongo database server.
If autoReconnect is true, you can try to use the DBClientConnect
ion even when
false was returned -- it will try to connect again.
@param serverHostname host to connect to. can include port numb
er ( 127.0.0.1 , 127.0.0.1:5555 )
If you use IPv6 you must add a port number
( ::1:27017 )
@param errmsg any relevant error message will appended to the st
ring
@deprecated please use HostAndPort
@return false if fails to connect.
*/
virtual bool connect(const char * hostname, string& errmsg) {
// TODO: remove this method
HostAndPort t( hostname );
return connect( t , errmsg );
}
/** Connect to a Mongo database server.
If autoReconnect is true, you can try to use the DBClientConnect
ion even when
false was returned -- it will try to connect again.
@param server server to connect to.
@param errmsg any relevant error message will appended to the st
ring
@return false if fails to connect.
*/
virtual bool connect(const HostAndPort& server, string& errmsg);
/** Connect to a Mongo database server. Exception throwing version
.
Throws a UserException if cannot connect.
If autoReconnect is true, you can try to use the DBClientConnect
ion even when
false was returned -- it will try to connect again.
@param serverHostname host to connect to. can include port numb
er ( 127.0.0.1 , 127.0.0.1:5555 )
*/
void connect(const string& serverHostname) {
string errmsg;
if( !connect(HostAndPort(serverHostname), errmsg) )
throw ConnectException(string("can't connect ") + errmsg);
}
virtual bool auth(const string &dbname, const string &username, con
st string &pwd, string& errmsg, bool digestPassword = true, Auth::Level* le
vel=NULL);
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer
y=Query(), int nToReturn = 0, int nToSkip = 0,
const BSONObj *fieldsToRetur
n = 0, int queryOptions = 0 , int batchSize = 0 ) {
checkConnection();
return DBClientBase::query( ns, query, nToReturn, nToSkip, fiel
dsToReturn, queryOptions , batchSize );
}
/** Uses QueryOption_Exhaust
Exhaust mode sends back all data queries as fast as possible, w
ith no back-and-for for OP_GETMORE. If you are certain
you will exhaust the query, it could be useful.
Use DBClientCursorBatchIterator version if you want to do items
in large blocks, perhaps to avoid granular locking and such.
*/
unsigned long long query( boost::function<void(const BSONObj&)> f,
const string& ns, Query query, const BSONObj *fieldsToReturn = 0, int query
Options = 0);
unsigned long long query( boost::function<void(DBClientCursorBatchI
terator&)> f, const string& ns, Query query, const BSONObj *fieldsToReturn
= 0, int queryOptions = 0);
virtual bool runCommand(const string &dbname, const BSONObj& cmd, B
SONObj &info, int options=0);
/**
@return true if this connection is currently in a failed state.
When autoreconnect is on,
a connection will transition back to an ok state after r
econnecting.
*/
bool isFailed() const { return _failed; }
MessagingPort& port() { assert(p); return *p; }
string toStringLong() const {
stringstream ss;
ss << _serverString;
if ( _failed ) ss << " failed";
return ss.str();
}
/** Returns the address of the server */
string toString() { return _serverString; }
string getServerAddress() const { return _serverString; }
virtual void killCursor( long long cursorID );
virtual bool callRead( Message& toSend , Message& response ) { retu
rn call( toSend , response ); }
virtual void say( Message &toSend, bool isRetry = false , string *
actualServer = 0 );
virtual bool recv( Message& m );
virtual void checkResponse( const char *data, int nReturned, bool*
retry = NULL, string* host = NULL );
virtual bool call( Message &toSend, Message &response, bool assertO
k = true , string * actualServer = 0 );
virtual ConnectionString::ConnectionType type() const { return Conn
ectionString::MASTER; }
void setSoTimeout(double to) { _so_timeout = to; }
double getSoTimeout() const { return _so_timeout; }
virtual bool lazySupported() const { return true; }
static int getNumConnections() {
return _numConnections;
}
static void setLazyKillCursor( bool lazy ) { _lazyKillCursor = lazy
; }
static bool getLazyKillCursor() { return _lazyKillCursor; }
protected:
friend class SyncClusterConnection;
virtual void sayPiggyBack( Message &toSend );
DBClientReplicaSet *clientSet;
boost::scoped_ptr<MessagingPort> p;
boost::scoped_ptr<SockAddr> server;
bool _failed;
const bool autoReconnect;
time_t lastReconnectTry;
HostAndPort _server; // remember for reconnects
string _serverString;
void _checkConnection();
// throws SocketException if in failed state and not reconnecting o
r if waiting to reconnect
void checkConnection() { if( _failed ) _checkConnection(); }
map< string, pair<string,string> > authCache;
double _so_timeout;
bool _connect( string& errmsg );
static AtomicUInt _numConnections;
static bool _lazyKillCursor; // lazy means we piggy back kill curso
rs on next op
#ifdef MONGO_SSL
static SSLManager* sslManager();
static SSLManager* _sslManager;
#endif #endif
};
/** pings server to check if it's up
*/
bool serverAlive( const string &uri );
DBClientBase * createDirectClient();
BSONElement getErrField( const BSONObj& result ); #include "mongo/client/redef_macros.h"
bool hasErrField( const BSONObj& result );
inline std::ostream& operator<<( std::ostream &s, const Query &q ) { #include "pch.h"
return s << q.toString();
}
} // namespace mongo #include "mongo/client/connpool.h"
#include "mongo/client/dbclient_rs.h"
#include "mongo/client/dbclientcursor.h"
#include "mongo/client/dbclientinterface.h"
#include "mongo/client/gridfs.h"
#include "mongo/client/model.h"
#include "mongo/client/syncclusterconnection.h"
#include "dbclientcursor.h" #include "mongo/client/undef_macros.h"
#include "dbclient_rs.h"
#include "undef_macros.h"
 End of changes. 7 change blocks. 
1211 lines changed or deleted 14 lines changed or added


 dbclient_rs.h   dbclient_rs.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 "../pch.h" #include "pch.h"
#include "dbclient.h"
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <set>
#include <utility>
#include "mongo/client/dbclientinterface.h"
#include "mongo/util/net/hostandport.h"
namespace mongo { namespace mongo {
class ReplicaSetMonitor; class ReplicaSetMonitor;
typedef shared_ptr<ReplicaSetMonitor> ReplicaSetMonitorPtr; typedef shared_ptr<ReplicaSetMonitor> ReplicaSetMonitorPtr;
typedef pair<set<string>,set<int> > NodeDiff; typedef pair<set<string>,set<int> > NodeDiff;
/** /**
* manages state about a replica set for client * manages state about a replica set for client
* keeps tabs on whose master and what slaves are up * keeps tabs on whose master and what slaves are up
skipping to change at line 58 skipping to change at line 65
*/ */
static ReplicaSetMonitorPtr get( const string& name ); static ReplicaSetMonitorPtr get( const string& name );
/** /**
* checks all sets for current master and new secondaries * checks all sets for current master and new secondaries
* usually only called from a BackgroundJob * usually only called from a BackgroundJob
*/ */
static void checkAll( bool checkAllSecondaries ); static void checkAll( bool checkAllSecondaries );
/** /**
* this is called whenever the config of any repclia set changes * deletes the ReplicaSetMonitor for the given set name.
*/
static void remove( const string& name );
/**
* this is called whenever the config of any replica set changes
* currently only 1 globally * currently only 1 globally
* asserts if one already exists * asserts if one already exists
* ownership passes to ReplicaSetMonitor and the hook will actually never be deleted * ownership passes to ReplicaSetMonitor and the hook will actually never be deleted
*/ */
static void setConfigChangeHook( ConfigChangeHook hook ); static void setConfigChangeHook( ConfigChangeHook hook );
~ReplicaSetMonitor(); ~ReplicaSetMonitor();
/** @return HostAndPort or throws an exception */ /** @return HostAndPort or throws an exception */
HostAndPort getMaster(); HostAndPort getMaster();
skipping to change at line 108 skipping to change at line 120
private: private:
/** /**
* This populates a list of hosts from the list of seeds (discardin g the * This populates a list of hosts from the list of seeds (discardin g the
* seed list). * seed list).
* @param name set name * @param name set name
* @param servers seeds * @param servers seeds
*/ */
ReplicaSetMonitor( const string& name , const vector<HostAndPort>& servers ); ReplicaSetMonitor( const string& name , const vector<HostAndPort>& servers );
/**
* Checks all connections from the host list and sets the current
* master.
*
* @param checkAllSecondaries if set to false, stop immediately whe
n
* the master is found or when _master is not -1.
*/
void _check( bool checkAllSecondaries ); void _check( bool checkAllSecondaries );
/** /**
* Use replSetGetStatus command to make sure hosts in host list are up * Use replSetGetStatus command to make sure hosts in host list are up
* and readable. Sets Node::ok appropriately. * and readable. Sets Node::ok appropriately.
*/ */
void _checkStatus(DBClientConnection *conn); void _checkStatus( const string& hostAddr );
/** /**
* Add array of hosts to host list. Doesn't do anything if hosts ar e * Add array of hosts to host list. Doesn't do anything if hosts ar e
* already in host list. * already in host list.
* @param hostList the list of hosts to add * @param hostList the list of hosts to add
* @param changed if new hosts were added * @param changed if new hosts were added
*/ */
void _checkHosts(const BSONObj& hostList, bool& changed); void _checkHosts(const BSONObj& hostList, bool& changed);
/** /**
* Updates host list. * Updates host list.
* @param c the connection to check * Invariant: if nodesOffset is >= 0, _nodes[nodesOffset].conn shou
ld be
* equal to conn.
*
* @param conn the connection to check
* @param maybePrimary OUT * @param maybePrimary OUT
* @param verbose * @param verbose
* @param nodesOffset - offset into _nodes array, -1 for not in it * @param nodesOffset - offset into _nodes array, -1 for not in it
* @return if the connection is good *
* @return true if the connection is good or false if invariant
* is broken
*/ */
bool _checkConnection( DBClientConnection * c , string& maybePrimar bool _checkConnection( DBClientConnection* conn, string& maybePrima
y , bool verbose , int nodesOffset ); ry,
bool verbose, int nodesOffset );
string _getServerAddress_inlock() const; string _getServerAddress_inlock() const;
NodeDiff _getHostDiff_inlock( const BSONObj& hostList ); NodeDiff _getHostDiff_inlock( const BSONObj& hostList );
bool _shouldChangeHosts( const BSONObj& hostList, bool inlock ); bool _shouldChangeHosts( const BSONObj& hostList, bool inlock );
/**
* @return the index to _nodes corresponding to the server address.
*/
int _find( const string& server ) const ; int _find( const string& server ) const ;
int _find_inlock( const string& server ) const ; int _find_inlock( const string& server ) const ;
int _find( const HostAndPort& server ) const ;
mutable mongo::mutex _lock; // protects _nodes /**
* Checks whether the given connection matches the connection store
d in _nodes.
* Mainly used for sanity checking to confirm that nodeOffset still
* refers to the right connection after releasing and reacquiring
* a mutex.
*/
bool _checkConnMatch_inlock( DBClientConnection* conn, size_t nodeO
ffset ) const;
// protects _nodes and indices pointing to it (_master & _nextSlave
)
mutable mongo::mutex _lock;
/**
* "Synchronizes" the _checkConnection method. Should ideally be on
e mutex per
* connection object being used. The purpose of this lock is to mak
e sure that
* the reply from the connection the lock holder got is the actual
response
* to what it sent.
*
* Deadlock WARNING: never acquire this while holding _lock
*/
mutable mongo::mutex _checkConnectionLock; mutable mongo::mutex _checkConnectionLock;
string _name; string _name;
// note these get copied around in the nodes vector so be sure to m aintain copyable semantics here // note these get copied around in the nodes vector so be sure to m aintain copyable semantics here
struct Node { struct Node {
Node( const HostAndPort& a , DBClientConnection* c ) Node( const HostAndPort& a , DBClientConnection* c )
: addr( a ) , conn(c) , ok(true) , : addr( a ) , conn(c) , ok(true) ,
ismaster(false), secondary( false ) , hidden( false ) , p ingTimeMillis(0) { ismaster(false), secondary( false ) , hidden( false ) , p ingTimeMillis(0) {
ok = conn.get() == NULL; ok = conn.get() == NULL;
skipping to change at line 214 skipping to change at line 259
/** Use this class to connect to a replica set of servers. The class w ill manage /** Use this class to connect to a replica set of servers. The class w ill manage
checking for which server in a replica set is master, and do failove r automatically. checking for which server in a replica set is master, and do failove r automatically.
This can also be used to connect to replica pairs since pairs are a subset of sets This can also be used to connect to replica pairs since pairs are a subset of sets
On a failover situation, expect at least one operation to return an error (throw On a failover situation, expect at least one operation to return an error (throw
an exception) before the failover is complete. Operations are not r etried. an exception) before the failover is complete. Operations are not r etried.
*/ */
class DBClientReplicaSet : public DBClientBase { class DBClientReplicaSet : public DBClientBase {
public: public:
using DBClientBase::query;
/** Call connect() after constructing. autoReconnect is always on f or DBClientReplicaSet connections. */ /** Call connect() after constructing. autoReconnect is always on f or DBClientReplicaSet connections. */
DBClientReplicaSet( const string& name , const vector<HostAndPort>& servers, double so_timeout=0 ); DBClientReplicaSet( const string& name , const vector<HostAndPort>& servers, double so_timeout=0 );
virtual ~DBClientReplicaSet(); virtual ~DBClientReplicaSet();
/** Returns false if nomember of the set were reachable, or neither is /** Returns false if nomember of the set were reachable, or neither is
* master, although, * master, although,
* when false returned, you can still try to use this connection ob ject, it will * when false returned, you can still try to use this connection ob ject, it will
* try reconnects. * try reconnects.
*/ */
bool connect(); bool connect();
 End of changes. 12 change blocks. 
11 lines changed or deleted 65 lines changed or added


 dbclientcursor.h   dbclientcursor.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 "../pch.h" #include "pch.h"
#include "../util/net/message.h"
#include "../db/jsobj.h"
#include "../db/json.h"
#include <stack> #include <stack>
#include "mongo/client/dbclientinterface.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
#include "mongo/util/net/message.h"
namespace mongo { namespace mongo {
class AScopedConnection; class AScopedConnection;
/** for mock purposes only -- do not create variants of DBClientCursor, nor hang code here /** for mock purposes only -- do not create variants of DBClientCursor, nor hang code here
@see DBClientMockCursor @see DBClientMockCursor
*/ */
class DBClientCursorInterface : boost::noncopyable { class DBClientCursorInterface : boost::noncopyable {
public: public:
virtual ~DBClientCursorInterface() {} virtual ~DBClientCursorInterface() {}
skipping to change at line 248 skipping to change at line 251
++_n; ++_n;
return _c.nextSafe(); return _c.nextSafe();
} }
int n() const { return _n; } int n() const { return _n; }
private: private:
DBClientCursor &_c; DBClientCursor &_c;
int _n; int _n;
}; };
} // namespace mongo } // namespace mongo
#include "undef_macros.h"
 End of changes. 3 change blocks. 
4 lines changed or deleted 7 lines changed or added


 dbhelpers.h   dbhelpers.h 
skipping to change at line 97 skipping to change at line 97
static void putSingleton(const char *ns, BSONObj obj); static void putSingleton(const char *ns, BSONObj obj);
static void putSingletonGod(const char *ns, BSONObj obj, bool logTh eOp); static void putSingletonGod(const char *ns, BSONObj obj, bool logTh eOp);
static bool getFirst(const char *ns, BSONObj& result) { return getS ingleton(ns, result); } static bool getFirst(const char *ns, BSONObj& result) { return getS ingleton(ns, result); }
static bool getLast(const char *ns, BSONObj& result); // get last o bject int he collection; e.g. {$natural : -1} static bool getLast(const char *ns, BSONObj& result); // get last o bject int he collection; e.g. {$natural : -1}
/** /**
* you have to lock * you have to lock
* you do not have to have Context set * you do not have to have Context set
* o has to have an _id field or will assert * o has to have an _id field or will assert
*/ */
static void upsert( const string& ns , const BSONObj& o ); static void upsert( const string& ns , const BSONObj& o, bool fromM igrate = false );
/** You do not need to set the database before calling. /** You do not need to set the database before calling.
@return true if collection is empty. @return true if collection is empty.
*/ */
static bool isEmpty(const char *ns, bool doAuth=true); static bool isEmpty(const char *ns, bool doAuth=true);
// TODO: this should be somewhere else probably // TODO: this should be somewhere else probably
static BSONObj toKeyFormat( const BSONObj& o , BSONObj& key ); static BSONObj toKeyFormat( const BSONObj& o , BSONObj& key );
class RemoveCallback { class RemoveCallback {
public: public:
virtual ~RemoveCallback() {} virtual ~RemoveCallback() {}
virtual void goingToDelete( const BSONObj& o ) = 0; virtual void goingToDelete( const BSONObj& o ) = 0;
}; };
/* removeRange: operation is oplog'd */
static long long removeRange( const string& ns , const BSONObj& min
, const BSONObj& max , bool yield = false , bool maxInclusive = false , Re
moveCallback * callback = 0 );
/* Remove all objects from a collection. /**
You do not need to set the database before calling. * Remove all documents in the range.
*/ * Does oplog the individual document deletions.
static void emptyCollection(const char *ns); */
static long long removeRange( const string& ns ,
}; const BSONObj& min ,
const BSONObj& max ,
bool yield = false ,
bool maxInclusive = false ,
RemoveCallback * callback = 0,
bool fromMigrate = false );
class Database; /**
* Remove all documents from a collection.
* You do not need to set the database before calling.
* Does not oplog the operation.
*/
static void emptyCollection(const char *ns);
// manage a set using collection backed storage
class DbSet {
public:
DbSet( const string &name = "", const BSONObj &key = BSONObj() ) :
name_( name ),
key_( key.getOwned() ) {
}
~DbSet();
void reset( const string &name = "", const BSONObj &key = BSONObj()
);
bool get( const BSONObj &obj ) const;
void set( const BSONObj &obj, bool val );
private:
string name_;
BSONObj key_;
}; };
/** /**
* user for saving deleted bson objects to a flat file * user for saving deleted bson objects to a flat file
*/ */
class RemoveSaver : public Helpers::RemoveCallback , boost::noncopyable { class RemoveSaver : public Helpers::RemoveCallback , boost::noncopyable {
public: public:
RemoveSaver( const string& type , const string& ns , const string& why); RemoveSaver( const string& type , const string& ns , const string& why);
~RemoveSaver(); ~RemoveSaver();
 End of changes. 5 change blocks. 
27 lines changed or deleted 18 lines changed or added


 dbmessage.h   dbmessage.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 "diskloc.h"
#include "jsobj.h" #include "jsobj.h"
#include "namespace-inl.h" #include "namespace-inl.h"
#include "../util/net/message.h" #include "../util/net/message.h"
#include "../client/constants.h" #include "../client/constants.h"
#include "instance.h" #include "instance.h"
namespace mongo { namespace mongo {
/* db response format /* db response format
skipping to change at line 220 skipping to change at line 219
return js; return js;
} }
const Message& msg() const { return m; } const Message& msg() const { return m; }
void markSet() { void markSet() {
mark = nextjsobj; mark = nextjsobj;
} }
void markReset() { void markReset() {
assert( mark ); verify( mark );
nextjsobj = mark; nextjsobj = mark;
} }
private: private:
const Message& m; const Message& m;
int* reserved; int* reserved;
const char *data; const char *data;
const char *nextjsobj; const char *nextjsobj;
const char *theEnd; const char *theEnd;
 End of changes. 2 change blocks. 
2 lines changed or deleted 1 lines changed or added


 dbtests.h   dbtests.h 
skipping to change at line 20 skipping to change at line 20
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "framework.h" #pragma once
#include "mongo/db/instance.h"
#include "mongo/unittest/unittest.h"
using namespace mongo; using namespace mongo;
using namespace mongo::regression; using namespace mongo::unittest;
using boost::shared_ptr; using boost::shared_ptr;
 End of changes. 2 change blocks. 
2 lines changed or deleted 5 lines changed or added


 debug_util.h   debug_util.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
#ifndef _WIN32
#include <signal.h>
#endif
namespace mongo { namespace mongo {
// for debugging // for debugging
typedef struct _Ints { typedef struct _Ints {
int i[100]; int i[100];
} *Ints; } *Ints;
typedef struct _Chars { typedef struct _Chars {
char c[200]; char c[200];
} *Chars; } *Chars;
typedef char CHARS[400]; typedef char CHARS[400];
typedef struct _OWS { typedef struct _OWS {
int size; int size;
char type; char type;
char string[400]; char string[400];
} *OWS; } *OWS;
#if defined(_DEBUG) #if defined(_DEBUG)
enum {DEBUG_BUILD = 1}; enum {DEBUG_BUILD = 1};
const bool debug=true;
#else #else
enum {DEBUG_BUILD = 0}; enum {DEBUG_BUILD = 0};
const bool debug=false;
#endif #endif
#define MONGO_DEV if( DEBUG_BUILD ) #define MONGO_DEV if( DEBUG_BUILD )
#define DEV MONGO_DEV #define DEV MONGO_DEV
#define MONGO_DEBUGGING if( 0 ) #define MONGO_DEBUGGING if( 0 )
#define DEBUGGING MONGO_DEBUGGING #define DEBUGGING MONGO_DEBUGGING
// The following declare one unique counter per enclosing function. // The following declare one unique counter per enclosing function.
// NOTE The implementation double-increments on a match, but we don't reall y care. // NOTE The implementation double-increments on a match, but we don't reall y care.
skipping to change at line 77 skipping to change at line 75
#if defined(_WIN32) #if defined(_WIN32)
inline int strcasecmp(const char* s1, const char* s2) {return _stricmp( s1, s2);} inline int strcasecmp(const char* s1, const char* s2) {return _stricmp( s1, s2);}
#endif #endif
// Sets SIGTRAP handler to launch GDB // Sets SIGTRAP handler to launch GDB
// Noop unless on *NIX and compiled with _DEBUG // Noop unless on *NIX and compiled with _DEBUG
void setupSIGTRAPforGDB(); void setupSIGTRAPforGDB();
extern int tlogLevel; extern int tlogLevel;
void mongo_breakpoint();
inline void breakpoint() { inline void breakpoint() {
if ( tlogLevel < 0 ) if ( tlogLevel < 0 )
return; return;
#ifdef _WIN32 mongo_breakpoint();
//DEV DebugBreak();
#endif
#ifndef _WIN32
// code to raise a breakpoint in GDB
ONCE {
//prevent SIGTRAP from crashing the program if default action i
s specified and we are not in gdb
struct sigaction current;
sigaction(SIGTRAP, NULL, &current);
if (current.sa_handler == SIG_DFL) {
signal(SIGTRAP, SIG_IGN);
}
}
raise(SIGTRAP);
#endif
}
// conditional breakpoint
inline void breakif(bool test) {
if (test)
breakpoint();
} }
} // namespace mongo } // namespace mongo
 End of changes. 6 change blocks. 
29 lines changed or deleted 4 lines changed or added


 dependency_tracker.h   dependency_tracker.h 
skipping to change at line 26 skipping to change at line 26
#pragma once #pragma once
#include "pch.h" #include "pch.h"
#include <boost/unordered_map.hpp> #include <boost/unordered_map.hpp>
#include "util/intrusive_counter.h" #include "util/intrusive_counter.h"
namespace mongo { namespace mongo {
class DocumentSource;
class DependencyTracker : class DependencyTracker :
public IntrusiveCounterUnsigned { public IntrusiveCounterUnsigned {
public: public:
void include(const string &fieldName); void addDependency(const string &fieldPath,
void exclude(const string &fieldName); const DocumentSource *pSource);
void removeDependency(const string &fieldPath);
bool isRequired(const string &fieldName) const; bool getDependency(intrusive_ptr<const DocumentSource> *ppSource,
const string &fieldPath) const;
private: private:
struct Tracker { struct Tracker {
string fieldName; Tracker(const string &fieldPath,
const DocumentSource *pSource);
string fieldPath;
intrusive_ptr<const DocumentSource> pSource;
struct Hash : struct Hash :
unary_function<string, size_t> { unary_function<string, size_t> {
size_t operator()(const string &rS) const; size_t operator()(const string &rS) const;
}; };
}; };
boost::unordered_map<string, Tracker, Tracker::Hash> map; typedef boost::unordered_map<string, Tracker, Tracker::Hash> MapTyp
e;
MapType map;
}; };
} }
/* ======================= INLINED IMPLEMENTATIONS ======================== == */ /* ======================= PRIVATE IMPLEMENTATIONS ======================== == */
namespace mongo { namespace mongo {
inline size_t DependencyTracker::Tracker::Hash::operator()( inline size_t DependencyTracker::Tracker::Hash::operator()(
const string &rS) const { const string &rS) const {
size_t seed = 0xf0afbeef; size_t seed = 0xf0afbeef;
boost::hash_combine(seed, rS); boost::hash_combine(seed, rS);
return seed; return seed;
} }
 End of changes. 6 change blocks. 
6 lines changed or deleted 17 lines changed or added


 diskloc.h   diskloc.h 
skipping to change at line 72 skipping to change at line 72
return ofs < -1 || return ofs < -1 ||
_a < -1 || _a < -1 ||
_a > 524288; _a > 524288;
} }
bool isNull() const { return _a == -1; } bool isNull() const { return _a == -1; }
void Null() { void Null() {
_a = -1; _a = -1;
ofs = 0; /* note NullOfs is different. todo clean up. see refs to NullOfs in code - use is valid but outside DiskLoc context so confusing as-is. */ ofs = 0; /* note NullOfs is different. todo clean up. see refs to NullOfs in code - use is valid but outside DiskLoc context so confusing as-is. */
} }
void assertOk() { assert(!isNull()); } void assertOk() { verify(!isNull()); }
void setInvalid() { void setInvalid() {
_a = -2; _a = -2;
ofs = 0; ofs = 0;
} }
bool isValid() const { return _a != -2; } bool isValid() const { return _a != -2; }
string toString() const { string toString() const {
if ( isNull() ) if ( isNull() )
return "null"; return "null";
stringstream ss; stringstream ss;
skipping to change at line 99 skipping to change at line 99
int a() const { return _a; } int a() const { return _a; }
int& GETOFS() { return ofs; } int& GETOFS() { return ofs; }
int getOfs() const { return ofs; } int getOfs() const { return ofs; }
void set(int a, int b) { void set(int a, int b) {
_a=a; _a=a;
ofs=b; ofs=b;
} }
void inc(int amt) { void inc(int amt) {
assert( !isNull() ); verify( !isNull() );
ofs += amt; ofs += amt;
} }
bool sameFile(DiskLoc b) { bool sameFile(DiskLoc b) {
return _a== b._a; return _a== b._a;
} }
bool operator==(const DiskLoc& b) const { bool operator==(const DiskLoc& b) const {
return _a==b._a&& ofs == b.ofs; return _a==b._a&& ofs == b.ofs;
} }
bool operator!=(const DiskLoc& b) const { bool operator!=(const DiskLoc& b) const {
return !(*this==b); return !(*this==b);
} }
const DiskLoc& operator=(const DiskLoc& b) { const DiskLoc& operator=(const DiskLoc& b) {
_a=b._a; _a=b._a;
ofs = b.ofs; ofs = b.ofs;
//assert(ofs!=0); //verify(ofs!=0);
return *this; return *this;
} }
int compare(const DiskLoc& b) const { int compare(const DiskLoc& b) const {
int x = _a - b._a; int x = _a - b._a;
if ( x ) if ( x )
return x; return x;
return ofs - b.ofs; return ofs - b.ofs;
} }
bool operator<(const DiskLoc& b) const { bool operator<(const DiskLoc& b) const {
return compare(b) < 0; return compare(b) < 0;
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 distlock.h   distlock.h 
skipping to change at line 21 skipping to change at line 21
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "dbclient.h"
#include "connpool.h" #include "connpool.h"
#include "redef_macros.h"
#include "syncclusterconnection.h" #include "syncclusterconnection.h"
#define LOCK_TIMEOUT (15 * 60 * 1000) #define LOCK_TIMEOUT (15 * 60 * 1000)
#define LOCK_SKEW_FACTOR (30) #define LOCK_SKEW_FACTOR (30)
#define LOCK_PING (LOCK_TIMEOUT / LOCK_SKEW_FACTOR) #define LOCK_PING (LOCK_TIMEOUT / LOCK_SKEW_FACTOR)
#define MAX_LOCK_NET_SKEW (LOCK_TIMEOUT / LOCK_SKEW_FACTOR) #define MAX_LOCK_NET_SKEW (LOCK_TIMEOUT / LOCK_SKEW_FACTOR)
#define MAX_LOCK_CLOCK_SKEW (LOCK_TIMEOUT / LOCK_SKEW_FACTOR) #define MAX_LOCK_CLOCK_SKEW (LOCK_TIMEOUT / LOCK_SKEW_FACTOR)
#define NUM_LOCK_SKEW_CHECKS (3) #define NUM_LOCK_SKEW_CHECKS (3)
// The maximum clock skew we need to handle between config servers is // The maximum clock skew we need to handle between config servers is
skipping to change at line 230 skipping to change at line 228
return *this; return *this;
} }
dist_lock_try( DistributedLock * lock , string why ) dist_lock_try( DistributedLock * lock , string why )
: _lock(lock), _why(why) { : _lock(lock), _why(why) {
_got = _lock->lock_try( why , false , &_other ); _got = _lock->lock_try( why , false , &_other );
} }
~dist_lock_try() { ~dist_lock_try() {
if ( _got ) { if ( _got ) {
assert( ! _other.isEmpty() ); verify( ! _other.isEmpty() );
_lock->unlock( &_other ); _lock->unlock( &_other );
} }
} }
bool reestablish(){ bool reestablish(){
return retry(); return retry();
} }
bool retry() { bool retry() {
assert( _lock ); verify( _lock );
assert( _got ); verify( _got );
assert( ! _other.isEmpty() ); verify( ! _other.isEmpty() );
return _got = _lock->lock_try( _why , true, &_other ); return _got = _lock->lock_try( _why , true, &_other );
} }
bool got() const { return _got; } bool got() const { return _got; }
BSONObj other() const { return _other; } BSONObj other() const { return _other; }
private: private:
DistributedLock * _lock; DistributedLock * _lock;
bool _got; bool _got;
 End of changes. 4 change blocks. 
6 lines changed or deleted 4 lines changed or added


 document.h   document.h 
skipping to change at line 25 skipping to change at line 25
*/ */
#pragma once #pragma once
#include "pch.h" #include "pch.h"
#include "util/intrusive_counter.h" #include "util/intrusive_counter.h"
namespace mongo { namespace mongo {
class BSONObj; class BSONObj;
class DependencyTracker;
class FieldIterator; class FieldIterator;
class Value; class Value;
class Document : class Document :
public IntrusiveCounterUnsigned { public IntrusiveCounterUnsigned {
public: public:
~Document(); ~Document();
/* /*
Create a new Document from the given BSONObj. Create a new Document from the given BSONObj.
Document field values may be pointed to in the BSONObj, so it Document field values may be pointed to in the BSONObj, so it
must live at least as long as the resulting Document. must live at least as long as the resulting Document.
LATER - use an abstract class for the dependencies; something lik
e
a "lookup(const string &fieldName)" so there can be other
implementations.
@returns shared pointer to the newly created Document @returns shared pointer to the newly created Document
*/ */
static intrusive_ptr<Document> createFromBsonObj(BSONObj *pBsonObj) static intrusive_ptr<Document> createFromBsonObj(
; BSONObj *pBsonObj, const DependencyTracker *pDependencies = NUL
L);
/* /*
Create a new empty Document. Create a new empty Document.
@param sizeHint a hint at what the number of fields will be; if @param sizeHint a hint at what the number of fields will be; if
known, this can be used to increase memory allocation efficienc y known, this can be used to increase memory allocation efficienc y
@returns shared pointer to the newly created Document @returns shared pointer to the newly created Document
*/ */
static intrusive_ptr<Document> create(size_t sizeHint = 0); static intrusive_ptr<Document> create(size_t sizeHint = 0);
skipping to change at line 187 skipping to change at line 193
boost classes such as unordered_map<>. boost classes such as unordered_map<>.
@param seed value to augment with this' hash @param seed value to augment with this' hash
*/ */
void hash_combine(size_t &seed) const; void hash_combine(size_t &seed) const;
private: private:
friend class FieldIterator; friend class FieldIterator;
Document(size_t sizeHint); Document(size_t sizeHint);
Document(BSONObj *pBsonObj); Document(BSONObj *pBsonObj, const DependencyTracker *pDependencies) ;
/* these two vectors parallel each other */ /* these two vectors parallel each other */
vector<string> vFieldName; vector<string> vFieldName;
vector<intrusive_ptr<const Value> > vpValue; vector<intrusive_ptr<const Value> > vpValue;
}; };
class FieldIterator : class FieldIterator :
boost::noncopyable { boost::noncopyable {
public: public:
/* /*
skipping to change at line 240 skipping to change at line 246
/* ======================= INLINED IMPLEMENTATIONS ======================== == */ /* ======================= INLINED IMPLEMENTATIONS ======================== == */
namespace mongo { namespace mongo {
inline size_t Document::getFieldCount() const { inline size_t Document::getFieldCount() const {
return vFieldName.size(); return vFieldName.size();
} }
inline Document::FieldPair Document::getField(size_t index) const { inline Document::FieldPair Document::getField(size_t index) const {
assert( index < vFieldName.size() ); verify( index < vFieldName.size() );
return FieldPair(vFieldName[index], vpValue[index]); return FieldPair(vFieldName[index], vpValue[index]);
} }
} }
 End of changes. 5 change blocks. 
4 lines changed or deleted 11 lines changed or added


 document_source.h   document_source.h 
skipping to change at line 24 skipping to change at line 24
* 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 <boost/unordered_map.hpp> #include <boost/unordered_map.hpp>
#include "util/intrusive_counter.h" #include "util/intrusive_counter.h"
#include "client/parallel.h" #include "client/parallel.h"
#include "db/clientcursor.h"
#include "db/jsobj.h" #include "db/jsobj.h"
#include "db/pipeline/dependency_tracker.h"
#include "db/pipeline/document.h" #include "db/pipeline/document.h"
#include "db/pipeline/expression.h" #include "db/pipeline/expression.h"
#include "db/pipeline/value.h" #include "db/pipeline/value.h"
#include "util/string_writer.h" #include "util/string_writer.h"
namespace mongo { namespace mongo {
class Accumulator; class Accumulator;
class Cursor; class Cursor;
class DependencyTracker; class DependencyTracker;
class Document; class Document;
skipping to change at line 48 skipping to change at line 50
class ExpressionObject; class ExpressionObject;
class Matcher; class Matcher;
class DocumentSource : class DocumentSource :
public IntrusiveCounterUnsigned, public IntrusiveCounterUnsigned,
public StringWriter { public StringWriter {
public: public:
virtual ~DocumentSource(); virtual ~DocumentSource();
// virtuals from StringWriter // virtuals from StringWriter
virtual void writeString(stringstream &ss) const;
/** /**
Write out a string representation of this pipeline operator. Set the step for a user-specified pipeline step.
@param ss string stream to write the string representation to The step is used for diagnostics.
*/
virtual void writeString(stringstream &ss) const; @param step step number 0 to n.
*/
void setPipelineStep(int step);
/**
Get the user-specified pipeline step.
@returns the step number, or -1 if it has never been set
*/
int getPipelineStep() const;
/** /**
Is the source at EOF? Is the source at EOF?
@returns true if the source has no more Documents to return. @returns true if the source has no more Documents to return.
*/ */
virtual bool eof() = 0; virtual bool eof() = 0;
/** /**
Advance the state of the DocumentSource so that it will return th e Advance the state of the DocumentSource so that it will return th e
next Document. next Document.
The default implementation returns false, after checking for
interrupts. Derived classes can call the default implementation
in their own implementations in order to check for interrupts.
@returns whether there is another document to fetch, i.e., whethe r or @returns whether there is another document to fetch, i.e., whethe r or
not getCurrent() will succeed. not getCurrent() will succeed. This default implementation alw
ays
returns false.
*/ */
virtual bool advance() = 0; virtual bool advance();
/** /**
Advance the source, and return the next Expression. Advance the source, and return the next Expression.
@returns the current Document @returns the current Document
TODO throws an exception if there are no more expressions to retu rn. TODO throws an exception if there are no more expressions to retu rn.
*/ */
virtual intrusive_ptr<Document> getCurrent() = 0; virtual intrusive_ptr<Document> getCurrent() = 0;
/** /**
Get the source's name.
@returns the string name of the source as a constant string;
this is static, and there's no need to worry about adopting it
*/
virtual const char *getSourceName() const;
/**
Set the underlying source this source should use to get Documents Set the underlying source this source should use to get Documents
from. from.
It is an error to set the source more than once. This is to It is an error to set the source more than once. This is to
prevent changing sources once the original source has been starte d; prevent changing sources once the original source has been starte d;
this could break the state maintained by the DocumentSource. this could break the state maintained by the DocumentSource.
This pointer is not reference counted because that has led to
some circular references. As a result, this doesn't keep
sources alive, and is only intended to be used temporarily for
the lifetime of a Pipeline::run().
@param pSource the underlying source to use @param pSource the underlying source to use
*/ */
virtual void setSource(const intrusive_ptr<DocumentSource> &pSource ); virtual void setSource(DocumentSource *pSource);
/** /**
Attempt to coalesce this DocumentSource with its successor in the Attempt to coalesce this DocumentSource with its successor in the
document processing pipeline. If successful, the successor document processing pipeline. If successful, the successor
DocumentSource should be removed from the pipeline and discarded. DocumentSource should be removed from the pipeline and discarded.
If successful, this operation can be applied repeatedly, in an If successful, this operation can be applied repeatedly, in an
attempt to coalesce several sources together. attempt to coalesce several sources together.
The default implementation is to do nothing, and return false. The default implementation is to do nothing, and return false.
skipping to change at line 122 skipping to change at line 153
This is intended for any operations that include expressions, and This is intended for any operations that include expressions, and
provides a hook for those to optimize those operations. provides a hook for those to optimize those operations.
The default implementation is to do nothing. The default implementation is to do nothing.
*/ */
virtual void optimize(); virtual void optimize();
/** /**
Adjust dependencies according to the needs of this source. Adjust dependencies according to the needs of this source.
$$$ $$$ MONGO_LATER_SERVER_4644
@param pTracker the dependency tracker @param pTracker the dependency tracker
*/ */
virtual void manageDependencies( virtual void manageDependencies(
const intrusive_ptr<DependencyTracker> &pTracker); const intrusive_ptr<DependencyTracker> &pTracker);
/** /**
Add the DocumentSource to the array builder. Add the DocumentSource to the array builder.
The default implementation calls sourceToBson() in order to The default implementation calls sourceToBson() in order to
convert the inner part of the object which will be added to the convert the inner part of the object which will be added to the
array being built here. array being built here.
@param pBuilder the array builder to add the operation to. @param pBuilder the array builder to add the operation to.
*/ */
virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const; virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const;
protected: protected:
/** /**
Base constructor.
*/
DocumentSource(const intrusive_ptr<ExpressionContext> &pExpCtx);
/**
Create an object that represents the document source. The object Create an object that represents the document source. The object
will have a single field whose name is the source's name. This will have a single field whose name is the source's name. This
will be used by the default implementation of addToBsonArray() will be used by the default implementation of addToBsonArray()
to add this object to a pipeline being represented in BSON. to add this object to a pipeline being represented in BSON.
@param pBuilder a blank object builder to write to @param pBuilder a blank object builder to write to
*/ */
virtual void sourceToBson(BSONObjBuilder *pBuilder) const = 0; virtual void sourceToBson(BSONObjBuilder *pBuilder) const = 0;
/* /*
Most DocumentSources have an underlying source they get their dat a Most DocumentSources have an underlying source they get their dat a
from. This is a convenience for them. from. This is a convenience for them.
The default implementation of setSource() sets this; if you don't The default implementation of setSource() sets this; if you don't
need a source, override that to assert(). The default is to need a source, override that to verify(). The default is to
assert() if this has already been set. verify() if this has already been set.
*/ */
intrusive_ptr<DocumentSource> pSource; DocumentSource *pSource;
/*
The zero-based user-specified pipeline step. Used for diagnostic
s.
Will be set to -1 for artificial pipeline steps that were not par
t
of the original user specification.
*/
int step;
intrusive_ptr<ExpressionContext> pExpCtx;
}; };
class DocumentSourceBsonArray : class DocumentSourceBsonArray :
public DocumentSource { public DocumentSource {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceBsonArray(); virtual ~DocumentSourceBsonArray();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual intrusive_ptr<Document> getCurrent(); virtual intrusive_ptr<Document> getCurrent();
virtual void setSource(const intrusive_ptr<DocumentSource> &pSource ); virtual void setSource(DocumentSource *pSource);
/** /**
Create a document source based on a BSON array. Create a document source based on a BSON array.
This is usually put at the beginning of a chain of document sourc es This is usually put at the beginning of a chain of document sourc es
in order to fetch data from the database. in order to fetch data from the database.
CAUTION: the BSON is not read until the source is used. Any CAUTION: the BSON is not read until the source is used. Any
elements that appear after these documents must not be read until elements that appear after these documents must not be read until
this source is exhausted. this source is exhausted.
@param pBsonElement the BSON array to treat as a document source @param pBsonElement the BSON array to treat as a document source
@param pExpCtx the expression context for the pipeline
@returns the newly created document source @returns the newly created document source
*/ */
static intrusive_ptr<DocumentSourceBsonArray> create( static intrusive_ptr<DocumentSourceBsonArray> create(
BSONElement *pBsonElement); BSONElement *pBsonElement,
const intrusive_ptr<ExpressionContext> &pExpCtx);
protected: protected:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual void sourceToBson(BSONObjBuilder *pBuilder) const; virtual void sourceToBson(BSONObjBuilder *pBuilder) const;
private: private:
DocumentSourceBsonArray(BSONElement *pBsonElement); DocumentSourceBsonArray(BSONElement *pBsonElement,
const intrusive_ptr<ExpressionContext> &pExpCtx);
BSONObj embeddedObject; BSONObj embeddedObject;
BSONObjIterator arrayIterator; BSONObjIterator arrayIterator;
BSONElement currentElement; BSONElement currentElement;
bool haveCurrent; bool haveCurrent;
}; };
class DocumentSourceCommandFutures : class DocumentSourceCommandFutures :
public DocumentSource { public DocumentSource {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceCommandFutures(); virtual ~DocumentSourceCommandFutures();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual intrusive_ptr<Document> getCurrent(); virtual intrusive_ptr<Document> getCurrent();
virtual void setSource(const intrusive_ptr<DocumentSource> &pSource ); virtual void setSource(DocumentSource *pSource);
/* convenient shorthand for a commonly used type */ /* convenient shorthand for a commonly used type */
typedef list<shared_ptr<Future::CommandResult> > FuturesList; typedef list<shared_ptr<Future::CommandResult> > FuturesList;
/** /**
Create a DocumentSource that wraps a list of Command::Futures. Create a DocumentSource that wraps a list of Command::Futures.
@param errmsg place to write error messages to; must exist for th e @param errmsg place to write error messages to; must exist for th e
lifetime of the created DocumentSourceCommandFutures lifetime of the created DocumentSourceCommandFutures
@param pList the list of futures @param pList the list of futures
@param pExpCtx the expression context for the pipeline
@returns the newly created DocumentSource
*/ */
static intrusive_ptr<DocumentSourceCommandFutures> create( static intrusive_ptr<DocumentSourceCommandFutures> create(
string &errmsg, FuturesList *pList); string &errmsg, FuturesList *pList,
const intrusive_ptr<ExpressionContext> &pExpCtx);
protected: protected:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual void sourceToBson(BSONObjBuilder *pBuilder) const; virtual void sourceToBson(BSONObjBuilder *pBuilder) const;
private: private:
DocumentSourceCommandFutures(string &errmsg, FuturesList *pList); DocumentSourceCommandFutures(string &errmsg, FuturesList *pList,
const intrusive_ptr<ExpressionContext> &pExpCtx);
/** /**
Advance to the next document, setting pCurrent appropriately. Advance to the next document, setting pCurrent appropriately.
Adjusts pCurrent, pBsonSource, and iterator, as needed. On exit, Adjusts pCurrent, pBsonSource, and iterator, as needed. On exit,
pCurrent is the Document to return, or NULL. If NULL, this pCurrent is the Document to return, or NULL. If NULL, this
indicates there is nothing more to return. indicates there is nothing more to return.
*/ */
void getNextDocument(); void getNextDocument();
skipping to change at line 255 skipping to change at line 307
}; };
class DocumentSourceCursor : class DocumentSourceCursor :
public DocumentSource { public DocumentSource {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceCursor(); virtual ~DocumentSourceCursor();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual intrusive_ptr<Document> getCurrent(); virtual intrusive_ptr<Document> getCurrent();
virtual void setSource(const intrusive_ptr<DocumentSource> &pSource virtual void setSource(DocumentSource *pSource);
); virtual void manageDependencies(
const intrusive_ptr<DependencyTracker> &pTracker);
/** /**
Create a document source based on a cursor. Create a document source based on a cursor.
This is usually put at the beginning of a chain of document sourc es This is usually put at the beginning of a chain of document sourc es
in order to fetch data from the database. in order to fetch data from the database.
@param pCursor the cursor to use to fetch data @param pCursor the cursor to use to fetch data
@param pExpCtx the expression context for the pipeline
*/ */
static intrusive_ptr<DocumentSourceCursor> create( static intrusive_ptr<DocumentSourceCursor> create(
const shared_ptr<Cursor> &pCursor); const shared_ptr<Cursor> &pCursor,
const string &ns,
const intrusive_ptr<ExpressionContext> &pExpCtx);
/** /**
Add a BSONObj dependency. Add a BSONObj dependency.
Some Cursor creation functions rely on BSON objects to specify Some Cursor creation functions rely on BSON objects to specify
their query predicate or sort. These often take a BSONObj their query predicate or sort. These often take a BSONObj
by reference for these, but to not copy it. As a result, the by reference for these, but to not copy it. As a result, the
BSONObjs specified must outlive the Cursor. In order to ensure BSONObjs specified must outlive the Cursor. In order to ensure
that, use this to preserve a pointer to the BSONObj here. that, use this to preserve a pointer to the BSONObj here.
skipping to change at line 297 skipping to change at line 354
@param pBsonObj pointer to the BSON object to preserve @param pBsonObj pointer to the BSON object to preserve
*/ */
void addBsonDependency(const shared_ptr<BSONObj> &pBsonObj); void addBsonDependency(const shared_ptr<BSONObj> &pBsonObj);
protected: protected:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual void sourceToBson(BSONObjBuilder *pBuilder) const; virtual void sourceToBson(BSONObjBuilder *pBuilder) const;
private: private:
DocumentSourceCursor(const shared_ptr<Cursor> &pTheCursor); DocumentSourceCursor(
const shared_ptr<Cursor> &pTheCursor, const string &ns,
const intrusive_ptr<ExpressionContext> &pExpCtx);
void findNext(); void findNext();
intrusive_ptr<Document> pCurrent; intrusive_ptr<Document> pCurrent;
/* /*
The bsonDependencies must outlive the Cursor wrapped by this The bsonDependencies must outlive the Cursor wrapped by this
source. Therefore, bsonDependencies must appear before pCursor source. Therefore, bsonDependencies must appear before pCursor
in order its destructor to be called *after* pCursor's. in order cause its destructor to be called *after* pCursor's.
*/ */
vector<shared_ptr<BSONObj> > bsonDependencies; vector<shared_ptr<BSONObj> > bsonDependencies;
shared_ptr<Cursor> pCursor; shared_ptr<Cursor> pCursor;
/*
In order to yield, we need a ClientCursor.
*/
ClientCursor::CleanupPointer pClientCursor;
/*
Advance the cursor, and yield sometimes.
If the state of the world changed during the yield such that we
are unable to continue execution of the query, this will release
the
client cursor, and throw an error.
*/
void advanceAndYield();
/*
This document source hangs on to the dependency tracker when it
gets it so that it can be used for selective reification of
fields in order to avoid fields that are not required through the
pipeline.
*/
intrusive_ptr<DependencyTracker> pDependencies;
}; };
/* /*
This contains all the basic mechanics for filtering a stream of This contains all the basic mechanics for filtering a stream of
Documents, except for the actual predicate evaluation itself. This w as Documents, except for the actual predicate evaluation itself. This w as
factored out so we could create DocumentSources that use both Matcher factored out so we could create DocumentSources that use both Matcher
style predicates as well as full Expressions. style predicates as well as full Expressions.
*/ */
class DocumentSourceFilterBase : class DocumentSourceFilterBase :
public DocumentSource { public DocumentSource {
skipping to change at line 340 skipping to change at line 421
as early a point as possible in the document processing pipeline. as early a point as possible in the document processing pipeline.
See db/Matcher.h and the associated wiki documentation for the See db/Matcher.h and the associated wiki documentation for the
format. This conversion is used to move back to the low-level format. This conversion is used to move back to the low-level
find() Cursor mechanism. find() Cursor mechanism.
@param pBuilder the builder to write to @param pBuilder the builder to write to
*/ */
virtual void toMatcherBson(BSONObjBuilder *pBuilder) const = 0; virtual void toMatcherBson(BSONObjBuilder *pBuilder) const = 0;
protected: protected:
DocumentSourceFilterBase(); DocumentSourceFilterBase(
const intrusive_ptr<ExpressionContext> &pExpCtx);
/** /**
Test the given document against the predicate and report if it Test the given document against the predicate and report if it
should be accepted or not. should be accepted or not.
@param pDocument the document to test @param pDocument the document to test
@returns true if the document matches the filter, false otherwise @returns true if the document matches the filter, false otherwise
*/ */
virtual bool accept(const intrusive_ptr<Document> &pDocument) const = 0; virtual bool accept(const intrusive_ptr<Document> &pDocument) const = 0;
skipping to change at line 367 skipping to change at line 449
intrusive_ptr<Document> pCurrent; intrusive_ptr<Document> pCurrent;
}; };
class DocumentSourceFilter : class DocumentSourceFilter :
public DocumentSourceFilterBase { public DocumentSourceFilterBase {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceFilter(); virtual ~DocumentSourceFilter();
virtual bool coalesce(const intrusive_ptr<DocumentSource> &pNextSou rce); virtual bool coalesce(const intrusive_ptr<DocumentSource> &pNextSou rce);
virtual void optimize(); virtual void optimize();
virtual const char *getSourceName() const;
/** /**
Create a filter. Create a filter.
@param pBsonElement the raw BSON specification for the filter @param pBsonElement the raw BSON specification for the filter
@param pExpCtx the expression context for the pipeline
@returns the filter @returns the filter
*/ */
static intrusive_ptr<DocumentSource> createFromBson( static intrusive_ptr<DocumentSource> createFromBson(
BSONElement *pBsonElement, BSONElement *pBsonElement,
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
/** /**
Create a filter. Create a filter.
@param pFilter the expression to use to filter @param pFilter the expression to use to filter
@param pExpCtx the expression context for the pipeline
@returns the filter @returns the filter
*/ */
static intrusive_ptr<DocumentSourceFilter> create( static intrusive_ptr<DocumentSourceFilter> create(
const intrusive_ptr<Expression> &pFilter); const intrusive_ptr<Expression> &pFilter,
const intrusive_ptr<ExpressionContext> &pExpCtx);
/** /**
Create a BSONObj suitable for Matcher construction. Create a BSONObj suitable for Matcher construction.
This is used after filter analysis has moved as many filters to This is used after filter analysis has moved as many filters to
as early a point as possible in the document processing pipeline. as early a point as possible in the document processing pipeline.
See db/Matcher.h and the associated wiki documentation for the See db/Matcher.h and the associated wiki documentation for the
format. This conversion is used to move back to the low-level format. This conversion is used to move back to the low-level
find() Cursor mechanism. find() Cursor mechanism.
skipping to change at line 410 skipping to change at line 496
static const char filterName[]; static const char filterName[];
protected: protected:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual void sourceToBson(BSONObjBuilder *pBuilder) const; virtual void sourceToBson(BSONObjBuilder *pBuilder) const;
// virtuals from DocumentSourceFilterBase // virtuals from DocumentSourceFilterBase
virtual bool accept(const intrusive_ptr<Document> &pDocument) const ; virtual bool accept(const intrusive_ptr<Document> &pDocument) const ;
private: private:
DocumentSourceFilter(const intrusive_ptr<Expression> &pFilter); DocumentSourceFilter(const intrusive_ptr<Expression> &pFilter,
const intrusive_ptr<ExpressionContext> &pExpCt
x);
intrusive_ptr<Expression> pFilter; intrusive_ptr<Expression> pFilter;
}; };
class DocumentSourceGroup : class DocumentSourceGroup :
public DocumentSource { public DocumentSource {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceGroup(); virtual ~DocumentSourceGroup();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual const char *getSourceName() const;
virtual intrusive_ptr<Document> getCurrent(); virtual intrusive_ptr<Document> getCurrent();
/** /**
Create a new grouping DocumentSource. Create a new grouping DocumentSource.
@param pCtx the expression context @param pExpCtx the expression context for the pipeline
@returns the DocumentSource @returns the DocumentSource
*/ */
static intrusive_ptr<DocumentSourceGroup> create( static intrusive_ptr<DocumentSourceGroup> create(
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
/** /**
Set the Id Expression. Set the Id Expression.
Documents that pass through the grouping Document are grouped Documents that pass through the grouping Document are grouped
according to this key. This will generate the id_ field in the according to this key. This will generate the id_ field in the
result documents. result documents.
@param pExpression the group key @param pExpression the group key
*/ */
skipping to change at line 469 skipping to change at line 557
const intrusive_ptr<Expression> &pExpression); const intrusive_ptr<Expression> &pExpression);
/** /**
Create a grouping DocumentSource from BSON. Create a grouping DocumentSource from BSON.
This is a convenience method that uses the above, and operates on This is a convenience method that uses the above, and operates on
a BSONElement that has been deteremined to be an Object with an a BSONElement that has been deteremined to be an Object with an
element named $group. element named $group.
@param pBsonElement the BSONELement that defines the group @param pBsonElement the BSONELement that defines the group
@param pCtx the expression context @param pExpCtx the expression context
@returns the grouping DocumentSource @returns the grouping DocumentSource
*/ */
static intrusive_ptr<DocumentSource> createFromBson( static intrusive_ptr<DocumentSource> createFromBson(
BSONElement *pBsonElement, BSONElement *pBsonElement,
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
/** /**
Create a unifying group that can be used to combine group results Create a unifying group that can be used to combine group results
from shards. from shards.
@returns the grouping DocumentSource @returns the grouping DocumentSource
*/ */
intrusive_ptr<DocumentSource> createMerger(); intrusive_ptr<DocumentSource> createMerger();
static const char groupName[]; static const char groupName[];
protected: protected:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual void sourceToBson(BSONObjBuilder *pBuilder) const; virtual void sourceToBson(BSONObjBuilder *pBuilder) const;
private: private:
DocumentSourceGroup(const intrusive_ptr<ExpressionContext> &pCtx); DocumentSourceGroup(const intrusive_ptr<ExpressionContext> &pExpCtx );
/* /*
Before returning anything, this source must fetch everything from Before returning anything, this source must fetch everything from
the underlying source and group it. populate() is used to do tha t the underlying source and group it. populate() is used to do tha t
on the first call to any method on this source. The populated on the first call to any method on this source. The populated
boolean indicates that this has been done. boolean indicates that this has been done.
*/ */
void populate(); void populate();
bool populated; bool populated;
skipping to change at line 530 skipping to change at line 618
vector<string> vFieldName; vector<string> vFieldName;
vector<intrusive_ptr<Accumulator> (*)( vector<intrusive_ptr<Accumulator> (*)(
const intrusive_ptr<ExpressionContext> &)> vpAccumulatorFactory ; const intrusive_ptr<ExpressionContext> &)> vpAccumulatorFactory ;
vector<intrusive_ptr<Expression> > vpExpression; vector<intrusive_ptr<Expression> > vpExpression;
intrusive_ptr<Document> makeDocument( intrusive_ptr<Document> makeDocument(
const GroupsType::iterator &rIter); const GroupsType::iterator &rIter);
GroupsType::iterator groupsIterator; GroupsType::iterator groupsIterator;
intrusive_ptr<Document> pCurrent; intrusive_ptr<Document> pCurrent;
intrusive_ptr<ExpressionContext> pCtx;
}; };
class DocumentSourceMatch : class DocumentSourceMatch :
public DocumentSourceFilterBase { public DocumentSourceFilterBase {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceMatch(); virtual ~DocumentSourceMatch();
virtual const char *getSourceName() const;
virtual void manageDependencies(
const intrusive_ptr<DependencyTracker> &pTracker);
/** /**
Create a filter. Create a filter.
@param pBsonElement the raw BSON specification for the filter @param pBsonElement the raw BSON specification for the filter
@returns the filter @returns the filter
*/ */
static intrusive_ptr<DocumentSource> createFromBson( static intrusive_ptr<DocumentSource> createFromBson(
BSONElement *pBsonElement, BSONElement *pBsonElement,
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pCtx);
skipping to change at line 573 skipping to change at line 662
static const char matchName[]; static const char matchName[];
protected: protected:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual void sourceToBson(BSONObjBuilder *pBuilder) const; virtual void sourceToBson(BSONObjBuilder *pBuilder) const;
// virtuals from DocumentSourceFilterBase // virtuals from DocumentSourceFilterBase
virtual bool accept(const intrusive_ptr<Document> &pDocument) const ; virtual bool accept(const intrusive_ptr<Document> &pDocument) const ;
private: private:
DocumentSourceMatch(const BSONObj &query); DocumentSourceMatch(const BSONObj &query,
const intrusive_ptr<ExpressionContext> &pExpCtx);
Matcher matcher; Matcher matcher;
}; };
class DocumentSourceOut : class DocumentSourceOut :
public DocumentSource { public DocumentSource {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceOut(); virtual ~DocumentSourceOut();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual const char *getSourceName() const;
virtual intrusive_ptr<Document> getCurrent(); virtual intrusive_ptr<Document> getCurrent();
/** /**
Create a document source for output and pass-through. Create a document source for output and pass-through.
This can be put anywhere in a pipeline and will store content as This can be put anywhere in a pipeline and will store content as
well as pass it on. well as pass it on.
@param pBsonElement the raw BSON specification for the source
@param pExpCtx the expression context for the pipeline
@returns the newly created document source @returns the newly created document source
*/ */
static intrusive_ptr<DocumentSourceOut> createFromBson( static intrusive_ptr<DocumentSourceOut> createFromBson(
BSONElement *pBsonElement); BSONElement *pBsonElement,
const intrusive_ptr<ExpressionContext> &pExpCtx);
static const char outName[]; static const char outName[];
protected: protected:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual void sourceToBson(BSONObjBuilder *pBuilder) const; virtual void sourceToBson(BSONObjBuilder *pBuilder) const;
private: private:
DocumentSourceOut(BSONElement *pBsonElement); DocumentSourceOut(BSONElement *pBsonElement,
const intrusive_ptr<ExpressionContext> &pExpCtx);
}; };
class DocumentSourceProject : class DocumentSourceProject :
public DocumentSource, public DocumentSource {
public boost::enable_shared_from_this<DocumentSourceProject> {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceProject(); virtual ~DocumentSourceProject();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual const char *getSourceName() const;
virtual intrusive_ptr<Document> getCurrent(); virtual intrusive_ptr<Document> getCurrent();
virtual void optimize(); virtual void optimize();
virtual void manageDependencies(
const intrusive_ptr<DependencyTracker> &pTracker);
/** /**
Create a new DocumentSource that can implement projection. Create a new DocumentSource that can implement projection.
@param pExpCtx the expression context for the pipeline
@returns the projection DocumentSource @returns the projection DocumentSource
*/ */
static intrusive_ptr<DocumentSourceProject> create(); static intrusive_ptr<DocumentSourceProject> create(
const intrusive_ptr<ExpressionContext> &pExpCtx);
/** /**
Include a field path in a projection. Include a field path in a projection.
@param fieldPath the path of the field to include @param fieldPath the path of the field to include
*/ */
void includePath(const string &fieldPath); void includePath(const string &fieldPath);
/** /**
Exclude a field path from the projection. Exclude a field path from the projection.
skipping to change at line 659 skipping to change at line 758
void addField(const string &fieldName, void addField(const string &fieldName,
const intrusive_ptr<Expression> &pExpression); const intrusive_ptr<Expression> &pExpression);
/** /**
Create a new projection DocumentSource from BSON. Create a new projection DocumentSource from BSON.
This is a convenience for directly handling BSON, and relies on t he This is a convenience for directly handling BSON, and relies on t he
above methods. above methods.
@param pBsonElement the BSONElement with an object named $project @param pBsonElement the BSONElement with an object named $project
@param pExpCtx the expression context for the pipeline
@returns the created projection @returns the created projection
*/ */
static intrusive_ptr<DocumentSource> createFromBson( static intrusive_ptr<DocumentSource> createFromBson(
BSONElement *pBsonElement, BSONElement *pBsonElement,
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
static const char projectName[]; static const char projectName[];
protected: protected:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual void sourceToBson(BSONObjBuilder *pBuilder) const; virtual void sourceToBson(BSONObjBuilder *pBuilder) const;
private: private:
DocumentSourceProject(); DocumentSourceProject(const intrusive_ptr<ExpressionContext> &pExpC tx);
// configuration state // configuration state
bool excludeId; bool excludeId;
intrusive_ptr<ExpressionObject> pEO; intrusive_ptr<ExpressionObject> pEO;
/*
Utility object used by manageDependencies().
Removes dependencies from a DependencyTracker.
*/
class DependencyRemover :
public ExpressionObject::PathSink {
public:
// virtuals from PathSink
virtual void path(const string &path, bool include);
/*
Constructor.
Captures a reference to the smart pointer to the DependencyTr
acker
that this will remove dependencies from via
ExpressionObject::emitPaths().
@param pTracker reference to the smart pointer to the
DependencyTracker
*/
DependencyRemover(const intrusive_ptr<DependencyTracker> &pTrac
ker);
private:
const intrusive_ptr<DependencyTracker> &pTracker;
};
/*
Utility object used by manageDependencies().
Checks dependencies to see if they are present. If not, then
throws a user error.
*/
class DependencyChecker :
public ExpressionObject::PathSink {
public:
// virtuals from PathSink
virtual void path(const string &path, bool include);
/*
Constructor.
Captures a reference to the smart pointer to the DependencyTr
acker
that this will check dependencies from from
ExpressionObject::emitPaths() to see if they are required.
@param pTracker reference to the smart pointer to the
DependencyTracker
@param pThis the projection that is making this request
*/
DependencyChecker(
const intrusive_ptr<DependencyTracker> &pTracker,
const DocumentSourceProject *pThis);
private:
const intrusive_ptr<DependencyTracker> &pTracker;
const DocumentSourceProject *pThis;
};
}; };
class DocumentSourceSort : class DocumentSourceSort :
public DocumentSource { public DocumentSource {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceSort(); virtual ~DocumentSourceSort();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual const char *getSourceName() const;
virtual intrusive_ptr<Document> getCurrent(); virtual intrusive_ptr<Document> getCurrent();
virtual void manageDependencies(
const intrusive_ptr<DependencyTracker> &pTracker);
/* /*
TODO TODO
Adjacent sorts should reduce to the last sort. Adjacent sorts should reduce to the last sort.
virtual bool coalesce(const intrusive_ptr<DocumentSource> &pNextSou rce); virtual bool coalesce(const intrusive_ptr<DocumentSource> &pNextSou rce);
*/ */
/** /**
Create a new sorting DocumentSource. Create a new sorting DocumentSource.
@param pCtx the expression context @param pExpCtx the expression context for the pipeline
@returns the DocumentSource @returns the DocumentSource
*/ */
static intrusive_ptr<DocumentSourceSort> create( static intrusive_ptr<DocumentSourceSort> create(
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
/** /**
Add sort key field. Add sort key field.
Adds a sort key field to the key being built up. A concatenated Adds a sort key field to the key being built up. A concatenated
key is built up by calling this repeatedly. key is built up by calling this repeatedly.
@param fieldPath the field path to the key component @param fieldPath the field path to the key component
@param ascending if true, use the key for an ascending sort, @param ascending if true, use the key for an ascending sort,
otherwise, use it for descending otherwise, use it for descending
skipping to change at line 730 skipping to change at line 892
void sortKeyToBson(BSONObjBuilder *pBuilder, bool usePrefix) const; void sortKeyToBson(BSONObjBuilder *pBuilder, bool usePrefix) const;
/** /**
Create a sorting DocumentSource from BSON. Create a sorting DocumentSource from BSON.
This is a convenience method that uses the above, and operates on This is a convenience method that uses the above, and operates on
a BSONElement that has been deteremined to be an Object with an a BSONElement that has been deteremined to be an Object with an
element named $group. element named $group.
@param pBsonElement the BSONELement that defines the group @param pBsonElement the BSONELement that defines the group
@param pCtx the expression context @param pExpCtx the expression context for the pipeline
@returns the grouping DocumentSource @returns the grouping DocumentSource
*/ */
static intrusive_ptr<DocumentSource> createFromBson( static intrusive_ptr<DocumentSource> createFromBson(
BSONElement *pBsonElement, BSONElement *pBsonElement,
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
static const char sortName[]; static const char sortName[];
protected: protected:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual void sourceToBson(BSONObjBuilder *pBuilder) const; virtual void sourceToBson(BSONObjBuilder *pBuilder) const;
private: private:
DocumentSourceSort(const intrusive_ptr<ExpressionContext> &pCtx); DocumentSourceSort(const intrusive_ptr<ExpressionContext> &pExpCtx) ;
/* /*
Before returning anything, this source must fetch everything from Before returning anything, this source must fetch everything from
the underlying source and group it. populate() is used to do tha t the underlying source and group it. populate() is used to do tha t
on the first call to any method on this source. The populated on the first call to any method on this source. The populated
boolean indicates that this has been done. boolean indicates that this has been done.
*/ */
void populate(); void populate();
bool populated; bool populated;
long long count; long long count;
/* these two parallel each other */ /* these two parallel each other */
vector<intrusive_ptr<ExpressionFieldPath> > vSortKey; typedef vector<intrusive_ptr<ExpressionFieldPath> > SortPaths;
SortPaths vSortKey;
vector<bool> vAscending; vector<bool> vAscending;
class Carrier { class Carrier {
public: public:
/* /*
We need access to the key for compares, so we have to carry We need access to the key for compares, so we have to carry
this around. this around.
*/ */
DocumentSourceSort *pSort; DocumentSourceSort *pSort;
skipping to change at line 792 skipping to change at line 955
indicating pL < pR, pL == pR, or pL > pR, respectively indicating pL < pR, pL == pR, or pL > pR, respectively
*/ */
int compare(const intrusive_ptr<Document> &pL, int compare(const intrusive_ptr<Document> &pL,
const intrusive_ptr<Document> &pR); const intrusive_ptr<Document> &pR);
typedef list<Carrier> ListType; typedef list<Carrier> ListType;
ListType documents; ListType documents;
ListType::iterator listIterator; ListType::iterator listIterator;
intrusive_ptr<Document> pCurrent; intrusive_ptr<Document> pCurrent;
intrusive_ptr<ExpressionContext> pCtx;
}; };
class DocumentSourceLimit : class DocumentSourceLimit :
public DocumentSource { public DocumentSource {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceLimit(); virtual ~DocumentSourceLimit();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual intrusive_ptr<Document> getCurrent(); virtual intrusive_ptr<Document> getCurrent();
virtual const char *getSourceName() const;
virtual bool coalesce(const intrusive_ptr<DocumentSource> &pNextSou
rce);
/** /**
Create a new limiting DocumentSource. Create a new limiting DocumentSource.
@param pCtx the expression context @param pExpCtx the expression context for the pipeline
@returns the DocumentSource @returns the DocumentSource
*/ */
static intrusive_ptr<DocumentSourceLimit> create( static intrusive_ptr<DocumentSourceLimit> create(
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
/** /**
Create a limiting DocumentSource from BSON. Create a limiting DocumentSource from BSON.
This is a convenience method that uses the above, and operates on This is a convenience method that uses the above, and operates on
a BSONElement that has been deteremined to be an Object with an a BSONElement that has been deteremined to be an Object with an
element named $limit. element named $limit.
@param pBsonElement the BSONELement that defines the limit @param pBsonElement the BSONELement that defines the limit
@param pCtx the expression context @param pExpCtx the expression context
@returns the grouping DocumentSource @returns the grouping DocumentSource
*/ */
static intrusive_ptr<DocumentSource> createFromBson( static intrusive_ptr<DocumentSource> createFromBson(
BSONElement *pBsonElement, BSONElement *pBsonElement,
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
static const char limitName[]; static const char limitName[];
protected: protected:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual void sourceToBson(BSONObjBuilder *pBuilder) const; virtual void sourceToBson(BSONObjBuilder *pBuilder) const;
private: private:
DocumentSourceLimit(const intrusive_ptr<ExpressionContext> &pCtx); DocumentSourceLimit(
const intrusive_ptr<ExpressionContext> &pExpCtx);
long long limit; long long limit;
long long count; long long count;
intrusive_ptr<Document> pCurrent; intrusive_ptr<Document> pCurrent;
intrusive_ptr<ExpressionContext> pCtx;
}; };
class DocumentSourceSkip : class DocumentSourceSkip :
public DocumentSource { public DocumentSource {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceSkip(); virtual ~DocumentSourceSkip();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual intrusive_ptr<Document> getCurrent(); virtual intrusive_ptr<Document> getCurrent();
virtual const char *getSourceName() const;
virtual bool coalesce(const intrusive_ptr<DocumentSource> &pNextSou
rce);
/** /**
Create a new skipping DocumentSource. Create a new skipping DocumentSource.
@param pCtx the expression context @param pExpCtx the expression context
@returns the DocumentSource @returns the DocumentSource
*/ */
static intrusive_ptr<DocumentSourceSkip> create( static intrusive_ptr<DocumentSourceSkip> create(
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
/** /**
Create a skipping DocumentSource from BSON. Create a skipping DocumentSource from BSON.
This is a convenience method that uses the above, and operates on This is a convenience method that uses the above, and operates on
a BSONElement that has been deteremined to be an Object with an a BSONElement that has been deteremined to be an Object with an
element named $skip. element named $skip.
@param pBsonElement the BSONELement that defines the skip @param pBsonElement the BSONELement that defines the skip
@param pCtx the expression context @param pExpCtx the expression context
@returns the grouping DocumentSource @returns the grouping DocumentSource
*/ */
static intrusive_ptr<DocumentSource> createFromBson( static intrusive_ptr<DocumentSource> createFromBson(
BSONElement *pBsonElement, BSONElement *pBsonElement,
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
static const char skipName[]; static const char skipName[];
protected: protected:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual void sourceToBson(BSONObjBuilder *pBuilder) const; virtual void sourceToBson(BSONObjBuilder *pBuilder) const;
private: private:
DocumentSourceSkip(const intrusive_ptr<ExpressionContext> &pCtx); DocumentSourceSkip(const intrusive_ptr<ExpressionContext> &pExpCtx) ;
/* /*
Skips initial documents. Skips initial documents.
*/ */
void skipper(); void skipper();
long long skip; long long skip;
long long count; long long count;
intrusive_ptr<Document> pCurrent; intrusive_ptr<Document> pCurrent;
intrusive_ptr<ExpressionContext> pCtx;
}; };
class DocumentSourceUnwind : class DocumentSourceUnwind :
public DocumentSource, public DocumentSource {
public boost::enable_shared_from_this<DocumentSourceUnwind> {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceUnwind(); virtual ~DocumentSourceUnwind();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual const char *getSourceName() const;
virtual intrusive_ptr<Document> getCurrent(); virtual intrusive_ptr<Document> getCurrent();
virtual void manageDependencies(
const intrusive_ptr<DependencyTracker> &pTracker);
/** /**
Create a new DocumentSource that can implement unwind. Create a new DocumentSource that can implement unwind.
@param pExpCtx the expression context for the pipeline
@returns the projection DocumentSource @returns the projection DocumentSource
*/ */
static intrusive_ptr<DocumentSourceUnwind> create(); static intrusive_ptr<DocumentSourceUnwind> create(
const intrusive_ptr<ExpressionContext> &pExpCtx);
/** /**
Specify the field to unwind. There must be exactly one before Specify the field to unwind. There must be exactly one before
the pipeline begins execution. the pipeline begins execution.
@param rFieldPath - path to the field to unwind @param rFieldPath - path to the field to unwind
*/ */
void unwindField(const FieldPath &rFieldPath); void unwindField(const FieldPath &rFieldPath);
/** /**
Create a new projection DocumentSource from BSON. Create a new projection DocumentSource from BSON.
This is a convenience for directly handling BSON, and relies on t he This is a convenience for directly handling BSON, and relies on t he
above methods. above methods.
@param pBsonElement the BSONElement with an object named $project @param pBsonElement the BSONElement with an object named $project
@param pExpCtx the expression context for the pipeline
@returns the created projection @returns the created projection
*/ */
static intrusive_ptr<DocumentSource> createFromBson( static intrusive_ptr<DocumentSource> createFromBson(
BSONElement *pBsonElement, BSONElement *pBsonElement,
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
static const char unwindName[]; static const char unwindName[];
protected: protected:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual void sourceToBson(BSONObjBuilder *pBuilder) const; virtual void sourceToBson(BSONObjBuilder *pBuilder) const;
private: private:
DocumentSourceUnwind(); DocumentSourceUnwind(const intrusive_ptr<ExpressionContext> &pExpCt x);
// configuration state // configuration state
FieldPath unwindPath; FieldPath unwindPath;
vector<int> fieldIndex; /* for the current document, the indices vector<int> fieldIndex; /* for the current document, the indices
leading down to the field being unwound */ leading down to the field being unwound */
// iteration state // iteration state
intrusive_ptr<Document> pNoUnwindDocument; intrusive_ptr<Document> pNoUnwindDocument;
// document to return, pre-un wind // document to return, pre-un wind
skipping to change at line 980 skipping to change at line 1147
clones (or the original) that we've made. clones (or the original) that we've made.
This expects pUnwindValue to have been set by a prior call to This expects pUnwindValue to have been set by a prior call to
advance(). However, pUnwindValue may also be NULL, in which case advance(). However, pUnwindValue may also be NULL, in which case
the field will be removed -- this is the action for an empty the field will be removed -- this is the action for an empty
array. array.
@returns a partial deep clone of pNoUnwindDocument @returns a partial deep clone of pNoUnwindDocument
*/ */
intrusive_ptr<Document> clonePath() const; intrusive_ptr<Document> clonePath() const;
}; };
} }
/* ======================= INLINED IMPLEMENTATIONS ======================== == */ /* ======================= INLINED IMPLEMENTATIONS ======================== == */
namespace mongo { namespace mongo {
inline void DocumentSource::setPipelineStep(int s) {
step = s;
}
inline int DocumentSource::getPipelineStep() const {
return step;
}
inline void DocumentSourceGroup::setIdExpression( inline void DocumentSourceGroup::setIdExpression(
const intrusive_ptr<Expression> &pExpression) { const intrusive_ptr<Expression> &pExpression) {
pIdExpression = pExpression; pIdExpression = pExpression;
} }
inline DocumentSourceProject::DependencyRemover::DependencyRemover(
const intrusive_ptr<DependencyTracker> &pT):
pTracker(pT) {
}
inline DocumentSourceProject::DependencyChecker::DependencyChecker(
const intrusive_ptr<DependencyTracker> &pTrack,
const DocumentSourceProject *pT):
pTracker(pTrack),
pThis(pT) {
}
inline void DocumentSourceUnwind::resetArray() { inline void DocumentSourceUnwind::resetArray() {
pNoUnwindDocument.reset(); pNoUnwindDocument.reset();
pUnwindArray.reset(); pUnwindArray.reset();
pUnwinder.reset(); pUnwinder.reset();
pUnwindValue.reset(); pUnwindValue.reset();
} }
inline DocumentSourceSort::Carrier::Carrier( inline DocumentSourceSort::Carrier::Carrier(
DocumentSourceSort *pTheSort, DocumentSourceSort *pTheSort,
const intrusive_ptr<Document> &pTheDocument): const intrusive_ptr<Document> &pTheDocument):
 End of changes. 92 change blocks. 
69 lines changed or deleted 264 lines changed or added


 dur.h   dur.h 
skipping to change at line 17 skipping to change at line 17
namespace mongo { namespace mongo {
class NamespaceDetails; class NamespaceDetails;
void mongoAbort(const char *msg); void mongoAbort(const char *msg);
void abort(); // not defined -- use mongoAbort() instead void abort(); // not defined -- use mongoAbort() instead
namespace dur { namespace dur {
void releasedWriteLock();
// a smaller limit is likely better on 32 bit // a smaller limit is likely better on 32 bit
#if defined(__i386__) || defined(_M_IX86) #if defined(__i386__) || defined(_M_IX86)
const unsigned UncommittedBytesLimit = 50 * 1024 * 1024; const unsigned UncommittedBytesLimit = 50 * 1024 * 1024;
#else #else
const unsigned UncommittedBytesLimit = 100 * 1024 * 1024; const unsigned UncommittedBytesLimit = 100 * 1024 * 1024;
#endif #endif
/** Call during startup so durability module can initialize /** Call during startup so durability module can initialize
Throws if fatal error Throws if fatal error
Does nothing if cmdLine.dur is false Does nothing if cmdLine.dur is false
skipping to change at line 91 skipping to change at line 93
/** Commit immediately. /** Commit immediately.
Generally, you do not want to do this often, as highly gran ular committing may affect Generally, you do not want to do this often, as highly gran ular committing may affect
performance. performance.
Does not return until the commit is complete. Does not return until the commit is complete.
You must be at least read locked when you call this. Ideal ly, you are not write locked You must be at least read locked when you call this. Ideal ly, you are not write locked
and then read operations can occur concurrently. and then read operations can occur concurrently.
Do not use this. Use commitIfNeeded() instead.
@return true if --dur is on. @return true if --dur is on.
@return false if --dur is off. (in which case there is acti on) @return false if --dur is off. (in which case there is acti on)
*/ */
virtual bool commitNow() = 0; virtual bool commitNow() = 0;
/** Commit if enough bytes have been modified. Current threshol d is 50MB /** Commit if enough bytes have been modified. Current threshol d is 50MB
The idea is that long running write operations that dont yi eld The idea is that long running write operations that dont yi eld
(like creating an index or update with $atomic) can call th is (like creating an index or update with $atomic) can call th is
whenever the db is in a sane state and it will prevent comm its whenever the db is in a sane state and it will prevent comm its
from growing too large. from growing too large.
@return true if commited @return true if commited
*/ */
virtual bool commitIfNeeded() = 0; virtual bool commitIfNeeded(bool force=false) = 0;
/** @return true if time to commit but does NOT do a commit */ /** @return true if time to commit but does NOT do a commit */
virtual bool aCommitIsNeeded() const = 0; virtual bool aCommitIsNeeded() const = 0;
/** Declare write intent for a DiskLoc. @see DiskLoc::writing( ) */ /** Declare write intent for a DiskLoc. @see DiskLoc::writing( ) */
inline DiskLoc& writingDiskLoc(DiskLoc& d) { return *((DiskLoc* ) writingPtr(&d, sizeof(d))); } inline DiskLoc& writingDiskLoc(DiskLoc& d) { return *((DiskLoc* ) writingPtr(&d, sizeof(d))); }
/** Declare write intent for an int */ /** Declare write intent for an int */
inline int& writingInt(const int& d) { return *((int*) writingP tr((int*) &d, sizeof(d))); } inline int& writingInt(int& d) { return *static_cast<int*>(writ ingPtr( &d, sizeof(d))); }
/** "assume i've already indicated write intent, let me write" /** "assume i've already indicated write intent, let me write"
redeclaration is fine too, but this is faster. redeclaration is fine too, but this is faster.
*/ */
template <typename T> template <typename T>
inline inline
T* alreadyDeclared(T *x) { T* alreadyDeclared(T *x) {
#if defined(_TESTINTENT) #if defined(_TESTINTENT)
return (T*) MongoMMF::switchToPrivateView(x); return (T*) MongoMMF::switchToPrivateView(x);
#else #else
skipping to change at line 135 skipping to change at line 139
#endif #endif
} }
/** declare intent to write to x for sizeof(*x) */ /** declare intent to write to x for sizeof(*x) */
template <typename T> template <typename T>
inline inline
T* writing(T *x) { T* writing(T *x) {
return (T*) writingPtr(x, sizeof(T)); return (T*) writingPtr(x, sizeof(T));
} }
/** write something that doesn't have to be journaled, as this
write is "unimportant".
a good example is paddingFactor.
can be thought of as memcpy(dst,src,len)
the dur implementation acquires a mutex in this method, so
do not assume it is faster
without measuring!
*/
virtual void setNoJournal(void *dst, void *src, unsigned len) =
0;
/** Commits pending changes, flushes all changes to main data /** Commits pending changes, flushes all changes to main data
files, then removes the journal. files, then removes the journal.
This is useful as a "barrier" to ensure that writes before this This is useful as a "barrier" to ensure that writes before this
call will never go through recovery and be applied to files call will never go through recovery and be applied to files
that have had changes made after this call applied. that have had changes made after this call applied.
*/ */
virtual void syncDataAndTruncateJournal() = 0; virtual void syncDataAndTruncateJournal() = 0;
static DurableInterface& getDur() { return *_impl; } static DurableInterface& getDur() { return *_impl; }
skipping to change at line 182 skipping to change at line 178
}; // class DurableInterface }; // class DurableInterface
class NonDurableImpl : public DurableInterface { class NonDurableImpl : public DurableInterface {
void* writingPtr(void *x, unsigned len); void* writingPtr(void *x, unsigned len);
void* writingAtOffset(void *buf, unsigned ofs, unsigned len) { return buf; } void* writingAtOffset(void *buf, unsigned ofs, unsigned len) { return buf; }
void* writingRangesAtOffsets(void *buf, const vector< pair< lon g long, unsigned > > &ranges) { return buf; } void* writingRangesAtOffsets(void *buf, const vector< pair< lon g long, unsigned > > &ranges) { return buf; }
void declareWriteIntent(void *, unsigned); void declareWriteIntent(void *, unsigned);
void createdFile(string filename, unsigned long long len) { } void createdFile(string filename, unsigned long long len) { }
bool awaitCommit() { return false; } bool awaitCommit() { return false; }
bool commitNow() { return false; } bool commitNow() { return false; }
bool commitIfNeeded() { return false; } bool commitIfNeeded(bool) { return false; }
bool aCommitIsNeeded() const { return false; } bool aCommitIsNeeded() const { return false; }
void setNoJournal(void *dst, void *src, unsigned len);
void syncDataAndTruncateJournal() {} void syncDataAndTruncateJournal() {}
}; };
class DurableImpl : public DurableInterface { class DurableImpl : public DurableInterface {
void* writingPtr(void *x, unsigned len); void* writingPtr(void *x, unsigned len);
void* writingAtOffset(void *buf, unsigned ofs, unsigned len); void* writingAtOffset(void *buf, unsigned ofs, unsigned len);
void* writingRangesAtOffsets(void *buf, const vector< pair< lon g long, unsigned > > &ranges); void* writingRangesAtOffsets(void *buf, const vector< pair< lon g long, unsigned > > &ranges);
void declareWriteIntent(void *, unsigned); void declareWriteIntent(void *, unsigned);
void createdFile(string filename, unsigned long long len); void createdFile(string filename, unsigned long long len);
bool awaitCommit(); bool awaitCommit();
bool commitNow(); bool commitNow();
bool aCommitIsNeeded() const; bool aCommitIsNeeded() const;
bool commitIfNeeded(); bool commitIfNeeded(bool);
void setNoJournal(void *dst, void *src, unsigned len);
void syncDataAndTruncateJournal(); void syncDataAndTruncateJournal();
}; };
} // namespace dur } // namespace dur
inline dur::DurableInterface& getDur() { return dur::DurableInterface:: getDur(); } inline dur::DurableInterface& getDur() { return dur::DurableInterface:: getDur(); }
/** declare that we are modifying a diskloc and this is a datafile writ e. */ /** declare that we are modifying a diskloc and this is a datafile writ e. */
inline DiskLoc& DiskLoc::writing() const { return getDur().writingDiskL oc(*const_cast< DiskLoc * >( this )); } inline DiskLoc& DiskLoc::writing() const { return getDur().writingDiskL oc(*const_cast< DiskLoc * >( this )); }
 End of changes. 8 change blocks. 
17 lines changed or deleted 8 lines changed or added


 dur_commitjob.h   dur_commitjob.h 
/* @file dur_commitjob.h used by dur.cpp /* @file dur_commitjob.h used by dur.cpp */
*/
/** /**
* Copyright (C) 2009 10gen Inc. * Copyright (C) 2009 10gen Inc.
* *
* This program is free software: you can redistribute it and/or modify * 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 , * it under the terms of the GNU Affero General Public License, version 3 ,
* as published by the Free Software Foundation. * as published by the Free Software Foundation.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
skipping to change at line 29 skipping to change at line 28
#pragma once #pragma once
#include "../util/alignedbuilder.h" #include "../util/alignedbuilder.h"
#include "../util/mongoutils/hash.h" #include "../util/mongoutils/hash.h"
#include "../util/concurrency/synchronization.h" #include "../util/concurrency/synchronization.h"
#include "cmdline.h" #include "cmdline.h"
#include "durop.h" #include "durop.h"
#include "dur.h" #include "dur.h"
#include "taskqueue.h" #include "taskqueue.h"
#include "d_concurrency.h"
//#define DEBUG_WRITE_INTENT 1
namespace mongo { namespace mongo {
namespace dur { namespace dur {
/** declaration of an intent to write to a region of a memory mappe void assertLockedForCommitting();
d view
* /** Declaration of an intent to write to a region of a memory mappe
* We store the end rather than the start pointer to make operator< d view
faster * We store the end rather than the start pointer to make operator
* since that is heavily used in set lookup. < faster
* since that is heavily used in set lookup.
*/ */
struct WriteIntent { /* copyable */ struct WriteIntent { /* copyable */
WriteIntent() : /*w_ptr(0), */ p(0) { } WriteIntent() : p(0) { }
WriteIntent(void *a, unsigned b) : /*w_ptr(0), */ p((char*)a+b) WriteIntent(void *a, unsigned b) : p((char*)a+b), len(b) { }
, len(b) { } void* start() const { return (char*)
p - len; }
void* start() const { return (char*)p - len; } void* end() const { return p; }
void* end() const { return p; } unsigned length() const { return len; }
unsigned length() const { return len; }
bool operator < (const WriteIntent& rhs) const { return end() < rhs.end(); } bool operator < (const WriteIntent& rhs) const { return end() < rhs.end(); }
bool overlaps(const WriteIntent& rhs) const { return (start(
// can they be merged? ) <= rhs.end() && end() >= rhs.start()); }
bool overlaps(const WriteIntent& rhs) const { bool contains(const WriteIntent& rhs) const { return (start(
return (start() <= rhs.end() && end() >= rhs.start()); ) <= rhs.start() && end() >= rhs.end()); }
} // merge into me:
// is merging necessary?
bool contains(const WriteIntent& rhs) const {
return (start() <= rhs.start() && end() >= rhs.end());
}
// merge into me
void absorb(const WriteIntent& other); void absorb(const WriteIntent& other);
friend ostream& operator << (ostream& out, const WriteIntent& w i) { friend ostream& operator << (ostream& out, const WriteIntent& w i) {
return (out << "p: " << wi.p << " end: " << wi.end() << " l en: " << wi.len); return (out << "p: " << wi.p << " end: " << wi.end() << " l en: " << wi.len);
} }
//mutable void *w_ptr; // writable mapping of p.
// mutable because set::iterator is const but this isn't used i
n op<
#if defined(_EXPERIMENTAL)
mutable unsigned ofsInJournalBuffer;
#endif
private: private:
void *p; // intent to write up to p void *p; // intent to write up to p
unsigned len; // up to this len unsigned len; // up to this len
}; };
/** try to remember things we have already marked for journaling. false negatives are ok if infrequent - /** try to remember things we have already marked for journaling. false negatives are ok if infrequent -
we will just log them twice. we will just log them twice.
*/ */
template<int Prime> template<int Prime>
class Already : boost::noncopyable { class Already : boost::noncopyable {
public: public:
Already() { clear(); } Already() { clear(); }
void clear() { memset(this, 0, sizeof(*this)); } void clear() { memset(this, 0, sizeof(*this)); }
/* see if we have Already recorded/indicated our write intent f or this region of memory. /* see if we have Already recorded/indicated our write intent f or this region of memory.
automatically upgrades the length if the length was shorter previously. automatically upgrades the length if the length was shorter previously.
@return true if already indicated. @return true if already indicated.
*/ */
bool checkAndSet(void* p, int len) { bool checkAndSet(void* p, int len) {
unsigned x = mongoutils::hashPointer(p); unsigned x = mongoutils::hashPointer(p);
pair<void*, int>& nd = nodes[x % N]; pair<void*, int>& nd = nodes[x % N];
if( nd.first == p ) { if( nd.first == p ) {
if( nd.second < len ) { if( nd.second < len ) {
nd.second = len; nd.second = len;
return false; // haven't indicated this len yet return false; // haven't indicated this len yet
} }
return true; // already indicated return true; // already indicated
} }
nd.first = p; nd.first = p;
nd.second = len; nd.second = len;
return false; // a new set return false; // a new set
} }
private: private:
enum { N = Prime }; // this should be small the idea is that it fits in the cpu cache easily enum { N = Prime }; // this should be small the idea is that it fits in the cpu cache easily
pair<void*,int> nodes[N]; pair<void*,int> nodes[N];
}; };
/** our record of pending/uncommitted write intents */ /** our record of pending/uncommitted write intents */
class Writes : boost::noncopyable { class IntentsAndDurOps : boost::noncopyable {
struct D {
void *p;
unsigned len;
static void go(const D& d);
};
public: public:
TaskQueue<D> _deferred; vector<WriteIntent> _intents;
Already<127> _alreadyNoted; Already<127> _alreadyNoted;
set<WriteIntent> _writes; vector< shared_ptr<DurOp> > _durOps; // all the ops other than
vector< shared_ptr<DurOp> > _ops; // all the ops other than bas basic writes
ic writes
bool _drained; // _deferred is drained? for asserting/testing
/** reset the Writes structure (empties all the above) */ /** reset the IntentsAndDurOps structure (empties all the above ) */
void clear(); void clear();
/** merges into set (ie non-deferred version) */
void _insertWriteIntent(void* p, int len);
void insertWriteIntent(void* p, int len) { void insertWriteIntent(void* p, int len) {
#if defined(DEBUG_WRITE_INTENT) _intents.push_back(WriteIntent(p,len));
if( _debug[p] < len ) wassert( _intents.size() < 2000000 );
_debug[p] = len;
#endif
D d;
d.p = p;
d.len = len;
_deferred.defer(d);
} }
#if defined(DEBUG_WRITE_INTENT)
#ifdef _DEBUG
WriteIntent _last;
#endif
#if defined(DEBUG_WRITE_INTENT)
map<void*,int> _debug; map<void*,int> _debug;
#endif #endif
}; };
#if defined(DEBUG_WRITE_INTENT) /** so we don't have to lock the groupCommitMutex too often */
void assertAlreadyDeclared(void *, int len); class ThreadLocalIntents {
#else enum { N = 21 };
inline void assertAlreadyDeclared(void *, int len) { } dur::WriteIntent i[N];
#endif int n;
public:
ThreadLocalIntents() : n(0) { }
void _unspool();
void unspool();
void push(const WriteIntent& i);
int n_informational() const { return n; }
static AtomicUInt nSpooled;
};
/** A commit job object for a group commit. Currently there is one instance of this object. /** A commit job object for a group commit. Currently there is one instance of this object.
concurrency: assumption is caller is appropriately locking. concurrency: assumption is caller is appropriately locking.
for example note() invocations are from the write lock. for example note() invocations are from the write lock.
other uses are in a read lock from a single thread (durThread) other uses are in a read lock from a single thread (durThread)
*/ */
class CommitJob : boost::noncopyable { class CommitJob : boost::noncopyable {
public: void _committingReset();
AlignedBuilder _ab; // for direct i/o writes to journal ~CommitJob(){ verify(!"shouldn't destroy CommitJob!"); }
CommitJob();
~CommitJob(){ assert(!"shouldn't destroy CommitJob!"); }
/** record/note an intent to write */ /** record/note an intent to write */
void note(void* p, int len); void note(void* p, int len);
// only called by :
friend class ThreadLocalIntents;
public:
SimpleMutex groupCommitMutex;
CommitJob();
/** note an operation other than a "basic write" */ /** note an operation other than a "basic write". threadsafe (l ocks in the impl) */
void noteOp(shared_ptr<DurOp> p); void noteOp(shared_ptr<DurOp> p);
set<WriteIntent>& writes() { vector< shared_ptr<DurOp> >& ops() {
if( !_wi._drained ) { dassert( Lock::isLocked() ); // a rather weak chec
// generally, you don't want to use the set until it is k, we require more than that
prepared (after deferred ops are applied) groupCommitMutex.dassertLocked(); // this is what really ma
// thus this assert here. kes the below safe
assert(false); return _intentsAndDurOps._durOps;
}
return _wi._writes;
} }
vector< shared_ptr<DurOp> >& ops() { return _wi._ops; }
/** this method is safe to call outside of locks. when haswritt en is false we don't do any group commit and avoid even /** this method is safe to call outside of locks. when haswritt en is false we don't do any group commit and avoid even
trying to acquire a lock, which might be helpful at times. trying to acquire a lock, which might be helpful at times.
*/ */
bool hasWritten() const { return _hasWritten; } bool hasWritten() const { return _hasWritten; }
/** we use the commitjob object over and over, calling reset() public:
rather than reconstructing */ /** these called by the groupCommit code as it goes along */
void reset(); void commitingBegin();
void beginCommit();
/** the commit code calls this when data reaches the journal (o n disk) */ /** the commit code calls this when data reaches the journal (o n disk) */
void notifyCommitted() { _notify.notifyAll(_commitNumber); } void committingNotifyCommitted() {
groupCommitMutex.dassertLocked();
_notify.notifyAll(_commitNumber);
}
/** we use the commitjob object over and over, calling reset()
rather than reconstructing */
void committingReset() {
groupCommitMutex.dassertLocked();
_committingReset();
}
public:
/** we check how much written and if it is getting to be a lot, we commit sooner. */ /** we check how much written and if it is getting to be a lot, we commit sooner. */
size_t bytes() const { return _bytes; } size_t bytes() const { return _bytes; }
#if defined(_DEBUG) /** used in prepbasicwrites. sorted so that overlapping and dup
const WriteIntent& lastWrite() const { return _wi._last; } licate items
#endif * can be merged. we sort here so the caller receives somethin
g they must
* keep const from their pov. */
const vector<WriteIntent>& getIntentsSorted() {
groupCommitMutex.dassertLocked();
sort(_intentsAndDurOps._intents.begin(), _intentsAndDurOps.
_intents.end());
return _intentsAndDurOps._intents;
}
bool _hasWritten;
Writes& wi() { return _wi; }
private: private:
NotifyAll::When _commitNumber; NotifyAll::When _commitNumber;
bool _hasWritten; IntentsAndDurOps _intentsAndDurOps;
Writes _wi; // todo: fix name
size_t _bytes; size_t _bytes;
public: public:
NotifyAll _notify; // for getlasterror fsync:true acknowledgeme NotifyAll _notify; // for getlasterror fsync:t
nts rue acknowledgements
unsigned _nSinceCommitIfNeededCall; unsigned _nSinceCommitIfNeededCall; // for asserts and debuggin
g
}; };
extern CommitJob& commitJob; extern CommitJob& commitJob;
#if defined(DEBUG_WRITE_INTENT)
void assertAlreadyDeclared(void *, int len);
#else
inline void assertAlreadyDeclared(void *, int len) { }
#endif
} }
} }
 End of changes. 31 change blocks. 
107 lines changed or deleted 95 lines changed or added


 dur_recover.h   dur_recover.h 
skipping to change at line 43 skipping to change at line 43
void applyEntries(const vector<ParsedJournalEntry> &entries); void applyEntries(const vector<ParsedJournalEntry> &entries);
bool processFileBuffer(const void *, unsigned len); bool processFileBuffer(const void *, unsigned len);
bool processFile(boost::filesystem::path journalfile); bool processFile(boost::filesystem::path journalfile);
void _close(); // doesn't lock void _close(); // doesn't lock
list<boost::shared_ptr<MongoMMF> > _mmfs; list<boost::shared_ptr<MongoMMF> > _mmfs;
unsigned long long _lastDataSyncedFromLastRun; unsigned long long _lastDataSyncedFromLastRun;
unsigned long long _lastSeqMentionedInConsoleLog; unsigned long long _lastSeqMentionedInConsoleLog;
public: public:
mongo::mutex _mx; // protects _mmfs; see setNoJournal() too mongo::mutex _mx; // protects _mmfs
private: private:
bool _recovering; // are we in recovery or WRITETODATAFILES bool _recovering; // are we in recovery or WRITETODATAFILES
static RecoveryJob &_instance; static RecoveryJob &_instance;
}; };
} }
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 engine.h   engine.h 
skipping to change at line 186 skipping to change at line 186
static void setup(); static void setup();
/** gets a scope from the pool or a new one if pool is empty /** gets a scope from the pool or a new one if pool is empty
* @param pool An identifier for the pool, usually the db name * @param pool An identifier for the pool, usually the db name
* @return the scope */ * @return the scope */
auto_ptr<Scope> getPooledScope( const string& pool ); auto_ptr<Scope> getPooledScope( const string& pool );
/** call this method to release some JS resources when a thread is done */ /** call this method to release some JS resources when a thread is done */
void threadDone(); void threadDone();
struct Unlocker { virtual ~Unlocker() {} };
virtual auto_ptr<Unlocker> newThreadUnlocker() { return auto_ptr< U
nlocker >( new Unlocker ); }
void setScopeInitCallback( void ( *func )( Scope & ) ) { _scopeInit Callback = func; } void setScopeInitCallback( void ( *func )( Scope & ) ) { _scopeInit Callback = func; }
static void setConnectCallback( void ( *func )( DBClientWithCommand s& ) ) { _connectCallback = func; } static void setConnectCallback( void ( *func )( DBClientWithCommand s& ) ) { _connectCallback = func; }
static void runConnectCallback( DBClientWithCommands &c ) { static void runConnectCallback( DBClientWithCommands &c ) {
if ( _connectCallback ) if ( _connectCallback )
_connectCallback( c ); _connectCallback( c );
} }
// engine implementation may either respond to interrupt events or // engine implementation may either respond to interrupt events or
// poll for interrupts // poll for interrupts
 End of changes. 1 change blocks. 
4 lines changed or deleted 0 lines changed or added


 engine_v8.h   engine_v8.h 
skipping to change at line 88 skipping to change at line 88
BSONHolder( BSONObj obj ) { BSONHolder( BSONObj obj ) {
_obj = obj.getOwned(); _obj = obj.getOwned();
_modified = false; _modified = false;
} }
~BSONHolder() { ~BSONHolder() {
} }
BSONObj _obj; BSONObj _obj;
bool _modified; bool _modified;
list<string> _extra;
set<string> _removed;
}; };
class V8Scope : public Scope { class V8Scope : public Scope {
public: public:
V8Scope( V8ScriptEngine * engine ); V8Scope( V8ScriptEngine * engine );
~V8Scope(); ~V8Scope();
virtual void reset(); virtual void reset();
virtual void init( const BSONObj * data ); virtual void init( const BSONObj * data );
skipping to change at line 239 skipping to change at line 242
public: public:
V8ScriptEngine(); V8ScriptEngine();
virtual ~V8ScriptEngine(); virtual ~V8ScriptEngine();
virtual Scope * createScope() { return new V8Scope( this ); } virtual Scope * createScope() { return new V8Scope( this ); }
virtual void runTest() {} virtual void runTest() {}
bool utf8Ok() const { return true; } bool utf8Ok() const { return true; }
class V8UnlockForClient : public Unlocker {
// V8Unlock u_;
};
virtual auto_ptr<Unlocker> newThreadUnlocker() { return auto_ptr< U
nlocker >( new V8UnlockForClient ); }
virtual void interrupt( unsigned opSpec ); virtual void interrupt( unsigned opSpec );
virtual void interruptAll(); virtual void interruptAll();
private: private:
friend class V8Scope; friend class V8Scope;
}; };
class ExternalString : public v8::String::ExternalAsciiStringResource { class ExternalString : public v8::String::ExternalAsciiStringResource {
public: public:
ExternalString(std::string str) : _data(str) { ExternalString(std::string str) : _data(str) {
 End of changes. 2 change blocks. 
7 lines changed or deleted 3 lines changed or added


 expression.h   expression.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 License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "pch.h" #include "pch.h"
#include "db/pipeline/field_path.h" #include "db/pipeline/field_path.h"
#include "util/intrusive_counter.h" #include "util/intrusive_counter.h"
#include "util/iterator.h"
namespace mongo { namespace mongo {
class BSONArrayBuilder; class BSONArrayBuilder;
class BSONElement; class BSONElement;
class BSONObjBuilder; class BSONObjBuilder;
class Builder; class Builder;
class DependencyTracker;
class Document; class Document;
class DocumentSource;
class ExpressionContext; class ExpressionContext;
class Value; class Value;
class Expression : class Expression :
public IntrusiveCounterUnsigned { public IntrusiveCounterUnsigned {
public: public:
virtual ~Expression() {}; virtual ~Expression() {};
/* /*
Optimize the Expression. Optimize the Expression.
skipping to change at line 53 skipping to change at line 57
$add, $and, or $or. $add, $and, or $or.
The Expression should be replaced with the return value, which ma y The Expression should be replaced with the return value, which ma y
or may not be the same object. In the case of constant folding, or may not be the same object. In the case of constant folding,
a computed expression may be replaced by a constant. a computed expression may be replaced by a constant.
@returns the optimized Expression @returns the optimized Expression
*/ */
virtual intrusive_ptr<Expression> optimize() = 0; virtual intrusive_ptr<Expression> optimize() = 0;
/**
Add this expression's field dependencies to the dependency track
er.
Expressions are trees, so this is often recursive.
@params pTracker the tracker to add the dependencies to
*/
virtual void addDependencies(
const intrusive_ptr<DependencyTracker> &pTracker,
const DocumentSource *pSource) const = 0;
/* /*
Evaluate the Expression using the given document as input. Evaluate the Expression using the given document as input.
@returns the computed value @returns the computed value
*/ */
virtual intrusive_ptr<const Value> evaluate( virtual intrusive_ptr<const Value> evaluate(
const intrusive_ptr<Document> &pDocument) const = 0; const intrusive_ptr<Document> &pDocument) const = 0;
/* /*
Add the Expression (and any descendant Expressions) into a BSON Add the Expression (and any descendant Expressions) into a BSON
object that is under construction. object that is under construction.
Unevaluated Expressions always materialize as objects. Evaluatio n Unevaluated Expressions always materialize as objects. Evaluatio n
may produce a scalar or another object, either of which will be may produce a scalar or another object, either of which will be
substituted inline. substituted inline.
@param pBuilder the builder to add the expression to @param pBuilder the builder to add the expression to
@param fieldName the name the object should be given @param fieldName the name the object should be given
@param requireExpression specify true if the value must appear
as an expression; this is used by DocumentSources like
$project which distinguish between field inclusion and virtual
field specification; See ExpressionConstant.
*/ */
virtual void addToBsonObj( virtual void addToBsonObj(
BSONObjBuilder *pBuilder, string fieldName, BSONObjBuilder *pBuilder, string fieldName,
unsigned depth) const = 0; bool requireExpression) const = 0;
/* /*
Add the Expression (and any descendant Expressions) into a BSON Add the Expression (and any descendant Expressions) into a BSON
array that is under construction. array that is under construction.
Unevaluated Expressions always materialize as objects. Evaluatio n Unevaluated Expressions always materialize as objects. Evaluatio n
may produce a scalar or another object, either of which will be may produce a scalar or another object, either of which will be
substituted inline. substituted inline.
@param pBuilder the builder to add the expression to @param pBuilder the builder to add the expression to
*/ */
virtual void addToBsonArray(BSONArrayBuilder *pBuilder, virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const = 0;
unsigned depth) const = 0;
/* /*
Convert the expression into a BSONObj that corresponds to the Convert the expression into a BSONObj that corresponds to the
db.collection.find() predicate language. This is intended for db.collection.find() predicate language. This is intended for
use by DocumentSourceFilter. use by DocumentSourceFilter.
This is more limited than the full expression language supported This is more limited than the full expression language supported
by all available expressions in a DocumentSource processing by all available expressions in a DocumentSource processing
pipeline, and will fail with an assertion if an attempt is made pipeline, and will fail with an assertion if an attempt is made
to go outside the bounds of the recognized patterns, which don't to go outside the bounds of the recognized patterns, which don't
include full computed expressions. There are other methods avail able include full computed expressions. There are other methods avail able
on DocumentSourceFilter which can be used to analyze a filter on DocumentSourceFilter which can be used to analyze a filter
predicate and break it up into appropriate expressions which can predicate and break it up into appropriate expressions which can
be translated within these constraints. As a result, the default be translated within these constraints. As a result, the default
implementation is to fail with an assertion; only a subset of implementation is to fail with an assertion; only a subset of
operators will be able to fulfill this request. operators will be able to fulfill this request.
@param pBuilder the builder to add the expression to. @param pBuilder the builder to add the expression to.
*/ */
virtual void toMatcherBson( virtual void toMatcherBson(BSONObjBuilder *pBuilder) const;
BSONObjBuilder *pBuilder, unsigned depth) const;
/* /*
Utility class for parseObject() below. Utility class for parseObject() below.
Only one array can be unwound in a processing pipeline. If the Only one array can be unwound in a processing pipeline. If the
UNWIND_OK option is used, unwindOk() will return true, and a fiel d UNWIND_OK option is used, unwindOk() will return true, and a fiel d
can be declared as unwound using unwind(), after which unwindUsed () can be declared as unwound using unwind(), after which unwindUsed ()
will return true. Only specify UNWIND_OK if it is OK to unwind a n will return true. Only specify UNWIND_OK if it is OK to unwind a n
array in the current context. array in the current context.
skipping to change at line 200 skipping to change at line 217
EQ = 0, // return true for a == b, false otherwise EQ = 0, // return true for a == b, false otherwise
NE = 1, // return true for a != b, false otherwise NE = 1, // return true for a != b, false otherwise
GT = 2, // return true for a > b, false otherwise GT = 2, // return true for a > b, false otherwise
GTE = 3, // return true for a >= b, false otherwise GTE = 3, // return true for a >= b, false otherwise
LT = 4, // return true for a < b, false otherwise LT = 4, // return true for a < b, false otherwise
LTE = 5, // return true for a <= b, false otherwise LTE = 5, // return true for a <= b, false otherwise
CMP = 6, // return -1, 0, 1 for a < b, a == b, a > b CMP = 6, // return -1, 0, 1 for a < b, a == b, a > b
}; };
static int signum(int i); static int signum(int i);
protected:
typedef vector<intrusive_ptr<Expression> > ExpressionVector;
}; };
class ExpressionNary : class ExpressionNary :
public Expression, public Expression {
public boost::enable_shared_from_this<ExpressionNary> {
public: public:
// virtuals from Expression // virtuals from Expression
virtual intrusive_ptr<Expression> optimize(); virtual intrusive_ptr<Expression> optimize();
virtual void addToBsonObj( virtual void addToBsonObj(
BSONObjBuilder *pBuilder, string fieldName, unsigned depth) con BSONObjBuilder *pBuilder, string fieldName,
st; bool requireExpression) const;
virtual void addToBsonArray( virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const;
BSONArrayBuilder *pBuilder, unsigned depth) const; virtual void addDependencies(
const intrusive_ptr<DependencyTracker> &pTracker,
const DocumentSource *pSource) const;
/* /*
Add an operand to the n-ary expression. Add an operand to the n-ary expression.
@param pExpression the expression to add @param pExpression the expression to add
*/ */
virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n); virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n);
/* /*
Return a factory function that will make Expression nodes of Return a factory function that will make Expression nodes of
skipping to change at line 250 skipping to change at line 273
@returns the name of the operator; this string belongs to the cla ss @returns the name of the operator; this string belongs to the cla ss
implementation, and should not be deleted implementation, and should not be deleted
and should not and should not
*/ */
virtual const char *getOpName() const = 0; virtual const char *getOpName() const = 0;
protected: protected:
ExpressionNary(); ExpressionNary();
vector<intrusive_ptr<Expression> > vpOperand; ExpressionVector vpOperand;
/* /*
Add the expression to the builder. Add the expression to the builder.
If there is only one operand (a unary operator), then the operand If there is only one operand (a unary operator), then the operand
is added directly, without an array. For more than one operand, is added directly, without an array. For more than one operand,
a named array is created. In both cases, the result is an object . a named array is created. In both cases, the result is an object .
@param pBuilder the (blank) builder to add the expression to @param pBuilder the (blank) builder to add the expression to
@param pOpName the name of the operator @param pOpName the name of the operator
*/ */
virtual void toBson(BSONObjBuilder *pBuilder, virtual void toBson(BSONObjBuilder *pBuilder,
const char *pOpName, unsigned depth) const; const char *pOpName) const;
/* /*
Checks the current size of vpOperand; if the size equal to or Checks the current size of vpOperand; if the size equal to or
greater than maxArgs, fires a user assertion indicating that this greater than maxArgs, fires a user assertion indicating that this
operator cannot have this many arguments. operator cannot have this many arguments.
The equal is there because this is intended to be used in The equal is there because this is intended to be used in
addOperand() to check for the limit *before* adding the requested addOperand() to check for the limit *before* adding the requested
argument. argument.
skipping to change at line 314 skipping to change at line 337
/* /*
Create an expression that finds the sum of n operands. Create an expression that finds the sum of n operands.
@returns addition expression @returns addition expression
*/ */
static intrusive_ptr<ExpressionNary> create(); static intrusive_ptr<ExpressionNary> create();
protected: protected:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual void toBson(BSONObjBuilder *pBuilder, virtual void toBson(BSONObjBuilder *pBuilder,
const char *pOpName, unsigned depth) const; const char *pOpName) const;
private: private:
ExpressionAdd(); ExpressionAdd();
/* /*
If the operator can be optimized, we save the original here. If the operator can be optimized, we save the original here.
This is necessary because addition must follow its original opera nd This is necessary because addition must follow its original opera nd
ordering strictly if a string is detected, otherwise string ordering strictly if a string is detected, otherwise string
concatenation may appear to have re-ordered the operands. concatenation may appear to have re-ordered the operands.
skipping to change at line 339 skipping to change at line 362
class ExpressionAnd : class ExpressionAnd :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from Expression // virtuals from Expression
virtual ~ExpressionAnd(); virtual ~ExpressionAnd();
virtual intrusive_ptr<Expression> optimize(); virtual intrusive_ptr<Expression> optimize();
virtual intrusive_ptr<const Value> evaluate( virtual intrusive_ptr<const Value> evaluate(
const intrusive_ptr<Document> &pDocument) const; const intrusive_ptr<Document> &pDocument) const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
virtual void toMatcherBson( virtual void toMatcherBson(BSONObjBuilder *pBuilder) const;
BSONObjBuilder *pBuilder, unsigned depth) const;
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual intrusive_ptr<ExpressionNary> (*getFactory() const)(); virtual intrusive_ptr<ExpressionNary> (*getFactory() const)();
/* /*
Create an expression that finds the conjunction of n operands. Create an expression that finds the conjunction of n operands.
The conjunction uses short-circuit logic; the expressions are The conjunction uses short-circuit logic; the expressions are
evaluated in the order they were added to the conjunction, and evaluated in the order they were added to the conjunction, and
the evaluation stops and returns false on the first operand that the evaluation stops and returns false on the first operand that
evaluates to false. evaluates to false.
@returns conjunction expression @returns conjunction expression
*/ */
static intrusive_ptr<ExpressionNary> create(); static intrusive_ptr<ExpressionNary> create();
private: private:
ExpressionAnd(); ExpressionAnd();
}; };
class ExpressionCoerceToBool : class ExpressionCoerceToBool :
public Expression, public Expression {
public boost::enable_shared_from_this<ExpressionCoerceToBool> {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionCoerceToBool(); virtual ~ExpressionCoerceToBool();
virtual intrusive_ptr<Expression> optimize(); virtual intrusive_ptr<Expression> optimize();
virtual void addDependencies(
const intrusive_ptr<DependencyTracker> &pTracker,
const DocumentSource *pSource) const;
virtual intrusive_ptr<const Value> evaluate( virtual intrusive_ptr<const Value> evaluate(
const intrusive_ptr<Document> &pDocument) const; const intrusive_ptr<Document> &pDocument) const;
virtual void addToBsonObj( virtual void addToBsonObj(
BSONObjBuilder *pBuilder, string fieldName, unsigned depth) con BSONObjBuilder *pBuilder, string fieldName,
st; bool requireExpression) const;
virtual void addToBsonArray( virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const;
BSONArrayBuilder *pBuilder, unsigned depth) const;
static intrusive_ptr<ExpressionCoerceToBool> create( static intrusive_ptr<ExpressionCoerceToBool> create(
const intrusive_ptr<Expression> &pExpression); const intrusive_ptr<Expression> &pExpression);
private: private:
ExpressionCoerceToBool(const intrusive_ptr<Expression> &pExpression ); ExpressionCoerceToBool(const intrusive_ptr<Expression> &pExpression );
intrusive_ptr<Expression> pExpression; intrusive_ptr<Expression> pExpression;
}; };
skipping to change at line 434 skipping to change at line 458
virtual const char *getOpName() const; virtual const char *getOpName() const;
virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n); virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n);
static intrusive_ptr<ExpressionNary> create(); static intrusive_ptr<ExpressionNary> create();
private: private:
ExpressionCond(); ExpressionCond();
}; };
class ExpressionConstant : class ExpressionConstant :
public Expression, public Expression {
public boost::enable_shared_from_this<ExpressionConstant> {
public: public:
// virtuals from Expression // virtuals from Expression
virtual ~ExpressionConstant(); virtual ~ExpressionConstant();
virtual intrusive_ptr<Expression> optimize(); virtual intrusive_ptr<Expression> optimize();
virtual void addDependencies(
const intrusive_ptr<DependencyTracker> &pTracker,
const DocumentSource *pSource) const;
virtual intrusive_ptr<const Value> evaluate( virtual intrusive_ptr<const Value> evaluate(
const intrusive_ptr<Document> &pDocument) const; const intrusive_ptr<Document> &pDocument) const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
virtual void addToBsonObj( virtual void addToBsonObj(
BSONObjBuilder *pBuilder, string fieldName, unsigned depth) con BSONObjBuilder *pBuilder, string fieldName,
st; bool requireExpression) const;
virtual void addToBsonArray( virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const;
BSONArrayBuilder *pBuilder, unsigned depth) const;
static intrusive_ptr<ExpressionConstant> createFromBsonElement( static intrusive_ptr<ExpressionConstant> createFromBsonElement(
BSONElement *pBsonElement); BSONElement *pBsonElement);
static intrusive_ptr<ExpressionConstant> create( static intrusive_ptr<ExpressionConstant> create(
const intrusive_ptr<const Value> &pValue); const intrusive_ptr<const Value> &pValue);
/* /*
Get the constant value represented by this Expression. Get the constant value represented by this Expression.
@returns the value @returns the value
skipping to change at line 532 skipping to change at line 558
virtual const char *getOpName() const; virtual const char *getOpName() const;
virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n); virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n);
static intrusive_ptr<ExpressionNary> create(); static intrusive_ptr<ExpressionNary> create();
private: private:
ExpressionDivide(); ExpressionDivide();
}; };
class ExpressionFieldPath : class ExpressionFieldPath :
public Expression, public Expression {
public boost::enable_shared_from_this<ExpressionFieldPath> {
public: public:
// virtuals from Expression // virtuals from Expression
virtual ~ExpressionFieldPath(); virtual ~ExpressionFieldPath();
virtual intrusive_ptr<Expression> optimize(); virtual intrusive_ptr<Expression> optimize();
virtual void addDependencies(
const intrusive_ptr<DependencyTracker> &pTracker,
const DocumentSource *pSource) const;
virtual intrusive_ptr<const Value> evaluate( virtual intrusive_ptr<const Value> evaluate(
const intrusive_ptr<Document> &pDocument) const; const intrusive_ptr<Document> &pDocument) const;
virtual void addToBsonObj( virtual void addToBsonObj(
BSONObjBuilder *pBuilder, string fieldName, unsigned depth) con BSONObjBuilder *pBuilder, string fieldName,
st; bool requireExpression) const;
virtual void addToBsonArray( virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const;
BSONArrayBuilder *pBuilder, unsigned depth) const;
/* /*
Create a field path expression. Create a field path expression.
Evaluation will extract the value associated with the given field Evaluation will extract the value associated with the given field
path from the source document. path from the source document.
@param fieldPath the field path string, without any leading docum ent @param fieldPath the field path string, without any leading docum ent
indicator indicator
@returns the newly created field path expression @returns the newly created field path expression
skipping to change at line 601 skipping to change at line 629
@returns the field found; could be an array @returns the field found; could be an array
*/ */
intrusive_ptr<const Value> evaluatePath( intrusive_ptr<const Value> evaluatePath(
size_t index, const size_t pathLength, size_t index, const size_t pathLength,
intrusive_ptr<Document> pDocument) const; intrusive_ptr<Document> pDocument) const;
FieldPath fieldPath; FieldPath fieldPath;
}; };
class ExpressionFieldRange : class ExpressionFieldRange :
public Expression, public Expression {
public boost::enable_shared_from_this<ExpressionFieldRange> {
public: public:
// virtuals from expression // virtuals from expression
virtual ~ExpressionFieldRange(); virtual ~ExpressionFieldRange();
virtual intrusive_ptr<Expression> optimize(); virtual intrusive_ptr<Expression> optimize();
virtual void addDependencies(
const intrusive_ptr<DependencyTracker> &pTracker,
const DocumentSource *pSource) const;
virtual intrusive_ptr<const Value> evaluate( virtual intrusive_ptr<const Value> evaluate(
const intrusive_ptr<Document> &pDocument) const; const intrusive_ptr<Document> &pDocument) const;
virtual void addToBsonObj( virtual void addToBsonObj(
BSONObjBuilder *pBuilder, string fieldName, unsigned depth) con BSONObjBuilder *pBuilder, string fieldName,
st; bool requireExpression) const;
virtual void addToBsonArray( virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const;
BSONArrayBuilder *pBuilder, unsigned depth) const; virtual void toMatcherBson(BSONObjBuilder *pBuilder) const;
virtual void toMatcherBson(
BSONObjBuilder *pBuilder, unsigned depth) const;
/* /*
Create a field range expression. Create a field range expression.
Field ranges are meant to match up with classic Matcher semantics , Field ranges are meant to match up with classic Matcher semantics ,
and therefore are conjunctions. For example, these appear in and therefore are conjunctions. For example, these appear in
mongo shell predicates in one of these forms: mongo shell predicates in one of these forms:
{ a : C } -> (a == C) // degenerate "point" range { a : C } -> (a == C) // degenerate "point" range
{ a : { $lt : C } } -> (a < C) // open range { a : { $lt : C } } -> (a < C) // open range
{ a : { $gt : C1, $lte : C2 } } -> ((a > C1) && (a <= C2)) // clo sed { a : { $gt : C1, $lte : C2 } } -> ((a > C1) && (a <= C2)) // clo sed
skipping to change at line 690 skipping to change at line 719
/* /*
Add to a generic Builder. Add to a generic Builder.
The methods to append items to an object and an array differ by The methods to append items to an object and an array differ by
their inclusion of a field name. For more complicated objects, their inclusion of a field name. For more complicated objects,
it makes sense to abstract that out and use a generic builder tha t it makes sense to abstract that out and use a generic builder tha t
always looks the same, and then implement addToBsonObj() and always looks the same, and then implement addToBsonObj() and
addToBsonArray() by using the common method. addToBsonArray() by using the common method.
*/ */
void addToBson(Builder *pBuilder, unsigned depth) const; void addToBson(Builder *pBuilder) const;
}; };
class ExpressionHour : class ExpressionHour :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionHour(); virtual ~ExpressionHour();
virtual intrusive_ptr<const Value> evaluate( virtual intrusive_ptr<const Value> evaluate(
const intrusive_ptr<Document> &pDocument) const; const intrusive_ptr<Document> &pDocument) const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
skipping to change at line 725 skipping to change at line 754
const intrusive_ptr<Document> &pDocument) const; const intrusive_ptr<Document> &pDocument) const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n); virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n);
static intrusive_ptr<ExpressionNary> create(); static intrusive_ptr<ExpressionNary> create();
private: private:
ExpressionIfNull(); ExpressionIfNull();
}; };
class ExpressionIsoDate :
public ExpressionNary {
public:
// virtuals from ExpressionNary
virtual ~ExpressionIsoDate();
virtual intrusive_ptr<const Value> evaluate(
const intrusive_ptr<Document> &pDocument) const;
virtual const char *getOpName() const;
virtual void addOperand(const intrusive_ptr<Expression> &pExpressio
n);
static intrusive_ptr<ExpressionNary> create();
private:
ExpressionIsoDate();
static const char argYear[];
static const char argMonth[];
static const char argDayOfMonth[];
static const char argHour[];
static const char argMinute[];
static const char argSecond[];
static const unsigned flagYear;
static const unsigned flagMonth;
static const unsigned flagDayOfMonth;
static const unsigned flagHour;
static const unsigned flagMinute;
static const unsigned flagSecond;
unsigned flag;
/**
Get a named long argument out of the given document.
@param pArgs the evaluated document with the named arguments in
it
@param pName the name of the argument
@param defaultValue the value to return if the argument isn't fo
und
@returns the value if found, otherwise zero
@throws uassert for non-whole numbers or non-numbers
*/
int getIntArg(
const intrusive_ptr<Document> &pArgs,
const char *pName, int defaultValue) const;
/**
Check that the named argument fits in an integer.
@params pName the name of the argument
@params value the long value of the argument
@returns the integer value
@throws uassert if the value is out of range
*/
int checkIntRange(const char *pName, long long value) const;
};
class ExpressionMinute : class ExpressionMinute :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionMinute(); virtual ~ExpressionMinute();
virtual intrusive_ptr<const Value> evaluate( virtual intrusive_ptr<const Value> evaluate(
const intrusive_ptr<Document> &pDocument) const; const intrusive_ptr<Document> &pDocument) const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n); virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n);
skipping to change at line 830 skipping to change at line 913
virtual const char *getOpName() const; virtual const char *getOpName() const;
virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n); virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n);
static intrusive_ptr<ExpressionNary> create(); static intrusive_ptr<ExpressionNary> create();
private: private:
ExpressionNot(); ExpressionNot();
}; };
class ExpressionObject : class ExpressionObject :
public Expression, public Expression {
public boost::enable_shared_from_this<ExpressionObject> {
public: public:
// virtuals from Expression // virtuals from Expression
virtual ~ExpressionObject(); virtual ~ExpressionObject();
virtual intrusive_ptr<Expression> optimize(); virtual intrusive_ptr<Expression> optimize();
virtual void addDependencies(
const intrusive_ptr<DependencyTracker> &pTracker,
const DocumentSource *pSource) const;
virtual intrusive_ptr<const Value> evaluate( virtual intrusive_ptr<const Value> evaluate(
const intrusive_ptr<Document> &pDocument) const; const intrusive_ptr<Document> &pDocument) const;
virtual void addToBsonObj( virtual void addToBsonObj(
BSONObjBuilder *pBuilder, string fieldName, unsigned depth) con BSONObjBuilder *pBuilder, string fieldName,
st; bool requireExpression) const;
virtual void addToBsonArray( virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const;
BSONArrayBuilder *pBuilder, unsigned depth) const;
/* /*
evaluate(), but return a Document instead of a Value-wrapped evaluate(), but return a Document instead of a Value-wrapped
Document. Document.
@param pDocument the input Document @param pDocument the input Document
@returns the result document @returns the result document
*/ */
intrusive_ptr<Document> evaluateDocument( intrusive_ptr<Document> evaluateDocument(
const intrusive_ptr<Document> &pDocument) const; const intrusive_ptr<Document> &pDocument) const;
/* /*
evaluate(), but add the evaluated fields to a given document evaluate(), but add the evaluated fields to a given document
instead of creating a new one. instead of creating a new one.
@param pResult the Document to add the evaluated expressions to @param pResult the Document to add the evaluated expressions to
@param pDocument the input Document @param pDocument the input Document
@param excludeId for exclusions, exclude the _id, if present
*/ */
void addToDocument(const intrusive_ptr<Document> &pResult, void addToDocument(const intrusive_ptr<Document> &pResult,
const intrusive_ptr<Document> &pDocument) const; const intrusive_ptr<Document> &pDocument,
bool excludeId = false) const;
/* /*
Estimate the number of fields that will result from evaluating Estimate the number of fields that will result from evaluating
this over pDocument. Does not include _id. This is an estimate this over pDocument. Does not include _id. This is an estimate
(really an upper bound) because we can't account for undefined (really an upper bound) because we can't account for undefined
fields without actually doing the evaluation. But this is still fields without actually doing the evaluation. But this is still
useful as an argument to Document::create(), if you plan to use useful as an argument to Document::create(), if you plan to use
addToDocument(). addToDocument().
@param pDocument the input document @param pDocument the input document
skipping to change at line 914 skipping to change at line 1001
Add a field path to the set of those to be excluded. Add a field path to the set of those to be excluded.
Note that excluding a nested field implies including everything o n Note that excluding a nested field implies including everything o n
the path leading down to it (because you're stating you want to s ee the path leading down to it (because you're stating you want to s ee
all the other fields that aren't being excluded). all the other fields that aren't being excluded).
@param fieldName the name of the field to be excluded @param fieldName the name of the field to be excluded
*/ */
void excludePath(const string &fieldPath); void excludePath(const string &fieldPath);
/**
Get an iterator that can be used to iterate over all the result
field names in this ExpressionObject.
@returns the (intrusive_ptr'ed) iterator
*/
Iterator<string> *getFieldIterator() const;
/* /*
Return the expression for a field. Return the expression for a field.
@param fieldName the field name for the expression to return @param fieldName the field name for the expression to return
@returns the expression used to compute the field, if it is prese nt, @returns the expression used to compute the field, if it is prese nt,
otherwise NULL. otherwise NULL.
*/ */
intrusive_ptr<Expression> getField(const string &fieldName) const; intrusive_ptr<Expression> getField(const string &fieldName) const;
/* /*
skipping to change at line 943 skipping to change at line 1038
@returns how many fields have been excluded. @returns how many fields have been excluded.
*/ */
size_t getExclusionCount() const; size_t getExclusionCount() const;
/* /*
Specialized BSON conversion that allows for writing out a Specialized BSON conversion that allows for writing out a
$project specification. This creates a standalone object, which must $project specification. This creates a standalone object, which must
be added to a containing object with a name be added to a containing object with a name
@param pBuilder where to write the object to @param pBuilder where to write the object to
@param requireExpression see Expression::addToBsonObj
*/
void documentToBson(BSONObjBuilder *pBuilder,
bool requireExpression) const;
/*
Visitor abstraction used by emitPaths(). Each path is recorded b
y
calling path().
*/
class PathSink {
public:
virtual ~PathSink() {};
/**
Record a path.
@param path the dotted path string
@param include if true, the path is included; if false, the
path
is excluded
*/
virtual void path(const string &path, bool include) = 0;
};
/**
Emit the field paths that have been included or excluded. "Inclu
ded"
includes paths that are referenced in expressions for computed
fields.
@param pSink where to write the paths to
@param pvPath pointer to a vector of strings describing the path
on
descent; the top-level call should pass an empty vector
*/ */
void documentToBson(BSONObjBuilder *pBuilder, unsigned depth) const ; void emitPaths(PathSink *pPathSink) const;
private: private:
ExpressionObject(); ExpressionObject();
void includePath( void includePath(
const FieldPath *pPath, size_t pathi, size_t pathn, const FieldPath *pPath, size_t pathi, size_t pathn,
bool excludeLast); bool excludeLast);
bool excludePaths; bool excludePaths;
set<string> path; set<string> path;
/* these two vectors are maintained in parallel */ /* these two vectors are maintained in parallel */
vector<string> vFieldName; vector<string> vFieldName;
vector<intrusive_ptr<Expression> > vpExpression; vector<intrusive_ptr<Expression> > vpExpression;
/* /*
Utility function used by documentToBson(). Emits inclusion Utility function used by documentToBson(). Emits inclusion
and exclusion paths by recursively walking down the nested and exclusion paths by recursively walking down the nested
ExpressionObject trees these have created. ExpressionObject trees these have created.
@param pBuilder the builder to write boolean valued path "fields" to @param pSink where to write the paths to
@param pvPath pointer to a vector of strings describing the path on @param pvPath pointer to a vector of strings describing the path on
descent; the top-level call should pass an empty vector descent; the top-level call should pass an empty vector
*/ */
void emitPaths(BSONObjBuilder *pBuilder, vector<string> *pvPath) co void emitPaths(PathSink *pPathSink, vector<string> *pvPath) const;
nst;
/*
Utility object for collecting emitPaths() results in a BSON
object.
*/
class BuilderPathSink :
public PathSink {
public:
// virtuals from PathSink
virtual void path(const string &path, bool include);
/*
Create a PathSink that writes paths to a BSONObjBuilder,
to create an object in the form of { path:is_included,...}
This object uses a builder pointer that won't guarantee the
lifetime of the builder, so make sure it outlasts the use of
this for an emitPaths() call.
@param pBuilder to the builder to write paths to
*/
BuilderPathSink(BSONObjBuilder *pBuilder);
private:
BSONObjBuilder *pBuilder;
};
/* utility class used by emitPaths() */ /* utility class used by emitPaths() */
class PathPusher : class PathPusher :
boost::noncopyable { boost::noncopyable {
public: public:
PathPusher(vector<string> *pvPath, const string &s); PathPusher(vector<string> *pvPath, const string &s);
~PathPusher(); ~PathPusher();
private: private:
vector<string> *pvPath; vector<string> *pvPath;
skipping to change at line 992 skipping to change at line 1144
class ExpressionOr : class ExpressionOr :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from Expression // virtuals from Expression
virtual ~ExpressionOr(); virtual ~ExpressionOr();
virtual intrusive_ptr<Expression> optimize(); virtual intrusive_ptr<Expression> optimize();
virtual intrusive_ptr<const Value> evaluate( virtual intrusive_ptr<const Value> evaluate(
const intrusive_ptr<Document> &pDocument) const; const intrusive_ptr<Document> &pDocument) const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
virtual void toMatcherBson( virtual void toMatcherBson(BSONObjBuilder *pBuilder) const;
BSONObjBuilder *pBuilder, unsigned depth) const;
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual intrusive_ptr<ExpressionNary> (*getFactory() const)(); virtual intrusive_ptr<ExpressionNary> (*getFactory() const)();
/* /*
Create an expression that finds the conjunction of n operands. Create an expression that finds the conjunction of n operands.
The conjunction uses short-circuit logic; the expressions are The conjunction uses short-circuit logic; the expressions are
evaluated in the order they were added to the conjunction, and evaluated in the order they were added to the conjunction, and
the evaluation stops and returns false on the first operand that the evaluation stops and returns false on the first operand that
evaluates to false. evaluates to false.
skipping to change at line 1179 skipping to change at line 1330
inline void ExpressionFieldPath::writeFieldPath( inline void ExpressionFieldPath::writeFieldPath(
ostream &outStream, bool fieldPrefix) const { ostream &outStream, bool fieldPrefix) const {
return fieldPath.writePath(outStream, fieldPrefix); return fieldPath.writePath(outStream, fieldPrefix);
} }
inline size_t ExpressionObject::getFieldCount() const { inline size_t ExpressionObject::getFieldCount() const {
return vFieldName.size(); return vFieldName.size();
} }
inline ExpressionObject::BuilderPathSink::BuilderPathSink(
BSONObjBuilder *pB):
pBuilder(pB) {
}
inline ExpressionObject::PathPusher::PathPusher( inline ExpressionObject::PathPusher::PathPusher(
vector<string> *pTheVPath, const string &s): vector<string> *pTheVPath, const string &s):
pvPath(pTheVPath) { pvPath(pTheVPath) {
pvPath->push_back(s); pvPath->push_back(s);
} }
inline ExpressionObject::PathPusher::~PathPusher() { inline ExpressionObject::PathPusher::~PathPusher() {
pvPath->pop_back(); pvPath->pop_back();
} }
 End of changes. 42 change blocks. 
56 lines changed or deleted 213 lines changed or added


 expression_context.h   expression_context.h 
skipping to change at line 25 skipping to change at line 25
*/ */
#pragma once #pragma once
#include "pch.h" #include "pch.h"
#include "util/intrusive_counter.h" #include "util/intrusive_counter.h"
namespace mongo { namespace mongo {
class InterruptStatus;
class ExpressionContext : class ExpressionContext :
public IntrusiveCounterUnsigned { public IntrusiveCounterUnsigned {
public: public:
virtual ~ExpressionContext(); virtual ~ExpressionContext();
void setInShard(bool b); void setInShard(bool b);
void setInRouter(bool b); void setInRouter(bool b);
bool getInShard() const; bool getInShard() const;
bool getInRouter() const; bool getInRouter() const;
static ExpressionContext *create(); /**
Used by a pipeline to check for interrupts so that killOp() work
s.
@throws if the operation has been interrupted
*/
void checkForInterrupt();
static ExpressionContext *create(InterruptStatus *pStatus);
private: private:
ExpressionContext(); ExpressionContext(InterruptStatus *pStatus);
bool inShard; bool inShard;
bool inRouter; bool inRouter;
unsigned intCheckCounter; // interrupt check counter
InterruptStatus *const pStatus;
}; };
} }
/* ======================= INLINED IMPLEMENTATIONS ======================== == */ /* ======================= INLINED IMPLEMENTATIONS ======================== == */
namespace mongo { namespace mongo {
inline void ExpressionContext::setInShard(bool b) { inline void ExpressionContext::setInShard(bool b) {
inShard = b; inShard = b;
} }
 End of changes. 4 change blocks. 
2 lines changed or deleted 14 lines changed or added


 extsort.h   extsort.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 "../pch.h" #include "pch.h"
#include "jsobj.h"
#include "namespace-inl.h" #include "mongo/db/index.h"
#include "curop-inl.h" #include "mongo/db/jsobj.h"
#include "../util/array.h" #include "mongo/db/namespace-inl.h"
#include "mongo/db/curop-inl.h"
#include "mongo/util/array.h"
#include "mongo/util/mmap.h"
namespace mongo { namespace mongo {
/** /**
for external (disk) sorting by BSONObj and attaching a value for external (disk) sorting by BSONObj and attaching a value
*/ */
class BSONObjExternalSorter : boost::noncopyable { class BSONObjExternalSorter : boost::noncopyable {
public: public:
BSONObjExternalSorter( IndexInterface &i, const BSONObj & order = B SONObj() , long maxFileSize = 1024 * 1024 * 100 ); BSONObjExternalSorter( IndexInterface &i, const BSONObj & order = B SONObj() , long maxFileSize = 1024 * 1024 * 100 );
~BSONObjExternalSorter(); ~BSONObjExternalSorter();
typedef pair<BSONObj,DiskLoc> Data; typedef pair<BSONObj,DiskLoc> Data;
private: private:
static HLMutex _extSortMutex;
IndexInterface& _idxi; IndexInterface& _idxi;
static int _compare(IndexInterface& i, const Data& l, const Data& r static int _compare(IndexInterface& i, const Data& l, const Data& r
, const Ordering& order) { , const Ordering& order);
RARELY killCurrentOp.checkForInterrupt();
_compares++;
int x = i.keyCompare(l.first, r.first, order);
if ( x )
return x;
return l.second.compare( r.second );
}
class MyCmp { class MyCmp {
public: public:
MyCmp( IndexInterface& i, BSONObj order = BSONObj() ) : _i(i), _order( Ordering::make(order) ) {} MyCmp( IndexInterface& i, BSONObj order = BSONObj() ) : _i(i), _order( Ordering::make(order) ) {}
bool operator()( const Data &l, const Data &r ) const { bool operator()( const Data &l, const Data &r ) const {
return _compare(_i, l, r, _order) < 0; return _compare(_i, l, r, _order) < 0;
}; };
private: private:
IndexInterface& _i; IndexInterface& _i;
const Ordering _order; const Ordering _order;
}; };
static IndexInterface *extSortIdxInterface; static IndexInterface *extSortIdxInterface;
static Ordering extSortOrder; static Ordering extSortOrder;
static int extSortComp( const void *lv, const void *rv ) { static int extSortComp( const void *lv, const void *rv );
DEV RARELY {
d.dbMutex.assertWriteLocked(); // must be as we use a globa
l var
}
Data * l = (Data*)lv;
Data * r = (Data*)rv;
return _compare(*extSortIdxInterface, *l, *r, extSortOrder);
};
class FileIterator : boost::noncopyable { class FileIterator : boost::noncopyable {
public: public:
FileIterator( string file ); FileIterator( string file );
~FileIterator(); ~FileIterator();
bool more(); bool more();
Data next(); Data next();
private: private:
MemoryMappedFile _file; MemoryMappedFile _file;
char * _buf; char * _buf;
 End of changes. 4 change blocks. 
23 lines changed or deleted 12 lines changed or added


 field_path.h   field_path.h 
skipping to change at line 27 skipping to change at line 27
#pragma once #pragma once
#include "pch.h" #include "pch.h"
namespace mongo { namespace mongo {
class FieldPath { class FieldPath {
public: public:
virtual ~FieldPath(); virtual ~FieldPath();
/**
Constructor.
@param fieldPath the dotted field path string
*/
FieldPath(const string &fieldPath); FieldPath(const string &fieldPath);
/**
Constructor.
*/
FieldPath(); FieldPath();
/* /**
Get the number of path elements in the field path. Get the number of path elements in the field path.
@returns the number of path elements @returns the number of path elements
*/ */
size_t getPathLength() const; size_t getPathLength() const;
/* /**
Get a particular path element from the path. Get a particular path element from the path.
@param i the index of the path element @param i the index of the path element
@returns the path element @returns the path element
*/ */
string getFieldName(size_t i) const; string getFieldName(size_t i) const;
/* /**
Get the full path. Get the full path.
@param fieldPrefix whether or not to include the field prefix @param fieldPrefix whether or not to include the field prefix
@returns the complete field path @returns the complete field path
*/ */
string getPath(bool fieldPrefix) const; string getPath(bool fieldPrefix) const;
/* /**
Write the full path. Write the full path.
@param outStream where to write the path to @param outStream where to write the path to
@param fieldPrefix whether or not to include the field prefix @param fieldPrefix whether or not to include the field prefix
*/ */
void writePath(ostream &outStream, bool fieldPrefix) const; void writePath(ostream &outStream, bool fieldPrefix) const;
/**
Assignment operator.
@param rRHS right hand side of the assignment
*/
FieldPath &operator=(const FieldPath &rRHS); FieldPath &operator=(const FieldPath &rRHS);
/**
Get the prefix string.
@returns the prefix string
*/
static const char *getPrefix();
static const char prefix[];
private: private:
vector<string> vFieldName; vector<string> vFieldName;
}; };
} }
/* ======================= INLINED IMPLEMENTATIONS ======================== == */ /* ======================= INLINED IMPLEMENTATIONS ======================== == */
namespace mongo { namespace mongo {
inline size_t FieldPath::getPathLength() const { inline size_t FieldPath::getPathLength() const {
return vFieldName.size(); return vFieldName.size();
} }
inline string FieldPath::getFieldName(size_t i) const { inline string FieldPath::getFieldName(size_t i) const {
return vFieldName[i]; return vFieldName[i];
} }
inline const char *FieldPath::getPrefix() {
return prefix;
}
} }
 End of changes. 9 change blocks. 
4 lines changed or deleted 31 lines changed or added


 file.h   file.h 
skipping to change at line 48 skipping to change at line 48
/* NOTE: not thread-safe. (at least the windows implementation isn't. * / /* NOTE: not thread-safe. (at least the windows implementation isn't. * /
class FileInterface { class FileInterface {
public: public:
void open(const char *fn) {} void open(const char *fn) {}
void write(fileofs o, const char *data, unsigned len) {} void write(fileofs o, const char *data, unsigned len) {}
void read(fileofs o, char *data, unsigned len) {} void read(fileofs o, char *data, unsigned len) {}
bool bad() {return false;} bool bad() {return false;}
bool is_open() {return false;} bool is_open() {return false;}
fileofs len() { return 0; } fileofs len() { return 0; }
void fsync() { assert(false); } void fsync() { verify(false); }
// shrink file to size bytes. No-op if file already smaller. // shrink file to size bytes. No-op if file already smaller.
void truncate(fileofs size); void truncate(fileofs size);
/** @return -1 if error or unavailable */ /** @return -1 if error or unavailable */
static boost::intmax_t freeSpace(const string &path) { assert(false ); return -1; } static boost::intmax_t freeSpace(const string &path) { verify(false ); return -1; }
}; };
#if defined(_WIN32) #if defined(_WIN32)
#include <io.h> #include <io.h>
class File : public FileInterface { class File : public FileInterface {
HANDLE fd; HANDLE fd;
bool _bad; bool _bad;
string _name; string _name;
void err(BOOL b=false) { /* false = error happened */ void err(BOOL b=false) { /* false = error happened */
skipping to change at line 213 skipping to change at line 213
fileofs len() { fileofs len() {
off_t o = lseek(fd, 0, SEEK_END); off_t o = lseek(fd, 0, SEEK_END);
if( o != (off_t) -1 ) if( o != (off_t) -1 )
return o; return o;
err(false); err(false);
return 0; return 0;
} }
void fsync() { ::fsync(fd); } void fsync() { ::fsync(fd); }
static boost::intmax_t freeSpace ( const string &path ) { static boost::intmax_t freeSpace ( const string &path ) {
struct statvfs info; struct statvfs info;
assert( !statvfs( path.c_str() , &info ) ); verify( !statvfs( path.c_str() , &info ) );
return boost::intmax_t( info.f_bavail ) * info.f_frsize; return boost::intmax_t( info.f_bavail ) * info.f_frsize;
} }
void truncate(fileofs size) { void truncate(fileofs size) {
if (len() <= size) if (len() <= size)
return; return;
err(ftruncate(fd, size) == 0); err(ftruncate(fd, size) == 0);
} }
}; };
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 file_allocator.h   file_allocator.h 
skipping to change at line 18 skipping to change at line 18
* *
* 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.
*/ */
#include "../pch.h" #include "pch.h"
#include <list>
#include <boost/thread/condition.hpp>
namespace mongo { namespace mongo {
/* /*
* 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.
* singleton * singleton
*/ */
class FileAllocator : boost::noncopyable { class FileAllocator : boost::noncopyable {
/* /*
skipping to change at line 77 skipping to change at line 81
// caller must hold pendingMutex_ lock. // caller must hold pendingMutex_ lock.
bool inProgress( const string &name ) const; bool inProgress( const string &name ) const;
/** called from the worked thread */ /** called from the worked thread */
static void run( FileAllocator * fa ); static void run( FileAllocator * fa );
mutable mongo::mutex _pendingMutex; mutable mongo::mutex _pendingMutex;
mutable boost::condition _pendingUpdated; mutable boost::condition _pendingUpdated;
list< string > _pending; std::list< string > _pending;
mutable map< string, long > _pendingSize; mutable map< string, long > _pendingSize;
bool _failed; bool _failed;
#endif #endif
static FileAllocator* _instance; static FileAllocator* _instance;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 2 change blocks. 
2 lines changed or deleted 6 lines changed or added


 framework.h   framework.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/>.
*/ */
/* /*
simple portable regression system simple portable regression system
*/ */
#include "../pch.h" #include <string>
#define ASSERT_THROWS(a,b) \
try { \
a; \
mongo::regression::assert_fail( #a , __FILE__ , __LINE__ ); \
} catch ( b& ){ \
mongo::regression::assert_pass(); \
}
#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 FAIL(x) mongo::regression::fail( #x , __FILE__ , __LINE__ )
#include "../db/instance.h"
namespace mongo { namespace mongo {
namespace dbtests {
namespace regression { int runDbTests( int argc, char ** argv, string default_dbpath );
} // dbtests
class Result; } // namespace mongo
class TestCase {
public:
virtual ~TestCase() {}
virtual void run() = 0;
virtual string getName() = 0;
};
template< class T >
class TestHolderBase : public TestCase {
public:
TestHolderBase() {}
virtual ~TestHolderBase() {}
virtual void run() {
auto_ptr<T> t;
t.reset( create() );
t->run();
}
virtual T * create() = 0;
virtual string getName() {
return demangleName( typeid(T) );
}
};
template< class T >
class TestHolder0 : public TestHolderBase<T> {
public:
virtual T * create() {
return new T();
}
};
template< class T , typename A >
class TestHolder1 : public TestHolderBase<T> {
public:
TestHolder1( const A& a ) : _a(a) {}
virtual T * create() {
return new T( _a );
}
const A& _a;
};
class Suite {
public:
Suite( string name ) : _name( name ) {
registerSuite( name , this );
_ran = 0;
}
virtual ~Suite() {
if ( _ran ) {
DBDirectClient c;
c.dropDatabase( "unittests" );
}
}
template<class T>
void add() {
_tests.push_back( new TestHolder0<T>() );
}
template<class T , typename A >
void add( const A& a ) {
_tests.push_back( new TestHolder1<T,A>(a) );
}
Result * run( const string& filter );
static int run( vector<string> suites , const string& filter );
static int run( int argc , char ** argv , string default_dbpath
);
protected:
virtual void setupTests() = 0;
private:
string _name;
list<TestCase*> _tests;
bool _ran;
static map<string,Suite*> * _suites;
void registerSuite( string name , Suite * s );
};
void assert_pass();
void assert_fail( const char * exp , const char * file , unsigned l
ine );
void fail( const char * exp , const char * file , unsigned line );
class MyAssertionException : boost::noncopyable {
public:
MyAssertionException() {
ss << "assertion: ";
}
stringstream ss;
};
class MyAsserts {
public:
MyAsserts( const char * aexp , const char * bexp , const char *
file , unsigned line )
: _aexp( aexp ) , _bexp( bexp ) , _file( file ) , _line( li
ne ) {
}
template<typename A,typename B>
void ae( 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;
}
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();
private:
void _gotAssert();
MyAssertionException * getBase();
string _aexp;
string _bexp;
string _file;
unsigned _line;
};
}
}
 End of changes. 2 change blocks. 
20 lines changed or deleted 1 lines changed or added


 goodies.h   goodies.h 
skipping to change at line 21 skipping to change at line 21
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "../bson/util/misc.h" #include <boost/detail/endian.hpp>
#include "concurrency/mutex.h" #include <boost/thread/condition_variable.hpp>
#include "mongo/bson/util/misc.h"
#include "mongo/util/concurrency/mutex.h"
#include "mongo/util/stacktrace.h"
namespace mongo { namespace mongo {
/* @return a dump of the buffer as hex byte ascii output */ /* @return a dump of the buffer as hex byte ascii output */
string hexdump(const char *data, unsigned len); string hexdump(const char *data, unsigned len);
/** /**
* @return if this name has an increasing counter associated, return th e value * @return if this name has an increasing counter associated, return th e value
* otherwise 0 * otherwise 0
*/ */
unsigned setThreadName(const char * name); long long setThreadName(const char * name);
string getThreadName(); string getThreadName();
template<class T> template<class T>
inline string ToString(const T& t) { inline string ToString(const T& t) {
stringstream s; stringstream s;
s << t; s << t;
return s.str(); return s.str();
} }
#if !defined(_WIN32) && !defined(NOEXECINFO) && !defined(__freebsd__) && !d
efined(__openbsd__) && !defined(__sun__)
} // namespace mongo
#include <pthread.h>
#include <execinfo.h>
namespace mongo {
inline pthread_t GetCurrentThreadId() {
return pthread_self();
}
/* use "addr2line -CFe <exe>" to parse. */
inline void printStackTrace(ostream &o = cout) {
void *b[20];
int size = backtrace(b, 20);
for (int i = 0; i < size; i++)
o << hex << b[i] << dec << ' ';
o << endl;
char **strings;
strings = backtrace_symbols(b, size);
for (int i = 0; i < size; i++)
o << ' ' << strings[i] << '\n';
o.flush();
free (strings);
}
#else
inline void printStackTrace(ostream &o = cout) { }
#endif
bool isPrime(int n); bool isPrime(int n);
int nextPrime(int n); int nextPrime(int n);
inline void dumpmemory(const char *data, int len) { inline void dumpmemory(const char *data, int len) {
if ( len > 1024 ) if ( len > 1024 )
len = 1024; len = 1024;
try { try {
const char *q = data; const char *q = data;
const char *p = q; const char *p = q;
while ( len > 0 ) { while ( len > 0 ) {
skipping to change at line 115 skipping to change at line 85
// PRINT(2+2); prints "2+2: 4" // PRINT(2+2); prints "2+2: 4"
#define MONGO_PRINT(x) cout << #x ": " << (x) << endl #define MONGO_PRINT(x) cout << #x ": " << (x) << endl
#define PRINT MONGO_PRINT #define PRINT MONGO_PRINT
// PRINTFL; prints file:line // PRINTFL; prints file:line
#define MONGO_PRINTFL cout << __FILE__ ":" << __LINE__ << endl #define MONGO_PRINTFL cout << __FILE__ ":" << __LINE__ << endl
#define PRINTFL MONGO_PRINTFL #define PRINTFL MONGO_PRINTFL
#define MONGO_FLOG log() << __FILE__ ":" << __LINE__ << endl #define MONGO_FLOG log() << __FILE__ ":" << __LINE__ << endl
#define FLOG MONGO_FLOG #define FLOG MONGO_FLOG
#undef assert
#define assert MONGO_assert
inline bool startsWith(const char *str, const char *prefix) { inline bool startsWith(const char *str, const char *prefix) {
size_t l = strlen(prefix); size_t l = strlen(prefix);
if ( strlen(str) < l ) return false; if ( strlen(str) < l ) return false;
return strncmp(str, prefix, l) == 0; return strncmp(str, prefix, l) == 0;
} }
inline bool startsWith(string s, string p) { return startsWith(s.c_str( ), p.c_str()); } inline bool startsWith(string s, string p) { return startsWith(s.c_str( ), p.c_str()); }
inline bool endsWith(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);
skipping to change at line 144 skipping to change at line 111
((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) {
return x; return x;
} }
#else #elif defined(BOOST_BIG_ENDIAN)
inline unsigned long fixEndian(unsigned long x) { inline unsigned long fixEndian(unsigned long x) {
return swapEndian(x); return swapEndian(x);
} }
#else
#error no boost endian header defined
#endif #endif
#if !defined(_WIN32) #if !defined(_WIN32)
typedef int HANDLE; typedef int HANDLE;
inline void strcpy_s(char *dst, unsigned len, const char *src) { inline void strcpy_s(char *dst, unsigned len, const char *src) {
assert( strlen(src) < len ); verify( strlen(src) < len );
strcpy(dst, src); strcpy(dst, src);
} }
#else #else
typedef void *HANDLE; typedef void *HANDLE;
#endif #endif
class ProgressMeter : boost::noncopyable {
public:
ProgressMeter( unsigned long long total , int secondsBetween = 3 ,
int checkInterval = 100 , string units = "" ) : _units(units) {
reset( total , secondsBetween , checkInterval );
}
ProgressMeter() {
_active = 0;
_units = "";
}
// typically you do ProgressMeterHolder
void reset( unsigned long long total , int secondsBetween = 3 , int
checkInterval = 100 ) {
_total = total;
_secondsBetween = secondsBetween;
_checkInterval = checkInterval;
_done = 0;
_hits = 0;
_lastTime = (int)time(0);
_active = 1;
}
void finished() {
_active = 0;
}
bool isActive() {
return _active;
}
/**
* @param n how far along we are relative to the total # we set in
CurOp::setMessage
* @return if row was printed
*/
bool hit( int n = 1 ) {
if ( ! _active ) {
cout << "warning: hit an inactive ProgressMeter" << endl;
return false;
}
_done += n;
_hits++;
if ( _hits % _checkInterval )
return false;
int t = (int) time(0);
if ( t - _lastTime < _secondsBetween )
return false;
if ( _total > 0 ) {
int per = (int)( ( (double)_done * 100.0 ) / (double)_total
);
cout << "\t\t" << _done << "/" << _total << "\t" << per <<
"%";
if ( ! _units.empty() ) {
cout << "\t(" << _units << ")" << endl;
}
else {
cout << endl;
}
}
_lastTime = t;
return true;
}
void setUnits( string units ) {
_units = units;
}
void setTotalWhileRunning( unsigned long long total ) {
_total = total;
}
unsigned long long done() const { return _done; }
unsigned long long hits() const { return _hits; }
unsigned long long total() const { return _total; }
string toString() const {
if ( ! _active )
return "";
stringstream buf;
buf << _done << "/" << _total << " " << (_done*100)/_total << "
%";
if ( ! _units.empty() ) {
buf << "\t(" << _units << ")" << endl;
}
return buf.str();
}
bool operator==( const ProgressMeter& other ) const {
return this == &other;
}
private:
bool _active;
unsigned long long _total;
int _secondsBetween;
int _checkInterval;
unsigned long long _done;
unsigned long long _hits;
int _lastTime;
string _units;
};
// e.g.:
// CurOp * op = cc().curop();
// ProgressMeterHolder pm( op->setMessage( "index: (1/3) external sort"
, d->stats.nrecords , 10 ) );
// loop { pm.hit(); }
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 {
public:
TicketHolder( int num ) : _mutex("TicketHolder") {
_outof = num;
_num = num;
}
bool tryAcquire() {
scoped_lock lk( _mutex );
if ( _num <= 0 ) {
if ( _num < 0 ) {
cerr << "DISASTER! in TicketHolder" << endl;
}
return false;
}
_num--;
return true;
}
void release() {
scoped_lock lk( _mutex );
_num++;
}
void resize( int newSize ) {
scoped_lock lk( _mutex );
int used = _outof - _num;
if ( used > newSize ) {
cout << "ERROR: can't resize since we're using (" << used <
< ") more than newSize(" << newSize << ")" << endl;
return;
}
_outof = newSize;
_num = _outof - used;
}
int available() const {
return _num;
}
int used() const {
return _outof - _num;
}
int outof() const { return _outof; }
private:
int _outof;
int _num;
mongo::mutex _mutex;
};
class TicketHolderReleaser {
public:
TicketHolderReleaser( TicketHolder * holder ) {
_holder = holder;
}
~TicketHolderReleaser() {
_holder->release();
}
private:
TicketHolder * _holder;
};
/** /**
* this is a thread safe string * this is a thread safe string
* you will never get a bad pointer, though data may be mungedd * you will never get a bad pointer, though data may be mungedd
*/ */
class ThreadSafeString : boost::noncopyable { class ThreadSafeString : boost::noncopyable {
public: public:
ThreadSafeString( size_t size=256 ) ThreadSafeString( size_t size=256 )
: _size( size ) , _buf( new char[size] ) { : _size( size ) , _buf( new char[size] ) {
memset( _buf , 0 , _size ); memset( _buf , 0 , _size );
} }
skipping to change at line 470 skipping to change at line 229
operator T* () const { return _p; } operator T* () const { return _p; }
private: private:
T* _p; T* _p;
}; };
using boost::shared_ptr; using boost::shared_ptr;
using boost::scoped_ptr; using boost::scoped_ptr;
using boost::scoped_array; using boost::scoped_array;
using boost::intrusive_ptr; using boost::intrusive_ptr;
using boost::bad_lexical_cast;
using boost::dynamic_pointer_cast; using boost::dynamic_pointer_cast;
} // namespace mongo } // namespace mongo
 End of changes. 9 change blocks. 
262 lines changed or deleted 11 lines changed or added


 grid.h   grid.h 
skipping to change at line 83 skipping to change at line 83
bool addShard( string* name , const ConnectionString& servers , lon g long maxSize , string& errMsg ); bool addShard( string* name , const ConnectionString& servers , lon g long maxSize , string& errMsg );
/** /**
* @return true if the config database knows about a host 'name' * @return true if the config database knows about a host 'name'
*/ */
bool knowAboutShard( const string& name ) const; bool knowAboutShard( const string& name ) const;
/** /**
* @return true if the chunk balancing functionality is enabled * @return true if the chunk balancing functionality is enabled
*/ */
bool shouldBalance() const; bool shouldBalance( const string& ns = "" ) const;
/** /**
* *
* Obtain grid configuration and settings data. * Obtain grid configuration and settings data.
* *
* @param name identifies a particular type of configuration data. * @param name identifies a particular type of configuration data.
* @return a BSON object containing the requested data. * @return a BSON object containing the requested data.
*/ */
BSONObj getConfigSetting( string name ) const; BSONObj getConfigSetting( string name ) const;
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 gridfs.h   gridfs.h 
skipping to change at line 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 "dbclient.h" #include "mongo/bson/bsonelement.h"
#include "redef_macros.h" #include "mongo/bson/bsonobj.h"
#include "mongo/client/dbclientinterface.h"
namespace mongo { namespace mongo {
typedef unsigned long long gridfs_offset; typedef unsigned long long gridfs_offset;
class GridFS; class GridFS;
class GridFile; class GridFile;
class GridFSChunk { class GridFSChunk {
public: public:
skipping to change at line 203 skipping to change at line 204
GridFile(const GridFS * grid , BSONObj obj ); GridFile(const GridFS * grid , BSONObj obj );
void _exists() const; void _exists() const;
const GridFS * _grid; const GridFS * _grid;
BSONObj _obj; BSONObj _obj;
friend class GridFS; friend class GridFS;
}; };
} }
#include "undef_macros.h"
 End of changes. 2 change blocks. 
2 lines changed or deleted 3 lines changed or added


 hashtab.h   hashtab.h 
skipping to change at line 114 skipping to change at line 114
// 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;
if ( sizeof(Node) != 628 ) { if ( sizeof(Node) != 628 ) {
out() << "HashTable() " << _name << " sizeof(node):" << siz eof(Node) << " n:" << n << " sizeof(Key): " << sizeof(Key) << " sizeof(Type ):" << sizeof(Type) << endl; out() << "HashTable() " << _name << " sizeof(node):" << siz eof(Node) << " n:" << n << " sizeof(Key): " << sizeof(Key) << " sizeof(Type ):" << sizeof(Type) << endl;
assert( sizeof(Node) == 628 ); verify( 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;
skipping to change at line 150 skipping to change at line 150
bool found; bool found;
int i = _find(k, found); int i = _find(k, found);
if ( i < 0 ) if ( i < 0 )
return false; return false;
Node* n = getDur().writing( &nodes(i) ); Node* n = getDur().writing( &nodes(i) );
if ( !found ) { if ( !found ) {
n->k = k; n->k = k;
n->hash = k.hash(); n->hash = k.hash();
} }
else { else {
assert( n->hash == k.hash() ); verify( n->hash == k.hash() );
} }
n->value = value; n->value = value;
return true; return true;
} }
typedef void (*IteratorCallback)( const Key& k , Type& v ); typedef void (*IteratorCallback)( const Key& k , Type& v );
void iterAll( IteratorCallback callback ) { void iterAll( IteratorCallback callback ) {
for ( int i=0; i<n; i++ ) { for ( int i=0; i<n; i++ ) {
if ( nodes(i).inUse() ) { if ( nodes(i).inUse() ) {
callback( nodes(i).k , nodes(i).value ); callback( nodes(i).k , nodes(i).value );
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 hex.h   hex.h 
skipping to change at line 29 skipping to change at line 29
namespace mongo { namespace mongo {
//can't use hex namespace because it conflicts with hex iostream functi on //can't use hex namespace because it conflicts with hex iostream functi on
inline int fromHex( char c ) { inline int fromHex( char c ) {
if ( '0' <= c && c <= '9' ) if ( '0' <= c && c <= '9' )
return c - '0'; return c - '0';
if ( 'a' <= c && c <= 'f' ) if ( 'a' <= c && c <= 'f' )
return c - 'a' + 10; return c - 'a' + 10;
if ( 'A' <= c && c <= 'F' ) if ( 'A' <= c && c <= 'F' )
return c - 'A' + 10; return c - 'A' + 10;
assert( false ); verify( false );
return 0xff; return 0xff;
} }
inline char fromHex( const char *c ) { inline char fromHex( const char *c ) {
return (char)(( fromHex( c[ 0 ] ) << 4 ) | fromHex( c[ 1 ] )); return (char)(( fromHex( c[ 0 ] ) << 4 ) | fromHex( c[ 1 ] ));
} }
inline string toHex(const void* inRaw, int len) { inline string toHex(const void* inRaw, int len) {
static const char hexchars[] = "0123456789ABCDEF"; static const char hexchars[] = "0123456789ABCDEF";
StringBuilder out; StringBuilder out;
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 histogram.h   histogram.h 
// histogram.h
/** /**
* Copyright (C) 2008 10gen Inc. * Copyright (C) 2008 10gen Inc.
* *
* This program is free software: you can redistribute it and/or modify * 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 , * it under the terms of the GNU Affero General Public License, version 3 ,
* as published by the Free Software Foundation. * as published by the Free Software Foundation.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef UTIL_HISTOGRAM_HEADER #ifndef UTIL_HISTOGRAM_HEADER
#define UTIL_HISTOGRAM_HEADER #define UTIL_HISTOGRAM_HEADER
#include "../pch.h"
#include <string> #include <string>
#include <stdint.h>
namespace mongo { namespace mongo {
using std::string;
/** /**
* A histogram for a 32-bit integer range. * A histogram for a 32-bit integer range.
*/ */
class Histogram { class Histogram {
public: public:
/** /**
* Construct a histogram with 'numBuckets' buckets, optionally * Construct a histogram with 'numBuckets' buckets, optionally
* having the first bucket start at 'initialValue' rather than * having the first bucket start at 'initialValue' rather than
* 0. By default, the histogram buckets will be 'bucketSize' wide. * 0. By default, the histogram buckets will be 'bucketSize' wide.
* *
skipping to change at line 62 skipping to change at line 57
* Usage example: * Usage example:
* Histogram::Options opts; * Histogram::Options opts;
* opts.numBuckets = 4; * opts.numBuckets = 4;
* opts.bucketSize = 125; * opts.bucketSize = 125;
* opts.exponential = true; * opts.exponential = true;
* Histogram h( opts ); * Histogram h( opts );
* *
* Generates the bucket ranges [0..125],[126..250],[251..500],[50 1..max_int] * Generates the bucket ranges [0..125],[126..250],[251..500],[50 1..max_int]
*/ */
struct Options { struct Options {
boost::uint32_t numBuckets; uint32_t numBuckets;
boost::uint32_t bucketSize; uint32_t bucketSize;
boost::uint32_t initialValue; uint32_t initialValue;
// use exponential buckets? // use exponential buckets?
bool exponential; bool exponential;
Options() Options()
: numBuckets(0) : numBuckets(0)
, bucketSize(0) , bucketSize(0)
, initialValue(0) , initialValue(0)
, exponential(false) {} , exponential(false) {}
}; };
explicit Histogram( const Options& opts ); explicit Histogram( const Options& opts );
~Histogram(); ~Histogram();
/** /**
* Find the bucket that 'element' falls into and increment its coun t. * Find the bucket that 'element' falls into and increment its coun t.
*/ */
void insert( boost::uint32_t element ); void insert( uint32_t element );
/** /**
* Render the histogram as string that can be used inside an * Render the histogram as string that can be used inside an
* HTML doc. * HTML doc.
*/ */
string toHTML() const; std::string toHTML() const;
// testing interface below -- consider it private // testing interface below -- consider it private
/** /**
* Return the count for the 'bucket'-th bucket. * Return the count for the 'bucket'-th bucket.
*/ */
boost::uint64_t getCount( boost::uint32_t bucket ) const; uint64_t getCount( uint32_t bucket ) const;
/** /**
* Return the maximum element that would fall in the * Return the maximum element that would fall in the
* 'bucket'-th bucket. * 'bucket'-th bucket.
*/ */
boost::uint32_t getBoundary( boost::uint32_t bucket ) const; uint32_t getBoundary( uint32_t bucket ) const;
/** /**
* Return the number of buckets in this histogram. * Return the number of buckets in this histogram.
*/ */
boost::uint32_t getBucketsNum() const; uint32_t getBucketsNum() const;
private: private:
/** /**
* Returns the bucket where 'element' should fall * Returns the bucket where 'element' should fall
* into. Currently assumes that 'element' is greater than the * into. Currently assumes that 'element' is greater than the
* minimum 'inialValue'. * minimum 'inialValue'.
*/ */
boost::uint32_t _findBucket( boost::uint32_t element ) const; uint32_t _findBucket( uint32_t element ) const;
boost::uint32_t _initialValue; // no value lower than it is recor uint32_t _initialValue; // no value lower than it is recorded
ded uint32_t _numBuckets; // total buckets in the histogram
boost::uint32_t _numBuckets; // total buckets in the histogram
// all below owned here // all below owned here
boost::uint32_t* _boundaries; // maximum element of each bucket uint32_t* _boundaries; // maximum element of each bucket
boost::uint64_t* _buckets; // current count of each bucket uint64_t* _buckets; // current count of each bucket
Histogram( const Histogram& ); Histogram( const Histogram& );
Histogram& operator=( const Histogram& ); Histogram& operator=( const Histogram& );
}; };
} // namespace mongo } // namespace mongo
#endif // UTIL_HISTOGRAM_HEADER #endif // UTIL_HISTOGRAM_HEADER
 End of changes. 13 change blocks. 
20 lines changed or deleted 14 lines changed or added


 hostandport.h   hostandport.h 
skipping to change at line 43 skipping to change at line 43
struct HostAndPort { struct HostAndPort {
HostAndPort() : _port(-1) { } HostAndPort() : _port(-1) { }
/** From a string hostname[:portnumber] or a #dynname /** From a string hostname[:portnumber] or a #dynname
Throws user assertion if bad config string or bad port #. Throws user assertion if bad config string or bad port #.
*/ */
HostAndPort(string s); HostAndPort(string s);
/** @param p port number. -1 is ok to use default. */ /** @param p port number. -1 is ok to use default. */
HostAndPort(string h, int p /*= -1*/) : _host(h), _port(p) { HostAndPort(string h, int p /*= -1*/) : _host(h), _port(p) {
assert( !str::startsWith(h, '#') ); verify( !str::startsWith(h, '#') );
} }
HostAndPort(const SockAddr& sock ) : _host( sock.getAddr() ) , _por t( sock.getPort() ) { } HostAndPort(const SockAddr& sock ) : _host( sock.getAddr() ) , _por t( sock.getPort() ) { }
static HostAndPort me() { return HostAndPort("localhost", cmdLine.p ort); } static HostAndPort me() { return HostAndPort("localhost", cmdLine.p ort); }
/* uses real hostname instead of localhost */ /* uses real hostname instead of localhost */
static HostAndPort Me(); static HostAndPort Me();
bool operator<(const HostAndPort& r) const { bool operator<(const HostAndPort& r) const {
skipping to change at line 161 skipping to change at line 161
ip = string(ips); ip = string(ips);
ips = ""; ips = "";
} }
HostAndPort h = HostAndPort(ip, cmdLine.port); HostAndPort h = HostAndPort(ip, cmdLine.port);
if (!h.isLocalHost()) { if (!h.isLocalHost()) {
return h; return h;
} }
} }
string h = getHostName(); string h = getHostName();
assert( !h.empty() ); verify( !h.empty() );
assert( h != "localhost" ); verify( h != "localhost" );
return HostAndPort(h, cmdLine.port); return HostAndPort(h, cmdLine.port);
} }
inline string HostAndPort::dynString() const { inline string HostAndPort::dynString() const {
return dyn() ? _dynName : toString(); return dyn() ? _dynName : toString();
} }
inline string HostAndPort::toStringLong() const { inline string HostAndPort::toStringLong() const {
return _dynName + ':' + toString(); return _dynName + ':' + toString();
} }
skipping to change at line 210 skipping to change at line 210
string _host = host(); string _host = host();
return ( _host == "localhost" return ( _host == "localhost"
|| startsWith(_host.c_str(), "127.") || startsWith(_host.c_str(), "127.")
|| _host == "::1" || _host == "::1"
|| _host == "anonymous unix socket" || _host == "anonymous unix socket"
|| _host.c_str()[0] == '/' // unix socket || _host.c_str()[0] == '/' // unix socket
); );
} }
inline void HostAndPort::init(const char *p) { inline void HostAndPort::init(const char *p) {
uassert(13110, "HostAndPort: bad host:port config string", *p); massert(13110, "HostAndPort: host is empty", *p);
assert( *p != '#' ); verify( *p != '#' );
assert( _dynName.empty() ); verify( _dynName.empty() );
const char *colon = strrchr(p, ':'); const char *colon = strrchr(p, ':');
if( colon ) { if( colon ) {
int port = atoi(colon+1); int port = atoi(colon+1);
uassert(13095, "HostAndPort: bad port #", port > 0); uassert(13095, "HostAndPort: bad port #", port > 0);
_host = string(p,colon-p); _host = string(p,colon-p);
_port = port; _port = port;
} }
else { else {
// no port specified. // no port specified.
_host = p; _host = p;
 End of changes. 3 change blocks. 
6 lines changed or deleted 6 lines changed or added


 index.h   index.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 "../pch.h" #include "pch.h"
#include "diskloc.h"
#include "jsobj.h" #include <vector>
#include "indexkey.h"
#include "key.h" #include "mongo/db/diskloc.h"
#include "mongo/db/index_insertion_continuation.h"
#include "mongo/db/indexkey.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/key.h"
#include "mongo/db/namespace.h"
namespace mongo { namespace mongo {
class IndexInterface { class IndexInterface {
protected: protected:
virtual ~IndexInterface() { } virtual ~IndexInterface() { }
public: public:
static void phasedBegin(); class IndexInserter : private boost::noncopyable {
virtual void phasedQueueItemToInsert( public:
IndexInserter();
~IndexInserter();
void addInsertionContinuation(IndexInsertionContinuation *c);
void finishAllInsertions();
private:
std::vector<IndexInsertionContinuation *> _continuations;
};
virtual IndexInsertionContinuation *beginInsertIntoIndex(
int idxNo, int idxNo,
DiskLoc thisLoc, DiskLoc _recordLoc, const BSONObj &_key, IndexDetails &_idx, DiskLoc _recordLoc, const BSONObj &_key,
const Ordering& _order, IndexDetails& _idx, bool dupsAllowed) = const Ordering& _order, bool dupsAllowed) = 0;
0;
static void phasedFinish();
virtual int keyCompare(const BSONObj& l,const BSONObj& r, const Ord ering &ordering) = 0; virtual int keyCompare(const BSONObj& l,const BSONObj& r, const Ord ering &ordering) = 0;
virtual long long fullValidate(const DiskLoc& thisLoc, const BSONOb j &order) = 0; virtual long long fullValidate(const DiskLoc& thisLoc, const BSONOb j &order) = 0;
virtual DiskLoc findSingle(const IndexDetails &indexdetails , const DiskLoc& thisLoc, const BSONObj& key) const = 0; virtual DiskLoc findSingle(const IndexDetails &indexdetails , const DiskLoc& thisLoc, const BSONObj& key) const = 0;
virtual bool unindex(const DiskLoc thisLoc, IndexDetails& id, const BSONObj& key, const DiskLoc recordLoc) const = 0; virtual bool unindex(const DiskLoc thisLoc, IndexDetails& id, const BSONObj& key, const DiskLoc recordLoc) const = 0;
virtual int bt_insert(const DiskLoc thisLoc, const DiskLoc recordLo c, virtual int bt_insert(const DiskLoc thisLoc, const DiskLoc recordLo c,
const BSONObj& key, const Ordering &order, bool dupsAllowed, const BSONObj& key, const Ordering &order, bool dupsAllowed,
IndexDetails& idx, bool toplevel = true) const = 0; IndexDetails& idx, bool toplevel = true) const = 0;
virtual DiskLoc addBucket(const IndexDetails&) = 0; virtual DiskLoc addBucket(const IndexDetails&) = 0;
virtual void uassertIfDups(IndexDetails& idx, vector<BSONObj*>& add edKeys, DiskLoc head, virtual void uassertIfDups(IndexDetails& idx, vector<BSONObj*>& add edKeys, DiskLoc head,
skipping to change at line 129 skipping to change at line 144
/* true if the specified key is in the index */ /* true if the specified key is in the index */
bool hasKey(const BSONObj& key); bool hasKey(const BSONObj& key);
// returns name of this index's storage area // returns name of this index's storage area
// database.table.$index // database.table.$index
string indexNamespace() const { string indexNamespace() const {
BSONObj io = info.obj(); BSONObj io = info.obj();
string s; string s;
s.reserve(Namespace::MaxNsLen); s.reserve(Namespace::MaxNsLen);
s = io.getStringField("ns"); s = io.getStringField("ns");
assert( !s.empty() ); verify( !s.empty() );
s += ".$"; s += ".$";
s += io.getStringField("name"); s += io.getStringField("name");
return s; return s;
} }
string indexName() const { // e.g. "ts_1" string indexName() const { // e.g. "ts_1"
BSONObj io = info.obj(); BSONObj io = info.obj();
return io.getStringField("name"); return io.getStringField("name");
} }
skipping to change at line 235 skipping to change at line 250
void dupCheck(IndexDetails& idx, DiskLoc curObjLoc) { void dupCheck(IndexDetails& idx, DiskLoc curObjLoc) {
if( added.empty() || !idx.unique() ) if( added.empty() || !idx.unique() )
return; return;
const Ordering ordering = Ordering::make(idx.keyPattern()); const Ordering ordering = Ordering::make(idx.keyPattern());
idx.idxInterface().uassertIfDups(idx, added, idx.head, curObjLo c, ordering); // "E11001 duplicate key on update" idx.idxInterface().uassertIfDups(idx, added, idx.head, curObjLo c, ordering); // "E11001 duplicate key on update"
} }
}; };
class NamespaceDetails; class NamespaceDetails;
// changedId should be initialized to false // changedId should be initialized to false
void getIndexChanges(vector<IndexChanges>& v, NamespaceDetails& d, BSON void getIndexChanges(vector<IndexChanges>& v, const char *ns, Namespace
Obj newObj, BSONObj oldObj, bool &cangedId); Details& d,
BSONObj newObj, BSONObj oldObj, bool &cangedId);
void dupCheck(vector<IndexChanges>& v, NamespaceDetails& d, DiskLoc cur ObjLoc); void dupCheck(vector<IndexChanges>& v, NamespaceDetails& d, DiskLoc cur ObjLoc);
} // namespace mongo } // namespace mongo
 End of changes. 5 change blocks. 
14 lines changed or deleted 29 lines changed or added


 inline_decls.h   inline_decls.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
#if defined(__GNUC__) #if defined(__GNUC__)
#define NOINLINE_DECL __attribute__((noinline)) #define NOINLINE_DECL __attribute__((noinline))
#define PACKED_DECL __attribute__((packed))
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#define NOINLINE_DECL __declspec(noinline) #define NOINLINE_DECL __declspec(noinline)
#define PACKED_DECL
#else #else
#define NOINLINE_DECL #define NOINLINE_DECL
#define PACKED_DECL
#endif #endif
namespace mongo { namespace mongo {
/* Note: do not clutter code with these -- ONLY use in hot spots / signific ant loops. */ /* Note: do not clutter code with these -- ONLY use in hot spots / signific ant loops. */
#if !defined(__GNUC__) #if !defined(__GNUC__)
// branch prediction. indicate we expect to be true // branch prediction. indicate we expect to be true
 End of changes. 3 change blocks. 
0 lines changed or deleted 3 lines changed or added


 instance.h   instance.h 
skipping to change at line 22 skipping to change at line 22
* 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 "../client/dbclient.h"
#include "curop-inl.h" #include "curop-inl.h"
#include "security.h" #include "security.h"
#include "cmdline.h" #include "cmdline.h"
#include "client.h" #include "client.h"
#include "mongo/client/dbclientinterface.h"
namespace mongo { namespace mongo {
extern string dbExecCommand; extern string dbExecCommand;
/** a high level recording of operations to the database - sometimes us ed for diagnostics /** a high level recording of operations to the database - sometimes us ed for diagnostics
and debugging. and debugging.
*/ */
class DiagLog { class DiagLog {
ofstream *f; // note this is never freed ofstream *f; // note this is never freed
skipping to change at line 87 skipping to change at line 87
/* returns true if there is no data on this server. useful when starti ng replication. /* returns true if there is no data on this server. useful when starti ng replication.
local database does NOT count. local database does NOT count.
*/ */
bool replHasDatabases(); bool replHasDatabases();
/** "embedded" calls to the local server directly. /** "embedded" calls to the local server directly.
Caller does not need to lock, that is handled within. Caller does not need to lock, that is handled within.
*/ */
class DBDirectClient : public DBClientBase { class DBDirectClient : public DBClientBase {
public: public:
using DBClientBase::query;
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0, virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0,
const BSONObj *fieldsToRetur n = 0, int queryOptions = 0, int batchSize = 0); const BSONObj *fieldsToRetur n = 0, int queryOptions = 0, int batchSize = 0);
virtual bool isFailed() const { virtual bool isFailed() const {
return false; return false;
} }
virtual string toString() { virtual string toString() {
return "DBDirectClient"; return "DBDirectClient";
} }
virtual string getServerAddress() const { virtual string getServerAddress() const {
skipping to change at line 119 skipping to change at line 121
return call( toSend , response ); return call( toSend , response );
} }
virtual unsigned long long count(const string &ns, const BSONObj& q uery = BSONObj(), int options=0, int limit=0, int skip=0 ); virtual unsigned long long count(const string &ns, const BSONObj& q uery = BSONObj(), int options=0, int limit=0, int skip=0 );
virtual ConnectionString::ConnectionType type() const { return Conn ectionString::MASTER; } virtual ConnectionString::ConnectionType type() const { return Conn ectionString::MASTER; }
double getSoTimeout() const { return 0; } double getSoTimeout() const { return 0; }
virtual bool lazySupported() const { return true; } virtual bool lazySupported() const { return true; }
virtual QueryOptions _lookupAvailableOptions();
private: private:
static HostAndPort _clientHost; static HostAndPort _clientHost;
}; };
extern int lockFile; extern int lockFile;
#ifdef _WIN32 #ifdef _WIN32
extern HANDLE lockFileHandle; extern HANDLE lockFileHandle;
#endif #endif
void acquirePathLock(bool doingRepair=false); // if doingRepair=true do n't consider unclean shutdown an error void acquirePathLock(bool doingRepair=false); // if doingRepair=true do n't consider unclean shutdown an error
void maybeCreatePidFile(); void maybeCreatePidFile();
void exitCleanly( ExitCode code );
} // namespace mongo } // namespace mongo
 End of changes. 5 change blocks. 
1 lines changed or deleted 8 lines changed or added


 jsobj.h   jsobj.h 
skipping to change at line 34 skipping to change at line 34
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 "../pch.h" #include "../pch.h"
#include "../bson/util/builder.h" #include "../bson/util/builder.h"
#include "../util/optime.h" #include "../util/optime.h"
//#include "boost/utility.hpp"
//#include <set>
#include "../bson/bsontypes.h" #include "../bson/bsontypes.h"
#include "../bson/oid.h" #include "../bson/oid.h"
#include "../bson/bsonelement.h" #include "../bson/bsonelement.h"
#include "../bson/bsonobj.h" #include "../bson/bsonobj.h"
#include "../bson/bsonmisc.h" #include "../bson/bsonmisc.h"
#include "../bson/bsonobjbuilder.h" #include "../bson/bsonobjbuilder.h"
#include "../bson/bsonobjiterator.h" #include "../bson/bsonobjiterator.h"
#include "../bson/bson-inl.h" #include "../bson/bson-inl.h"
#include "../bson/ordering.h" #include "../bson/ordering.h"
#include "../bson/stringdata.h" #include "../bson/stringdata.h"
 End of changes. 1 change blocks. 
2 lines changed or deleted 0 lines changed or added


 jsobjmanipulator.h   jsobjmanipulator.h 
skipping to change at line 33 skipping to change at line 33
namespace mongo { namespace mongo {
/** Manipulate the binary representation of a BSONElement in-place. /** Manipulate the binary representation of a BSONElement in-place.
Careful, this casts away const. Careful, this casts away const.
*/ */
class BSONElementManipulator { class BSONElementManipulator {
public: public:
BSONElementManipulator( const BSONElement &element ) : BSONElementManipulator( const BSONElement &element ) :
_element( element ) { _element( element ) {
assert( !_element.eoo() ); verify( !_element.eoo() );
} }
/** Replace a Timestamp type with a Date type initialized to /** Replace a Timestamp type with a Date type initialized to
OpTime::now().asDate() OpTime::now().asDate()
*/ */
void initTimestamp(); void initTimestamp();
// Note the ones with a capital letter call getDur().writing and jo urnal // Note the ones with a capital letter call getDur().writing and jo urnal
/** Change the value, in place, of the number. */ /** Change the value, in place, of the number. */
void setNumber(double d) { void setNumber(double d) {
if ( _element.type() == NumberDouble ) *reinterpret_cast< doubl e * >( value() ) = d; if ( _element.type() == NumberDouble ) *reinterpret_cast< doubl e * >( value() ) = d;
else if ( _element.type() == NumberInt ) *reinterpret_cast< int * >( value() ) = (int) d; else if ( _element.type() == NumberInt ) *reinterpret_cast< int * >( value() ) = (int) d;
else assert(0); else verify(0);
} }
void SetNumber(double d); void SetNumber(double d);
void setLong(long long n) { void setLong(long long n) {
assert( _element.type() == NumberLong ); verify( _element.type() == NumberLong );
*reinterpret_cast< long long * >( value() ) = n; *reinterpret_cast< long long * >( value() ) = n;
} }
void SetLong(long long n); void SetLong(long long n);
void setInt(int n) { void setInt(int n) {
assert( _element.type() == NumberInt ); verify( _element.type() == NumberInt );
*reinterpret_cast< int * >( value() ) = n; *reinterpret_cast< int * >( value() ) = n;
} }
void SetInt(int n); void SetInt(int n);
/** Replace the type and value of the element with the type and val ue of e, /** Replace the type and value of the element with the type and val ue of e,
preserving the original fieldName */ preserving the original fieldName */
void replaceTypeAndValue( const BSONElement &e ) { void replaceTypeAndValue( const BSONElement &e ) {
*data() = e.type(); *data() = e.type();
memcpy( value(), e.value(), e.valuesize() ); memcpy( value(), e.value(), e.valuesize() );
} }
skipping to change at line 81 skipping to change at line 81
// If have a Timestamp field as the first or second element, // If have a Timestamp field as the first or second element,
// update it to a Date field set to OpTime::now().asDate(). Th e // update it to a Date field set to OpTime::now().asDate(). Th e
// replacement policy is a work in progress. // replacement policy is a work in progress.
BSONObjIterator i( obj ); BSONObjIterator i( obj );
for( int j = 0; i.moreWithEOO() && j < 2; ++j ) { for( int j = 0; i.moreWithEOO() && j < 2; ++j ) {
BSONElement e = i.next(); BSONElement e = i.next();
if ( e.eoo() ) if ( e.eoo() )
break; break;
if ( e.type() == Timestamp ) { if ( e.type() == Timestamp ) {
// performance note, this locks a mutex:
BSONElementManipulator( e ).initTimestamp(); BSONElementManipulator( e ).initTimestamp();
break; break;
} }
} }
} }
private: private:
char *data() { return nonConst( _element.rawdata() ); } char *data() { return nonConst( _element.rawdata() ); }
char *value() { return nonConst( _element.value() ); } char *value() { return nonConst( _element.value() ); }
static char *nonConst( const char *s ) { return const_cast< char * >( s ); } static char *nonConst( const char *s ) { return const_cast< char * >( s ); }
 End of changes. 5 change blocks. 
4 lines changed or deleted 5 lines changed or added


 key.h   key.h 
skipping to change at line 45 skipping to change at line 45
explicit KeyBson(const BSONObj& obj) : _o(obj) { } explicit KeyBson(const BSONObj& obj) : _o(obj) { }
int woCompare(const KeyBson& r, const Ordering &o) const; int woCompare(const KeyBson& r, const Ordering &o) const;
BSONObj toBson() const { return _o; } BSONObj toBson() const { return _o; }
string toString() const { return _o.toString(); } string toString() const { return _o.toString(); }
int dataSize() const { return _o.objsize(); } int dataSize() const { return _o.objsize(); }
const char * data() const { return _o.objdata(); } const char * data() const { return _o.objdata(); }
BSONElement _firstElement() const { return _o.firstElement(); } BSONElement _firstElement() const { return _o.firstElement(); }
bool isCompactFormat() const { return false; } bool isCompactFormat() const { return false; }
bool woEqual(const KeyBson& r) const; bool woEqual(const KeyBson& r) const;
void assign(const KeyBson& rhs) { *this = rhs; } void assign(const KeyBson& rhs) { *this = rhs; }
bool isValid() const { return true; }
private: private:
BSONObj _o; BSONObj _o;
}; };
class KeyV1Owned; class KeyV1Owned;
// corresponding to BtreeData_V1 // corresponding to BtreeData_V1
class KeyV1 { class KeyV1 {
void operator=(const KeyV1&); // disallowed just to make people be careful as we don't own the buffer void operator=(const KeyV1&); // disallowed just to make people be careful as we don't own the buffer
KeyV1(const KeyV1Owned&); // disallowed as this is not a great idea as KeyV1Owned likely will go out of scope KeyV1(const KeyV1Owned&); // disallowed as this is not a great idea as KeyV1Owned likely will go out of scope
skipping to change at line 87 skipping to change at line 88
/** get the key data we want to store in the btree bucket */ /** get the key data we want to store in the btree bucket */
const char * data() const { return (const char *) _keyData; } const char * data() const { return (const char *) _keyData; }
/** @return size of data() */ /** @return size of data() */
int dataSize() const; int dataSize() const;
/** only used by geo, which always has bson keys */ /** only used by geo, which always has bson keys */
BSONElement _firstElement() const { return bson().firstElement(); } BSONElement _firstElement() const { return bson().firstElement(); }
bool isCompactFormat() const { return *_keyData != IsBSON; } bool isCompactFormat() const { return *_keyData != IsBSON; }
bool isValid() const { return _keyData > (const unsigned char*)1; }
protected: protected:
enum { IsBSON = 0xff }; enum { IsBSON = 0xff };
const unsigned char *_keyData; const unsigned char *_keyData;
BSONObj bson() const { BSONObj bson() const {
dassert( !isCompactFormat() ); dassert( !isCompactFormat() );
return BSONObj((const char *) _keyData+1); return BSONObj((const char *) _keyData+1);
} }
private: private:
int compareHybrid(const KeyV1& right, const Ordering& order) const; int compareHybrid(const KeyV1& right, const Ordering& order) const;
}; };
 End of changes. 2 change blocks. 
0 lines changed or deleted 3 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 "../bson/oid.h" #include "mongo/bson/oid.h"
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 ;
OID upsertedId; OID upsertedId;
skipping to change at line 117 skipping to change at line 117
extern class LastErrorHolder { extern class LastErrorHolder {
public: public:
LastErrorHolder(){} LastErrorHolder(){}
~LastErrorHolder(); ~LastErrorHolder();
LastError * get( bool create = false ); LastError * get( bool create = false );
LastError * getSafe() { LastError * getSafe() {
LastError * le = get(false); LastError * le = get(false);
if ( ! le ) { if ( ! le ) {
error() << " no LastError!" << endl; error() << " no LastError!" << endl;
assert( le ); verify( le );
} }
return le; return le;
} }
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. */ /** ok to call more than once. */
void initThread(); void initThread();
skipping to change at line 150 skipping to change at line 150
LastError *disableForCommand(); // only call once per command invoc ation! LastError *disableForCommand(); // only call once per command invoc ation!
private: private:
boost::thread_specific_ptr<LastError> _tl; boost::thread_specific_ptr<LastError> _tl;
struct Status { struct Status {
time_t time; time_t time;
LastError *lerr; LastError *lerr;
}; };
} lastError; } lastError;
void raiseError(int code , const char *msg); void setLastError(int code , const char *msg);
} // namespace mongo } // namespace mongo
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 linenoise.h   linenoise.h 
skipping to change at line 39 skipping to change at line 39
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF T HE * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF T HE
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef __LINENOISE_H #ifndef __LINENOISE_H
#define __LINENOISE_H #define __LINENOISE_H
struct linenoiseCompletions { struct linenoiseCompletions;
int completionCount;
char * * completionStrings;
};
typedef void( linenoiseCompletionCallback )( const char *, linenoiseComplet ions * ); typedef void( linenoiseCompletionCallback )( const char *, linenoiseComplet ions * );
void linenoiseSetCompletionCallback( linenoiseCompletionCallback * fn ); void linenoiseSetCompletionCallback( linenoiseCompletionCallback * fn );
void linenoiseAddCompletion( linenoiseCompletions * lc, const char * str ); void linenoiseAddCompletion( linenoiseCompletions * lc, const char * str );
char *linenoise( const char* prompt ); char *linenoise( const char* prompt );
void linenoisePreloadBuffer( const char* preloadText );
int linenoiseHistoryAdd( const char* line ); int linenoiseHistoryAdd( const char* line );
int linenoiseHistorySetMaxLen( int len ); int linenoiseHistorySetMaxLen( int len );
int linenoiseHistorySave( const char* filename ); int linenoiseHistorySave( const char* filename );
int linenoiseHistoryLoad( const char* filename ); int linenoiseHistoryLoad( const char* filename );
void linenoiseHistoryFree( void ); void linenoiseHistoryFree( void );
void linenoiseClearScreen( void ); void linenoiseClearScreen( void );
#endif /* __LINENOISE_H */ #endif /* __LINENOISE_H */
 End of changes. 2 change blocks. 
4 lines changed or deleted 2 lines changed or added


 list.h   list.h 
skipping to change at line 66 skipping to change at line 66
use(p); use(p);
and this is not: and this is not:
if( mylist.head() ) if( mylist.head() )
use( mylist.head() ); // could become 0 use( mylist.head() ); // could become 0
*/ */
T* head() const { return (T*) _head; } T* head() const { return (T*) _head; }
void push(T* t) { void push(T* t) {
assert( t->_next == 0 ); verify( t->_next == 0 );
scoped_lock lk(_m); scoped_lock lk(_m);
t->_next = (T*) _head; t->_next = (T*) _head;
_head = t; _head = t;
} }
// intentionally leaks. // intentionally leaks.
void orphanAll() { void orphanAll() {
scoped_lock lk(_m); scoped_lock lk(_m);
_head = 0; _head = 0;
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 listen.h   listen.h 
skipping to change at line 21 skipping to change at line 21
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "sock.h" #include "sock.h"
#include "mongo/util/concurrency/ticketholder.h"
namespace mongo { namespace mongo {
class MessagingPort; class MessagingPort;
class Listener : boost::noncopyable { class Listener : boost::noncopyable {
public: public:
Listener(const string& name, const string &ip, int port, bool logCo nnect=true ); Listener(const string& name, const string &ip, int port, bool logCo nnect=true );
skipping to change at line 46 skipping to change at line 47
* ownership of SSLManager remains with the caller * ownership of SSLManager remains with the caller
*/ */
void secure( SSLManager* manager ); void secure( SSLManager* manager );
void addSecurePort( SSLManager* manager , int additionalPort ); void addSecurePort( SSLManager* manager , int additionalPort );
#endif #endif
void initAndListen(); // never returns unless error (start a thread ) void initAndListen(); // never returns unless error (start a thread )
/* spawn a thread, etc., then return */ /* spawn a thread, etc., then return */
virtual void accepted(Socket socket); virtual void accepted(boost::shared_ptr<Socket> psocket);
virtual void accepted(MessagingPort *mp); virtual void acceptedMP(MessagingPort *mp);
const int _port; const int _port;
/** /**
* @return a rough estimate of elapsed time since the server starte d * @return a rough estimate of elapsed time since the server starte d
*/ */
long long getMyElapsedTimeMillis() const { return _elapsedTime; } long long getMyElapsedTimeMillis() const { return _elapsedTime; }
void setAsTimeTracker() { void setAsTimeTracker() {
_timeTracker = this; _timeTracker = this;
 End of changes. 2 change blocks. 
2 lines changed or deleted 3 lines changed or added


 log.h   log.h 
skipping to change at line 27 skipping to change at line 27
#pragma once #pragma once
#include <string.h> #include <string.h>
#include <sstream> #include <sstream>
#include <errno.h> #include <errno.h>
#include <vector> #include <vector>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
#include <boost/thread/tss.hpp> #include <boost/thread/tss.hpp>
#include "../bson/util/builder.h"
#include "debug_util.h" #include "mongo/bson/util/builder.h"
#include "mongo/util/debug_util.h"
#include "mongo/util/exit_code.h"
#ifndef _WIN32 #ifndef _WIN32
#include <syslog.h> #include <syslog.h>
#endif #endif
namespace mongo { namespace mongo {
enum ExitCode; enum ExitCode;
enum LogLevel { LL_DEBUG , LL_INFO , LL_NOTICE , LL_WARNING , LL_ERROR , LL_SEVERE }; enum LogLevel { LL_DEBUG , LL_INFO , LL_NOTICE , LL_WARNING , LL_ERROR , LL_SEVERE };
skipping to change at line 202 skipping to change at line 204
} }
template< class T > template< class T >
Nullstream& operator<<(T *t) { Nullstream& operator<<(T *t) {
return operator<<( static_cast<void*>( t ) ); return operator<<( static_cast<void*>( t ) );
} }
template< class T > template< class T >
Nullstream& operator<<(const T *t) { Nullstream& operator<<(const T *t) {
return operator<<( static_cast<const void*>( t ) ); return operator<<( static_cast<const void*>( t ) );
} }
template< class T > template< class T >
Nullstream& operator<<(const shared_ptr<T> p ) { Nullstream& operator<<(const boost::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;
} }
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<< (std::ostream& ( *endl )(std::ostrea m&)) {
return *this; return *this;
} }
virtual Nullstream& operator<< (ios_base& (*hex)(ios_base&)) { virtual Nullstream& operator<< (std::ios_base& (*hex)(std::ios_base &)) {
return *this; return *this;
} }
virtual void flush(Tee *t = 0) {} virtual void flush(Tee *t = 0) {}
}; };
extern Nullstream nullstream; extern Nullstream nullstream;
class mutex;
class Logstream : public Nullstream { class Logstream : public Nullstream {
static mongo::mutex mutex; static mongo::mutex mutex;
static int doneSetup; static int doneSetup;
stringstream ss; std::stringstream ss;
int indent; int indent;
LogLevel logLevel; LogLevel logLevel;
static FILE* logfile; static FILE* logfile;
static boost::scoped_ptr<ostream> stream; static boost::scoped_ptr<std::ostream> stream;
static vector<Tee*> * globalTees; static std::vector<Tee*> * globalTees;
static bool isSyslog; static bool isSyslog;
public: public:
static void logLockless( const StringData& s ); static void logLockless( const StringData& s );
static void setLogFile(FILE* f); static void setLogFile(FILE* f);
#ifndef _WIN32 #ifndef _WIN32
static void useSyslog(const char * name) { static void useSyslog(const char * name) {
cout << "using syslog ident: " << name << endl; std::cout << "using syslog ident: " << name << std::endl;
// openlog requires heap allocated non changing pointer // openlog requires heap allocated non changing pointer
// this should only be called once per pragram execution // this should only be called once per pragram execution
char * newName = (char *) malloc( strlen(name) + 1 ); char * newName = (char *) malloc( strlen(name) + 1 );
strcpy( newName , name); strcpy( newName , name);
openlog( newName , LOG_ODELAY , LOG_USER ); openlog( newName , LOG_ODELAY , LOG_USER );
isSyslog = true; isSyslog = true;
} }
#endif #endif
skipping to change at line 305 skipping to change at line 305
Logstream& operator<<(const LazyString& x) { Logstream& operator<<(const LazyString& x) {
ss << x.val(); ss << x.val();
return *this; return *this;
} }
Nullstream& operator<< (Tee* tee) { Nullstream& operator<< (Tee* tee) {
ss << '\n'; ss << '\n';
flush(tee); flush(tee);
return *this; return *this;
} }
Logstream& operator<< (ostream& ( *_endl )(ostream&)) { Logstream& operator<< (std::ostream& ( *_endl )(std::ostream&)) {
ss << '\n'; ss << '\n';
flush(0); flush(0);
return *this; return *this;
} }
Logstream& operator<< (ios_base& (*_hex)(ios_base&)) { Logstream& operator<< (std::ios_base& (*_hex)(std::ios_base&)) {
ss << _hex; ss << _hex;
return *this; return *this;
} }
Logstream& prolog() { Logstream& prolog() {
return *this; return *this;
} }
void addGlobalTee( Tee * t ) { void addGlobalTee( Tee * t ) {
if ( ! globalTees ) if ( ! globalTees )
globalTees = new vector<Tee*>(); globalTees = new std::vector<Tee*>();
globalTees->push_back( t ); globalTees->push_back( t );
} }
void removeGlobalTee( Tee * tee );
void indentInc(){ indent++; } void indentInc(){ indent++; }
void indentDec(){ indent--; } void indentDec(){ indent--; }
int getIndent() const { return indent; } int getIndent() const { return indent; }
private: private:
static boost::thread_specific_ptr<Logstream> tsp; static boost::thread_specific_ptr<Logstream> tsp;
Logstream() { Logstream() {
indent = 0; indent = 0;
_init(); _init();
} }
skipping to change at line 368 skipping to change at line 370
/* 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();
} }
/** logging which we may not want during unit tests (dbtests) runs. /** logging which we may not want during unit tests (dbtests) runs.
set tlogLevel to -1 to suppress tlog() output in a test program. */ set tlogLevel to -1 to suppress tlog() output in a test program. */
inline Nullstream& tlog( int level = 0 ) { Nullstream& tlog( int level = 0 );
if ( level > tlogLevel || level > logLevel )
return nullstream;
return Logstream::get().prolog();
}
// log if debug build or if at a certain level // log if debug build or if at a certain level
inline Nullstream& dlog( int level ) { inline Nullstream& dlog( int level ) {
if ( level <= logLevel || DEBUG_BUILD ) if ( level <= logLevel || DEBUG_BUILD )
return Logstream::get().prolog(); return Logstream::get().prolog();
return nullstream; return nullstream;
} }
inline Nullstream& log( int level ) { inline Nullstream& log( int level ) {
if ( level > logLevel ) if ( level > logLevel )
skipping to change at line 428 skipping to change at line 426
return nullstream; return nullstream;
Logstream& l = Logstream::get().prolog(); Logstream& l = Logstream::get().prolog();
l << ' ' << getcurns() << ' '; l << ' ' << getcurns() << ' ';
return l; return l;
} }
/** /**
log to a file rather than stdout log to a file rather than stdout
defined in assert_util.cpp defined in assert_util.cpp
*/ */
void initLogging( const string& logpath , bool append ); bool initLogging( const string& logpath , bool append );
void rotateLogs( int signal = 0 ); bool rotateLogs();
std::string toUtf8String(const std::wstring& wide); std::string toUtf8String(const std::wstring& wide);
/** output the error # and error message with prefix. /** output the error # and error message with prefix.
handy for use as parm in uassert/massert. handy for use as parm in uassert/massert.
*/ */
string errnoWithPrefix( const char * prefix ); string errnoWithPrefix( const char * prefix );
struct LogIndentLevel { struct LogIndentLevel {
LogIndentLevel(){ LogIndentLevel(){
Logstream::get().indentInc(); Logstream::get().indentInc();
} }
~LogIndentLevel(){ ~LogIndentLevel(){
Logstream::get().indentDec(); Logstream::get().indentDec();
} }
}; };
extern Tee* const warnings; // Things put here go in serverStatus extern Tee* const warnings; // Things put here go in serverStatus
string errnoWithDescription(int errorcode = -1); string errnoWithDescription(int errorcode = -1);
void rawOut( const string &s );
} // namespace mongo } // namespace mongo
 End of changes. 15 change blocks. 
21 lines changed or deleted 20 lines changed or added


 lruishmap.h   lruishmap.h 
skipping to change at line 46 skipping to change at line 46
hashes = new int[n]; hashes = new int[n];
for ( int i = 0; i < n; i++ ) hashes[i] = 0; for ( int i = 0; i < n; i++ ) hashes[i] = 0;
} }
~LRUishMap() { ~LRUishMap() {
delete[] keys; delete[] keys;
delete[] hashes; delete[] hashes;
} }
int _find(const K& k, bool& found) { int _find(const K& k, bool& found) {
int h = k.hash(); int h = k.hash();
assert( h > 0 ); verify( h > 0 );
int j = h % n; int j = h % n;
int first = j; int first = j;
for ( int i = 0; i < MaxChain; i++ ) { for ( int i = 0; i < MaxChain; i++ ) {
if ( hashes[j] == h ) { if ( hashes[j] == h ) {
if ( keys[j] == k ) { if ( keys[j] == k ) {
found = true; found = true;
return j; return j;
} }
} }
else if ( hashes[j] == 0 ) { else if ( hashes[j] == 0 ) {
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 matcher.h   matcher.h 
skipping to change at line 89 skipping to change at line 89
shared_ptr<Matcher> _subMatcher; shared_ptr<Matcher> _subMatcher;
bool _subMatcherOnPrimitives ; bool _subMatcherOnPrimitives ;
vector< shared_ptr<Matcher> > _allMatchers; vector< shared_ptr<Matcher> > _allMatchers;
}; };
class Where; // used for $where javascript eval class Where; // used for $where javascript eval
class DiskLoc; class DiskLoc;
struct MatchDetails { /** Reports information about a match request. */
MatchDetails() { class MatchDetails {
reset(); public:
} MatchDetails();
void resetOutput();
string toString() const;
void reset() { /** Request that an elemMatchKey be recorded. */
_loadedObject = false; void requestElemMatchKey() { _elemMatchKeyRequested = true; }
_elemMatchKey = 0;
}
string toString() const { bool needRecord() const { return _elemMatchKeyRequested; }
stringstream ss;
ss << "loadedObject: " << _loadedObject << " "; bool hasLoadedRecord() const { return _loadedRecord; }
ss << "elemMatchKey: " << ( _elemMatchKey ? _elemMatchKey : "NU bool hasElemMatchKey() const { return _elemMatchKeyFound; }
LL" ) << " "; string elemMatchKey() const {
return ss.str(); verify( hasElemMatchKey() );
return _elemMatchKey;
}
void setLoadedRecord( bool loadedRecord ) { _loadedRecord = loadedR
ecord; }
void setElemMatchKey( const string &elemMatchKey ) {
if ( _elemMatchKeyRequested ) {
_elemMatchKeyFound = true;
_elemMatchKey = elemMatchKey;
}
} }
bool _loadedObject; private:
const char * _elemMatchKey; // warning, this may go out of scope if bool _loadedRecord;
matched object does bool _elemMatchKeyRequested;
bool _elemMatchKeyFound;
string _elemMatchKey;
}; };
/* Match BSON objects against a query pattern. /* Match BSON objects against a query pattern.
e.g. e.g.
db.foo.find( { a : 3 } ); db.foo.find( { a : 3 } );
{ a : 3 } is the pattern object. See wiki documentation for full in fo. { a : 3 } is the pattern object. See wiki documentation for full in fo.
GT/LT: GT/LT:
skipping to change at line 150 skipping to change at line 163
static int opDirection(int op) { static int opDirection(int op) {
return op <= BSONObj::LTE ? -1 : 1; return op <= BSONObj::LTE ? -1 : 1;
} }
Matcher(const BSONObj &pattern, bool nested=false); Matcher(const BSONObj &pattern, bool nested=false);
~Matcher(); ~Matcher();
bool matches(const BSONObj& j, MatchDetails * details = 0 ) const; bool matches(const BSONObj& j, MatchDetails * details = 0 ) const;
#ifdef MONGO_LATER_SERVER_4644
class FieldSink {
public:
virtual ~FieldSink() {};
virtual void referenceField(const string &fieldPath) = 0;
};
/**
Visit all of the fields that are referenced by this Matcher
(and any descendants).
This can be used to gather a list of all the references made by
this matcher. The implementation of this parallels that of
matches() above.
@param pSink a FieldSink that the caller will use to gather or
process the references
*/
void visitReferences(FieldSink *pSink) const;
#endif /* MONGO_LATER_SERVER_4644 */
bool atomic() const { return _atomic; } bool atomic() const { return _atomic; }
string toString() const { string toString() const {
return _jsobj.toString(); return _jsobj.toString();
} }
void addOrDedupConstraint( const shared_ptr< FieldRangeVector > &fr v ) { void addOrDedupConstraint( const shared_ptr< FieldRangeVector > &fr v ) {
_orDedupConstraints.push_back( frv ); _orDedupConstraints.push_back( frv );
} }
skipping to change at line 178 skipping to change at line 212
bool keyMatch( const Matcher &docMatcher ) const; bool keyMatch( const Matcher &docMatcher ) const;
bool singleSimpleCriterion() const { bool singleSimpleCriterion() const {
return false; // TODO SERVER-958 return false; // TODO SERVER-958
// // TODO Really check, especially if all basics are ok. // // TODO Really check, especially if all basics are ok.
// // $all, etc // // $all, etc
// // _orConstraints? // // _orConstraints?
// return ( ( basics.size() + nRegex ) < 2 ) && !where && !_orMa tchers.size() && !_norMatchers.size(); // return ( ( basics.size() + nRegex ) < 2 ) && !where && !_orMa tchers.size() && !_norMatchers.size();
} }
const BSONObj *getQuery() const { return &_jsobj; }; const BSONObj *getQuery() const { return &_jsobj; };
private: private:
/** /**
* Generate a matcher for the provided index key format using the * Generate a matcher for the provided index key format using the
* provided full doc matcher. * provided full doc matcher.
*/ */
Matcher( const Matcher &docMatcher, const BSONObj &constrainIndexKe y ); Matcher( const Matcher &docMatcher, const BSONObj &constrainIndexKe y );
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.
skipping to change at line 236 skipping to change at line 270
list< shared_ptr< Matcher > > _orMatchers; list< shared_ptr< Matcher > > _orMatchers;
list< shared_ptr< Matcher > > _norMatchers; list< shared_ptr< Matcher > > _norMatchers;
vector< shared_ptr< FieldRangeVector > > _orDedupConstraints; vector< shared_ptr< FieldRangeVector > > _orDedupConstraints;
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 CoveredIndexMatcher(const BSONObj &pattern, const BSONObj &indexKey
Pattern , bool alwaysUseRecord=false ); Pattern);
bool matches(const BSONObj &o) { return _docMatcher->matches( o );
}
bool matchesWithSingleKeyIndex(const BSONObj &key, const DiskLoc &r ecLoc , MatchDetails * details = 0 ) { bool matchesWithSingleKeyIndex(const BSONObj &key, const DiskLoc &r ecLoc , MatchDetails * details = 0 ) {
return matches( key, recLoc, details, true ); return matches( key, recLoc, details, true );
} }
/** /**
* This is the preferred method for matching against a cursor, as i t * This is the preferred method for matching against a cursor, as i t
* can handle both multi and single key cursors. * can handle both multi and single key cursors.
*/ */
bool matchesCurrent( Cursor * cursor , MatchDetails * details = 0 ) ; bool matchesCurrent( Cursor * cursor , MatchDetails * details = 0 ) ;
bool needRecord() { return _needRecord; } bool needRecord() { return _needRecord; }
skipping to change at line 259 skipping to change at line 292
// once this is called, shouldn't use this matcher for matching any more // once this is called, shouldn't use this matcher for matching any more
void advanceOrClause( const shared_ptr< FieldRangeVector > &frv ) { void advanceOrClause( const shared_ptr< FieldRangeVector > &frv ) {
_docMatcher->addOrDedupConstraint( frv ); _docMatcher->addOrDedupConstraint( frv );
// TODO this is not yet optimal. Since we could skip an entire // TODO this is not yet optimal. Since we could skip an entire
// or clause (if a match is impossible) between calls to advanc eOrClause() // or clause (if a match is impossible) between calls to advanc eOrClause()
// we may not pop all the clauses we can. // we may not pop all the clauses we can.
_docMatcher->popOrClause(); _docMatcher->popOrClause();
} }
CoveredIndexMatcher *nextClauseMatcher( const BSONObj &indexKeyPatt CoveredIndexMatcher *nextClauseMatcher( const BSONObj &indexKeyPatt
ern, bool alwaysUseRecord=false ) { ern ) {
return new CoveredIndexMatcher( _docMatcher, indexKeyPattern, a return new CoveredIndexMatcher( _docMatcher, indexKeyPattern );
lwaysUseRecord );
} }
string toString() const; string toString() const;
private: private:
bool matches(const BSONObj &key, const DiskLoc &recLoc , MatchDetai ls * details = 0 , bool keyUsable = true ); bool matches(const BSONObj &key, const DiskLoc &recLoc , MatchDetai ls * details = 0 , bool keyUsable = true );
CoveredIndexMatcher(const shared_ptr< Matcher > &docMatcher, const CoveredIndexMatcher(const shared_ptr< Matcher > &docMatcher, const
BSONObj &indexKeyPattern , bool alwaysUseRecord=false ); BSONObj &indexKeyPattern);
void init( bool alwaysUseRecord ); void init();
shared_ptr< Matcher > _docMatcher; shared_ptr< Matcher > _docMatcher;
Matcher _keyMatcher; Matcher _keyMatcher;
bool _needRecord; // if the key itself isn't good enough to determi ne a positive match bool _needRecord; // if the key itself isn't good enough to determi ne a positive match
}; };
} // namespace mongo } // namespace mongo
 End of changes. 9 change blocks. 
29 lines changed or deleted 59 lines changed or added


 memconcept.h   memconcept.h 
#pragma once #pragma once
/* The idea here is to 'name' memory pointers so that we can do diagnostics
.
these diagnostics might involve concurrency or other things. mainly wou
ld
be for _DEBUG builds. Experimental we'll see how useful.
*/
namespace mongo { namespace mongo {
namespace memconcept { namespace memconcept {
enum concept { /** these are like fancy enums - you can use them as "types" of thi
err, ngs
something, and see if foo.concept == bar.concept.
database, copyable.
other, */
memorymappedfile, class concept {
nsdetails, public:
datafileheader, concept() { *this = err; }
extent, const char * toString() const { return c; }
record, static concept err;
deletedrecord static concept something;
static concept database;
static concept other;
static concept memorymappedfile;
static concept nsdetails;
static concept datafileheader;
static concept extent;
static concept record;
static concept deletedrecord;
static concept btreebucket;
private:
const char * c;
concept(const char *);
}; };
/** file was unmapped or something */ /** file was unmapped or something */
void invalidate(void *p, unsigned len); void invalidate(void *p, unsigned len=0);
void invalidate(void *p);
/** note you can be more than one thing; a datafile header is also the starting pointer /** note you can be more than one thing; a datafile header is also the starting pointer
for a file */ for a file */
void is(void *p, concept c, std::string desc = "", unsigned len=0); void is(void *p, concept c, std::string desc = "", unsigned len=0);
#if 1 #if 1
//#if !defined(_DEBUG) //#if !defined(_DEBUG)
inline void invalidate(void *p, unsigned len) { } inline void invalidate(void *p, unsigned len) { }
inline void invalidate(void *p) { }
inline void is(void *p, concept c, std::string, unsigned) { } inline void is(void *p, concept c, std::string, unsigned) { }
#endif #endif
} }
} }
 End of changes. 4 change blocks. 
14 lines changed or deleted 31 lines changed or added


 message.h   message.h 
skipping to change at line 58 skipping to change at line 58
case 0: return "none"; case 0: return "none";
case opReply: return "reply"; case opReply: return "reply";
case dbMsg: return "msg"; case dbMsg: return "msg";
case dbUpdate: return "update"; case dbUpdate: return "update";
case dbInsert: return "insert"; case dbInsert: return "insert";
case dbQuery: return "query"; case dbQuery: return "query";
case dbGetMore: return "getmore"; case dbGetMore: return "getmore";
case dbDelete: return "remove"; case dbDelete: return "remove";
case dbKillCursors: return "killcursors"; case dbKillCursors: return "killcursors";
default: default:
PRINT(op); massert( 16141, str::stream() << "cannot translate opcode " <<
assert(0); op, !op );
return ""; return "";
} }
} }
inline bool opIsWrite( int op ) { inline bool opIsWrite( int op ) {
switch ( op ) { switch ( op ) {
case 0: case 0:
case opReply: case opReply:
case dbMsg: case dbMsg:
skipping to change at line 82 skipping to change at line 81
case dbKillCursors: case dbKillCursors:
return false; return false;
case dbUpdate: case dbUpdate:
case dbInsert: case dbInsert:
case dbDelete: case dbDelete:
return true; return true;
default: default:
PRINT(op); PRINT(op);
assert(0); verify(0);
return ""; return "";
} }
} }
#pragma pack(1) #pragma pack(1)
/* see http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol /* see http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol
*/ */
struct MSGHEADER { struct MSGHEADER {
int messageLength; // total message size, including this int messageLength; // total message size, including this
int requestID; // identifier for this message int requestID; // identifier for this message
int responseTo; // requestID from the original request int responseTo; // requestID from the original request
// (used in reponses from db) // (used in reponses from db)
int opCode; int opCode;
}; };
struct OP_GETMORE : public MSGHEADER {
MSGHEADER header; // standard message header
int ZERO_or_flags; // 0 - reserved for future use
//cstring fullCollectionName; // "dbname.collectionname"
//int32 numberToReturn; // number of documents to return
//int64 cursorID; // cursorID from the OP_REPLY
};
#pragma pack() #pragma pack()
#pragma pack(1) #pragma pack(1)
/* todo merge this with MSGHEADER (or inherit from it). */ /* todo merge this with MSGHEADER (or inherit from it). */
struct MsgData { struct MsgData {
int len; /* len of the msg, including this field */ int len; /* len of the msg, including this field */
MSGID id; /* request/reply id's match... */ MSGID id; /* request/reply id's match... */
MSGID responseTo; /* id of the message we are responding to */ MSGID responseTo; /* id of the message we are responding to */
short _operation; short _operation;
char _flags; char _flags;
skipping to change at line 139 skipping to change at line 131
bool valid() { bool valid() {
if ( len <= 0 || len > ( 4 * BSONObjMaxInternalSize ) ) if ( len <= 0 || len > ( 4 * BSONObjMaxInternalSize ) )
return false; return false;
if ( _operation < 0 || _operation > 30000 ) if ( _operation < 0 || _operation > 30000 )
return false; return false;
return true; return true;
} }
long long getCursor() { long long getCursor() {
assert( responseTo > 0 ); verify( responseTo > 0 );
assert( _operation == opReply ); verify( _operation == opReply );
long long * l = (long long *)(_data + 4); long long * l = (long long *)(_data + 4);
return l[0]; return l[0];
} }
int dataLen(); // len without header int dataLen(); // len without header
}; };
const int MsgDataHeaderSize = sizeof(MsgData) - 4; const int MsgDataHeaderSize = sizeof(MsgData) - 4;
inline int MsgData::dataLen() { inline int MsgData::dataLen() {
return len - MsgDataHeaderSize; return len - MsgDataHeaderSize;
} }
skipping to change at line 171 skipping to change at line 163
Message(Message& r) : _buf( 0 ), _data( 0 ), _freeIt( false ) { Message(Message& r) : _buf( 0 ), _data( 0 ), _freeIt( false ) {
*this = r; *this = r;
} }
~Message() { ~Message() {
reset(); reset();
} }
SockAddr _from; SockAddr _from;
MsgData *header() const { MsgData *header() const {
assert( !empty() ); verify( !empty() );
return _buf ? _buf : reinterpret_cast< MsgData* > ( _data[ 0 ]. first ); return _buf ? _buf : reinterpret_cast< MsgData* > ( _data[ 0 ]. first );
} }
int operation() const { return header()->operation(); } int operation() const { return header()->operation(); }
MsgData *singleData() const { MsgData *singleData() const {
massert( 13273, "single data buffer expected", _buf ); massert( 13273, "single data buffer expected", _buf );
return header(); return header();
} }
bool empty() const { return !_buf && _data.empty(); } bool empty() const { return !_buf && _data.empty(); }
skipping to change at line 205 skipping to change at line 197
int dataSize() const { return size() - sizeof(MSGHEADER); } int dataSize() const { return size() - sizeof(MSGHEADER); }
// concat multiple buffers - noop if <2 buffers already, otherwise can be expensive copy // concat multiple buffers - noop if <2 buffers already, otherwise can be expensive copy
// can get rid of this if we make response handling smarter // can get rid of this if we make response handling smarter
void concat() { void concat() {
if ( _buf || empty() ) { if ( _buf || empty() ) {
return; return;
} }
assert( _freeIt ); verify( _freeIt );
int totalSize = 0; int totalSize = 0;
for( vector< pair< char *, int > >::const_iterator i = _data.be gin(); i != _data.end(); ++i ) { for( vector< pair< char *, int > >::const_iterator i = _data.be gin(); i != _data.end(); ++i ) {
totalSize += i->second; totalSize += i->second;
} }
char *buf = (char*)malloc( totalSize ); char *buf = (char*)malloc( totalSize );
char *p = buf; char *p = buf;
for( vector< pair< char *, int > >::const_iterator i = _data.be gin(); i != _data.end(); ++i ) { for( vector< pair< char *, int > >::const_iterator i = _data.be gin(); i != _data.end(); ++i ) {
memcpy( p, i->first, i->second ); memcpy( p, i->first, i->second );
p += i->second; p += i->second;
} }
reset(); reset();
_setData( (MsgData*)buf, true ); _setData( (MsgData*)buf, true );
} }
// vector swap() so this is fast // vector swap() so this is fast
Message& operator=(Message& r) { Message& operator=(Message& r) {
assert( empty() ); verify( empty() );
assert( r._freeIt ); verify( r._freeIt );
_buf = r._buf; _buf = r._buf;
r._buf = 0; r._buf = 0;
if ( r._data.size() > 0 ) { if ( r._data.size() > 0 ) {
_data.swap( r._data ); _data.swap( r._data );
} }
r._freeIt = false; r._freeIt = false;
_freeIt = true; _freeIt = true;
return *this; return *this;
} }
skipping to change at line 260 skipping to change at line 252
void appendData(char *d, int size) { void appendData(char *d, int size) {
if ( size <= 0 ) { if ( size <= 0 ) {
return; return;
} }
if ( empty() ) { if ( empty() ) {
MsgData *md = (MsgData*)d; MsgData *md = (MsgData*)d;
md->len = size; // can be updated later if more buffers add ed md->len = size; // can be updated later if more buffers add ed
_setData( md, true ); _setData( md, true );
return; return;
} }
assert( _freeIt ); verify( _freeIt );
if ( _buf ) { if ( _buf ) {
_data.push_back( make_pair( (char*)_buf, _buf->len ) ); _data.push_back( make_pair( (char*)_buf, _buf->len ) );
_buf = 0; _buf = 0;
} }
_data.push_back( make_pair( d, size ) ); _data.push_back( make_pair( d, size ) );
header()->len += size; header()->len += size;
} }
// use to set first buffer if empty // use to set first buffer if empty
void setData(MsgData *d, bool freeIt) { void setData(MsgData *d, bool freeIt) {
assert( empty() ); verify( empty() );
_setData( d, freeIt ); _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( empty() ); verify( 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);
_setData( d, true ); _setData( d, true );
} }
bool doIFreeIt() { bool doIFreeIt() {
return _freeIt; return _freeIt;
 End of changes. 10 change blocks. 
19 lines changed or deleted 12 lines changed or added


 message_port.h   message_port.h 
skipping to change at line 50 skipping to change at line 50
virtual void assertStillConnected() = 0; virtual void assertStillConnected() = 0;
public: public:
// TODO make this private with some helpers // TODO make this private with some helpers
/* ports can be tagged with various classes. see closeAllSockets(t ag). defaults to 0. */ /* ports can be tagged with various classes. see closeAllSockets(t ag). defaults to 0. */
unsigned tag; unsigned tag;
}; };
class MessagingPort : public AbstractMessagingPort , public Socket { class MessagingPort : public AbstractMessagingPort {
public: public:
MessagingPort(int fd, const SockAddr& remote); MessagingPort(int fd, const SockAddr& remote);
// in some cases the timeout will actually be 2x this value - eg we do a partial send, // in some cases the timeout will actually be 2x this value - eg we do a partial send,
// then the timeout fires, then we try to send again, then the time out fires again with // then the timeout fires, then we try to send again, then the time out fires again with
// no data sent, then we detect that the other side is down // no data sent, then we detect that the other side is down
MessagingPort(double so_timeout = 0, int logLevel = 0 ); MessagingPort(double so_timeout = 0, int logLevel = 0 );
MessagingPort(Socket&; socket); MessagingPort(boost::shared_ptr<Socket>; socket);
virtual ~MessagingPort(); virtual ~MessagingPort();
void shutdown(); void shutdown();
/* it's assumed if you reuse a message object, that it doesn't cros s MessagingPort's. /* it's assumed if you reuse a message object, that it doesn't cros s MessagingPort's.
also, the Message data will go out of scope on the subsequent re cv call. also, the Message data will go out of scope on the subsequent re cv call.
*/ */
bool recv(Message& m); bool recv(Message& m);
void reply(Message& received, Message& response, MSGID responseTo); void reply(Message& received, Message& response, MSGID responseTo);
skipping to change at line 88 skipping to change at line 88
* you would do * you would do
* say( to ) * say( to )
* recv( from ) * recv( from )
* Note: if you fail to call recv and someone else uses this port, * Note: if you fail to call recv and someone else uses this port,
* horrible things will happend * horrible things will happend
*/ */
bool recv( const Message& sent , Message& response ); bool recv( const Message& sent , Message& response );
void piggyBack( Message& toSend , int responseTo = -1 ); void piggyBack( Message& toSend , int responseTo = -1 );
unsigned remotePort() const { return Socket::remotePort(); } unsigned remotePort() const { return psock->remotePort(); }
virtual HostAndPort remote() const; virtual HostAndPort remote() const;
void assertStillConnected(); void assertStillConnected();
boost::shared_ptr<Socket> psock;
void send( const char * data , int len, const char *context ) {
psock->send( data, len, context );
}
void send( const vector< pair< char *, int > > &data, const char *c
ontext ) {
psock->send( data, context );
}
bool connect(SockAddr& farEnd) {
return psock->connect( farEnd );
}
#ifdef MONGO_SSL
/** secures inline */
void secure( SSLManager * ssl ) {
psock->secure( ssl );
}
#endif
private: private:
PiggyBackData * piggyBackData; PiggyBackData * piggyBackData;
// this is the parsed version of remote // this is the parsed version of remote
// mutable because its initialized only on call to remote() // mutable because its initialized only on call to remote()
mutable HostAndPort _remoteParsed; mutable HostAndPort _remoteParsed;
public: public:
static void closeAllSockets(unsigned tagMask = 0xffffffff); static void closeAllSockets(unsigned tagMask = 0xffffffff);
 End of changes. 4 change blocks. 
3 lines changed or deleted 22 lines changed or added


 minilex.h   minilex.h 
skipping to change at line 117 skipping to change at line 117
p++; p++;
while ( *p && *p != '"' ) p++; while ( *p && *p != '"' ) p++;
} }
p++; p++;
} }
} }
MiniLex() { MiniLex() {
strhashmap atest; strhashmap atest;
atest["foo"] = 3; atest["foo"] = 3;
assert( atest.count("bar") == 0 ); verify( atest.count("bar") == 0 );
assert( atest.count("foo") == 1 ); verify( atest.count("foo") == 1 );
assert( atest["foo"] == 3 ); verify( atest["foo"] == 3 );
for ( int i = 0; i < 256; i++ ) { for ( int i = 0; i < 256; i++ ) {
ic[i] = starter[i] = false; ic[i] = starter[i] = false;
} }
for ( int i = 'a'; i <= 'z'; i++ ) for ( int i = 'a'; i <= 'z'; i++ )
ic[i] = starter[i] = true; ic[i] = starter[i] = true;
for ( int i = 'A'; i <= 'Z'; i++ ) for ( int i = 'A'; i <= 'Z'; i++ )
ic[i] = starter[i] = true; ic[i] = starter[i] = true;
for ( int i = '0'; i <= '9'; i++ ) for ( int i = '0'; i <= '9'; i++ )
ic[i] = true; ic[i] = true;
 End of changes. 1 change blocks. 
3 lines changed or deleted 3 lines changed or added


 miniwebserver.h   miniwebserver.h 
skipping to change at line 56 skipping to change at line 56
static string parseURL( const char * buf ); static string parseURL( const char * buf );
static string parseMethod( const char * headers ); static string parseMethod( const char * headers );
static string getHeader( const char * headers , string name ); static string getHeader( const char * headers , string name );
static const char *body( const char *buf ); static const char *body( const char *buf );
static string urlDecode(const char* s); static string urlDecode(const char* s);
static string urlDecode(string s) {return urlDecode(s.c_str());} static string urlDecode(string s) {return urlDecode(s.c_str());}
private: private:
void accepted(Socket socket); void accepted(boost::shared_ptr<Socket> psocket);
static bool fullReceive( const char *buf ); static bool fullReceive( const char *buf );
}; };
} // namespace mongo } // namespace mongo
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 misc.h   misc.h 
skipping to change at line 23 skipping to change at line 23
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include <ctime> #include <ctime>
#include <limits>
namespace mongo { namespace mongo {
using namespace std;
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, 32, &t); ctime_s(buf, 32, &t);
#else #else
ctime_r(&t, buf); ctime_r(&t, buf);
#endif #endif
buf[24] = 0; // don't want the \n buf[24] = 0; // don't want the \n
} }
inline string time_t_to_String(time_t t = time(0) ) { inline std::string time_t_to_String(time_t t = time(0) ) {
char buf[64]; char buf[64];
#if defined(_WIN32) #if defined(_WIN32)
ctime_s(buf, sizeof(buf), &t); ctime_s(buf, sizeof(buf), &t);
#else #else
ctime_r(&t, buf); ctime_r(&t, buf);
#endif #endif
buf[24] = 0; // don't want the \n buf[24] = 0; // don't want the \n
return buf; return buf;
} }
inline string time_t_to_String_no_year(time_t t) { inline std::string time_t_to_String_no_year(time_t t) {
char buf[64]; char buf[64];
#if defined(_WIN32) #if defined(_WIN32)
ctime_s(buf, sizeof(buf), &t); ctime_s(buf, sizeof(buf), &t);
#else #else
ctime_r(&t, buf); ctime_r(&t, buf);
#endif #endif
buf[19] = 0; buf[19] = 0;
return buf; return buf;
} }
inline string time_t_to_String_short(time_t t) { inline std::string time_t_to_String_short(time_t t) {
char buf[64]; char buf[64];
#if defined(_WIN32) #if defined(_WIN32)
ctime_s(buf, sizeof(buf), &t); ctime_s(buf, sizeof(buf), &t);
#else #else
ctime_r(&t, buf); ctime_r(&t, buf);
#endif #endif
buf[19] = 0; buf[19] = 0;
if( buf[0] && buf[1] && buf[2] && buf[3] ) if( buf[0] && buf[1] && buf[2] && buf[3] )
return buf + 4; // skip day of week return buf + 4; // skip day of week
return buf; 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; }
void toTm (tm *buf) { void toTm (tm *buf) {
time_t dtime = (time_t)(millis/1000); time_t dtime = toTimeT();
#if defined(_WIN32) #if defined(_WIN32)
gmtime_s(buf, &dtime); gmtime_s(buf, &dtime);
#else #else
gmtime_r(&dtime, buf); gmtime_r(&dtime, buf);
#endif #endif
} }
string toString() const { std::string toString() const {
char buf[64]; char buf[64];
time_t_to_String(millis/1000, buf); time_t_to_String(toTimeT(), buf);
return buf; return buf;
} }
time_t toTimeT() const {
// cant use uassert from bson/util
verify((long long)millis >= 0); // TODO when millis is signed,
delete
verify(((long long)millis/1000) < (std::numeric_limits<time_t>:
:max)());
return millis / 1000;
}
}; };
// Like strlen, but only scans up to n bytes. // Like strlen, but only scans up to n bytes.
// Returns -1 if no '0' found. // Returns -1 if no '0' found.
inline int strnlen( const char *s, int n ) { inline int strnlen( const char *s, int n ) {
for( int i = 0; i < n; ++i ) for( int i = 0; i < n; ++i )
if ( !s[ i ] ) if ( !s[ i ] )
return i; return i;
return -1; return -1;
} }
 End of changes. 9 change blocks. 
8 lines changed or deleted 15 lines changed or added


 mmap.h   mmap.h 
skipping to change at line 28 skipping to change at line 28
#pragma once #pragma once
#include <boost/thread/xtime.hpp> #include <boost/thread/xtime.hpp>
#include "concurrency/rwlock.h" #include "concurrency/rwlock.h"
namespace mongo { namespace mongo {
class MAdvise { class MAdvise {
void *_p; void *_p;
unsigned _len; unsigned _len;
public: public:
enum Advice { Sequential=1 }; enum Advice { Sequential=1 , Random=2 };
MAdvise(void *p, unsigned len, Advice a); MAdvise(void *p, unsigned len, Advice a);
~MAdvise(); // destructor resets the range to MADV_NORMAL ~MAdvise(); // destructor resets the range to MADV_NORMAL
}; };
// lock order: lock dbMutex before this if you lock both // lock order: lock dbMutex before this if you lock both
class LockMongoFilesShared { class LockMongoFilesShared {
friend class LockMongoFilesExclusive; friend class LockMongoFilesExclusive;
static RWLockRecursiveNongreedy mmmutex; static RWLockRecursiveNongreedy mmmutex;
static unsigned era; static unsigned era;
RWLockRecursive::Shared lk; RWLockRecursive::Shared lk;
skipping to change at line 95 skipping to change at line 95
static set<MongoFile*>& getAllFiles() { return mmfiles; } static set<MongoFile*>& getAllFiles() { return mmfiles; }
// callbacks if you need them // callbacks if you need them
static void (*notifyPreFlush)(); static void (*notifyPreFlush)();
static void (*notifyPostFlush)(); static void (*notifyPostFlush)();
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 );
#if defined(_DEBUG)
static void markAllWritable();
static void unmarkAllWritable();
#else
static void markAllWritable() { }
static void unmarkAllWritable() { }
#endif
virtual bool isMongoMMF() { return false; } virtual bool isMongoMMF() { return false; }
string filename() const { return _filename; } string filename() const { return _filename; }
void setFilename(string fn); void setFilename(string fn);
private: private:
string _filename; string _filename;
static int _flushAll( bool sync ); // returns n flushed static int _flushAll( bool sync ); // returns n flushed
protected: protected:
virtual void close() = 0; virtual void close() = 0;
skipping to change at line 131 skipping to change at line 123
/* subclass must call in destructor (or at close). /* subclass must call in destructor (or at close).
removes this from pathToFile and other maps removes this from pathToFile and other maps
safe to call more than once, albeit might be wasted work safe to call more than once, albeit might be wasted work
ideal to call close to the close, if the close is well before ob ject destruction ideal to call close to the close, if the close is well before ob ject destruction
*/ */
void destroyed(); void destroyed();
virtual unsigned long long length() const = 0; virtual unsigned long long length() const = 0;
// only supporting on posix mmap
virtual void _lock() {}
virtual void _unlock() {}
static set<MongoFile*> mmfiles; static set<MongoFile*> mmfiles;
public: public:
static map<string,MongoFile*> pathToFile; static map<string,MongoFile*> pathToFile;
}; };
/** look up a MMF by filename. scoped mutex locking convention. /** look up a MMF by filename. scoped mutex locking convention.
example: example:
MMFFinderByName finder; MMFFinderByName finder;
MongoMMF *a = finder.find("file_name_a"); MongoMMF *a = finder.find("file_name_a");
MongoMMF *b = finder.find("file_name_b"); MongoMMF *b = finder.find("file_name_b");
skipping to change at line 162 skipping to change at line 150
*/ */
MongoFile* findByPath(string path) { MongoFile* findByPath(string path) {
map<string,MongoFile*>::iterator i = MongoFile::pathToFile.find (path); map<string,MongoFile*>::iterator i = MongoFile::pathToFile.find (path);
return i == MongoFile::pathToFile.end() ? NULL : i->second; return i == MongoFile::pathToFile.end() ? NULL : i->second;
} }
private: private:
LockMongoFilesShared _lk; LockMongoFilesShared _lk;
}; };
struct MongoFileAllowWrites {
MongoFileAllowWrites() {
MongoFile::markAllWritable();
}
~MongoFileAllowWrites() {
MongoFile::unmarkAllWritable();
}
};
class MemoryMappedFile : public MongoFile { class MemoryMappedFile : public MongoFile {
protected: protected:
virtual void* viewForFlushing() { virtual void* viewForFlushing() {
if( views.size() == 0 ) if( views.size() == 0 )
return 0; return 0;
assert( views.size() == 1 ); verify( views.size() == 1 );
return views[0]; return views[0];
} }
public: public:
MemoryMappedFile(); MemoryMappedFile();
virtual ~MemoryMappedFile() { virtual ~MemoryMappedFile() {
LockMongoFilesExclusive lk; LockMongoFilesExclusive lk;
close(); close();
} }
skipping to change at line 246 skipping to change at line 225
boost::shared_ptr<mutex> _flushMutex; boost::shared_ptr<mutex> _flushMutex;
void clearWritableBits(void *privateView); void clearWritableBits(void *privateView);
public: public:
static const unsigned ChunkSize = 64 * 1024 * 1024; static const unsigned ChunkSize = 64 * 1024 * 1024;
static const unsigned NChunks = 1024 * 1024; static const unsigned NChunks = 1024 * 1024;
#else #else
void clearWritableBits(void *privateView) { } void clearWritableBits(void *privateView) { }
#endif #endif
protected: protected:
// only posix mmap implementations will support this
virtual void _lock();
virtual void _unlock();
/** close the current private view and open a new replacement */ /** close the current private view and open a new replacement */
void* remapPrivateView(void *oldPrivateAddr); void* remapPrivateView(void *oldPrivateAddr);
}; };
typedef MemoryMappedFile MMF; typedef MemoryMappedFile MMF;
/** p is called from within a mutex that MongoFile uses. so be careful not to deadlock. */ /** p is called from within a mutex that MongoFile uses. so be careful not to deadlock. */
template < class F > template < class F >
inline void MongoFile::forEach( F p ) { inline void MongoFile::forEach( F p ) {
skipping to change at line 273 skipping to change at line 249
#if defined(_WIN32) #if defined(_WIN32)
class ourbitset { class ourbitset {
volatile unsigned bits[MemoryMappedFile::NChunks]; // volatile as w e are doing double check locking volatile unsigned bits[MemoryMappedFile::NChunks]; // volatile as w e are doing double check locking
public: public:
ourbitset() { ourbitset() {
memset((void*) bits, 0, sizeof(bits)); memset((void*) bits, 0, sizeof(bits));
} }
bool get(unsigned i) const { bool get(unsigned i) const {
unsigned x = i / 32; unsigned x = i / 32;
assert( x < MemoryMappedFile::NChunks ); verify( x < MemoryMappedFile::NChunks );
return (bits[x] & (1 << (i%32))) != 0; return (bits[x] & (1 << (i%32))) != 0;
} }
void set(unsigned i) { void set(unsigned i) {
unsigned x = i / 32; unsigned x = i / 32;
wassert( x < (MemoryMappedFile::NChunks*2/3) ); // warn if gett ing close to limit wassert( x < (MemoryMappedFile::NChunks*2/3) ); // warn if gett ing close to limit
assert( x < MemoryMappedFile::NChunks ); verify( x < MemoryMappedFile::NChunks );
bits[x] |= (1 << (i%32)); bits[x] |= (1 << (i%32));
} }
void clear(unsigned i) { void clear(unsigned i) {
unsigned x = i / 32; unsigned x = i / 32;
assert( x < MemoryMappedFile::NChunks ); verify( x < MemoryMappedFile::NChunks );
bits[x] &= ~(1 << (i%32)); bits[x] &= ~(1 << (i%32));
} }
}; };
extern ourbitset writable; extern ourbitset writable;
void makeChunkWritable(size_t chunkno); void makeChunkWritable(size_t chunkno);
inline void MemoryMappedFile::makeWritable(void *_p, unsigned len) { inline void MemoryMappedFile::makeWritable(void *_p, unsigned len) {
size_t p = (size_t) _p; size_t p = (size_t) _p;
unsigned a = p/ChunkSize; unsigned a = p/ChunkSize;
unsigned b = (p+len)/ChunkSize; unsigned b = (p+len)/ChunkSize;
for( unsigned i = a; i <= b; i++ ) { for( unsigned i = a; i <= b; i++ ) {
 End of changes. 9 change blocks. 
29 lines changed or deleted 5 lines changed or added


 model.h   model.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 "dbclient.h" #include "mongo/bson/bsonelement.h"
#include "redef_macros.h" #include "mongo/bson/bsonobj.h"
namespace mongo { namespace mongo {
/** Model is a base class for defining objects which are serializable t o the Mongo /** Model is a base class for defining objects which are serializable t o the Mongo
database via the database driver. database via the database driver.
Definition Definition
Your serializable class should inherit from Model and implement the abstract methods Your serializable class should inherit from Model and implement the abstract methods
below. below.
skipping to change at line 61 skipping to change at line 61
*/ */
virtual bool load(BSONObj& query); virtual bool load(BSONObj& query);
virtual void save( bool safe=false ); virtual void save( bool safe=false );
virtual void remove( bool safe=false ); virtual void remove( bool safe=false );
protected: protected:
BSONObj _id; BSONObj _id;
}; };
} // namespace mongo } // namespace mongo
#include "undef_macros.h"
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 mongommf.h   mongommf.h 
skipping to change at line 78 skipping to change at line 78
initialization. initialization.
*/ */
static void* _switchToWritableView(void *private_ptr); static void* _switchToWritableView(void *private_ptr);
/** for a filename a/b/c.3 /** for a filename a/b/c.3
filePath() is "a/b/c" filePath() is "a/b/c"
fileSuffixNo() is 3 fileSuffixNo() is 3
if the suffix is "ns", fileSuffixNo -1 if the suffix is "ns", fileSuffixNo -1
*/ */
const RelativePath& relativePath() const { const RelativePath& relativePath() const {
DEV assert( !_p._p.empty() ); DEV verify( !_p._p.empty() );
return _p; return _p;
} }
int fileSuffixNo() const { return _fileSuffixNo; } int fileSuffixNo() const { return _fileSuffixNo; }
/** true if we have written. /** true if we have written.
set in PREPLOGBUFFER, it is NOT set immediately on write intent declaration. set in PREPLOGBUFFER, it is NOT set immediately on write intent declaration.
reset to false in REMAPPRIVATEVIEW reset to false in REMAPPRIVATEVIEW
*/ */
bool& willNeedRemap() { return _willNeedRemap; } bool& willNeedRemap() { return _willNeedRemap; }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 mongomutex.h   mongomutex.h 
skipping to change at line 19 skipping to change at line 19
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Lice nse * You should have received a copy of the GNU Affero General Public Lice nse
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* Mutex heirarchy (1 = "leaf")
name level
Logstream::mutex 1
ClientCursor::ccmutex 2
dblock 3
End func name with _inlock to indicate "caller must lock before callin
g".
*/
#pragma once #pragma once
#include "../util/concurrency/rwlock.h"
#include "../util/mmap.h"
#include "../util/time_support.h" #include "../util/time_support.h"
#include "d_globals.h" #include "d_globals.h"
namespace mongo { namespace mongo {
class Client; class Client;
Client* curopWaitingForLock( int type );
void curopGotLock(Client*);
/* mongomutex time stats */ /* mongomutex time stats */
class MutexInfo { class MutexInfo {
unsigned long long enter, timeLocked; // microseconds unsigned long long enter, timeLocked; // microseconds
int locked; int locked;
unsigned long long start; // last as we touch this least often unsigned long long start; // last as we touch this least often
public: public:
MutexInfo() : timeLocked(0) , locked(0) { MutexInfo() : timeLocked(0) , locked(0) {
start = curTimeMicros64(); start = curTimeMicros64();
} }
void entered() { void entered() {
if ( locked == 0 ) if ( locked == 0 )
enter = curTimeMicros64(); enter = curTimeMicros64();
locked++; locked++;
assert( locked >= 1 ); verify( locked >= 1 );
} }
void leaving() { void leaving() {
locked--; locked--;
assert( locked >= 0 ); verify( locked >= 0 );
if ( locked == 0 ) if ( locked == 0 )
timeLocked += curTimeMicros64() - enter; timeLocked += curTimeMicros64() - enter;
} }
int isLocked() const { return locked; } int isLocked() const { return locked; }
void getTimingInfo(unsigned long long &s, unsigned long long &tl) c onst { void getTimingInfo(unsigned long long &s, unsigned long long &tl) c onst {
s = start; s = start;
tl = timeLocked; tl = timeLocked;
} }
unsigned long long getTimeLocked() const { return timeLocked; } unsigned long long getTimeLocked() const { return timeLocked; }
}; };
/** the 'big lock'. a read/write lock. /** old. see Lock class in d_concurrency.h instead. */
there is one of these, d.dbMutex. class MongoMutex : boost::noncopyable {
generally if you need to declare a mutex use the right primitive cl
ass, not this.
use readlock and writelock classes for scoped locks on this rather
than direct
manipulation.
*/
class MongoMutex {
public: public:
MongoMutex(const char * name); MongoMutex();
/** @return
* > 0 write lock
* = 0 no lock
* < 0 read lock
*/
int getState() const { return _state.get(); }
bool atLeastReadLocked() const { return _state.get() != 0; }
void assertAtLeastReadLocked() const { assert(atLeastReadLocked());
}
bool isWriteLocked/*by our thread*/() const { return getState() > 0
; }
void assertWriteLocked() const {
assert( getState() > 0 );
DEV assert( !_releasedEarly.get() );
}
// write lock. use the writelock scoped lock class, not this direc
tly.
void lock() {
if ( _writeLockedAlready() )
return;
_state.set(1);
curopWaitingForLock( 1 ); // stats
_m.lock();
MongoFile::markAllWritable(); // for _DEBUG validation -- a no
op for release build
_acquiredWriteLock();
}
// try write lock
bool lock_try( int millis ) {
if ( _writeLockedAlready() ) // adjusts _state
return true;
curopWaitingForLock( 1 );
bool got = _m.lock_try( millis );
if ( got ) {
_state.set(1);
MongoFile::markAllWritable(); // for _DEBUG validation -- a
no op for release build
_acquiredWriteLock();
}
return got;
}
// un write lock
void unlock() {
int s = _state.get();
if( s > 1 ) {
_state.set(s-1); // recursive lock case
return;
}
if( s != 1 ) {
if( _releasedEarly.get() ) {
_releasedEarly.set(false);
return;
}
massert( 12599, "internal error: attempt to unlock when was
n't in a write lock", false);
}
_releasingWriteLock();
MongoFile::unmarkAllWritable(); // _DEBUG validation
_state.set(0);
_m.unlock();
}
/* unlock (write lock), and when unlock() is called later,
be smart then and don't unlock it again.
*/
void releaseEarly() {
assert( getState() == 1 ); // must not be recursive
assert( !_releasedEarly.get() );
_releasedEarly.set(true);
unlock();
}
// read lock. don't call directly, use readlock.
void lock_shared() {
int s = _state.get();
if( s ) {
if( s > 0 ) {
// already in write lock - just be recursive and stay w
rite locked
_state.set(s+1);
}
else {
// already in read lock - recurse
_state.set(s-1);
}
}
else {
_state.set(-1);
Client *c = curopWaitingForLock( -1 );
_m.lock_shared();
curopGotLock(c);
}
}
// try read lock
bool lock_shared_try( int millis ) {
int s = _state.get();
if ( s ) {
// we already have a lock, so no need to try
lock_shared();
return true;
}
/* [dm] should there be
Client *c = curopWaitingForLock( 1 );
here? i think so. seems to be missing.
*/
bool got = _m.lock_shared_try( millis );
if ( got )
_state.set(-1);
return got;
}
void unlock_shared() {
int s = _state.get();
if( s > 0 ) {
wassert( s > 1 ); /* we must have done a lock write first t
o have s > 1 */
_state.set(s-1);
return;
}
if( s < -1 ) {
_state.set(s+1);
return;
}
wassert( s == -1 );
_state.set(0);
_m.unlock_shared();
}
MutexInfo& info() { return _minfo; } MutexInfo& info() { return _minfo; }
private:
void lockedExclusively();
void unlockingExclusively();
void _acquiredWriteLock();
void _releasingWriteLock();
/* @return true if was already write locked. increments recursive
lock count. */
bool _writeLockedAlready();
RWLock _m;
/* > 0 write lock with recurse count
< 0 read lock
*/
ThreadLocalValue<int> _state;
MutexInfo _minfo; MutexInfo _minfo;
public:
// indicates we need to call dur::REMAPPRIVATEVIEW on the next writ
e lock
bool _remapPrivateViewRequested;
private:
/* See the releaseEarly() method.
we use a separate TLS value for releasedEarly - that is ok as
our normal/common code path, we never even touch it */
ThreadLocalValue<bool> _releasedEarly;
/* this is for fsyncAndLock command. otherwise write lock's greedi
ness will
make us block on any attempted write lock the the fsync's lock.
*/
//volatile bool _blockWrites;
}; };
namespace dur {
void REMAPPRIVATEVIEW();
void releasingWriteLock(); // because it's hard to include dur.h he
re
}
inline void MongoMutex::_releasingWriteLock() {
dur::releasingWriteLock();
unlockingExclusively();
}
inline void MongoMutex::_acquiredWriteLock() {
lockedExclusively();
if( _remapPrivateViewRequested ) {
dur::REMAPPRIVATEVIEW();
dassert( !_remapPrivateViewRequested );
}
}
string sayClientState();
/* @return true if was already write locked. increments recursive lock
count. */
inline bool MongoMutex::_writeLockedAlready() {
int s = _state.get();
if( s > 0 ) {
_state.set(s+1);
return true;
}
massert( 10293 , string("internal error: locks are not upgradeable:
") + sayClientState() , s == 0 );
return false;
}
struct writelock {
writelock() { d.dbMutex.lock(); }
writelock(const string& ns) { d.dbMutex.lock(); }
~writelock() {
DESTRUCTOR_GUARD(
d.dbMutex.unlock();
);
}
};
struct readlock {
readlock(const string& ns) {
d.dbMutex.lock_shared();
}
readlock() { d.dbMutex.lock_shared(); }
~readlock() {
DESTRUCTOR_GUARD(
d.dbMutex.unlock_shared();
);
}
};
struct readlocktry {
readlocktry( const string&ns , int tryms ) {
_got = d.dbMutex.lock_shared_try( tryms );
}
~readlocktry() {
if ( _got ) {
d.dbMutex.unlock_shared();
}
}
bool got() const { return _got; }
private:
bool _got;
};
struct writelocktry {
writelocktry( const string&ns , int tryms ) {
_got = d.dbMutex.lock_try( tryms );
}
~writelocktry() {
if ( _got ) {
d.dbMutex.unlock();
}
}
bool got() const { return _got; }
private:
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 {
atleastreadlock( const string& ns = "" ) {
_prev = d.dbMutex.getState();
if ( _prev == 0 )
d.dbMutex.lock_shared();
}
~atleastreadlock() {
if ( _prev == 0 )
d.dbMutex.unlock_shared();
}
private:
int _prev;
};
/* parameterized choice of read or write locking
use readlock and writelock instead of this when statically known whi
ch you want
*/
class mongolock {
bool _writelock;
public:
mongolock(bool write) : _writelock(write) {
if( _writelock ) {
d.dbMutex.lock();
}
else
d.dbMutex.lock_shared();
}
~mongolock() {
DESTRUCTOR_GUARD(
if( _writelock ) {
d.dbMutex.unlock();
}
else {
d.dbMutex.unlock_shared();
}
);
}
/* this unlocks, does NOT upgrade. that works for our current usage
*/
//void releaseAndWriteLock();
};
/* deprecated - use writelock and readlock instead */
struct dblock : public writelock {
dblock() : writelock("") { }
};
// eliminate this - we should just type "d.dbMutex.assertWriteLocked();
" instead
inline void assertInWriteLock() { d.dbMutex.assertWriteLocked(); }
} }
 End of changes. 10 change blocks. 
348 lines changed or deleted 5 lines changed or added


 mr.h   mr.h 
skipping to change at line 287 skipping to change at line 287
/** State maintains ownership, do no use past State lifetime */ /** State maintains ownership, do no use past State lifetime */
Scope* scope() { return _scope.get(); } Scope* scope() { return _scope.get(); }
const Config& config() { return _config; } const Config& config() { return _config; }
const bool isOnDisk() { return _onDisk; } const bool isOnDisk() { return _onDisk; }
long long numEmits() const { if (_jsMode) return _scope->getNum berLongLong("_emitCt"); return _numEmits; } long long numEmits() const { if (_jsMode) return _scope->getNum berLongLong("_emitCt"); return _numEmits; }
long long numReduces() const { if (_jsMode) return _scope->getN umberLongLong("_redCt"); return _config.reducer->numReduces; } long long numReduces() const { if (_jsMode) return _scope->getN umberLongLong("_redCt"); return _config.reducer->numReduces; }
long long numInMemKeys() const { if (_jsMode) return _scope->ge tNumberLongLong("_keyCt"); return _temp->size(); }
bool jsMode() {return _jsMode;} bool jsMode() {return _jsMode;}
void switchMode(bool jsMode); void switchMode(bool jsMode);
void bailFromJS(); void bailFromJS();
const Config& _config; const Config& _config;
DBDirectClient _db; DBDirectClient _db;
protected: protected:
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 msg.h   msg.h 
skipping to change at line 22 skipping to change at line 22
* 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 <deque> #include <deque>
#include <boost/thread/condition.hpp>
#include "task.h" #include "task.h"
namespace mongo { namespace mongo {
namespace task { namespace task {
typedef boost::function<void()> lam; typedef boost::function<void()> lam;
/** typical usage is: task::fork( new Server("threadname") ); */ /** typical usage is: task::fork( new Server("threadname") ); */
class Server : public Task { class Server : public Task {
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 mutex.h   mutex.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 "../heapcheck.h" #ifdef _WIN32
#include "threadlocal.h" # include <concrt.h>
#endif
#include <boost/noncopyable.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/xtime.hpp>
#include "mongo/util/assert_util.h"
#include "mongo/util/heapcheck.h"
#include "mongo/util/concurrency/threadlocal.h"
#if defined(_DEBUG) #if defined(_DEBUG)
#include "mutexdebugger.h" #include "mongo/util/concurrency/mutexdebugger.h"
#endif #endif
namespace mongo { namespace mongo {
inline boost::xtime incxtimemillis( long long s ) { inline boost::xtime incxtimemillis( 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 += (int)( s / 1000 ); xt.sec += (int)( s / 1000 );
xt.nsec += (int)(( s % 1000 ) * 1000000); xt.nsec += (int)(( s % 1000 ) * 1000000);
if ( xt.nsec >= 1000000000 ) { if ( xt.nsec >= 1000000000 ) {
skipping to change at line 73 skipping to change at line 83
if( !StaticObserver::_destroyingStatics ) { if( !StaticObserver::_destroyingStatics ) {
UNIGNORE_OBJECT( _m ); UNIGNORE_OBJECT( _m );
delete _m; delete _m;
} }
} }
class try_lock : boost::noncopyable { class try_lock : boost::noncopyable {
public: public:
try_lock( mongo::mutex &m , int millis = 0 ) try_lock( mongo::mutex &m , int millis = 0 )
: _l( m.boost() , incxtimemillis( millis ) ) , : _l( m.boost() , incxtimemillis( millis ) ) ,
#if BOOST_VERSION >= 103500
ok( _l.owns_lock() ) ok( _l.owns_lock() )
#else
ok( _l.locked() )
#endif
{ } { }
private: private:
boost::timed_mutex::scoped_timed_lock _l; boost::timed_mutex::scoped_timed_lock _l;
public: public:
const bool ok; const bool ok;
}; };
class scoped_lock : boost::noncopyable { class scoped_lock : boost::noncopyable {
public: public:
#if defined(_DEBUG) #if defined(_DEBUG)
skipping to change at line 116 skipping to change at line 122
} }
boost::timed_mutex::scoped_lock &boost() { return _l; } boost::timed_mutex::scoped_lock &boost() { return _l; }
private: private:
boost::timed_mutex::scoped_lock _l; boost::timed_mutex::scoped_lock _l;
}; };
private: private:
boost::timed_mutex &boost() { return *_m; } boost::timed_mutex &boost() { return *_m; }
boost::timed_mutex *_m; boost::timed_mutex *_m;
}; };
typedef mutex::scoped_lock scoped_lock; typedef mongo::mutex::scoped_lock scoped_lock;
typedef boost::recursive_mutex::scoped_lock recursive_scoped_lock;
/** The concept with SimpleMutex is that it is a basic lock/unlock with no /** The concept with SimpleMutex is that it is a basic lock/unlock with no
special functionality (such as try and try timeout). Thus it can be special functionality (such as try and try timeout). Thus it can be
implemented using OS-specific facilities in all environments (if desired). implemented using OS-specific facilities in all environments (if desired).
On Windows, the implementation below is faster than boost mutex. On Windows, the implementation below is faster than boost mutex.
*/ */
#if defined(_WIN32) #if defined(_WIN32)
class SimpleMutex : boost::noncopyable { class SimpleMutex {
CRITICAL_SECTION _cs;
public: public:
SimpleMutex(const char *name) { InitializeCriticalSection(&_cs); } SimpleMutex( const char * ) {}
~SimpleMutex() { DeleteCriticalSection(&_cs); }
#if defined(_DEBUG)
ThreadLocalValue<int> _nlocksByMe;
void lock() {
assert( _nlocksByMe.get() == 0 ); // indicates you rae trying t
o lock recursively
_nlocksByMe.set(1);
EnterCriticalSection(&_cs);
}
void dassertLocked() const {
assert( _nlocksByMe.get() == 1 );
}
void unlock() {
dassertLocked();
_nlocksByMe.set(0);
LeaveCriticalSection(&_cs);
}
#else
void dassertLocked() const { } void dassertLocked() const { }
void lock() { void lock() { _cs.lock(); }
EnterCriticalSection(&_cs); void unlock() { _cs.unlock(); }
} class scoped_lock {
void unlock() {
LeaveCriticalSection(&_cs);
}
#endif
class scoped_lock : boost::noncopyable {
SimpleMutex& _m; SimpleMutex& _m;
public: public:
scoped_lock( SimpleMutex &m ) : _m(m) { _m.lock(); } scoped_lock( SimpleMutex &m ) : _m(m) { _m.lock(); }
~scoped_lock() { _m.unlock(); } ~scoped_lock() { _m.unlock(); }
# if defined(_DEBUG)
const SimpleMutex& m() const { return _m; } const SimpleMutex& m() const { return _m; }
# endif
}; };
private:
Concurrency::critical_section _cs;
}; };
#else #else
class SimpleMutex : boost::noncopyable { class SimpleMutex : boost::noncopyable {
public: public:
void dassertLocked() const { } void dassertLocked() const { }
SimpleMutex(const char* name) { assert( pthread_mutex_init(&_lock,0 ) == 0 ); } SimpleMutex(const char* name) { verify( pthread_mutex_init(&_lock,0 ) == 0 ); }
~SimpleMutex(){ ~SimpleMutex(){
if ( ! StaticObserver::_destroyingStatics ) { if ( ! StaticObserver::_destroyingStatics ) {
assert( pthread_mutex_destroy(&_lock) == 0 ); verify( pthread_mutex_destroy(&_lock) == 0 );
} }
} }
void lock() { assert( pthread_mutex_lock(&_lock) == 0 ); } void lock() { verify( pthread_mutex_lock(&_lock) == 0 ); }
void unlock() { assert( pthread_mutex_unlock(&_lock) == 0 ); } void unlock() { verify( pthread_mutex_unlock(&_lock) == 0 ); }
public: public:
class scoped_lock : boost::noncopyable { class scoped_lock : boost::noncopyable {
SimpleMutex& _m; SimpleMutex& _m;
public: public:
scoped_lock( SimpleMutex &m ) : _m(m) { _m.lock(); } scoped_lock( SimpleMutex &m ) : _m(m) { _m.lock(); }
~scoped_lock() { _m.unlock(); } ~scoped_lock() { _m.unlock(); }
const SimpleMutex& m() const { return _m; } const SimpleMutex& m() const { return _m; }
}; };
private: private:
skipping to change at line 210 skipping to change at line 191
bool isLocked() const { return n.get() > 0; } bool isLocked() const { return n.get() > 0; }
class scoped_lock : boost::noncopyable { class scoped_lock : boost::noncopyable {
RecursiveMutex& rm; RecursiveMutex& rm;
int& nLocksByMe; int& nLocksByMe;
public: public:
scoped_lock( RecursiveMutex &m ) : rm(m), nLocksByMe(rm.n.getRe f()) { scoped_lock( RecursiveMutex &m ) : rm(m), nLocksByMe(rm.n.getRe f()) {
if( nLocksByMe++ == 0 ) if( nLocksByMe++ == 0 )
rm.m.lock(); rm.m.lock();
} }
~scoped_lock() { ~scoped_lock() {
assert( nLocksByMe > 0 ); verify( nLocksByMe > 0 );
if( --nLocksByMe == 0 ) { if( --nLocksByMe == 0 ) {
rm.m.unlock(); rm.m.unlock();
} }
} }
}; };
private: private:
SimpleMutex m; SimpleMutex m;
ThreadLocalValue<int> n; ThreadLocalValue<int> n;
}; };
 End of changes. 15 change blocks. 
47 lines changed or deleted 27 lines changed or added


 mutexdebugger.h   mutexdebugger.h 
// @file mutexdebugger.h // @file mutexdebugger.h
#pragma once #pragma once
#include "mongo/client/undef_macros.h"
#include <iostream>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include "boost/thread/mutex.hpp"
#include "mongo/client/redef_macros.h"
#include "mongo/util/assert_util.h"
namespace mongo { namespace mongo {
/** only used on _DEBUG builds. /** only used on _DEBUG builds.
MutexDebugger checks that we always acquire locks for multiple mute xes in a consistant (acyclic) order. MutexDebugger checks that we always acquire locks for multiple mute xes in a consistant (acyclic) order.
If we were inconsistent we could deadlock. If we were inconsistent we could deadlock.
*/ */
class MutexDebugger { class MutexDebugger {
typedef const char * mid; // mid = mutex ID typedef const char * mid; // mid = mutex ID
typedef map<mid,int> Preceeding; typedef std::map<mid,int> Preceeding;
map< mid, int > maxNest; std::map< mid, int > maxNest;
boost::thread_specific_ptr< Preceeding > us; boost::thread_specific_ptr< Preceeding > us;
map< mid, set<mid> > followers; std::map< mid, std::set<mid> > followers;
boost::mutex &x; boost::mutex &x;
unsigned magic; unsigned magic;
void aBreakPoint() { } // for debugging void aBreakPoint() { } // for debugging
public: public:
// set these to create an assert that // set these to create an assert that
// b must never be locked before a // b must never be locked before a
// so // so
// a.lock(); b.lock(); is fine // a.lock(); b.lock(); is fine
// b.lock(); alone is fine too // b.lock(); alone is fine too
// only checked on _DEBUG builds. // only checked on _DEBUG builds.
string a,b; std::string a,b;
/** outputs some diagnostic info on mutexes (on _DEBUG builds) */ /** outputs some diagnostic info on mutexes (on _DEBUG builds) */
void programEnding(); void programEnding();
MutexDebugger(); MutexDebugger();
string currentlyLocked() const { std::string currentlyLocked() const {
Preceeding *_preceeding = us.get(); Preceeding *_preceeding = us.get();
if( _preceeding == 0 ) if( _preceeding == 0 )
return ""; return "";
Preceeding &preceeding = *_preceeding; Preceeding &preceeding = *_preceeding;
stringstream q; std::stringstream q;
for( Preceeding::const_iterator i = preceeding.begin(); i != pr eceeding.end(); i++ ) { for( Preceeding::const_iterator i = preceeding.begin(); i != pr eceeding.end(); i++ ) {
if( i->second > 0 ) if( i->second > 0 )
q << " " << i->first << ' ' << i->second << '\n'; q << " " << i->first << ' ' << i->second << '\n';
} }
return q.str(); return q.str();
} }
void entering(mid m) { void entering(mid m) {
if( this == 0 || m == 0 ) return; if( this == 0 || m == 0 ) return;
assert( magic == 0x12345678 ); verify( magic == 0x12345678 );
Preceeding *_preceeding = us.get(); Preceeding *_preceeding = us.get();
if( _preceeding == 0 ) if( _preceeding == 0 )
us.reset( _preceeding = new Preceeding() ); us.reset( _preceeding = new Preceeding() );
Preceeding &preceeding = *_preceeding; Preceeding &preceeding = *_preceeding;
if( a == m ) { if( a == m ) {
aBreakPoint(); aBreakPoint();
if( preceeding[b.c_str()] ) { if( preceeding[b.c_str()] ) {
cout << "****** MutexDebugger error! warning " << b << std::cout << "****** MutexDebugger error! warning " <<
" was locked before " << a << endl; b << " was locked before " << a << std::endl;
assert(false); verify(false);
} }
} }
preceeding[m]++; preceeding[m]++;
if( preceeding[m] > 1 ) { if( preceeding[m] > 1 ) {
// recursive re-locking. // recursive re-locking.
if( preceeding[m] > maxNest[m] ) if( preceeding[m] > maxNest[m] )
maxNest[m] = preceeding[m]; maxNest[m] = preceeding[m];
return; return;
} }
bool failed = false; bool failed = false;
string err; std::string err;
{ {
boost::mutex::scoped_lock lk(x); boost::mutex::scoped_lock lk(x);
followers[m]; followers[m];
for( Preceeding::iterator i = preceeding.begin(); i != prec eeding.end(); i++ ) { for( Preceeding::iterator i = preceeding.begin(); i != prec eeding.end(); i++ ) {
if( m != i->first && i->second > 0 ) { if( m != i->first && i->second > 0 ) {
followers[i->first].insert(m); followers[i->first].insert(m);
if( followers[m].count(i->first) != 0 ) { if( followers[m].count(i->first) != 0 ) {
failed = true; failed = true;
stringstream ss; std::stringstream ss;
mid bad = i->first; mid bad = i->first;
ss << "mutex problem" << ss << "mutex problem" <<
"\n when locking " << m << "\n when locking " << m <<
"\n " << bad << " was already locked and sh ould not be." "\n " << bad << " was already locked and sh ould not be."
"\n set a and b above to debug.\n"; "\n set a and b above to debug.\n";
stringstream q; std::stringstream q;
for( Preceeding::iterator i = preceeding.begin( ); i != preceeding.end(); i++ ) { for( Preceeding::iterator i = preceeding.begin( ); i != preceeding.end(); i++ ) {
if( i->first != m && i->first != bad && i-> second > 0 ) if( i->first != m && i->first != bad && i-> second > 0 )
q << " " << i->first << '\n'; q << " " << i->first << '\n';
} }
string also = q.str(); std::string also = q.str();
if( !also.empty() ) if( !also.empty() )
ss << "also locked before " << m << " in th is thread (no particular order):\n" << also; ss << "also locked before " << m << " in th is thread (no particular order):\n" << also;
err = ss.str(); err = ss.str();
break; break;
} }
} }
} }
} }
if( failed ) { if( failed ) {
cout << err << endl; std::cout << err << std::endl;
assert( 0 ); verify( 0 );
} }
} }
void leaving(mid m) { void leaving(mid m) {
if( this == 0 || m == 0 ) return; // still in startup pre-main( ) if( this == 0 || m == 0 ) return; // still in startup pre-main( )
Preceeding& preceeding = *us.get(); Preceeding& preceeding = *us.get();
preceeding[m]--; preceeding[m]--;
if( preceeding[m] < 0 ) { if( preceeding[m] < 0 ) {
cout << "ERROR: lock count for " << m << " is " << preceedi std::cout << "ERROR: lock count for " << m << " is " << pre
ng[m] << endl; ceeding[m] << std::endl;
assert( preceeding[m] >= 0 ); verify( preceeding[m] >= 0 );
} }
} }
}; };
extern MutexDebugger &mutexDebugger; extern MutexDebugger &mutexDebugger;
} }
 End of changes. 14 change blocks. 
19 lines changed or deleted 33 lines changed or added


 mvar.h   mvar.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/recursive_mutex.hpp>
#include <boost/thread/condition.hpp>
namespace mongo { namespace mongo {
/* This is based on haskell's MVar synchronization primitive: /* This is based on haskell's MVar synchronization primitive:
* http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-C oncurrent-MVar.html * http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-C oncurrent-MVar.html
* *
* It is a thread-safe queue that can hold at most one object. * It is a thread-safe queue that can hold at most one object.
* You can also think of it as a box that can be either full or empty. * You can also think of it as a box that can be either full or empty.
*/ */
template <typename T> template <typename T>
 End of changes. 1 change blocks. 
0 lines changed or deleted 3 lines changed or added


 namespace-inl.h   namespace-inl.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 "namespace.h" #include "mongo/db/namespace.h"
namespace mongo { namespace mongo {
inline Namespace& Namespace::operator=(const char *ns) { inline Namespace& Namespace::operator=(const char *ns) {
// we fill the remaining space with all zeroes here. as the full N amespace struct is in // we fill the remaining space with all zeroes here. as the full N amespace struct is in
// the datafiles (the .ns files specifically), that is helpful as t hen they are deterministic // the datafiles (the .ns files specifically), that is helpful as t hen they are deterministic
// in the bytes they have for a given sequence of operations. that makes testing and debugging // in the bytes they have for a given sequence of operations. that makes testing and debugging
// the data files easier. // the data files easier.
// //
// if profiling indicates this method is a significant bottleneck, we could have a version we // if profiling indicates this method is a significant bottleneck, we could have a version we
skipping to change at line 66 skipping to change at line 66
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
} }
/* future : this doesn't need to be an inline. */ /* future : this doesn't need to be an inline. */
inline string Namespace::getSisterNS( const char * local ) const { inline string Namespace::getSisterNS( const char * local ) const {
assert( local && local[0] != '.' ); verify( local && local[0] != '.' );
string old(buf); string old(buf);
if ( old.find( "." ) != string::npos ) if ( old.find( "." ) != string::npos )
old = old.substr( 0 , old.find( "." ) ); old = old.substr( 0 , old.find( "." ) );
return old + "." + local; return old + "." + local;
} }
inline IndexDetails& NamespaceDetails::idx(int idxNo, bool missingExpec } // namespace mongo
ted ) {
if( idxNo < NIndexesBase ) {
IndexDetails& id = _indexes[idxNo];
return id;
}
Extra *e = extra();
if ( ! e ) {
if ( missingExpected )
throw MsgAssertionException( 13283 , "Missing Extra" );
massert(14045, "missing Extra", e);
}
int i = idxNo - NIndexesBase;
if( i >= NIndexesExtra ) {
e = e->next(this);
if ( ! e ) {
if ( missingExpected )
throw MsgAssertionException( 14823 , "missing extra" );
massert(14824, "missing Extra", e);
}
i -= NIndexesExtra;
}
return e->details[i];
}
inline int NamespaceDetails::idxNo(IndexDetails& idx) {
IndexIterator i = ii();
while( i.more() ) {
if( &i.next() == &idx )
return i.pos()-1;
}
massert( 10349 , "E12000 idxNo fails", false);
return -1;
}
inline int NamespaceDetails::findIndexByKeyPattern(const BSONObj& keyPa
ttern) {
IndexIterator i = ii();
while( i.more() ) {
if( i.next().keyPattern() == keyPattern )
return i.pos()-1;
}
return -1;
}
// @return offset in indexes[]
inline int NamespaceDetails::findIndexByName(const char *name) {
IndexIterator i = ii();
while( i.more() ) {
if ( strcmp(i.next().info.obj().getStringField("name"),name) ==
0 )
return i.pos()-1;
}
return -1;
}
inline NamespaceDetails::IndexIterator::IndexIterator(NamespaceDetails
*_d) {
d = _d;
i = 0;
n = d->nIndexes;
}
}
 End of changes. 3 change blocks. 
2 lines changed or deleted 2 lines changed or added


 namespace.h   namespace.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 "../pch.h" #include "pch.h"
#include "namespacestring.h"
#include "jsobj.h"
#include "querypattern.h"
#include "diskloc.h"
#include "../util/hashtab.h"
#include "mongommf.h"
#include "d_concurrency.h"
namespace mongo { #include <cstring>
#include <string>
class Database; namespace mongo {
#pragma pack(1) #pragma pack(1)
/* This helper class is used to make the HashMap below in NamespaceInde
x e.g. see line:
HashTable<Namespace,NamespaceDetails> *ht;
*/
class Namespace { class Namespace {
public: public:
explicit Namespace(const char *ns) { *this = ns; } explicit Namespace(const char *ns) { *this = ns; }
Namespace& operator=(const char *ns); Namespace& operator=(const char *ns);
bool hasDollarSign() const { return strchr( buf , '$' ) > 0; } bool hasDollarSign() const { return strchr( buf , '$' ) > 0; }
void kill() { buf[0] = 0x7f; } void kill() { buf[0] = 0x7f; }
bool operator==(const char *r) const { return strcmp(buf, r) == 0; } bool operator==(const char *r) const { return strcmp(buf, r) == 0; }
bool operator==(const Namespace& r) const { return strcmp(buf, r.bu f) == 0; } bool operator==(const Namespace& r) const { return strcmp(buf, r.bu f) == 0; }
int hash() const; // value returned is always > 0 int hash() const; // value returned is always > 0
size_t size() const { return strlen( buf ); } size_t size() const { return strlen( buf ); }
string toString() const { return (string) buf; } string toString() const { return buf; }
operator string() const { return (string) buf; } operator string() const { return buf; }
/* NamespaceDetails::Extra was added after fact to allow chaining o f data blocks to support more than 10 indexes /* NamespaceDetails::Extra was added after fact to allow chaining o f data blocks to support more than 10 indexes
(more than 10 IndexDetails). It's a bit hacky because of this l ate addition with backward (more than 10 IndexDetails). It's a bit hacky because of this l ate addition with backward
file support. */ file support. */
string extraName(int i) const; string extraName(int i) const;
bool isExtra() const; /* ends with $extr... -- when true an extra b lock not a normal NamespaceDetails block */ bool isExtra() const; /* ends with $extr... -- when true an extra b lock not a normal NamespaceDetails block */
/** ( foo.bar ).getSisterNS( "blah" ) == foo.blah /** ( foo.bar ).getSisterNS( "blah" ) == foo.blah
perhaps this should move to the NamespaceString helper? perhaps this should move to the NamespaceString helper?
*/ */
string getSisterNS( const char * local ) const; string getSisterNS( const char * local ) const;
enum MaxNsLenValue { MaxNsLen = 128 }; enum MaxNsLenValue { MaxNsLen = 128 };
private: private:
char buf[MaxNsLen]; char buf[MaxNsLen];
}; };
#pragma pack() #pragma pack()
} // namespace mongo } // namespace mongo
#include "index.h"
namespace mongo {
/** @return true if a client can modify this namespace even though it i
s under ".system."
For example <dbname>.system.users is ok for regular clients to upda
te.
@param write used when .system.js
*/
bool legalClientSystemNS( const string& ns , bool write );
/* 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.
*/
const int Buckets = 19;
const int MaxBucket = 18;
extern int bucketSizes[];
#pragma pack(1)
/* NamespaceDetails : this is the "header" for a collection that has al
l its details.
It's in the .ns file and this is a memory mapped region (thus the pa
ck pragma above).
*/
class NamespaceDetails {
public:
enum { NIndexesMax = 64, NIndexesExtra = 30, NIndexesBase = 10 };
/*-------- data fields, as present on disk : */
DiskLoc firstExtent;
DiskLoc lastExtent;
/* NOTE: capped collections v1 override the meaning of deletedList.
deletedList[0] points to a list of free records (DeletedRe
cord's) for all extents in
the capped namespace.
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
yet computed.
*/
DiskLoc deletedList[Buckets];
// ofs 168 (8 byte aligned)
struct Stats {
// datasize and nrecords MUST Be adjacent code assumes!
long long datasize; // this includes padding, but not record he
aders
long long nrecords;
} stats;
int lastExtentSize;
int nIndexes;
private:
// ofs 192
IndexDetails _indexes[NIndexesBase];
public:
// ofs 352 (16 byte aligned)
int capped;
int max; // max # of objects for a cap
ped table. TODO: should this be 64 bit?
double paddingFactor; // 1.0 = no padding.
// ofs 386 (16)
int flags;
DiskLoc capExtent;
DiskLoc capFirstNewRecord;
unsigned short dataFileVersion; // NamespaceDetails version.
So we can do backward compatibility in the future. See filever.h
unsigned short indexFileVersion;
unsigned long long multiKeyIndexBits;
private:
// ofs 400 (16)
unsigned long long reservedA;
long long extraOffset; // where the $extra info is l
ocated (bytes relative to this)
public:
int indexBuildInProgress; // 1 if in prog
unsigned reservedB;
// ofs 424 (8)
struct Capped2 {
unsigned long long cc2_ptr; // see capped.cpp
unsigned fileNumber;
} capped2;
char reserved[60];
/*-------- end data 496 bytes */
explicit NamespaceDetails( const DiskLoc &loc, bool _capped );
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); return *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) { *getDur().writing(&_next) = ofs; }
void copy(NamespaceDetails *d, const Extra& e) {
memcpy(this, &e, sizeof(Extra));
_next = 0;
}
};
Extra* extra() {
if( extraOffset == 0 ) return 0;
return (Extra *) (((char *) this) + extraOffset);
}
/* 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
/* called when loaded from disk */
void onLoad(const Namespace& k);
/* dump info on this namespace. for debugging. */
void dump(const Namespace& k);
/* dump info on all extents for this namespace. for debugging. */
void dumpExtents();
private:
Extent *theCapExtent() const { return capExtent.ext(); }
void advanceCapExtent( const char *ns );
DiskLoc __capAlloc(int len);
DiskLoc cappedAlloc(const char *ns, int len);
DiskLoc &cappedFirstDeletedInCurExtent();
bool nextIsInCapExtent( const DiskLoc &dl ) const;
public:
DiskLoc& cappedListOfAllDeletedRecords() { return deletedList[0]; }
DiskLoc& cappedLastDelRecLastExtent() { return deletedList[1]; }
void cappedDumpDelInfo();
bool capLooped() const { return capped && capFirstNewRecord.isValid
(); }
bool inCapExtent( const DiskLoc &dl ) const;
void cappedCheckMigrate();
/**
* Truncate documents newer than the document at 'end' from the cap
ped
* collection. The collection cannot be completely emptied using t
his
* function. An assertion will be thrown if that is attempted.
* @param inclusive - Truncate 'end' as well iff true
*/
void cappedTruncateAfter(const char *ns, DiskLoc end, bool inclusiv
e);
/** Remove all documents from the capped collection */
void emptyCappedCollection(const char *ns);
/* 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.
*/
int nIndexesBeingBuilt() const { return nIndexes + indexBuildInProg
ress; }
/* NOTE: be careful with flags. are we manipulating them in read l
ocks? if so,
this isn't thread safe. TODO
*/
enum NamespaceFlags {
Flag_HaveIdIndex = 1 << 0 // set when we have _id index (ONLY i
f ensureIdIndex was called -- 0 if that has never been called)
};
IndexDetails& idx(int idxNo, bool missingExpected = false );
/** get the IndexDetails for the index currently being built in the
background. (there is at most one) */
IndexDetails& inProgIdx() {
DEV assert(indexBuildInProgress);
return idx(nIndexes);
}
class IndexIterator {
public:
int pos() { return i; } // note this is the next one to come
bool more() { return i < n; }
IndexDetails& next() { return d->idx(i++); }
private:
friend class NamespaceDetails;
int i, n;
NamespaceDetails *d;
IndexIterator(NamespaceDetails *_d);
};
IndexIterator ii() { return IndexIterator(this); }
/* hackish - find our index # in the indexes array */
int idxNo(IndexDetails& idx);
/* multikey indexes are indexes where there are more than one key i
n the index
for a single document. see multikey in wiki.
for these, we have to do some dedup work on queries.
*/
bool isMultikey(int i) const { return (multiKeyIndexBits & (((unsig
ned long long) 1) << i)) != 0; }
void setIndexIsMultikey(int i) {
dassert( i < NIndexesMax );
unsigned long long x = ((unsigned long long) 1) << i;
if( multiKeyIndexBits & x ) return;
*getDur().writing(&multiKeyIndexBits) |= x;
}
void clearIndexIsMultikey(int i) {
dassert( i < NIndexesMax );
unsigned long long x = ((unsigned long long) 1) << i;
if( (multiKeyIndexBits & x) == 0 ) return;
*getDur().writing(&multiKeyIndexBits) &= ~x;
}
/* add a new index. does not add to system.indexes etc. - just to
NamespaceDetails.
caller must populate returned object.
*/
IndexDetails& addIndex(const char *thisns, bool resetTransient=true
);
void aboutToDeleteAnIndex() {
*getDur().writing(&flags) = flags & ~Flag_HaveIdIndex;
}
/* returns index of the first index in which the field is present.
-1 if not present. */
int fieldIsIndexed(const char *fieldName);
/* called to indicate that an update fit in place.
fits also called on an insert -- idea there is that if you had s
ome mix and then went to
pure inserts it would adapt and PF would trend to 1.0. note upd
ate calls insert on a move
so there is a double count there that must be adjusted for below
.
todo: greater sophistication could be helpful and added later.
for example the absolute
size of documents might be considered -- in some cases sma
ller ones are more likely
to grow than larger ones in the same collection? (not alwa
ys)
*/
void paddingFits() {
MONGO_SOMETIMES(sometimes, 4) { // do this on a sampled basis t
o journal less
double x = paddingFactor - 0.001;
if ( x >= 1.0 ) {
*getDur().writing(&paddingFactor) = x;
//getDur().setNoJournal(&paddingFactor, &x, sizeof(x));
}
}
}
void paddingTooSmall() {
MONGO_SOMETIMES(sometimes, 4) { // do this on a sampled basis t
o journal less
/* the more indexes we have, the higher the cost of a move.
so we take that into
account herein. note on a move that insert() calls padd
ingFits(), thus
here for example with no inserts and nIndexes = 1 we hav
e
.001*4-.001 or a 3:1 ratio to non moves -> 75% nonmoves.
insert heavy
can pushes this down considerably. further tweaking will
be a good idea but
this should be an adequate starting point.
*/
double N = min(nIndexes,7) + 3;
double x = paddingFactor + (0.001 * N);
if ( x <= 2.0 ) {
*getDur().writing(&paddingFactor) = x;
//getDur().setNoJournal(&paddingFactor, &x, sizeof(x));
}
}
}
// @return offset in indexes[]
int findIndexByName(const char *name);
// @return offset in indexes[]
int findIndexByKeyPattern(const BSONObj& keyPattern);
void findIndexByType( const string& name , vector<int>& matches ) {
IndexIterator i = ii();
while ( i.more() ) {
if ( i.next().getSpec().getTypeName() == name )
matches.push_back( i.pos() - 1 );
}
}
/* @return -1 = not found
generally id is first index, so not that expensive an operation
(assuming present).
*/
int findIdIndex() {
IndexIterator i = ii();
while( i.more() ) {
if( i.next().isIdIndex() )
return i.pos()-1;
}
return -1;
}
bool haveIdIndex() {
return (flags & NamespaceDetails::Flag_HaveIdIndex) || findIdIn
dex() >= 0;
}
/* return which "deleted bucket" for this size object */
static int bucket(int n) {
for ( int i = 0; i < Buckets; i++ )
if ( bucketSizes[i] > n )
return i;
return Buckets-1;
}
/* predetermine location of the next alloc without actually doing i
t.
if cannot predetermine returns null (so still call alloc() then)
*/
DiskLoc allocWillBeAt(const char *ns, int lenToAlloc);
/* allocate a new record. lenToAlloc includes headers. */
DiskLoc alloc(const char *ns, int lenToAlloc, DiskLoc& extentLoc);
/* add a given record to the deleted chains for this NS */
void addDeletedRec(DeletedRecord *d, DiskLoc dloc);
void dumpDeleted(set<DiskLoc> *extents = 0);
// Start from firstExtent by default.
DiskLoc firstRecord( const DiskLoc &startExtent = DiskLoc() ) const
;
// Start from lastExtent by default.
DiskLoc lastRecord( const DiskLoc &startExtent = DiskLoc() ) const;
long long storageSize( int * numExtents = 0 , BSONArrayBuilder * ex
tentInfo = 0 ) const;
int averageObjectSize() {
if ( stats.nrecords == 0 )
return 5;
return (int) (stats.datasize / stats.nrecords);
}
NamespaceDetails *writingWithoutExtra() {
return ( NamespaceDetails* ) getDur().writingPtr( this, sizeof(
NamespaceDetails ) );
}
/** Make all linked Extra objects writeable as well */
NamespaceDetails *writingWithExtra();
private:
DiskLoc _alloc(const char *ns, int len);
void maybeComplain( const char *ns, int len ) const;
DiskLoc __stdAlloc(int len, bool willBeAt);
void compact(); // combine adjacent deleted records
friend class NamespaceIndex;
struct ExtraOld {
// note we could use this field for more chaining later, so don
't waste it:
unsigned long long reserved1;
IndexDetails details[NIndexesExtra];
unsigned reserved2;
unsigned reserved3;
};
/** Update cappedLastDelRecLastExtent() after capExtent changed in
cappedTruncateAfter() */
void cappedTruncateLastDelUpdate();
BOOST_STATIC_ASSERT( NIndexesMax <= NIndexesBase + NIndexesExtra*2
);
BOOST_STATIC_ASSERT( NIndexesMax <= 64 ); // multiKey bits
BOOST_STATIC_ASSERT( sizeof(NamespaceDetails::ExtraOld) == 496 );
BOOST_STATIC_ASSERT( sizeof(NamespaceDetails::Extra) == 496 );
}; // NamespaceDetails
#pragma pack()
/* NamespaceDetailsTransient
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
information.
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;
as currently used that does not cause anything terrible to
happen.
todo: cleanup code, need abstractions and separation
*/
// todo: multiple db's with the same name (repairDatbase) is not handle
d herein. that may be
// the way to go, if not used by repair, but need some sort of en
forcement / asserts.
class NamespaceDetailsTransient : boost::noncopyable {
BOOST_STATIC_ASSERT( sizeof(NamespaceDetails) == 496 );
//Database *database;
const string _ns;
void reset();
static std::map< string, shared_ptr< NamespaceDetailsTransient > >
_nsdMap;
NamespaceDetailsTransient(Database*,const char *ns);
public:
~NamespaceDetailsTransient();
void addedIndex() { assertInWriteLock(); reset(); }
void deletedIndex() { assertInWriteLock(); reset(); }
/* Drop cached information on all namespaces beginning with the spe
cified prefix.
Can be useful as index namespaces share the same start as the re
gular collection.
SLOW - sequential scan of all NamespaceDetailsTransient objects
*/
static void clearForPrefix(const char *prefix);
static void eraseForPrefix(const char *prefix);
/**
* @return a cursor interface to the query optimizer. The implemen
tation may
* utilize a single query plan or interleave results from multiple
query
* plans before settling on a single query plan. Note that the sch
ema of
* currKey() documents, the matcher(), and the isMultiKey() nature
of the
* cursor may change over the course of iteration.
*
* @param query - Query used to select indexes and populate matcher
s; this is not copied, and must outlive the Cursor
*
* @param order - Required ordering spec for documents produced by
this cursor,
* empty object default indicates no order requirement. If no inde
x exists that
* satisfies the required sort order, an empty shared_ptr is return
ed. This is nit copied, and must outlive the Cursor
*
* @param requireIndex - If true, no unindexed (ie collection scan)
cursors are
* used to generate the returned cursor. If an unindexed cursor is
required, an
* assertion is raised by the cursor during iteration.
*
* @param simpleEqualityMatch - Set to true for certain simple quer
ies -
* see queryoptimizer.cpp.
*
* The returned cursor may @throw inside of advance() or recoverFro
mYield() in
* certain error cases, for example if a capped overrun occurred du
ring a yield.
* This indicates that the cursor was unable to perform a complete
scan.
*
* This is a work in progress. Partial list of features not yet im
plemented:
* - covered indexes
* - in memory sorting
*/
static shared_ptr<Cursor> getCursor( const char *ns, const BSONObj
&query,
const BSONObj &order = BSONObj(
), bool requireIndex = false,
bool *simpleEqualityMatch = 0 )
;
/**
* @return a single cursor that may work well for the given query.
* It is possible no cursor is returned if the sort is not supporte
d by an index. Clients are responsible
* for checking this if they are not sure an index for a sort exist
s, and defaulting to a non-sort if
* no suitable indices exist.
*/
static shared_ptr<Cursor> bestGuessCursor( const char *ns, const BS
ONObj &query, const BSONObj &sort );
/* indexKeys() cache ----------------------------------------------
------ */
/* assumed to be in write lock for this */
private:
bool _keysComputed;
set<string> _indexKeys;
void computeIndexKeys();
public:
/* get set of index keys for this namespace. handy to quickly chec
k if a given
field is indexed (Note it might be a secondary component of a co
mpound index.)
*/
set<string>& indexKeys() {
DEV assertInWriteLock();
if ( !_keysComputed )
computeIndexKeys();
return _indexKeys;
}
/* IndexSpec caching */
private:
map<const IndexDetails*,IndexSpec> _indexSpecs;
static SimpleMutex _isMutex;
public:
const IndexSpec& getIndexSpec( const IndexDetails * details ) {
IndexSpec& spec = _indexSpecs[details];
if ( ! spec._finishedInit ) {
SimpleMutex::scoped_lock lk(_isMutex);
if ( ! spec._finishedInit ) {
spec.reset( details );
assert( spec._finishedInit );
}
}
return spec;
}
/* query cache (for query optimizer) ------------------------------
------- */
private:
int _qcWriteCount;
map< QueryPattern, pair< BSONObj, long long > > _qcCache;
static NamespaceDetailsTransient& make_inlock(const char *ns);
public:
static SimpleMutex _qcMutex;
/* you must be in the qcMutex when calling this.
A NamespaceDetailsTransient object will not go out of scope on y
ou if you are
d.dbMutex.atLeastReadLocked(), so you do't have to stay locked.
Creates a NamespaceDetailsTransient before returning if one DNE.
todo: avoid creating too many on erroneous ns queries.
*/
static NamespaceDetailsTransient& get_inlock(const char *ns);
static NamespaceDetailsTransient& get(const char *ns) {
SimpleMutex::scoped_lock lk(_qcMutex);
return get_inlock(ns);
}
void clearQueryCache() { // public for unit tests
_qcCache.clear();
_qcWriteCount = 0;
}
/* you must notify the cache if you are doing writes, as query plan
optimality will change */
void notifyOfWriteOp() {
if ( _qcCache.empty() )
return;
if ( ++_qcWriteCount >= 100 )
clearQueryCache();
}
BSONObj indexForPattern( const QueryPattern &pattern ) {
return _qcCache[ pattern ].first;
}
long long nScannedForPattern( const QueryPattern &pattern ) {
return _qcCache[ pattern ].second;
}
void registerIndexForPattern( const QueryPattern &pattern, const BS
ONObj &indexKey, long long nScanned ) {
_qcCache[ pattern ] = make_pair( indexKey, nScanned );
}
}; /* NamespaceDetailsTransient */
inline NamespaceDetailsTransient& NamespaceDetailsTransient::get_inlock
(const char *ns) {
std::map< string, shared_ptr< NamespaceDetailsTransient > >::iterat
or i = _nsdMap.find(ns);
if( i != _nsdMap.end() &&
i->second.get() ) { // could be null ptr from clearForPrefix
return *i->second;
}
return make_inlock(ns);
}
/* 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.)
*/
class NamespaceIndex {
public:
NamespaceIndex(const string &dir, const string &database) :
ht( 0 ), dir_( dir ), database_( database ) {}
/* returns true if new db will be created if we init lazily */
bool exists() const;
void init() {
if( !ht )
_init();
}
void add_ns(const char *ns, DiskLoc& loc, bool capped);
void add_ns( const char *ns, const NamespaceDetails &details );
NamespaceDetails* details(const char *ns) {
if ( !ht )
return 0;
Namespace n(ns);
NamespaceDetails *d = ht->get(n);
if ( d && d->capped )
d->cappedCheckMigrate();
return d;
}
void kill_ns(const char *ns);
bool find(const char *ns, DiskLoc& loc) {
NamespaceDetails *l = details(ns);
if ( l ) {
loc = l->firstExtent;
return true;
}
return false;
}
bool allocated() const { return ht != 0; }
void getNamespaces( list<string>& tofill , bool onlyCollections = t
rue ) const;
NamespaceDetails::Extra* newExtra(const char *ns, int n, NamespaceD
etails *d);
boost::filesystem::path path() const;
unsigned long long fileLength() const { return f.length(); }
private:
void _init();
void maybeMkdir() const;
MongoMMF f;
HashTable<Namespace,NamespaceDetails> *ht;
string dir_;
string database_;
};
extern string dbpath; // --dbpath parm
extern bool directoryperdb;
// Rename a namespace within current 'client' db.
// (Arguments should include db name)
void renameNamespace( const char *from, const char *to, bool stayTemp);
} // namespace mongo
 End of changes. 6 change blocks. 
16 lines changed or deleted 6 lines changed or added


 namespacestring.h   namespacestring.h 
skipping to change at line 29 skipping to change at line 29
#pragma once #pragma once
#include <string> #include <string>
namespace mongo { namespace mongo {
using std::string; using std::string;
/* in the mongo source code, "client" means "database". */ /* in the mongo source code, "client" means "database". */
const int MaxDatabaseNameLen = 256; // max str len for the db name, inc luding null char const int MaxDatabaseNameLen = 128; // max str len for the db name, inc luding null char
/* 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")
skipping to change at line 122 skipping to change at line 122
void init(const char *ns) { void init(const char *ns) {
const char *p = strchr(ns, '.'); const char *p = strchr(ns, '.');
if( p == 0 ) return; if( p == 0 ) return;
db = string(ns, p - ns); db = string(ns, p - ns);
coll = p + 1; coll = p + 1;
} }
}; };
// "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; for( int i = 0; i < MaxDatabaseNameLen; i++ ) {
char *q = database; database[i] = ns[i];
while ( *p != '.' ) { if( database[i] == '.' ) {
if ( *p == 0 ) database[i] = 0;
break; return;
*q++ = *p++; }
} if( database[i] == 0 ) {
*q = 0; return;
if (q-database>=MaxDatabaseNameLen) { }
log() << "nsToDatabase: ns too long. terminating, buf overrun c
ondition" << endl;
dbexit( EXIT_POSSIBLE_CORRUPTION );
} }
// other checks should have happened already, this is defensive. th
us massert not uassert
massert(10078, "nsToDatabase: ns too long", false);
} }
inline string nsToDatabase(const char *ns) { inline string nsToDatabase(const char *ns) {
char buf[MaxDatabaseNameLen]; char buf[MaxDatabaseNameLen];
nsToDatabase(ns, buf); nsToDatabase(ns, buf);
return buf; return buf;
} }
inline string nsToDatabase(const string& ns) { inline string nsToDatabase(const string& ns) {
size_t i = ns.find( '.' ); size_t i = ns.find( '.' );
if ( i == string::npos ) if ( i == string::npos )
return ns; return ns;
massert(10088, "nsToDatabase: ns too long", i < (size_t)MaxDatabase NameLen);
return ns.substr( 0 , i ); return ns.substr( 0 , i );
} }
} }
 End of changes. 4 change blocks. 
13 lines changed or deleted 14 lines changed or added


 ntservice.h   ntservice.h 
skipping to change at line 26 skipping to change at line 26
*/ */
#pragma once #pragma once
#if defined(_WIN32) #if defined(_WIN32)
#include <windows.h> #include <windows.h>
#include "boost/program_options.hpp" #include "boost/program_options.hpp"
namespace mongo { namespace mongo {
struct ntServiceDefaultStrings {
const wchar_t* serviceName;
const wchar_t* displayName;
const wchar_t* serviceDescription;
};
typedef bool ( *ServiceCallback )( void ); typedef bool ( *ServiceCallback )( void );
bool serviceParamsCheck( boost::program_options::variables_map& params, bool serviceParamsCheck(
const std::string dbpath, int argc, char* argv[] ); boost::program_options::variables_map& params,
const std::string dbpath,
const ntServiceDefaultStrings& defaultStrings,
const vector<string>& disallowedOptions,
int argc,
char* argv[]
);
class ServiceController { class ServiceController {
public: public:
ServiceController(); ServiceController();
virtual ~ServiceController() {} virtual ~ServiceController() {}
static bool installService( const std::wstring& serviceName, const static bool installService(
std::wstring& displayName, const std::wstring& serviceDesc, const std::wstr const std::wstring& serviceName,
ing& serviceUser, const std::wstring& servicePassword, const std::string db const std::wstring& displayName,
path, int argc, char* argv[] ); const std::wstring& serviceDesc,
const std::wstring& serviceUser,
const std::wstring& servicePassword,
const std::string dbpath,
int argc,
char* argv[]
);
static bool removeService( const std::wstring& serviceName ); static bool removeService( const std::wstring& serviceName );
static bool startService( const std::wstring& serviceName, ServiceC allback startService ); static bool startService( const std::wstring& serviceName, ServiceC allback startService );
static bool reportStatus( DWORD reportState, DWORD waitHint = 0 ); static bool reportStatus( DWORD reportState, DWORD waitHint = 0 );
static void WINAPI initService( DWORD argc, LPTSTR *argv ); static void WINAPI initService( DWORD argc, LPTSTR *argv );
static void WINAPI serviceCtrl( DWORD ctrlCode ); static void WINAPI serviceCtrl( DWORD ctrlCode );
protected: protected:
static std::wstring _serviceName; static std::wstring _serviceName;
static SERVICE_STATUS_HANDLE _statusHandle; static SERVICE_STATUS_HANDLE _statusHandle;
 End of changes. 3 change blocks. 
6 lines changed or deleted 24 lines changed or added


 oid.h   oid.h 
skipping to change at line 44 skipping to change at line 44
Typical contents of the BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch), Typical contents of the BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch),
a 3-byte machine id, a 2-byte process id, and a 3-byte counter. Not e that the timestamp and counter fields must a 3-byte machine id, a 2-byte process id, and a 3-byte counter. Not e that the timestamp and counter fields must
be stored big endian unlike the rest of BSON. This is because they are compared byte-by-byte and we want to ensure be stored big endian unlike the rest of BSON. This is because they are compared byte-by-byte and we want to ensure
a mostly increasing order. a mostly increasing order.
*/ */
class OID { class OID {
public: public:
OID() : a(0), b(0) { } OID() : a(0), b(0) { }
/** init from a 24 char hex string */ /** init from a 24 char hex string */
explicit OID(const string &s) { init(s); } explicit OID(const std::string &s) { init(s); }
/** initialize to 'null' */ /** initialize to 'null' */
void clear() { a = 0; b = 0; } void clear() { a = 0; b = 0; }
const unsigned char *getData() const { return data; } const unsigned char *getData() const { return data; }
bool operator==(const OID& r) const { return a==r.a && b==r.b; } bool operator==(const OID& r) const { return a==r.a && b==r.b; }
bool operator!=(const OID& r) const { return a!=r.a || b!=r.b; } bool operator!=(const OID& r) const { return a!=r.a || b!=r.b; }
int compare( const OID& other ) const { return memcmp( data , other .data , 12 ); } int compare( const OID& other ) const { return memcmp( data , other .data , 12 ); }
bool operator<( const OID& other ) const { return compare( other ) < 0; } bool operator<( const OID& other ) const { return compare( other ) < 0; }
bool operator<=( const OID& other ) const { return compare( other ) <= 0; } bool operator<=( const OID& other ) const { return compare( other ) <= 0; }
/** @return the object ID output as 24 hex digits */ /** @return the object ID output as 24 hex digits */
string str() const { return toHexLower(data, 12); } std::string str() const { return toHexLower(data, 12); }
string toString() const { return str(); } std::string toString() const { return str(); }
static OID gen() { OID o; o.init(); return o; } static OID gen() { OID o; o.init(); return o; }
/** sets the contents to a new oid / randomized value */ /** sets the contents to a new oid / randomized value */
void init(); void init();
/** init from a 24 char hex string */ /** init from a 24 char hex string */
void init( string s ); void init( std::string s );
/** Set to the min/max OID that could be generated at given timesta mp. */ /** Set to the min/max OID that could be generated at given timesta mp. */
void init( Date_t date, bool max=false ); void init( Date_t date, bool max=false );
time_t asTimeT(); time_t asTimeT();
Date_t asDateT() { return asTimeT() * (long long)1000; } Date_t asDateT() { return asTimeT() * (long long)1000; }
bool isSet() const { return a || b; } bool isSet() const { return a || b; }
/** /**
skipping to change at line 124 skipping to change at line 124
}; };
unsigned char data[12]; unsigned char data[12];
}; };
static unsigned ourPid(); static unsigned ourPid();
static void foldInPid(MachineAndPid& x); static void foldInPid(MachineAndPid& x);
static MachineAndPid genMachineAndPid(); static MachineAndPid genMachineAndPid();
}; };
#pragma pack() #pragma pack()
ostream& operator<<( ostream &s, const OID &o ); std::ostream& operator<<( std::ostream &s, const OID &o );
inline StringBuilder& operator<< (StringBuilder& s, const OID& o) { ret urn (s << o.str()); } inline StringBuilder& operator<< (StringBuilder& s, const OID& o) { ret urn (s << o.str()); }
/** Formatting mode for generating JSON from BSON. /** Formatting mode for generating JSON from BSON.
See <http://mongodb.onconfluence.com/display/DOCS/Mongo+Extended+JS ON> See <http://mongodb.onconfluence.com/display/DOCS/Mongo+Extended+JS ON>
for details. for details.
*/ */
enum JsonStringFormat { enum JsonStringFormat {
/** strict RFC format */ /** strict RFC format */
Strict, Strict,
/** 10gen format, which is close to JS format. This form is unders tandable by /** 10gen format, which is close to JS format. This form is unders tandable by
javascript running inside the Mongo server via eval() */ javascript running inside the Mongo server via eval() */
TenGen, TenGen,
/** Javascript JSON compatible */ /** Javascript JSON compatible */
JS JS
}; };
ostream& operator<<( ostream &s, const OID &o ); std::ostream& operator<<( std::ostream &s, const OID &o );
} }
 End of changes. 5 change blocks. 
6 lines changed or deleted 6 lines changed or added


 oplog.h   oplog.h 
skipping to change at line 30 skipping to change at line 30
local.oplog.$main is the default local.oplog.$main is the default
*/ */
#pragma once #pragma once
#include "pdfile.h" #include "pdfile.h"
#include "db.h" #include "db.h"
#include "dbhelpers.h" #include "dbhelpers.h"
#include "clientcursor.h" #include "clientcursor.h"
#include "../client/dbclient.h"
#include "../util/optime.h" #include "../util/optime.h"
#include "../util/timer.h" #include "../util/timer.h"
namespace mongo { namespace mongo {
void createOplog(); void createOplog();
void _logOpObjRS(const BSONObj& op); void _logOpObjRS(const BSONObj& op);
/** Write operation to the log (local.oplog.$main) /** Write operation to the log (local.oplog.$main)
skipping to change at line 52 skipping to change at line 51
@param opstr @param opstr
"i" insert "i" insert
"u" update "u" update
"d" delete "d" delete
"c" db cmd "c" db cmd
"n" no-op "n" no-op
"db" declares presence of a database (ns is set to the db name + '. ') "db" declares presence of a database (ns is set to the db name + '. ')
See _logOp() in oplog.cpp for more details. See _logOp() in oplog.cpp for more details.
*/ */
void logOp(const char *opstr, const char *ns, const BSONObj& obj, BSONO bj *patt = 0, bool *b = 0); void logOp( const char *opstr, const char *ns, const BSONObj& obj, BSON Obj *patt = 0, bool *b = 0, bool fromMigrate = false );
void logKeepalive(); void logKeepalive();
/** puts obj in the oplog as a comment (a no-op). Just for diags. /** puts obj in the oplog as a comment (a no-op). Just for diags.
convention is convention is
{ msg : "text", ... } { msg : "text", ... }
*/ */
void logOpComment(const BSONObj& obj); void logOpComment(const BSONObj& obj);
void oplogCheckCloseDatabase( Database * db ); void oplogCheckCloseDatabase( Database * db );
skipping to change at line 82 skipping to change at line 81
/** /**
* The cursor will attempt to find the first op in the oplog matchi ng the * The cursor will attempt to find the first op in the oplog matchi ng the
* 'ts' field of the qp's query. * 'ts' field of the qp's query.
*/ */
FindingStartCursor( const QueryPlan & qp ); FindingStartCursor( const QueryPlan & qp );
/** @return true if the first matching op in the oplog has been fou nd. */ /** @return true if the first matching op in the oplog has been fou nd. */
bool done() const { return !_findingStart; } bool done() const { return !_findingStart; }
/** @return cursor pointing to the first matching op, if done(). */ /** @return cursor pointing to the first matching op, if done(). */
shared_ptr<Cursor> cursor() { verify( 14835, done() ); return _c; } shared_ptr<Cursor> cursor() { verify( done() ); return _c; }
/** Iterate the cursor, to continue trying to find matching op. */ /** Iterate the cursor, to continue trying to find matching op. */
void next(); void next();
/** Yield cursor, if not done(). */ /** Yield cursor, if not done(). */
bool prepareToYield() { bool prepareToYield() {
if ( _findingStartCursor ) { if ( _findingStartCursor ) {
return _findingStartCursor->prepareToYield( _yieldData ); return _findingStartCursor->prepareToYield( _yieldData );
} }
return false; return false;
skipping to change at line 104 skipping to change at line 103
/** Recover from cursor yield. */ /** Recover from cursor yield. */
void recoverFromYield() { void recoverFromYield() {
if ( _findingStartCursor ) { if ( _findingStartCursor ) {
if ( !ClientCursor::recoverFromYield( _yieldData ) ) { if ( !ClientCursor::recoverFromYield( _yieldData ) ) {
_findingStartCursor.reset( 0 ); _findingStartCursor.reset( 0 );
msgassertedNoTrace( 15889, "FindingStartCursor::recover FromYield() failed to recover" ); msgassertedNoTrace( 15889, "FindingStartCursor::recover FromYield() failed to recover" );
} }
} }
} }
/**
* @return a BasicCursor constructed using a FindingStartCursor wit
h the provided query and
* order parameters.
* @yields the db lock.
* @asserts on yield recovery failure.
*/
static shared_ptr<Cursor> getCursor( const char *ns, const BSONObj
&query, const BSONObj &order );
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::CleanupPointer _findingStartCursor; ClientCursor::CleanupPointer _findingStartCursor;
shared_ptr<Cursor> _c; shared_ptr<Cursor> _c;
ClientCursor::YieldData _yieldData; ClientCursor::YieldData _yieldData;
 End of changes. 4 change blocks. 
3 lines changed or deleted 13 lines changed or added


 oplogreader.h   oplogreader.h 
/** @file oplogreader.h */ /** @file oplogreader.h */
#pragma once #pragma once
#include "../client/dbclient.h"
#include "../client/constants.h" #include "../client/constants.h"
#include "dbhelpers.h" #include "dbhelpers.h"
#include "mongo/client/dbclientcursor.h"
namespace mongo { namespace mongo {
/* started abstracting out the querying of the primary/master's oplog /* started abstracting out the querying of the primary/master's oplog
still fairly awkward but a start. still fairly awkward but a start.
*/ */
class OplogReader { class OplogReader {
shared_ptr<DBClientConnection> _conn; shared_ptr<DBClientConnection> _conn;
shared_ptr<DBClientCursor> cursor; shared_ptr<DBClientCursor> cursor;
bool _doHandshake;
int _tailingQueryOptions;
public: public:
OplogReader() { } OplogReader( bool doHandshake = true );
~OplogReader() { } ~OplogReader() { }
void resetCursor() { cursor.reset(); } void resetCursor() { cursor.reset(); }
void resetConnection() { void resetConnection() {
cursor.reset(); cursor.reset();
_conn.reset(); _conn.reset();
} }
DBClientConnection* conn() { return _conn.get(); } DBClientConnection* conn() { return _conn.get(); }
BSONObj findOne(const char *ns, const Query& q) { BSONObj findOne(const char *ns, const Query& q) {
return conn()->findOne(ns, q, 0, QueryOption_SlaveOk); return conn()->findOne(ns, q, 0, QueryOption_SlaveOk);
} }
skipping to change at line 51 skipping to change at line 54
resetCursor(); resetCursor();
} }
} }
bool haveCursor() { return cursor.get() != 0; } bool haveCursor() { return cursor.get() != 0; }
/** this is ok but commented out as when used one should consider i f QueryOption_OplogReplay /** this is ok but commented out as when used one should consider i f QueryOption_OplogReplay
is needed; if not fine, but if so, need to change. is needed; if not fine, but if so, need to change.
*//* *//*
void query(const char *ns, const BSONObj& query) { void query(const char *ns, const BSONObj& query) {
assert( !haveCursor() ); verify( !haveCursor() );
cursor.reset( _conn->query(ns, query, 0, 0, 0, QueryOption_Slav eOk).release() ); cursor.reset( _conn->query(ns, query, 0, 0, 0, QueryOption_Slav eOk).release() );
}*/ }*/
/** this can be used; it is commented out as it does not indicate /** this can be used; it is commented out as it does not indicate
QueryOption_OplogReplay and that is likely important. could be uncommented QueryOption_OplogReplay and that is likely important. could be uncommented
just need to add that. just need to add that.
*/ */
/* /*
void queryGTE(const char *ns, OpTime t) { void queryGTE(const char *ns, OpTime t) {
BSONObjBuilder q; BSONObjBuilder q;
q.appendDate("$gte", t.asDate()); q.appendDate("$gte", t.asDate());
BSONObjBuilder q2; BSONObjBuilder q2;
q2.append("ts", q.done()); q2.append("ts", q.done());
query(ns, q2.done()); query(ns, q2.done());
} }
*/ */
void tailingQuery(const char *ns, const BSONObj& query, const BSONO void tailingQuery(const char *ns, const BSONObj& query, const BSONO
bj* fields=0) { bj* fields=0);
assert( !haveCursor() );
log(2) << "repl: " << ns << ".find(" << query.toString() << ')'
<< endl;
cursor.reset( _conn->query( ns, query, 0, 0, fields,
QueryOption_CursorTailable | QueryO
ption_SlaveOk | QueryOption_OplogReplay |
/* TODO: slaveOk maybe shouldn't us
e? */
QueryOption_AwaitData
).release() );
}
void tailingQueryGTE(const char *ns, OpTime t, const BSONObj* field void tailingQueryGTE(const char *ns, OpTime t, const BSONObj* field
s=0) { s=0);
BSONObjBuilder q;
q.appendDate("$gte", t.asDate());
BSONObjBuilder query;
query.append("ts", q.done());
tailingQuery(ns, query.done(), fields);
}
/* Do a tailing query, but only send the ts field back. */ /* Do a tailing query, but only send the ts field back. */
void ghostQueryGTE(const char *ns, OpTime t) { void ghostQueryGTE(const char *ns, OpTime t) {
const BSONObj fields = BSON("ts" << 1 << "_id" << 0); const BSONObj fields = BSON("ts" << 1 << "_id" << 0);
return tailingQueryGTE(ns, t, &fields); return tailingQueryGTE(ns, t, &fields);
} }
bool more() { bool more() {
uassert( 15910, "Doesn't have cursor for reading oplog", cursor .get() ); uassert( 15910, "Doesn't have cursor for reading oplog", cursor .get() );
return cursor->more(); return cursor->more();
skipping to change at line 108 skipping to change at line 97
bool moreInCurrentBatch() { bool moreInCurrentBatch() {
uassert( 15911, "Doesn't have cursor for reading oplog", cursor .get() ); uassert( 15911, "Doesn't have cursor for reading oplog", cursor .get() );
return cursor->moreInCurrentBatch(); return cursor->moreInCurrentBatch();
} }
/* old mongod's can't do the await flag... */ /* old mongod's can't do the await flag... */
bool awaitCapable() { bool awaitCapable() {
return cursor->hasResultFlag(ResultFlag_AwaitCapable); return cursor->hasResultFlag(ResultFlag_AwaitCapable);
} }
int getTailingQueryOptions() const { return _tailingQueryOptions; }
void setTailingQueryOptions( int tailingQueryOptions ) { _tailingQu
eryOptions = tailingQueryOptions; }
void peek(vector<BSONObj>& v, int n) { void peek(vector<BSONObj>& v, int n) {
if( cursor.get() ) if( cursor.get() )
cursor->peek(v,n); cursor->peek(v,n);
} }
BSONObj nextSafe() { return cursor->nextSafe(); } BSONObj nextSafe() { return cursor->nextSafe(); }
BSONObj next() { return cursor->next(); } BSONObj next() { return cursor->next(); }
void putBack(BSONObj op) { cursor->putBack(op); } void putBack(BSONObj op) { cursor->putBack(op); }
private: private:
/** @return true iff connection was successful */
bool commonConnect(const string& hostName); bool commonConnect(const string& hostName);
bool passthroughHandshake(const BSONObj& rid, const int f); bool passthroughHandshake(const BSONObj& rid, const int f);
}; };
} }
 End of changes. 10 change blocks. 
24 lines changed or deleted 15 lines changed or added


 optime.h   optime.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 "../db/concurrency.h" #include <boost/thread/condition.hpp>
namespace mongo { namespace mongo {
void exitCleanly( ExitCode code );
struct ClockSkewException : public DBException { struct ClockSkewException : public DBException {
ClockSkewException() : DBException( "clock skew exception" , 20001 ) {} ClockSkewException() : DBException( "clock skew exception" , 20001 ) {}
}; };
/* replsets used to use RSOpTime. /* replsets used to use RSOpTime.
M/S uses OpTime. M/S uses OpTime.
But this is useable from both. But this is useable from both.
*/ */
typedef unsigned long long ReplTime; typedef unsigned long long ReplTime;
skipping to change at line 45 skipping to change at line 44
/* Operation sequence #. A combination of current second plus an ordin al value. /* Operation sequence #. A combination of current second plus an ordin al value.
*/ */
#pragma pack(4) #pragma pack(4)
class OpTime { class OpTime {
unsigned i; // ordinal comes first so we can do a single 64 bit com pare on little endian unsigned i; // ordinal comes first so we can do a single 64 bit com pare on little endian
unsigned secs; unsigned secs;
static OpTime last; static OpTime last;
static OpTime skewed(); static OpTime skewed();
public: public:
static void setLast(const Date_t &date) { static void setLast(const Date_t &date) {
notifier().notify_all(); // won't really do anything until writ mutex::scoped_lock lk(m);
e-lock released notifier.notify_all(); // won't really do anything until write-
lock released
last = OpTime(date); last = OpTime(date);
} }
unsigned getSecs() const { unsigned getSecs() const {
return secs; return secs;
} }
unsigned getInc() const { unsigned getInc() const {
return i; return i;
} }
OpTime(Date_t date) { OpTime(Date_t date) {
reinterpret_cast<unsigned long long&>(*this) = date.millis; reinterpret_cast<unsigned long long&>(*this) = date.millis;
skipping to change at line 78 skipping to change at line 77
OpTime( const OpTime& other ) { OpTime( const OpTime& other ) {
secs = other.secs; secs = other.secs;
i = other.i; i = other.i;
dassert( (int)secs >= 0 ); dassert( (int)secs >= 0 );
} }
OpTime() { OpTime() {
secs = 0; secs = 0;
i = 0; i = 0;
} }
// it isn't generally safe to not be locked for this. so use now(). some tests use this. // it isn't generally safe to not be locked for this. so use now(). some tests use this.
static OpTime now_inlock() { static OpTime _now();
notifier().notify_all(); // won't really do anything until writ
e-lock released
unsigned t = (unsigned) time(0); static mongo::mutex m;
if ( last.secs == t ) {
last.i++; static OpTime now(const mongo::mutex::scoped_lock&);
return last;
} static OpTime getLast(const mongo::mutex::scoped_lock&);
if ( t < last.secs ) {
return skewed(); // separate function to keep out of the ho
t code path
}
last = OpTime(t, 1);
return last;
}
static OpTime now();
static OpTime last_inlock();
// Waits for global OpTime to be different from *this // Waits for global OpTime to be different from *this
// Must be atLeastReadLocked
// Defined in instance.cpp (only current user) as it needs dbtempre
lease
void waitForDifferent(unsigned millis); void waitForDifferent(unsigned millis);
/* We store OpTime's in the database as BSON Date datatype -- we ne eded some sort of /* We store OpTime's in the database as BSON Date datatype -- we ne eded some sort of
64 bit "container" for these values. While these are not really " Dates", that seems a 64 bit "container" for these values. While these are not really " Dates", that seems a
better choice for now than say, Number, which is floating point. Note the BinData type better choice for now than say, Number, which is floating point. Note the BinData type
is perhaps the cleanest choice, lacking a true unsigned64 datatype , but BinData has 5 is perhaps the cleanest choice, lacking a true unsigned64 datatype , but BinData has 5
bytes of overhead. bytes of overhead.
*/ */
unsigned long long asDate() const { unsigned long long asDate() const {
return reinterpret_cast<const unsigned long long*>(&i)[0]; return reinterpret_cast<const unsigned long long*>(&i)[0];
skipping to change at line 157 skipping to change at line 145
bool operator<=(const OpTime& r) const { bool operator<=(const OpTime& r) const {
return *this < r || *this == r; return *this < r || *this == r;
} }
bool operator>(const OpTime& r) const { bool operator>(const OpTime& r) const {
return !(*this <= r); return !(*this <= r);
} }
bool operator>=(const OpTime& r) const { bool operator>=(const OpTime& r) const {
return !(*this < r); return !(*this < r);
} }
private: private:
static boost::condition notifier;
// The following functions are to get around the need to define cla
ss-level statics in a cpp
static boost::condition& notifier() {
static boost::condition* holder = new boost::condition();
return *holder;
};
static boost::mutex& notifyMutex() {
static boost::mutex* holder = new boost::mutex();
return *holder;
};
}; };
#pragma pack() #pragma pack()
} // namespace mongo } // namespace mongo
 End of changes. 7 change blocks. 
36 lines changed or deleted 11 lines changed or added


 ordering.h   ordering.h 
skipping to change at line 49 skipping to change at line 49
get(0) == 1 get(0) == 1
get(1) == -1 get(1) == -1
*/ */
int get(int i) const { int get(int i) const {
return ((1 << i) & bits) ? -1 : 1; return ((1 << i) & bits) ? -1 : 1;
} }
// for woCompare... // for woCompare...
unsigned descending(unsigned mask) const { return bits & mask; } unsigned descending(unsigned mask) const { return bits & mask; }
/*operator string() const { /*operator std::string() const {
StringBuilder buf; StringBuilder buf;
for ( unsigned i=0; i<nkeys; i++) for ( unsigned i=0; i<nkeys; i++)
buf.append( get(i) > 0 ? "+" : "-" ); buf.append( get(i) > 0 ? "+" : "-" );
return buf.str(); return buf.str();
}*/ }*/
static Ordering make(const BSONObj& obj) { static Ordering make(const BSONObj& obj) {
unsigned b = 0; unsigned b = 0;
BSONObjIterator k(obj); BSONObjIterator k(obj);
unsigned n = 0; unsigned n = 0;
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 pagefault.h   pagefault.h 
// @file pagefault.h // @file pagefault.h
// define this : _PAGEFAULTEXCEPTION
#pragma once #pragma once
namespace mongo { namespace mongo {
class Record; class Record;
class PageFaultException /*: public DBException*/ { class PageFaultException /*: public DBException*/ {
unsigned era; unsigned era;
Record *r; const Record *r;
public: public:
PageFaultException(const PageFaultException& rhs) : era(rhs.era), r (rhs.r) { } PageFaultException(const PageFaultException& rhs) : era(rhs.era), r (rhs.r) { }
explicit PageFaultException(Record*); explicit PageFaultException(const Record*);
void touch(); void touch();
}; };
class PageFaultRetryableSection : boost::noncopyable { class PageFaultRetryableSection : boost::noncopyable {
unsigned _laps; unsigned _laps;
public: public:
unsigned laps() const { return _laps; } unsigned laps() const { return _laps; }
void didLap() { _laps++; } void didLap() { _laps++; }
PageFaultRetryableSection(); PageFaultRetryableSection();
~PageFaultRetryableSection(); ~PageFaultRetryableSection();
 End of changes. 3 change blocks. 
4 lines changed or deleted 2 lines changed or added


 parallel.h   parallel.h 
skipping to change at line 24 skipping to change at line 24
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/** /**
tools for working in parallel/sharded/clustered environment tools for working in parallel/sharded/clustered environment
*/ */
#pragma once #pragma once
#include "../pch.h" #include "mongo/db/dbmessage.h"
#include "dbclient.h" #include "mongo/db/matcher.h"
#include "redef_macros.h" #include "mongo/db/namespacestring.h"
#include "../db/dbmessage.h" #include "mongo/s/util.h"
#include "../db/matcher.h" #include "mongo/util/concurrency/mvar.h"
#include "../util/concurrency/mvar.h"
namespace mongo { namespace mongo {
/** /**
* 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() ) {
skipping to change at line 373 skipping to change at line 372
virtual void explain(BSONObjBuilder& b); virtual void explain(BSONObjBuilder& b);
protected: protected:
void _finishCons(); void _finishCons();
void _init(); void _init();
void _oldInit(); void _oldInit();
virtual void _explain( map< string,list<BSONObj> >& out ); virtual void _explain( map< string,list<BSONObj> >& out );
void _markStaleNS( const NamespaceString& staleNS, bool& forceReloa d, bool& fullReload ); void _markStaleNS( const NamespaceString& staleNS, const StaleConfi gException& e, bool& forceReload, bool& fullReload );
void _handleStaleNS( const NamespaceString& staleNS, bool forceRelo ad, bool fullReload ); void _handleStaleNS( const NamespaceString& staleNS, bool forceRelo ad, bool fullReload );
set<Shard> _qShards; set<Shard> _qShards;
QuerySpec _qSpec; QuerySpec _qSpec;
CommandInfo _cInfo; CommandInfo _cInfo;
// Count round-trips req'd for namespaces and total // Count round-trips req'd for namespaces and total
map<string,int> _staleNSMap; map<string,int> _staleNSMap;
int _totalTries; int _totalTries;
skipping to change at line 410 skipping to change at line 409
class Future { class Future {
public: public:
class CommandResult { class CommandResult {
public: public:
string getServer() const { return _server; } string getServer() const { return _server; }
bool isDone() const { return _done; } bool isDone() const { return _done; }
bool ok() const { bool ok() const {
assert( _done ); verify( _done );
return _ok; return _ok;
} }
BSONObj result() const { BSONObj result() const {
assert( _done ); verify( _done );
return _res; return _res;
} }
/** /**
blocks until command is done blocks until command is done
returns ok() returns ok()
*/ */
bool join( int maxRetries = 1 ); bool join( int maxRetries = 1 );
private: private:
skipping to change at line 456 skipping to change at line 455
/** /**
* @param server server name * @param server server name
* @param db db name * @param db db name
* @param cmd cmd to exec * @param cmd cmd to exec
* @param conn optional connection to use. will use standard poole d if non-specified * @param conn optional connection to use. will use standard poole d if non-specified
*/ */
static shared_ptr<CommandResult> spawnCommand( const string& server , const string& db , const BSONObj& cmd , int options , DBClientBase * con n = 0 ); static shared_ptr<CommandResult> spawnCommand( const string& server , const string& db , const BSONObj& cmd , int options , DBClientBase * con n = 0 );
}; };
} }
#include "undef_macros.h"
 End of changes. 5 change blocks. 
9 lines changed or deleted 8 lines changed or added


 pch.h   pch.h 
skipping to change at line 24 skipping to change at line 24
* 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.
*/ */
#ifndef MONGO_PCH_H #ifndef MONGO_PCH_H
#define MONGO_PCH_H #define MONGO_PCH_H
#if defined(MONGO_EXPOSE_MACROS) // our #define macros must not be active when we include
// this is defined in server.h for non-MONGO_EXPOSE_MACROS // system headers and boost headers
# define BOOST_ENABLE_ASSERT_HANDLER 1 #include "mongo/client/undef_macros.h"
# define JS_C_STRINGS_ARE_UTF8 #include "mongo/platform/basic.h"
# undef SUPPORT_UCP
# define SUPPORT_UCP
# undef SUPPORT_UTF8
# define SUPPORT_UTF8
# undef _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS
#endif
#if defined(_WIN32)
// for rand_s() usage:
# define _CRT_RAND_S
# ifndef NOMINMAX
# define NOMINMAX
# endif
#define WIN32_LEAN_AND_MEAN
# include <winsock2.h> //this must be included before the first windows.h i
nclude
# include <ws2tcpip.h>
# include <wspiapi.h>
# include <windows.h>
#endif
#if defined(__linux__) && defined(MONGO_EXPOSE_MACROS)
// glibc's optimized versions are better than g++ builtins
# define __builtin_strcmp strcmp
# define __builtin_strlen strlen
# define __builtin_memchr memchr
# define __builtin_memcmp memcmp
# define __builtin_memcpy memcpy
# define __builtin_memset memset
# define __builtin_memmove memmove
#endif
#include <ctime> #include <ctime>
#include <cstring> #include <cstring>
#include <string> #include <string>
#include <memory> #include <memory>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <vector> #include <vector>
#include <set> #include <set>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <signal.h> #include <signal.h>
#include "targetver.h"
#include "time.h" #include "time.h"
#include "string.h" #include "string.h"
#include "limits.h" #include "limits.h"
#define BOOST_FILESYSTEM_VERSION 2 #define BOOST_FILESYSTEM_VERSION 2
#include <boost/lexical_cast.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/smart_ptr.hpp> #include <boost/smart_ptr.hpp>
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/thread/tss.hpp>
#include <boost/detail/endian.hpp>
#include <boost/version.hpp> #include <boost/version.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/condition.hpp> #include "mongo/client/redef_macros.h"
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/xtime.hpp> #include "mongo/util/exit_code.h"
#undef assert
#define assert MONGO_assert
namespace mongo { namespace mongo {
using namespace std; using namespace std;
using boost::shared_ptr; using boost::shared_ptr;
#if defined(_DEBUG) void dbexit( ExitCode returnCode, const char *whyMsg = "" );
const bool debug=true;
#else
const bool debug=false;
#endif
// pdfile versions
const int PDFILE_VERSION = 4;
const int PDFILE_VERSION_MINOR = 5;
enum ExitCode {
EXIT_CLEAN = 0 ,
EXIT_BADOPTIONS = 2 ,
EXIT_REPLICATION_ERROR = 3 ,
EXIT_NEED_UPGRADE = 4 ,
EXIT_SHARDING_ERROR = 5 ,
EXIT_KILL = 12 ,
EXIT_ABRUPT = 14 ,
EXIT_NTSERVICE_ERROR = 20 ,
EXIT_JAVA = 21 ,
EXIT_OOM_MALLOC = 42 ,
EXIT_OOM_REALLOC = 43 ,
EXIT_FS = 45 ,
EXIT_CLOCK_SKEW = 47 ,
EXIT_NET_ERROR = 48 ,
EXIT_WINDOWS_SERVICE_STOP = 49 ,
EXIT_POSSIBLE_CORRUPTION = 60 , // this means we detected a possibl
e corruption situation, like a buf overflow
EXIT_UNCAUGHT = 100 , // top level exception that wasn't caught
EXIT_TEST = 101
};
void dbexit( ExitCode returnCode, const char *whyMsg = "", bool tryToGe
tLock = false);
/** /**
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 quit you should either use dbexit to shutdown cleanly, or ::exit to tell the system to quit
if you use this, you'll get a link error since mongo::exit isn't def ined if you use this, you'll get a link error since mongo::exit isn't def ined
*/ */
void exit( ExitCode returnCode ); void exit( ExitCode returnCode );
bool inShutdown(); bool inShutdown();
void asserted(const char *msg, const char *file, unsigned line);
} }
// TODO: Rework the headers so we don't need this craziness #include "mongo/util/assert_util.h"
#include "bson/inline_decls.h" #include "mongo/util/debug_util.h"
#define MONGO_assert(_Expression) (void)( MONGO_likely(!!(_Expression)) || #include "mongo/util/goodies.h"
(mongo::asserted(#_Expression, __FILE__, __LINE__), 0) ) #include "mongo/util/allocator.h"
#include "mongo/util/log.h"
#include "util/debug_util.h"
#include "util/goodies.h"
#include "util/log.h"
#include "util/allocator.h"
#include "util/assert_util.h"
namespace mongo {
void sayDbContext(const char *msg = 0);
void rawOut( const string &s );
typedef char _TCHAR;
using boost::uint32_t;
using boost::uint64_t;
/** called by mongos, mongod, test. do not call from clients and such.
invoked before about everything except global var construction.
*/
void doPreServerStartupInits();
} // namespace mongo
#endif // MONGO_PCH_H #endif // MONGO_PCH_H
 End of changes. 8 change blocks. 
109 lines changed or deleted 16 lines changed or added


 pcre.h   pcre.h 
/************************************************* /*************************************************
* Perl-Compatible Regular Expressions * * Perl-Compatible Regular Expressions *
*************************************************/ *************************************************/
/* This is the public header file for the PCRE library, to be #included by /* This is the public header file for the PCRE library, to be #included by
applications that call the PCRE functions. applications that call the PCRE functions.
Copyright (c) 1997-2007 University of Cambridge Copyright (c) 1997-2012 University of Cambridge
--------------------------------------------------------------------------- -- --------------------------------------------------------------------------- --
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice , * Redistributions of source code must retain the above copyright notice ,
this list of conditions and the following disclaimer. this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright * Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the notice, this list of conditions and the following disclaimer in the
skipping to change at line 44 skipping to change at line 44
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- -- --------------------------------------------------------------------------- --
*/ */
#ifndef _PCRE_H #ifndef _PCRE_H
#define _PCRE_H #define _PCRE_H
/* The current PCRE version information. */ /* The current PCRE version information. */
#define PCRE_MAJOR 7 #define PCRE_MAJOR 8
#define PCRE_MINOR 4 #define PCRE_MINOR 30
#define PCRE_PRERELEASE #define PCRE_PRERELEASE
#define PCRE_DATE 2007-09-21 #define PCRE_DATE 2012-02-04
/* When an application links to a PCRE DLL in Windows, the symbols that are /* When an application links to a PCRE DLL in Windows, the symbols that are
imported have to be identified as such. When building PCRE, the appropriate imported have to be identified as such. When building PCRE, the appropriate
export setting is defined in pcre_internal.h, which includes this file. So we export setting is defined in pcre_internal.h, which includes this file. So we
don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL. */ don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL. */
/*#if defined(_WIN32) && !defined(PCRE_STATIC) #if defined(_WIN32) && !defined(PCRE_STATIC)
#error why are we here?
# ifndef PCRE_EXP_DECL # ifndef PCRE_EXP_DECL
# define PCRE_EXP_DECL extern __declspec(dllimport) # define PCRE_EXP_DECL extern
# endif # endif
# ifdef __cplusplus # ifdef __cplusplus
# ifndef PCRECPP_EXP_DECL # ifndef PCRECPP_EXP_DECL
# define PCRECPP_EXP_DECL extern __declspec(dllimport) # define PCRECPP_EXP_DECL extern
# endif # endif
# ifndef PCRECPP_EXP_DEFN # ifndef PCRECPP_EXP_DEFN
# define PCRECPP_EXP_DEFN __declspec(dllimport) # define PCRECPP_EXP_DEFN
# endif # endif
# endif # endif
#endif*/ #endif
/* By default, we use the standard "extern" declarations. */ /* By default, we use the standard "extern" declarations. */
#ifndef PCRE_EXP_DECL #ifndef PCRE_EXP_DECL
# ifdef __cplusplus # ifdef __cplusplus
# define PCRE_EXP_DECL extern "C" # define PCRE_EXP_DECL extern "C"
# else # else
# define PCRE_EXP_DECL extern # define PCRE_EXP_DECL extern
# endif # endif
#endif #endif
skipping to change at line 99 skipping to change at line 98
it is needed here for malloc. */ it is needed here for malloc. */
#include <stdlib.h> #include <stdlib.h>
/* Allow for C++ users */ /* Allow for C++ users */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* Options */ /* Options. Some are compile-time only, some are run-time only, and some ar
e
#define PCRE_CASELESS 0x00000001 both, so we keep them all distinct. However, almost all the bits in the opt
#define PCRE_MULTILINE 0x00000002 ions
#define PCRE_DOTALL 0x00000004 word are now used. In the long run, we may have to re-use some of the
#define PCRE_EXTENDED 0x00000008 compile-time only bits for runtime options, or vice versa. In the comments
#define PCRE_ANCHORED 0x00000010 below, "compile", "exec", and "DFA exec" mean that the option is permitted
#define PCRE_DOLLAR_ENDONLY 0x00000020 to
#define PCRE_EXTRA 0x00000040 be set for those functions; "used in" means that an option may be set only
#define PCRE_NOTBOL 0x00000080 for
#define PCRE_NOTEOL 0x00000100 compile, but is subsequently referenced in exec and/or DFA exec. Any of the
#define PCRE_UNGREEDY 0x00000200 compile-time options may be inspected during studying (and therefore JIT
#define PCRE_NOTEMPTY 0x00000400 compiling). */
#define PCRE_UTF8 0x00000800
#define PCRE_NO_AUTO_CAPTURE 0x00001000 #define PCRE_CASELESS 0x00000001 /* Compile */
#define PCRE_NO_UTF8_CHECK 0x00002000 #define PCRE_MULTILINE 0x00000002 /* Compile */
#define PCRE_AUTO_CALLOUT 0x00004000 #define PCRE_DOTALL 0x00000004 /* Compile */
#define PCRE_PARTIAL 0x00008000 #define PCRE_EXTENDED 0x00000008 /* Compile */
#define PCRE_DFA_SHORTEST 0x00010000 #define PCRE_ANCHORED 0x00000010 /* Compile, exec, DFA exec */
#define PCRE_DFA_RESTART 0x00020000 #define PCRE_DOLLAR_ENDONLY 0x00000020 /* Compile, used in exec, DFA e
#define PCRE_FIRSTLINE 0x00040000 xec */
#define PCRE_DUPNAMES 0x00080000 #define PCRE_EXTRA 0x00000040 /* Compile */
#define PCRE_NEWLINE_CR 0x00100000 #define PCRE_NOTBOL 0x00000080 /* Exec, DFA exec */
#define PCRE_NEWLINE_LF 0x00200000 #define PCRE_NOTEOL 0x00000100 /* Exec, DFA exec */
#define PCRE_NEWLINE_CRLF 0x00300000 #define PCRE_UNGREEDY 0x00000200 /* Compile */
#define PCRE_NEWLINE_ANY 0x00400000 #define PCRE_NOTEMPTY 0x00000400 /* Exec, DFA exec */
#define PCRE_NEWLINE_ANYCRLF 0x00500000 /* The next two are also used in exec and DFA exec */
#define PCRE_BSR_ANYCRLF 0x00800000 #define PCRE_UTF8 0x00000800 /* Compile (same as PCRE_UTF16)
#define PCRE_BSR_UNICODE 0x01000000 */
#define PCRE_UTF16 0x00000800 /* Compile (same as PCRE_UTF8)
*/
#define PCRE_NO_AUTO_CAPTURE 0x00001000 /* Compile */
/* The next two are also used in exec and DFA exec */
#define PCRE_NO_UTF8_CHECK 0x00002000 /* Compile (same as PCRE_NO_UTF
16_CHECK) */
#define PCRE_NO_UTF16_CHECK 0x00002000 /* Compile (same as PCRE_NO_UTF
8_CHECK) */
#define PCRE_AUTO_CALLOUT 0x00004000 /* Compile */
#define PCRE_PARTIAL_SOFT 0x00008000 /* Exec, DFA exec */
#define PCRE_PARTIAL 0x00008000 /* Backwards compatible synonym
*/
#define PCRE_DFA_SHORTEST 0x00010000 /* DFA exec */
#define PCRE_DFA_RESTART 0x00020000 /* DFA exec */
#define PCRE_FIRSTLINE 0x00040000 /* Compile, used in exec, DFA e
xec */
#define PCRE_DUPNAMES 0x00080000 /* Compile */
#define PCRE_NEWLINE_CR 0x00100000 /* Compile, exec, DFA exec */
#define PCRE_NEWLINE_LF 0x00200000 /* Compile, exec, DFA exec */
#define PCRE_NEWLINE_CRLF 0x00300000 /* Compile, exec, DFA exec */
#define PCRE_NEWLINE_ANY 0x00400000 /* Compile, exec, DFA exec */
#define PCRE_NEWLINE_ANYCRLF 0x00500000 /* Compile, exec, DFA exec */
#define PCRE_BSR_ANYCRLF 0x00800000 /* Compile, exec, DFA exec */
#define PCRE_BSR_UNICODE 0x01000000 /* Compile, exec, DFA exec */
#define PCRE_JAVASCRIPT_COMPAT 0x02000000 /* Compile, used in exec */
#define PCRE_NO_START_OPTIMIZE 0x04000000 /* Compile, exec, DFA exec */
#define PCRE_NO_START_OPTIMISE 0x04000000 /* Synonym */
#define PCRE_PARTIAL_HARD 0x08000000 /* Exec, DFA exec */
#define PCRE_NOTEMPTY_ATSTART 0x10000000 /* Exec, DFA exec */
#define PCRE_UCP 0x20000000 /* Compile, used in exec, DFA e
xec */
/* Exec-time and get/set-time error codes */ /* Exec-time and get/set-time error codes */
#define PCRE_ERROR_NOMATCH (-1) #define PCRE_ERROR_NOMATCH (-1)
#define PCRE_ERROR_NULL (-2) #define PCRE_ERROR_NULL (-2)
#define PCRE_ERROR_BADOPTION (-3) #define PCRE_ERROR_BADOPTION (-3)
#define PCRE_ERROR_BADMAGIC (-4) #define PCRE_ERROR_BADMAGIC (-4)
#define PCRE_ERROR_UNKNOWN_OPCODE (-5) #define PCRE_ERROR_UNKNOWN_OPCODE (-5)
#define PCRE_ERROR_UNKNOWN_NODE (-5) /* For backward compatibility */ #define PCRE_ERROR_UNKNOWN_NODE (-5) /* For backward compatibility */
#define PCRE_ERROR_NOMEMORY (-6) #define PCRE_ERROR_NOMEMORY (-6)
#define PCRE_ERROR_NOSUBSTRING (-7) #define PCRE_ERROR_NOSUBSTRING (-7)
#define PCRE_ERROR_MATCHLIMIT (-8) #define PCRE_ERROR_MATCHLIMIT (-8)
#define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */ #define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */
#define PCRE_ERROR_BADUTF8 (-10) #define PCRE_ERROR_BADUTF8 (-10) /* Same for 8/16 */
#define PCRE_ERROR_BADUTF8_OFFSET (-11) #define PCRE_ERROR_BADUTF16 (-10) /* Same for 8/16 */
#define PCRE_ERROR_PARTIAL (-12) #define PCRE_ERROR_BADUTF8_OFFSET (-11) /* Same for 8/16 */
#define PCRE_ERROR_BADPARTIAL (-13) #define PCRE_ERROR_BADUTF16_OFFSET (-11) /* Same for 8/16 */
#define PCRE_ERROR_INTERNAL (-14) #define PCRE_ERROR_PARTIAL (-12)
#define PCRE_ERROR_BADCOUNT (-15) #define PCRE_ERROR_BADPARTIAL (-13)
#define PCRE_ERROR_DFA_UITEM (-16) #define PCRE_ERROR_INTERNAL (-14)
#define PCRE_ERROR_DFA_UCOND (-17) #define PCRE_ERROR_BADCOUNT (-15)
#define PCRE_ERROR_DFA_UMLIMIT (-18) #define PCRE_ERROR_DFA_UITEM (-16)
#define PCRE_ERROR_DFA_WSSIZE (-19) #define PCRE_ERROR_DFA_UCOND (-17)
#define PCRE_ERROR_DFA_RECURSE (-20) #define PCRE_ERROR_DFA_UMLIMIT (-18)
#define PCRE_ERROR_RECURSIONLIMIT (-21) #define PCRE_ERROR_DFA_WSSIZE (-19)
#define PCRE_ERROR_NULLWSLIMIT (-22) /* No longer actually used */ #define PCRE_ERROR_DFA_RECURSE (-20)
#define PCRE_ERROR_BADNEWLINE (-23) #define PCRE_ERROR_RECURSIONLIMIT (-21)
#define PCRE_ERROR_NULLWSLIMIT (-22) /* No longer actually used */
#define PCRE_ERROR_BADNEWLINE (-23)
#define PCRE_ERROR_BADOFFSET (-24)
#define PCRE_ERROR_SHORTUTF8 (-25)
#define PCRE_ERROR_SHORTUTF16 (-25) /* Same for 8/16 */
#define PCRE_ERROR_RECURSELOOP (-26)
#define PCRE_ERROR_JIT_STACKLIMIT (-27)
#define PCRE_ERROR_BADMODE (-28)
#define PCRE_ERROR_BADENDIANNESS (-29)
/* Specific error codes for UTF-8 validity checks */
#define PCRE_UTF8_ERR0 0
#define PCRE_UTF8_ERR1 1
#define PCRE_UTF8_ERR2 2
#define PCRE_UTF8_ERR3 3
#define PCRE_UTF8_ERR4 4
#define PCRE_UTF8_ERR5 5
#define PCRE_UTF8_ERR6 6
#define PCRE_UTF8_ERR7 7
#define PCRE_UTF8_ERR8 8
#define PCRE_UTF8_ERR9 9
#define PCRE_UTF8_ERR10 10
#define PCRE_UTF8_ERR11 11
#define PCRE_UTF8_ERR12 12
#define PCRE_UTF8_ERR13 13
#define PCRE_UTF8_ERR14 14
#define PCRE_UTF8_ERR15 15
#define PCRE_UTF8_ERR16 16
#define PCRE_UTF8_ERR17 17
#define PCRE_UTF8_ERR18 18
#define PCRE_UTF8_ERR19 19
#define PCRE_UTF8_ERR20 20
#define PCRE_UTF8_ERR21 21
/* Specific error codes for UTF-16 validity checks */
#define PCRE_UTF16_ERR0 0
#define PCRE_UTF16_ERR1 1
#define PCRE_UTF16_ERR2 2
#define PCRE_UTF16_ERR3 3
#define PCRE_UTF16_ERR4 4
/* Request types for pcre_fullinfo() */ /* Request types for pcre_fullinfo() */
#define PCRE_INFO_OPTIONS 0 #define PCRE_INFO_OPTIONS 0
#define PCRE_INFO_SIZE 1 #define PCRE_INFO_SIZE 1
#define PCRE_INFO_CAPTURECOUNT 2 #define PCRE_INFO_CAPTURECOUNT 2
#define PCRE_INFO_BACKREFMAX 3 #define PCRE_INFO_BACKREFMAX 3
#define PCRE_INFO_FIRSTBYTE 4 #define PCRE_INFO_FIRSTBYTE 4
#define PCRE_INFO_FIRSTCHAR 4 /* For backwards compatibility */ #define PCRE_INFO_FIRSTCHAR 4 /* For backwards compatibility */
#define PCRE_INFO_FIRSTTABLE 5 #define PCRE_INFO_FIRSTTABLE 5
#define PCRE_INFO_LASTLITERAL 6 #define PCRE_INFO_LASTLITERAL 6
#define PCRE_INFO_NAMEENTRYSIZE 7 #define PCRE_INFO_NAMEENTRYSIZE 7
#define PCRE_INFO_NAMECOUNT 8 #define PCRE_INFO_NAMECOUNT 8
#define PCRE_INFO_NAMETABLE 9 #define PCRE_INFO_NAMETABLE 9
#define PCRE_INFO_STUDYSIZE 10 #define PCRE_INFO_STUDYSIZE 10
#define PCRE_INFO_DEFAULT_TABLES 11 #define PCRE_INFO_DEFAULT_TABLES 11
#define PCRE_INFO_OKPARTIAL 12 #define PCRE_INFO_OKPARTIAL 12
#define PCRE_INFO_JCHANGED 13 #define PCRE_INFO_JCHANGED 13
#define PCRE_INFO_HASCRORLF 14 #define PCRE_INFO_HASCRORLF 14
#define PCRE_INFO_MINLENGTH 15
#define PCRE_INFO_JIT 16
#define PCRE_INFO_JITSIZE 17
/* Request types for pcre_config(). Do not re-arrange, in order to remain /* Request types for pcre_config(). Do not re-arrange, in order to remain
compatible. */ compatible. */
#define PCRE_CONFIG_UTF8 0 #define PCRE_CONFIG_UTF8 0
#define PCRE_CONFIG_NEWLINE 1 #define PCRE_CONFIG_NEWLINE 1
#define PCRE_CONFIG_LINK_SIZE 2 #define PCRE_CONFIG_LINK_SIZE 2
#define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD 3 #define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD 3
#define PCRE_CONFIG_MATCH_LIMIT 4 #define PCRE_CONFIG_MATCH_LIMIT 4
#define PCRE_CONFIG_STACKRECURSE 5 #define PCRE_CONFIG_STACKRECURSE 5
#define PCRE_CONFIG_UNICODE_PROPERTIES 6 #define PCRE_CONFIG_UNICODE_PROPERTIES 6
#define PCRE_CONFIG_MATCH_LIMIT_RECURSION 7 #define PCRE_CONFIG_MATCH_LIMIT_RECURSION 7
#define PCRE_CONFIG_BSR 8 #define PCRE_CONFIG_BSR 8
#define PCRE_CONFIG_JIT 9
#define PCRE_CONFIG_UTF16 10
#define PCRE_CONFIG_JITTARGET 11
/* Bit flags for the pcre_extra structure. Do not re-arrange or redefine /* Request types for pcre_study(). Do not re-arrange, in order to remain
compatible. */
#define PCRE_STUDY_JIT_COMPILE 0x0001
/* Bit flags for the pcre[16]_extra structure. Do not re-arrange or redefin
e
these bits, just add new ones on the end, in order to remain compatible. */ these bits, just add new ones on the end, in order to remain compatible. */
#define PCRE_EXTRA_STUDY_DATA 0x0001 #define PCRE_EXTRA_STUDY_DATA 0x0001
#define PCRE_EXTRA_MATCH_LIMIT 0x0002 #define PCRE_EXTRA_MATCH_LIMIT 0x0002
#define PCRE_EXTRA_CALLOUT_DATA 0x0004 #define PCRE_EXTRA_CALLOUT_DATA 0x0004
#define PCRE_EXTRA_TABLES 0x0008 #define PCRE_EXTRA_TABLES 0x0008
#define PCRE_EXTRA_MATCH_LIMIT_RECURSION 0x0010 #define PCRE_EXTRA_MATCH_LIMIT_RECURSION 0x0010
#define PCRE_EXTRA_MARK 0x0020
#define PCRE_EXTRA_EXECUTABLE_JIT 0x0040
/* Types */ /* Types */
struct real_pcre; /* declaration; the definition is private */ struct real_pcre; /* declaration; the definition is private */
typedef struct real_pcre pcre; typedef struct real_pcre pcre;
struct real_pcre16; /* declaration; the definition is private
*/
typedef struct real_pcre16 pcre16;
struct real_pcre_jit_stack; /* declaration; the definition is private
*/
typedef struct real_pcre_jit_stack pcre_jit_stack;
struct real_pcre16_jit_stack; /* declaration; the definition is private
*/
typedef struct real_pcre16_jit_stack pcre16_jit_stack;
/* If PCRE is compiled with 16 bit character support, PCRE_UCHAR16 must con
tain
a 16 bit wide signed data type. Otherwise it can be a dummy data type since
pcre16 functions are not implemented. There is a check for this in pcre_int
ernal.h. */
#ifndef PCRE_UCHAR16
#define PCRE_UCHAR16 unsigned short
#endif
#ifndef PCRE_SPTR16
#define PCRE_SPTR16 const PCRE_UCHAR16 *
#endif
/* When PCRE is compiled as a C++ library, the subject pointer type can be /* When PCRE is compiled as a C++ library, the subject pointer type can be
replaced with a custom type. For conventional use, the public interface is a replaced with a custom type. For conventional use, the public interface is a
const char *. */ const char *. */
#ifndef PCRE_SPTR #ifndef PCRE_SPTR
#define PCRE_SPTR const char * #define PCRE_SPTR const char *
#endif #endif
/* The structure for passing additional data to pcre_exec(). This is define d in /* The structure for passing additional data to pcre_exec(). This is define d in
such as way as to be extensible. Always add new fields at the end, in order to such as way as to be extensible. Always add new fields at the end, in order to
remain compatible. */ remain compatible. */
typedef struct pcre_extra { typedef struct pcre_extra {
unsigned long int flags; /* Bits for which fields are set */ unsigned long int flags; /* Bits for which fields are set */
void *study_data; /* Opaque data from pcre_study() */ void *study_data; /* Opaque data from pcre_study() */
unsigned long int match_limit; /* Maximum number of calls to match() */ unsigned long int match_limit; /* Maximum number of calls to match() */
void *callout_data; /* Data passed back in callouts */ void *callout_data; /* Data passed back in callouts */
const unsigned char *tables; /* Pointer to character tables */ const unsigned char *tables; /* Pointer to character tables */
unsigned long int match_limit_recursion; /* Max recursive calls to match( ) */ unsigned long int match_limit_recursion; /* Max recursive calls to match( ) */
unsigned char **mark; /* For passing back a mark pointer */
void *executable_jit; /* Contains a pointer to a compiled jit c
ode */
} pcre_extra; } pcre_extra;
/* Same structure as above, but with 16 bit char pointers. */
typedef struct pcre16_extra {
unsigned long int flags; /* Bits for which fields are set */
void *study_data; /* Opaque data from pcre_study() */
unsigned long int match_limit; /* Maximum number of calls to match() */
void *callout_data; /* Data passed back in callouts */
const unsigned char *tables; /* Pointer to character tables */
unsigned long int match_limit_recursion; /* Max recursive calls to match(
) */
PCRE_UCHAR16 **mark; /* For passing back a mark pointer */
void *executable_jit; /* Contains a pointer to a compiled jit c
ode */
} pcre16_extra;
/* The structure for passing out data via the pcre_callout_function. We use a /* The structure for passing out data via the pcre_callout_function. We use a
structure so that new fields can be added on the end in future versions, structure so that new fields can be added on the end in future versions,
without changing the API of the function, thereby allowing old databases to work without changing the API of the function, thereby allowing old clients to w ork
without modification. */ without modification. */
typedef struct pcre_callout_block { typedef struct pcre_callout_block {
int version; /* Identifies version of block */ int version; /* Identifies version of block */
/* ------------------------ Version 0 ------------------------------- */ /* ------------------------ Version 0 ------------------------------- */
int callout_number; /* Number compiled into pattern */ int callout_number; /* Number compiled into pattern */
int *offset_vector; /* The offset vector */ int *offset_vector; /* The offset vector */
PCRE_SPTR subject; /* The subject being matched */ PCRE_SPTR subject; /* The subject being matched */
int subject_length; /* The length of the subject */ int subject_length; /* The length of the subject */
int start_match; /* Offset to start of this match attempt */ int start_match; /* Offset to start of this match attempt */
int current_position; /* Where we currently are in the subject */ int current_position; /* Where we currently are in the subject */
int capture_top; /* Max current capture */ int capture_top; /* Max current capture */
int capture_last; /* Most recently closed capture */ int capture_last; /* Most recently closed capture */
void *callout_data; /* Data passed in with the call */ void *callout_data; /* Data passed in with the call */
/* ------------------- Added for Version 1 -------------------------- */ /* ------------------- Added for Version 1 -------------------------- */
int pattern_position; /* Offset to next item in the pattern */ int pattern_position; /* Offset to next item in the pattern */
int next_item_length; /* Length of next item in the pattern */ int next_item_length; /* Length of next item in the pattern */
/* ------------------- Added for Version 2 -------------------------- */
const unsigned char *mark; /* Pointer to current mark or NULL */
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
} pcre_callout_block; } pcre_callout_block;
/* Same structure as above, but with 16 bit char pointers. */
typedef struct pcre16_callout_block {
int version; /* Identifies version of block */
/* ------------------------ Version 0 ------------------------------- */
int callout_number; /* Number compiled into pattern */
int *offset_vector; /* The offset vector */
PCRE_SPTR16 subject; /* The subject being matched */
int subject_length; /* The length of the subject */
int start_match; /* Offset to start of this match attempt
*/
int current_position; /* Where we currently are in the subject
*/
int capture_top; /* Max current capture */
int capture_last; /* Most recently closed capture */
void *callout_data; /* Data passed in with the call */
/* ------------------- Added for Version 1 -------------------------- */
int pattern_position; /* Offset to next item in the pattern */
int next_item_length; /* Length of next item in the pattern */
/* ------------------- Added for Version 2 -------------------------- */
const PCRE_UCHAR16 *mark; /* Pointer to current mark or NULL */
/* ------------------------------------------------------------------ */
} pcre16_callout_block;
/* Indirection for store get and free functions. These can be set to /* Indirection for store get and free functions. These can be set to
alternative malloc/free functions if required. Special ones are used in the alternative malloc/free functions if required. Special ones are used in the
non-recursive case for "frames". There is also an optional callout function non-recursive case for "frames". There is also an optional callout function
that is triggered by the (?) regex item. For Virtual Pascal, these definiti ons that is triggered by the (?) regex item. For Virtual Pascal, these definiti ons
have to take another form. */ have to take another form. */
#ifndef VPCOMPAT #ifndef VPCOMPAT
PCRE_EXP_DECL void *(*pcre_malloc)(size_t); PCRE_EXP_DECL void *(*pcre_malloc)(size_t);
PCRE_EXP_DECL void (*pcre_free)(void *); PCRE_EXP_DECL void (*pcre_free)(void *);
PCRE_EXP_DECL void *(*pcre_stack_malloc)(size_t); PCRE_EXP_DECL void *(*pcre_stack_malloc)(size_t);
PCRE_EXP_DECL void (*pcre_stack_free)(void *); PCRE_EXP_DECL void (*pcre_stack_free)(void *);
PCRE_EXP_DECL int (*pcre_callout)(pcre_callout_block *); PCRE_EXP_DECL int (*pcre_callout)(pcre_callout_block *);
PCRE_EXP_DECL void *(*pcre16_malloc)(size_t);
PCRE_EXP_DECL void (*pcre16_free)(void *);
PCRE_EXP_DECL void *(*pcre16_stack_malloc)(size_t);
PCRE_EXP_DECL void (*pcre16_stack_free)(void *);
PCRE_EXP_DECL int (*pcre16_callout)(pcre16_callout_block *);
#else /* VPCOMPAT */ #else /* VPCOMPAT */
PCRE_EXP_DECL void *pcre_malloc(size_t); PCRE_EXP_DECL void *pcre_malloc(size_t);
PCRE_EXP_DECL void pcre_free(void *); PCRE_EXP_DECL void pcre_free(void *);
PCRE_EXP_DECL void *pcre_stack_malloc(size_t); PCRE_EXP_DECL void *pcre_stack_malloc(size_t);
PCRE_EXP_DECL void pcre_stack_free(void *); PCRE_EXP_DECL void pcre_stack_free(void *);
PCRE_EXP_DECL int pcre_callout(pcre_callout_block *); PCRE_EXP_DECL int pcre_callout(pcre_callout_block *);
PCRE_EXP_DECL void *pcre16_malloc(size_t);
PCRE_EXP_DECL void pcre16_free(void *);
PCRE_EXP_DECL void *pcre16_stack_malloc(size_t);
PCRE_EXP_DECL void pcre16_stack_free(void *);
PCRE_EXP_DECL int pcre16_callout(pcre16_callout_block *);
#endif /* VPCOMPAT */ #endif /* VPCOMPAT */
/* User defined callback which provides a stack just before the match start
s. */
typedef pcre_jit_stack *(*pcre_jit_callback)(void *);
typedef pcre16_jit_stack *(*pcre16_jit_callback)(void *);
/* Exported PCRE functions */ /* Exported PCRE functions */
PCRE_EXP_DECL pcre *pcre_compile(const char *, int, const char **, int *, PCRE_EXP_DECL pcre *pcre_compile(const char *, int, const char **, int *,
const unsigned char *); const unsigned char *);
PCRE_EXP_DECL pcre16 *pcre16_compile(PCRE_SPTR16, int, const char **, int *
,
const unsigned char *);
PCRE_EXP_DECL pcre *pcre_compile2(const char *, int, int *, const char **, PCRE_EXP_DECL pcre *pcre_compile2(const char *, int, int *, const char **,
int *, const unsigned char *); int *, const unsigned char *);
PCRE_EXP_DECL pcre16 *pcre16_compile2(PCRE_SPTR16, int, int *, const char *
*,
int *, const unsigned char *);
PCRE_EXP_DECL int pcre_config(int, void *); PCRE_EXP_DECL int pcre_config(int, void *);
PCRE_EXP_DECL int pcre16_config(int, void *);
PCRE_EXP_DECL int pcre_copy_named_substring(const pcre *, const char *, PCRE_EXP_DECL int pcre_copy_named_substring(const pcre *, const char *,
int *, int, const char *, char *, int); int *, int, const char *, char *, int);
PCRE_EXP_DECL int pcre_copy_substring(const char *, int *, int, int, char PCRE_EXP_DECL int pcre16_copy_named_substring(const pcre16 *, PCRE_SPTR16,
*, int *, int, PCRE_SPTR16, PCRE_UCHAR16 *, int);
int); PCRE_EXP_DECL int pcre_copy_substring(const char *, int *, int, int,
char *, int);
PCRE_EXP_DECL int pcre16_copy_substring(PCRE_SPTR16, int *, int, int,
PCRE_UCHAR16 *, int);
PCRE_EXP_DECL int pcre_dfa_exec(const pcre *, const pcre_extra *, PCRE_EXP_DECL int pcre_dfa_exec(const pcre *, const pcre_extra *,
const char *, int, int, int, int *, int , int *, int); const char *, int, int, int, int *, int , int *, int);
PCRE_EXP_DECL int pcre16_dfa_exec(const pcre16 *, const pcre16_extra *,
PCRE_SPTR16, int, int, int, int *, int , int *, int);
PCRE_EXP_DECL int pcre_exec(const pcre *, const pcre_extra *, PCRE_SPTR, PCRE_EXP_DECL int pcre_exec(const pcre *, const pcre_extra *, PCRE_SPTR,
int, int, int, int *, int); int, int, int, int *, int);
PCRE_EXP_DECL int pcre16_exec(const pcre16 *, const pcre16_extra *,
PCRE_SPTR16, int, int, int, int *, int);
PCRE_EXP_DECL void pcre_free_substring(const char *); PCRE_EXP_DECL void pcre_free_substring(const char *);
PCRE_EXP_DECL void pcre16_free_substring(PCRE_SPTR16);
PCRE_EXP_DECL void pcre_free_substring_list(const char **); PCRE_EXP_DECL void pcre_free_substring_list(const char **);
PCRE_EXP_DECL void pcre16_free_substring_list(PCRE_SPTR16 *);
PCRE_EXP_DECL int pcre_fullinfo(const pcre *, const pcre_extra *, int, PCRE_EXP_DECL int pcre_fullinfo(const pcre *, const pcre_extra *, int,
void *); void *);
PCRE_EXP_DECL int pcre16_fullinfo(const pcre16 *, const pcre16_extra *, in
t,
void *);
PCRE_EXP_DECL int pcre_get_named_substring(const pcre *, const char *, PCRE_EXP_DECL int pcre_get_named_substring(const pcre *, const char *,
int *, int, const char *, const char **); int *, int, const char *, const char **);
PCRE_EXP_DECL int pcre16_get_named_substring(const pcre16 *, PCRE_SPTR16,
int *, int, PCRE_SPTR16, PCRE_SPTR16 *);
PCRE_EXP_DECL int pcre_get_stringnumber(const pcre *, const char *); PCRE_EXP_DECL int pcre_get_stringnumber(const pcre *, const char *);
PCRE_EXP_DECL int pcre16_get_stringnumber(const pcre16 *, PCRE_SPTR16);
PCRE_EXP_DECL int pcre_get_stringtable_entries(const pcre *, const char *, PCRE_EXP_DECL int pcre_get_stringtable_entries(const pcre *, const char *,
char **, char **); char **, char **);
PCRE_EXP_DECL int pcre16_get_stringtable_entries(const pcre16 *, PCRE_SPTR
16,
PCRE_UCHAR16 **, PCRE_UCHAR16 **);
PCRE_EXP_DECL int pcre_get_substring(const char *, int *, int, int, PCRE_EXP_DECL int pcre_get_substring(const char *, int *, int, int,
const char **); const char **);
PCRE_EXP_DECL int pcre16_get_substring(PCRE_SPTR16, int *, int, int,
PCRE_SPTR16 *);
PCRE_EXP_DECL int pcre_get_substring_list(const char *, int *, int, PCRE_EXP_DECL int pcre_get_substring_list(const char *, int *, int,
const char ***); const char ***);
PCRE_EXP_DECL int pcre_info(const pcre *, int *, int *); PCRE_EXP_DECL int pcre16_get_substring_list(PCRE_SPTR16, int *, int,
PCRE_SPTR16 **);
PCRE_EXP_DECL const unsigned char *pcre_maketables(void); PCRE_EXP_DECL const unsigned char *pcre_maketables(void);
PCRE_EXP_DECL const unsigned char *pcre16_maketables(void);
PCRE_EXP_DECL int pcre_refcount(pcre *, int); PCRE_EXP_DECL int pcre_refcount(pcre *, int);
PCRE_EXP_DECL int pcre16_refcount(pcre16 *, int);
PCRE_EXP_DECL pcre_extra *pcre_study(const pcre *, int, const char **); PCRE_EXP_DECL pcre_extra *pcre_study(const pcre *, int, const char **);
PCRE_EXP_DECL pcre16_extra *pcre16_study(const pcre16 *, int, const char **
);
PCRE_EXP_DECL void pcre_free_study(pcre_extra *);
PCRE_EXP_DECL void pcre16_free_study(pcre16_extra *);
PCRE_EXP_DECL const char *pcre_version(void); PCRE_EXP_DECL const char *pcre_version(void);
PCRE_EXP_DECL const char *pcre16_version(void);
/* Utility functions for byte order swaps. */
PCRE_EXP_DECL int pcre_pattern_to_host_byte_order(pcre *, pcre_extra *,
const unsigned char *);
PCRE_EXP_DECL int pcre16_pattern_to_host_byte_order(pcre16 *, pcre16_extra
*,
const unsigned char *);
PCRE_EXP_DECL int pcre16_utf16_to_host_byte_order(PCRE_UCHAR16 *,
PCRE_SPTR16, int, int *, int);
/* JIT compiler related functions. */
PCRE_EXP_DECL pcre_jit_stack *pcre_jit_stack_alloc(int, int);
PCRE_EXP_DECL pcre16_jit_stack *pcre16_jit_stack_alloc(int, int);
PCRE_EXP_DECL void pcre_jit_stack_free(pcre_jit_stack *);
PCRE_EXP_DECL void pcre16_jit_stack_free(pcre16_jit_stack *);
PCRE_EXP_DECL void pcre_assign_jit_stack(pcre_extra *,
pcre_jit_callback, void *);
PCRE_EXP_DECL void pcre16_assign_jit_stack(pcre16_extra *,
pcre16_jit_callback, void *);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif #endif
#endif /* End of pcre.h */ #endif /* End of pcre.h */
 End of changes. 41 change blocks. 
69 lines changed or deleted 297 lines changed or added


 pcre_internal.h   pcre_internal.h 
/************************************************* /*************************************************
* Perl-Compatible Regular Expressions * * Perl-Compatible Regular Expressions *
*************************************************/ *************************************************/
/* PCRE is a library of functions to support regular expressions whose synt ax /* PCRE is a library of functions to support regular expressions whose synt ax
and semantics are as close as possible to those of the Perl 5 language. and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel Written by Philip Hazel
Copyright (c) 1997-2007 University of Cambridge Copyright (c) 1997-2012 University of Cambridge
--------------------------------------------------------------------------- -- --------------------------------------------------------------------------- --
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice , * Redistributions of source code must retain the above copyright notice ,
this list of conditions and the following disclaimer. this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright * Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the notice, this list of conditions and the following disclaimer in the
skipping to change at line 42 skipping to change at line 42
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- -- --------------------------------------------------------------------------- --
*/ */
/* This header contains definitions that are shared between the different /* This header contains definitions that are shared between the different
modules, but which are not relevant to the exported API. This includes some modules, but which are not relevant to the exported API. This includes some
functions whose names all begin with "_pcre_". */ functions whose names all begin with "_pcre_" or "_pcre16_" depending on
the PRIV macro. */
#ifndef PCRE_INTERNAL_H #ifndef PCRE_INTERNAL_H
#define PCRE_INTERNAL_H #define PCRE_INTERNAL_H
/* Define DEBUG to get debugging output on stdout. */ /* Define PCRE_DEBUG to get debugging output on stdout. */
#if 0 #if 0
#define DEBUG #define PCRE_DEBUG
#endif
/* PCRE is compiled as an 8 bit library if it is not requested otherwise. *
/
#ifndef COMPILE_PCRE16
#define COMPILE_PCRE8
#endif
/* If SUPPORT_UCP is defined, SUPPORT_UTF must also be defined. The
"configure" script ensures this, but not everybody uses "configure". */
#if defined SUPPORT_UCP && !(defined SUPPORT_UTF)
#define SUPPORT_UTF 1
#endif
/* We define SUPPORT_UTF if SUPPORT_UTF8 is enabled for compatibility
reasons with existing code. */
#if defined SUPPORT_UTF8 && !(defined SUPPORT_UTF)
#define SUPPORT_UTF 1
#endif
/* Fixme: SUPPORT_UTF8 should be eventually disappear from the code.
Until then we define it if SUPPORT_UTF is defined. */
#if defined SUPPORT_UTF && !(defined SUPPORT_UTF8)
#define SUPPORT_UTF8 1
#endif
/* We do not support both EBCDIC and UTF-8/16 at the same time. The "config
ure"
script prevents both being selected, but not everybody uses "configure". */
#if defined EBCDIC && defined SUPPORT_UTF
#error The use of both EBCDIC and SUPPORT_UTF8/16 is not supported.
#endif #endif
/* Use a macro for debugging printing, 'cause that eliminates the use of #i fdef /* Use a macro for debugging printing, 'cause that eliminates the use of #i fdef
inline, and there are *still* stupid compilers about that don't like indent ed inline, and there are *still* stupid compilers about that don't like indent ed
pre-processor statements, or at least there were when I first wrote this. A fter pre-processor statements, or at least there were when I first wrote this. A fter
all, it had only been about 10 years then... all, it had only been about 10 years then...
It turns out that the Mac Debugging.h header also defines the macro DPRINTF , so It turns out that the Mac Debugging.h header also defines the macro DPRINTF , so
be absolutely sure we get our version. */ be absolutely sure we get our version. */
#undef DPRINTF #undef DPRINTF
#ifdef DEBUG #ifdef PCRE_DEBUG
#define DPRINTF(p) printf p #define DPRINTF(p) printf p
#else #else
#define DPRINTF(p) /* Nothing */ #define DPRINTF(p) /* Nothing */
#endif #endif
/* Standard C headers plus the external interface definition. The only time /* Standard C headers plus the external interface definition. The only time
setjmp and stdarg are used is when NO_RECURSE is set. */ setjmp and stdarg are used is when NO_RECURSE is set. */
#include <ctype.h> #include <ctype.h>
#include <limits.h> #include <limits.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
/* When compiling a DLL for Windows, the exported symbols have to be declar ed /* When compiling a DLL for Windows, the exported symbols have to be declar ed
using some MS magic. I found some useful information on this web page: using some MS magic. I found some useful information on this web page:
http://msdn2.microsoft.com/en-us/library/y4h7bcy6(VS.80).aspx. According to the http://msdn2.microsoft.com/en-us/library/y4h7bcy6(VS.80).aspx. According to the
information there, using __declspec(dllexport) without "extern" we have a information there, using __declspec(dllexport) without "extern" we have a
definition; with "extern" we have a declaration. The settings here override the definition; with "extern" we have a declaration. The settings here override the
skipping to change at line 108 skipping to change at line 140
The reason for wrapping this in #ifndef PCRE_EXP_DECL is so that pcretest, The reason for wrapping this in #ifndef PCRE_EXP_DECL is so that pcretest,
which is an application, but needs to import this file in order to "peek" a t which is an application, but needs to import this file in order to "peek" a t
internals, can #include pcre.h first to get an application's-eye view. internals, can #include pcre.h first to get an application's-eye view.
In principle, people compiling for non-Windows, non-Unix-like (i.e. uncommo n, In principle, people compiling for non-Windows, non-Unix-like (i.e. uncommo n,
special-purpose environments) might want to stick other stuff in front of special-purpose environments) might want to stick other stuff in front of
exported symbols. That's why, in the non-Windows case, we set PCRE_EXP_DEFN and exported symbols. That's why, in the non-Windows case, we set PCRE_EXP_DEFN and
PCRE_EXP_DATA_DEFN only if they are not already set. */ PCRE_EXP_DATA_DEFN only if they are not already set. */
#ifndef PCRE_EXP_DECL #ifndef PCRE_EXP_DECL
/*# ifdef _WIN32 # ifdef _WIN32
# ifndef PCRE_STATIC # ifndef PCRE_STATIC
# define PCRE_EXP_DECL extern __declspec(dllexport) # define PCRE_EXP_DECL extern __declspec(dllexport)
# define PCRE_EXP_DEFN __declspec(dllexport) # define PCRE_EXP_DEFN __declspec(dllexport)
# define PCRE_EXP_DATA_DEFN __declspec(dllexport) # define PCRE_EXP_DATA_DEFN __declspec(dllexport)
# else # else
# define PCRE_EXP_DECL extern # define PCRE_EXP_DECL extern
# define PCRE_EXP_DEFN # define PCRE_EXP_DEFN
# define PCRE_EXP_DATA_DEFN # define PCRE_EXP_DATA_DEFN
# endif # endif
# else*/ # else
# ifdef __cplusplus # ifdef __cplusplus
# define PCRE_EXP_DECL extern "C" # define PCRE_EXP_DECL extern "C"
# else # else
# define PCRE_EXP_DECL extern # define PCRE_EXP_DECL extern
# endif # endif
# ifndef PCRE_EXP_DEFN # ifndef PCRE_EXP_DEFN
# define PCRE_EXP_DEFN PCRE_EXP_DECL # define PCRE_EXP_DEFN PCRE_EXP_DECL
# endif # endif
# ifndef PCRE_EXP_DATA_DEFN # ifndef PCRE_EXP_DATA_DEFN
# define PCRE_EXP_DATA_DEFN # define PCRE_EXP_DATA_DEFN
# endif # endif
# endif # endif
/*#endif*/ #endif
/* We need to have types that specify unsigned 16-bit and 32-bit integers. /* When compiling with the MSVC compiler, it is sometimes necessary to incl
We ude
a "calling convention" before exported function names. (This is secondhand
information; I know nothing about MSVC myself). For example, something like
void __cdecl function(....)
might be needed. In order so make this easy, all the exported functions hav
e
PCRE_CALL_CONVENTION just before their names. It is rarely needed; if not
set, we ensure here that it has no effect. */
#ifndef PCRE_CALL_CONVENTION
#define PCRE_CALL_CONVENTION
#endif
/* We need to have types that specify unsigned 8, 16 and 32-bit integers. W
e
cannot determine these outside the compilation (e.g. by running a program a s cannot determine these outside the compilation (e.g. by running a program a s
part of "configure") because PCRE is often cross-compiled for use on other part of "configure") because PCRE is often cross-compiled for use on other
systems. Instead we make use of the maximum sizes that are available at systems. Instead we make use of the maximum sizes that are available at
preprocessor time in standard C environments. */ preprocessor time in standard C environments. */
typedef unsigned char pcre_uint8;
#if USHRT_MAX == 65535 #if USHRT_MAX == 65535
typedef unsigned short pcre_uint16; typedef unsigned short pcre_uint16;
typedef short pcre_int16;
#elif UINT_MAX == 65535 #elif UINT_MAX == 65535
typedef unsigned int pcre_uint16; typedef unsigned int pcre_uint16;
typedef int pcre_int16;
#else #else
#error Cannot determine a type for 16-bit unsigned integers #error Cannot determine a type for 16-bit unsigned integers
#endif #endif
#if UINT_MAX == 4294967295 #if UINT_MAX == 4294967295
typedef unsigned int pcre_uint32; typedef unsigned int pcre_uint32;
typedef int pcre_int32;
#elif ULONG_MAX == 4294967295 #elif ULONG_MAX == 4294967295
typedef unsigned long int pcre_uint32; typedef unsigned long int pcre_uint32;
typedef long int pcre_int32;
#else #else
#error Cannot determine a type for 32-bit unsigned integers #error Cannot determine a type for 32-bit unsigned integers
#endif #endif
/* When checking for integer overflow in pcre_compile(), we need to handle
large integers. If a 64-bit integer type is available, we can use that.
Otherwise we have to cast to double, which of course requires floating poin
t
arithmetic. Handle this by defining a macro for the appropriate type. If
stdint.h is available, include it; it may define INT64_MAX. Systems that do
not
have stdint.h (e.g. Solaris) may have inttypes.h. The macro int64_t may be
set
by "configure". */
#if HAVE_STDINT_H
#include <stdint.h>
#elif HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#if defined INT64_MAX || defined int64_t
#define INT64_OR_DOUBLE int64_t
#else
#define INT64_OR_DOUBLE double
#endif
/* All character handling must be done as unsigned characters. Otherwise th ere /* All character handling must be done as unsigned characters. Otherwise th ere
are problems with top-bit-set characters and functions such as isspace(). are problems with top-bit-set characters and functions such as isspace().
However, we leave the interface to the outside world as char *, because tha However, we leave the interface to the outside world as char * or short *,
t because that should make things easier for callers. This character type is
should make things easier for callers. We define a short type for unsigned called pcre_uchar.
char
to save lots of typing. I tried "uchar", but it causes problems on Digital The IN_UCHARS macro multiply its argument with the byte size of the current
Unix, where it is defined in sys/types, so use "uschar" instead. */ pcre_uchar type. Useful for memcpy and such operations, whose require the
byte size of their input/output buffers.
The MAX_255 macro checks whether its pcre_uchar input is less than 256.
The TABLE_GET macro is designed for accessing elements of tables whose cont
ain
exactly 256 items. When the character is able to contain more than 256
items, some check is needed before accessing these tables.
*/
#ifdef COMPILE_PCRE8
typedef unsigned char uschar; typedef unsigned char pcre_uchar;
#define IN_UCHARS(x) (x)
#define MAX_255(c) 1
#define TABLE_GET(c, table, default) ((table)[c])
#else
#ifdef COMPILE_PCRE16
#if USHRT_MAX != 65535
/* This is a warning message. Change PCRE_UCHAR16 to a 16 bit data type in
pcre.h(.in) and disable (comment out) this message. */
#error Warning: PCRE_UCHAR16 is not a 16 bit data type.
#endif
typedef pcre_uint16 pcre_uchar;
#define IN_UCHARS(x) ((x) << 1)
#define MAX_255(c) ((c) <= 255u)
#define TABLE_GET(c, table, default) (MAX_255(c)? ((table)[c]):(default))
#else
#error Unsupported compiling mode
#endif /* COMPILE_PCRE16 */
#endif /* COMPILE_PCRE8 */
/* This is an unsigned int value that no character can ever have. UTF-8 /* This is an unsigned int value that no character can ever have. UTF-8
characters only go up to 0x7fffffff (though Unicode doesn't go beyond characters only go up to 0x7fffffff (though Unicode doesn't go beyond
0x0010ffff). */ 0x0010ffff). */
#define NOTACHAR 0xffffffff #define NOTACHAR 0xffffffff
/* PCRE is able to support several different kinds of newline (CR, LF, CRLF , /* PCRE is able to support several different kinds of newline (CR, LF, CRLF ,
"any" and "anycrlf" at present). The following macros are used to package u p "any" and "anycrlf" at present). The following macros are used to package u p
testing for newlines. NLBLOCK, PSSTART, and PSEND are defined in the variou s testing for newlines. NLBLOCK, PSSTART, and PSEND are defined in the variou s
skipping to change at line 185 skipping to change at line 292
#define NLTYPE_FIXED 0 /* Newline is a fixed length string */ #define NLTYPE_FIXED 0 /* Newline is a fixed length string */
#define NLTYPE_ANY 1 /* Newline is any Unicode line ending */ #define NLTYPE_ANY 1 /* Newline is any Unicode line ending */
#define NLTYPE_ANYCRLF 2 /* Newline is CR, LF, or CRLF */ #define NLTYPE_ANYCRLF 2 /* Newline is CR, LF, or CRLF */
/* This macro checks for a newline at the given position */ /* This macro checks for a newline at the given position */
#define IS_NEWLINE(p) \ #define IS_NEWLINE(p) \
((NLBLOCK->nltype != NLTYPE_FIXED)? \ ((NLBLOCK->nltype != NLTYPE_FIXED)? \
((p) < NLBLOCK->PSEND && \ ((p) < NLBLOCK->PSEND && \
_pcre_is_newline((p), NLBLOCK->nltype, NLBLOCK->PSEND, &(NLBLOCK->nlle PRIV(is_newline)((p), NLBLOCK->nltype, NLBLOCK->PSEND, \
n),\ &(NLBLOCK->nllen), utf)) \
utf8)) \
: \ : \
((p) <= NLBLOCK->PSEND - NLBLOCK->nllen && \ ((p) <= NLBLOCK->PSEND - NLBLOCK->nllen && \
(p)[0] == NLBLOCK->nl[0] && \ (p)[0] == NLBLOCK->nl[0] && \
(NLBLOCK->nllen == 1 || (p)[1] == NLBLOCK->nl[1]) \ (NLBLOCK->nllen == 1 || (p)[1] == NLBLOCK->nl[1]) \
) \ ) \
) )
/* This macro checks for a newline immediately preceding the given position */ /* This macro checks for a newline immediately preceding the given position */
#define WAS_NEWLINE(p) \ #define WAS_NEWLINE(p) \
((NLBLOCK->nltype != NLTYPE_FIXED)? \ ((NLBLOCK->nltype != NLTYPE_FIXED)? \
((p) > NLBLOCK->PSSTART && \ ((p) > NLBLOCK->PSSTART && \
_pcre_was_newline((p), NLBLOCK->nltype, NLBLOCK->PSSTART, \ PRIV(was_newline)((p), NLBLOCK->nltype, NLBLOCK->PSSTART, \
&(NLBLOCK->nllen), utf8)) \ &(NLBLOCK->nllen), utf)) \
: \ : \
((p) >= NLBLOCK->PSSTART + NLBLOCK->nllen && \ ((p) >= NLBLOCK->PSSTART + NLBLOCK->nllen && \
(p)[-NLBLOCK->nllen] == NLBLOCK->nl[0] && \ (p)[-NLBLOCK->nllen] == NLBLOCK->nl[0] && \
(NLBLOCK->nllen == 1 || (p)[-NLBLOCK->nllen+1] == NLBLOCK->nl[1]) \ (NLBLOCK->nllen == 1 || (p)[-NLBLOCK->nllen+1] == NLBLOCK->nl[1]) \
) \ ) \
) )
/* When PCRE is compiled as a C++ library, the subject pointer can be repla ced /* When PCRE is compiled as a C++ library, the subject pointer can be repla ced
with a custom type. This makes it possible, for example, to allow pcre_exec () with a custom type. This makes it possible, for example, to allow pcre_exec ()
to process subject strings that are discontinuous by using a smart pointer to process subject strings that are discontinuous by using a smart pointer
class. It must always be possible to inspect all of the subject string in class. It must always be possible to inspect all of the subject string in
pcre_exec() because of the way it backtracks. Two macros are required in th e pcre_exec() because of the way it backtracks. Two macros are required in th e
normal case, for sign-unspecified and unsigned char pointers. The former is normal case, for sign-unspecified and unsigned char pointers. The former is
used for the external interface and appears in pcre.h, which is why its nam e used for the external interface and appears in pcre.h, which is why its nam e
must begin with PCRE_. */ must begin with PCRE_. */
#ifdef CUSTOM_SUBJECT_PTR #ifdef CUSTOM_SUBJECT_PTR
#define PCRE_SPTR CUSTOM_SUBJECT_PTR #define PCRE_PUCHAR CUSTOM_SUBJECT_PTR
#define USPTR CUSTOM_SUBJECT_PTR
#else #else
#define PCRE_SPTR const char * #define PCRE_PUCHAR const pcre_uchar *
#define USPTR const unsigned char *
#endif #endif
/* Include the public PCRE header and the definitions of UCP character prop erty /* Include the public PCRE header and the definitions of UCP character prop erty
values. */ values. */
#include "pcre.h" #include "pcre.h"
#include "ucp.h" #include "ucp.h"
/* When compiling for use with the Virtual Pascal compiler, these functions /* When compiling for use with the Virtual Pascal compiler, these functions
need to have their names changed. PCRE must be compiled with the -DVPCOMPAT need to have their names changed. PCRE must be compiled with the -DVPCOMPAT
skipping to change at line 291 skipping to change at line 396
offset limits the size of the compiled regex to around 64K, which is big en ough offset limits the size of the compiled regex to around 64K, which is big en ough
for almost everybody. However, I received a request for an even bigger limi t. for almost everybody. However, I received a request for an even bigger limi t.
For this reason, and also to make the code easier to maintain, the storing and For this reason, and also to make the code easier to maintain, the storing and
loading of offsets from the byte string is now handled by the macros that a re loading of offsets from the byte string is now handled by the macros that a re
defined here. defined here.
The macros are controlled by the value of LINK_SIZE. This defaults to 2 in The macros are controlled by the value of LINK_SIZE. This defaults to 2 in
the config.h file, but can be overridden by using -D on the command line. T his the config.h file, but can be overridden by using -D on the command line. T his
is automated on Unix systems via the "configure" command. */ is automated on Unix systems via the "configure" command. */
#ifdef COMPILE_PCRE8
#if LINK_SIZE == 2 #if LINK_SIZE == 2
#define PUT(a,n,d) \ #define PUT(a,n,d) \
(a[n] = (d) >> 8), \ (a[n] = (d) >> 8), \
(a[(n)+1] = (d) & 255) (a[(n)+1] = (d) & 255)
#define GET(a,n) \ #define GET(a,n) \
(((a)[n] << 8) | (a)[(n)+1]) (((a)[n] << 8) | (a)[(n)+1])
#define MAX_PATTERN_SIZE (1 << 16) #define MAX_PATTERN_SIZE (1 << 16)
skipping to change at line 325 skipping to change at line 432
#define PUT(a,n,d) \ #define PUT(a,n,d) \
(a[n] = (d) >> 24), \ (a[n] = (d) >> 24), \
(a[(n)+1] = (d) >> 16), \ (a[(n)+1] = (d) >> 16), \
(a[(n)+2] = (d) >> 8), \ (a[(n)+2] = (d) >> 8), \
(a[(n)+3] = (d) & 255) (a[(n)+3] = (d) & 255)
#define GET(a,n) \ #define GET(a,n) \
(((a)[n] << 24) | ((a)[(n)+1] << 16) | ((a)[(n)+2] << 8) | (a)[(n)+3]) (((a)[n] << 24) | ((a)[(n)+1] << 16) | ((a)[(n)+2] << 8) | (a)[(n)+3])
#define MAX_PATTERN_SIZE (1 << 30) /* Keep it positive */ /* Keep it positive */
#define MAX_PATTERN_SIZE (1 << 30)
#else
#error LINK_SIZE must be either 2, 3, or 4
#endif
#else /* COMPILE_PCRE8 */
#ifdef COMPILE_PCRE16
#if LINK_SIZE == 2
#undef LINK_SIZE
#define LINK_SIZE 1
#define PUT(a,n,d) \
(a[n] = (d))
#define GET(a,n) \
(a[n])
#define MAX_PATTERN_SIZE (1 << 16)
#elif LINK_SIZE == 3 || LINK_SIZE == 4
#undef LINK_SIZE
#define LINK_SIZE 2
#define PUT(a,n,d) \
(a[n] = (d) >> 16), \
(a[(n)+1] = (d) & 65535)
#define GET(a,n) \
(((a)[n] << 16) | (a)[(n)+1])
/* Keep it positive */
#define MAX_PATTERN_SIZE (1 << 30)
#else #else
#error LINK_SIZE must be either 2, 3, or 4 #error LINK_SIZE must be either 2, 3, or 4
#endif #endif
#else
#error Unsupported compiling mode
#endif /* COMPILE_PCRE16 */
#endif /* COMPILE_PCRE8 */
/* Convenience macro defined in terms of the others */ /* Convenience macro defined in terms of the others */
#define PUTINC(a,n,d) PUT(a,n,d), a += LINK_SIZE #define PUTINC(a,n,d) PUT(a,n,d), a += LINK_SIZE
/* PCRE uses some other 2-byte quantities that do not change when the size of /* PCRE uses some other 2-byte quantities that do not change when the size of
offsets changes. There are used for repeat counts and for other things such as offsets changes. There are used for repeat counts and for other things such as
capturing parenthesis numbers in back references. */ capturing parenthesis numbers in back references. */
#ifdef COMPILE_PCRE8
#define IMM2_SIZE 2
#define PUT2(a,n,d) \ #define PUT2(a,n,d) \
a[n] = (d) >> 8; \ a[n] = (d) >> 8; \
a[(n)+1] = (d) & 255 a[(n)+1] = (d) & 255
#define GET2(a,n) \ #define GET2(a,n) \
(((a)[n] << 8) | (a)[(n)+1]) (((a)[n] << 8) | (a)[(n)+1])
#define PUT2INC(a,n,d) PUT2(a,n,d), a += 2 #else /* COMPILE_PCRE8 */
#ifdef COMPILE_PCRE16
#define IMM2_SIZE 1
#define PUT2(a,n,d) \
a[n] = d
#define GET2(a,n) \
a[n]
#else
#error Unsupported compiling mode
#endif /* COMPILE_PCRE16 */
#endif /* COMPILE_PCRE8 */
/* When UTF-8 encoding is being used, a character is no longer just a singl #define PUT2INC(a,n,d) PUT2(a,n,d), a += IMM2_SIZE
e
byte. The macros for character handling generate simple sequences when used
in
byte-mode, and more complicated ones for UTF-8 characters. BACKCHAR should
never be called in byte mode. To make sure it can never even appear when UT
F-8
support is omitted, we don't even define it. */
#ifndef SUPPORT_UTF8 /* When UTF encoding is being used, a character is no longer just a single
character. The macros for character handling generate simple sequences when
used in character-mode, and more complicated ones for UTF characters.
GETCHARLENTEST and other macros are not used when UTF is not supported,
so they are not defined. To make sure they can never even appear when
UTF support is omitted, we don't even define them. */
#ifndef SUPPORT_UTF
/* #define MAX_VALUE_FOR_SINGLE_CHAR */
/* #define HAS_EXTRALEN(c) */
/* #define GET_EXTRALEN(c) */
/* #define NOT_FIRSTCHAR(c) */
#define GETCHAR(c, eptr) c = *eptr; #define GETCHAR(c, eptr) c = *eptr;
#define GETCHARTEST(c, eptr) c = *eptr; #define GETCHARTEST(c, eptr) c = *eptr;
#define GETCHARINC(c, eptr) c = *eptr++; #define GETCHARINC(c, eptr) c = *eptr++;
#define GETCHARINCTEST(c, eptr) c = *eptr++; #define GETCHARINCTEST(c, eptr) c = *eptr++;
#define GETCHARLEN(c, eptr, len) c = *eptr; #define GETCHARLEN(c, eptr, len) c = *eptr;
/* #define GETCHARLENTEST(c, eptr, len) */
/* #define BACKCHAR(eptr) */ /* #define BACKCHAR(eptr) */
/* #define FORWARDCHAR(eptr) */
/* #define ACROSSCHAR(condition, eptr, action) */
#else /* SUPPORT_UTF8 */ #else /* SUPPORT_UTF */
#ifdef COMPILE_PCRE8
/* These macros were originally written in the form of loops that used data
from the tables whose names start with PRIV(utf8_table). They were rewritte
n by
a user so as not to use loops, because in some environments this gives a
significant performance advantage, and it seems never to do any harm. */
/* Tells the biggest code point which can be encoded as a single character.
*/
#define MAX_VALUE_FOR_SINGLE_CHAR 127
/* Tests whether the code point needs extra characters to decode. */
#define HAS_EXTRALEN(c) ((c) >= 0xc0)
/* Returns with the additional number of characters if IS_MULTICHAR(c) is T
RUE.
Otherwise it has an undefined behaviour. */
#define GET_EXTRALEN(c) (PRIV(utf8_table4)[(c) & 0x3f])
/* Returns TRUE, if the given character is not the first character
of a UTF sequence. */
#define NOT_FIRSTCHAR(c) (((c) & 0xc0) == 0x80)
/* Base macro to pick up the remaining bytes of a UTF-8 character, not
advancing the pointer. */
#define GETUTF8(c, eptr) \
{ \
if ((c & 0x20) == 0) \
c = ((c & 0x1f) << 6) | (eptr[1] & 0x3f); \
else if ((c & 0x10) == 0) \
c = ((c & 0x0f) << 12) | ((eptr[1] & 0x3f) << 6) | (eptr[2] & 0x3f);
\
else if ((c & 0x08) == 0) \
c = ((c & 0x07) << 18) | ((eptr[1] & 0x3f) << 12) | \
((eptr[2] & 0x3f) << 6) | (eptr[3] & 0x3f); \
else if ((c & 0x04) == 0) \
c = ((c & 0x03) << 24) | ((eptr[1] & 0x3f) << 18) | \
((eptr[2] & 0x3f) << 12) | ((eptr[3] & 0x3f) << 6) | \
(eptr[4] & 0x3f); \
else \
c = ((c & 0x01) << 30) | ((eptr[1] & 0x3f) << 24) | \
((eptr[2] & 0x3f) << 18) | ((eptr[3] & 0x3f) << 12) | \
((eptr[4] & 0x3f) << 6) | (eptr[5] & 0x3f); \
}
/* Get the next UTF-8 character, not advancing the pointer. This is called when /* Get the next UTF-8 character, not advancing the pointer. This is called when
we know we are in UTF-8 mode. */ we know we are in UTF-8 mode. */
#define GETCHAR(c, eptr) \ #define GETCHAR(c, eptr) \
c = *eptr; \ c = *eptr; \
if (c >= 0xc0) \ if (c >= 0xc0) GETUTF8(c, eptr);
{ \
int gcii; \
int gcaa = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes
*/ \
int gcss = 6*gcaa; \
c = (c & _pcre_utf8_table3[gcaa]) << gcss; \
for (gcii = 1; gcii <= gcaa; gcii++) \
{ \
gcss -= 6; \
c |= (eptr[gcii] & 0x3f) << gcss; \
} \
}
/* Get the next UTF-8 character, testing for UTF-8 mode, and not advancing the /* Get the next UTF-8 character, testing for UTF-8 mode, and not advancing the
pointer. */ pointer. */
#define GETCHARTEST(c, eptr) \ #define GETCHARTEST(c, eptr) \
c = *eptr; \ c = *eptr; \
if (utf8 && c >= 0xc0) \ if (utf && c >= 0xc0) GETUTF8(c, eptr);
/* Base macro to pick up the remaining bytes of a UTF-8 character, advancin
g
the pointer. */
#define GETUTF8INC(c, eptr) \
{ \ { \
int gcii; \ if ((c & 0x20) == 0) \
int gcaa = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes c = ((c & 0x1f) << 6) | (*eptr++ & 0x3f); \
*/ \ else if ((c & 0x10) == 0) \
int gcss = 6*gcaa; \ { \
c = (c & _pcre_utf8_table3[gcaa]) << gcss; \ c = ((c & 0x0f) << 12) | ((*eptr & 0x3f) << 6) | (eptr[1] & 0x3f); \
for (gcii = 1; gcii <= gcaa; gcii++) \ eptr += 2; \
} \
else if ((c & 0x08) == 0) \
{ \
c = ((c & 0x07) << 18) | ((*eptr & 0x3f) << 12) | \
((eptr[1] & 0x3f) << 6) | (eptr[2] & 0x3f); \
eptr += 3; \
} \
else if ((c & 0x04) == 0) \
{ \ { \
gcss -= 6; \ c = ((c & 0x03) << 24) | ((*eptr & 0x3f) << 18) | \
c |= (eptr[gcii] & 0x3f) << gcss; \ ((eptr[1] & 0x3f) << 12) | ((eptr[2] & 0x3f) << 6) | \
(eptr[3] & 0x3f); \
eptr += 4; \
} \
else \
{ \
c = ((c & 0x01) << 30) | ((*eptr & 0x3f) << 24) | \
((eptr[1] & 0x3f) << 18) | ((eptr[2] & 0x3f) << 12) | \
((eptr[3] & 0x3f) << 6) | (eptr[4] & 0x3f); \
eptr += 5; \
} \ } \
} }
/* Get the next UTF-8 character, advancing the pointer. This is called when we /* Get the next UTF-8 character, advancing the pointer. This is called when we
know we are in UTF-8 mode. */ know we are in UTF-8 mode. */
#define GETCHARINC(c, eptr) \ #define GETCHARINC(c, eptr) \
c = *eptr++; \ c = *eptr++; \
if (c >= 0xc0) \ if (c >= 0xc0) GETUTF8INC(c, eptr);
{ \
int gcaa = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes
*/ \
int gcss = 6*gcaa; \
c = (c & _pcre_utf8_table3[gcaa]) << gcss; \
while (gcaa-- > 0) \
{ \
gcss -= 6; \
c |= (*eptr++ & 0x3f) << gcss; \
} \
}
/* Get the next character, testing for UTF-8 mode, and advancing the pointe /* Get the next character, testing for UTF-8 mode, and advancing the pointe
r */ r.
This is called when we don't know if we are in UTF-8 mode. */
#define GETCHARINCTEST(c, eptr) \ #define GETCHARINCTEST(c, eptr) \
c = *eptr++; \ c = *eptr++; \
if (utf8 && c >= 0xc0) \ if (utf && c >= 0xc0) GETUTF8INC(c, eptr);
/* Base macro to pick up the remaining bytes of a UTF-8 character, not
advancing the pointer, incrementing the length. */
#define GETUTF8LEN(c, eptr, len) \
{ \ { \
int gcaa = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes if ((c & 0x20) == 0) \
*/ \ { \
int gcss = 6*gcaa; \ c = ((c & 0x1f) << 6) | (eptr[1] & 0x3f); \
c = (c & _pcre_utf8_table3[gcaa]) << gcss; \ len++; \
while (gcaa-- > 0) \ } \
else if ((c & 0x10) == 0) \
{ \
c = ((c & 0x0f) << 12) | ((eptr[1] & 0x3f) << 6) | (eptr[2] & 0x3f);
\
len += 2; \
} \
else if ((c & 0x08) == 0) \
{\
c = ((c & 0x07) << 18) | ((eptr[1] & 0x3f) << 12) | \
((eptr[2] & 0x3f) << 6) | (eptr[3] & 0x3f); \
len += 3; \
} \
else if ((c & 0x04) == 0) \
{ \ { \
gcss -= 6; \ c = ((c & 0x03) << 24) | ((eptr[1] & 0x3f) << 18) | \
c |= (*eptr++ & 0x3f) << gcss; \ ((eptr[2] & 0x3f) << 12) | ((eptr[3] & 0x3f) << 6) | \
(eptr[4] & 0x3f); \
len += 4; \
} \
else \
{\
c = ((c & 0x01) << 30) | ((eptr[1] & 0x3f) << 24) | \
((eptr[2] & 0x3f) << 18) | ((eptr[3] & 0x3f) << 12) | \
((eptr[4] & 0x3f) << 6) | (eptr[5] & 0x3f); \
len += 5; \
} \ } \
} }
/* Get the next UTF-8 character, not advancing the pointer, incrementing le ngth /* Get the next UTF-8 character, not advancing the pointer, incrementing le ngth
if there are extra bytes. This is called when we know we are in UTF-8 mode. */ if there are extra bytes. This is called when we know we are in UTF-8 mode. */
#define GETCHARLEN(c, eptr, len) \ #define GETCHARLEN(c, eptr, len) \
c = *eptr; \ c = *eptr; \
if (c >= 0xc0) \ if (c >= 0xc0) GETUTF8LEN(c, eptr, len);
{ \
int gcii; \ /* Get the next UTF-8 character, testing for UTF-8 mode, not advancing the
int gcaa = _pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes pointer, incrementing length if there are extra bytes. This is called when
*/ \ we
int gcss = 6*gcaa; \ do not know if we are in UTF-8 mode. */
c = (c & _pcre_utf8_table3[gcaa]) << gcss; \
for (gcii = 1; gcii <= gcaa; gcii++) \ #define GETCHARLENTEST(c, eptr, len) \
{ \ c = *eptr; \
gcss -= 6; \ if (utf && c >= 0xc0) GETUTF8LEN(c, eptr, len);
c |= (eptr[gcii] & 0x3f) << gcss; \
} \
len += gcaa; \
}
/* If the pointer is not at the start of a character, move it back until /* If the pointer is not at the start of a character, move it back until
it is. This is called only in UTF-8 mode - we don't put a test within the m acro it is. This is called only in UTF-8 mode - we don't put a test within the m acro
because almost all calls are already within a block of UTF-8 only code. */ because almost all calls are already within a block of UTF-8 only code. */
#define BACKCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr-- #define BACKCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr--
/* Same as above, just in the other direction. */
#define FORWARDCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr++
/* Same as above, but it allows a fully customizable form. */
#define ACROSSCHAR(condition, eptr, action) \
while((condition) && ((eptr) & 0xc0) == 0x80) action
#else /* COMPILE_PCRE8 */
#ifdef COMPILE_PCRE16
/* Tells the biggest code point which can be encoded as a single character.
*/
#define MAX_VALUE_FOR_SINGLE_CHAR 65535
/* Tests whether the code point needs extra characters to decode. */
#define HAS_EXTRALEN(c) (((c) & 0xfc00) == 0xd800)
/* Returns with the additional number of characters if IS_MULTICHAR(c) is T
RUE.
Otherwise it has an undefined behaviour. */
#define GET_EXTRALEN(c) 1
/* Returns TRUE, if the given character is not the first character
of a UTF sequence. */
#define NOT_FIRSTCHAR(c) (((c) & 0xfc00) == 0xdc00)
/* Base macro to pick up the low surrogate of a UTF-16 character, not
advancing the pointer. */
#define GETUTF16(c, eptr) \
{ c = (((c & 0x3ff) << 10) | (eptr[1] & 0x3ff)) + 0x10000; }
/* Get the next UTF-16 character, not advancing the pointer. This is called
when
we know we are in UTF-16 mode. */
#define GETCHAR(c, eptr) \
c = *eptr; \
if ((c & 0xfc00) == 0xd800) GETUTF16(c, eptr);
/* Get the next UTF-16 character, testing for UTF-16 mode, and not advancin
g the
pointer. */
#define GETCHARTEST(c, eptr) \
c = *eptr; \
if (utf && (c & 0xfc00) == 0xd800) GETUTF16(c, eptr);
/* Base macro to pick up the low surrogate of a UTF-16 character, advancing
the pointer. */
#define GETUTF16INC(c, eptr) \
{ c = (((c & 0x3ff) << 10) | (*eptr++ & 0x3ff)) + 0x10000; }
/* Get the next UTF-16 character, advancing the pointer. This is called whe
n we
know we are in UTF-16 mode. */
#define GETCHARINC(c, eptr) \
c = *eptr++; \
if ((c & 0xfc00) == 0xd800) GETUTF16INC(c, eptr);
/* Get the next character, testing for UTF-16 mode, and advancing the point
er.
This is called when we don't know if we are in UTF-16 mode. */
#define GETCHARINCTEST(c, eptr) \
c = *eptr++; \
if (utf && (c & 0xfc00) == 0xd800) GETUTF16INC(c, eptr);
/* Base macro to pick up the low surrogate of a UTF-16 character, not
advancing the pointer, incrementing the length. */
#define GETUTF16LEN(c, eptr, len) \
{ c = (((c & 0x3ff) << 10) | (eptr[1] & 0x3ff)) + 0x10000; len++; }
/* Get the next UTF-16 character, not advancing the pointer, incrementing
length if there is a low surrogate. This is called when we know we are in
UTF-16 mode. */
#define GETCHARLEN(c, eptr, len) \
c = *eptr; \
if ((c & 0xfc00) == 0xd800) GETUTF16LEN(c, eptr, len);
/* Get the next UTF-816character, testing for UTF-16 mode, not advancing th
e
pointer, incrementing length if there is a low surrogate. This is called wh
en
we do not know if we are in UTF-16 mode. */
#define GETCHARLENTEST(c, eptr, len) \
c = *eptr; \
if (utf && (c & 0xfc00) == 0xd800) GETUTF16LEN(c, eptr, len);
/* If the pointer is not at the start of a character, move it back until
it is. This is called only in UTF-16 mode - we don't put a test within the
macro because almost all calls are already within a block of UTF-16 only
code. */
#define BACKCHAR(eptr) if ((*eptr & 0xfc00) == 0xdc00) eptr--
/* Same as above, just in the other direction. */
#define FORWARDCHAR(eptr) if ((*eptr & 0xfc00) == 0xdc00) eptr++
/* Same as above, but it allows a fully customizable form. */
#define ACROSSCHAR(condition, eptr, action) \
if ((condition) && ((eptr) & 0xfc00) == 0xdc00) action
#endif #endif
#endif /* COMPILE_PCRE8 */
#endif /* SUPPORT_UTF */
/* In case there is no definition of offsetof() provided - though any prope r /* In case there is no definition of offsetof() provided - though any prope r
Standard C system should have one. */ Standard C system should have one. */
#ifndef offsetof #ifndef offsetof
#define offsetof(p_type,field) ((size_t)&(((p_type *)0)->field)) #define offsetof(p_type,field) ((size_t)&(((p_type *)0)->field))
#endif #endif
/* These are the public options that can change during matching. */
#define PCRE_IMS (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL)
/* Private flags containing information about the compiled regex. They used to /* Private flags containing information about the compiled regex. They used to
live at the top end of the options word, but that got almost full, so now t hey live at the top end of the options word, but that got almost full, so now t hey
are in a 16-bit flags word. */ are in a 16-bit flags word. From release 8.00, PCRE_NOPARTIAL is unused, as
the restrictions on partial matching have been lifted. It remains for backw
ards
compatibility. */
#define PCRE_NOPARTIAL 0x0001 /* can't use partial with this regex */ #ifdef COMPILE_PCRE8
#define PCRE_FIRSTSET 0x0002 /* first_byte is set */ #define PCRE_MODE 0x0001 /* compiled in 8 bit mode */
#define PCRE_REQCHSET 0x0004 /* req_byte is set */ #endif
#define PCRE_STARTLINE 0x0008 /* start after \n for multiline */ #ifdef COMPILE_PCRE16
#define PCRE_JCHANGED 0x0010 /* j option used in regex */ #define PCRE_MODE 0x0002 /* compiled in 16 bit mode */
#define PCRE_HASCRORLF 0x0020 /* explicit \r or \n in pattern */ #endif
#define PCRE_FIRSTSET 0x0010 /* first_char is set */
#define PCRE_FCH_CASELESS 0x0020 /* caseless first char */
#define PCRE_REQCHSET 0x0040 /* req_byte is set */
#define PCRE_RCH_CASELESS 0x0080 /* caseless requested char */
#define PCRE_STARTLINE 0x0100 /* start after \n for multiline */
#define PCRE_NOPARTIAL 0x0200 /* can't use partial with this regex */
#define PCRE_JCHANGED 0x0400 /* j option used in regex */
#define PCRE_HASCRORLF 0x0800 /* explicit \r or \n in pattern */
#define PCRE_HASTHEN 0x1000 /* pattern contains (*THEN) */
/* Options for the "extra" block produced by pcre_study(). */ /* Flags for the "extra" block produced by pcre_study(). */
#define PCRE_STUDY_MAPPED 0x01 /* a map of starting chars exists */ #define PCRE_STUDY_MAPPED 0x0001 /* a map of starting chars exists */
#define PCRE_STUDY_MINLEN 0x0002 /* a minimum length field exists */
/* Masks for identifying the public options that are permitted at compile /* Masks for identifying the public options that are permitted at compile
time, run time, or study time, respectively. */ time, run time, or study time, respectively. */
#define PCRE_NEWLINE_BITS (PCRE_NEWLINE_CR|PCRE_NEWLINE_LF|PCRE_NEWLINE_ANY | \ #define PCRE_NEWLINE_BITS (PCRE_NEWLINE_CR|PCRE_NEWLINE_LF|PCRE_NEWLINE_ANY | \
PCRE_NEWLINE_ANYCRLF) PCRE_NEWLINE_ANYCRLF)
#define PUBLIC_OPTIONS \ #define PUBLIC_COMPILE_OPTIONS \
(PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \ (PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \
PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8| \ PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8| \
PCRE_NO_AUTO_CAPTURE|PCRE_NO_UTF8_CHECK|PCRE_AUTO_CALLOUT|PCRE_FIRSTLINE | \ PCRE_NO_AUTO_CAPTURE|PCRE_NO_UTF8_CHECK|PCRE_AUTO_CALLOUT|PCRE_FIRSTLINE | \
PCRE_DUPNAMES|PCRE_NEWLINE_BITS|PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE) PCRE_DUPNAMES|PCRE_NEWLINE_BITS|PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE| \
PCRE_JAVASCRIPT_COMPAT|PCRE_UCP|PCRE_NO_START_OPTIMIZE)
#define PUBLIC_EXEC_OPTIONS \ #define PUBLIC_EXEC_OPTIONS \
(PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NO_UTF8_CHECK| (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NOTEMPTY_ATSTAR
\ T| \
PCRE_PARTIAL|PCRE_NEWLINE_BITS|PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE) PCRE_NO_UTF8_CHECK|PCRE_PARTIAL_HARD|PCRE_PARTIAL_SOFT|PCRE_NEWLINE_BITS
| \
PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE|PCRE_NO_START_OPTIMIZE)
#define PUBLIC_DFA_EXEC_OPTIONS \ #define PUBLIC_DFA_EXEC_OPTIONS \
(PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NO_UTF8_CHECK| (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NOTEMPTY_ATSTAR
\ T| \
PCRE_PARTIAL|PCRE_DFA_SHORTEST|PCRE_DFA_RESTART|PCRE_NEWLINE_BITS| \ PCRE_NO_UTF8_CHECK|PCRE_PARTIAL_HARD|PCRE_PARTIAL_SOFT|PCRE_DFA_SHORTEST
PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE) | \
PCRE_DFA_RESTART|PCRE_NEWLINE_BITS|PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE| \
PCRE_NO_START_OPTIMIZE)
#define PUBLIC_STUDY_OPTIONS 0 /* None defined */ #define PUBLIC_STUDY_OPTIONS \
PCRE_STUDY_JIT_COMPILE
/* Magic number to provide a small check against being handed junk. Also us /* Magic number to provide a small check against being handed junk. */
ed
to detect whether a pattern was compiled on a host of different endianness.
*/
#define MAGIC_NUMBER 0x50435245UL /* 'PCRE' */ #define MAGIC_NUMBER 0x50435245UL /* 'PCRE' */
/* This variable is used to detect a loaded regular expression
in different endianness. */
#define REVERSED_MAGIC_NUMBER 0x45524350UL /* 'ERCP' */
/* Negative values for the firstchar and reqchar variables */ /* Negative values for the firstchar and reqchar variables */
#define REQ_UNSET (-2) #define REQ_UNSET (-2)
#define REQ_NONE (-1) #define REQ_NONE (-1)
/* The maximum remaining length of subject we are prepared to search for a /* The maximum remaining length of subject we are prepared to search for a
req_byte match. */ req_byte match. */
#define REQ_BYTE_MAX 1000 #define REQ_BYTE_MAX 1000
/* Flags added to firstbyte or reqbyte; a "non-literal" item is either a /* Miscellaneous definitions. The #ifndef is to pacify compiler warnings in
variable-length repeat, or a anything other than literal characters. */ environments where these macros are defined elsewhere. Unfortunately, there
is no way to do the same for the typedef. */
#define REQ_CASELESS 0x0100 /* indicates caselessness */
#define REQ_VARY 0x0200 /* reqbyte followed non-literal item */
/* Miscellaneous definitions */
typedef int BOOL; typedef int BOOL;
#ifndef FALSE
#define FALSE 0 #define FALSE 0
#define TRUE 1 #define TRUE 1
#endif
/* If PCRE is to support UTF-8 on EBCDIC platforms, we cannot use normal
character constants like '*' because the compiler would emit their EBCDIC c
ode,
which is different from their ASCII/UTF-8 code. Instead we define macros fo
r
the characters so that they always use the ASCII/UTF-8 code when UTF-8 supp
ort
is enabled. When UTF-8 support is not enabled, the definitions use characte
r
literals. Both character and string versions of each character are needed,
and
there are some longer strings as well.
This means that, on EBCDIC platforms, the PCRE library can handle either
EBCDIC, or UTF-8, but not both. To support both in the same compiled librar
y
would need different lookups depending on whether PCRE_UTF8 was set or not.
This would make it impossible to use characters in switch/case statements,
which would reduce performance. For a theoretical use (which nobody has ask
ed
for) in a minority area (EBCDIC platforms), this is not sensible. Any
application that did need both could compile two versions of the library, u
sing
macros to give the functions distinct names. */
#ifndef SUPPORT_UTF
/* UTF-8 support is not enabled; use the platform-dependent character liter
als
so that PCRE works on both ASCII and EBCDIC platforms, in non-UTF-mode only
. */
#define CHAR_HT '\t'
#define CHAR_VT '\v'
#define CHAR_FF '\f'
#define CHAR_CR '\r'
#define CHAR_NL '\n'
#define CHAR_BS '\b'
#define CHAR_BEL '\a'
#ifdef EBCDIC
#define CHAR_ESC '\047'
#define CHAR_DEL '\007'
#else
#define CHAR_ESC '\033'
#define CHAR_DEL '\177'
#endif
#define CHAR_SPACE ' '
#define CHAR_EXCLAMATION_MARK '!'
#define CHAR_QUOTATION_MARK '"'
#define CHAR_NUMBER_SIGN '#'
#define CHAR_DOLLAR_SIGN '$'
#define CHAR_PERCENT_SIGN '%'
#define CHAR_AMPERSAND '&'
#define CHAR_APOSTROPHE '\''
#define CHAR_LEFT_PARENTHESIS '('
#define CHAR_RIGHT_PARENTHESIS ')'
#define CHAR_ASTERISK '*'
#define CHAR_PLUS '+'
#define CHAR_COMMA ','
#define CHAR_MINUS '-'
#define CHAR_DOT '.'
#define CHAR_SLASH '/'
#define CHAR_0 '0'
#define CHAR_1 '1'
#define CHAR_2 '2'
#define CHAR_3 '3'
#define CHAR_4 '4'
#define CHAR_5 '5'
#define CHAR_6 '6'
#define CHAR_7 '7'
#define CHAR_8 '8'
#define CHAR_9 '9'
#define CHAR_COLON ':'
#define CHAR_SEMICOLON ';'
#define CHAR_LESS_THAN_SIGN '<'
#define CHAR_EQUALS_SIGN '='
#define CHAR_GREATER_THAN_SIGN '>'
#define CHAR_QUESTION_MARK '?'
#define CHAR_COMMERCIAL_AT '@'
#define CHAR_A 'A'
#define CHAR_B 'B'
#define CHAR_C 'C'
#define CHAR_D 'D'
#define CHAR_E 'E'
#define CHAR_F 'F'
#define CHAR_G 'G'
#define CHAR_H 'H'
#define CHAR_I 'I'
#define CHAR_J 'J'
#define CHAR_K 'K'
#define CHAR_L 'L'
#define CHAR_M 'M'
#define CHAR_N 'N'
#define CHAR_O 'O'
#define CHAR_P 'P'
#define CHAR_Q 'Q'
#define CHAR_R 'R'
#define CHAR_S 'S'
#define CHAR_T 'T'
#define CHAR_U 'U'
#define CHAR_V 'V'
#define CHAR_W 'W'
#define CHAR_X 'X'
#define CHAR_Y 'Y'
#define CHAR_Z 'Z'
#define CHAR_LEFT_SQUARE_BRACKET '['
#define CHAR_BACKSLASH '\\'
#define CHAR_RIGHT_SQUARE_BRACKET ']'
#define CHAR_CIRCUMFLEX_ACCENT '^'
#define CHAR_UNDERSCORE '_'
#define CHAR_GRAVE_ACCENT '`'
#define CHAR_a 'a'
#define CHAR_b 'b'
#define CHAR_c 'c'
#define CHAR_d 'd'
#define CHAR_e 'e'
#define CHAR_f 'f'
#define CHAR_g 'g'
#define CHAR_h 'h'
#define CHAR_i 'i'
#define CHAR_j 'j'
#define CHAR_k 'k'
#define CHAR_l 'l'
#define CHAR_m 'm'
#define CHAR_n 'n'
#define CHAR_o 'o'
#define CHAR_p 'p'
#define CHAR_q 'q'
#define CHAR_r 'r'
#define CHAR_s 's'
#define CHAR_t 't'
#define CHAR_u 'u'
#define CHAR_v 'v'
#define CHAR_w 'w'
#define CHAR_x 'x'
#define CHAR_y 'y'
#define CHAR_z 'z'
#define CHAR_LEFT_CURLY_BRACKET '{'
#define CHAR_VERTICAL_LINE '|'
#define CHAR_RIGHT_CURLY_BRACKET '}'
#define CHAR_TILDE '~'
#define STR_HT "\t"
#define STR_VT "\v"
#define STR_FF "\f"
#define STR_CR "\r"
#define STR_NL "\n"
#define STR_BS "\b"
#define STR_BEL "\a"
#ifdef EBCDIC
#define STR_ESC "\047"
#define STR_DEL "\007"
#else
#define STR_ESC "\033"
#define STR_DEL "\177"
#endif
#define STR_SPACE " "
#define STR_EXCLAMATION_MARK "!"
#define STR_QUOTATION_MARK "\""
#define STR_NUMBER_SIGN "#"
#define STR_DOLLAR_SIGN "$"
#define STR_PERCENT_SIGN "%"
#define STR_AMPERSAND "&"
#define STR_APOSTROPHE "'"
#define STR_LEFT_PARENTHESIS "("
#define STR_RIGHT_PARENTHESIS ")"
#define STR_ASTERISK "*"
#define STR_PLUS "+"
#define STR_COMMA ","
#define STR_MINUS "-"
#define STR_DOT "."
#define STR_SLASH "/"
#define STR_0 "0"
#define STR_1 "1"
#define STR_2 "2"
#define STR_3 "3"
#define STR_4 "4"
#define STR_5 "5"
#define STR_6 "6"
#define STR_7 "7"
#define STR_8 "8"
#define STR_9 "9"
#define STR_COLON ":"
#define STR_SEMICOLON ";"
#define STR_LESS_THAN_SIGN "<"
#define STR_EQUALS_SIGN "="
#define STR_GREATER_THAN_SIGN ">"
#define STR_QUESTION_MARK "?"
#define STR_COMMERCIAL_AT "@"
#define STR_A "A"
#define STR_B "B"
#define STR_C "C"
#define STR_D "D"
#define STR_E "E"
#define STR_F "F"
#define STR_G "G"
#define STR_H "H"
#define STR_I "I"
#define STR_J "J"
#define STR_K "K"
#define STR_L "L"
#define STR_M "M"
#define STR_N "N"
#define STR_O "O"
#define STR_P "P"
#define STR_Q "Q"
#define STR_R "R"
#define STR_S "S"
#define STR_T "T"
#define STR_U "U"
#define STR_V "V"
#define STR_W "W"
#define STR_X "X"
#define STR_Y "Y"
#define STR_Z "Z"
#define STR_LEFT_SQUARE_BRACKET "["
#define STR_BACKSLASH "\\"
#define STR_RIGHT_SQUARE_BRACKET "]"
#define STR_CIRCUMFLEX_ACCENT "^"
#define STR_UNDERSCORE "_"
#define STR_GRAVE_ACCENT "`"
#define STR_a "a"
#define STR_b "b"
#define STR_c "c"
#define STR_d "d"
#define STR_e "e"
#define STR_f "f"
#define STR_g "g"
#define STR_h "h"
#define STR_i "i"
#define STR_j "j"
#define STR_k "k"
#define STR_l "l"
#define STR_m "m"
#define STR_n "n"
#define STR_o "o"
#define STR_p "p"
#define STR_q "q"
#define STR_r "r"
#define STR_s "s"
#define STR_t "t"
#define STR_u "u"
#define STR_v "v"
#define STR_w "w"
#define STR_x "x"
#define STR_y "y"
#define STR_z "z"
#define STR_LEFT_CURLY_BRACKET "{"
#define STR_VERTICAL_LINE "|"
#define STR_RIGHT_CURLY_BRACKET "}"
#define STR_TILDE "~"
#define STRING_ACCEPT0 "ACCEPT\0"
#define STRING_COMMIT0 "COMMIT\0"
#define STRING_F0 "F\0"
#define STRING_FAIL0 "FAIL\0"
#define STRING_MARK0 "MARK\0"
#define STRING_PRUNE0 "PRUNE\0"
#define STRING_SKIP0 "SKIP\0"
#define STRING_THEN "THEN"
#define STRING_alpha0 "alpha\0"
#define STRING_lower0 "lower\0"
#define STRING_upper0 "upper\0"
#define STRING_alnum0 "alnum\0"
#define STRING_ascii0 "ascii\0"
#define STRING_blank0 "blank\0"
#define STRING_cntrl0 "cntrl\0"
#define STRING_digit0 "digit\0"
#define STRING_graph0 "graph\0"
#define STRING_print0 "print\0"
#define STRING_punct0 "punct\0"
#define STRING_space0 "space\0"
#define STRING_word0 "word\0"
#define STRING_xdigit "xdigit"
#define STRING_DEFINE "DEFINE"
#define STRING_CR_RIGHTPAR "CR)"
#define STRING_LF_RIGHTPAR "LF)"
#define STRING_CRLF_RIGHTPAR "CRLF)"
#define STRING_ANY_RIGHTPAR "ANY)"
#define STRING_ANYCRLF_RIGHTPAR "ANYCRLF)"
#define STRING_BSR_ANYCRLF_RIGHTPAR "BSR_ANYCRLF)"
#define STRING_BSR_UNICODE_RIGHTPAR "BSR_UNICODE)"
#ifdef COMPILE_PCRE8
#define STRING_UTF_RIGHTPAR "UTF8)"
#endif
#ifdef COMPILE_PCRE16
#define STRING_UTF_RIGHTPAR "UTF16)"
#endif
#define STRING_UCP_RIGHTPAR "UCP)"
#define STRING_NO_START_OPT_RIGHTPAR "NO_START_OPT)"
#else /* SUPPORT_UTF */
/* UTF-8 support is enabled; always use UTF-8 (=ASCII) character codes. Thi
s
works in both modes non-EBCDIC platforms, and on EBCDIC platforms in UTF-8
mode
only. */
#define CHAR_HT '\011'
#define CHAR_VT '\013'
#define CHAR_FF '\014'
#define CHAR_CR '\015'
#define CHAR_NL '\012'
#define CHAR_BS '\010'
#define CHAR_BEL '\007'
#define CHAR_ESC '\033'
#define CHAR_DEL '\177'
#define CHAR_SPACE '\040'
#define CHAR_EXCLAMATION_MARK '\041'
#define CHAR_QUOTATION_MARK '\042'
#define CHAR_NUMBER_SIGN '\043'
#define CHAR_DOLLAR_SIGN '\044'
#define CHAR_PERCENT_SIGN '\045'
#define CHAR_AMPERSAND '\046'
#define CHAR_APOSTROPHE '\047'
#define CHAR_LEFT_PARENTHESIS '\050'
#define CHAR_RIGHT_PARENTHESIS '\051'
#define CHAR_ASTERISK '\052'
#define CHAR_PLUS '\053'
#define CHAR_COMMA '\054'
#define CHAR_MINUS '\055'
#define CHAR_DOT '\056'
#define CHAR_SLASH '\057'
#define CHAR_0 '\060'
#define CHAR_1 '\061'
#define CHAR_2 '\062'
#define CHAR_3 '\063'
#define CHAR_4 '\064'
#define CHAR_5 '\065'
#define CHAR_6 '\066'
#define CHAR_7 '\067'
#define CHAR_8 '\070'
#define CHAR_9 '\071'
#define CHAR_COLON '\072'
#define CHAR_SEMICOLON '\073'
#define CHAR_LESS_THAN_SIGN '\074'
#define CHAR_EQUALS_SIGN '\075'
#define CHAR_GREATER_THAN_SIGN '\076'
#define CHAR_QUESTION_MARK '\077'
#define CHAR_COMMERCIAL_AT '\100'
#define CHAR_A '\101'
#define CHAR_B '\102'
#define CHAR_C '\103'
#define CHAR_D '\104'
#define CHAR_E '\105'
#define CHAR_F '\106'
#define CHAR_G '\107'
#define CHAR_H '\110'
#define CHAR_I '\111'
#define CHAR_J '\112'
#define CHAR_K '\113'
#define CHAR_L '\114'
#define CHAR_M '\115'
#define CHAR_N '\116'
#define CHAR_O '\117'
#define CHAR_P '\120'
#define CHAR_Q '\121'
#define CHAR_R '\122'
#define CHAR_S '\123'
#define CHAR_T '\124'
#define CHAR_U '\125'
#define CHAR_V '\126'
#define CHAR_W '\127'
#define CHAR_X '\130'
#define CHAR_Y '\131'
#define CHAR_Z '\132'
#define CHAR_LEFT_SQUARE_BRACKET '\133'
#define CHAR_BACKSLASH '\134'
#define CHAR_RIGHT_SQUARE_BRACKET '\135'
#define CHAR_CIRCUMFLEX_ACCENT '\136'
#define CHAR_UNDERSCORE '\137'
#define CHAR_GRAVE_ACCENT '\140'
#define CHAR_a '\141'
#define CHAR_b '\142'
#define CHAR_c '\143'
#define CHAR_d '\144'
#define CHAR_e '\145'
#define CHAR_f '\146'
#define CHAR_g '\147'
#define CHAR_h '\150'
#define CHAR_i '\151'
#define CHAR_j '\152'
#define CHAR_k '\153'
#define CHAR_l '\154'
#define CHAR_m '\155'
#define CHAR_n '\156'
#define CHAR_o '\157'
#define CHAR_p '\160'
#define CHAR_q '\161'
#define CHAR_r '\162'
#define CHAR_s '\163'
#define CHAR_t '\164'
#define CHAR_u '\165'
#define CHAR_v '\166'
#define CHAR_w '\167'
#define CHAR_x '\170'
#define CHAR_y '\171'
#define CHAR_z '\172'
#define CHAR_LEFT_CURLY_BRACKET '\173'
#define CHAR_VERTICAL_LINE '\174'
#define CHAR_RIGHT_CURLY_BRACKET '\175'
#define CHAR_TILDE '\176'
#define STR_HT "\011"
#define STR_VT "\013"
#define STR_FF "\014"
#define STR_CR "\015"
#define STR_NL "\012"
#define STR_BS "\010"
#define STR_BEL "\007"
#define STR_ESC "\033"
#define STR_DEL "\177"
#define STR_SPACE "\040"
#define STR_EXCLAMATION_MARK "\041"
#define STR_QUOTATION_MARK "\042"
#define STR_NUMBER_SIGN "\043"
#define STR_DOLLAR_SIGN "\044"
#define STR_PERCENT_SIGN "\045"
#define STR_AMPERSAND "\046"
#define STR_APOSTROPHE "\047"
#define STR_LEFT_PARENTHESIS "\050"
#define STR_RIGHT_PARENTHESIS "\051"
#define STR_ASTERISK "\052"
#define STR_PLUS "\053"
#define STR_COMMA "\054"
#define STR_MINUS "\055"
#define STR_DOT "\056"
#define STR_SLASH "\057"
#define STR_0 "\060"
#define STR_1 "\061"
#define STR_2 "\062"
#define STR_3 "\063"
#define STR_4 "\064"
#define STR_5 "\065"
#define STR_6 "\066"
#define STR_7 "\067"
#define STR_8 "\070"
#define STR_9 "\071"
#define STR_COLON "\072"
#define STR_SEMICOLON "\073"
#define STR_LESS_THAN_SIGN "\074"
#define STR_EQUALS_SIGN "\075"
#define STR_GREATER_THAN_SIGN "\076"
#define STR_QUESTION_MARK "\077"
#define STR_COMMERCIAL_AT "\100"
#define STR_A "\101"
#define STR_B "\102"
#define STR_C "\103"
#define STR_D "\104"
#define STR_E "\105"
#define STR_F "\106"
#define STR_G "\107"
#define STR_H "\110"
#define STR_I "\111"
#define STR_J "\112"
#define STR_K "\113"
#define STR_L "\114"
#define STR_M "\115"
#define STR_N "\116"
#define STR_O "\117"
#define STR_P "\120"
#define STR_Q "\121"
#define STR_R "\122"
#define STR_S "\123"
#define STR_T "\124"
#define STR_U "\125"
#define STR_V "\126"
#define STR_W "\127"
#define STR_X "\130"
#define STR_Y "\131"
#define STR_Z "\132"
#define STR_LEFT_SQUARE_BRACKET "\133"
#define STR_BACKSLASH "\134"
#define STR_RIGHT_SQUARE_BRACKET "\135"
#define STR_CIRCUMFLEX_ACCENT "\136"
#define STR_UNDERSCORE "\137"
#define STR_GRAVE_ACCENT "\140"
#define STR_a "\141"
#define STR_b "\142"
#define STR_c "\143"
#define STR_d "\144"
#define STR_e "\145"
#define STR_f "\146"
#define STR_g "\147"
#define STR_h "\150"
#define STR_i "\151"
#define STR_j "\152"
#define STR_k "\153"
#define STR_l "\154"
#define STR_m "\155"
#define STR_n "\156"
#define STR_o "\157"
#define STR_p "\160"
#define STR_q "\161"
#define STR_r "\162"
#define STR_s "\163"
#define STR_t "\164"
#define STR_u "\165"
#define STR_v "\166"
#define STR_w "\167"
#define STR_x "\170"
#define STR_y "\171"
#define STR_z "\172"
#define STR_LEFT_CURLY_BRACKET "\173"
#define STR_VERTICAL_LINE "\174"
#define STR_RIGHT_CURLY_BRACKET "\175"
#define STR_TILDE "\176"
#define STRING_ACCEPT0 STR_A STR_C STR_C STR_E STR_P STR_T "\0
"
#define STRING_COMMIT0 STR_C STR_O STR_M STR_M STR_I STR_T "\0
"
#define STRING_F0 STR_F "\0"
#define STRING_FAIL0 STR_F STR_A STR_I STR_L "\0"
#define STRING_MARK0 STR_M STR_A STR_R STR_K "\0"
#define STRING_PRUNE0 STR_P STR_R STR_U STR_N STR_E "\0"
#define STRING_SKIP0 STR_S STR_K STR_I STR_P "\0"
#define STRING_THEN STR_T STR_H STR_E STR_N
#define STRING_alpha0 STR_a STR_l STR_p STR_h STR_a "\0"
#define STRING_lower0 STR_l STR_o STR_w STR_e STR_r "\0"
#define STRING_upper0 STR_u STR_p STR_p STR_e STR_r "\0"
#define STRING_alnum0 STR_a STR_l STR_n STR_u STR_m "\0"
#define STRING_ascii0 STR_a STR_s STR_c STR_i STR_i "\0"
#define STRING_blank0 STR_b STR_l STR_a STR_n STR_k "\0"
#define STRING_cntrl0 STR_c STR_n STR_t STR_r STR_l "\0"
#define STRING_digit0 STR_d STR_i STR_g STR_i STR_t "\0"
#define STRING_graph0 STR_g STR_r STR_a STR_p STR_h "\0"
#define STRING_print0 STR_p STR_r STR_i STR_n STR_t "\0"
#define STRING_punct0 STR_p STR_u STR_n STR_c STR_t "\0"
#define STRING_space0 STR_s STR_p STR_a STR_c STR_e "\0"
#define STRING_word0 STR_w STR_o STR_r STR_d "\0"
#define STRING_xdigit STR_x STR_d STR_i STR_g STR_i STR_t
#define STRING_DEFINE STR_D STR_E STR_F STR_I STR_N STR_E
#define STRING_CR_RIGHTPAR STR_C STR_R STR_RIGHT_PARENTHESIS
#define STRING_LF_RIGHTPAR STR_L STR_F STR_RIGHT_PARENTHESIS
#define STRING_CRLF_RIGHTPAR STR_C STR_R STR_L STR_F STR_RIGHT_PA
RENTHESIS
#define STRING_ANY_RIGHTPAR STR_A STR_N STR_Y STR_RIGHT_PARENTHE
SIS
#define STRING_ANYCRLF_RIGHTPAR STR_A STR_N STR_Y STR_C STR_R STR_L
STR_F STR_RIGHT_PARENTHESIS
#define STRING_BSR_ANYCRLF_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR
_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS
#define STRING_BSR_UNICODE_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR
_U STR_N STR_I STR_C STR_O STR_D STR_E STR_RIGHT_PARENTHESIS
#ifdef COMPILE_PCRE8
#define STRING_UTF_RIGHTPAR STR_U STR_T STR_F STR_8 STR_RIGHT_PA
RENTHESIS
#endif
#ifdef COMPILE_PCRE16
#define STRING_UTF_RIGHTPAR STR_U STR_T STR_F STR_1 STR_6 STR_RI
GHT_PARENTHESIS
#endif
#define STRING_UCP_RIGHTPAR STR_U STR_C STR_P STR_RIGHT_PARENTHE
SIS
#define STRING_NO_START_OPT_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_S STR
_T STR_A STR_R STR_T STR_UNDERSCORE STR_O STR_P STR_T STR_RIGHT_PARENTHESIS
#endif /* SUPPORT_UTF */
/* Escape items that are just an encoding of a particular data value. */ /* Escape items that are just an encoding of a particular data value. */
#ifndef ESC_e #ifndef ESC_e
#define ESC_e 27 #define ESC_e CHAR_ESC
#endif #endif
#ifndef ESC_f #ifndef ESC_f
#define ESC_f '\f' #define ESC_f CHAR_FF
#endif #endif
#ifndef ESC_n #ifndef ESC_n
#define ESC_n '\n' #define ESC_n CHAR_NL
#endif #endif
#ifndef ESC_r #ifndef ESC_r
#define ESC_r '\r' #define ESC_r CHAR_CR
#endif #endif
/* We can't officially use ESC_t because it is a POSIX reserved identifier /* We can't officially use ESC_t because it is a POSIX reserved identifier
(presumably because of all the others like size_t). */ (presumably because of all the others like size_t). */
#ifndef ESC_tee #ifndef ESC_tee
#define ESC_tee '\t' #define ESC_tee CHAR_HT
#endif #endif
/* Codes for different types of Unicode property */ /* Codes for different types of Unicode property */
#define PT_ANY 0 /* Any property - matches all chars */ #define PT_ANY 0 /* Any property - matches all chars */
#define PT_LAMP 1 /* L& - the union of Lu, Ll, Lt */ #define PT_LAMP 1 /* L& - the union of Lu, Ll, Lt */
#define PT_GC 2 /* General characteristic (e.g. L) */ #define PT_GC 2 /* Specified general characteristic (e.g. L) */
#define PT_PC 3 /* Particular characteristic (e.g. Lu) */ #define PT_PC 3 /* Specified particular characteristic (e.g. Lu)
*/
#define PT_SC 4 /* Script (e.g. Han) */ #define PT_SC 4 /* Script (e.g. Han) */
#define PT_ALNUM 5 /* Alphanumeric - the union of L and N */
#define PT_SPACE 6 /* Perl space - Z plus 9,10,12,13 */
#define PT_PXSPACE 7 /* POSIX space - Z plus 9,10,11,12,13 */
#define PT_WORD 8 /* Word - L plus N plus underscore */
/* Flag bits and data types for the extended class (OP_XCLASS) for classes that /* Flag bits and data types for the extended class (OP_XCLASS) for classes that
contain UTF-8 characters with values greater than 255. */ contain characters with values greater than 255. */
#define XCL_NOT 0x01 /* Flag: this is a negative class */ #define XCL_NOT 0x01 /* Flag: this is a negative class */
#define XCL_MAP 0x02 /* Flag: a 32-byte map is present */ #define XCL_MAP 0x02 /* Flag: a 32-byte map is present */
#define XCL_END 0 /* Marks end of individual items */ #define XCL_END 0 /* Marks end of individual items */
#define XCL_SINGLE 1 /* Single item (one multibyte char) follows */ #define XCL_SINGLE 1 /* Single item (one multibyte char) follows */
#define XCL_RANGE 2 /* A range (two multibyte chars) follows */ #define XCL_RANGE 2 /* A range (two multibyte chars) follows */
#define XCL_PROP 3 /* Unicode property (2-byte property code follow s) */ #define XCL_PROP 3 /* Unicode property (2-byte property code follow s) */
#define XCL_NOTPROP 4 /* Unicode inverted property (ditto) */ #define XCL_NOTPROP 4 /* Unicode inverted property (ditto) */
/* These are escaped items that aren't just an encoding of a particular dat a /* These are escaped items that aren't just an encoding of a particular dat a
value such as \n. They must have non-zero values, as check_escape() returns value such as \n. They must have non-zero values, as check_escape() returns
their negation. Also, they must appear in the same order as in the opcode their negation. Also, they must appear in the same order as in the opcode
definitions below, up to ESC_z. There's a dummy for OP_ANY because it definitions below, up to ESC_z. There's a dummy for OP_ALLANY because it
corresponds to "." rather than an escape sequence. The final one must be corresponds to "." in DOTALL mode rather than an escape sequence. It is als
ESC_REF as subsequent values are used for backreferences (\1, \2, \3, etc). o
There are two tests in the code for an escape greater than ESC_b and less t used for [^] in JavaScript compatibility mode, and for \C in non-utf mode.
han In
ESC_Z to detect the types that may be repeated. These are the types that non-DOTALL mode, "." behaves like \N.
consume characters. If any new escapes are put in between that don't consum
e a The special values ESC_DU, ESC_du, etc. are used instead of ESC_D, ESC_d, e
character, that code will have to change. */ tc.
when PCRE_UCP is set, when replacement of \d etc by \p sequences is require
d.
They must be contiguous, and remain in order so that the replacements can b
e
looked up from a table.
The final escape must be ESC_REF as subsequent values are used for
backreferences (\1, \2, \3, etc). There are two tests in the code for an es
cape
greater than ESC_b and less than ESC_Z to detect the types that may be
repeated. These are the types that consume characters. If any new escapes a
re
put in between that don't consume a character, that code will have to chang
e.
*/
enum { ESC_A = 1, ESC_G, ESC_K, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, enum { ESC_A = 1, ESC_G, ESC_K, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s,
ESC_W, ESC_w, ESC_dum1, ESC_C, ESC_P, ESC_p, ESC_R, ESC_H, ESC_h, ESC_W, ESC_w, ESC_N, ESC_dum, ESC_C, ESC_P, ESC_p, ESC_R, ESC_H,
ESC_V, ESC_v, ESC_X, ESC_Z, ESC_z, ESC_E, ESC_Q, ESC_k, ESC_REF }; ESC_h, ESC_V, ESC_v, ESC_X, ESC_Z, ESC_z,
ESC_E, ESC_Q, ESC_g, ESC_k,
ESC_DU, ESC_du, ESC_SU, ESC_su, ESC_WU, ESC_wu,
ESC_REF };
/* Opcode table: Starting from 1 (i.e. after OP_END), the values up to /* Opcode table: Starting from 1 (i.e. after OP_END), the values up to
OP_EOD must correspond in order to the list of escapes immediately above. OP_EOD must correspond in order to the list of escapes immediately above.
*** NOTE NOTE NOTE *** Whenever this list is updated, the two macro definit ions *** NOTE NOTE NOTE *** Whenever this list is updated, the two macro definit ions
that follow must also be updated to match. There is also a table called that follow must also be updated to match. There are also tables called
"coptable" in pcre_dfa_exec.c that must be updated. */ "coptable" and "poptable" in pcre_dfa_exec.c that must be updated. */
enum { enum {
OP_END, /* 0 End of pattern */ OP_END, /* 0 End of pattern */
/* Values corresponding to backslashed metacharacters */ /* Values corresponding to backslashed metacharacters */
OP_SOD, /* 1 Start of data: \A */ OP_SOD, /* 1 Start of data: \A */
OP_SOM, /* 2 Start of match (subject + offset): \G */ OP_SOM, /* 2 Start of match (subject + offset): \G */
OP_SET_SOM, /* 3 Set start of match (\K) */ OP_SET_SOM, /* 3 Set start of match (\K) */
OP_NOT_WORD_BOUNDARY, /* 4 \B */ OP_NOT_WORD_BOUNDARY, /* 4 \B */
OP_WORD_BOUNDARY, /* 5 \b */ OP_WORD_BOUNDARY, /* 5 \b */
OP_NOT_DIGIT, /* 6 \D */ OP_NOT_DIGIT, /* 6 \D */
OP_DIGIT, /* 7 \d */ OP_DIGIT, /* 7 \d */
OP_NOT_WHITESPACE, /* 8 \S */ OP_NOT_WHITESPACE, /* 8 \S */
OP_WHITESPACE, /* 9 \s */ OP_WHITESPACE, /* 9 \s */
OP_NOT_WORDCHAR, /* 10 \W */ OP_NOT_WORDCHAR, /* 10 \W */
OP_WORDCHAR, /* 11 \w */ OP_WORDCHAR, /* 11 \w */
OP_ANY, /* 12 Match any character */
OP_ANYBYTE, /* 13 Match any byte (\C); different to OP_ANY for UTF
-8 */
OP_NOTPROP, /* 14 \P (not Unicode property) */
OP_PROP, /* 15 \p (Unicode property) */
OP_ANYNL, /* 16 \R (any newline sequence) */
OP_NOT_HSPACE, /* 17 \H (not horizontal whitespace) */
OP_HSPACE, /* 18 \h (horizontal whitespace) */
OP_NOT_VSPACE, /* 19 \V (not vertical whitespace) */
OP_VSPACE, /* 20 \v (vertical whitespace) */
OP_EXTUNI, /* 21 \X (extended Unicode sequence */
OP_EODN, /* 22 End of data or \n at end of data: \Z. */
OP_EOD, /* 23 End of data: \z */
OP_OPT, /* 24 Set runtime options */
OP_CIRC, /* 25 Start of line - varies with multiline switch */
OP_DOLL, /* 26 End of line - varies with multiline switch */
OP_CHAR, /* 27 Match one character, casefully */
OP_CHARNC, /* 28 Match one character, caselessly */
OP_NOT, /* 29 Match one character, not the following one */
OP_STAR, /* 30 The maximizing and minimizing versions of */
OP_MINSTAR, /* 31 these six opcodes must come in pairs, with */
OP_PLUS, /* 32 the minimizing one second. */
OP_MINPLUS, /* 33 This first set applies to single characters.*/
OP_QUERY, /* 34 */
OP_MINQUERY, /* 35 */
OP_UPTO, /* 36 From 0 to n matches */
OP_MINUPTO, /* 37 */
OP_EXACT, /* 38 Exactly n matches */
OP_POSSTAR, /* 39 Possessified star */
OP_POSPLUS, /* 40 Possessified plus */
OP_POSQUERY, /* 41 Posesssified query */
OP_POSUPTO, /* 42 Possessified upto */
OP_NOTSTAR, /* 43 The maximizing and minimizing versions of */
OP_NOTMINSTAR, /* 44 these six opcodes must come in pairs, with */
OP_NOTPLUS, /* 45 the minimizing one second. They must be in */
OP_NOTMINPLUS, /* 46 exactly the same order as those above. */
OP_NOTQUERY, /* 47 This set applies to "not" single characters. */
OP_NOTMINQUERY, /* 48 */
OP_NOTUPTO, /* 49 From 0 to n matches */
OP_NOTMINUPTO, /* 50 */
OP_NOTEXACT, /* 51 Exactly n matches */
OP_NOTPOSSTAR, /* 52 Possessified versions */
OP_NOTPOSPLUS, /* 53 */
OP_NOTPOSQUERY, /* 54 */
OP_NOTPOSUPTO, /* 55 */
OP_TYPESTAR, /* 56 The maximizing and minimizing versions of */
OP_TYPEMINSTAR, /* 57 these six opcodes must come in pairs, with */
OP_TYPEPLUS, /* 58 the minimizing one second. These codes must */
OP_TYPEMINPLUS, /* 59 be in exactly the same order as those above. */
OP_TYPEQUERY, /* 60 This set applies to character types such as \d *
/
OP_TYPEMINQUERY, /* 61 */
OP_TYPEUPTO, /* 62 From 0 to n matches */
OP_TYPEMINUPTO, /* 63 */
OP_TYPEEXACT, /* 64 Exactly n matches */
OP_TYPEPOSSTAR, /* 65 Possessified versions */
OP_TYPEPOSPLUS, /* 66 */
OP_TYPEPOSQUERY, /* 67 */
OP_TYPEPOSUPTO, /* 68 */
OP_CRSTAR, /* 69 The maximizing and minimizing versions of */
OP_CRMINSTAR, /* 70 all these opcodes must come in pairs, with */
OP_CRPLUS, /* 71 the minimizing one second. These codes must */
OP_CRMINPLUS, /* 72 be in exactly the same order as those above. */
OP_CRQUERY, /* 73 These are for character classes and back refs */
OP_CRMINQUERY, /* 74 */
OP_CRRANGE, /* 75 These are different to the three sets above. */
OP_CRMINRANGE, /* 76 */
OP_CLASS, /* 77 Match a character class, chars < 256 only */
OP_NCLASS, /* 78 Same, but the bitmap was created from a negative
class - the difference is relevant only when a U
TF-8
character > 255 is encountered. */
OP_XCLASS, /* 79 Extended class for handling UTF-8 chars within t
he
class. This does both positive and negative. */
OP_REF, /* 80 Match a back reference */
OP_RECURSE, /* 81 Match a numbered subpattern (possibly recursive)
*/
OP_CALLOUT, /* 82 Call out to external function if provided */
OP_ALT, /* 83 Start of alternation */
OP_KET, /* 84 End of group that doesn't have an unbounded repe
at */
OP_KETRMAX, /* 85 These two must remain together and in this */
OP_KETRMIN, /* 86 order. They are for groups the repeat for ever.
*/
/* The assertions must come before BRA, CBRA, ONCE, and COND.*/
OP_ASSERT, /* 87 Positive lookahead */
OP_ASSERT_NOT, /* 88 Negative lookahead */
OP_ASSERTBACK, /* 89 Positive lookbehind */
OP_ASSERTBACK_NOT, /* 90 Negative lookbehind */
OP_REVERSE, /* 91 Move pointer back - used in lookbehind assertion
s */
/* ONCE, BRA, CBRA, and COND must come after the assertions, with ONCE fi
rst,
as there's a test for >= ONCE for a subpattern that isn't an assertion. *
/
OP_ONCE, /* 92 Atomic group */
OP_BRA, /* 93 Start of non-capturing bracket */
OP_CBRA, /* 94 Start of capturing bracket */
OP_COND, /* 95 Conditional group */
/* These three must follow the previous three, in the same order. There's OP_ANY, /* 12 Match any character except newline */
a OP_ALLANY, /* 13 Match any character */
check for >= SBRA to distinguish the two sets. */ OP_ANYBYTE, /* 14 Match any byte (\C); different to OP_ANY for UTF
-8 */
OP_NOTPROP, /* 15 \P (not Unicode property) */
OP_PROP, /* 16 \p (Unicode property) */
OP_ANYNL, /* 17 \R (any newline sequence) */
OP_NOT_HSPACE, /* 18 \H (not horizontal whitespace) */
OP_HSPACE, /* 19 \h (horizontal whitespace) */
OP_NOT_VSPACE, /* 20 \V (not vertical whitespace) */
OP_VSPACE, /* 21 \v (vertical whitespace) */
OP_EXTUNI, /* 22 \X (extended Unicode sequence */
OP_EODN, /* 23 End of data or \n at end of data: \Z. */
OP_EOD, /* 24 End of data: \z */
OP_CIRC, /* 25 Start of line - not multiline */
OP_CIRCM, /* 26 Start of line - multiline */
OP_DOLL, /* 27 End of line - not multiline */
OP_DOLLM, /* 28 End of line - multiline */
OP_CHAR, /* 29 Match one character, casefully */
OP_CHARI, /* 30 Match one character, caselessly */
OP_NOT, /* 31 Match one character, not the given one, casefull
y */
OP_NOTI, /* 32 Match one character, not the given one, caseless
ly */
/* The following sets of 13 opcodes must always be kept in step because
the offset from the first one is used to generate the others. */
/**** Single characters, caseful, must precede the caseless ones ****/
OP_STAR, /* 33 The maximizing and minimizing versions of */
OP_MINSTAR, /* 34 these six opcodes must come in pairs, with */
OP_PLUS, /* 35 the minimizing one second. */
OP_MINPLUS, /* 36 */
OP_QUERY, /* 37 */
OP_MINQUERY, /* 38 */
OP_UPTO, /* 39 From 0 to n matches of one character, caseful*/
OP_MINUPTO, /* 40 */
OP_EXACT, /* 41 Exactly n matches */
OP_POSSTAR, /* 42 Possessified star, caseful */
OP_POSPLUS, /* 43 Possessified plus, caseful */
OP_POSQUERY, /* 44 Posesssified query, caseful */
OP_POSUPTO, /* 45 Possessified upto, caseful */
/**** Single characters, caseless, must follow the caseful ones */
OP_STARI, /* 46 */
OP_MINSTARI, /* 47 */
OP_PLUSI, /* 48 */
OP_MINPLUSI, /* 49 */
OP_QUERYI, /* 50 */
OP_MINQUERYI, /* 51 */
OP_UPTOI, /* 52 From 0 to n matches of one character, caseless *
/
OP_MINUPTOI, /* 53 */
OP_EXACTI, /* 54 */
OP_POSSTARI, /* 55 Possessified star, caseless */
OP_POSPLUSI, /* 56 Possessified plus, caseless */
OP_POSQUERYI, /* 57 Posesssified query, caseless */
OP_POSUPTOI, /* 58 Possessified upto, caseless */
/**** The negated ones must follow the non-negated ones, and match them *
***/
/**** Negated single character, caseful; must precede the caseless ones *
***/
OP_NOTSTAR, /* 59 The maximizing and minimizing versions of */
OP_NOTMINSTAR, /* 60 these six opcodes must come in pairs, with */
OP_NOTPLUS, /* 61 the minimizing one second. They must be in */
OP_NOTMINPLUS, /* 62 exactly the same order as those above. */
OP_NOTQUERY, /* 63 */
OP_NOTMINQUERY, /* 64 */
OP_NOTUPTO, /* 65 From 0 to n matches, caseful */
OP_NOTMINUPTO, /* 66 */
OP_NOTEXACT, /* 67 Exactly n matches */
OP_NOTPOSSTAR, /* 68 Possessified versions, caseful */
OP_NOTPOSPLUS, /* 69 */
OP_NOTPOSQUERY, /* 70 */
OP_NOTPOSUPTO, /* 71 */
/**** Negated single character, caseless; must follow the caseful ones **
**/
OP_NOTSTARI, /* 72 */
OP_NOTMINSTARI, /* 73 */
OP_NOTPLUSI, /* 74 */
OP_NOTMINPLUSI, /* 75 */
OP_NOTQUERYI, /* 76 */
OP_NOTMINQUERYI, /* 77 */
OP_NOTUPTOI, /* 78 From 0 to n matches, caseless */
OP_NOTMINUPTOI, /* 79 */
OP_NOTEXACTI, /* 80 Exactly n matches */
OP_NOTPOSSTARI, /* 81 Possessified versions, caseless */
OP_NOTPOSPLUSI, /* 82 */
OP_NOTPOSQUERYI, /* 83 */
OP_NOTPOSUPTOI, /* 84 */
/**** Character types ****/
OP_TYPESTAR, /* 85 The maximizing and minimizing versions of */
OP_TYPEMINSTAR, /* 86 these six opcodes must come in pairs, with */
OP_TYPEPLUS, /* 87 the minimizing one second. These codes must */
OP_TYPEMINPLUS, /* 88 be in exactly the same order as those above. */
OP_TYPEQUERY, /* 89 */
OP_TYPEMINQUERY, /* 90 */
OP_TYPEUPTO, /* 91 From 0 to n matches */
OP_TYPEMINUPTO, /* 92 */
OP_TYPEEXACT, /* 93 Exactly n matches */
OP_TYPEPOSSTAR, /* 94 Possessified versions */
OP_TYPEPOSPLUS, /* 95 */
OP_TYPEPOSQUERY, /* 96 */
OP_TYPEPOSUPTO, /* 97 */
/* These are used for character classes and back references; only the
first six are the same as the sets above. */
OP_CRSTAR, /* 98 The maximizing and minimizing versions of */
OP_CRMINSTAR, /* 99 all these opcodes must come in pairs, with */
OP_CRPLUS, /* 100 the minimizing one second. These codes must */
OP_CRMINPLUS, /* 101 be in exactly the same order as those above. */
OP_CRQUERY, /* 102 */
OP_CRMINQUERY, /* 103 */
OP_CRRANGE, /* 104 These are different to the three sets above. */
OP_CRMINRANGE, /* 105 */
/* End of quantifier opcodes */
OP_CLASS, /* 106 Match a character class, chars < 256 only */
OP_NCLASS, /* 107 Same, but the bitmap was created from a negativ
e
class - the difference is relevant only when
a
character > 255 is encountered. */
OP_XCLASS, /* 108 Extended class for handling > 255 chars within
the
class. This does both positive and negative.
*/
OP_REF, /* 109 Match a back reference, casefully */
OP_REFI, /* 110 Match a back reference, caselessly */
OP_RECURSE, /* 111 Match a numbered subpattern (possibly recursive
) */
OP_CALLOUT, /* 112 Call out to external function if provided */
OP_ALT, /* 113 Start of alternation */
OP_KET, /* 114 End of group that doesn't have an unbounded rep
eat */
OP_KETRMAX, /* 115 These two must remain together and in this */
OP_KETRMIN, /* 116 order. They are for groups the repeat for ever.
*/
OP_KETRPOS, /* 117 Possessive unlimited repeat. */
/* The assertions must come before BRA, CBRA, ONCE, and COND, and the fou
r
asserts must remain in order. */
OP_REVERSE, /* 118 Move pointer back - used in lookbehind assertio
ns */
OP_ASSERT, /* 119 Positive lookahead */
OP_ASSERT_NOT, /* 120 Negative lookahead */
OP_ASSERTBACK, /* 121 Positive lookbehind */
OP_ASSERTBACK_NOT, /* 122 Negative lookbehind */
/* ONCE, ONCE_NC, BRA, BRAPOS, CBRA, CBRAPOS, and COND must come immediat
ely
after the assertions, with ONCE first, as there's a test for >= ONCE for
a
subpattern that isn't an assertion. The POS versions must immediately fol
low
the non-POS versions in each case. */
OP_ONCE, /* 123 Atomic group, contains captures */
OP_ONCE_NC, /* 124 Atomic group containing no captures */
OP_BRA, /* 125 Start of non-capturing bracket */
OP_BRAPOS, /* 126 Ditto, with unlimited, possessive repeat */
OP_CBRA, /* 127 Start of capturing bracket */
OP_CBRAPOS, /* 128 Ditto, with unlimited, possessive repeat */
OP_COND, /* 129 Conditional group */
OP_SBRA, /* 96 Start of non-capturing bracket, check empty */ /* These five must follow the previous five, in the same order. There's a
OP_SCBRA, /* 97 Start of capturing bracket, check empty */ check for >= SBRA to distinguish the two sets. */
OP_SCOND, /* 98 Conditional group, check empty */
OP_CREF, /* 99 Used to hold a capture number as condition */
OP_RREF, /* 100 Used to hold a recursion number as condition */
OP_DEF, /* 101 The DEFINE condition */
OP_BRAZERO, /* 102 These two must remain together and in this */ OP_SBRA, /* 130 Start of non-capturing bracket, check empty */
OP_BRAMINZERO, /* 103 order. */ OP_SBRAPOS, /* 131 Ditto, with unlimited, possessive repeat */
OP_SCBRA, /* 132 Start of capturing bracket, check empty */
OP_SCBRAPOS, /* 133 Ditto, with unlimited, possessive repeat */
OP_SCOND, /* 134 Conditional group, check empty */
/* The next two pairs must (respectively) be kept together. */
OP_CREF, /* 135 Used to hold a capture number as condition */
OP_NCREF, /* 136 Same, but generated by a name reference*/
OP_RREF, /* 137 Used to hold a recursion number as condition */
OP_NRREF, /* 138 Same, but generated by a name reference*/
OP_DEF, /* 139 The DEFINE condition */
OP_BRAZERO, /* 140 These two must remain together and in this */
OP_BRAMINZERO, /* 141 order. */
OP_BRAPOSZERO, /* 142 */
/* These are backtracking control verbs */ /* These are backtracking control verbs */
OP_PRUNE, /* 104 */ OP_MARK, /* 143 always has an argument */
OP_SKIP, /* 105 */ OP_PRUNE, /* 144 */
OP_THEN, /* 106 */ OP_PRUNE_ARG, /* 145 same, but with argument */
OP_COMMIT, /* 107 */ OP_SKIP, /* 146 */
OP_SKIP_ARG, /* 147 same, but with argument */
OP_THEN, /* 148 */
OP_THEN_ARG, /* 149 same, but with argument */
OP_COMMIT, /* 150 */
/* These are forced failure and success verbs */ /* These are forced failure and success verbs */
OP_FAIL, /* 108 */ OP_FAIL, /* 151 */
OP_ACCEPT /* 109 */ OP_ACCEPT, /* 152 */
OP_ASSERT_ACCEPT, /* 153 Used inside assertions */
OP_CLOSE, /* 154 Used before OP_ACCEPT to close open captures */
/* This is used to skip a subpattern with a {0} quantifier */
OP_SKIPZERO, /* 155 */
/* This is not an opcode, but is used to check that tables indexed by opc
ode
are the correct length, in order to catch updating errors - there have be
en
some in the past. */
OP_TABLE_LENGTH
}; };
/* *** NOTE NOTE NOTE *** Whenever the list above is updated, the two macro
definitions that follow must also be updated to match. There are also table
s
called "coptable" and "poptable" in pcre_dfa_exec.c that must be updated. *
/
/* This macro defines textual names for all the opcodes. These are used onl y /* This macro defines textual names for all the opcodes. These are used onl y
for debugging. The macro is referenced only in pcre_printint.c. */ for debugging, and some of them are only partial names. The macro is refere
nced
only in pcre_printint.c, which fills out the full names in many cases (and
in
some cases doesn't actually use these names at all). */
#define OP_NAME_LIST \ #define OP_NAME_LIST \
"End", "\\A", "\\G", "\\K", "\\B", "\\b", "\\D", "\\d", \ "End", "\\A", "\\G", "\\K", "\\B", "\\b", "\\D", "\\d", \
"\\S", "\\s", "\\W", "\\w", "Any", "Anybyte", \ "\\S", "\\s", "\\W", "\\w", "Any", "AllAny", "Anybyte", \
"notprop", "prop", "\\R", "\\H", "\\h", "\\V", "\\v", \ "notprop", "prop", "\\R", "\\H", "\\h", "\\V", "\\v", \
"extuni", "\\Z", "\\z", \ "extuni", "\\Z", "\\z", \
"Opt", "^", "$", "char", "charnc", "not", \ "^", "^", "$", "$", "char", "chari", "not", "noti", \
"*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ "*", "*?", "+", "+?", "?", "??", \
"{", "{", "{", \
"*+","++", "?+", "{", \ "*+","++", "?+", "{", \
"*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ "*", "*?", "+", "+?", "?", "??", \
"{", "{", "{", \
"*+","++", "?+", "{", \
"*", "*?", "+", "+?", "?", "??", \
"{", "{", "{", \
"*+","++", "?+", "{", \
"*", "*?", "+", "+?", "?", "??", \
"{", "{", "{", \
"*+","++", "?+", "{", \ "*+","++", "?+", "{", \
"*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \
"*+","++", "?+", "{", \ "*+","++", "?+", "{", \
"*", "*?", "+", "+?", "?", "??", "{", "{", \ "*", "*?", "+", "+?", "?", "??", "{", "{", \
"class", "nclass", "xclass", "Ref", "Recurse", "Callout", \ "class", "nclass", "xclass", "Ref", "Refi", \
"Alt", "Ket", "KetRmax", "KetRmin", "Assert", "Assert not", \ "Recurse", "Callout", \
"AssertB", "AssertB not", "Reverse", \ "Alt", "Ket", "KetRmax", "KetRmin", "KetRpos", \
"Once", "Bra", "CBra", "Cond", "SBra", "SCBra", "SCond", \ "Reverse", "Assert", "Assert not", "AssertB", "AssertB not", \
"Cond ref", "Cond rec", "Cond def", "Brazero", "Braminzero", \ "Once", "Once_NC", \
"*PRUNE", "*SKIP", "*THEN", "*COMMIT", "*FAIL", "*ACCEPT" "Bra", "BraPos", "CBra", "CBraPos", \
"Cond", \
"SBra", "SBraPos", "SCBra", "SCBraPos", \
"SCond", \
"Cond ref", "Cond nref", "Cond rec", "Cond nrec", "Cond def", \
"Brazero", "Braminzero", "Braposzero", \
"*MARK", "*PRUNE", "*PRUNE", "*SKIP", "*SKIP", \
"*THEN", "*THEN", "*COMMIT", "*FAIL", \
"*ACCEPT", "*ASSERT_ACCEPT", \
"Close", "Skip zero"
/* This macro defines the length of fixed length operations in the compiled /* This macro defines the length of fixed length operations in the compiled
regex. The lengths are used when searching for specific things, and also in the regex. The lengths are used when searching for specific things, and also in the
debugging printing of a compiled regex. We use a macro so that it can be debugging printing of a compiled regex. We use a macro so that it can be
defined close to the definitions of the opcodes themselves. defined close to the definitions of the opcodes themselves.
As things have been extended, some of these are no longer fixed lenths, but are As things have been extended, some of these are no longer fixed lenths, but are
minima instead. For example, the length of a single-character repeat may va ry minima instead. For example, the length of a single-character repeat may va ry
in UTF-8 mode. The code that uses this table must know about such things. * / in UTF-8 mode. The code that uses this table must know about such things. * /
#define OP_LENGTHS \ #define OP_LENGTHS \
1, /* End */ \ 1, /* End */ \
1, 1, 1, 1, 1, /* \A, \G, \K, \B, \b */ \ 1, 1, 1, 1, 1, /* \A, \G, \K, \B, \b */ \
1, 1, 1, 1, 1, 1, /* \D, \d, \S, \s, \W, \w */ \ 1, 1, 1, 1, 1, 1, /* \D, \d, \S, \s, \W, \w */ \
1, 1, /* Any, Anybyte 1, 1, 1, /* Any, AllAny, Anybyte
*/ \ */ \
3, 3, 1, /* NOTPROP, PROP, EXTUNI 3, 3, /* \P, \p
*/ \ */ \
1, 1, 1, 1, 1, /* \R, \H, \h, \V, \v */ \ 1, 1, 1, 1, 1, /* \R, \H, \h, \V, \v */ \
1, 1, 2, 1, 1, /* \Z, \z, Opt, ^, $ 1, /* \X
*/ \ */ \
1, 1, 1, 1, 1, 1, /* \Z, \z, ^, ^M, $, $M
*/ \
2, /* Char - the minimum length */ \ 2, /* Char - the minimum length */ \
2, /* Charnc - the minimum length */ \ 2, /* Chari - the minimum length */ \
2, /* not */ \ 2, /* not */ \
/* Positive single-char repeats ** These are 2, /* noti
*/ \ */ \
2, 2, 2, 2, 2, 2, /* *, *?, +, +?, ?, ?? ** minima in /* Positive single-char repeats ** These are
*/ \ */ \
4, 4, 4, /* upto, minupto, exact ** UTF-8 mode 2, 2, 2, 2, 2, 2, /* *, *?, +, +?, ?, ?? ** minima in
*/ \ */ \
2, 2, 2, 4, /* *+, ++, ?+, upto+ 2+IMM2_SIZE, 2+IMM2_SIZE, /* upto, minupto ** mode
*/ \ */ \
2+IMM2_SIZE, /* exact
*/ \
2, 2, 2, 2+IMM2_SIZE, /* *+, ++, ?+, upto+
*/ \
2, 2, 2, 2, 2, 2, /* *I, *?I, +I, +?I, ?I, ??I ** UTF-8
*/ \
2+IMM2_SIZE, 2+IMM2_SIZE, /* upto I, minupto I
*/ \
2+IMM2_SIZE, /* exact I
*/ \
2, 2, 2, 2+IMM2_SIZE, /* *+I, ++I, ?+I, upto+I
*/ \
/* Negative single-char repeats - only for chars < 256 */ \ /* Negative single-char repeats - only for chars < 256 */ \
2, 2, 2, 2, 2, 2, /* NOT *, *?, +, +?, ?, ?? */ \ 2, 2, 2, 2, 2, 2, /* NOT *, *?, +, +?, ?, ?? */ \
4, 4, 4, /* NOT upto, minupto, exact 2+IMM2_SIZE, 2+IMM2_SIZE, /* NOT upto, minupto
*/ \ */ \
2, 2, 2, 4, /* Possessive *, +, ?, upto 2+IMM2_SIZE, /* NOT exact
*/ \ */ \
2, 2, 2, 2+IMM2_SIZE, /* Possessive NOT *, +, ?, upto
*/ \
2, 2, 2, 2, 2, 2, /* NOT *I, *?I, +I, +?I, ?I, ??I
*/ \
2+IMM2_SIZE, 2+IMM2_SIZE, /* NOT upto I, minupto I
*/ \
2+IMM2_SIZE, /* NOT exact I
*/ \
2, 2, 2, 2+IMM2_SIZE, /* Possessive NOT *I, +I, ?I, upto I
*/ \
/* Positive type repeats */ \ /* Positive type repeats */ \
2, 2, 2, 2, 2, 2, /* Type *, *?, +, +?, ?, ?? */ \ 2, 2, 2, 2, 2, 2, /* Type *, *?, +, +?, ?, ?? */ \
4, 4, 4, /* Type upto, minupto, exact 2+IMM2_SIZE, 2+IMM2_SIZE, /* Type upto, minupto
*/ \ */ \
2, 2, 2, 4, /* Possessive *+, ++, ?+, upto+ 2+IMM2_SIZE, /* Type exact
*/ \ */ \
2, 2, 2, 2+IMM2_SIZE, /* Possessive *+, ++, ?+, upto+
*/ \
/* Character class & ref repeats */ \ /* Character class & ref repeats */ \
1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ \ 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ \
5, 5, /* CRRANGE, CRMINRANGE 1+2*IMM2_SIZE, 1+2*IMM2_SIZE, /* CRRANGE, CRMINRANGE
*/ \ */ \
33, /* CLASS 1+(32/sizeof(pcre_uchar)), /* CLASS
*/ \ */ \
33, /* NCLASS 1+(32/sizeof(pcre_uchar)), /* NCLASS
*/ \ */ \
0, /* XCLASS - variable length */ \ 0, /* XCLASS - variable length */ \
3, /* REF 1+IMM2_SIZE, /* REF
*/ \ */ \
1+IMM2_SIZE, /* REFI
*/ \
1+LINK_SIZE, /* RECURSE */ \ 1+LINK_SIZE, /* RECURSE */ \
2+2*LINK_SIZE, /* CALLOUT */ \ 2+2*LINK_SIZE, /* CALLOUT */ \
1+LINK_SIZE, /* Alt */ \ 1+LINK_SIZE, /* Alt */ \
1+LINK_SIZE, /* Ket */ \ 1+LINK_SIZE, /* Ket */ \
1+LINK_SIZE, /* KetRmax */ \ 1+LINK_SIZE, /* KetRmax */ \
1+LINK_SIZE, /* KetRmin */ \ 1+LINK_SIZE, /* KetRmin */ \
1+LINK_SIZE, /* KetRpos
*/ \
1+LINK_SIZE, /* Reverse
*/ \
1+LINK_SIZE, /* Assert */ \ 1+LINK_SIZE, /* Assert */ \
1+LINK_SIZE, /* Assert not */ \ 1+LINK_SIZE, /* Assert not */ \
1+LINK_SIZE, /* Assert behind */ \ 1+LINK_SIZE, /* Assert behind */ \
1+LINK_SIZE, /* Assert behind not */ \ 1+LINK_SIZE, /* Assert behind not */ \
1+LINK_SIZE, /* Reverse */ \
1+LINK_SIZE, /* ONCE */ \ 1+LINK_SIZE, /* ONCE */ \
1+LINK_SIZE, /* ONCE_NC */ \
1+LINK_SIZE, /* BRA */ \ 1+LINK_SIZE, /* BRA */ \
3+LINK_SIZE, /* CBRA 1+LINK_SIZE, /* BRAPOS
*/ \ */ \
1+LINK_SIZE+IMM2_SIZE, /* CBRA
*/ \
1+LINK_SIZE+IMM2_SIZE, /* CBRAPOS
*/ \
1+LINK_SIZE, /* COND */ \ 1+LINK_SIZE, /* COND */ \
1+LINK_SIZE, /* SBRA */ \ 1+LINK_SIZE, /* SBRA */ \
3+LINK_SIZE, /* SCBRA 1+LINK_SIZE, /* SBRAPOS
*/ \ */ \
1+LINK_SIZE+IMM2_SIZE, /* SCBRA
*/ \
1+LINK_SIZE+IMM2_SIZE, /* SCBRAPOS
*/ \
1+LINK_SIZE, /* SCOND */ \ 1+LINK_SIZE, /* SCOND */ \
3, /* CREF 1+IMM2_SIZE, 1+IMM2_SIZE, /* CREF, NCREF
*/ \ */ \
3, /* RREF 1+IMM2_SIZE, 1+IMM2_SIZE, /* RREF, NRREF
*/ \ */ \
1, /* DEF */ \ 1, /* DEF */ \
1, 1, /* BRAZERO, BRAMINZERO 1, 1, 1, /* BRAZERO, BRAMINZERO, BRAPOSZERO
*/ \ */ \
1, 1, 1, 1, /* PRUNE, SKIP, THEN, COMMIT, 3, 1, 3, /* MARK, PRUNE, PRUNE_ARG
*/ \ */ \
1, 1 /* FAIL, ACCEPT 1, 3, /* SKIP, SKIP_ARG
*/ */ \
1, 3, /* THEN, THEN_ARG
*/ \
1, 1, 1, 1, /* COMMIT, FAIL, ACCEPT, ASSERT_ACCEPT
*/ \
1+IMM2_SIZE, 1 /* CLOSE, SKIPZERO
*/
/* A magic value for OP_RREF to indicate the "any recursion" condition. */ /* A magic value for OP_RREF and OP_NRREF to indicate the "any recursion"
condition. */
#define RREF_ANY 0xffff #define RREF_ANY 0xffff
/* Error code numbers. They are given names so that they can more easily be /* Compile time error code numbers. They are given names so that they can m
tracked. */ ore
easily be tracked. When a new number is added, the table called eint in
pcreposix.c must be updated. */
enum { ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, enum { ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9,
ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19 , ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19 ,
ERR20, ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR28, ERR29 , ERR20, ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR28, ERR29 ,
ERR30, ERR31, ERR32, ERR33, ERR34, ERR35, ERR36, ERR37, ERR38, ERR39 , ERR30, ERR31, ERR32, ERR33, ERR34, ERR35, ERR36, ERR37, ERR38, ERR39 ,
ERR40, ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47, ERR48, ERR49 , ERR40, ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47, ERR48, ERR49 ,
ERR50, ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59 , ERR50, ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59 ,
ERR60, ERR61 }; ERR60, ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69
,
ERR70, ERR71, ERR72, ERR73, ERR74, ERRCOUNT };
/* The real format of the start of the pcre block; the index of names and t he /* The real format of the start of the pcre block; the index of names and t he
code vector run on as long as necessary after the end. We store an explicit code vector run on as long as necessary after the end. We store an explicit
offset to the name table so that if a regex is compiled on one host, saved, and offset to the name table so that if a regex is compiled on one host, saved, and
then run on another where the size of pointers is different, all might stil l then run on another where the size of pointers is different, all might stil l
be well. For the case of compiled-on-4 and run-on-8, we include an extra be well. For the case of compiled-on-4 and run-on-8, we include an extra
pointer that is always NULL. For future-proofing, a few dummy fields were pointer that is always NULL. For future-proofing, a few dummy fields were
originally included - even though you can never get this planning right - b ut originally included - even though you can never get this planning right - b ut
there is only one left now. there is only one left now.
NOTE NOTE NOTE: NOTE NOTE NOTE:
Because people can now save and re-use compiled patterns, any additions to this Because people can now save and re-use compiled patterns, any additions to this
structure should be made at the end, and something earlier (e.g. a new structure should be made at the end, and something earlier (e.g. a new
flag in the options or one of the dummy fields) should indicate that the ne w flag in the options or one of the dummy fields) should indicate that the ne w
fields are present. Currently PCRE always sets the dummy fields to zero. fields are present. Currently PCRE always sets the dummy fields to zero.
NOTE NOTE NOTE: NOTE NOTE NOTE
*/ */
typedef struct real_pcre { #ifdef COMPILE_PCRE8
#define REAL_PCRE real_pcre
#else
#define REAL_PCRE real_pcre16
#endif
typedef struct REAL_PCRE {
pcre_uint32 magic_number; pcre_uint32 magic_number;
pcre_uint32 size; /* Total that was malloced */ pcre_uint32 size; /* Total that was malloced */
pcre_uint32 options; /* Public options */ pcre_uint32 options; /* Public options */
pcre_uint16 flags; /* Private flags */ pcre_uint16 flags; /* Private flags */
pcre_uint16 dummy1; /* For future use */ pcre_uint16 dummy1; /* For future use */
pcre_uint16 top_bracket; pcre_uint16 top_bracket;
pcre_uint16 top_backref; pcre_uint16 top_backref;
pcre_uint16 first_byte; pcre_uint16 first_char; /* Starting character */
pcre_uint16 req_byte; pcre_uint16 req_char; /* This character must be seen */
pcre_uint16 name_table_offset; /* Offset to name table that follows */ pcre_uint16 name_table_offset; /* Offset to name table that follows */
pcre_uint16 name_entry_size; /* Size of any name items */ pcre_uint16 name_entry_size; /* Size of any name items */
pcre_uint16 name_count; /* Number of name items */ pcre_uint16 name_count; /* Number of name items */
pcre_uint16 ref_count; /* Reference count */ pcre_uint16 ref_count; /* Reference count */
const unsigned char *tables; /* Pointer to tables or NULL for std */ const pcre_uint8 *tables; /* Pointer to tables or NULL for std */
const unsigned char *nullpad; /* NULL padding */ const pcre_uint8 *nullpad; /* NULL padding */
} real_pcre; } REAL_PCRE;
/* The format of the block used to store data from pcre_study(). The same /* The format of the block used to store data from pcre_study(). The same
remark (see NOTE above) about extending this structure applies. */ remark (see NOTE above) about extending this structure applies. */
typedef struct pcre_study_data { typedef struct pcre_study_data {
pcre_uint32 size; /* Total that was malloced */ pcre_uint32 size; /* Total that was malloced */
pcre_uint32 options; pcre_uint32 flags; /* Private flags */
uschar start_bits[32]; pcre_uint8 start_bits[32]; /* Starting char bits */
pcre_uint32 minlength; /* Minimum subject length */
} pcre_study_data; } pcre_study_data;
/* Structure for building a chain of open capturing subpatterns during
compiling, so that instructions to close them can be compiled when (*ACCEPT
) is
encountered. This is also used to identify subpatterns that contain recursi
ve
back references to themselves, so that they can be made atomic. */
typedef struct open_capitem {
struct open_capitem *next; /* Chain link */
pcre_uint16 number; /* Capture number */
pcre_uint16 flag; /* Set TRUE if recursive back ref */
} open_capitem;
/* Structure for passing "static" information around between the functions /* Structure for passing "static" information around between the functions
doing the compiling, so that they are thread-safe. */ doing the compiling, so that they are thread-safe. */
typedef struct compile_data { typedef struct compile_data {
const uschar *lcc; /* Points to lower casing table */ const pcre_uint8 *lcc; /* Points to lower casing table */
const uschar *fcc; /* Points to case-flipping table */ const pcre_uint8 *fcc; /* Points to case-flipping table */
const uschar *cbits; /* Points to character type table */ const pcre_uint8 *cbits; /* Points to character type table */
const uschar *ctypes; /* Points to table of type maps */ const pcre_uint8 *ctypes; /* Points to table of type maps */
const uschar *start_workspace;/* The start of working space */ const pcre_uchar *start_workspace;/* The start of working space */
const uschar *start_code; /* The start of the compiled code */ const pcre_uchar *start_code; /* The start of the compiled code */
const uschar *start_pattern; /* The start of the pattern */ const pcre_uchar *start_pattern; /* The start of the pattern */
const uschar *end_pattern; /* The end of the pattern */ const pcre_uchar *end_pattern; /* The end of the pattern */
uschar *hwm; /* High watermark of workspace */ open_capitem *open_caps; /* Chain of open capture items */
uschar *name_table; /* The name/number table */ pcre_uchar *hwm; /* High watermark of workspace */
int names_found; /* Number of entries so far */ pcre_uchar *name_table; /* The name/number table */
int name_entry_size; /* Size of each entry */ int names_found; /* Number of entries so far */
int bracount; /* Count of capturing parens */ int name_entry_size; /* Size of each entry */
int top_backref; /* Maximum back reference */ int workspace_size; /* Size of workspace */
unsigned int backref_map; /* Bitmap of low back refs */ int bracount; /* Count of capturing parens as we comp
int external_options; /* External (initial) options */ ile */
int external_flags; /* External flag bits to be set */ int final_bracount; /* Saved value after first pass */
int req_varyopt; /* "After variable item" flag for reqbyte * int top_backref; /* Maximum back reference */
/ unsigned int backref_map; /* Bitmap of low back refs */
BOOL had_accept; /* (*ACCEPT) encountered */ int assert_depth; /* Depth of nested assertions */
int nltype; /* Newline type */ int external_options; /* External (initial) options */
int nllen; /* Newline string length */ int external_flags; /* External flag bits to be set */
uschar nl[4]; /* Newline string when fixed length */ int req_varyopt; /* "After variable item" flag for reqby
te */
BOOL had_accept; /* (*ACCEPT) encountered */
BOOL check_lookbehind; /* Lookbehinds need later checking */
int nltype; /* Newline type */
int nllen; /* Newline string length */
pcre_uchar nl[4]; /* Newline string when fixed length */
} compile_data; } compile_data;
/* Structure for maintaining a chain of pointers to the currently incomplet e /* Structure for maintaining a chain of pointers to the currently incomplet e
branches, for testing for left recursion. */ branches, for testing for left recursion while compiling. */
typedef struct branch_chain { typedef struct branch_chain {
struct branch_chain *outer; struct branch_chain *outer;
uschar *current; pcre_uchar *current_branch;
} branch_chain; } branch_chain;
/* Structure for items in a linked list that represents an explicit recursi ve /* Structure for items in a linked list that represents an explicit recursi ve
call within the pattern. */ call within the pattern; used by pcre_exec(). */
typedef struct recursion_info { typedef struct recursion_info {
struct recursion_info *prevrec; /* Previous recursion record (or NULL) */ struct recursion_info *prevrec; /* Previous recursion record (or NULL) */
int group_num; /* Number of group that was called */ int group_num; /* Number of group that was called */
const uschar *after_call; /* "Return value": points after the call in int *offset_save; /* Pointer to start of saved offsets */
the expr */ int saved_max; /* Number of saved offsets */
USPTR save_start; /* Old value of mstart */ PCRE_PUCHAR subject_position; /* Position at start of recursion */
int *offset_save; /* Pointer to start of saved offsets */
int saved_max; /* Number of saved offsets */
} recursion_info; } recursion_info;
/* A similar structure for pcre_dfa_exec(). */
typedef struct dfa_recursion_info {
struct dfa_recursion_info *prevrec;
int group_num;
PCRE_PUCHAR subject_position;
} dfa_recursion_info;
/* Structure for building a chain of data for holding the values of the sub ject /* Structure for building a chain of data for holding the values of the sub ject
pointer at the start of each subpattern, so as to detect when an empty stri ng pointer at the start of each subpattern, so as to detect when an empty stri ng
has been matched by a subpattern - to break infinite loops. */ has been matched by a subpattern - to break infinite loops; used by
pcre_exec(). */
typedef struct eptrblock { typedef struct eptrblock {
struct eptrblock *epb_prev; struct eptrblock *epb_prev;
USPTR epb_saved_eptr; PCRE_PUCHAR epb_saved_eptr;
} eptrblock; } eptrblock;
/* Structure for passing "static" information around between the functions /* Structure for passing "static" information around between the functions
doing traditional NFA matching, so that they are thread-safe. */ doing traditional NFA matching, so that they are thread-safe. */
typedef struct match_data { typedef struct match_data {
unsigned long int match_call_count; /* As it says */ unsigned long int match_call_count; /* As it says */
unsigned long int match_limit; /* As it says */ unsigned long int match_limit; /* As it says */
unsigned long int match_limit_recursion; /* As it says */ unsigned long int match_limit_recursion; /* As it says */
int *offset_vector; /* Offset vector */ int *offset_vector; /* Offset vector */
int offset_end; /* One past the end */ int offset_end; /* One past the end */
int offset_max; /* The maximum usable for return data */ int offset_max; /* The maximum usable for return data */
int nltype; /* Newline type */ int nltype; /* Newline type */
int nllen; /* Newline string length */ int nllen; /* Newline string length */
uschar nl[4]; /* Newline string when fixed */ int name_count; /* Number of names in name table */
const uschar *lcc; /* Points to lower casing table */ int name_entry_size; /* Size of entry in names table */
const uschar *ctypes; /* Points to table of type maps */ pcre_uchar *name_table; /* Table of names */
BOOL offset_overflow; /* Set if too many extractions */ pcre_uchar nl[4]; /* Newline string when fixed */
BOOL notbol; /* NOTBOL flag */ const pcre_uint8 *lcc; /* Points to lower casing table */
BOOL noteol; /* NOTEOL flag */ const pcre_uint8 *fcc; /* Points to case-flipping table */
BOOL utf8; /* UTF8 flag */ const pcre_uint8 *ctypes; /* Points to table of type maps */
BOOL endonly; /* Dollar not before final \n */ BOOL offset_overflow; /* Set if too many extractions */
BOOL notempty; /* Empty string match not wanted */ BOOL notbol; /* NOTBOL flag */
BOOL partial; /* PARTIAL flag */ BOOL noteol; /* NOTEOL flag */
BOOL hitend; /* Hit the end of the subject at some point BOOL utf; /* UTF-8 / UTF-16 flag */
*/ BOOL jscript_compat; /* JAVASCRIPT_COMPAT flag */
BOOL bsr_anycrlf; /* \R is just any CRLF, not full Unicode */ BOOL use_ucp; /* PCRE_UCP flag */
const uschar *start_code; /* For use when recursing */ BOOL endonly; /* Dollar not before final \n */
USPTR start_subject; /* Start of the subject string */ BOOL notempty; /* Empty string match not wanted */
USPTR end_subject; /* End of the subject string */ BOOL notempty_atstart; /* Empty string match at start not wanted
USPTR start_match_ptr; /* Start of matched string */ */
USPTR end_match_ptr; /* Subject position at end match */ BOOL hitend; /* Hit the end of the subject at some poi
int end_offset_top; /* Highwater mark at end of match */ nt */
int capture_last; /* Most recent capture number */ BOOL bsr_anycrlf; /* \R is just any CRLF, not full Unicode
int start_offset; /* The start offset value */ */
eptrblock *eptrchain; /* Chain of eptrblocks for tail recursions BOOL hasthen; /* Pattern contains (*THEN) */
*/ BOOL ignore_skip_arg; /* For re-run when SKIP name not found */
int eptrn; /* Next free eptrblock */ const pcre_uchar *start_code; /* For use when recursing */
recursion_info *recursive; /* Linked list of recursion data */ PCRE_PUCHAR start_subject; /* Start of the subject string */
void *callout_data; /* To pass back to callouts */ PCRE_PUCHAR end_subject; /* End of the subject string */
PCRE_PUCHAR start_match_ptr; /* Start of matched string */
PCRE_PUCHAR end_match_ptr; /* Subject position at end match */
PCRE_PUCHAR start_used_ptr; /* Earliest consulted character */
int partial; /* PARTIAL options */
int end_offset_top; /* Highwater mark at end of match */
int capture_last; /* Most recent capture number */
int start_offset; /* The start offset value */
int match_function_type; /* Set for certain special calls of MATCH
() */
eptrblock *eptrchain; /* Chain of eptrblocks for tail recursion
s */
int eptrn; /* Next free eptrblock */
recursion_info *recursive; /* Linked list of recursion data */
void *callout_data; /* To pass back to callouts */
const pcre_uchar *mark; /* Mark pointer to pass back on success *
/
const pcre_uchar *nomatch_mark;/* Mark pointer to pass back on failure *
/
const pcre_uchar *once_target; /* Where to back up to for atomic groups
*/
} match_data; } match_data;
/* A similar structure is used for the same purpose by the DFA matching /* A similar structure is used for the same purpose by the DFA matching
functions. */ functions. */
typedef struct dfa_match_data { typedef struct dfa_match_data {
const uschar *start_code; /* Start of the compiled pattern */ const pcre_uchar *start_code; /* Start of the compiled pattern */
const uschar *start_subject; /* Start of the subject string */ const pcre_uchar *start_subject ; /* Start of the subject string */
const uschar *end_subject; /* End of subject string */ const pcre_uchar *end_subject; /* End of subject string */
const uschar *tables; /* Character tables */ const pcre_uchar *start_used_ptr; /* Earliest consulted character */
int moptions; /* Match options */ const pcre_uint8 *tables; /* Character tables */
int poptions; /* Pattern options */ int start_offset; /* The start offset value */
int nltype; /* Newline type */ int moptions; /* Match options */
int nllen; /* Newline string length */ int poptions; /* Pattern options */
uschar nl[4]; /* Newline string when fixed */ int nltype; /* Newline type */
void *callout_data; /* To pass back to callouts */ int nllen; /* Newline string length */
pcre_uchar nl[4]; /* Newline string when fixed */
void *callout_data; /* To pass back to callouts */
dfa_recursion_info *recursive; /* Linked list of recursion data */
} dfa_match_data; } dfa_match_data;
/* Bit definitions for entries in the pcre_ctypes table. */ /* Bit definitions for entries in the pcre_ctypes table. */
#define ctype_space 0x01 #define ctype_space 0x01
#define ctype_letter 0x02 #define ctype_letter 0x02
#define ctype_digit 0x04 #define ctype_digit 0x04
#define ctype_xdigit 0x08 #define ctype_xdigit 0x08
#define ctype_word 0x10 /* alphameric or '_' */ #define ctype_word 0x10 /* alphanumeric or '_' */
#define ctype_meta 0x80 /* regexp meta char or zero (end pattern) */ #define ctype_meta 0x80 /* regexp meta char or zero (end pattern) */
/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set /* Offsets for the bitmap tables in pcre_cbits. Each table contains a set
of bits for a class map. Some classes are built by combining these tables. */ of bits for a class map. Some classes are built by combining these tables. */
#define cbit_space 0 /* [:space:] or \s */ #define cbit_space 0 /* [:space:] or \s */
#define cbit_xdigit 32 /* [:xdigit:] */ #define cbit_xdigit 32 /* [:xdigit:] */
#define cbit_digit 64 /* [:digit:] or \d */ #define cbit_digit 64 /* [:digit:] or \d */
#define cbit_upper 96 /* [:upper:] */ #define cbit_upper 96 /* [:upper:] */
#define cbit_lower 128 /* [:lower:] */ #define cbit_lower 128 /* [:lower:] */
skipping to change at line 1048 skipping to change at line 2171
/* Offsets of the various tables from the base tables pointer, and /* Offsets of the various tables from the base tables pointer, and
total length. */ total length. */
#define lcc_offset 0 #define lcc_offset 0
#define fcc_offset 256 #define fcc_offset 256
#define cbits_offset 512 #define cbits_offset 512
#define ctypes_offset (cbits_offset + cbit_length) #define ctypes_offset (cbits_offset + cbit_length)
#define tables_length (ctypes_offset + 256) #define tables_length (ctypes_offset + 256)
/* Internal function prefix */
#ifdef COMPILE_PCRE8
#ifndef PUBL
#define PUBL(name) pcre_##name
#endif
#ifndef PRIV
#define PRIV(name) _pcre_##name
#endif
#else /* COMPILE_PCRE8 */
#ifdef COMPILE_PCRE16
#ifndef PUBL
#define PUBL(name) pcre16_##name
#endif
#ifndef PRIV
#define PRIV(name) _pcre16_##name
#endif
#else
#error Unsupported compiling mode
#endif /* COMPILE_PCRE16 */
#endif /* COMPILE_PCRE8 */
/* Layout of the UCP type table that translates property names into types a nd /* Layout of the UCP type table that translates property names into types a nd
codes. Each entry used to point directly to a name, but to reduce the numbe r of codes. Each entry used to point directly to a name, but to reduce the numbe r of
relocations in shared libraries, it now has an offset into a single string relocations in shared libraries, it now has an offset into a single string
instead. */ instead. */
typedef struct { typedef struct {
pcre_uint16 name_offset; pcre_uint16 name_offset;
pcre_uint16 type; pcre_uint16 type;
pcre_uint16 value; pcre_uint16 value;
} ucp_type_table; } ucp_type_table;
/* Internal shared data tables. These are tables that are used by more than one /* Internal shared data tables. These are tables that are used by more than one
of the exported public functions. They have to be "external" in the C sense , of the exported public functions. They have to be "external" in the C sense ,
but are not part of the PCRE public API. The data for these tables is in th e but are not part of the PCRE public API. The data for these tables is in th e
pcre_tables.c module. */ pcre_tables.c module. */
extern const int _pcre_utf8_table1[]; #ifdef COMPILE_PCRE8
extern const int _pcre_utf8_table2[];
extern const int _pcre_utf8_table3[]; extern const int PRIV(utf8_table1)[];
extern const uschar _pcre_utf8_table4[]; extern const int PRIV(utf8_table1_size);
extern const int PRIV(utf8_table2)[];
extern const int PRIV(utf8_table3)[];
extern const pcre_uint8 PRIV(utf8_table4)[];
extern const int _pcre_utf8_table1_size; #endif /* COMPILE_PCRE8 */
extern const char _pcre_utt_names[]; extern const char PRIV(utt_names)[];
extern const ucp_type_table _pcre_utt[]; extern const ucp_type_table PRIV(utt)[];
extern const int _pcre_utt_size; extern const int PRIV(utt_size);
extern const uschar _pcre_default_tables[]; extern const pcre_uint8 PRIV(default_tables)[];
extern const uschar _pcre_OP_lengths[]; extern const pcre_uint8 PRIV(OP_lengths)[];
/* Internal shared functions. These are functions that are used by more tha n /* Internal shared functions. These are functions that are used by more tha n
one of the exported public functions. They have to be "external" in the C one of the exported public functions. They have to be "external" in the C
sense, but are not part of the PCRE public API. */ sense, but are not part of the PCRE public API. */
extern BOOL _pcre_is_newline(const uschar *, int, const uschar *, /* String comparison functions. */
int *, BOOL); #ifdef COMPILE_PCRE8
extern int _pcre_ord2utf8(int, uschar *);
extern real_pcre *_pcre_try_flipped(const real_pcre *, real_pcre *, #define STRCMP_UC_UC(str1, str2) \
const pcre_study_data *, pcre_study_data *); strcmp((char *)(str1), (char *)(str2))
extern int _pcre_ucp_findprop(const unsigned int, int *, int *); #define STRCMP_UC_C8(str1, str2) \
extern unsigned int _pcre_ucp_othercase(const unsigned int); strcmp((char *)(str1), (str2))
extern int _pcre_valid_utf8(const uschar *, int); #define STRNCMP_UC_UC(str1, str2, num) \
extern BOOL _pcre_was_newline(const uschar *, int, const uschar *, strncmp((char *)(str1), (char *)(str2), (num))
int *, BOOL); #define STRNCMP_UC_C8(str1, str2, num) \
extern BOOL _pcre_xclass(int, const uschar *); strncmp((char *)(str1), (str2), (num))
#define STRLEN_UC(str) strlen((const char *)str)
#else
extern int PRIV(strcmp_uc_uc)(const pcre_uchar *,
const pcre_uchar *);
extern int PRIV(strcmp_uc_c8)(const pcre_uchar *,
const char *);
extern int PRIV(strncmp_uc_uc)(const pcre_uchar *,
const pcre_uchar *, unsigned int num);
extern int PRIV(strncmp_uc_c8)(const pcre_uchar *,
const char *, unsigned int num);
extern unsigned int PRIV(strlen_uc)(const pcre_uchar *str);
#define STRCMP_UC_UC(str1, str2) \
PRIV(strcmp_uc_uc)((str1), (str2))
#define STRCMP_UC_C8(str1, str2) \
PRIV(strcmp_uc_c8)((str1), (str2))
#define STRNCMP_UC_UC(str1, str2, num) \
PRIV(strncmp_uc_uc)((str1), (str2), (num))
#define STRNCMP_UC_C8(str1, str2, num) \
PRIV(strncmp_uc_c8)((str1), (str2), (num))
#define STRLEN_UC(str) PRIV(strlen_uc)(str)
#endif /* COMPILE_PCRE8 */
extern const pcre_uchar *PRIV(find_bracket)(const pcre_uchar *, BOOL, int);
extern BOOL PRIV(is_newline)(PCRE_PUCHAR, int, PCRE_PUCHAR,
int *, BOOL);
extern int PRIV(ord2utf)(pcre_uint32, pcre_uchar *);
extern int PRIV(valid_utf)(PCRE_PUCHAR, int, int *);
extern BOOL PRIV(was_newline)(PCRE_PUCHAR, int, PCRE_PUCHAR,
int *, BOOL);
extern BOOL PRIV(xclass)(int, const pcre_uchar *, BOOL);
#ifdef SUPPORT_JIT
extern void PRIV(jit_compile)(const REAL_PCRE *, PUBL(extra) *
);
extern int PRIV(jit_exec)(const REAL_PCRE *, void *,
const pcre_uchar *, int, int, int, int, int *, i
nt);
extern void PRIV(jit_free)(void *);
extern int PRIV(jit_get_size)(void *);
extern const char* PRIV(jit_get_target)(void);
#endif
/* Unicode character database (UCD) */
typedef struct {
pcre_uint8 script;
pcre_uint8 chartype;
pcre_int32 other_case;
} ucd_record;
extern const ucd_record PRIV(ucd_records)[];
extern const pcre_uint8 PRIV(ucd_stage1)[];
extern const pcre_uint16 PRIV(ucd_stage2)[];
extern const int PRIV(ucp_gentype)[];
#ifdef SUPPORT_JIT
extern const int PRIV(ucp_typerange)[];
#endif
#ifdef SUPPORT_UCP
/* UCD access macros */
#define UCD_BLOCK_SIZE 128
#define GET_UCD(ch) (PRIV(ucd_records) + \
PRIV(ucd_stage2)[PRIV(ucd_stage1)[(ch) / UCD_BLOCK_SIZE] * \
UCD_BLOCK_SIZE + (ch) % UCD_BLOCK_SIZE])
#define UCD_CHARTYPE(ch) GET_UCD(ch)->chartype
#define UCD_SCRIPT(ch) GET_UCD(ch)->script
#define UCD_CATEGORY(ch) PRIV(ucp_gentype)[UCD_CHARTYPE(ch)]
#define UCD_OTHERCASE(ch) (ch + GET_UCD(ch)->other_case)
#endif /* SUPPORT_UCP */
#endif #endif
/* End of pcre_internal.h */ /* End of pcre_internal.h */
 End of changes. 124 change blocks. 
457 lines changed or deleted 1771 lines changed or added


 pcre_scanner.h   pcre_scanner.h 
skipping to change at line 51 skipping to change at line 51
// ...; // ...;
// } // }
#ifndef _PCRE_SCANNER_H #ifndef _PCRE_SCANNER_H
#define _PCRE_SCANNER_H #define _PCRE_SCANNER_H
#include <assert.h> #include <assert.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include "pcrecpp.h" #include <pcrecpp.h>
#include "pcre_stringpiece.h" #include <pcre_stringpiece.h>
namespace pcrecpp { namespace pcrecpp {
class Scanner { class PCRECPP_EXP_DEFN Scanner {
public: public:
Scanner(); Scanner();
explicit Scanner(const std::string& input); explicit Scanner(const std::string& input);
~Scanner(); ~Scanner();
// Return current line number. The returned line-number is // Return current line number. The returned line-number is
// one-based. I.e. it returns 1 + the number of consumed newlines. // one-based. I.e. it returns 1 + the number of consumed newlines.
// //
// Note: this method may be slow. It may take time proportional to // Note: this method may be slow. It may take time proportional to
// the size of the input. // the size of the input.
skipping to change at line 83 skipping to change at line 83
// Return true iff the start of the remaining input matches "re" // Return true iff the start of the remaining input matches "re"
bool LookingAt(const RE& re) const; bool LookingAt(const RE& re) const;
// Return true iff all of the following are true // Return true iff all of the following are true
// a. the start of the remaining input matches "re", // a. the start of the remaining input matches "re",
// b. if any arguments are supplied, matched sub-patterns can be // b. if any arguments are supplied, matched sub-patterns can be
// parsed and stored into the arguments. // parsed and stored into the arguments.
// If it returns true, it skips over the matched input and any // If it returns true, it skips over the matched input and any
// following input that matches the "skip" regular expression. // following input that matches the "skip" regular expression.
bool Consume(const RE& re, bool Consume(const RE& re,
const Arg& arg0 = no_arg, const Arg& arg0 = RE::no_arg,
const Arg& arg1 = no_arg, const Arg& arg1 = RE::no_arg,
const Arg& arg2 = no_arg const Arg& arg2 = RE::no_arg
// TODO: Allow more arguments? // TODO: Allow more arguments?
); );
// Set the "skip" regular expression. If after consuming some data, // Set the "skip" regular expression. If after consuming some data,
// a prefix of the input matches this RE, it is automatically // a prefix of the input matches this RE, it is automatically
// skipped. For example, a programming language scanner would use // skipped. For example, a programming language scanner would use
// a skip RE that matches white space and comments. // a skip RE that matches white space and comments.
// //
// scanner.SetSkipExpression("\\s+|//.*|/[*](.|\n)*?[*]/"); // scanner.SetSkipExpression("\\s+|//.*|/[*](.|\n)*?[*]/");
// //
 End of changes. 3 change blocks. 
6 lines changed or deleted 6 lines changed or added


 pcre_stringpiece.h   pcre_stringpiece.h 
skipping to change at line 41 skipping to change at line 41
// //
// A string like object that points into another piece of memory. // A string like object that points into another piece of memory.
// Useful for providing an interface that allows clients to easily // Useful for providing an interface that allows clients to easily
// pass in either a "const char*" or a "string". // pass in either a "const char*" or a "string".
// //
// Arghh! I wish C++ literals were automatically of type "string". // Arghh! I wish C++ literals were automatically of type "string".
#ifndef _PCRE_STRINGPIECE_H #ifndef _PCRE_STRINGPIECE_H
#define _PCRE_STRINGPIECE_H #define _PCRE_STRINGPIECE_H
#include <string.h> #include <cstring>
#include <string> #include <string>
#include <iosfwd> // for ostream forward-declaration #include <iosfwd> // for ostream forward-declaration
#if 0 #if 0
#define HAVE_TYPE_TRAITS #define HAVE_TYPE_TRAITS
#include <type_traits.h> #include <type_traits.h>
#elif 0 #elif 0
#define HAVE_TYPE_TRAITS #define HAVE_TYPE_TRAITS
#include <bits/type_traits.h> #include <bits/type_traits.h>
#endif #endif
#include <pcre.h> #include <pcre.h>
using std::memcmp;
using std::strlen;
using std::string; using std::string;
namespace pcrecpp { namespace pcrecpp {
class PCRECPP_EXP_DEFN StringPiece { class PCRECPP_EXP_DEFN StringPiece {
private: private:
const char* ptr_; const char* ptr_;
int length_; int length_;
public: public:
 End of changes. 2 change blocks. 
1 lines changed or deleted 3 lines changed or added


 pcrecpp.h   pcrecpp.h 
skipping to change at line 348 skipping to change at line 348
namespace pcrecpp { namespace pcrecpp {
#define PCRE_SET_OR_CLEAR(b, o) \ #define PCRE_SET_OR_CLEAR(b, o) \
if (b) all_options_ |= (o); else all_options_ &= ~(o); \ if (b) all_options_ |= (o); else all_options_ &= ~(o); \
return *this return *this
#define PCRE_IS_SET(o) \ #define PCRE_IS_SET(o) \
(all_options_ & o) == o (all_options_ & o) == o
// We convert user-passed pointers into special Arg objects
PCRECPP_EXP_DECL Arg no_arg;
/***** Compiling regular expressions: the RE class *****/ /***** Compiling regular expressions: the RE class *****/
// RE_Options allow you to set options to be passed along to pcre, // RE_Options allow you to set options to be passed along to pcre,
// along with other options we put on top of pcre. // along with other options we put on top of pcre.
// Only 9 modifiers, plus match_limit and match_limit_recursion, // Only 9 modifiers, plus match_limit and match_limit_recursion,
// are supported now. // are supported now.
class RE_Options { class PCRECPP_EXP_DEFN RE_Options {
public: public:
// constructor // constructor
RE_Options() : match_limit_(0), match_limit_recursion_(0), all_options_(0 ) {} RE_Options() : match_limit_(0), match_limit_recursion_(0), all_options_(0 ) {}
// alternative constructor. // alternative constructor.
// To facilitate transfer of legacy code from C programs // To facilitate transfer of legacy code from C programs
// //
// This lets you do // This lets you do
// RE(pattern, RE_Options(PCRE_CASELESS|PCRE_MULTILINE)).PartialMatch( str); // RE(pattern, RE_Options(PCRE_CASELESS|PCRE_MULTILINE)).PartialMatch( str);
// But new code is better off doing // But new code is better off doing
skipping to change at line 405 skipping to change at line 402
return PCRE_IS_SET(PCRE_MULTILINE); return PCRE_IS_SET(PCRE_MULTILINE);
} }
RE_Options &set_multiline(bool x) { RE_Options &set_multiline(bool x) {
PCRE_SET_OR_CLEAR(x, PCRE_MULTILINE); PCRE_SET_OR_CLEAR(x, PCRE_MULTILINE);
} }
bool dotall() const { bool dotall() const {
return PCRE_IS_SET(PCRE_DOTALL); return PCRE_IS_SET(PCRE_DOTALL);
} }
RE_Options &set_dotall(bool x) { RE_Options &set_dotall(bool x) {
PCRE_SET_OR_CLEAR(x,PCRE_DOTALL); PCRE_SET_OR_CLEAR(x, PCRE_DOTALL);
} }
bool extended() const { bool extended() const {
return PCRE_IS_SET(PCRE_EXTENDED); return PCRE_IS_SET(PCRE_EXTENDED);
} }
RE_Options &set_extended(bool x) { RE_Options &set_extended(bool x) {
PCRE_SET_OR_CLEAR(x,PCRE_EXTENDED); PCRE_SET_OR_CLEAR(x, PCRE_EXTENDED);
} }
bool dollar_endonly() const { bool dollar_endonly() const {
return PCRE_IS_SET(PCRE_DOLLAR_ENDONLY); return PCRE_IS_SET(PCRE_DOLLAR_ENDONLY);
} }
RE_Options &set_dollar_endonly(bool x) { RE_Options &set_dollar_endonly(bool x) {
PCRE_SET_OR_CLEAR(x,PCRE_DOLLAR_ENDONLY); PCRE_SET_OR_CLEAR(x, PCRE_DOLLAR_ENDONLY);
} }
bool extra() const { bool extra() const {
return PCRE_IS_SET( PCRE_EXTRA); return PCRE_IS_SET(PCRE_EXTRA);
} }
RE_Options &set_extra(bool x) { RE_Options &set_extra(bool x) {
PCRE_SET_OR_CLEAR(x, PCRE_EXTRA); PCRE_SET_OR_CLEAR(x, PCRE_EXTRA);
} }
bool ungreedy() const { bool ungreedy() const {
return PCRE_IS_SET(PCRE_UNGREEDY); return PCRE_IS_SET(PCRE_UNGREEDY);
} }
RE_Options &set_ungreedy(bool x) { RE_Options &set_ungreedy(bool x) {
PCRE_SET_OR_CLEAR(x, PCRE_UNGREEDY); PCRE_SET_OR_CLEAR(x, PCRE_UNGREEDY);
skipping to change at line 489 skipping to change at line 486
return RE_Options().set_dotall(true); return RE_Options().set_dotall(true);
} }
static inline RE_Options EXTENDED() { static inline RE_Options EXTENDED() {
return RE_Options().set_extended(true); return RE_Options().set_extended(true);
} }
// Interface for regular expression matching. Also corresponds to a // Interface for regular expression matching. Also corresponds to a
// pre-compiled regular expression. An "RE" object is safe for // pre-compiled regular expression. An "RE" object is safe for
// concurrent use by multiple threads. // concurrent use by multiple threads.
class RE { class PCRECPP_EXP_DEFN RE {
public: public:
// We provide implicit conversions from strings so that users can // We provide implicit conversions from strings so that users can
// pass in a string or a "const char*" wherever an "RE" is expected. // pass in a string or a "const char*" wherever an "RE" is expected.
RE(const string& pat) { Init(pat, NULL); } RE(const string& pat) { Init(pat, NULL); }
RE(const string& pat, const RE_Options& option) { Init(pat, &option); } RE(const string& pat, const RE_Options& option) { Init(pat, &option); }
RE(const char* pat) { Init(pat, NULL); } RE(const char* pat) { Init(pat, NULL); }
RE(const char* pat, const RE_Options& option) { Init(pat, &option); } RE(const char* pat, const RE_Options& option) { Init(pat, &option); }
RE(const unsigned char* pat) { RE(const unsigned char* pat) {
Init(reinterpret_cast<const char*>(pat), NULL); Init(reinterpret_cast<const char*>(pat), NULL);
} }
skipping to change at line 624 skipping to change at line 621
bool Extract(const StringPiece &rewrite, bool Extract(const StringPiece &rewrite,
const StringPiece &text, const StringPiece &text,
string *out) const; string *out) const;
// Escapes all potentially meaningful regexp characters in // Escapes all potentially meaningful regexp characters in
// 'unquoted'. The returned string, used as a regular expression, // 'unquoted'. The returned string, used as a regular expression,
// will exactly match the original string. For example, // will exactly match the original string. For example,
// 1.5-2.0? // 1.5-2.0?
// may become: // may become:
// 1\.5\-2\.0\? // 1\.5\-2\.0\?
// Note QuoteMeta behaves the same as perl's QuoteMeta function,
// *except* that it escapes the NUL character (\0) as backslash + 0,
// rather than backslash + NUL.
static string QuoteMeta(const StringPiece& unquoted); static string QuoteMeta(const StringPiece& unquoted);
/***** Generic matching interface *****/ /***** Generic matching interface *****/
// Type of match (TODO: Should be restructured as part of RE_Options) // Type of match (TODO: Should be restructured as part of RE_Options)
enum Anchor { enum Anchor {
UNANCHORED, // No anchoring UNANCHORED, // No anchoring
ANCHOR_START, // Anchor at start only ANCHOR_START, // Anchor at start only
ANCHOR_BOTH // Anchor at start and end ANCHOR_BOTH // Anchor at start and end
}; };
skipping to change at line 646 skipping to change at line 646
// "*consumed" if successful. // "*consumed" if successful.
bool DoMatch(const StringPiece& text, bool DoMatch(const StringPiece& text,
Anchor anchor, Anchor anchor,
int* consumed, int* consumed,
const Arg* const* args, int n) const; const Arg* const* args, int n) const;
// Return the number of capturing subpatterns, or -1 if the // Return the number of capturing subpatterns, or -1 if the
// regexp wasn't valid on construction. // regexp wasn't valid on construction.
int NumberOfCapturingGroups() const; int NumberOfCapturingGroups() const;
// The default value for an argument, to indicate the end of the argument
// list. This must be used only in optional argument defaults. It should
NOT
// be passed explicitly. Some people have tried to use it like this:
//
// FullMatch(x, y, &z, no_arg, &w);
//
// This is a mistake, and will not work.
static Arg no_arg;
private: private:
void Init(const string& pattern, const RE_Options* options); void Init(const string& pattern, const RE_Options* options);
void Cleanup(); void Cleanup();
// Match against "text", filling in "vec" (up to "vecsize" * 2/3) with // Match against "text", filling in "vec" (up to "vecsize" * 2/3) with
// pairs of integers for the beginning and end positions of matched // pairs of integers for the beginning and end positions of matched
// text. The first pair corresponds to the entire matched text; // text. The first pair corresponds to the entire matched text;
// subsequent pairs correspond, in order, to parentheses-captured // subsequent pairs correspond, in order, to parentheses-captured
// matches. Returns the number of pairs (one more than the number of // matches. Returns the number of pairs (one more than the number of
// the last subpattern with a match) if matching was successful // the last subpattern with a match) if matching was successful
// and zero if the match failed. // and zero if the match failed.
// I.e. for RE("(foo)|(bar)|(baz)") it will return 2, 3, and 4 when match ing // I.e. for RE("(foo)|(bar)|(baz)") it will return 2, 3, and 4 when match ing
// against "foo", "bar", and "baz" respectively. // against "foo", "bar", and "baz" respectively.
// When matching RE("(foo)|hello") against "hello", it will return 1. // When matching RE("(foo)|hello") against "hello", it will return 1.
// But the values for all subpattern are filled in into "vec". // But the values for all subpattern are filled in into "vec".
int TryMatch(const StringPiece& text, int TryMatch(const StringPiece& text,
int startpos, int startpos,
Anchor anchor, Anchor anchor,
bool empty_ok,
int *vec, int *vec,
int vecsize) const; int vecsize) const;
// Append the "rewrite" string, with backslash subsitutions from "text" // Append the "rewrite" string, with backslash subsitutions from "text"
// and "vec", to string "out". // and "vec", to string "out".
bool Rewrite(string *out, bool Rewrite(string *out,
const StringPiece& rewrite, const StringPiece& rewrite,
const StringPiece& text, const StringPiece& text,
int *vec, int *vec,
int veclen) const; int veclen) const;
 End of changes. 10 change blocks. 
9 lines changed or deleted 20 lines changed or added


 pcrecpp_internal.h   pcrecpp_internal.h 
/************************************************* /*************************************************
* Perl-Compatible Regular Expressions * * Perl-Compatible Regular Expressions *
*************************************************/ *************************************************/
/* /*
Copyright (c) 2005, Google Inc.
All rights reserved.
--------------------------------------------------------------------------- -- --------------------------------------------------------------------------- --
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice , * Redistributions of source code must retain the above copyright notice ,
this list of conditions and the following disclaimer. this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright * Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution. documentation and/or other materials provided with the distribution.
skipping to change at line 52 skipping to change at line 55
definition; with "extern" we have a declaration. The settings here override the definition; with "extern" we have a declaration. The settings here override the
setting in pcre.h. We use: setting in pcre.h. We use:
PCRECPP_EXP_DECL for declarations PCRECPP_EXP_DECL for declarations
PCRECPP_EXP_DEFN for definitions of exported functions PCRECPP_EXP_DEFN for definitions of exported functions
*/ */
#ifndef PCRECPP_EXP_DECL #ifndef PCRECPP_EXP_DECL
# ifdef _WIN32 # ifdef _WIN32
# ifndef PCRECPP_STATIC # ifndef PCRE_STATIC
# define PCRECPP_EXP_DECL extern __declspec(dllexport) # define PCRECPP_EXP_DECL extern __declspec(dllexport)
# define PCRECPP_EXP_DEFN __declspec(dllexport) # define PCRECPP_EXP_DEFN __declspec(dllexport)
# else # else
# define PCRECPP_EXP_DECL extern # define PCRECPP_EXP_DECL extern
# define PCRECPP_EXP_DEFN # define PCRECPP_EXP_DEFN
# endif # endif
# else # else
# define PCRECPP_EXP_DECL extern # define PCRECPP_EXP_DECL extern
# define PCRECPP_EXP_DEFN # define PCRECPP_EXP_DEFN
# endif # endif
 End of changes. 2 change blocks. 
1 lines changed or deleted 4 lines changed or added


 pcrecpparg.h   pcrecpparg.h 
skipping to change at line 51 skipping to change at line 51
class StringPiece; class StringPiece;
// Hex/Octal/Binary? // Hex/Octal/Binary?
// Special class for parsing into objects that define a ParseFrom() method // Special class for parsing into objects that define a ParseFrom() method
template <class T> template <class T>
class _RE_MatchObject { class _RE_MatchObject {
public: public:
static inline bool Parse(const char* str, int n, void* dest) { static inline bool Parse(const char* str, int n, void* dest) {
if (dest == NULL) return true;
T* object = reinterpret_cast<T*>(dest); T* object = reinterpret_cast<T*>(dest);
return object->ParseFrom(str, n); return object->ParseFrom(str, n);
} }
}; };
class PCRECPP_EXP_DEFN Arg { class PCRECPP_EXP_DEFN Arg {
public: public:
// Empty constructor so we can declare arrays of Arg // Empty constructor so we can declare arrays of Arg
Arg(); Arg();
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 pcreposix.h   pcreposix.h 
skipping to change at line 12 skipping to change at line 12
* Perl-Compatible Regular Expressions * * Perl-Compatible Regular Expressions *
*************************************************/ *************************************************/
#ifndef _PCREPOSIX_H #ifndef _PCREPOSIX_H
#define _PCREPOSIX_H #define _PCREPOSIX_H
/* This is the header for the POSIX wrapper interface to the PCRE Perl- /* This is the header for the POSIX wrapper interface to the PCRE Perl-
Compatible Regular Expression library. It defines the things POSIX says sho uld Compatible Regular Expression library. It defines the things POSIX says sho uld
be there. I hope. be there. I hope.
Copyright (c) 1997-2007 University of Cambridge Copyright (c) 1997-2012 University of Cambridge
--------------------------------------------------------------------------- -- --------------------------------------------------------------------------- --
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice , * Redistributions of source code must retain the above copyright notice ,
this list of conditions and the following disclaimer. this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright * Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the notice, this list of conditions and the following disclaimer in the
skipping to change at line 53 skipping to change at line 53
/* Have to include stdlib.h in order to ensure that size_t is defined. */ /* Have to include stdlib.h in order to ensure that size_t is defined. */
#include <stdlib.h> #include <stdlib.h>
/* Allow for C++ users */ /* Allow for C++ users */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* Options, mostly defined by POSIX, but with a couple of extras. */ /* Options, mostly defined by POSIX, but with some extras. */
#define REG_ICASE 0x0001 #define REG_ICASE 0x0001 /* Maps to PCRE_CASELESS */
#define REG_NEWLINE 0x0002 #define REG_NEWLINE 0x0002 /* Maps to PCRE_MULTILINE */
#define REG_NOTBOL 0x0004 #define REG_NOTBOL 0x0004 /* Maps to PCRE_NOTBOL */
#define REG_NOTEOL 0x0008 #define REG_NOTEOL 0x0008 /* Maps to PCRE_NOTEOL */
#define REG_DOTALL 0x0010 /* NOT defined by POSIX. */ #define REG_DOTALL 0x0010 /* NOT defined by POSIX; maps to PCRE_DOTALL
#define REG_NOSUB 0x0020 */
#define REG_UTF8 0x0040 /* NOT defined by POSIX. */ #define REG_NOSUB 0x0020 /* Maps to PCRE_NO_AUTO_CAPTURE */
#define REG_UTF8 0x0040 /* NOT defined by POSIX; maps to PCRE_UTF8 *
/
#define REG_STARTEND 0x0080 /* BSD feature: pass subject string by so,eo
*/
#define REG_NOTEMPTY 0x0100 /* NOT defined by POSIX; maps to PCRE_NOTEMP
TY */
#define REG_UNGREEDY 0x0200 /* NOT defined by POSIX; maps to PCRE_UNGREE
DY */
#define REG_UCP 0x0400 /* NOT defined by POSIX; maps to PCRE_UCP */
/* This is not used by PCRE, but by defining it we make it easier /* This is not used by PCRE, but by defining it we make it easier
to slot PCRE into existing programs that make POSIX calls. */ to slot PCRE into existing programs that make POSIX calls. */
#define REG_EXTENDED 0 #define REG_EXTENDED 0
/* Error values. Not all these are relevant or used by the wrapper. */ /* Error values. Not all these are relevant or used by the wrapper. */
enum { enum {
REG_ASSERT = 1, /* internal error ? */ REG_ASSERT = 1, /* internal error ? */
 End of changes. 3 change blocks. 
9 lines changed or deleted 18 lines changed or added


 pdfile.h   pdfile.h 
skipping to change at line 28 skipping to change at line 28
Files: Files:
database.ns - namespace index database.ns - namespace index
database.1 - data files database.1 - data files
database.2 database.2
... ...
*/ */
#pragma once #pragma once
#include "../pch.h" #include "mongo/db/client.h"
#include "../util/mmap.h" #include "mongo/db/diskloc.h"
#include "diskloc.h" #include "mongo/db/jsobjmanipulator.h"
#include "jsobjmanipulator.h" #include "mongo/db/memconcept.h"
#include "namespace-inl.h" #include "mongo/db/mongommf.h"
#include "client.h" #include "mongo/db/namespace-inl.h"
#include "mongommf.h" #include "mongo/db/namespace_details-inl.h"
#include "memconcept.h" #include "mongo/db/namespacestring.h"
#include "mongo/util/mmap.h"
#include "mongo/util/util.h"
namespace mongo { namespace mongo {
// pdfile versions
const int PDFILE_VERSION = 4;
const int PDFILE_VERSION_MINOR = 5;
class DataFileHeader; class DataFileHeader;
class Extent; class Extent;
class Record; class Record;
class Cursor; class Cursor;
class OpDebug; class OpDebug;
void dropDatabase(string db); void dropDatabase(string db);
bool repairDatabase(string db, string &errmsg, bool preserveClonedFiles OnFailure = false, bool backupOriginalFiles = false); bool repairDatabase(string db, string &errmsg, bool preserveClonedFiles OnFailure = false, bool backupOriginalFiles = false);
/* low level - only drops this ns */ /* low level - only drops this ns */
skipping to change at line 127 skipping to change at line 133
/** @return DiskLoc where item ends up */ /** @return DiskLoc where item ends up */
// changedId should be initialized to false // changedId should be initialized to false
const DiskLoc updateRecord( const DiskLoc updateRecord(
const char *ns, const char *ns,
NamespaceDetails *d, NamespaceDetails *d,
NamespaceDetailsTransient *nsdt, NamespaceDetailsTransient *nsdt,
Record *toupdate, const DiskLoc& dl, Record *toupdate, const DiskLoc& dl,
const char *buf, int len, OpDebug& debug, bool god=false); const char *buf, int len, OpDebug& debug, bool god=false);
// The object o may be updated if modified on insert. // The object o may be updated if modified on insert.
void insertAndLog( const char *ns, const BSONObj &o, bool god = fal se ); void insertAndLog( const char *ns, const BSONObj &o, bool god = fal se, bool fromMigrate = false );
/** insert will add an _id to the object if not present. if you wo uld like to see the final object /** insert will add an _id to the object if not present. if you wo uld like to see the final object
after such an addition, use this method. after such an addition, use this method.
@param o both and in and out param @param o both and in and out param
*/ */
DiskLoc insertWithObjMod(const char *ns, BSONObj & /*out*/o, bool g od = false); DiskLoc insertWithObjMod(const char *ns, BSONObj & /*out*/o, bool g od = false);
/** @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) ;
skipping to change at line 166 skipping to change at line 172
private: private:
vector<MongoDataFile *> files; vector<MongoDataFile *> files;
}; };
extern DataFileMgr theDataFileMgr; extern DataFileMgr theDataFileMgr;
#pragma pack(1) #pragma pack(1)
class DeletedRecord { class DeletedRecord {
public: public:
int lengthWithHeaders;
int extentOfs; int lengthWithHeaders() const { _accessing(); return _lengthWithHea
DiskLoc nextDeleted; ders; }
int& lengthWithHeaders() { _accessing(); return _lengthWithHeaders;
}
int extentOfs() const { _accessing(); return _extentOfs; }
int& extentOfs() { _accessing(); return _extentOfs; }
// TODO: we need to not const_cast here but problem is DiskLoc::wri
ting
DiskLoc& nextDeleted() const { _accessing(); return const_cast<Disk
Loc&>(_nextDeleted); }
DiskLoc myExtentLoc(const DiskLoc& myLoc) const { DiskLoc myExtentLoc(const DiskLoc& myLoc) const {
return DiskLoc(myLoc.a(), extentOfs); _accessing();
return DiskLoc(myLoc.a(), _extentOfs);
} }
Extent* myExtent(const DiskLoc& myLoc) { Extent* myExtent(const DiskLoc& myLoc) {
return DataFileMgr::getExtent(DiskLoc(myLoc.a(), extentOfs)); _accessing();
return DataFileMgr::getExtent(DiskLoc(myLoc.a(), _extentOfs));
} }
private:
void _accessing() const;
int _lengthWithHeaders;
int _extentOfs;
DiskLoc _nextDeleted;
}; };
/* Record is a record in a datafile. DeletedRecord is similar but for deleted space. /* Record is a record in a datafile. DeletedRecord is similar but for deleted space.
*11:03:20 AM) dm10gen: regarding extentOfs... *11:03:20 AM) dm10gen: regarding extentOfs...
(11:03:42 AM) dm10gen: an extent is a continugous disk area, which cont ains many Records and DeleteRecords (11:03:42 AM) dm10gen: an extent is a continugous disk area, which cont ains many Records and DeleteRecords
(11:03:56 AM) dm10gen: a DiskLoc has two pieces, the fileno and ofs. ( 64 bit total) (11:03:56 AM) dm10gen: a DiskLoc has two pieces, the fileno and ofs. ( 64 bit total)
(11:04:16 AM) dm10gen: to keep the headesr small, instead of storing a 64 bit ptr to the full extent address, we keep just the offset (11:04:16 AM) dm10gen: to keep the headesr small, instead of storing a 64 bit ptr to the full extent address, we keep just the offset
(11:04:29 AM) dm10gen: we can do this as we know the record's address, and it has the same fileNo (11:04:29 AM) dm10gen: we can do this as we know the record's address, and it has the same fileNo
(11:04:33 AM) dm10gen: see class DiskLoc for more info (11:04:33 AM) dm10gen: see class DiskLoc for more info
(11:04:43 AM) dm10gen: so that is how Record::myExtent() works (11:04:43 AM) dm10gen: so that is how Record::myExtent() works
(11:04:53 AM) dm10gen: on an alloc(), when we build a new Record, we mu st populate its extentOfs then (11:04:53 AM) dm10gen: on an alloc(), when we build a new Record, we mu st populate its extentOfs then
*/ */
class Record { class Record {
public: public:
enum HeaderSizeValue { HeaderSize = 16 }; enum HeaderSizeValue { HeaderSize = 16 };
int lengthWithHeaders;
int extentOfs;
int nextOfs;
int prevOfs;
/** be careful when referencing this that your write intent was cor int lengthWithHeaders() const { _accessing(); return _lengthWithHe
rect */ aders; }
char data[4]; int& lengthWithHeaders() { _accessing(); return _lengthWithHeaders
; }
int netLength() { int extentOfs() const { _accessing(); return _extentOfs; }
return lengthWithHeaders - HeaderSize; int& extentOfs() { _accessing(); return _extentOfs; }
}
//void setNewLength(int netlen) { lengthWithHeaders = netlen + Head int nextOfs() const { _accessing(); return _nextOfs; }
erSize; } int& nextOfs() { _accessing(); return _nextOfs; }
int prevOfs() const { _accessing(); return _prevOfs; }
int& prevOfs() { _accessing(); return _prevOfs; }
const char * data() const { _accessing(); return _data; }
char * data() { _accessing(); return _data; }
int netLength() const { _accessing(); return _netLength(); }
/* use this when a record is deleted. basically a union with next/p rev fields */ /* use this when a record is deleted. basically a union with next/p rev fields */
DeletedRecord& asDeleted() { return *((DeletedRecord*) this); } DeletedRecord& asDeleted() { return *((DeletedRecord*) this); }
Extent* myExtent(const DiskLoc& myLoc) { return DataFileMgr::getExt ent(DiskLoc(myLoc.a(), extentOfs)); } Extent* myExtent(const DiskLoc& myLoc) { return DataFileMgr::getExt ent(DiskLoc(myLoc.a(), extentOfs() ) ); }
/* get the next record in the namespace, traversing extents as nece ssary */ /* get the next record in the namespace, traversing extents as nece ssary */
DiskLoc getNext(const DiskLoc& myLoc); DiskLoc getNext(const DiskLoc& myLoc);
DiskLoc getPrev(const DiskLoc& myLoc); DiskLoc getPrev(const DiskLoc& myLoc);
DiskLoc nextInExtent(const DiskLoc& myLoc) { DiskLoc nextInExtent(const DiskLoc& myLoc) {
if ( nextOfs == DiskLoc::NullOfs ) _accessing();
if ( _nextOfs == DiskLoc::NullOfs )
return DiskLoc(); return DiskLoc();
assert( nextOfs ); verify( _nextOfs );
return DiskLoc(myLoc.a(), nextOfs); return DiskLoc(myLoc.a(), _nextOfs);
} }
struct NP { struct NP {
int nextOfs; int nextOfs;
int prevOfs; int prevOfs;
}; };
NP* np() { return (NP*) &nextOfs; } NP* np() { return (NP*) &_nextOfs; }
// --------------------- // ---------------------
// memory cache // memory cache
// --------------------- // ---------------------
/** /**
* touches the data so that is in physical memory * touches the data so that is in physical memory
* @param entireRecrd if false, only the header and first byte is t ouched * @param entireRecrd if false, only the header and first byte is t ouched
* if true, the entire record is touched * if true, the entire record is touched
* */ * */
void touch( bool entireRecrd = false ); void touch( bool entireRecrd = false ) const;
/** /**
* @return if this record is likely in physical memory * @return if this record is likely in physical memory
* its not guaranteed because its possible it gets swapped out in a very unlucky windows * its not guaranteed because its possible it gets swapped out in a very unlucky windows
*/ */
bool likelyInPhysicalMemory(); bool likelyInPhysicalMemory() const ;
/** /**
* tell the cache this Record was accessed * tell the cache this Record was accessed
* @return this, for simple chaining * @return this, for simple chaining
*/ */
Record* accessed(); Record* accessed();
private:
int _netLength() const { return _lengthWithHeaders - HeaderSize; }
/**
* call this when accessing a field which could hit disk
*/
void _accessing() const;
int _lengthWithHeaders;
int _extentOfs;
int _nextOfs;
int _prevOfs;
/** be careful when referencing this that your write intent was cor
rect */
char _data[4];
public:
static bool MemoryTrackingEnabled; static bool MemoryTrackingEnabled;
}; };
/* extents are datafile regions where all the records within the region /* extents are datafile regions where all the records within the region
belong to the same namespace. belong to the same namespace.
(11:12:35 AM) dm10gen: when the extent is allocated, all its empty spac e is stuck into one big DeletedRecord (11:12:35 AM) dm10gen: when the extent is allocated, all its empty spac e is stuck into one big DeletedRecord
(11:12:55 AM) dm10gen: and that is placed on the free list (11:12:55 AM) dm10gen: and that is placed on the free list
*/ */
class Extent { class Extent {
skipping to change at line 303 skipping to change at line 350
/* assumes already zeroed -- insufficient for block 'reuse' perhaps /* assumes already zeroed -- insufficient for block 'reuse' perhaps
Returns a DeletedRecord location which is the data in the extent re ady for us. Returns a DeletedRecord location which is the data in the extent re ady for us.
Caller will need to add that to the freelist structure in namespace detail. Caller will need to add that to the freelist structure in namespace detail.
*/ */
DiskLoc init(const char *nsname, int _length, int _fileNo, int _off set, bool capped); DiskLoc init(const char *nsname, int _length, int _fileNo, int _off set, bool capped);
/* like init(), but for a reuse case */ /* like init(), but for a reuse case */
DiskLoc reuse(const char *nsname, bool newUseIsAsCapped); DiskLoc reuse(const char *nsname, bool newUseIsAsCapped);
bool isOk() const { return magic == 0x41424344; } bool isOk() const { return magic == 0x41424344; }
void assertOk() const { assert(isOk()); } void assertOk() const { verify(isOk()); }
Record* newRecord(int len); Record* newRecord(int len);
Record* getRecord(DiskLoc dl) { Record* getRecord(DiskLoc dl) {
assert( !dl.isNull() ); verify( !dl.isNull() );
assert( dl.sameFile(myLoc) ); verify( dl.sameFile(myLoc) );
int x = dl.getOfs() - myLoc.getOfs(); int x = dl.getOfs() - myLoc.getOfs();
assert( x > 0 ); verify( x > 0 );
return (Record *) (((char *) this) + x); return (Record *) (((char *) this) + x);
} }
Extent* getNextExtent() { return xnext.isNull() ? 0 : DataFileMgr:: getExtent(xnext); } Extent* getNextExtent() { return xnext.isNull() ? 0 : DataFileMgr:: getExtent(xnext); }
Extent* getPrevExtent() { return xprev.isNull() ? 0 : DataFileMgr:: getExtent(xprev); } Extent* getPrevExtent() { return xprev.isNull() ? 0 : DataFileMgr:: getExtent(xprev); }
static int maxSize(); static int maxSize();
static int minSize() { return 0x100; } static int minSize() { return 0x1000; }
/** /**
* @param len lengt of record we need * @param len lengt of record we need
* @param lastRecord size of last extent which is a factor in next extent size * @param lastRecord size of last extent which is a factor in next extent size
*/ */
static int followupSize(int len, int lastExtentLen); static int followupSize(int len, int lastExtentLen);
/** get a suggested size for the first extent in a namespace /** get a suggested size for the first extent in a namespace
* @param len length of record we need to insert * @param len length of record we need to insert
*/ */
static int initialSize(int len); static int initialSize(int len);
skipping to change at line 384 skipping to change at line 431
bool uninitialized() const { return version == 0; } bool uninitialized() const { return version == 0; }
void init(int fileno, int filelength, const char* filename) { void init(int fileno, int filelength, const char* filename) {
if ( uninitialized() ) { if ( uninitialized() ) {
DEV log() << "datafileheader::init initializing " << filena me << " n:" << fileno << endl; DEV log() << "datafileheader::init initializing " << filena me << " n:" << fileno << endl;
if( !(filelength > 32768 ) ) { if( !(filelength > 32768 ) ) {
massert(13640, str::stream() << "DataFileHeader looks c orrupt at file open filelength:" << filelength << " fileno:" << fileno, fal se); massert(13640, str::stream() << "DataFileHeader looks c orrupt at file open filelength:" << filelength << " fileno:" << fileno, fal se);
} }
{ {
if( !d.dbMutex.isWriteLocked() ) { // "something" is too vague, but we checked for the rig
ht db to be locked higher up the call stack
if( !Lock::somethingWriteLocked() ) {
LockState::Dump();
log() << "*** TEMP NOT INITIALIZING FILE " << filen ame << ", not in a write lock." << endl; log() << "*** TEMP NOT INITIALIZING FILE " << filen ame << ", not in a write lock." << endl;
log() << "temp bypass until more elaborate change - case that is manifesting is benign anyway" << endl; log() << "temp bypass until more elaborate change - case that is manifesting is benign anyway" << endl;
return; return;
/** /**
log() << "ERROR can't create outside a write lock" << endl; log() << "ERROR can't create outside a write lock" << endl;
printStackTrace(); printStackTrace();
::abort(); ::abort();
**/ **/
} }
} }
getDur().createdFile(filename, filelength); getDur().createdFile(filename, filelength);
assert( HeaderSize == 8192 ); verify( HeaderSize == 8192 );
DataFileHeader *h = getDur().writing(this); DataFileHeader *h = getDur().writing(this);
h->fileLength = filelength; h->fileLength = filelength;
h->version = PDFILE_VERSION; h->version = PDFILE_VERSION;
h->versionMinor = PDFILE_VERSION_MINOR; h->versionMinor = PDFILE_VERSION_MINOR;
h->unused.set( fileno, HeaderSize ); h->unused.set( fileno, HeaderSize );
assert( (data-(char*)this) == HeaderSize ); verify( (data-(char*)this) == HeaderSize );
h->unusedLength = fileLength - HeaderSize - 16; h->unusedLength = fileLength - HeaderSize - 16;
} }
} }
bool isEmpty() const { bool isEmpty() const {
return uninitialized() || ( unusedLength == fileLength - Header Size - 16 ); return uninitialized() || ( unusedLength == fileLength - Header Size - 16 );
} }
}; };
#pragma pack() #pragma pack()
inline Extent* MongoDataFile::_getExtent(DiskLoc loc) const { inline Extent* MongoDataFile::_getExtent(DiskLoc loc) const {
loc.assertOk(); loc.assertOk();
Extent *e = (Extent *) (p()+loc.getOfs()); Extent *e = (Extent *) (p()+loc.getOfs());
return e; return e;
} }
inline Extent* MongoDataFile::getExtent(DiskLoc loc) const { inline Extent* MongoDataFile::getExtent(DiskLoc loc) const {
Extent *e = _getExtent(loc); Extent *e = _getExtent(loc);
e->assertOk(); e->assertOk();
memconcept::is(e, memconcept::extent); memconcept::is(e, memconcept::concept::extent);
return e; return e;
} }
} // namespace mongo } // namespace mongo
#include "cursor.h" #include "cursor.h"
namespace mongo { namespace mongo {
inline Record* MongoDataFile::recordAt(DiskLoc dl) { inline Record* MongoDataFile::recordAt(DiskLoc dl) {
skipping to change at line 447 skipping to change at line 496
return (Record*) (p()+ofs); return (Record*) (p()+ofs);
} }
inline Record* MongoDataFile::makeRecord(DiskLoc dl, int size) { inline Record* MongoDataFile::makeRecord(DiskLoc dl, int size) {
int ofs = dl.getOfs(); int ofs = dl.getOfs();
if( ofs < DataFileHeader::HeaderSize ) badOfs(ofs); // will uassert - external call to keep out of the normal code path if( ofs < DataFileHeader::HeaderSize ) badOfs(ofs); // will uassert - external call to keep out of the normal code path
return (Record*) (p()+ofs); return (Record*) (p()+ofs);
} }
inline DiskLoc Record::getNext(const DiskLoc& myLoc) { inline DiskLoc Record::getNext(const DiskLoc& myLoc) {
if ( nextOfs != DiskLoc::NullOfs ) { _accessing();
if ( _nextOfs != DiskLoc::NullOfs ) {
/* defensive */ /* defensive */
if ( nextOfs >= 0 && nextOfs < 10 ) { if ( _nextOfs >= 0 && _nextOfs < 10 ) {
sayDbContext("Assertion failure - Record::getNext() referen cing a deleted record?"); sayDbContext("Assertion failure - Record::getNext() referen cing a deleted record?");
return DiskLoc(); return DiskLoc();
} }
return DiskLoc(myLoc.a(), nextOfs); return DiskLoc(myLoc.a(), _nextOfs);
} }
Extent *e = myExtent(myLoc); Extent *e = myExtent(myLoc);
while ( 1 ) { while ( 1 ) {
if ( e->xnext.isNull() ) if ( e->xnext.isNull() )
return DiskLoc(); // end of table. return DiskLoc(); // end of table.
e = e->xnext.ext(); e = e->xnext.ext();
if ( !e->firstRecord.isNull() ) if ( !e->firstRecord.isNull() )
break; break;
// entire extent could be empty, keep looking // entire extent could be empty, keep looking
} }
return e->firstRecord; return e->firstRecord;
} }
inline DiskLoc Record::getPrev(const DiskLoc& myLoc) { inline DiskLoc Record::getPrev(const DiskLoc& myLoc) {
if ( prevOfs != DiskLoc::NullOfs ) _accessing();
return DiskLoc(myLoc.a(), prevOfs); if ( _prevOfs != DiskLoc::NullOfs )
return DiskLoc(myLoc.a(), _prevOfs);
Extent *e = myExtent(myLoc); Extent *e = myExtent(myLoc);
if ( e->xprev.isNull() ) if ( e->xprev.isNull() )
return DiskLoc(); return DiskLoc();
return e->xprev.ext()->lastRecord; return e->xprev.ext()->lastRecord;
} }
inline BSONObj DiskLoc::obj() const { inline BSONObj DiskLoc::obj() const {
return BSONObj(rec()->accessed()); return BSONObj(rec()->accessed());
} }
inline DeletedRecord* DiskLoc::drec() const { inline DeletedRecord* DiskLoc::drec() const {
assert( _a != -1 ); verify( _a != -1 );
DeletedRecord* dr = (DeletedRecord*) rec(); DeletedRecord* dr = (DeletedRecord*) rec();
memconcept::is(dr, memconcept::deletedrecord); memconcept::is(dr, memconcept::concept::deletedrecord);
return dr; return dr;
} }
inline Extent* DiskLoc::ext() const { inline Extent* DiskLoc::ext() const {
return DataFileMgr::getExtent(*this); return DataFileMgr::getExtent(*this);
} }
template< class V > template< class V >
inline inline
const BtreeBucket<V> * DiskLoc::btree() const { const BtreeBucket<V> * DiskLoc::btree() const {
assert( _a != -1 ); verify( _a != -1 );
return (const BtreeBucket<V> *) rec()->data; Record *r = rec();
memconcept::is(r, memconcept::concept::btreebucket, "", 8192);
return (const BtreeBucket<V> *) r->data();
} }
} // namespace mongo } // namespace mongo
#include "database.h" #include "database.h"
#include "memconcept.h" #include "memconcept.h"
namespace mongo { namespace mongo {
boost::intmax_t dbSize( const char *database ); boost::intmax_t dbSize( const char *database );
inline NamespaceIndex* nsindex(const char *ns) { inline NamespaceIndex* nsindex(const char *ns) {
Database *database = cc().database(); Database *database = cc().database();
assert( database ); verify( database );
memconcept::is(database, memconcept::database, ns, sizeof(Database) memconcept::is(database, memconcept::concept::database, ns, sizeof(
); Database));
DEV { DEV {
char buf[256]; char buf[256];
nsToDatabase(ns, buf); nsToDatabase(ns, buf);
if ( database->name != buf ) { if ( database->name != buf ) {
out() << "ERROR: attempt to write to wrong database\n"; out() << "ERROR: attempt to write to wrong database\n";
out() << " ns:" << ns << '\n'; out() << " ns:" << ns << '\n';
out() << " database->name:" << database->name << endl; out() << " database->name:" << database->name << endl;
assert( database->name == buf ); verify( database->name == buf );
} }
} }
return &database->namespaceIndex; return &database->namespaceIndex;
} }
inline NamespaceDetails* nsdetails(const char *ns) { inline NamespaceDetails* nsdetails(const char *ns) {
// if this faults, did you set the current db first? (Client::Cont ext + dblock) // if this faults, did you set the current db first? (Client::Cont ext + dblock)
NamespaceDetails *d = nsindex(ns)->details(ns); NamespaceDetails *d = nsindex(ns)->details(ns);
if( d ) { if( d ) {
memconcept::is(d, memconcept::nsdetails, ns, sizeof(NamespaceDe tails)); memconcept::is(d, memconcept::concept::nsdetails, ns, sizeof(Na mespaceDetails));
} }
return d; return d;
} }
inline Extent* DataFileMgr::getExtent(const DiskLoc& dl) { inline Extent* DataFileMgr::getExtent(const DiskLoc& dl) {
assert( dl.a() != -1 ); verify( dl.a() != -1 );
return cc().database()->getFile(dl.a())->getExtent(dl); return cc().database()->getFile(dl.a())->getExtent(dl);
} }
inline Record* DataFileMgr::getRecord(const DiskLoc& dl) { inline Record* DataFileMgr::getRecord(const DiskLoc& dl) {
assert( dl.a() != -1 ); verify( dl.a() != -1 );
Record* r = cc().database()->getFile(dl.a())->recordAt(dl); Record* r = cc().database()->getFile(dl.a())->recordAt(dl);
return r; return r;
} }
BOOST_STATIC_ASSERT( 16 == sizeof(DeletedRecord) ); BOOST_STATIC_ASSERT( 16 == sizeof(DeletedRecord) );
inline DeletedRecord* DataFileMgr::makeDeletedRecord(const DiskLoc& dl, int len) { inline DeletedRecord* DataFileMgr::makeDeletedRecord(const DiskLoc& dl, int len) {
assert( dl.a() != -1 ); verify( dl.a() != -1 );
return (DeletedRecord*) cc().database()->getFile(dl.a())->makeRecor d(dl, sizeof(DeletedRecord)); return (DeletedRecord*) cc().database()->getFile(dl.a())->makeRecor d(dl, sizeof(DeletedRecord));
} }
void ensureHaveIdIndex(const char *ns); void ensureHaveIdIndex(const char *ns);
bool dropIndexes( NamespaceDetails *d, const char *ns, const char *name , string &errmsg, BSONObjBuilder &anObjBuilder, bool maydeleteIdIndex ); bool dropIndexes( NamespaceDetails *d, const char *ns, const char *name , string &errmsg, BSONObjBuilder &anObjBuilder, bool maydeleteIdIndex );
inline BSONObj::BSONObj(const Record *r) { inline BSONObj::BSONObj(const Record *r) {
init(r->data); init(r->data());
} }
} // namespace mongo } // namespace mongo
 End of changes. 39 change blocks. 
60 lines changed or deleted 119 lines changed or added


 pipeline_d.h   pipeline_d.h 
skipping to change at line 50 skipping to change at line 50
will feed the execution of the pipeline. will feed the execution of the pipeline.
This method looks for early pipeline stages that can be folded i nto This method looks for early pipeline stages that can be folded i nto
the underlying cursor, and when a cursor can absorb those, they the underlying cursor, and when a cursor can absorb those, they
are removed from the head of the pipeline. For example, an are removed from the head of the pipeline. For example, an
early match can be removed and replaced with a Cursor that will early match can be removed and replaced with a Cursor that will
do an index scan. do an index scan.
@param pPipeline the logical "this" for this operation @param pPipeline the logical "this" for this operation
@param dbName the name of the database @param dbName the name of the database
@param pExpCtx the expression context for this pipeline
@returns a document source that wraps an appropriate cursor to @returns a document source that wraps an appropriate cursor to
be at the beginning of this pipeline be at the beginning of this pipeline
*/ */
static intrusive_ptr<DocumentSource> prepareCursorSource( static intrusive_ptr<DocumentSource> prepareCursorSource(
const intrusive_ptr<Pipeline> &pPipeline, const intrusive_ptr<Pipeline> &pPipeline,
const string &dbName); const string &dbName,
const intrusive_ptr<ExpressionContext> &pExpCtx);
private: private:
PipelineD(); // does not exist: prevent instantiation PipelineD(); // does not exist: prevent instantiation
}; };
} // namespace mongo } // namespace mongo
 End of changes. 2 change blocks. 
1 lines changed or deleted 3 lines changed or added


 processinfo.h   processinfo.h 
skipping to change at line 30 skipping to change at line 30
#include <sys/types.h> #include <sys/types.h>
#include <string> #include <string>
#ifndef _WIN32 #ifndef _WIN32
#include <unistd.h> #include <unistd.h>
#else #else
typedef int pid_t; typedef int pid_t;
int getpid(); int getpid();
#endif #endif
namespace mongo { #include <db/jsobj.h>
class BSONObjBuilder; namespace mongo {
class ProcessInfo { class ProcessInfo {
public: public:
ProcessInfo( pid_t pid = getpid() ); ProcessInfo( pid_t pid = getpid() );
~ProcessInfo(); ~ProcessInfo();
/** /**
* @return mbytes * @return mbytes
*/ */
int getVirtualMemorySize(); int getVirtualMemorySize();
/** /**
* @return mbytes * @return mbytes
*/ */
int getResidentSize(); int getResidentSize();
/** /**
* Get the type of os (e.g. Windows, Linux, Mac OS)
*/
const string& getOsType() const { return sysInfo().osType; }
/**
* Get the os Name (e.g. Ubuntu, Gentoo, Windows Server 2008)
*/
const string& getOsName() const { return sysInfo().osName; }
/**
* Get the os version (e.g. 10.04, 11.3.0, 6.1 (build 7600))
*/
const string& getOsVersion() const { return sysInfo().osVersion; }
/**
* Get the cpu address size (e.g. 32, 36, 64)
*/
const unsigned getAddrSize() const { return sysInfo().addrSize; }
/**
* Get the total amount of system memory in MB
*/
const unsigned long long getMemSizeMB() const { return sysInfo().me
mSize / (1024 * 1024); }
/**
* Get the number of CPUs
*/
const unsigned getNumCores() const { return sysInfo().numCores; }
/**
* Get the CPU architecture (e.g. x86, x86_64)
*/
const string& getArch() const { return sysInfo().cpuArch; }
/**
* Determine if NUMA is enabled (interleaved) for this process
*/
bool hasNumaEnabled() const { return sysInfo().hasNuma; }
/**
* Get extra system stats
*/
void appendSystemDetails( BSONObjBuilder& details ) const {
details.append( StringData("extra"), sysInfo()._extraStats.copy
() );
}
/**
* Append platform-specific data to obj * Append platform-specific data to obj
*/ */
void getExtraInfo(BSONObjBuilder& info); void getExtraInfo( BSONObjBuilder& info );
bool supported(); bool supported();
static bool blockCheckSupported(); static bool blockCheckSupported();
static bool blockInMemory( char * start ); static bool blockInMemory( char * start );
private: private:
/**
* Host and operating system info. Does not change over time.
*/
class SystemInfo {
public:
string osType;
string osName;
string osVersion;
unsigned addrSize;
unsigned long long memSize;
unsigned numCores;
string cpuArch;
bool hasNuma;
BSONObj _extraStats;
SystemInfo() :
addrSize( 0 ),
memSize( 0 ),
numCores( 0 ),
hasNuma( false ) {
// populate SystemInfo during construction
collectSystemInfo();
}
private:
/** Collect host system info */
void collectSystemInfo();
};
pid_t _pid; pid_t _pid;
static mongo::mutex _sysInfoLock;
static bool checkNumaEnabled();
const SystemInfo& sysInfo() const {
// initialize and collect sysInfo on first call
// TODO: SERVER-5112
static ProcessInfo::SystemInfo *initSysInfo = NULL;
if ( ! initSysInfo ) {
scoped_lock lk( _sysInfoLock );
if ( ! initSysInfo ) {
initSysInfo = new SystemInfo();
}
}
return *initSysInfo;
}
}; };
void writePidFile( const std::string& path ); void writePidFile( const std::string& path );
void printMemInfo( const char * whereContextStr = 0 ); void printMemInfo( const char * whereContextStr = 0 );
} }
 End of changes. 7 change blocks. 
3 lines changed or deleted 97 lines changed or added


 query.h   query.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
#include "../../pch.h" #include "../../pch.h"
#include "../../util/net/message.h" #include "../../util/net/message.h"
#include "../dbmessage.h" #include "../dbmessage.h"
#include "../jsobj.h" #include "../jsobj.h"
#include "../diskloc.h" #include "../diskloc.h"
#include "../projection.h" #include "../explain.h"
#include "../../s/d_chunk_manager.h"
// struct QueryOptions, QueryResult, QueryResultFlags in: // struct QueryOptions, QueryResult, QueryResultFlags in:
#include "../../client/dbclient.h"
namespace mongo { namespace mongo {
extern const int MaxBytesToReturnToClientAtOnce; class ParsedQuery;
class QueryOptimizerCursor;
class QueryPlanSummary;
QueryResult* processGetMore(const char *ns, int ntoreturn, long long cu rsorid , CurOp& op, int pass, bool& exhaust); QueryResult* processGetMore(const char *ns, int ntoreturn, long long cu rsorid , CurOp& op, int pass, bool& exhaust);
const char * runQuery(Message& m, QueryMessage& q, CurOp& curop, Messag e &result); const char * runQuery(Message& m, QueryMessage& q, CurOp& curop, Messag e &result);
/* This is for languages whose "objects" are not well ordered (JSON is /** Exception indicating that a query should be retried from the beginn
well ordered). ing. */
[ { a : ... } , { b : ... } ] -> { a : ..., b : ... } class QueryRetryException : public DBException {
*/ public:
inline BSONObj transformOrderFromArrayFormat(BSONObj order) { QueryRetryException() : DBException( "query retry exception" , 1608
/* note: this is slow, but that is ok as order will have very few p 3 ) {
ieces */ return;
BSONObjBuilder b; massert( 16083, "reserve 16083", true ); // Reserve 16083.
char p[2] = "0";
while ( 1 ) {
BSONObj j = order.getObjectField(p);
if ( j.isEmpty() )
break;
BSONElement e = j.firstElement();
uassert( 10102 , "bad order array", !e.eoo());
uassert( 10103 , "bad order array [2]", e.isNumber());
b.append(e);
(*p)++;
uassert( 10104 , "too many ordering elements", *p <= '9');
} }
};
return b.obj(); /** Interface for recording events that contribute to explain results.
} */
class ExplainRecordingStrategy {
/**
* this represents a total user query
* includes fields from the query message, both possible query levels
* parses everything up front
*/
class ParsedQuery : boost::noncopyable {
public: public:
ParsedQuery( QueryMessage& qm ) ExplainRecordingStrategy( const ExplainQueryInfo::AncillaryInfo &an
: _ns( qm.ns ) , _ntoskip( qm.ntoskip ) , _ntoreturn( qm.ntoret cillaryInfo );
urn ) , _options( qm.queryOptions ) { virtual ~ExplainRecordingStrategy() {}
init( qm.query ); /** Note information about a single query plan. */
initFields( qm.fields ); virtual void notePlan( bool scanAndOrder, bool indexOnly ) {}
} /** Note an iteration of the query. */
ParsedQuery( const char* ns , int ntoskip , int ntoreturn , int que virtual void noteIterate( bool match, bool orderedMatch, bool loade
ryoptions , const BSONObj& query , const BSONObj& fields ) dRecord,
: _ns( ns ) , _ntoskip( ntoskip ) , _ntoreturn( ntoreturn ) , _ bool chunkSkip ) {}
options( queryoptions ) { /** Note that the query yielded. */
init( query ); virtual void noteYield() {}
initFields( fields ); /** @return number of ordered matches noted. */
} virtual long long orderedMatches() const { return 0; }
/** @return ExplainQueryInfo for a complete query. */
shared_ptr<ExplainQueryInfo> doneQueryInfo();
protected:
/** @return ExplainQueryInfo for a complete query, to be implemente
d by subclass. */
virtual shared_ptr<ExplainQueryInfo> _doneQueryInfo() = 0;
private:
ExplainQueryInfo::AncillaryInfo _ancillaryInfo;
};
const char * ns() const { return _ns; } /** No explain events are recorded. */
bool isLocalDB() const { return strncmp(_ns, "local.", 6) == 0; } class NoExplainStrategy : public ExplainRecordingStrategy {
public:
NoExplainStrategy();
private:
/** @asserts always. */
virtual shared_ptr<ExplainQueryInfo> _doneQueryInfo();
};
const BSONObj& getFilter() const { return _filter; } class MatchCountingExplainStrategy : public ExplainRecordingStrategy {
Projection* getFields() const { return _fields.get(); } public:
shared_ptr<Projection> getFieldPtr() const { return _fields; } MatchCountingExplainStrategy( const ExplainQueryInfo::AncillaryInfo
&ancillaryInfo );
int getSkip() const { return _ntoskip; } protected:
int getNumToReturn() const { return _ntoreturn; } virtual void _noteIterate( bool match, bool orderedMatch, bool load
bool wantMore() const { return _wantMore; } edRecord,
int getOptions() const { return _options; } bool chunkSkip ) = 0;
bool hasOption( int x ) const { return x & _options; } private:
virtual void noteIterate( bool match, bool orderedMatch, bool loade
bool isExplain() const { return _explain; } dRecord,
bool isSnapshot() const { return _snapshot; } bool chunkSkip );
bool returnKey() const { return _returnKey; } virtual long long orderedMatches() const { return _orderedMatches;
bool showDiskLoc() const { return _showDiskLoc; } }
long long _orderedMatches;
const BSONObj& getMin() const { return _min; } };
const BSONObj& getMax() const { return _max; }
const BSONObj& getOrder() const { return _order; }
const BSONElement& getHint() const { return _hint; }
int getMaxScan() const { return _maxScan; }
bool couldBeCommand() const {
/* we assume you are using findOne() for running a cmd... */
return _ntoreturn == 1 && strstr( _ns , ".$cmd" );
}
bool hasIndexSpecifier() const { /** Record explain events for a simple cursor representing a single cla
return ! _hint.eoo() || ! _min.isEmpty() || ! _max.isEmpty(); use and plan. */
} class SimpleCursorExplainStrategy : public MatchCountingExplainStrategy
{
public:
SimpleCursorExplainStrategy( const ExplainQueryInfo::AncillaryInfo
&ancillaryInfo,
const shared_ptr<Cursor> &cursor );
private:
virtual void notePlan( bool scanAndOrder, bool indexOnly );
virtual void _noteIterate( bool match, bool orderedMatch, bool load
edRecord,
bool chunkSkip );
virtual void noteYield();
virtual shared_ptr<ExplainQueryInfo> _doneQueryInfo();
shared_ptr<Cursor> _cursor;
shared_ptr<ExplainSinglePlanQueryInfo> _explainInfo;
};
/* if ntoreturn is zero, we return up to 101 objects. on the subse /**
quent getmore, there * Record explain events for a QueryOptimizerCursor, which may record s
is only a size limit. The idea is that on a find() where one do ome explain information
esn't use much results, * for multiple clauses and plans through an internal implementation.
we don't return much, but once getmore kicks in, we start pushin */
g significant quantities. class QueryOptimizerCursorExplainStrategy : public MatchCountingExplain
Strategy {
The n limit (vs. size) is important when someone fetches only on public:
e small field from big QueryOptimizerCursorExplainStrategy( const ExplainQueryInfo::Ancill
objects, which causes massive scanning server-side. aryInfo &ancillaryInfo,
*/ const shared_ptr<QueryOptimizer
bool enoughForFirstBatch( int n , int len ) const { Cursor> &cursor );
if ( _ntoreturn == 0 ) private:
return ( len > 1024 * 1024 ) || n >= 101; virtual void _noteIterate( bool match, bool orderedMatch, bool load
return n >= _ntoreturn || len > MaxBytesToReturnToClientAtOnce; edRecord,
} bool chunkSkip );
virtual shared_ptr<ExplainQueryInfo> _doneQueryInfo();
shared_ptr<QueryOptimizerCursor> _cursor;
};
bool enough( int n ) const { /** Interface for building a query response in a supplied BufBuilder. *
if ( _ntoreturn == 0 ) /
return false; class ResponseBuildStrategy {
return n >= _ntoreturn; public:
} /**
* @param queryPlan must be supplied if @param cursor is not a Quer
yOptimizerCursor and
* results must be sorted or read with a covered index.
*/
ResponseBuildStrategy( const ParsedQuery &parsedQuery, const shared
_ptr<Cursor> &cursor,
BufBuilder &buf, const QueryPlanSummary &quer
yPlan );
virtual ~ResponseBuildStrategy() {}
/**
* Handle the current iterate of the supplied cursor as a (possibly
duplicate) match.
* @return true if a match is found.
* @param orderedMatch set if it is an ordered match.
*/
virtual bool handleMatch( bool &orderedMatch ) = 0;
/**
* Write all matches into the buffer, overwriting existing data.
* @return number of matches written, or -1 if no op.
*/
virtual int rewriteMatches() { return -1; }
/** @return the number of matches that have been written to the buf
fer. */
virtual int bufferedMatches() const = 0;
/**
* Callback when enough results have been read for the first batch,
with potential handoff
* to getMore.
*/
virtual void finishedFirstBatch() {}
/** Reset the buffer. */
void resetBuf();
protected:
/**
* Return the document for the current iterate. Implements the $re
turnKey option.
* @param allowCovered - enable covered index support.
*/
BSONObj current( bool allowCovered ) const;
const ParsedQuery &_parsedQuery;
shared_ptr<Cursor> _cursor;
shared_ptr<QueryOptimizerCursor> _queryOptimizerCursor;
BufBuilder &_buf;
};
/** Build strategy for a cursor returning in order results. */
class OrderedBuildStrategy : public ResponseBuildStrategy {
public:
OrderedBuildStrategy( const ParsedQuery &parsedQuery, const shared_
ptr<Cursor> &cursor,
BufBuilder &buf, const QueryPlanSummary &query
Plan );
virtual bool handleMatch( bool &orderedMatch );
virtual int bufferedMatches() const { return _bufferedMatches; }
private: private:
void init( const BSONObj& q ) { int _skip;
_reset(); int _bufferedMatches;
uassert( 10105 , "bad skip value in query", _ntoskip >= 0); };
if ( _ntoreturn < 0 ) {
/* _ntoreturn greater than zero is simply a hint on how man
y objects to send back per
"cursor batch".
A negative number indicates a hard limit.
*/
_wantMore = false;
_ntoreturn = -_ntoreturn;
}
BSONElement e = q["query"];
if ( ! e.isABSONObj() )
e = q["$query"];
if ( e.isABSONObj() ) {
_filter = e.embeddedObject();
_initTop( q );
}
else {
_filter = q;
}
}
void _reset() { class ScanAndOrder;
_wantMore = true;
_explain = false;
_snapshot = false;
_returnKey = false;
_showDiskLoc = false;
_maxScan = 0;
}
void _initTop( const BSONObj& top ) { /** Build strategy for a cursor returning out of order results. */
BSONObjIterator i( top ); class ReorderBuildStrategy : public ResponseBuildStrategy {
while ( i.more() ) { public:
BSONElement e = i.next(); ReorderBuildStrategy( const ParsedQuery &parsedQuery,
const char * name = e.fieldName(); const shared_ptr<Cursor> &cursor,
BufBuilder &buf,
if ( strcmp( "$orderby" , name ) == 0 || const QueryPlanSummary &queryPlan );
strcmp( "orderby" , name ) == 0 ) { virtual bool handleMatch( bool &orderedMatch );
if ( e.type() == Object ) { /** Handle a match without performing deduping. */
_order = e.embeddedObject(); void _handleMatchNoDedup();
} virtual int rewriteMatches();
else if ( e.type() == Array ) { virtual int bufferedMatches() const { return _bufferedMatches; }
_order = transformOrderFromArrayFormat( _order ); private:
} ScanAndOrder *newScanAndOrder( const QueryPlanSummary &queryPlan )
else { const;
uasserted(13513, "sort must be an object or array") shared_ptr<ScanAndOrder> _scanAndOrder;
; int _bufferedMatches;
} };
continue;
}
if( *name == '$' ) {
name++;
if ( strcmp( "explain" , name ) == 0 )
_explain = e.trueValue();
else if ( strcmp( "snapshot" , name ) == 0 )
_snapshot = e.trueValue();
else if ( strcmp( "min" , name ) == 0 )
_min = e.embeddedObject();
else if ( strcmp( "max" , name ) == 0 )
_max = e.embeddedObject();
else if ( strcmp( "hint" , name ) == 0 )
_hint = e;
else if ( strcmp( "returnKey" , name ) == 0 )
_returnKey = e.trueValue();
else if ( strcmp( "maxScan" , name ) == 0 )
_maxScan = e.numberInt();
else if ( strcmp( "showDiskLoc" , name ) == 0 )
_showDiskLoc = e.trueValue();
else if ( strcmp( "comment" , name ) == 0 ) {
; // no-op
}
}
}
if ( _snapshot ) {
uassert( 12001 , "E12001 can't sort with $snapshot", _order
.isEmpty() );
uassert( 12002 , "E12002 can't use hint with $snapshot", _h
int.eoo() );
}
/** Helper class for deduping DiskLocs */
class DiskLocDupSet {
public:
/** @return true if dup, otherwise return false and insert. */
bool getsetdup( const DiskLoc &loc ) {
pair<set<DiskLoc>::iterator, bool> p = _dups.insert(loc);
return !p.second;
} }
private:
set<DiskLoc> _dups;
};
void initFields( const BSONObj& fields ) { /**
if ( fields.isEmpty() ) * Build strategy for a QueryOptimizerCursor containing some in order a
return; nd some out of order
_fields.reset( new Projection() ); * candidate plans.
_fields->init( fields ); */
} class HybridBuildStrategy : public ResponseBuildStrategy {
public:
HybridBuildStrategy( const ParsedQuery &parsedQuery,
const shared_ptr<QueryOptimizerCursor> &cursor,
BufBuilder &buf );
private:
virtual bool handleMatch( bool &orderedMatch );
virtual int rewriteMatches();
virtual int bufferedMatches() const;
virtual void finishedFirstBatch();
bool handleReorderMatch();
DiskLocDupSet _scanAndOrderDups;
OrderedBuildStrategy _orderedBuild;
ReorderBuildStrategy _reorderBuild;
bool _reorderedMatches;
};
const char * const _ns; /**
const int _ntoskip; * Builds a query response with the help of an ExplainRecordingStrategy
int _ntoreturn; and a
BSONObj _filter; * ResponseBuildStrategy.
BSONObj _order; */
const int _options; class QueryResponseBuilder {
shared_ptr< Projection > _fields; public:
bool _wantMore; /**
bool _explain; * @param queryPlan must be supplied if @param cursor is not a Quer
bool _snapshot; yOptimizerCursor and
bool _returnKey; * results must be sorted or read with a covered index.
bool _showDiskLoc; */
BSONObj _min; QueryResponseBuilder( const ParsedQuery &parsedQuery, const shared_
BSONObj _max; ptr<Cursor> &cursor,
BSONElement _hint; const QueryPlanSummary &queryPlan, const BSONO
int _maxScan; bj &oldPlan );
/** @return true if the current iterate matches and is added. */
bool addMatch();
/** Note that a yield occurred. */
void noteYield();
/** @return true if there are enough results to return the first ba
tch. */
bool enoughForFirstBatch() const;
/** @return true if there are enough results to return the full res
ult set. */
bool enoughTotalResults() const;
/**
* Callback when enough results have been read for the first batch,
with potential handoff
* to getMore.
*/
void finishedFirstBatch();
/**
* Set the data portion of the supplied Message to a buffer contain
ing the query results.
* @return the number of results in the buffer.
*/
int handoff( Message &result );
/** A chunk manager found at the beginning of the query. */
ShardChunkManagerPtr chunkManager() const { return _chunkManager; }
private:
ShardChunkManagerPtr newChunkManager() const;
shared_ptr<ExplainRecordingStrategy> newExplainRecordingStrategy
( const QueryPlanSummary &queryPlan, const BSONObj &oldPlan ) const
;
shared_ptr<ResponseBuildStrategy> newResponseBuildStrategy
( const QueryPlanSummary &queryPlan );
bool currentMatches();
bool chunkMatches();
const ParsedQuery &_parsedQuery;
shared_ptr<Cursor> _cursor;
shared_ptr<QueryOptimizerCursor> _queryOptimizerCursor;
BufBuilder _buf;
ShardChunkManagerPtr _chunkManager;
shared_ptr<ExplainRecordingStrategy> _explain;
shared_ptr<ResponseBuildStrategy> _builder;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 20 change blocks. 
203 lines changed or deleted 267 lines changed or added


 queryoptimizer.h   queryoptimizer.h 
skipping to change at line 22 skipping to change at line 22
* 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 "cursor.h" #include "cursor.h"
#include "jsobj.h"
#include "queryutil.h" #include "queryutil.h"
#include "matcher.h" #include "matcher.h"
#include "explain.h"
#include "../util/net/listen.h" #include "../util/net/listen.h"
#include <queue> #include "mongo/db/querypattern.h"
namespace mongo { namespace mongo {
class IndexDetails; class IndexDetails;
class IndexType; class IndexType;
class ElapsedTracker; class QueryPlanSummary;
/** A plan for executing a query using the given index spec and FieldRa ngeSet. */ /** A plan for executing a query using the given index spec and FieldRa ngeSet. */
class QueryPlan : boost::noncopyable { class QueryPlan : boost::noncopyable {
public: public:
/** /**
* @param originalFrsp - original constraints for this query clause . If null, frsp will be used instead. * @param originalFrsp - original constraints for this query clause . If null, frsp will be used instead.
*/ */
QueryPlan(NamespaceDetails *d, QueryPlan(NamespaceDetails *d,
int idxNo, // -1 = no index int idxNo, // -1 = no index
const FieldRangeSetPair &frsp, const FieldRangeSetPair &frsp,
const FieldRangeSetPair *originalFrsp, const FieldRangeSetPair *originalFrsp,
const BSONObj &originalQuery, const BSONObj &originalQuery,
const BSONObj &order, const BSONObj &order,
bool mustAssertOnYieldFailure = true, const shared_ptr<const ParsedQuery> &parsedQuery =
shared_ptr<const ParsedQuery>(),
const BSONObj &startKey = BSONObj(), const BSONObj &startKey = BSONObj(),
const BSONObj &endKey = BSONObj(), const BSONObj &endKey = BSONObj(),
string special="" ); string special="" );
/** @return true iff this plan cannot return any documents. */ /** @return true iff this plan cannot return any documents. */
bool impossible() const { return _impossible; } bool impossible() const { return _impossible; }
/** /**
* @return true iff this plan should run as the only candidate plan in the absence of an * @return true iff this plan should run as the only candidate plan in the absence of an
* impossible plan. * impossible plan.
*/ */
skipping to change at line 74 skipping to change at line 75
* @return true iff the index we are using has keys such that it ca n completely resolve the * @return true iff the index we are using has keys such that it ca n completely resolve the
* query expression to match by itself without ever checking the ma in object. * query expression to match by itself without ever checking the ma in object.
*/ */
bool exactKeyMatch() const { return _exactKeyMatch; } bool exactKeyMatch() const { return _exactKeyMatch; }
/** @return true iff this QueryPlan would perform an unindexed scan . */ /** @return true iff this QueryPlan would perform an unindexed scan . */
bool willScanTable() const { return _idxNo < 0 && !_impossible; } bool willScanTable() const { return _idxNo < 0 && !_impossible; }
/** @return 'special' attribute of the plan, which was either set e xplicitly or generated from the index. */ /** @return 'special' attribute of the plan, which was either set e xplicitly or generated from the index. */
const string &special() const { return _special; } const string &special() const { return _special; }
/** @return a new cursor based on this QueryPlan's index and FieldR angeSet. */ /** @return a new cursor based on this QueryPlan's index and FieldR angeSet. */
shared_ptr<Cursor> newCursor( const DiskLoc &startLoc = DiskLoc() , int numWanted=0 ) const; shared_ptr<Cursor> newCursor( const DiskLoc &startLoc = DiskLoc() ) const;
/** @return a new reverse cursor if this is an unindexed plan. */ /** @return a new reverse cursor if this is an unindexed plan. */
shared_ptr<Cursor> newReverseCursor() const; shared_ptr<Cursor> newReverseCursor() const;
/** Register this plan as a winner for its QueryPattern, with speci fied 'nscanned'. */ /** Register this plan as a winner for its QueryPattern, with speci fied 'nscanned'. */
void registerSelf( long long nScanned ) const; void registerSelf( long long nScanned, CandidatePlanCharacter candi datePlans ) const;
int direction() const { return _direction; } int direction() const { return _direction; }
BSONObj indexKey() const; BSONObj indexKey() const;
bool indexed() const { return _index; } bool indexed() const { return _index != 0; }
const IndexDetails *index() const { return _index; }
int idxNo() const { return _idxNo; } int idxNo() const { return _idxNo; }
const char *ns() const { return _frs.ns(); } const char *ns() const { return _frs.ns(); }
NamespaceDetails *nsd() const { return _d; } NamespaceDetails *nsd() const { return _d; }
BSONObj originalQuery() const { return _originalQuery; } BSONObj originalQuery() const { return _originalQuery; }
BSONObj simplifiedQuery( const BSONObj& fields = BSONObj() ) const
{ return _frs.simplifiedQuery( fields ); }
const FieldRange &range( const char *fieldName ) const { return _fr
s.range( fieldName ); }
shared_ptr<FieldRangeVector> originalFrv() const { return _original Frv; } shared_ptr<FieldRangeVector> originalFrv() const { return _original Frv; }
const FieldRangeSet &multikeyFrs() const { return _frsMulti; } const FieldRangeSet &multikeyFrs() const { return _frsMulti; }
bool mustAssertOnYieldFailure() const { return _mustAssertOnYieldFa ilure; } shared_ptr<Projection::KeyOnly> keyFieldsOnly() const { return _key FieldsOnly; }
/** The following member functions are just for testing. */ QueryPlanSummary summary() const;
/** The following member functions are for testing, or public for t
esting. */
shared_ptr<FieldRangeVector> frv() const { return _frv; } shared_ptr<FieldRangeVector> frv() const { return _frv; }
bool isMultiKey() const; bool isMultiKey() const;
string toString() const;
bool queryFiniteSetOrderSuffix() const;
private: private:
void checkTableScanAllowed() const; void checkTableScanAllowed() const;
void warnOnCappedIdTableScan() const; int independentRangesSingleIntervalLimit() const;
NamespaceDetails * _d; NamespaceDetails * _d;
int _idxNo; int _idxNo;
const FieldRangeSet &_frs; const FieldRangeSet &_frs;
const FieldRangeSet &_frsMulti; const FieldRangeSet &_frsMulti;
const BSONObj &_originalQuery; const BSONObj _originalQuery;
const BSONObj &_order; const BSONObj _order;
shared_ptr<const ParsedQuery> _parsedQuery;
const IndexDetails * _index; const IndexDetails * _index;
bool _optimal; bool _optimal;
bool _scanAndOrderRequired; bool _scanAndOrderRequired;
bool _exactKeyMatch; bool _exactKeyMatch;
int _direction; int _direction;
shared_ptr<FieldRangeVector> _frv; shared_ptr<FieldRangeVector> _frv;
shared_ptr<FieldRangeVector> _originalFrv; shared_ptr<FieldRangeVector> _originalFrv;
BSONObj _startKey; BSONObj _startKey;
BSONObj _endKey; BSONObj _endKey;
bool _endKeyInclusive; bool _endKeyInclusive;
bool _unhelpful; bool _unhelpful;
bool _impossible; bool _impossible;
string _special; string _special;
IndexType * _type; IndexType * _type;
bool _startOrEndSpec; bool _startOrEndSpec;
bool _mustAssertOnYieldFailure; shared_ptr<Projection::KeyOnly> _keyFieldsOnly;
};
/**
* A QueryPlanSummary owns its own attributes and may be shared. Curre
ntly a QueryPlan
* should only be owned by a QueryPlanSet.
*/
class QueryPlanSummary {
public:
QueryPlanSummary() :
_scanAndOrderRequired() {
}
QueryPlanSummary( const QueryPlan &queryPlan ) :
_fieldRangeSetMulti( new FieldRangeSet( queryPlan.multikeyFrs() ) )
,
_keyFieldsOnly( queryPlan.keyFieldsOnly() ),
_scanAndOrderRequired( queryPlan.scanAndOrderRequired() ) {
}
bool valid() const { return _fieldRangeSetMulti; }
shared_ptr<FieldRangeSet> _fieldRangeSetMulti;
shared_ptr<Projection::KeyOnly> _keyFieldsOnly;
bool _scanAndOrderRequired;
}; };
/** /**
* 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.
* *
* Normal sequence of events: * Normal sequence of events:
* 1) A new QueryOp is generated using createChild(). * 1) A new QueryOp is generated using createChild().
* 2) A QueryPlan is assigned to this QueryOp with setQueryPlan(). * 2) A QueryPlan is assigned to this QueryOp with setQueryPlan().
skipping to change at line 163 skipping to change at line 188
const QueryPlan &qp() const { return *_qp; } const QueryPlan &qp() const { return *_qp; }
/** Advance to next potential matching document (eg using a cursor) . */ /** Advance to next potential matching document (eg using a cursor) . */
virtual void next() = 0; virtual void next() = 0;
/** /**
* @return current 'nscanned' metric for this QueryOp. Used to com pare * @return current 'nscanned' metric for this QueryOp. Used to com pare
* cost to other QueryOps. * cost to other QueryOps.
*/ */
virtual long long nscanned() = 0; virtual long long nscanned() = 0;
/** Take any steps necessary before the db mutex is yielded. */ /** Take any steps necessary before the db mutex is yielded. */
virtual bool prepareToYield() { massert( 13335, "yield not supporte d", false ); return false; } virtual void prepareToYield() = 0;
/** Recover once the db mutex is regained. */ /** Recover once the db mutex is regained. */
virtual void recoverFromYield() { massert( 13336, "yield not suppor ted", false ); } virtual void recoverFromYield() = 0;
/** /**
* @return true iff the QueryPlan for this QueryOp may be registere d * @return true iff the QueryPlan for this QueryOp may be registere d
* as a winning plan. * as a winning plan.
*/ */
virtual bool mayRecordPlan() const = 0; virtual bool mayRecordPlan() const = 0;
/** @return true iff the implementation called setComplete() or set Stop(). */ /** @return true iff the implementation called setComplete() or set Stop(). */
bool complete() const { return _complete; } bool complete() const { return _complete; }
/** @return true iff the implementation called steStop(). */ /** @return true iff the implementation called steStop(). */
bool stopRequested() const { return _stopRequested; } bool stopRequested() const { return _stopRequested; }
bool completeWithoutStop() const { return complete() && !stopReques ted(); }
/** @return true iff the implementation threw an exception. */ /** @return true iff the implementation threw an exception. */
bool error() const { return _error; } bool error() const { return _error; }
/** @return the exception thrown by implementation if one was throw n. */ /** @return the exception thrown by implementation if one was throw n. */
ExceptionInfo exception() const { return _exception; } ExceptionInfo exception() const { return _exception; }
/** To be called by QueryPlanSet::Runner only. */ /** To be called by QueryPlanSet::Runner only. */
QueryOp *createChild(); QueryOp *createChild();
void setQueryPlan( const QueryPlan *qp ) { _qp = qp; assert( _qp != NULL ); } void setQueryPlan( const QueryPlan *qp ) { _qp = qp; verify( _qp != NULL ); }
void init(); void init();
void setException( const DBException &e ) { void setException( const DBException &e ) {
_error = true; _error = true;
_exception = e.getInfo(); _exception = e.getInfo();
} }
shared_ptr<CoveredIndexMatcher> matcher( const shared_ptr<Cursor>& c ) const { shared_ptr<CoveredIndexMatcher> matcher( const shared_ptr<Cursor>& c ) const {
return matcher( c.get() ); return matcher( c.get() );
} }
shared_ptr<CoveredIndexMatcher> matcher( Cursor* c ) const { shared_ptr<CoveredIndexMatcher> matcher( Cursor* c ) const {
if( ! c ) return _matcher; if( ! c ) return _matcher;
return c->matcher() ? c->matcherPtr() : _matcher; return c->matcher() ? c->matcherPtr() : _matcher;
} }
/** @return an ExplainPlanInfo object that will be updated as the q
uery runs. */
virtual shared_ptr<ExplainPlanInfo> generateExplainInfo() {
return shared_ptr<ExplainPlanInfo>( new ExplainPlanInfo() );
}
protected: protected:
/** Call if all results have been found. */ /** Call if all results have been found. */
void setComplete() { void setComplete() {
_orConstraint = qp().originalFrv(); _orConstraint = qp().originalFrv();
_complete = true; _complete = true;
} }
/** Call if the scan is complete even if not all results have been found. */ /** Call if the scan is complete even if not all results have been found. */
void setStop() { setComplete(); _stopRequested = true; } void setStop() { setComplete(); _stopRequested = true; }
/** Handle initialization after a QueryPlan has been set. */ /** Handle initialization after a QueryPlan has been set. */
virtual void _init() = 0; virtual void _init() = 0;
/** @return a copy of the inheriting class, which will be run with its own query plan. */ /** @return a copy of the inheriting class, which will be run with its own query plan. */
virtual QueryOp *_createChild() const = 0; virtual QueryOp *_createChild() const = 0;
virtual bool alwaysUseRecord() const { return false; }
private: private:
bool _complete; bool _complete;
bool _stopRequested; bool _stopRequested;
ExceptionInfo _exception; ExceptionInfo _exception;
const QueryPlan *_qp; const QueryPlan *_qp;
bool _error; bool _error;
shared_ptr<CoveredIndexMatcher> _matcher; shared_ptr<CoveredIndexMatcher> _matcher;
shared_ptr<CoveredIndexMatcher> _oldMatcher; shared_ptr<CoveredIndexMatcher> _oldMatcher;
shared_ptr<FieldRangeVector> _orConstraint; shared_ptr<FieldRangeVector> _orConstraint;
}; };
skipping to change at line 255 skipping to change at line 284
for( size_t i = 1; i < v.size(); i++ ) { for( size_t i = 1; i < v.size(); i++ ) {
if( v[t] < v[i] ) if( v[t] < v[i] )
t = i; t = i;
} }
T ret = v[t]; T ret = v[t];
v.erase(v.begin()+t); v.erase(v.begin()+t);
return ret; return ret;
} }
}; };
class QueryPlanSet;
/** Populates a provided QueryPlanSet with candidate query plans, when
requested. */
class QueryPlanGenerator {
public:
/** Policies for utilizing recorded plans. */
typedef enum {
Ignore, // Ignore the recorded plan and try all candidate plans
.
UseIfInOrder, // Use the recorded plan if it is properly ordere
d.
Use // Always use the recorded plan.
} RecordedPlanPolicy;
/** @param qps The QueryPlanSet to which plans will be provided. */
QueryPlanGenerator( QueryPlanSet &qps,
auto_ptr<FieldRangeSetPair> originalFrsp,
const shared_ptr<const ParsedQuery> &parsedQuery
,
const BSONObj &hint,
RecordedPlanPolicy recordedPlanPolicy,
const BSONObj &min,
const BSONObj &max );
/** Populate the provided QueryPlanSet with an initial set of plans
. */
void addInitialPlans();
/** Supplement a cached plan provided earlier by adding additional
query plans. */
void addFallbackPlans();
private:
bool addShortCircuitPlan( NamespaceDetails *d );
bool addHintPlan( NamespaceDetails *d );
bool addSpecialPlan( NamespaceDetails *d );
void addStandardPlans( NamespaceDetails *d );
bool addCachedPlan( NamespaceDetails *d );
shared_ptr<QueryPlan> newPlan( NamespaceDetails *d,
int idxNo,
const BSONObj &min = BSONObj(),
const BSONObj &max = BSONObj(),
const string &special = "" ) const;
bool setUnindexedPlanIf( bool set, NamespaceDetails *d );
void setSingleUnindexedPlan( NamespaceDetails *d );
void setHintedPlan( IndexDetails &id );
void warnOnCappedIdTableScan() const;
QueryPlanSet &_qps;
auto_ptr<FieldRangeSetPair> _originalFrsp;
shared_ptr<const ParsedQuery> _parsedQuery;
BSONObj _hint;
RecordedPlanPolicy _recordedPlanPolicy;
BSONObj _min;
BSONObj _max;
};
/** /**
* A set of candidate query plans for a query. This class can return a best buess plan or run a * A set of candidate query plans for a query. This class can return a best guess plan or run a
* QueryOp on all the plans. * QueryOp on all the plans.
*/ */
class QueryPlanSet { class QueryPlanSet {
public: public:
typedef boost::shared_ptr<QueryPlan> QueryPlanPtr; typedef boost::shared_ptr<QueryPlan> QueryPlanPtr;
typedef vector<QueryPlanPtr> PlanSet; typedef vector<QueryPlanPtr> PlanSet;
/** /**
* @param originalFrsp - original constraints for this query clause * @param originalFrsp - original constraints for this query clause
; if null, frsp will be used. ; if null, frsp will be
* used.
*/ */
QueryPlanSet( const char *ns, QueryPlanSet( const char *ns,
auto_ptr<FieldRangeSetPair> frsp, auto_ptr<FieldRangeSetPair> frsp,
auto_ptr<FieldRangeSetPair> originalFrsp, auto_ptr<FieldRangeSetPair> originalFrsp,
const BSONObj &originalQuery, const BSONObj &originalQuery,
const BSONObj &order, const BSONObj &order,
bool mustAssertOnYieldFailure = true, const shared_ptr<const ParsedQuery> &parsedQuery =
const BSONElement *hint = 0, shared_ptr<const ParsedQuery>(),
bool honorRecordedPlan = true, const BSONObj &hint = BSONObj(),
const BSONObj &min = BSONObj(), QueryPlanGenerator::RecordedPlanPolicy recordedPlanPol
const BSONObj &max = BSONObj(), icy =
bool bestGuessOnly = false, QueryPlanGenerator::Use,
bool mayYield = false); const BSONObj &min = BSONObj(),
const BSONObj &max = BSONObj() );
/** @return number of candidate plans. */ /** @return number of candidate plans. */
int nPlans() const { return _plans.size(); } int nPlans() const { return _plans.size(); }
/**
* Clone op for each query plan, and @return the first cloned op to
call
* setComplete() or setStop().
*/
shared_ptr<QueryOp> runOp( QueryOp &op );
template<class T>
shared_ptr<T> runOp( T &op ) {
return dynamic_pointer_cast<T>( runOp( static_cast<QueryOp&>( o
p ) ) );
}
/** Initialize or iterate a runner generated from @param originalOp
. */
shared_ptr<QueryOp> nextOp( QueryOp &originalOp, bool retried = fal
se );
/** Yield the runner member. */
bool prepareToYield();
void recoverFromYield();
/** Clear the runner member. */
void clearRunner();
QueryPlanPtr firstPlan() const { return _plans[ 0 ]; } QueryPlanPtr firstPlan() const { return _plans[ 0 ]; }
/** @return metadata about cursors and index bounds for all plans, /** @return true if a plan is selected based on previous success of
suitable for explain output. */ this plan. */
BSONObj explain() const;
/** @return true iff a plan is selected based on previous success o
f this plan. */
bool usingCachedPlan() const { return _usingCachedPlan; } bool usingCachedPlan() const { return _usingCachedPlan; }
/** @return true if some candidate plans may have been excluded due
to plan caching. */
bool hasPossiblyExcludedPlans() const;
/** @return a single plan that may work well for the specified quer y. */ /** @return a single plan that may work well for the specified quer y. */
QueryPlanPtr getBestGuess() const; QueryPlanPtr getBestGuess() const;
//for testing
const FieldRangeSetPair &frsp() const { return *_frsp; } const FieldRangeSetPair &frsp() const { return *_frsp; }
const FieldRangeSetPair *originalFrsp() const { return _originalFrs BSONObj originalQuery() const { return _originalQuery; }
p.get(); } BSONObj order() const { return _order; }
/** @return true if an active plan is in order. */
bool haveInOrderPlan() const;
/** @return true if an active or fallback plan is in order. */
bool possibleInOrderPlan() const;
/** @return true if an active or fallback plan is out of order. */
bool possibleOutOfOrderPlan() const;
CandidatePlanCharacter characterizeCandidatePlans() const;
bool prepareToRetryQuery();
string toString() const;
/** Configure a single query plan if one has not already been provi
ded. */
void setSinglePlan( const QueryPlanPtr &plan );
/** Configure a query plan from the plan cache. */
void setCachedPlan( const QueryPlanPtr &plan, const CachedQueryPlan
&cachedPlan );
/** Add a candidate query plan, potentially one of many. */
void addCandidatePlan( const QueryPlanPtr &plan );
//for testing
bool modifiedKeys() const; bool modifiedKeys() const;
bool hasMultiKey() const; bool hasMultiKey() const;
private:
void addOtherPlans( bool checkFirst );
void addPlan( QueryPlanPtr plan, bool checkFirst ) {
if ( checkFirst && plan->indexKey().woCompare( _plans[ 0 ]->ind
exKey() ) == 0 )
return;
_plans.push_back( plan );
}
void init();
void addHint( IndexDetails &id );
class Runner { class Runner {
public: public:
Runner( QueryPlanSet &plans, QueryOp &op ); Runner( QueryPlanSet &plans, QueryOp &op );
/** /**
* Iterate interactively through candidate documents on all pla * Advance the runner, if it is not done().
ns. * @return the next non error op if there is one, otherwise an
* QueryOp objects are returned at each interleaved step. error op.
*/ * If the returned op is complete() or error(), the Runner beco
mes done().
/** @return a plan that has completed, otherwise an arbitrary p
lan. */
shared_ptr<QueryOp> init();
/**
* Move the Runner forward one iteration, and @return the plan
for
* this iteration.
*/ */
shared_ptr<QueryOp> next(); shared_ptr<QueryOp> next();
/** @return next non error op if there is one, otherwise an err /** @return true if done iterating. */
or op. */ bool done() const { return _done; }
shared_ptr<QueryOp> nextNonError();
bool prepareToYield(); void prepareToYield();
void recoverFromYield(); void recoverFromYield();
/** Run until first op completes. */ /** @return an ExplainClauseInfo object that will be updated as
shared_ptr<QueryOp> runUntilFirstCompletes(); the query runs. */
shared_ptr<ExplainClauseInfo> generateExplainInfo() {
_explainClauseInfo.reset( new ExplainClauseInfo() );
return _explainClauseInfo;
}
void mayYield(); private:
QueryOp &_op; QueryOp &_op;
QueryPlanSet &_plans; QueryPlanSet &_plans;
static void initOp( QueryOp &op ); static void initOp( QueryOp &op );
static void nextOp( QueryOp &op ); static void nextOp( QueryOp &op );
static bool prepareToYieldOp( QueryOp &op ); static void prepareToYieldOp( QueryOp &op );
static void recoverFromYieldOp( QueryOp &op ); static void recoverFromYieldOp( QueryOp &op );
private:
/** Initialize the Runner. */
shared_ptr<QueryOp> init();
/** Move the Runner forward one iteration, and @return the plan
for the iteration. */
shared_ptr<QueryOp> _next();
vector<shared_ptr<QueryOp> > _ops; vector<shared_ptr<QueryOp> > _ops;
struct OpHolder { struct OpHolder {
OpHolder( const shared_ptr<QueryOp> &op ) : _op( op ), _off set() {} OpHolder( const shared_ptr<QueryOp> &op ) : _op( op ), _off set() {}
shared_ptr<QueryOp> _op; shared_ptr<QueryOp> _op;
long long _offset; long long _offset;
bool operator<( const OpHolder &other ) const { bool operator<( const OpHolder &other ) const {
return _op->nscanned() + _offset > other._op->nscanned( ) + other._offset; return _op->nscanned() + _offset > other._op->nscanned( ) + other._offset;
} }
}; };
our_priority_queue<OpHolder> _queue; our_priority_queue<OpHolder> _queue;
shared_ptr<ExplainClauseInfo> _explainClauseInfo;
bool _done;
}; };
const char *_ns; private:
void addFallbackPlans();
void init();
QueryPlanGenerator _generator;
BSONObj _originalQuery; BSONObj _originalQuery;
auto_ptr<FieldRangeSetPair> _frsp; auto_ptr<FieldRangeSetPair> _frsp;
auto_ptr<FieldRangeSetPair> _originalFrsp;
PlanSet _plans; PlanSet _plans;
bool _mayRecordPlan; bool _mayRecordPlan;
bool _usingCachedPlan; bool _usingCachedPlan;
BSONObj _hint; CandidatePlanCharacter _cachedPlanCharacter;
BSONObj _order; BSONObj _order;
long long _oldNScanned; long long _oldNScanned;
bool _honorRecordedPlan;
BSONObj _min;
BSONObj _max;
string _special;
bool _bestGuessOnly;
bool _mayYield;
ElapsedTracker _yieldSometimesTracker; ElapsedTracker _yieldSometimesTracker;
shared_ptr<Runner> _runner;
bool _mustAssertOnYieldFailure;
}; };
/** Handles $or type queries by generating a QueryPlanSet for each $or clause. */ /** Handles $or type queries by generating a QueryPlanSet for each $or clause. */
class MultiPlanScanner { class MultiPlanScanner {
public: public:
MultiPlanScanner( const char *ns, MultiPlanScanner( const char *ns,
const BSONObj &query, const BSONObj &query,
const BSONObj &order, const BSONObj &order,
const BSONElement *hint = 0, const shared_ptr<const ParsedQuery> &parsedQuery
bool honorRecordedPlan = true, =
shared_ptr<const ParsedQuery>(),
const BSONObj &hint = BSONObj(),
QueryPlanGenerator::RecordedPlanPolicy recordedPl
anPolicy =
QueryPlanGenerator::Use,
const BSONObj &min = BSONObj(), const BSONObj &min = BSONObj(),
const BSONObj &max = BSONObj(), const BSONObj &max = BSONObj() );
bool bestGuessOnly = false,
bool mayYield = false);
/** Set the initial QueryOp for QueryPlanSet iteration. */
void initialOp( const shared_ptr<QueryOp> &originalOp ) { _baseOp =
originalOp; }
/** /**
* Clone op for each query plan of a single $or clause, and @return * Advance to the next QueryOp, if not doneOps().
the first cloned op * @return the next non error op if there is one, otherwise an erro
* to call setComplete() or setStop(). r op.
* If the returned op is complete() or error(), the MultiPlanScanne
r becomes doneOps() and
* no further QueryOp iteration is possible.
*/ */
shared_ptr<QueryOp> nextOp();
shared_ptr<QueryOp> runOpOnce( QueryOp &op ); /** @return true if done with QueryOp iteration. */
template<class T> bool doneOps() const { return _doneOps; }
shared_ptr<T> runOpOnce( T &op ) {
return dynamic_pointer_cast<T>( runOpOnce( static_cast<QueryOp&
>( op ) ) );
}
/** /**
* For each $or clause, calls runOpOnce on the child QueryOp cloned * Advance to the next $or clause; hasMoreClauses() must be true.
from the winning QueryOp * @param currentPlan QueryPlan of the current $or clause
* of the previous $or clause (or from the supplied 'op' for the fi * @return best guess query plan of the next $or clause, 0 if there
rst $or clause). is no such plan.
*/ */
const QueryPlan *nextClauseBestGuessPlan( const QueryPlan &currentP lan );
shared_ptr<QueryOp> runOp( QueryOp &op ); /** Add explain information for a new clause. */
template<class T> void addClauseInfo( const shared_ptr<ExplainClauseInfo> &clauseInfo
shared_ptr<T> runOp( T &op ) { ) {
return dynamic_pointer_cast<T>( runOp( static_cast<QueryOp&>( o verify( _explainQueryInfo );
p ) ) ); _explainQueryInfo->addClauseInfo( clauseInfo );
} }
/** Initialize or iterate a runner generated from @param originalOp /** @return an ExplainQueryInfo object that will be updated as the
. */ query runs. */
shared_ptr<ExplainQueryInfo> generateExplainInfo() {
void initialOp( const shared_ptr<QueryOp> &originalOp ) { _baseOp = _explainQueryInfo.reset( new ExplainQueryInfo() );
originalOp; } return _explainQueryInfo;
shared_ptr<QueryOp> nextOp(); }
/** Yield the runner member. */ /** Yield the runner member. */
bool prepareToYield(); void prepareToYield();
void recoverFromYield(); void recoverFromYield();
/** Clear the runner member. */ /** Clear the runner member. */
void clearRunner(); void clearRunner();
int currentNPlans() const; void setRecordedPlanPolicy( QueryPlanGenerator::RecordedPlanPolicy
recordedPlanPolicy ) {
_recordedPlanPolicy = recordedPlanPolicy;
}
/** int currentNPlans() const;
* @return a single simple cursor if the scanner would run a single
cursor
* for this query, otherwise return an empty shared_ptr.
*/
shared_ptr<Cursor> singleCursor() const;
/** /**
* @return the query plan that would be used if the scanner would r un a single * @return the query plan that would be used if the scanner would r un a single
* cursor for this query, otherwise 0. The returned plan is invali d if this * cursor for this query, otherwise 0. The returned plan is invali d if this
* MultiPlanScanner is destroyed, hence we return a raw pointer. * MultiPlanScanner is destroyed, hence we return a raw pointer.
*/ */
const QueryPlan *singlePlan() const; const QueryPlan *singlePlan() const;
/** @return true iff more $or clauses need to be scanned. */ /** @return true if more $or clauses need to be scanned. */
bool mayRunMore() const { bool hasMoreClauses() const {
return _or ? ( !_tableScanned && !_org->orRangesExhausted() ) : _i == 0; return _or ? ( !_tableScanned && !_org->orRangesExhausted() ) : _i == 0;
} }
/** @return non-$or version of explain output. */ /**
BSONObj oldExplain() const { assertNotOr(); return _currentQps->exp * @return plan information if there is a cached plan for a non $or
lain(); } query, otherwise an
/** @return true iff this is not a $or query and a plan is selected * empty object.
based on previous success of this plan. */ */
bool usingCachedPlan() const { return !_or && _currentQps->usingCac BSONObj cachedPlanExplainSummary() const;
hedPlan(); } /**
/** Don't attempt to scan multiple plans, just use the best guess. * @return true if this is not a $or query and some candidate plans
*/ may have been excluded
void setBestGuessOnly() { _bestGuessOnly = true; } * due to plan caching.
/** Yielding is allowed while running each QueryPlan. */ */
void mayYield( bool val ) { _mayYield = val; } bool hasPossiblyExcludedPlans() const {
bool modifiedKeys() const { return _currentQps->modifiedKeys(); } return !_or && _currentQps->hasPossiblyExcludedPlans();
}
bool hasMultiKey() const { return _currentQps->hasMultiKey(); } bool hasMultiKey() const { return _currentQps->hasMultiKey(); }
/** Clear recorded indexes for the current QueryPlanSet's patterns.
*/
void clearIndexesForPatterns() const;
/** @return true if an active plan of _currentQps is in order. */
bool haveInOrderPlan() const;
/** @return true if an active or fallback plan of _currentQps is in
order. */
bool possibleInOrderPlan() const;
/** @return true if an active or fallback plan of _currentQps is ou
t of order. */
bool possibleOutOfOrderPlan() const;
int i() const { return _i; }
string toString() const;
private: private:
/** Initialize or iterate a runner generated from @param originalOp
. */
shared_ptr<QueryOp> iterateRunner( QueryOp &originalOp, bool retrie
d = false );
shared_ptr<QueryOp> nextOpSimple();
shared_ptr<QueryOp> nextOpOr();
void updateCurrentQps( QueryPlanSet *qps );
void assertNotOr() const { void assertNotOr() const {
massert( 13266, "not implemented for $or query", !_or ); massert( 13266, "not implemented for $or query", !_or );
} }
void assertMayRunMore() const { void assertHasMoreClauses() const {
massert( 13271, "can't run more ops", mayRunMore() ); massert( 13271, "no more clauses", hasMoreClauses() );
} }
shared_ptr<QueryOp> nextOpBeginningClause();
shared_ptr<QueryOp> nextOpHandleEndOfClause(); void handleEndOfClause( const QueryPlan &clausePlan );
bool uselessOr( const BSONElement &hint ) const; void handleBeginningOfClause();
bool mayHandleBeginningOfClause();
bool haveUselessOr() const;
const string _ns; const string _ns;
bool _or; bool _or;
BSONObj _query; BSONObj _query;
shared_ptr<OrRangeGenerator> _org; // May be null in certain non $o shared_ptr<const ParsedQuery> _parsedQuery;
r query cases. scoped_ptr<OrRangeGenerator> _org; // May be null in certain non $o
auto_ptr<QueryPlanSet> _currentQps; r query cases.
scoped_ptr<QueryPlanSet> _currentQps;
int _i; int _i;
bool _honorRecordedPlan; QueryPlanGenerator::RecordedPlanPolicy _recordedPlanPolicy;
bool _bestGuessOnly;
BSONObj _hint; BSONObj _hint;
bool _mayYield;
bool _tableScanned; bool _tableScanned;
shared_ptr<QueryOp> _baseOp; shared_ptr<QueryOp> _baseOp;
scoped_ptr<QueryPlanSet::Runner> _runner;
shared_ptr<ExplainQueryInfo> _explainQueryInfo;
bool _doneOps;
}; };
/** Provides a cursor interface for certain limited uses of a MultiPlan /**
Scanner. */ * Provides a cursor interface for serial single Cursor iteration using
a MultiPlanScanner.
* Currently used internally by a QueryOptimizerCursor.
*
* A MultiCursor is backed by one BasicCursor or BtreeCursor at a time
and forwards calls for
* ensuring a consistent state after a write to its backing Cursor. Th
ere is a known issue in
* some cases when advance() causes a switch to a new BasicCursor backi
ng (SERVER-5198).
*/
class MultiCursor : public Cursor { class MultiCursor : public Cursor {
public: public:
class CursorOp : public QueryOp { /** @param nscanned is the initial nscanned value. */
public: MultiCursor( auto_ptr<MultiPlanScanner> mps, const shared_ptr<Curso
CursorOp() {} r> &c,
CursorOp( const QueryOp &other ) : QueryOp( other ) {} const shared_ptr<CoveredIndexMatcher> &matcher,
virtual shared_ptr<Cursor> newCursor() const = 0; const shared_ptr<ExplainPlanInfo> &explainPlanInfo,
}; const QueryOp &op, long long nscanned );
/** takes ownership of 'op' */
MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj
&order, shared_ptr<CursorOp> op = shared_ptr<CursorOp>(), bool mayYield = f
alse );
/**
* Used
* 1. To handoff a query to a getMore()
* 2. To handoff a QueryOptimizerCursor
* @param nscanned is an optional initial value, if not supplied ns
canned()
* will always return -1
*/
MultiCursor( auto_ptr<MultiPlanScanner> mps, const shared_ptr<Curso
r> &c, const shared_ptr<CoveredIndexMatcher> &matcher, const QueryOp &op, l
ong long nscanned = -1 );
virtual bool ok() { return _c->ok(); } virtual bool ok() { return _c->ok(); }
virtual Record* _current() { return _c->_current(); } virtual Record* _current() { return _c->_current(); }
virtual BSONObj current() { return _c->current(); } virtual BSONObj current() { return _c->current(); }
virtual DiskLoc currLoc() { return _c->currLoc(); } virtual DiskLoc currLoc() { return _c->currLoc(); }
virtual bool advance() { virtual bool advance();
_c->advance();
while( !ok() && _mps->mayRunMore() ) {
nextClause();
}
return ok();
}
virtual BSONObj currKey() const { return _c->currKey(); } virtual BSONObj currKey() const { return _c->currKey(); }
virtual DiskLoc refLoc() { return _c->refLoc(); } virtual DiskLoc refLoc() { return _c->refLoc(); }
virtual void noteLocation() { _c->noteLocation(); } virtual void noteLocation() { _c->noteLocation(); }
virtual void checkLocation() { _c->checkLocation(); } virtual void checkLocation() { _c->checkLocation(); }
virtual void recoverFromYield();
virtual bool supportGetMore() { return true; } virtual bool supportGetMore() { return true; }
virtual bool supportYields() { return _c->supportYields(); } virtual bool supportYields() { return true; }
virtual BSONObj indexKeyPattern() { return _c->indexKeyPattern(); } virtual BSONObj indexKeyPattern() { return _c->indexKeyPattern(); }
/** /** Deduping documents from a prior cursor is handled by the matche
* with update we could potentially get the same document on multip r. */
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 bool getsetdup(DiskLoc loc) { return _c->getsetdup( loc ); }
virtual bool autoDedup() const { return _c->autoDedup(); } virtual bool autoDedup() const { return _c->autoDedup(); }
virtual bool modifiedKeys() const { return _mps->modifiedKeys(); } virtual bool modifiedKeys() const { return true; }
virtual bool isMultiKey() const { return _mps->hasMultiKey(); } virtual bool isMultiKey() const { return _mps->hasMultiKey(); }
virtual shared_ptr< CoveredIndexMatcher > matcherPtr() const { retu rn _matcher; } virtual shared_ptr< CoveredIndexMatcher > matcherPtr() const { retu rn _matcher; }
virtual CoveredIndexMatcher* matcher() const { return _matcher.get( ); } virtual CoveredIndexMatcher* matcher() const { return _matcher.get( ); }
virtual bool capped() const { return _c->capped(); } virtual bool capped() const { return _c->capped(); }
/** return -1 if we're a getmore handoff */ virtual long long nscanned() { return _nscanned + _c->nscanned(); }
virtual long long nscanned() { return _nscanned >= 0 ? _nscanned +
_c->nscanned() : _nscanned; } void noteIterate( bool match, bool loadedRecord );
/** just for testing */
shared_ptr<Cursor> sub_c() const { return _c; } void noteYield();
const QueryPlan &queryPlan() const {
verify( _c->ok() && _queryPlan );
return *_queryPlan;
}
const Projection::KeyOnly *keyFieldsOnly() const {
verify( _c->ok() && _queryPlan );
return _queryPlan->keyFieldsOnly().get();
}
private: private:
class NoOp : public CursorOp {
public:
NoOp() {}
NoOp( const QueryOp &other ) : CursorOp( other ) {}
virtual void _init() { setComplete(); }
virtual void next() {}
virtual bool mayRecordPlan() const { return false; }
virtual QueryOp *_createChild() const { return new NoOp(); }
virtual shared_ptr<Cursor> newCursor() const { return qp().newC
ursor(); }
virtual long long nscanned() { assert( false ); return 0; }
};
void nextClause(); void nextClause();
shared_ptr<CursorOp> _op;
shared_ptr<Cursor> _c;
auto_ptr<MultiPlanScanner> _mps; auto_ptr<MultiPlanScanner> _mps;
shared_ptr<Cursor> _c;
shared_ptr<CoveredIndexMatcher> _matcher; shared_ptr<CoveredIndexMatcher> _matcher;
const QueryPlan *_queryPlan;
long long _nscanned; long long _nscanned;
shared_ptr<ExplainPlanInfo> _explainPlanInfo;
}; };
/** 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 );
class CachedQueryPlan;
/** /**
* Add-on functionality for queryutil classes requiring access to index ing * Add-on functionality for queryutil classes requiring access to index ing
* functionality not currently linked to mongos. * functionality not currently linked to mongos.
* TODO Clean this up a bit, possibly with separate sharded and non sha rded * TODO Clean this up a bit, possibly with separate sharded and non sha rded
* implementations for the appropriate queryutil classes or by pulling index * implementations for the appropriate queryutil classes or by pulling index
* related functionality into separate wrapper classes. * related functionality into separate wrapper classes.
*/ */
struct QueryUtilIndexed { struct QueryUtilIndexed {
/** @return true if the index may be useful according to its KeySpe c. */ /** @return true if the index may be useful according to its KeySpe c. */
static bool indexUseful( const FieldRangeSetPair &frsp, NamespaceDe tails *d, int idxNo, const BSONObj &order ); static bool indexUseful( const FieldRangeSetPair &frsp, NamespaceDe tails *d, int idxNo, const BSONObj &order );
/** Clear any indexes recorded as the best for either the single or multi key pattern. */ /** Clear any indexes recorded as the best for either the single or multi key pattern. */
static void clearIndexesForPatterns( const FieldRangeSetPair &frsp, const BSONObj &order ); static void clearIndexesForPatterns( const FieldRangeSetPair &frsp, const BSONObj &order );
/** Return a recorded best index for the single or multi key patter n. */ /** Return a recorded best index for the single or multi key patter n. */
static pair< BSONObj, long long > bestIndexForPatterns( const Field RangeSetPair &frsp, const BSONObj &order ); static CachedQueryPlan bestIndexForPatterns( const FieldRangeSetPai r &frsp, const BSONObj &order );
static bool uselessOr( const OrRangeGenerator& org, NamespaceDetail s *d, int hintIdx ); static bool uselessOr( const OrRangeGenerator& org, NamespaceDetail s *d, int hintIdx );
}; };
} // namespace mongo } // namespace mongo
 End of changes. 82 change blocks. 
236 lines changed or deleted 335 lines changed or added


 queryoptimizercursor.h   queryoptimizercursor.h 
// @file queryoptimizercursor.h // @file queryoptimizercursor.h - Interface for a cursor interleaving multi ple candidate cursors.
/** /**
* Copyright (C) 2011 10gen Inc. * Copyright (C) 2011 10gen Inc.
* *
* This program is free software: you can redistribute it and/or modify * 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, * it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation. * as published by the Free Software Foundation.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Lice nse * You should have received a copy of the GNU Affero General Public Lice nse
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once
#include "cursor.h"
#include "diskloc.h"
namespace mongo { namespace mongo {
/** Helper class for caching and counting matches during execution of a class QueryPlan;
QueryPlan. */ class CandidatePlanCharacter;
class CachedMatchCounter {
/**
* An interface for policies overriding the query optimizer's default q
uery plan selection
* behavior.
*/
class QueryPlanSelectionPolicy {
public: public:
/** virtual ~QueryPlanSelectionPolicy() {}
* @param aggregateNscanned - shared count of nscanned for this and virtual string name() const = 0;
othe plans. virtual bool permitOptimalNaturalPlan() const { return true; }
* @param cumulativeCount - starting point for accumulated count ov virtual bool permitOptimalIdPlan() const { return true; }
er a series of plans. virtual bool permitPlan( const QueryPlan &plan ) const { return tru
*/ e; }
CachedMatchCounter( long long &aggregateNscanned, int cumulativeCou virtual BSONObj planHint( const char *ns ) const { return BSONObj()
nt ) : _aggregateNscanned( aggregateNscanned ), _nscanned(), _cumulativeCou ; }
nt( cumulativeCount ), _count(), _checkDups(), _match( Unknown ), _counted(
) {} /** Allow any query plan selection, permitting the query optimizer'
s default behavior. */
static const QueryPlanSelectionPolicy &any();
/** Set whether dup checking is enabled when counting. */ /** Prevent unindexed collection scans. */
void setCheckDups( bool checkDups ) { _checkDups = checkDups; } static const QueryPlanSelectionPolicy &indexOnly();
/** /**
* Usual sequence of events: * Generally hints to use the _id plan, falling back to the $natura
* 1) resetMatch() - reset stored match value to Unkonwn. l plan. However, the
* 2) setMatch() - set match value to a definite true/false value. * $natural plan will always be used if optimal for the query.
* 3) knowMatch() - check if setMatch() has been called.
* 4) countMatch() - increment count if match is true.
*/ */
static const QueryPlanSelectionPolicy &idElseNatural();
void resetMatch() {
_match = Unknown;
_counted = false;
}
void setMatch( bool match ) { _match = match ? True : False; }
bool knowMatch() const { return _match != Unknown; }
void countMatch( const DiskLoc &loc ) {
if ( !_counted && _match == True && !getsetdup( loc ) ) {
++_cumulativeCount;
++_count;
_counted = true;
}
}
bool enoughCumulativeMatchesToChooseAPlan() const {
// This is equivalent to the default condition for switching fr
om
// a query to a getMore, which was the historical default match
count for
// choosing a plan.
return _cumulativeCount >= 101;
}
bool enoughMatchesToRecordPlan() const {
// Recording after 50 matches is a historical default (101 defa
ult limit / 2).
return _count > 50;
}
int cumulativeCount() const { return _cumulativeCount; }
int count() const { return _count; }
/** Update local and aggregate nscanned counts. */
void updateNscanned( long long nscanned ) {
_aggregateNscanned += ( nscanned - _nscanned );
_nscanned = nscanned;
}
long long nscanned() const { return _nscanned; }
long long &aggregateNscanned() const { return _aggregateNscanned; }
private: private:
bool getsetdup( const DiskLoc &loc ) { class Any;
if ( !_checkDups ) { static Any __any;
return false; class IndexOnly;
} static IndexOnly __indexOnly;
pair<set<DiskLoc>::iterator, bool> p = _dups.insert( loc ); class IdElseNatural;
return !p.second; static IdElseNatural __idElseNatural;
}
long long &_aggregateNscanned;
long long _nscanned;
int _cumulativeCount;
int _count;
bool _checkDups;
enum MatchState { Unknown, False, True };
MatchState _match;
bool _counted;
set<DiskLoc> _dups;
}; };
/** Dup tracking class, optimizing one common case with small set and f class QueryPlanSelectionPolicy::Any : public QueryPlanSelectionPolicy {
ew initial reads. */
class SmallDupSet {
public: public:
SmallDupSet() : _accesses() { virtual string name() const { return "any"; }
_vec.reserve( 250 );
}
/** @return true if @param 'loc' already added to the set, false if
adding to the set in this call. */
bool getsetdup( const DiskLoc &loc ) {
access();
return vec() ? getsetdupVec( loc ) : getsetdupSet( loc );
}
/** @return true when @param loc in the set. */
bool getdup( const DiskLoc &loc ) {
access();
return vec() ? getdupVec( loc ) : getdupSet( loc );
}
private:
void access() {
++_accesses;
mayUpgrade();
}
void mayUpgrade() {
if ( vec() && _accesses > 500 ) {
_set.insert( _vec.begin(), _vec.end() );
}
}
bool vec() const {
return _set.size() == 0;
}
bool getsetdupVec( const DiskLoc &loc ) {
if ( getdupVec( loc ) ) {
return true;
}
_vec.push_back( loc );
return false;
}
bool getdupVec( const DiskLoc &loc ) const {
for( vector<DiskLoc>::const_iterator i = _vec.begin(); i != _ve
c.end(); ++i ) {
if ( *i == loc ) {
return true;
}
}
return false;
}
bool getsetdupSet( const DiskLoc &loc ) {
pair<set<DiskLoc>::iterator, bool> p = _set.insert(loc);
return !p.second;
}
bool getdupSet( const DiskLoc &loc ) {
return _set.count( loc ) > 0;
}
vector<DiskLoc> _vec;
set<DiskLoc> _set;
long long _accesses;
}; };
class QueryPlanSelectionPolicy::IndexOnly : public QueryPlanSelectionPo
licy {
public:
virtual string name() const { return "indexOnly"; }
virtual bool permitOptimalNaturalPlan() const { return false; }
virtual bool permitPlan( const QueryPlan &plan ) const;
};
class QueryPlanSelectionPolicy::IdElseNatural : public QueryPlanSelecti
onPolicy {
public:
virtual string name() const { return "idElseNatural"; }
virtual bool permitPlan( const QueryPlan &plan ) const;
virtual BSONObj planHint( const char *ns ) const;
};
class FieldRangeSet;
class ExplainQueryInfo;
/**
* Adds functionality to Cursor for running multiple plans, running out
of order plans,
* utilizing covered indexes, and generating explain output.
*/
class QueryOptimizerCursor : public Cursor {
public:
/** Candidate plans for the query before it begins running. */
virtual CandidatePlanCharacter initialCandidatePlans() const = 0;
/** FieldRangeSet for the query before it begins running. */
virtual const FieldRangeSet *initialFieldRangeSet() const = 0;
/** @return true if the plan for the current iterate is out of orde
r. */
virtual bool currentPlanScanAndOrderRequired() const = 0;
/** @return true when there may be multiple plans running and some
are in order. */
virtual bool runningInitialInOrderPlan() const = 0;
/**
* @return true when some query plans may have been excluded due to
plan caching, for a
* non-$or query.
*/
virtual bool hasPossiblyExcludedPlans() const = 0;
/**
* @return true when both in order and out of order candidate plans
were available, and
* an out of order candidate plan completed iteration.
*/
virtual bool completePlanOfHybridSetScanAndOrderRequired() const =
0;
/** Clear recorded indexes for the current clause's query patterns.
*/
virtual void clearIndexesForPatterns() = 0;
/** Stop returning results from out of order plans and do not allow
them to complete. */
virtual void abortOutOfOrderPlans() = 0;
/** Note match information for the current iterate, to generate exp
lain output. */
virtual void noteIterate( bool match, bool loadedDocument, bool chu
nkSkip ) = 0;
/** @return explain output for the query run by this cursor. */
virtual shared_ptr<ExplainQueryInfo> explainQueryInfo() const = 0;
};
} // namespace mongo } // namespace mongo
 End of changes. 12 change blocks. 
131 lines changed or deleted 111 lines changed or added


 querypattern.h   querypattern.h 
skipping to change at line 21 skipping to change at line 21
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "jsobj.h" #include "jsobj.h"
#include "queryutil.h"
namespace mongo { namespace mongo {
class FieldRangeSet;
/** /**
* 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.
* *
* Two queries will generate the same QueryPattern, and therefore match each * Two queries will generate the same QueryPattern, and therefore match each
* other, if their fields have the same Types and they have the same so rt * other, if their fields have the same Types and they have the same so rt
* spec. * spec.
*/ */
class QueryPattern { class QueryPattern {
public: public:
skipping to change at line 58 skipping to change at line 59
bool operator!=( const QueryPattern &other ) const; bool operator!=( const QueryPattern &other ) const;
/** for development / debugging */ /** for development / debugging */
string toString() const; string toString() const;
private: private:
void setSort( const BSONObj sort ); void setSort( const BSONObj sort );
static BSONObj normalizeSort( const BSONObj &spec ); static BSONObj normalizeSort( const BSONObj &spec );
map<string,Type> _fieldTypes; map<string,Type> _fieldTypes;
BSONObj _sort; BSONObj _sort;
}; };
/** Summarizes the candidate plans that may run for a query. */
class CandidatePlanCharacter {
public:
CandidatePlanCharacter( bool mayRunInOrderPlan, bool mayRunOutOfOrd
erPlan ) :
_mayRunInOrderPlan( mayRunInOrderPlan ),
_mayRunOutOfOrderPlan( mayRunOutOfOrderPlan ) {
}
CandidatePlanCharacter() :
_mayRunInOrderPlan(),
_mayRunOutOfOrderPlan() {
}
bool mayRunInOrderPlan() const { return _mayRunInOrderPlan; }
bool mayRunOutOfOrderPlan() const { return _mayRunOutOfOrderPlan; }
bool valid() const { return mayRunInOrderPlan() || mayRunOutOfOrder
Plan(); }
bool hybridPlanSet() const { return mayRunInOrderPlan() && mayRunOu
tOfOrderPlan(); }
private:
bool _mayRunInOrderPlan;
bool _mayRunOutOfOrderPlan;
};
/** Information about a query plan that ran successfully for a QueryPat
tern. */
class CachedQueryPlan {
public:
CachedQueryPlan() :
_nScanned() {
}
CachedQueryPlan( const BSONObj &indexKey, long long nScanned,
CandidatePlanCharacter planCharacter );
BSONObj indexKey() const { return _indexKey; }
long long nScanned() const { return _nScanned; }
CandidatePlanCharacter planCharacter() const { return _planCharacte
r; }
private:
BSONObj _indexKey;
long long _nScanned;
CandidatePlanCharacter _planCharacter;
};
inline bool QueryPattern::operator<( const QueryPattern &other ) const { inline bool QueryPattern::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;
 End of changes. 3 change blocks. 
1 lines changed or deleted 44 lines changed or added


 queryutil-inl.h   queryutil-inl.h 
skipping to change at line 35 skipping to change at line 35
} }
inline bool FieldRange::equality() const { inline bool FieldRange::equality() const {
return return
!empty() && !empty() &&
min().woCompare( max(), false ) == 0 && min().woCompare( max(), false ) == 0 &&
maxInclusive() && maxInclusive() &&
minInclusive(); minInclusive();
} }
inline bool FieldRange::inQuery() const {
if ( equality() ) {
return true;
}
for( vector<FieldInterval>::const_iterator i = _intervals.begin();
i != _intervals.end(); ++i ) {
if ( !i->equality() ) {
return false;
}
}
return true;
}
inline const FieldRange &FieldRangeSet::range( const char *fieldName ) const { inline const FieldRange &FieldRangeSet::range( const char *fieldName ) const {
map<string,FieldRange>::const_iterator f = _ranges.find( fieldName ); map<string,FieldRange>::const_iterator f = _ranges.find( fieldName );
if ( f == _ranges.end() ) if ( f == _ranges.end() )
return universalRange(); return universalRange();
return f->second; return f->second;
} }
inline FieldRange &FieldRangeSet::range( const char *fieldName ) { inline FieldRange &FieldRangeSet::range( const char *fieldName ) {
map<string,FieldRange>::iterator f = _ranges.find( fieldName ); map<string,FieldRange>::iterator f = _ranges.find( fieldName );
if ( f == _ranges.end() ) { if ( f == _ranges.end() ) {
skipping to change at line 89 skipping to change at line 77
if ( e.fieldName() == string( "$natural" ) ) { if ( e.fieldName() == string( "$natural" ) ) {
return true; return true;
} }
if ( range( e.fieldName() ).empty() ) { if ( range( e.fieldName() ).empty() ) {
return false; return false;
} }
} }
return true; return true;
} }
inline long long FieldRangeVector::size() { inline unsigned FieldRangeVector::size() {
long long ret = 1; unsigned ret = 1;
for( vector<FieldRange>::const_iterator i = _ranges.begin(); i != _ ranges.end(); ++i ) { for( vector<FieldRange>::const_iterator i = _ranges.begin(); i != _ ranges.end(); ++i ) {
ret *= i->intervals().size(); unsigned long long product =
(unsigned long long)ret * (unsigned long long)i->interv
als().size();
// Check for overflow SERVER-5415.
verify( ( product >> 32 ) == 0 );
ret = static_cast<unsigned>( product );
} }
return ret; return ret;
} }
inline void FieldRangeVectorIterator::CompoundRangeCounter::set( int i,
int newVal ) {
resetIntervalCount();
_i[ i ] = newVal;
}
inline void FieldRangeVectorIterator::CompoundRangeCounter::inc( int i
) {
resetIntervalCount();
++_i[ i ];
}
inline void FieldRangeVectorIterator::CompoundRangeCounter::setZeroes(
int i ) {
resetIntervalCount();
for( int j = i; j < (int)_i.size(); ++j ) _i[ j ] = 0;
}
inline void FieldRangeVectorIterator::CompoundRangeCounter::setUnknowns
( int i ) {
resetIntervalCount();
for( int j = i; j < (int)_i.size(); ++j ) _i[ j ] = -1;
}
inline FieldRangeSetPair *OrRangeGenerator::topFrsp() const { inline FieldRangeSetPair *OrRangeGenerator::topFrsp() const {
FieldRangeSetPair *ret = new FieldRangeSetPair( _baseSet ); FieldRangeSetPair *ret = new FieldRangeSetPair( _baseSet );
if (_orSets.size()) { if (_orSets.size()) {
*ret &= _orSets.front(); *ret &= _orSets.front();
} }
return ret; return ret;
} }
inline FieldRangeSetPair *OrRangeGenerator::topFrspOriginal() const { inline FieldRangeSetPair *OrRangeGenerator::topFrspOriginal() const {
FieldRangeSetPair *ret = new FieldRangeSetPair( _baseSet ); FieldRangeSetPair *ret = new FieldRangeSetPair( _baseSet );
 End of changes. 4 change blocks. 
16 lines changed or deleted 32 lines changed or added


 queryutil.h   queryutil.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 "jsobj.h" #include "jsobj.h"
#include "indexkey.h" #include "indexkey.h"
#include "projection.h"
namespace mongo { namespace mongo {
extern const int MaxBytesToReturnToClientAtOnce;
/* This is for languages whose "objects" are not well ordered (JSON is
well ordered).
[ { a : ... } , { b : ... } ] -> { a : ..., b : ... }
*/
inline BSONObj transformOrderFromArrayFormat(BSONObj order) {
/* note: this is slow, but that is ok as order will have very few p
ieces */
BSONObjBuilder b;
char p[2] = "0";
while ( 1 ) {
BSONObj j = order.getObjectField(p);
if ( j.isEmpty() )
break;
BSONElement e = j.firstElement();
uassert( 10102 , "bad order array", !e.eoo());
uassert( 10103 , "bad order array [2]", e.isNumber());
b.append(e);
(*p)++;
uassert( 10104 , "too many ordering elements", *p <= '9');
}
return b.obj();
}
class QueryMessage;
/** /**
* One side of an interval of valid BSONElements, specified by a value * this represents a total user query
and a * includes fields from the query message, both possible query levels
* boolean indicating whether the interval includes the value. * parses everything up front
*/
class ParsedQuery : boost::noncopyable {
public:
ParsedQuery( QueryMessage& qm );
ParsedQuery( const char* ns , int ntoskip , int ntoreturn , int que
ryoptions , const BSONObj& query , const BSONObj& fields )
: _ns( ns ) , _ntoskip( ntoskip ) , _ntoreturn( ntoreturn ) , _opti
ons( queryoptions ) {
init( query );
initFields( fields );
}
const char * ns() const { return _ns; }
bool isLocalDB() const { return strncmp(_ns, "local.", 6) == 0; }
const BSONObj& getFilter() const { return _filter; }
Projection* getFields() const { return _fields.get(); }
shared_ptr<Projection> getFieldPtr() const { return _fields; }
int getSkip() const { return _ntoskip; }
int getNumToReturn() const { return _ntoreturn; }
bool wantMore() const { return _wantMore; }
int getOptions() const { return _options; }
bool hasOption( int x ) const { return ( x & _options ) != 0; }
bool isExplain() const { return _explain; }
bool isSnapshot() const { return _snapshot; }
bool returnKey() const { return _returnKey; }
bool showDiskLoc() const { return _showDiskLoc; }
const BSONObj& getMin() const { return _min; }
const BSONObj& getMax() const { return _max; }
const BSONObj& getOrder() const { return _order; }
const BSONObj& getHint() const { return _hint; }
int getMaxScan() const { return _maxScan; }
bool couldBeCommand() const {
/* we assume you are using findOne() for running a cmd... */
return _ntoreturn == 1 && strstr( _ns , ".$cmd" );
}
bool hasIndexSpecifier() const {
return ! _hint.isEmpty() || ! _min.isEmpty() || ! _max.isEmpty(
);
}
/* if ntoreturn is zero, we return up to 101 objects. on the subse
quent getmore, there
is only a size limit. The idea is that on a find() where one does
n't use much results,
we don't return much, but once getmore kicks in, we start pushing
significant quantities.
The n limit (vs. size) is important when someone fetches only one
small field from big
objects, which causes massive scanning server-side.
*/
bool enoughForFirstBatch( int n , int len ) const {
if ( _ntoreturn == 0 )
return ( len > 1024 * 1024 ) || n >= 101;
return n >= _ntoreturn || len > MaxBytesToReturnToClientAtOnce;
}
bool enough( int n ) const {
if ( _ntoreturn == 0 )
return false;
return n >= _ntoreturn;
}
bool enoughForExplain( long long n ) const {
if ( _wantMore || _ntoreturn == 0 ) {
return false;
}
return n >= _ntoreturn;
}
private:
void init( const BSONObj& q ) {
_reset();
uassert( 10105 , "bad skip value in query", _ntoskip >= 0);
if ( _ntoreturn < 0 ) {
/* _ntoreturn greater than zero is simply a hint on how man
y objects to send back per
"cursor batch".
A negative number indicates a hard limit.
*/
_wantMore = false;
_ntoreturn = -_ntoreturn;
}
BSONElement e = q["query"];
if ( ! e.isABSONObj() )
e = q["$query"];
if ( e.isABSONObj() ) {
_filter = e.embeddedObject();
_initTop( q );
}
else {
_filter = q;
}
}
void _reset() {
_wantMore = true;
_explain = false;
_snapshot = false;
_returnKey = false;
_showDiskLoc = false;
_maxScan = 0;
}
void _initTop( const BSONObj& top ) {
BSONObjIterator i( top );
while ( i.more() ) {
BSONElement e = i.next();
const char * name = e.fieldName();
if ( strcmp( "$orderby" , name ) == 0 ||
strcmp( "orderby" , name ) == 0 ) {
if ( e.type() == Object ) {
_order = e.embeddedObject();
}
else if ( e.type() == Array ) {
_order = transformOrderFromArrayFormat( _order );
}
else {
uasserted(13513, "sort must be an object or array")
;
}
continue;
}
if( *name == '$' ) {
name++;
if ( strcmp( "explain" , name ) == 0 )
_explain = e.trueValue();
else if ( strcmp( "snapshot" , name ) == 0 )
_snapshot = e.trueValue();
else if ( strcmp( "min" , name ) == 0 )
_min = e.embeddedObject();
else if ( strcmp( "max" , name ) == 0 )
_max = e.embeddedObject();
else if ( strcmp( "hint" , name ) == 0 )
_hint = e.wrap();
else if ( strcmp( "returnKey" , name ) == 0 )
_returnKey = e.trueValue();
else if ( strcmp( "maxScan" , name ) == 0 )
_maxScan = e.numberInt();
else if ( strcmp( "showDiskLoc" , name ) == 0 )
_showDiskLoc = e.trueValue();
else if ( strcmp( "comment" , name ) == 0 ) {
; // no-op
}
}
}
if ( _snapshot ) {
uassert( 12001 , "E12001 can't sort with $snapshot", _order
.isEmpty() );
uassert( 12002 , "E12002 can't use hint with $snapshot", _h
int.isEmpty() );
}
}
void initFields( const BSONObj& fields ) {
if ( fields.isEmpty() )
return;
_fields.reset( new Projection() );
_fields->init( fields );
}
const char * const _ns;
const int _ntoskip;
int _ntoreturn;
BSONObj _filter;
BSONObj _order;
const int _options;
shared_ptr< Projection > _fields;
bool _wantMore;
bool _explain;
bool _snapshot;
bool _returnKey;
bool _showDiskLoc;
BSONObj _min;
BSONObj _max;
BSONObj _hint;
int _maxScan;
};
/**
* One side of an interval of BSONElements, defined by a value and a bo
olean indicating if the
* interval includes the value.
*/ */
struct FieldBound { struct FieldBound {
BSONElement _bound; BSONElement _bound;
bool _inclusive; bool _inclusive;
bool operator==( const FieldBound &other ) const { bool operator==( const FieldBound &other ) const {
return _bound.woCompare( other._bound ) == 0 && return _bound.woCompare( other._bound ) == 0 &&
_inclusive == other._inclusive; _inclusive == other._inclusive;
} }
void flipInclusive() { _inclusive = !_inclusive; } void flipInclusive() { _inclusive = !_inclusive; }
}; };
/** A closed interval composed of a lower and an upper FieldBound. */ /** An interval defined between a lower and an upper FieldBound. */
struct FieldInterval { struct FieldInterval {
FieldInterval() : _cachedEquality( -1 ) {} FieldInterval() : _cachedEquality( -1 ) {}
FieldInterval( const BSONElement& e ) : _cachedEquality( -1 ) { FieldInterval( const BSONElement& e ) : _cachedEquality( -1 ) {
_lower._bound = _upper._bound = e; _lower._bound = _upper._bound = e;
_lower._inclusive = _upper._inclusive = true; _lower._inclusive = _upper._inclusive = true;
} }
FieldBound _lower; FieldBound _lower;
FieldBound _upper; FieldBound _upper;
/** @return true iff no single element can be contained in the inte rval. */ /** @return true iff no single element can be contained in the inte rval. */
bool strictValid() const { bool strictValid() const {
skipping to change at line 82 skipping to change at line 295
/** @return Range of elements elements included in 'this' but not ' other'. */ /** @return Range of elements elements included in 'this' but not ' other'. */
const FieldRange &operator-=( const FieldRange &other ); const FieldRange &operator-=( const FieldRange &other );
/** @return true iff this range is a subset of 'other'. */ /** @return true iff this range is a subset of 'other'. */
bool operator<=( const FieldRange &other ) const; bool operator<=( const FieldRange &other ) const;
/** /**
* If there are any valid values for this range, the extreme values can * If there are any valid values for this range, the extreme values can
* be extracted. * be extracted.
*/ */
BSONElement min() const { assert( !empty() ); return _intervals[ 0 BSONElement min() const { verify( !empty() ); return _intervals[ 0
]._lower._bound; } ]._lower._bound; }
BSONElement max() const { assert( !empty() ); return _intervals[ _i BSONElement max() const { verify( !empty() ); return _intervals[ _i
ntervals.size() - 1 ]._upper._bound; } ntervals.size() - 1 ]._upper._bound; }
bool minInclusive() const { assert( !empty() ); return _intervals[ bool minInclusive() const { verify( !empty() ); return _intervals[
0 ]._lower._inclusive; } 0 ]._lower._inclusive; }
bool maxInclusive() const { assert( !empty() ); return _intervals[ bool maxInclusive() const { verify( !empty() ); return _intervals[
_intervals.size() - 1 ]._upper._inclusive; } _intervals.size() - 1 ]._upper._inclusive; }
/** @return true iff this range expresses a single equality interva l. */ /** @return true iff this range expresses a single equality interva l. */
bool equality() const; bool equality() const;
/** @return true if all the intervals for this range are equalities
*/
bool inQuery() const;
/** /**
* @return true iff this range includes all BSONElements * @return true iff this range includes all BSONElements
* (the range is the universal set of BSONElements). * (the range is the universal set of BSONElements).
*/ */
bool universal() const; bool universal() const;
/** @return true iff this range includes no BSONElements. */ /** @return true iff this range includes no BSONElements. */
bool empty() const { return _intervals.empty(); } bool empty() const { return _intervals.empty(); }
/**
* @return true in many cases when this FieldRange describes a fini
te set of BSONElements,
* all of which will be matched by the query BSONElement that gener
ated this FieldRange.
* This attribute is used to implement higher level optimizations a
nd is computed with a
* simple implementation that identifies common (but not all) cases
satisfying the stated
* properties.
*/
bool simpleFiniteSet() const { return _simpleFiniteSet; }
/** Empty the range so it includes no BSONElements. */ /** Empty the range so it includes no BSONElements. */
void makeEmpty() { _intervals.clear(); } void makeEmpty() { _intervals.clear(); }
const vector<FieldInterval> &intervals() const { return _intervals; } const vector<FieldInterval> &intervals() const { return _intervals; }
string getSpecial() const { return _special; } string getSpecial() const { return _special; }
/** Make component intervals noninclusive. */ /** Make component intervals noninclusive. */
void setExclusiveBounds(); void setExclusiveBounds();
/** /**
* Constructs a range where all FieldIntervals and FieldBounds are in * Constructs a range where all FieldIntervals and FieldBounds are in
* the opposite order of the current range. * the opposite order of the current range.
* NOTE the resulting intervals might not be strictValid(). * NOTE the resulting intervals might not be strictValid().
*/ */
void reverse( FieldRange &ret ) const; void reverse( FieldRange &ret ) const;
string toString() const; string toString() const;
private: private:
BSONObj addObj( const BSONObj &o ); BSONObj addObj( const BSONObj &o );
void finishOperation( const vector<FieldInterval> &newIntervals, co void finishOperation( const vector<FieldInterval> &newIntervals, co
nst FieldRange &other ); nst FieldRange &other,
bool simpleFiniteSet );
vector<FieldInterval> _intervals; vector<FieldInterval> _intervals;
// Owns memory for our BSONElements. // Owns memory for our BSONElements.
vector<BSONObj> _objData; vector<BSONObj> _objData;
string _special; string _special;
bool _singleKey; bool _singleKey;
bool _simpleFiniteSet;
}; };
/** /**
* 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;
skipping to change at line 164 skipping to change at line 385
* is not useful information for a single key FieldRangeSet and * is not useful information for a single key FieldRangeSet and
* matchPossibleForIndex() should be used instead. * matchPossibleForIndex() should be used instead.
*/ */
bool matchPossible() const; bool matchPossible() const;
/** /**
* @return true if a match could be possible given the value of _si ngleKey * @return true if a match could be possible given the value of _si ngleKey
* and index key 'keyPattern'. * and index key 'keyPattern'.
* @param keyPattern May be {} or {$natural:1} for a non index scan . * @param keyPattern May be {} or {$natural:1} for a non index scan .
*/ */
bool matchPossibleForIndex( const BSONObj &keyPattern ) const; bool matchPossibleForIndex( const BSONObj &keyPattern ) const;
/**
* @return true in many cases when this FieldRangeSet describes a f
inite set of BSONObjs,
* all of which will be matched by the query BSONObj that generated
this FieldRangeSet.
* This attribute is used to implement higher level optimizations a
nd is computed with a
* simple implementation that identifies common (but not all) cases
satisfying the stated
* properties.
*/
bool simpleFiniteSet() const { return _simpleFiniteSet; }
const char *ns() const { return _ns; } const char *ns() const { return _ns.c_str(); }
/** /**
* @return a simplified query from the extreme values of the non un iversal * @return a simplified query from the extreme values of the non un iversal
* fields. * fields.
* @param fields If specified, the fields of the returned object ar e * @param fields If specified, the fields of the returned object ar e
* ordered to match those of 'fields'. * ordered to match those of 'fields'.
*/ */
BSONObj simplifiedQuery( const BSONObj &fields = BSONObj() ) const; BSONObj simplifiedQuery( const BSONObj &fields = BSONObj() ) const;
QueryPattern pattern( const BSONObj &sort = BSONObj() ) const; QueryPattern pattern( const BSONObj &sort = BSONObj() ) const;
skipping to change at line 210 skipping to change at line 439
* @return - A new FieldRangeSet based on this FieldRangeSet, but w ith only * @return - A new FieldRangeSet based on this FieldRangeSet, but w ith only
* a subset of the fields. * a subset of the fields.
* @param fields - Only fields which are represented as field names in this object * @param fields - Only fields which are represented as field names in this object
* will be included in the returned FieldRangeSet. * will be included in the returned FieldRangeSet.
*/ */
FieldRangeSet *subset( const BSONObj &fields ) const; FieldRangeSet *subset( const BSONObj &fields ) const;
bool singleKey() const { return _singleKey; } bool singleKey() const { return _singleKey; }
BSONObj originalQuery() const { return _queries[ 0 ]; } BSONObj originalQuery() const { return _queries[ 0 ]; }
string toString() const;
private: private:
void appendQueries( const FieldRangeSet &other ); void appendQueries( const FieldRangeSet &other );
void makeEmpty(); void makeEmpty();
void processQueryField( const BSONElement &e, bool optimize ); void processQueryField( const BSONElement &e, bool optimize );
void processOpElement( const char *fieldName, const BSONElement &f, bool isNot, bool optimize ); void processOpElement( const char *fieldName, const BSONElement &f, bool isNot, bool optimize );
/** Must be called when a match element is skipped or modified to g
enerate a FieldRange. */
void adjustMatchField();
void intersectMatchField( const char *fieldName, const BSONElement
&matchElement,
bool isNot, bool optimize );
static FieldRange *__singleKeyUniversalRange; static FieldRange *__singleKeyUniversalRange;
static FieldRange *__multiKeyUniversalRange; static FieldRange *__multiKeyUniversalRange;
const FieldRange &universalRange() const; const FieldRange &universalRange() const;
map<string,FieldRange> _ranges; map<string,FieldRange> _ranges;
const char *_ns; string _ns;
// Owns memory for FieldRange BSONElements. // Owns memory for FieldRange BSONElements.
vector<BSONObj> _queries; vector<BSONObj> _queries;
bool _singleKey; bool _singleKey;
bool _simpleFiniteSet;
}; };
class NamespaceDetails; class NamespaceDetails;
/** /**
* A pair of FieldRangeSets, one representing constraints for single ke y * A pair of FieldRangeSets, one representing constraints for single ke y
* indexes and the other representing constraints for multi key indexes and * indexes and the other representing constraints for multi key indexes and
* unindexed scans. In several member functions the caller is asked to * unindexed scans. In several member functions the caller is asked to
* supply an index so that the implementation may utilize the proper * supply an index so that the implementation may utilize the proper
* FieldRangeSet and return results that are appropriate with respect t o that * FieldRangeSet and return results that are appropriate with respect t o that
skipping to change at line 247 skipping to change at line 483
FieldRangeSetPair( const char *ns, const BSONObj &query, bool optim ize=true ) FieldRangeSetPair( const char *ns, const BSONObj &query, bool optim ize=true )
:_singleKey( ns, query, true, optimize ), _multiKey( ns, query, fal se, optimize ) {} :_singleKey( ns, query, true, optimize ), _multiKey( ns, query, fal se, optimize ) {}
/** /**
* @return the appropriate single or multi key FieldRangeSet for th e specified index. * @return the appropriate single or multi key FieldRangeSet for th e specified index.
* @param idxNo -1 for non index scan. * @param idxNo -1 for non index scan.
*/ */
const FieldRangeSet &frsForIndex( const NamespaceDetails* nsd, int idxNo ) const; const FieldRangeSet &frsForIndex( const NamespaceDetails* nsd, int idxNo ) const;
/** @return a field range in the single key FieldRangeSet. */ /** @return a field range in the single key FieldRangeSet. */
const FieldRange &singleKeyRange( const char *fieldName ) const { const FieldRange &shardKeyRange( const char *fieldName ) const {
return _singleKey.range( fieldName ); return _singleKey.range( fieldName );
} }
/** @return true if the range limits are equivalent to an empty que ry. */ /** @return true if the range limits are equivalent to an empty que ry. */
bool noNonUniversalRanges() const; bool noNonUniversalRanges() const;
/** @return false if a match is impossible regardless of index. */ /** @return false if a match is impossible regardless of index. */
bool matchPossible() const { return _multiKey.matchPossible(); } bool matchPossible() const { return _multiKey.matchPossible(); }
/** /**
* @return false if a match is impossible on the specified index. * @return false if a match is impossible on the specified index.
* @param idxNo -1 for non index scan. * @param idxNo -1 for non index scan.
*/ */
skipping to change at line 272 skipping to change at line 508
string getSpecial() const { return _singleKey.getSpecial(); } string getSpecial() const { return _singleKey.getSpecial(); }
/** Intersect with another FieldRangeSetPair. */ /** Intersect with another FieldRangeSetPair. */
FieldRangeSetPair &operator&=( const FieldRangeSetPair &other ); FieldRangeSetPair &operator&=( const FieldRangeSetPair &other );
/** /**
* Subtract a FieldRangeSet, generally one expressing a range that has * Subtract a FieldRangeSet, generally one expressing a range that has
* already been scanned. * already been scanned.
*/ */
FieldRangeSetPair &operator-=( const FieldRangeSet &scanned ); FieldRangeSetPair &operator-=( const FieldRangeSet &scanned );
BoundList singleKeyIndexBounds( const BSONObj &keyPattern, int dire BoundList shardKeyIndexBounds( const BSONObj &keyPattern ) const {
ction ) const { return _singleKey.indexBounds( keyPattern, 1 );
return _singleKey.indexBounds( keyPattern, direction ); }
bool matchPossibleForShardKey( const BSONObj &keyPattern ) const {
return _singleKey.matchPossibleForIndex( keyPattern );
} }
BSONObj originalQuery() const { return _singleKey.originalQuery(); } BSONObj originalQuery() const { return _singleKey.originalQuery(); }
string toString() const;
private: private:
FieldRangeSetPair( const FieldRangeSet &singleKey, const FieldRange Set &multiKey ) FieldRangeSetPair( const FieldRangeSet &singleKey, const FieldRange Set &multiKey )
:_singleKey( singleKey ), _multiKey( multiKey ) {} :_singleKey( singleKey ), _multiKey( multiKey ) {}
void assertValidIndex( const NamespaceDetails *d, int idxNo ) const ; void assertValidIndex( const NamespaceDetails *d, int idxNo ) const ;
void assertValidIndexOrNoIndex( const NamespaceDetails *d, int idxN o ) const; void assertValidIndexOrNoIndex( const NamespaceDetails *d, int idxN o ) const;
/** matchPossibleForIndex() must be true. */ /** matchPossibleForIndex() must be true. */
BSONObj simplifiedQueryForIndex( NamespaceDetails *d, int idxNo, co nst BSONObj &keyPattern ) const; BSONObj simplifiedQueryForIndex( NamespaceDetails *d, int idxNo, co nst BSONObj &keyPattern ) const;
FieldRangeSet _singleKey; FieldRangeSet _singleKey;
FieldRangeSet _multiKey; FieldRangeSet _multiKey;
friend class OrRangeGenerator; friend class OrRangeGenerator;
skipping to change at line 308 skipping to change at line 549
public: public:
/** /**
* @param frs The valid ranges for all fields, as defined by the qu ery spec. None of the * @param frs The valid ranges for all fields, as defined by the qu ery spec. None of the
* fields in indexSpec may be empty() ranges of frs. * fields in indexSpec may be empty() ranges of frs.
* @param indexSpec The index spec (key pattern and info) * @param indexSpec The index spec (key pattern and info)
* @param direction The direction of index traversal * @param direction The direction of index traversal
*/ */
FieldRangeVector( const FieldRangeSet &frs, const IndexSpec &indexS pec, int direction ); FieldRangeVector( const FieldRangeSet &frs, const IndexSpec &indexS pec, int direction );
/** @return the number of index ranges represented by 'this' */ /** @return the number of index ranges represented by 'this' */
long long size(); unsigned size();
/** @return starting point for an index traversal. */ /** @return starting point for an index traversal. */
BSONObj startKey() const; BSONObj startKey() const;
/** @return end point for an index traversal. */ /** @return end point for an index traversal. */
BSONObj endKey() const; BSONObj endKey() const;
/** @return a client readable representation of 'this' */ /** @return a client readable representation of 'this' */
BSONObj obj() const; BSONObj obj() const;
const IndexSpec& getSpec(){ return _indexSpec; } const IndexSpec& getSpec(){ return _indexSpec; }
/** /**
skipping to change at line 332 skipping to change at line 573
* FieldRangeVector. This function is used for $or clause deduping . * FieldRangeVector. This function is used for $or clause deduping .
*/ */
bool matches( const BSONObj &obj ) const; bool matches( const BSONObj &obj ) const;
/** /**
* @return first key of 'obj' that would be encountered by a forwar d * @return first key of 'obj' that would be encountered by a forwar d
* index scan using this FieldRangeVector, BSONObj() if no such key . * index scan using this FieldRangeVector, BSONObj() if no such key .
*/ */
BSONObj firstMatch( const BSONObj &obj ) const; BSONObj firstMatch( const BSONObj &obj ) const;
string toString() const;
private: private:
int matchingLowElement( const BSONElement &e, int i, bool direction , bool &lowEquality ) const; int matchingLowElement( const BSONElement &e, int i, bool direction , bool &lowEquality ) const;
bool matchesElement( const BSONElement &e, int i, bool direction ) const; bool matchesElement( const BSONElement &e, int i, bool direction ) const;
bool matchesKey( const BSONObj &key ) const; bool matchesKey( const BSONObj &key ) const;
vector<FieldRange> _ranges; vector<FieldRange> _ranges;
const IndexSpec _indexSpec; const IndexSpec _indexSpec;
int _direction; int _direction;
vector<BSONObj> _queries; // make sure mem owned vector<BSONObj> _queries; // make sure mem owned
friend class FieldRangeVectorIterator; friend class FieldRangeVectorIterator;
}; };
/** /**
* Helper class for iterating through an ordered representation of keys * Helper class for iterating through an ordered representation of keys
* to find those keys that match a specified FieldRangeVector. * to find those keys that match a specified FieldRangeVector.
*/ */
class FieldRangeVectorIterator { class FieldRangeVectorIterator {
public: public:
FieldRangeVectorIterator( const FieldRangeVector &v ) : _v( v ), _i /**
( _v._ranges.size(), -1 ), _cmp( _v._ranges.size(), 0 ), _inc( _v._ranges.s * @param v - a FieldRangeVector representing matching keys.
ize(), false ), _after() { * @param singleIntervalLimit - The maximum number of keys to match
} a single (compound)
static BSONObj minObject() { * interval before advancing to the next interval. Limit check
BSONObjBuilder b; b.appendMinKey( "" ); ing is disabled if 0 and
return b.obj(); * must be disabled if v contains FieldIntervals that are not e
} quality().
static BSONObj maxObject() { */
BSONObjBuilder b; b.appendMaxKey( "" ); FieldRangeVectorIterator( const FieldRangeVector &v, int singleInte
return b.obj(); rvalLimit );
}
/** /**
* @return Suggested advance method, based on current key. * @return Suggested advance method through an ordered list of keys
* -2 Iteration is complete, no need to advance. with lookup support
* -1 Advance to the next key, without skipping. * (generally a btree).
* >=0 Skip parameter. If @return is r, skip to the key comprised * -2 Iteration is complete, no need to advance further.
* of the first r elements of curr followed by the (r+1)th and * -1 Advance to the next ordered key, without skipping.
* remaining elements of cmp() (with inclusivity specified by * >=0 Skip parameter, let's call it 'r'. If after() is true, ski
* the (r+1)th and remaining elements of inc()). If after() i p past the key prefix
s * comprised of the first r elements of curr. For example, if
* true, skip past this key not to it. curr is {a:1,b:1}, the
* index is {a:1,b:1}, the direction is 1, and r == 1, skip pa
st {a:1,b:MaxKey}. If
* after() is false, skip to the key comprised of the first r
elements of curr followed
* by the (r+1)th and greater elements of cmp() (with inclusiv
ity specified by the
* (r+1)th and greater elements of inc()). For example, if cu
rr is {a:1,b:1}, the
* index is {a:1,b:1}, the direction is 1, r == 1, cmp()[1] ==
b:4, and inc()[1] ==
* true, then skip to {a:1,b:4}. Note that the element field
names in curr and cmp()
* should generally be ignored when performing index key compa
risons.
* @param curr The key at the current position in the list of keys.
Values of curr must be
* supplied in order.
*/ */
int advance( const BSONObj &curr ); int advance( const BSONObj &curr );
const vector<const BSONElement *> &cmp() const { return _cmp; } const vector<const BSONElement *> &cmp() const { return _cmp; }
const vector<bool> &inc() const { return _inc; } const vector<bool> &inc() const { return _inc; }
bool after() const { return _after; } bool after() const { return _after; }
void prepDive(); void prepDive();
void setZero( int i ) { for( int j = i; j < (int)_i.size(); ++j ) _
i[ j ] = 0; } /**
void setMinus( int i ) { for( int j = i; j < (int)_i.size(); ++j ) * Helper class representing a position within a vector of ranges.
_i[ j ] = -1; } Public for testing.
bool ok() { return _i[ 0 ] < (int)_v._ranges[ 0 ].intervals().size( */
); } class CompoundRangeCounter {
BSONObj startKey(); public:
// temp CompoundRangeCounter( int size, int singleIntervalLimit );
BSONObj endKey(); int size() const { return (int)_i.size(); }
int get( int i ) const { return _i[ i ]; }
void set( int i, int newVal );
void inc( int i );
void setZeroes( int i );
void setUnknowns( int i );
void incSingleIntervalCount() {
if ( isTrackingIntervalCounts() ) ++_singleIntervalCount;
}
bool hasSingleIntervalCountReachedLimit() const {
return isTrackingIntervalCounts() && _singleIntervalCount >
= _singleIntervalLimit;
}
void resetIntervalCount() { _singleIntervalCount = 0; }
private:
bool isTrackingIntervalCounts() const { return _singleIntervalL
imit > 0; }
vector<int> _i;
int _singleIntervalCount;
int _singleIntervalLimit;
};
/**
* Helper class for matching a BSONElement with the bounds of a Fie
ldInterval. Some
* internal comparison results are cached. Public for testing.
*/
class FieldIntervalMatcher {
public:
FieldIntervalMatcher( const FieldInterval &interval, const BSON
Element &element,
bool reverse );
bool isEqInclusiveUpperBound() const {
return upperCmp() == 0 && _interval._upper._inclusive;
}
bool isGteUpperBound() const { return upperCmp() >= 0; }
bool isEqExclusiveLowerBound() const {
return lowerCmp() == 0 && !_interval._lower._inclusive;
}
bool isLtLowerBound() const { return lowerCmp() < 0; }
private:
struct BoundCmp {
BoundCmp() : _cmp(), _valid() {}
void set( int cmp ) { _cmp = cmp; _valid = true; }
int _cmp;
bool _valid;
};
int mayReverse( int val ) const { return _reverse ? -val : val;
}
int cmp( const BSONElement &bound ) const {
return mayReverse( _element.woCompare( bound, false ) );
}
void setCmp( BoundCmp &boundCmp, const BSONElement &bound ) con
st {
boundCmp.set( cmp( bound ) );
}
int lowerCmp() const;
int upperCmp() const;
const FieldInterval &_interval;
const BSONElement &_element;
bool _reverse;
mutable BoundCmp _lowerCmp;
mutable BoundCmp _upperCmp;
};
private: private:
/**
* @return values similar to advance()
* -2 Iteration is complete for the current interval.
* -1 Iteration is not complete for the current interval.
* >=0 Return value to be forwarded by advance().
*/
int validateCurrentInterval( int intervalIdx, const BSONElement &cu
rrElt,
bool reverse, bool first, bool &eqInclu
siveUpperBound );
/** Skip to curr / i / nextbounds. */
int advanceToLowerBound( int i );
/** Skip to curr / i / superlative. */
int advancePast( int i );
/** Skip to curr / i / superlative and reset following interval pos
itions. */
int advancePastZeroed( int i );
bool hasReachedLimitForLastInterval( int intervalIdx ) const {
return _i.hasSingleIntervalCountReachedLimit() && ( intervalIdx
+ 1 == _i.size() );
}
const FieldRangeVector &_v; const FieldRangeVector &_v;
vector<int> _i; CompoundRangeCounter _i;
vector<const BSONElement*> _cmp; vector<const BSONElement*> _cmp;
vector<bool> _inc; vector<bool> _inc;
bool _after; bool _after;
}; };
/** /**
* As we iterate through $or clauses this class generates a FieldRangeS etPair * As we iterate through $or clauses this class generates a FieldRangeS etPair
* for the current $or clause, in some cases by excluding ranges that w ere * for the current $or clause, in some cases by excluding ranges that w ere
* included in a previous clause. * included in a previous clause.
*/ */
 End of changes. 24 change blocks. 
56 lines changed or deleted 425 lines changed or added


 queue.h   queue.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 "../pch.h" #include "pch.h"
#include <limits>
#include <queue> #include <queue>
#include "../util/timer.h" #include "mongo/util/timer.h"
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") { } BlockingQueue() :
_lock("BlockingQueue"),
_size(std::numeric_limits<std::size_t>::max()) { }
BlockingQueue(size_t size) :
_lock("BlockingQueue(bounded)"),
_size(size) { }
void push(T const& t) { void push(T const& t) {
scoped_lock l( _lock ); scoped_lock l( _lock );
while (_queue.size() >= _size) {
_cvNoLongerFull.wait( l.boost() );
}
_queue.push( t ); _queue.push( t );
_condition.notify_one(); _cvNoLongerEmpty.notify_one();
} }
bool empty() const { bool empty() const {
scoped_lock l( _lock ); scoped_lock l( _lock );
return _queue.empty(); return _queue.empty();
} }
size_t size() const { size_t size() const {
scoped_lock l( _lock ); scoped_lock l( _lock );
return _queue.size(); return _queue.size();
} }
bool tryPop( T & t ) { bool tryPop( T & t ) {
scoped_lock l( _lock ); scoped_lock l( _lock );
if ( _queue.empty() ) if ( _queue.empty() )
return false; return false;
t = _queue.front(); t = _queue.front();
_queue.pop(); _queue.pop();
_cvNoLongerFull.notify_one();
return true; return true;
} }
T blockingPop() { T blockingPop() {
scoped_lock l( _lock ); scoped_lock l( _lock );
while( _queue.empty() ) while( _queue.empty() )
_condition.wait( l.boost() ); _cvNoLongerEmpty.wait( l.boost() );
T t = _queue.front(); T t = _queue.front();
_queue.pop(); _queue.pop();
_cvNoLongerFull.notify_one();
return t; return t;
} }
/** /**
* blocks waiting for an object until maxSecondsToWait passes * blocks waiting for an object until maxSecondsToWait passes
* if got one, return true and set in t * if got one, return true and set in t
* otherwise return false and t won't be changed * otherwise return false and t won't be changed
*/ */
bool blockingPop( T& t , int maxSecondsToWait ) { bool blockingPop( T& t , int maxSecondsToWait ) {
Timer timer; Timer timer;
boost::xtime xt; boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC); boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += maxSecondsToWait; xt.sec += maxSecondsToWait;
scoped_lock l( _lock ); scoped_lock l( _lock );
while( _queue.empty() ) { while( _queue.empty() ) {
if ( ! _condition.timed_wait( l.boost() , xt ) ) if ( ! _cvNoLongerEmpty.timed_wait( l.boost() , xt ) )
return false; return false;
} }
t = _queue.front(); t = _queue.front();
_queue.pop(); _queue.pop();
_cvNoLongerFull.notify_one();
return true; return true;
} }
private: private:
std::queue<T> _queue;
mutable mongo::mutex _lock; mutable mongo::mutex _lock;
boost::condition _condition; std::queue<T> _queue;
size_t _size;
boost::condition _cvNoLongerFull;
boost::condition _cvNoLongerEmpty;
}; };
} }
 End of changes. 14 change blocks. 
10 lines changed or deleted 25 lines changed or added


 redef_macros.h   redef_macros.h 
/** @file redef_macros.h macros the implementation uses. /** @file redef_macros.h macros for mongo internals
@see undef_macros.h undefines these after use to minimize name pollutio n. @see undef_macros.h undefines these after use to minimize name pollutio n.
*/ */
/* 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
* *
skipping to change at line 23 skipping to change at line 23
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
// If you define a new global un-prefixed macro, please add it here and in undef_macros // If you define a new global un-prefixed macro, please add it here and in undef_macros
// #pragma once // this file is intended to be processed multiple times #define MONGO_MACROS_PUSHED 1
#if defined(MONGO_MACROS_CLEANED)
// util/allocator.h // util/allocator.h
#pragma push_macro("malloc")
#undef malloc
#define malloc MONGO_malloc #define malloc MONGO_malloc
#pragma push_macro("realloc")
#undef realloc
#define realloc MONGO_realloc #define realloc MONGO_realloc
// util/assert_util.h // util/assert_util.h
#define assert MONGO_assert #pragma push_macro("verify")
#undef verify
#define verify MONGO_verify
#pragma push_macro("dassert")
#undef dassert
#define dassert MONGO_dassert #define dassert MONGO_dassert
#pragma push_macro("wassert")
#undef wassert
#define wassert MONGO_wassert #define wassert MONGO_wassert
#pragma push_macro("massert")
#undef massert
#define massert MONGO_massert #define massert MONGO_massert
#pragma push_macro("uassert")
#undef uassert
#define uassert MONGO_uassert #define uassert MONGO_uassert
#define BOOST_CHECK_EXCEPTION MONGO_BOOST_CHECK_EXCEPTION #pragma push_macro("DESTRUCTOR_GUARD")
#undef DESTRUCTOR_GUARD
#define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD #define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD
// util/goodies.h // util/goodies.h
#pragma push_macro("PRINT")
#undef PRINT
#define PRINT MONGO_PRINT #define PRINT MONGO_PRINT
#pragma push_macro("PRINTFL")
#undef PRINTFL
#define PRINTFL MONGO_PRINTFL #define PRINTFL MONGO_PRINTFL
#define asctime MONGO_asctime
#define gmtime MONGO_gmtime
#define localtime MONGO_localtime
#define ctime MONGO_ctime
// util/debug_util.h // util/debug_util.h
#pragma push_macro("DEV")
#undef DEV
#define DEV MONGO_DEV #define DEV MONGO_DEV
#pragma push_macro("DEBUGGING")
#undef DEBUGGING
#define DEBUGGING MONGO_DEBUGGING #define DEBUGGING MONGO_DEBUGGING
#pragma push_macro("SOMETIMES")
#undef SOMETIMES
#define SOMETIMES MONGO_SOMETIMES #define SOMETIMES MONGO_SOMETIMES
#pragma push_macro("OCCASIONALLY")
#undef OCCASIONALLY
#define OCCASIONALLY MONGO_OCCASIONALLY #define OCCASIONALLY MONGO_OCCASIONALLY
#pragma push_macro("RARELY")
#undef RARELY
#define RARELY MONGO_RARELY #define RARELY MONGO_RARELY
#pragma push_macro("ONCE")
#undef ONCE
#define ONCE MONGO_ONCE #define ONCE MONGO_ONCE
// util/log.h // util/log.h
#pragma push_macro("LOG")
#undef LOG
#define LOG MONGO_LOG #define LOG MONGO_LOG
#undef MONGO_MACROS_CLEANED
#endif
 End of changes. 20 change blocks. 
10 lines changed or deleted 37 lines changed or added


 repl.h   repl.h 
skipping to change at line 33 skipping to change at line 33
at the master: at the master:
local.oplog.$<source> local.oplog.$<source>
*/ */
#pragma once #pragma once
#include "pdfile.h" #include "pdfile.h"
#include "db.h" #include "db.h"
#include "dbhelpers.h" #include "dbhelpers.h"
#include "../client/dbclient.h"
#include "../util/optime.h" #include "../util/optime.h"
#include "oplog.h" #include "oplog.h"
#include "../util/concurrency/thread_pool.h" #include "../util/concurrency/thread_pool.h"
#include "oplogreader.h" #include "oplogreader.h"
#include "cloner.h" #include "cloner.h"
namespace mongo { namespace mongo {
/* replication slave? (possibly with slave) /* replication slave? (possibly with slave)
--slave cmd line setting -> SimpleSlave --slave cmd line setting -> SimpleSlave
 End of changes. 1 change blocks. 
1 lines changed or deleted 0 lines changed or added


 replutil.h   replutil.h 
skipping to change at line 22 skipping to change at line 22
* *
* 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 "db.h" #include "db.h"
#include "dbhelpers.h" #include "dbhelpers.h"
#include "json.h" #include "json.h"
#include "../client/dbclient.h"
#include "repl.h" #include "repl.h"
#include "cmdline.h" #include "cmdline.h"
#include "repl/rs.h" #include "repl/rs.h"
#include "ops/query.h" #include "mongo/db/queryutil.h"
namespace mongo { namespace mongo {
extern const char *replAllDead; extern const char *replAllDead;
/* note we always return true for the "local" namespace. /* note we always return true for the "local" namespace.
we should not allow most operations when not the master we should not allow most operations when not the master
also we report not master if we are "dead". also we report not master if we are "dead".
skipping to change at line 69 skipping to change at line 68
if ( cc().isGod() ) if ( cc().isGod() )
return true; return true;
return false; return false;
} }
inline bool isMaster(const char * dbname = 0) { inline bool isMaster(const char * dbname = 0) {
if( _isMaster() ) if( _isMaster() )
return true; return true;
if ( ! dbname ) { if ( ! dbname ) {
Database *database = cc().database(); Database *database = cc().database();
assert( database ); verify( database );
dbname = database->name.c_str(); dbname = database->name.c_str();
} }
return strcmp( dbname , "local" ) == 0; return strcmp( dbname , "local" ) == 0;
} }
inline bool isMasterNs( const char *ns ) { inline bool isMasterNs( const char *ns ) {
if ( _isMaster() ) if ( _isMaster() )
return true; return true;
assert( ns ); verify( ns );
if ( ! str::startsWith( ns , "local" ) ) if ( ! str::startsWith( ns , "local" ) )
return false; return false;
return ns[5] == 0 || ns[5] == '.'; return ns[5] == 0 || ns[5] == '.';
} }
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 */ /** we allow queries to SimpleSlave's */
inline void replVerifyReadsOk(ParsedQuery& pq) { inline void replVerifyReadsOk(ParsedQuery* pq = 0) {
if( replSet ) { if( replSet ) {
/* todo: speed up the secondary case. as written here there ar e 2 mutex entries, it can b 1. */ /* todo: speed up the secondary case. as written here there ar e 2 mutex entries, it can b 1. */
if( isMaster() ) return; if( isMaster() ) return;
uassert(13435, "not master and slaveOk=false", pq.hasOption(Que ryOption_SlaveOk)); uassert(13435, "not master and slaveOk=false", !pq || pq->hasOp tion(QueryOption_SlaveOk));
uassert(13436, "not master or secondary; cannot currently read from this replSet member", theReplSet && theReplSet->isSecondary() ); uassert(13436, "not master or secondary; cannot currently read from this replSet member", theReplSet && theReplSet->isSecondary() );
} }
else { else {
notMasterUnless(isMaster() || pq.hasOption(QueryOption_SlaveOk) || replSettings.slave == SimpleSlave ); notMasterUnless(isMaster() || (!pq || pq->hasOption(QueryOption _SlaveOk)) || replSettings.slave == SimpleSlave );
} }
} }
} // namespace mongo } // namespace mongo
 End of changes. 7 change blocks. 
7 lines changed or deleted 6 lines changed or added


 request.h   request.h 
skipping to change at line 53 skipping to change at line 53
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;
} }
DBConfigPtr getConfig() const { DBConfigPtr getConfig() const {
assert( _didInit ); verify( _didInit );
return _config; return _config;
} }
bool isShardingEnabled() const { bool isShardingEnabled() const {
assert( _didInit ); verify( _didInit );
return _config->isShardingEnabled(); return _config->isShardingEnabled();
} }
ChunkManagerPtr getChunkManager() const { ChunkManagerPtr getChunkManager() const {
assert( _didInit ); verify( _didInit );
return _chunkManager; return _chunkManager;
} }
ClientInfo * getClientInfo() const { ClientInfo * getClientInfo() const {
return _clientInfo; return _clientInfo;
} }
/** /**
* @param ns - 0=use ns from message * @param ns - 0=use ns from message
*/ */
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 rs.h   rs.h 
skipping to change at line 218 skipping to change at line 218
/** /**
* most operations on a ReplSet object should be done while locked. tha t * most operations on a ReplSet object should be done while locked. tha t
* logic implemented here. * logic implemented here.
* *
* Order of locking: lock the replica set, then take a rwlock. * Order of locking: lock the replica set, then take a rwlock.
*/ */
class RSBase : boost::noncopyable { class RSBase : boost::noncopyable {
public: public:
const unsigned magic; const unsigned magic;
void assertValid() { assert( magic == 0x12345677 ); } void assertValid() { verify( magic == 0x12345677 ); }
private: private:
mongo::mutex m; mongo::mutex m;
int _locked; int _locked;
ThreadLocalValue<bool> _lockedByMe; ThreadLocalValue<bool> _lockedByMe;
protected: protected:
RSBase() : magic(0x12345677), m("RSBase"), _locked(0) { } RSBase() : magic(0x12345677), m("RSBase"), _locked(0) { }
~RSBase() { ~RSBase() {
/* this can happen if we throw in the constructor; otherwise ne ver happens. thus we log it as it is quite unusual. */ /* this can happen if we throw in the constructor; otherwise ne ver happens. thus we log it as it is quite unusual. */
log() << "replSet ~RSBase called" << rsLog; log() << "replSet ~RSBase called" << rsLog;
} }
skipping to change at line 240 skipping to change at line 240
public: public:
class lock { class lock {
RSBase& rsbase; RSBase& rsbase;
auto_ptr<scoped_lock> sl; auto_ptr<scoped_lock> sl;
public: public:
lock(RSBase* b) : rsbase(*b) { lock(RSBase* b) : rsbase(*b) {
if( rsbase._lockedByMe.get() ) if( rsbase._lockedByMe.get() )
return; // recursive is ok... return; // recursive is ok...
sl.reset( new scoped_lock(rsbase.m) ); sl.reset( new scoped_lock(rsbase.m) );
DEV assert(rsbase._locked == 0); DEV verify(rsbase._locked == 0);
rsbase._locked++; rsbase._locked++;
rsbase._lockedByMe.set(true); rsbase._lockedByMe.set(true);
} }
~lock() { ~lock() {
if( sl.get() ) { if( sl.get() ) {
assert( rsbase._lockedByMe.get() ); verify( rsbase._lockedByMe.get() );
DEV assert(rsbase._locked == 1); DEV verify(rsbase._locked == 1);
rsbase._lockedByMe.set(false); rsbase._lockedByMe.set(false);
rsbase._locked--; rsbase._locked--;
} }
} }
}; };
/* for asserts */ /* for asserts */
bool locked() const { return _locked != 0; } bool locked() const { return _locked != 0; }
/* if true, is locked, and was locked by this thread. note if false , it could be in the lock or not for another /* if true, is locked, and was locked by this thread. note if false , it could be in the lock or not for another
skipping to change at line 308 skipping to change at line 308
} }
} }
void set(MemberState s, const Member *p) { void set(MemberState s, const Member *p) {
rwlock lk(m, true); rwlock lk(m, true);
sp.state = s; sp.state = s;
sp.primary = p; sp.primary = p;
} }
void setSelfPrimary(const Member *self) { change(MemberState::RS_PR IMARY, self); } void setSelfPrimary(const Member *self) { change(MemberState::RS_PR IMARY, self); }
void setOtherPrimary(const Member *mem) { void setOtherPrimary(const Member *mem) {
rwlock lk(m, true); rwlock lk(m, true);
assert( !sp.state.primary() ); verify( !sp.state.primary() );
sp.primary = mem; sp.primary = mem;
} }
void noteRemoteIsPrimary(const Member *remote) { void noteRemoteIsPrimary(const Member *remote) {
rwlock lk(m, true); rwlock lk(m, true);
if( !sp.state.secondary() && !sp.state.fatal() ) if( !sp.state.secondary() && !sp.state.fatal() )
sp.state = MemberState::RS_RECOVERING; sp.state = MemberState::RS_RECOVERING;
sp.primary = remote; sp.primary = remote;
} }
StateBox() : m("StateBox") { } StateBox() : m("StateBox") { }
private: private:
skipping to change at line 358 skipping to change at line 358
static DiagStr startupStatusMsg; static DiagStr startupStatusMsg;
static string stateAsHtml(MemberState state); static string stateAsHtml(MemberState state);
/* todo thread */ /* todo thread */
void msgUpdateHBInfo(HeartbeatInfo); void msgUpdateHBInfo(HeartbeatInfo);
StateBox box; StateBox box;
OpTime lastOpTimeWritten; OpTime lastOpTimeWritten;
long long lastH; // hash we use to make sure we are reading the rig ht flow of ops and aren't on an out-of-date "fork" long long lastH; // hash we use to make sure we are reading the rig ht flow of ops and aren't on an out-of-date "fork"
bool forceSyncFrom(const string& host, string& errmsg, BSONObjBuild er& result);
private: private:
set<ReplSetHealthPollTask*> healthTasks; set<ReplSetHealthPollTask*> healthTasks;
void endOldHealthTasks(); void endOldHealthTasks();
void startHealthTaskFor(Member *m); void startHealthTaskFor(Member *m);
Consensus elect; Consensus elect;
void relinquish(); void relinquish();
void forgetPrimary(); void forgetPrimary();
protected: protected:
bool _stepDown(int secs); bool _stepDown(int secs);
skipping to change at line 380 skipping to change at line 381
void assumePrimary(); void assumePrimary();
void loadLastOpTimeWritten(bool quiet=false); void loadLastOpTimeWritten(bool quiet=false);
void changeState(MemberState s); void changeState(MemberState s);
/** /**
* Find the closest member (using ping time) with a higher latest o ptime. * Find the closest member (using ping time) with a higher latest o ptime.
*/ */
Member* getMemberToSyncTo(); Member* getMemberToSyncTo();
void veto(const string& host, unsigned secs=10); void veto(const string& host, unsigned secs=10);
Member* _currentSyncTarget; Member* _currentSyncTarget;
Member* _forceSyncTarget;
bool _blockSync; bool _blockSync;
void blockSync(bool block); void blockSync(bool block);
// set of electable members' _ids // set of electable members' _ids
set<unsigned> _electableSet; set<unsigned> _electableSet;
protected: protected:
// "heartbeat message" // "heartbeat message"
// sent in requestHeartbeat respond in field "hbm" // sent in requestHeartbeat respond in field "hbm"
char _hbmsg[256]; // we change this unlocked, thus not an stl::stri ng char _hbmsg[256]; // we change this unlocked, thus not an stl::stri ng
skipping to change at line 556 skipping to change at line 558
public: public:
ReplSet(ReplSetCmdline& replSetCmdline) : ReplSetImpl(replSetCmdlin e) { } ReplSet(ReplSetCmdline& replSetCmdline) : ReplSetImpl(replSetCmdlin e) { }
// for the replSetStepDown command // for the replSetStepDown command
bool stepDown(int secs) { return _stepDown(secs); } bool stepDown(int secs) { return _stepDown(secs); }
// for the replSetFreeze command // for the replSetFreeze command
bool freeze(int secs) { return _freeze(secs); } bool freeze(int secs) { return _freeze(secs); }
string selfFullName() { string selfFullName() {
assert( _self ); verify( _self );
return _self->fullName(); return _self->fullName();
} }
bool buildIndexes() const { return _buildIndexes; } bool buildIndexes() const { return _buildIndexes; }
/* call after constructing to start - returns fairly quickly after la[unching its threads */ /* call after constructing to start - returns fairly quickly after la[unching its threads */
void go() { _go(); } void go() { _go(); }
void fatal() { _fatal(); } void fatal() { _fatal(); }
bool isPrimary() { return box.getState().primary(); } bool isPrimary() { return box.getState().primary(); }
skipping to change at line 662 skipping to change at line 664
/** /**
* does local authentication * does local authentication
* directly authorizes against AuthenticationInfo * directly authorizes against AuthenticationInfo
*/ */
void replLocalAuth(); void replLocalAuth();
/** inlines ----------------- */ /** inlines ----------------- */
inline Member::Member(HostAndPort h, unsigned ord, const ReplSetConfig: :MemberCfg *c, bool self) : inline Member::Member(HostAndPort h, unsigned ord, const ReplSetConfig: :MemberCfg *c, bool self) :
_config(*c), _h(h), _hbinfo(ord) { _config(*c), _h(h), _hbinfo(ord) {
assert(c); verify(c);
if( self ) if( self )
_hbinfo.health = 1.0; _hbinfo.health = 1.0;
} }
} }
 End of changes. 8 change blocks. 
7 lines changed or deleted 9 lines changed or added


 rs_config.h   rs_config.h 
skipping to change at line 34 skipping to change at line 34
#include "../../util/concurrency/race.h" #include "../../util/concurrency/race.h"
#include "health.h" #include "health.h"
namespace mongo { namespace mongo {
class Member; class Member;
const string rsConfigNs = "local.system.replset"; const string rsConfigNs = "local.system.replset";
class ReplSetConfig { class ReplSetConfig {
enum { EMPTYCONFIG = -2 }; enum { EMPTYCONFIG = -2 };
struct TagSubgroup; struct TagSubgroup;
// Protects _groups.
static mongo::mutex groupMx;
public: public:
/** /**
* This contacts the given host and tries to get a config from them . * This contacts the given host and tries to get a config from them .
* *
* This sends a test heartbeat to the host and, if all goes well an d the * This sends a test heartbeat to the host and, if all goes well an d the
* host has a more recent config, fetches the config and loads it ( see * host has a more recent config, fetches the config and loads it ( see
* from(). * from().
* *
* If it's contacting itself, it skips the heartbeat (for obvious * If it's contacting itself, it skips the heartbeat (for obvious
* reasons.) If something is misconfigured, throws an exception. If the * reasons.) If something is misconfigured, throws an exception. If the
skipping to change at line 79 skipping to change at line 82
return _groups; return _groups;
} }
set<TagSubgroup*>& groupsw() { set<TagSubgroup*>& groupsw() {
return _groups; return _groups;
} }
void check() const; /* check validity, assert if not. */ void check() const; /* check validity, assert if not. */
BSONObj asBson() const; BSONObj asBson() const;
bool potentiallyHot() const { return !arbiterOnly && priority > 0; } bool potentiallyHot() const { return !arbiterOnly && priority > 0; }
void updateGroups(const OpTime& last) { void updateGroups(const OpTime& last) {
RACECHECK RACECHECK
scoped_lock lk(ReplSetConfig::groupMx);
for (set<TagSubgroup*>::const_iterator it = groups().begin( ); it != groups().end(); it++) { for (set<TagSubgroup*>::const_iterator it = groups().begin( ); it != groups().end(); it++) {
(*it)->updateLast(last); (*it)->updateLast(last);
} }
} }
bool operator==(const MemberCfg& r) const { bool operator==(const MemberCfg& r) const {
if (!tags.empty() || !r.tags.empty()) { if (!tags.empty() || !r.tags.empty()) {
if (tags.size() != r.tags.size()) { if (tags.size() != r.tags.size()) {
return false; return false;
} }
 End of changes. 2 change blocks. 
0 lines changed or deleted 4 lines changed or added


 rs_member.h   rs_member.h 
skipping to change at line 45 skipping to change at line 45
enum MS { enum MS {
RS_STARTUP = 0, RS_STARTUP = 0,
RS_PRIMARY = 1, RS_PRIMARY = 1,
RS_SECONDARY = 2, RS_SECONDARY = 2,
RS_RECOVERING = 3, RS_RECOVERING = 3,
RS_FATAL = 4, RS_FATAL = 4,
RS_STARTUP2 = 5, RS_STARTUP2 = 5,
RS_UNKNOWN = 6, /* remote node not yet reached */ RS_UNKNOWN = 6, /* remote node not yet reached */
RS_ARBITER = 7, RS_ARBITER = 7,
RS_DOWN = 8, /* node not reachable for a report */ RS_DOWN = 8, /* node not reachable for a report */
RS_ROLLBACK = 9 RS_ROLLBACK = 9,
RS_SHUNNED = 10, /* node shunned from replica set */
} s; } s;
MemberState(MS ms = RS_UNKNOWN) : s(ms) { } MemberState(MS ms = RS_UNKNOWN) : s(ms) { }
explicit MemberState(int ms) : s((MS) ms) { } explicit MemberState(int ms) : s((MS) ms) { }
bool startup() const { return s == RS_STARTUP; } bool startup() const { return s == RS_STARTUP; }
bool primary() const { return s == RS_PRIMARY; } bool primary() const { return s == RS_PRIMARY; }
bool secondary() const { return s == RS_SECONDARY; } bool secondary() const { return s == RS_SECONDARY; }
bool recovering() const { return s == RS_RECOVERING; } bool recovering() const { return s == RS_RECOVERING; }
bool startup2() const { return s == RS_STARTUP2; } bool startup2() const { return s == RS_STARTUP2; }
bool fatal() const { return s == RS_FATAL; } bool fatal() const { return s == RS_FATAL; }
bool rollback() const { return s == RS_ROLLBACK; } bool rollback() const { return s == RS_ROLLBACK; }
bool readable() const { return s == RS_PRIMARY || s == RS_SECONDARY ; } bool readable() const { return s == RS_PRIMARY || s == RS_SECONDARY ; }
bool shunned() const { return s == RS_SHUNNED; }
string toString() const; string toString() const;
bool operator==(const MemberState& r) const { return s == r.s; } bool operator==(const MemberState& r) const { return s == r.s; }
bool operator!=(const MemberState& r) const { return s != r.s; } bool operator!=(const MemberState& r) const { return s != r.s; }
}; };
/* this is supposed to be just basic information on a member, /* this is supposed to be just basic information on a member,
and copy constructable. */ and copy constructable. */
class HeartbeatInfo { class HeartbeatInfo {
skipping to change at line 126 skipping to change at line 128
case RS_STARTUP: return "STARTUP"; case RS_STARTUP: return "STARTUP";
case RS_PRIMARY: return "PRIMARY"; case RS_PRIMARY: return "PRIMARY";
case RS_SECONDARY: return "SECONDARY"; case RS_SECONDARY: return "SECONDARY";
case RS_RECOVERING: return "RECOVERING"; case RS_RECOVERING: return "RECOVERING";
case RS_FATAL: return "FATAL"; case RS_FATAL: return "FATAL";
case RS_STARTUP2: return "STARTUP2"; case RS_STARTUP2: return "STARTUP2";
case RS_ARBITER: return "ARBITER"; case RS_ARBITER: return "ARBITER";
case RS_DOWN: return "DOWN"; case RS_DOWN: return "DOWN";
case RS_ROLLBACK: return "ROLLBACK"; case RS_ROLLBACK: return "ROLLBACK";
case RS_UNKNOWN: return "UNKNOWN"; case RS_UNKNOWN: return "UNKNOWN";
case RS_SHUNNED: return "REMOVED";
} }
return ""; return "";
} }
} }
 End of changes. 3 change blocks. 
1 lines changed or deleted 4 lines changed or added


 rs_optime.h   rs_optime.h 
skipping to change at line 27 skipping to change at line 27
*/ */
#pragma once #pragma once
#include "../../util/optime.h" #include "../../util/optime.h"
namespace mongo { namespace mongo {
const char rsoplog[] = "local.oplog.rs"; const char rsoplog[] = "local.oplog.rs";
/*
class RSOpTime : public OpTime {
public:
bool initiated() const { return getSecs() != 0; }
};*/
/*struct RSOpTime {
unsigned long long ord;
RSOpTime() : ord(0) { }
bool initiated() const { return ord > 0; }
void initiate() {
assert( !initiated() );
ord = 1000000;
}
ReplTime inc() {
DEV assertInWriteLock();
return ++ord;
}
string toString() const { return str::stream() << ord; }
// query the oplog and set the highest value herein. acquires a db
read lock. throws.
void load();
};
extern RSOpTime rsOpTime;*/
} }
 End of changes. 1 change blocks. 
32 lines changed or deleted 0 lines changed or added


 rwlock.h   rwlock.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 Lice nse * You should have received a copy of the GNU Affero General Public Lice nse
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "mutex.h" #include "mutex.h"
#include "../time_support.h" #include "../time_support.h"
#include "rwlockimpl.h" #include "rwlockimpl.h"
#if defined(_DEBUG) #if defined(_DEBUG)
#include "mutexdebugger.h" #include "mutexdebugger.h"
#endif #endif
#include "simplerwlock.h"
namespace mongo { namespace mongo {
/** separated out as later the implementation of this may be different
than RWLock,
depending on OS, as there is no upgrade etc. facility herein.
*/
class SimpleRWLock : public RWLockBase {
public:
explicit SimpleRWLock(const char *) { }
SimpleRWLock() { }
void lock() { RWLockBase::lock(); }
void unlock() { RWLockBase::unlock(); }
void lock_shared() { RWLockBase::lock_shared(); }
void unlock_shared() { RWLockBase::unlock_shared(); }
class Shared : boost::noncopyable {
SimpleRWLock& _r;
public:
Shared(SimpleRWLock& rwlock) : _r(rwlock) {_r.lock_shared(); }
~Shared() { _r.unlock_shared(); }
};
class Exclusive : boost::noncopyable {
SimpleRWLock& _r;
public:
Exclusive(SimpleRWLock& rwlock) : _r(rwlock) {_r.lock(); }
~Exclusive() { _r.unlock(); }
};
};
class RWLock : public RWLockBase { class RWLock : public RWLockBase {
enum { NilState, UpgradableState, Exclusive } x; // only bother to set when doing upgradable related things enum { NilState, UpgradableState, Exclusive } x; // only bother to set when doing upgradable related things
public: public:
const char * const _name; const char * const _name;
RWLock(const char *name) : _name(name) { RWLock(const char *name) : _name(name) {
x = NilState; x = NilState;
} }
void lock() { void lock() {
RWLockBase::lock(); RWLockBase::lock();
#if defined(_DEBUG) #if defined(_DEBUG)
skipping to change at line 85 skipping to change at line 60
void lock_shared() { RWLockBase::lock_shared(); } void lock_shared() { RWLockBase::lock_shared(); }
void unlock_shared() { RWLockBase::unlock_shared(); } void unlock_shared() { RWLockBase::unlock_shared(); }
private: private:
void lockAsUpgradable() { RWLockBase::lockAsUpgradable(); } void lockAsUpgradable() { RWLockBase::lockAsUpgradable(); }
void unlockFromUpgradable() { // upgradable -> unlocked void unlockFromUpgradable() { // upgradable -> unlocked
RWLockBase::unlockFromUpgradable(); RWLockBase::unlockFromUpgradable();
} }
public: public:
void upgrade() { // upgradable -> exclusive lock void upgrade() { // upgradable -> exclusive lock
assert( x == UpgradableState ); verify( x == UpgradableState );
RWLockBase::upgrade(); RWLockBase::upgrade();
x = Exclusive; x = Exclusive;
} }
bool lock_shared_try( int millis ) { return RWLockBase::lock_shared _try(millis); } bool lock_shared_try( int millis ) { return RWLockBase::lock_shared _try(millis); }
bool lock_try( int millis = 0 ) { bool lock_try( int millis = 0 ) {
if( RWLockBase::lock_try(millis) ) { if( RWLockBase::lock_try(millis) ) {
#if defined(_DEBUG) #if defined(_DEBUG)
mutexDebugger.entering(_name); mutexDebugger.entering(_name);
skipping to change at line 111 skipping to change at line 86
/** acquire upgradable state. You must be unlocked before creating . /** acquire upgradable state. You must be unlocked before creating .
unlocks on destruction, whether in upgradable state or upgraded to exclusive unlocks on destruction, whether in upgradable state or upgraded to exclusive
in the interim. in the interim.
*/ */
class Upgradable : boost::noncopyable { class Upgradable : boost::noncopyable {
RWLock& _r; RWLock& _r;
public: public:
Upgradable(RWLock& r) : _r(r) { Upgradable(RWLock& r) : _r(r) {
r.lockAsUpgradable(); r.lockAsUpgradable();
assert( _r.x == NilState ); verify( _r.x == NilState );
_r.x = RWLock::UpgradableState; _r.x = RWLock::UpgradableState;
} }
~Upgradable() { ~Upgradable() {
if( _r.x == RWLock::UpgradableState ) { if( _r.x == RWLock::UpgradableState ) {
_r.x = NilState; _r.x = NilState;
_r.unlockFromUpgradable(); _r.unlockFromUpgradable();
} }
else { else {
//TEMP assert( _r.x == Exclusive ); // has been upgraded //TEMP verify( _r.x == Exclusive ); // has been upgraded
_r.x = NilState; _r.x = NilState;
_r.unlock(); _r.unlock();
} }
} }
}; };
}; };
/** throws on failure to acquire in the specified time period. */ /** throws on failure to acquire in the specified time period. */
class rwlock_try_write : boost::noncopyable { class rwlock_try_write : boost::noncopyable {
public: public:
skipping to change at line 192 skipping to change at line 167
protected: protected:
ThreadLocalValue<int> _state; ThreadLocalValue<int> _state;
void lock(); // not implemented - Lock() should be used; didn't ove rload this name to avoid mistakes void lock(); // not implemented - Lock() should be used; didn't ove rload this name to avoid mistakes
virtual void Lock() { RWLockBase::lock(); } virtual void Lock() { RWLockBase::lock(); }
public: public:
virtual ~RWLockRecursive() { } virtual ~RWLockRecursive() { }
const char * const _name; const char * const _name;
RWLockRecursive(const char *name) : _name(name) { } RWLockRecursive(const char *name) : _name(name) { }
void assertExclusivelyLocked() { void assertExclusivelyLocked() {
assert( _state.get() < 0 ); verify( _state.get() < 0 );
} }
class Exclusive : boost::noncopyable { class Exclusive : boost::noncopyable {
RWLockRecursive& _r; RWLockRecursive& _r;
public: public:
Exclusive(RWLockRecursive& r) : _r(r) { Exclusive(RWLockRecursive& r) : _r(r) {
int s = _r._state.get(); int s = _r._state.get();
dassert( s <= 0 ); dassert( s <= 0 );
if( s == 0 ) if( s == 0 )
_r.Lock(); _r.Lock();
 End of changes. 7 change blocks. 
31 lines changed or deleted 5 lines changed or added


 rwlockimpl.h   rwlockimpl.h 
// @file rwlockimpl.h // @file rwlockimpl.h
#pragma once #pragma once
#include "mutex.h" #include "mutex.h"
//#define RWLOCK_TEST 1
namespace mongo {
class RWLockBase1 : boost::noncopyable {
unsigned reading;
unsigned writing;
unsigned wantToWrite;
boost::mutex m;
boost::condition m_cond;
boost::mutex writer;
public:
RWLockBase1();
~RWLockBase1();
const char * implType() const { return "mongo"; }
void lock();
void unlock();
void lock_shared();
void unlock_shared();
bool lock_shared_try(int millis);
bool lock_try(int millis = 0);
void lockAsUpgradable();
void unlockFromUpgradable();
void upgrade();
};
}
#if defined(RWLOCK_TEST) #if defined(RWLOCK_TEST)
namespace mongo { namespace mongo {
typedef RWLockBase1 RWLockBase; typedef RWLockBase1 RWLockBase;
} }
#elif defined(MONGO_USE_SRW_ON_WINDOWS) && defined(_WIN32) #elif defined(MONGO_USE_SRW_ON_WINDOWS) && defined(_WIN32)
// windows slimreaderwriter version. newer windows versions only // windows slimreaderwriter version. newer windows versions only
namespace mongo { namespace mongo {
unsigned long long curTimeMicros64(); unsigned long long curTimeMicros64();
class RWLockBase : boost::noncopyable { class RWLockBase : boost::noncopyable {
friend class SimpleRWLock;
SRWLOCK _lock; SRWLOCK _lock;
protected: protected:
RWLockBase() { InitializeSRWLock(&_lock); } RWLockBase() { InitializeSRWLock(&_lock); }
~RWLockBase() { ~RWLockBase() {
// no special action needed to destroy a SRWLOCK // no special action needed to destroy a SRWLOCK
} }
void lock() { AcquireSRWLockExclusive(&_lock); } void lock() { AcquireSRWLockExclusive(&_lock); }
void unlock() { ReleaseSRWLockExclusive(&_lock); } void unlock() { ReleaseSRWLockExclusive(&_lock); }
void lock_shared() { AcquireSRWLockShared(&_lock); } void lock_shared() { AcquireSRWLockShared(&_lock); }
void unlock_shared() { ReleaseSRWLockShared(&_lock); } void unlock_shared() { ReleaseSRWLockShared(&_lock); }
skipping to change at line 110 skipping to change at line 83
# error need boost >= 1.35 for windows # error need boost >= 1.35 for windows
# endif # endif
// pthreads version // pthreads version
# include <pthread.h> # include <pthread.h>
# include <errno.h> # include <errno.h>
namespace mongo { namespace mongo {
class RWLockBase : boost::noncopyable { class RWLockBase : boost::noncopyable {
friend class SimpleRWLock;
pthread_rwlock_t _lock; pthread_rwlock_t _lock;
static void check( int x ) { static void check( int x ) {
assert( x == 0 ); verify( x == 0 );
} }
protected: protected:
~RWLockBase() { ~RWLockBase() {
if ( ! StaticObserver::_destroyingStatics ) { if ( ! StaticObserver::_destroyingStatics ) {
wassert( pthread_rwlock_destroy( &_lock ) == 0 ); // wasser t as don't want to throw from a destructor wassert( pthread_rwlock_destroy( &_lock ) == 0 ); // wasser t as don't want to throw from a destructor
} }
} }
RWLockBase() { RWLockBase() {
check( pthread_rwlock_init( &_lock , 0 ) ); check( pthread_rwlock_init( &_lock , 0 ) );
} }
void lock() { check( pthread_rwlock_wrlock( &_lock ) ); } void lock() { check( pthread_rwlock_wrlock( &_lock ) ); }
void unlock() { check( pthread_rwlock_unlock( &_lock ) ); } void unlock() { check( pthread_rwlock_unlock( &_lock ) ); }
void lock_shared() { check( pthread_rwlock_rdlock( &_lock ) ); } void lock_shared() { check( pthread_rwlock_rdlock( &_lock ) ); }
void unlock_shared() { check( pthread_rwlock_unlock( &_lock ) ); } void unlock_shared() { check( pthread_rwlock_unlock( &_lock ) ); }
bool lock_shared_try( int millis ) { return _try( millis , false ); } bool lock_shared_try( int millis ) { return _try( millis , false ); }
bool lock_try( int millis = 0 ) { return _try( millis , true ); } bool lock_try( int millis = 0 ) { return _try( millis , true ); }
bool _try( int millis , bool write ) { bool _try( int millis , bool write ) {
while ( true ) { while ( true ) {
int x = write ? int x = write ?
pthread_rwlock_trywrlock( &_lock ) : pthread_rwlock_trywrlock( &_lock ) :
skipping to change at line 169 skipping to change at line 140
// Boost version // Boost version
# if defined(_WIN32) # if defined(_WIN32)
# include "shared_mutex_win.hpp" # include "shared_mutex_win.hpp"
namespace mongo { typedef boost::modified_shared_mutex shared_mutex; } namespace mongo { typedef boost::modified_shared_mutex shared_mutex; }
# else # else
# include <boost/thread/shared_mutex.hpp> # include <boost/thread/shared_mutex.hpp>
namespace mongo { using boost::shared_mutex; } namespace mongo { using boost::shared_mutex; }
# endif # endif
# undef assert
# define assert MONGO_assert
namespace mongo { namespace mongo {
class RWLockBase : boost::noncopyable { class RWLockBase : boost::noncopyable {
friend class SimpleRWLock;
shared_mutex _m; shared_mutex _m;
protected: protected:
void lock() { void lock() {
_m.lock(); _m.lock();
} }
void unlock() { void unlock() {
_m.unlock(); _m.unlock();
} }
void lockAsUpgradable() { void lockAsUpgradable() {
_m.lock_upgrade(); _m.lock_upgrade();
 End of changes. 9 change blocks. 
34 lines changed or deleted 4 lines changed or added


 scanandorder.h   scanandorder.h 
skipping to change at line 37 skipping to change at line 37
namespace mongo { namespace mongo {
static const int ScanAndOrderMemoryLimitExceededAssertionCode = 10128; static const int ScanAndOrderMemoryLimitExceededAssertionCode = 10128;
class KeyType : boost::noncopyable { class KeyType : boost::noncopyable {
public: public:
IndexSpec _spec; IndexSpec _spec;
FieldRangeVector _keyCutter; FieldRangeVector _keyCutter;
public: public:
KeyType(const BSONObj &pattern, const FieldRangeSet &frs): KeyType(const BSONObj &pattern, const FieldRangeSet &frs):
_spec((assert(!pattern.isEmpty()),pattern)), _spec((verify(!pattern.isEmpty()),pattern)),
_keyCutter(frs, _spec, 1) { _keyCutter(frs, _spec, 1) {
} }
/** /**
* @return first key of the object that would be encountered while * @return first key of the object that would be encountered while
* scanning index with keySpec 'pattern' using constraints 'frs', o r * scanning an index with keySpec 'pattern' using constraints 'frs' , or
* BSONObj() if no such key. * BSONObj() if no such key.
*/ */
BSONObj getKeyFromObject(const BSONObj &o) const { BSONObj getKeyFromObject(const BSONObj &o) const {
return _keyCutter.firstMatch(o); return _keyCutter.firstMatch(o);
} }
}; };
/* todo: /* todo:
_ response size limit from runquery; push it up a bit. _ response size limit from runquery; push it up a bit.
*/ */
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 scopeguard.h   scopeguard.h 
skipping to change at line 18 skipping to change at line 18
// purpose is hereby granted without fee, provided that the above copyr ight // purpose is hereby granted without fee, provided that the above copyr ight
// notice appear in all copies and that both that copyright notice and this // notice appear in all copies and that both that copyright notice and this
// permission notice appear in supporting documentation. // permission notice appear in supporting documentation.
// The author makes no representations about the // The author makes no representations about the
// suitability of this software for any purpose. It is provided "as is" // suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty. // without express or implied warranty.
/////////////////////////////////////////////////////////////////////////// ///// /////////////////////////////////////////////////////////////////////////// /////
#ifndef LOKI_SCOPEGUARD_H_ #ifndef LOKI_SCOPEGUARD_H_
#define LOKI_SCOPEGUARD_H_ #define LOKI_SCOPEGUARD_H_
#include "mongo/platform/compiler.h"
namespace mongo namespace mongo
{ {
/////////////////////////////////////////////////////////////////////// ///////// /////////////////////////////////////////////////////////////////////// /////////
/// \class RefToValue /// \class RefToValue
/// ///
/// Transports a reference as a value /// Transports a reference as a value
/// Serves to implement the Colvin/Gibbons trick for SmartPtr/ScopeGua rd /// Serves to implement the Colvin/Gibbons trick for SmartPtr/ScopeGua rd
/////////////////////////////////////////////////////////////////////// ///////// /////////////////////////////////////////////////////////////////////// /////////
skipping to change at line 417 skipping to change at line 419
{ {
return ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1a,P2a),P1b,P2b>::Make ObjGuard(*obj,memFun,p1,p2); return ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1a,P2a),P1b,P2b>::Make ObjGuard(*obj,memFun,p1,p2);
} }
} // namespace Loki } // namespace Loki
#define LOKI_CONCATENATE_DIRECT(s1, s2) s1##s2 #define LOKI_CONCATENATE_DIRECT(s1, s2) s1##s2
#define LOKI_CONCATENATE(s1, s2) LOKI_CONCATENATE_DIRECT(s1, s2) #define LOKI_CONCATENATE(s1, s2) LOKI_CONCATENATE_DIRECT(s1, s2)
#define LOKI_ANONYMOUS_VARIABLE(str) LOKI_CONCATENATE(str, __LINE__) #define LOKI_ANONYMOUS_VARIABLE(str) LOKI_CONCATENATE(str, __LINE__)
#ifdef __GNUC__ #define ON_BLOCK_EXIT \
#define ON_BLOCK_EXIT ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) __attr MONGO_COMPILER_VARIABLE_UNUSED ScopeGuard LOKI_ANONYMOUS_VARIABLE(scope
ibute__ ((unused)) = MakeGuard Guard) = MakeGuard
#define ON_BLOCK_EXIT_OBJ ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) __ #define ON_BLOCK_EXIT_OBJ \
attribute__ ((unused)) = MakeObjGuard MONGO_COMPILER_VARIABLE_UNUSED ScopeGuard LOKI_ANONYMOUS_VARIABLE(scope
#else Guard) = MakeObjGuard
#define ON_BLOCK_EXIT ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = Make
Guard
#define ON_BLOCK_EXIT_OBJ ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) =
MakeObjGuard
#endif
#endif //LOKI_SCOPEGUARD_H_ #endif //LOKI_SCOPEGUARD_H_
 End of changes. 2 change blocks. 
11 lines changed or deleted 8 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 "nonce.h" #include "mongo/db/authlevel.h"
#include "concurrency.h" #include "mongo/db/nonce.h"
#include "security_common.h" #include "mongo/db/security_common.h"
#include "../util/concurrency/spin_lock.h" #include "mongo/util/concurrency/spin_lock.h"
// this is used by both mongos and mongod // this is used by both mongos and mongod
namespace mongo { namespace mongo {
/* /** An AuthenticationInfo object is present within every mongo::Client
* for a particular db object */
* levels
* 0 : none
* 1 : read
* 2 : write
*/
struct Auth {
enum Level { NONE = 0 , READ = 1 , WRITE = 2 };
Auth() { level = NONE; }
Level level;
string user;
};
class AuthenticationInfo : boost::noncopyable { class AuthenticationInfo : boost::noncopyable {
bool _isLocalHost;
bool _isLocalHostAndLocalHostIsAuthorizedForAll;
public: public:
bool isLocalHost; void startRequest(); // need to call at the beginning of each reque
st
AuthenticationInfo(){ isLocalHost = false; } void setIsALocalHostConnectionWithSpecialAuthPowers(); // called, i
f localhost, when conneciton established.
AuthenticationInfo() {
_isLocalHost = false;
_isLocalHostAndLocalHostIsAuthorizedForAll = false;
}
~AuthenticationInfo() {} ~AuthenticationInfo() {}
bool isLocalHost() const { return _isLocalHost; } // why are you ca lling this? makes no sense to be externalized
// -- modifiers ---- // -- modifiers ----
void logout(const string& dbname ) { void logout(const string& dbname ) {
scoped_spinlock lk(_lock); scoped_spinlock lk(_lock);
_dbs.erase(dbname); _dbs.erase(dbname);
} }
void authorize(const string& dbname , const string& user ) { void authorize(const string& dbname , const string& user ) {
scoped_spinlock lk(_lock); scoped_spinlock lk(_lock);
_dbs[dbname].level = Auth::WRITE; _dbs[dbname].level = Auth::WRITE;
skipping to change at line 95 skipping to change at line 86
} }
bool isAuthorizedForLevel( const string& dbname , Auth::Level level ) const { bool isAuthorizedForLevel( const string& dbname , Auth::Level level ) const {
return _isAuthorized( dbname , level ); return _isAuthorized( dbname , level );
} }
string getUser( const string& dbname ) const; string getUser( const string& dbname ) const;
void print() const; void print() const;
protected: private:
void _checkLocalHostSpecialAdmin();
/** takes a lock */ /** takes a lock */
bool _isAuthorized(const string& dbname, Auth::Level level) const; bool _isAuthorized(const string& dbname, Auth::Level level) const;
bool _isAuthorizedSingle_inlock(const string& dbname, Auth::Level l evel) const; bool _isAuthorizedSingle_inlock(const string& dbname, Auth::Level l evel) const;
/** cannot call this locked */ /** cannot call this locked */
bool _isAuthorizedSpecialChecks( const string& dbname ) const ; bool _isAuthorizedSpecialChecks( const string& dbname ) const ;
private: private:
// while most access to _dbs is from our thread (the TLS thread), c
urrentOp() inspects
// it too thus we need this
mutable SpinLock _lock; mutable SpinLock _lock;
// todo: caching should not last forever
typedef map<string,Auth> MA; typedef map<string,Auth> MA;
MA _dbs; // dbname -> auth MA _dbs; // dbname -> auth
static bool _warned; static bool _warned;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 8 change blocks. 
24 lines changed or deleted 24 lines changed or added


 security_common.h   security_common.h 
skipping to change at line 22 skipping to change at line 22
* 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 "commands.h" #include "commands.h"
#include "concurrency.h"
#include "../util/concurrency/spin_lock.h" #include "../util/concurrency/spin_lock.h"
namespace mongo { namespace mongo {
/** /**
* Internal secret key info. * Internal secret key info.
*/ */
struct AuthInfo { struct AuthInfo {
AuthInfo() { AuthInfo() {
user = "__system"; user = "__system";
 End of changes. 1 change blocks. 
1 lines changed or deleted 0 lines changed or added


 shard.h   shard.h 
skipping to change at line 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 "../pch.h" #include "pch.h"
#include "../client/connpool.h"
#include "mongo/client/connpool.h"
#include "mongo/client/dbclient_rs.h"
namespace mongo { namespace mongo {
class ShardConnection; class ShardConnection;
class ShardStatus; class ShardStatus;
/* /*
* A "shard" one partition of the overall database (and a replica set t ypically). * A "shard" one partition of the overall database (and a replica set t ypically).
*/ */
skipping to change at line 74 skipping to change at line 76
/** /**
* @param ident either name or address * @param ident either name or address
*/ */
void reset( const string& ident ); void reset( const string& ident );
void setAddress( const ConnectionString& cs ); void setAddress( const ConnectionString& cs );
ConnectionString getAddress() const { return _cs; } ConnectionString getAddress() const { return _cs; }
string getName() const { string getName() const {
assert( _name.size() ); verify( _name.size() );
return _name; return _name;
} }
string getConnString() const { string getConnString() const {
assert( _addr.size() ); verify( _addr.size() );
return _addr; return _addr;
} }
long long getMaxSize() const { long long getMaxSize() const {
return _maxSize; return _maxSize;
} }
bool isDraining() const { bool isDraining() const {
return _isDraining; return _isDraining;
} }
skipping to change at line 103 skipping to change at line 105
} }
friend ostream& operator << (ostream& out, const Shard& s) { friend ostream& operator << (ostream& out, const Shard& s) {
return (out << s.toString()); return (out << s.toString());
} }
bool operator==( const Shard& s ) const { bool operator==( const Shard& s ) const {
bool n = _name == s._name; bool n = _name == s._name;
bool a = _addr == s._addr; bool a = _addr == s._addr;
assert( n == a ); // names and address are 1 to 1 verify( n == a ); // names and address are 1 to 1
return n; return n;
} }
bool operator!=( const Shard& s ) const { bool operator!=( const Shard& s ) const {
bool n = _name == s._name; bool n = _name == s._name;
bool a = _addr == s._addr; bool a = _addr == s._addr;
return ! ( n && a ); return ! ( n && a );
} }
bool operator==( const string& s ) const { bool operator==( const string& s ) const {
skipping to change at line 227 skipping to change at line 229
ShardConnection( const Shard& s , const string& ns, ChunkManagerPtr manager = ChunkManagerPtr() ); ShardConnection( const Shard& s , const string& ns, ChunkManagerPtr manager = ChunkManagerPtr() );
ShardConnection( const string& addr , const string& ns, ChunkManage rPtr manager = ChunkManagerPtr() ); ShardConnection( const string& addr , const string& ns, ChunkManage rPtr manager = ChunkManagerPtr() );
~ShardConnection(); ~ShardConnection();
void done(); void done();
void kill(); void kill();
DBClientBase& conn() { DBClientBase& conn() {
_finishInit(); _finishInit();
assert( _conn ); verify( _conn );
return *_conn; return *_conn;
} }
DBClientBase* operator->() { DBClientBase* operator->() {
_finishInit(); _finishInit();
assert( _conn ); verify( _conn );
return _conn; return _conn;
} }
DBClientBase* get() { DBClientBase* get() {
_finishInit(); _finishInit();
assert( _conn ); verify( _conn );
return _conn; return _conn;
} }
string getHost() const { string getHost() const {
return _addr; return _addr;
} }
string getNS() const { string getNS() const {
return _ns; return _ns;
} }
 End of changes. 7 change blocks. 
8 lines changed or deleted 10 lines changed or added


 shardkey.h   shardkey.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 "../client/dbclient.h"
namespace mongo { namespace mongo {
class Chunk; class Chunk;
/* A ShardKeyPattern is a pattern indicating what data to extract from the object to make the shard key from. /* A ShardKeyPattern is a pattern indicating what data to extract from the object to make the shard key from.
Analogous to an index key pattern. Analogous to an index key pattern.
*/ */
class ShardKeyPattern { class ShardKeyPattern {
public: public:
ShardKeyPattern( BSONObj p = BSONObj() ); ShardKeyPattern( BSONObj p = BSONObj() );
skipping to change at line 68 skipping to change at line 66
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 ) const; int compare( const BSONObj& l , const BSONObj& r ) const;
/** /**
@return whether or not obj has all fields in this shard key patt ern @return whether or not obj has all fields in this shard key patt ern
e.g. e.g.
ShardKey({num:1}).hasShardKey({ name:"joe", num:3 }) is true ShardKey({num:1}).hasShardKey({ name:"joe", num:3 }) is true
ShardKey({"a.b":1}).hasShardKey({ "a.b":"joe"}) is true
ShardKey({"a.b":1}).hasShardKey({ "a": {"b":"joe"}}) is true
ShardKey({num:1}).hasShardKey({ name:"joe"}) is false
ShardKey({num:1}).hasShardKey({ name:"joe", num:{$gt:3} }) is
false
see unit test for more examples
*/ */
bool hasShardKey( const BSONObj& obj ) const; bool hasShardKey( const BSONObj& obj ) const;
BSONObj key() const { return pattern; } BSONObj key() const { return pattern; }
string toString() const; string toString() const;
BSONObj extractKey(const BSONObj& from) const; BSONObj extractKey(const BSONObj& from) const;
bool partOfShardKey(const char* key ) const { bool partOfShardKey(const char* key ) const {
 End of changes. 2 change blocks. 
2 lines changed or deleted 8 lines changed or added


 signal_handlers.h   signal_handlers.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 "../pch.h"
namespace mongo { namespace mongo {
/** /**
* Obtains the log file handler and writes the current thread's stack t race to * Obtains the log file handler and writes the current thread's stack t race to
* it. This call issues an exit(). The function can safely be called fr om within a * it. This call issues an exit(). The function can safely be called fr om within a
* signal handler. * signal handler.
* *
* @param signal that this hadler is called for * @param signal that this hadler is called for
*/ */
void printStackAndExit( int signalNum ); void printStackAndExit( int signalNum );
 End of changes. 1 change blocks. 
2 lines changed or deleted 0 lines changed or added


 sock.h   sock.h 
skipping to change at line 174 skipping to change at line 174
bool _client; bool _client;
SSL_CTX* _context; SSL_CTX* _context;
string _password; string _password;
}; };
#endif #endif
/** /**
* thin wrapped around file descriptor and system calls * thin wrapped around file descriptor and system calls
* todo: ssl * todo: ssl
*/ */
class Socket { class Socket : boost::noncopyable {
public: public:
Socket(int sock, const SockAddr& farEnd); Socket(int sock, const SockAddr& farEnd);
/** In some cases the timeout will actually be 2x this value - eg w e do a partial send, /** In some cases the timeout will actually be 2x this value - eg w e do a partial send,
then the timeout fires, then we try to send again, then the tim eout fires again with then the timeout fires, then we try to send again, then the tim eout fires again with
no data sent, then we detect that the other side is down. no data sent, then we detect that the other side is down.
Generally you don't want a timeout, you should be very prepared for errors if you set one. Generally you don't want a timeout, you should be very prepared for errors if you set one.
*/ */
Socket(double so_timeout = 0, int logLevel = 0 ); Socket(double so_timeout = 0, int logLevel = 0 );
~Socket() {
close();
}
bool connect(SockAddr& farEnd); bool connect(SockAddr& farEnd);
void close(); void close();
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 ); 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 );
skipping to change at line 248 skipping to change at line 252
SockAddr _remote; SockAddr _remote;
double _timeout; double _timeout;
long long _bytesIn; long long _bytesIn;
long long _bytesOut; long long _bytesOut;
#ifdef MONGO_SSL #ifdef MONGO_SSL
SSL* _ssl; SSL* _ssl;
SSLManager * _sslAccepted; SSLManager * _sslAccepted;
#endif #endif
protected:
int _logLevel; // passed to log() when logging errors int _logLevel; // passed to log() when logging errors
}; };
} // namespace mongo } // namespace mongo
 End of changes. 3 change blocks. 
3 lines changed or deleted 5 lines changed or added


 spin_lock.h   spin_lock.h 
skipping to change at line 20 skipping to change at line 20
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#ifdef _WIN32
#include <windows.h>
#endif
#include "mutex.h" #include "mutex.h"
namespace mongo { namespace mongo {
/** /**
* The spinlock currently requires late GCC support routines to be effi cient. * The spinlock currently requires late GCC support routines to be effi cient.
* Other platforms default to a mutex implemenation. * Other platforms default to a mutex implemenation.
*/ */
class SpinLock : boost::noncopyable { class SpinLock : boost::noncopyable {
skipping to change at line 48 skipping to change at line 51
CRITICAL_SECTION _cs; CRITICAL_SECTION _cs;
public: public:
void lock() {EnterCriticalSection(&_cs); } void lock() {EnterCriticalSection(&_cs); }
void unlock() { LeaveCriticalSection(&_cs); } void unlock() { LeaveCriticalSection(&_cs); }
#elif defined(__USE_XOPEN2K) #elif defined(__USE_XOPEN2K)
pthread_spinlock_t _lock; pthread_spinlock_t _lock;
void _lk(); void _lk();
public: public:
void unlock() { pthread_spin_unlock(&_lock); } void unlock() { pthread_spin_unlock(&_lock); }
void lock() { void lock() {
if ( pthread_spin_trylock( &_lock ) == 0 ) if ( MONGO_likely( pthread_spin_trylock( &_lock ) == 0 ) )
return; return;
_lk(); _lk();
} }
#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
volatile bool _locked; volatile bool _locked;
public: public:
void unlock() {__sync_lock_release(&_locked); } void unlock() {__sync_lock_release(&_locked); }
void lock(); void lock();
#else #else
// default to a mutex if not implemented // default to a mutex if not implemented
 End of changes. 2 change blocks. 
1 lines changed or deleted 4 lines changed or added


 strategy.h   strategy.h 
skipping to change at line 42 skipping to change at line 42
virtual void writeOp( int op , Request& r ) = 0; virtual void writeOp( int op , Request& r ) = 0;
void insert( const Shard& shard , const char * ns , const BSONObj& obj , int flags=0 , bool safe=false ); void insert( const Shard& shard , const char * ns , const BSONObj& obj , int flags=0 , bool safe=false );
virtual void commandOp( const string& db, const BSONObj& command, i nt options, virtual void commandOp( const string& db, const BSONObj& command, i nt options,
const string& versionedNS, const BSONObj& f ilter, const string& versionedNS, const BSONObj& f ilter,
map<Shard,BSONObj>& results ) map<Shard,BSONObj>& results )
{ {
// Only call this from sharded, for now. // Only call this from sharded, for now.
// TODO: Refactor all this. // TODO: Refactor all this.
assert( false ); verify( false );
} }
// These interfaces will merge soon, so make it easy to share logic
friend class ShardStrategy;
friend class SingleStrategy;
protected: protected:
void doWrite( int op , Request& r , const Shard& shard , bool check Version = true ); void doWrite( int op , Request& r , const Shard& shard , bool check Version = true );
void doQuery( Request& r , const Shard& shard ); void doQuery( Request& r , const Shard& shard );
void broadcastWrite(int op, Request& r); // Sends to all shards in cluster. DOESN'T CHECK VERSION
void insert( const Shard& shard , const char * ns , const vector<BS ONObj>& v , int flags=0 , bool safe=false ); void insert( const Shard& shard , const char * ns , const vector<BS ONObj>& v , int flags=0 , bool safe=false );
void update( const Shard& shard , const char * ns , const BSONObj& query , const BSONObj& toupdate , int flags=0, bool safe=false ); void update( const Shard& shard , const char * ns , const BSONObj& query , const BSONObj& toupdate , int flags=0, bool safe=false );
}; };
extern Strategy * SINGLE; extern Strategy * SINGLE;
extern Strategy * SHARDED; extern Strategy * SHARDED;
} }
 End of changes. 3 change blocks. 
1 lines changed or deleted 6 lines changed or added


 stringdata.h   stringdata.h 
skipping to change at line 45 skipping to change at line 45
class StringData { class StringData {
public: public:
/** Construct a StringData, for the case where the length of /** Construct a StringData, for the case where the length of
* string is not known. 'c' must be a pointer to a null-terminated string. * string is not known. 'c' must be a pointer to a null-terminated string.
*/ */
StringData( const char* c ) StringData( const char* c )
: _data(c), _size((unsigned) strlen(c)) {} : _data(c), _size((unsigned) strlen(c)) {}
/** Construct a StringData explicitly, for the case where the lengt h of the string /** Construct a StringData explicitly, for the case where the lengt h of the string
* is already known. 'c' must be a pointer to a null-terminated str ing, and strlenOfc * is already known. 'c' must be a pointer to a null-terminated str ing, and strlenOfc
* must be the length that std::strlen(c) would return, a.k.a the i ndex of the * must be the length that strlen(c) would return, a.k.a the index of the
* terminator in c. * terminator in c.
*/ */
StringData( const char* c, unsigned len ) StringData( const char* c, unsigned len )
: _data(c), _size(len) {} : _data(c), _size(len) {}
/** Construct a StringData, for the case of a std::string. */ /** Construct a StringData, for the case of a string. */
StringData( const string& s ) StringData( const std::string& s )
: _data(s.c_str()), _size((unsigned) s.size()) {} : _data(s.c_str()), _size((unsigned) s.size()) {}
// Construct a StringData explicitly, for the case of a literal who se size is // Construct a StringData explicitly, for the case of a literal who se size is
// known at compile time. // known at compile time.
struct LiteralTag {}; struct LiteralTag {};
template<size_t N> template<size_t N>
StringData( const char (&val)[N], LiteralTag ) StringData( const char (&val)[N], LiteralTag )
: _data(&val[0]), _size(N-1) {} : _data(&val[0]), _size(N-1) {}
// accessors // accessors
 End of changes. 2 change blocks. 
3 lines changed or deleted 3 lines changed or added


 stringutils.h   stringutils.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 <string>
#include <vector>
#include <boost/scoped_array.hpp>
namespace mongo { namespace mongo {
// see also mongoutils/str.h - perhaps move these there? // see also mongoutils/str.h - perhaps move these there?
// see also text.h // see also text.h
void splitStringDelim( const string& str , vector<string>* res , char d elim ); void splitStringDelim( const string& str , std::vector<std::string>* re s , char delim );
void joinStringDelim( const vector<string>& strs , string* res , char d elim ); void joinStringDelim( const std::vector<std::string>& strs , std::strin g* res , char delim );
inline string tolowerString( const string& input ) { inline std::string tolowerString( const std::string& input ) {
string::size_type sz = input.size(); std::string::size_type sz = input.size();
boost::scoped_array<char> line(new char[sz+1]); boost::scoped_array<char> line(new char[sz+1]);
char * copy = line.get(); char * copy = line.get();
for ( string::size_type i=0; i<sz; i++ ) { for ( std::string::size_type i=0; i<sz; i++ ) {
char c = input[i]; char c = input[i];
copy[i] = (char)tolower( (int)c ); copy[i] = (char)tolower( (int)c );
} }
copy[sz] = 0; copy[sz] = 0;
return string(copy); return copy;
} }
/** /** Functor for combining lexical and numeric comparisons. */
* Non numeric characters are compared lexicographically; numeric subst class LexNumCmp {
rings public:
* are compared numerically; dots separate ordered comparable subunits. /** @param lexOnly - compare all characters lexically, including di
* For convenience, character 255 is greater than anything else. gits. */
*/ LexNumCmp( bool lexOnly );
inline int lexNumCmp( const char *s1, const char *s2 ) { /**
//cout << "START : " << s1 << "\t" << s2 << endl; * Non numeric characters are compared lexicographically; numeric s
ubstrings
bool startWord = true; * are compared numerically; dots separate ordered comparable subun
its.
while( *s1 && *s2 ) { * For convenience, character 255 is greater than anything else.
* @param lexOnly - compare all characters lexically, including dig
bool d1 = ( *s1 == '.' ); its.
bool d2 = ( *s2 == '.' ); */
if ( d1 && !d2 ) static int cmp( const char *s1, const char *s2, bool lexOnly );
return -1; int cmp( const char *s1, const char *s2 ) const;
if ( d2 && !d1 ) bool operator()( const char *s1, const char *s2 ) const;
return 1; bool operator()( const std::string &s1, const std::string &s2 ) con
if ( d1 && d2 ) { st;
++s1; ++s2; private:
startWord = true; bool _lexOnly;
continue; };
}
bool p1 = ( *s1 == (char)255 );
bool p2 = ( *s2 == (char)255 );
//cout << "\t\t " << p1 << "\t" << p2 << endl;
if ( p1 && !p2 )
return 1;
if ( p2 && !p1 )
return -1;
bool n1 = isNumber( *s1 );
bool n2 = isNumber( *s2 );
if ( n1 && n2 ) {
// get rid of leading 0s
if ( startWord ) {
while ( *s1 == '0' ) s1++;
while ( *s2 == '0' ) s2++;
}
char * e1 = (char*)s1;
char * e2 = (char*)s2;
// find length
// if end of string, will break immediately ('\0')
while ( isNumber (*e1) ) e1++;
while ( isNumber (*e2) ) e2++;
int len1 = (int)(e1-s1);
int len2 = (int)(e2-s2);
int result;
// if one is longer than the other, return
if ( len1 > len2 ) {
return 1;
}
else if ( len2 > len1 ) {
return -1;
}
// if the lengths are equal, just strcmp
else if ( (result = strncmp(s1, s2, len1)) != 0 ) {
return result;
}
// otherwise, the numbers are equal
s1 = e1;
s2 = e2;
startWord = false;
continue;
}
if ( n1 )
return 1;
if ( n2 )
return -1;
if ( *s1 > *s2 )
return 1;
if ( *s2 > *s1 )
return -1;
s1++; s2++;
startWord = false;
}
if ( *s1 )
return 1;
if ( *s2 )
return -1;
return 0;
}
} // namespace mongo } // namespace mongo
 End of changes. 7 change blocks. 
102 lines changed or deleted 34 lines changed or added


 syncclusterconnection.h   syncclusterconnection.h 
skipping to change at line 21 skipping to change at line 21
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "../pch.h" #include "mongo/bson/bsonelement.h"
#include "dbclient.h" #include "mongo/bson/bsonobj.h"
#include "redef_macros.h" #include "mongo/client/dbclientinterface.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 * 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 * 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, * rollback if a problem occurs during the second phase. Naturally, wi th all these fsyncs,
* these operations will be quite slow -- use sparingly. * these operations will be quite slow -- use sparingly.
* *
* Read operations are sent to a single random node. * 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 * 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. * 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:
using DBClientBase::query;
/** /**
* @param commaSeparated should be 3 hosts comma separated * @param commaSeparated should be 3 hosts comma separated
*/ */
SyncClusterConnection( const list<HostAndPort> &, double socketTime out = 0); SyncClusterConnection( const list<HostAndPort> &, double socketTime out = 0);
SyncClusterConnection( string commaSeparated, double socketTimeout = 0); SyncClusterConnection( string commaSeparated, double socketTimeout = 0);
SyncClusterConnection( string a , string b , string c, double socke tTimeout = 0 ); SyncClusterConnection( string a , string b , string c, double socke tTimeout = 0 );
~SyncClusterConnection(); ~SyncClusterConnection();
/** /**
* @return true if all servers are up and ready for writes * @return true if all servers are up and ready for writes
skipping to change at line 125 skipping to change at line 128
vector<BSONObj> _lastErrors; vector<BSONObj> _lastErrors;
double _socketTimeout; double _socketTimeout;
}; };
class UpdateNotTheSame : public UserException { class UpdateNotTheSame : public UserException {
public: public:
UpdateNotTheSame( int code , const string& msg , const vector<strin g>& addrs , const vector<BSONObj>& lastErrors ) UpdateNotTheSame( int code , const string& msg , const vector<strin g>& addrs , const vector<BSONObj>& lastErrors )
: UserException( code , msg ) , _addrs( addrs ) , _lastErrors( lastErrors ) { : UserException( code , msg ) , _addrs( addrs ) , _lastErrors( lastErrors ) {
assert( _addrs.size() == _lastErrors.size() ); verify( _addrs.size() == _lastErrors.size() );
} }
virtual ~UpdateNotTheSame() throw() { virtual ~UpdateNotTheSame() throw() {
} }
unsigned size() const { unsigned size() const {
return _addrs.size(); return _addrs.size();
} }
pair<string,BSONObj> operator[](unsigned i) const { pair<string,BSONObj> operator[](unsigned i) const {
return make_pair( _addrs[i] , _lastErrors[i] ); return make_pair( _addrs[i] , _lastErrors[i] );
} }
private: private:
vector<string> _addrs; vector<string> _addrs;
vector<BSONObj> _lastErrors; vector<BSONObj> _lastErrors;
}; };
}; };
#include "undef_macros.h"
 End of changes. 4 change blocks. 
4 lines changed or deleted 7 lines changed or added


 task.h   task.h 
skipping to change at line 32 skipping to change at line 32
namespace mongo { namespace mongo {
namespace task { namespace task {
/** abstraction around threads. simpler than BackgroundJob which i s used behind the scenes. /** abstraction around threads. simpler than BackgroundJob which i s used behind the scenes.
allocate the Task dynamically. when the thread terminates, the Task object will delete itself. allocate the Task dynamically. when the thread terminates, the Task object will delete itself.
*/ */
class Task : private BackgroundJob { class Task : private BackgroundJob {
protected: protected:
virtual void setUp(); // Override to perform any do-once work for the task.
virtual void doWork() = 0; // implement the ta sk here. virtual void doWork() = 0; // implement the ta sk here.
virtual string name() const = 0; // name the threada virtual string name() const = 0; // name the thread
public: public:
Task(); Task();
/** for a repeating task, stop after current invocation ends. c an be called by other threads /** for a repeating task, stop after current invocation ends. c an be called by other threads
as long as the Task is still in scope. as long as the Task is still in scope.
*/ */
void halt(); void halt();
private: private:
unsigned n, repeat; unsigned n, repeat;
friend void fork(Task* t); friend void fork(Task* t);
 End of changes. 2 change blocks. 
1 lines changed or deleted 2 lines changed or added


 taskqueue.h   taskqueue.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/>.
*/ */
#pragma once #pragma once
#include "mongomutex.h" #include "mongomutex.h"
// if you turn this back on be sure to enable TaskQueueTest again
#if 0
namespace mongo { namespace mongo {
/** defer work items by queueing them for invocation by another thread. presumption is that /** defer work items by queueing them for invocation by another thread. presumption is that
consumer thread is outside of locks more than the source thread. A dditional presumption consumer thread is outside of locks more than the source thread. A dditional presumption
is that several objects or micro-tasks will be queued and that havi ng a single thread is that several objects or micro-tasks will be queued and that havi ng a single thread
processing them in batch is hepful as they (in the first use case) use a common data processing them in batch is hepful as they (in the first use case) use a common data
structure that can then be in local cpu classes. structure that can then be in local cpu classes.
this class is in db/ as it is dbMutex (mongomutex) specific (so far ). this class is in db/ as it is dbMutex (mongomutex) specific (so far ).
skipping to change at line 49 skipping to change at line 52
see DefInvoke in dbtests/ for an example. see DefInvoke in dbtests/ for an example.
*/ */
template< class MT > template< class MT >
class TaskQueue { class TaskQueue {
public: public:
TaskQueue() : _which(0), _invokeMutex("deferredinvoker") { } TaskQueue() : _which(0), _invokeMutex("deferredinvoker") { }
void defer(MT mt) { void defer(MT mt) {
// only one writer allowed. however the invoke processing belo w can occur concurrently with // only one writer allowed. however the invoke processing belo w can occur concurrently with
// writes (for the most part) // writes (for the most part)
DEV d.dbMutex.assertWriteLocked(); DEV verify( Lock::isW() );
_queues[_which].push_back(mt); _queues[_which].push_back(mt);
} }
/** call to process deferrals. /** call to process deferrals.
concurrency: handled herein. multiple threads could call invok e(), but their efforts will be concurrency: handled herein. multiple threads could call invok e(), but their efforts will be
serialized. the common case is that there is a si ngle processor calling invoke(). serialized. the common case is that there is a si ngle processor calling invoke().
normally, you call this outside of any lock. but if you want t o fully drain the queue, normally, you call this outside of any lock. but if you want t o fully drain the queue,
skipping to change at line 75 skipping to change at line 78
d.invoke(); d.invoke();
... ...
} }
you can also call invoke periodically to do some work and then pick up later on more. you can also call invoke periodically to do some work and then pick up later on more.
*/ */
void invoke() { void invoke() {
mutex::scoped_lock lk2(_invokeMutex); mutex::scoped_lock lk2(_invokeMutex);
int toDrain = 0; int toDrain = 0;
{ {
// flip queueing to the other queue (we are double buffered ) // flip queueing to the other queue (we are double buffered )
readlocktry lk("", 5); readlocktry lk(5);
if( !lk.got() ) if( !lk.got() )
return; return;
toDrain = _which; toDrain = _which;
_which = _which ^ 1; _which = _which ^ 1;
wassert( _queues[_which].empty() ); // we are in dbMutex, s o it should be/stay empty til we exit dbMutex wassert( _queues[_which].empty() ); // we are in dbMutex, s o it should be/stay empty til we exit dbMutex
} }
_drain( _queues[toDrain] ); _drain( _queues[toDrain] );
assert( _queues[toDrain].empty() ); verify( _queues[toDrain].empty() );
} }
private: private:
int _which; // 0 or 1 int _which; // 0 or 1
typedef vector< MT > Queue; typedef vector< MT > Queue;
Queue _queues[2]; Queue _queues[2];
// lock order when multiple locks: dbMutex, _invokeMutex // lock order when multiple locks: dbMutex, _invokeMutex
mongo::mutex _invokeMutex; mongo::mutex _invokeMutex;
void _drain(Queue& queue) { void _drain(Queue& queue) {
unsigned oldCap = queue.capacity(); unsigned oldCap = queue.capacity();
for( typename Queue::iterator i = queue.begin(); i != queue.end (); i++ ) { for( typename Queue::iterator i = queue.begin(); i != queue.end (); i++ ) {
const MT& v = *i; const MT& v = *i;
MT::go(v); MT::go(v);
} }
queue.clear(); queue.clear();
DEV assert( queue.capacity() == oldCap ); // just checking that clear() doesn't deallocate, we don't want that DEV verify( queue.capacity() == oldCap ); // just checking that clear() doesn't deallocate, we don't want that
} }
}; };
} }
#endif
 End of changes. 6 change blocks. 
4 lines changed or deleted 7 lines changed or added


 text.h   text.h 
skipping to change at line 148 skipping to change at line 148
endLen = 0; endLen = 0;
} }
uassert( 13306, "could not convert string to long long", endLen != 0 && n[ endLen ] == 0 ); uassert( 13306, "could not convert string to long long", endLen != 0 && n[ endLen ] == 0 );
#else // stoll() wasn't introduced until VS 2010. #else // stoll() wasn't introduced until VS 2010.
char* endPtr = 0; char* endPtr = 0;
ret = _strtoi64( n, &endPtr, 10 ); ret = _strtoi64( n, &endPtr, 10 );
uassert( 13310, "could not convert string to long long", (*endPtr = = 0) && (ret != _I64_MAX) && (ret != _I64_MIN) ); uassert( 13310, "could not convert string to long long", (*endPtr = = 0) && (ret != _I64_MAX) && (ret != _I64_MIN) );
#endif // !defined(_WIN32) #endif // !defined(_WIN32)
return ret; return ret;
} }
}
#if defined(_WIN32)
class WindowsCommandLine {
char** _argv;
public:
WindowsCommandLine( int argc, wchar_t* argvW[] );
~WindowsCommandLine();
char** argv( void ) const { return _argv; };
};
#endif // #if defined(_WIN32)
} // namespace mongo
 End of changes. 1 change blocks. 
0 lines changed or deleted 0 lines changed or added


 thread_pool.h   thread_pool.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/function.hpp> #include <list>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#undef assert #include <boost/function.hpp>
#define assert MONGO_assert #include <boost/thread/condition.hpp>
namespace mongo { namespace mongo {
namespace threadpool { namespace threadpool {
class Worker; class Worker;
typedef boost::function<void(void)> Task; //nullary function or fun ctor typedef boost::function<void(void)> Task; //nullary function or fun ctor
// exported to the mongo namespace // exported to the mongo namespace
class ThreadPool : boost::noncopyable { class ThreadPool : boost::noncopyable {
skipping to change at line 68 skipping to change at line 69
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, typena me D, typename E> template<typename F, typename A, typename B, typename C, typena me D, typename E>
void schedule(F f, A a, B b, C c, D d, E e) { schedule(boost::b ind(f,a,b,c,d,e)); } void schedule(F f, A a, B b, C c, D d, E e) { schedule(boost::b ind(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) std::list<Worker*> _freeWorkers; //used as LIFO stack (always f
list<Task> _tasks; //used as FIFO queue (push_back, pop_front) ront)
std::list<Task> _tasks; //used as FIFO queue (push_back, pop_fr
ont)
int _tasksRemaining; // in queue + currently processing int _tasksRemaining; // in queue + currently processing
int _nThreads; // only used for sanity checking. could be remov ed in the future. int _nThreads; // only used for sanity checking. could be remov ed in 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);
friend class Worker; friend class Worker;
}; };
} //namespace threadpool } //namespace threadpool
 End of changes. 3 change blocks. 
5 lines changed or deleted 8 lines changed or added


 threadlocal.h   threadlocal.h 
skipping to change at line 19 skipping to change at line 19
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "mongo/client/undef_macros.h"
#include <boost/thread/tss.hpp> #include <boost/thread/tss.hpp>
#include "mongo/client/redef_macros.h"
namespace mongo { namespace mongo {
using boost::thread_specific_ptr; using boost::thread_specific_ptr;
/* thread local "value" rather than a pointer /* thread local "value" rather than a pointer
good for things which have copy constructors (and the copy construct or is fast enough) good for things which have copy constructors (and the copy construct or is fast enough)
e.g. e.g.
ThreadLocalValue<int> myint; ThreadLocalValue<int> myint;
*/ */
skipping to change at line 81 skipping to change at line 83
get's are fast. get's are fast.
*/ */
#if defined(_WIN32) || (defined(__GNUC__) && defined(__linux__)) #if defined(_WIN32) || (defined(__GNUC__) && defined(__linux__))
template< class T > template< class T >
struct TSP { struct TSP {
boost::thread_specific_ptr<T> tsp; boost::thread_specific_ptr<T> tsp;
public: public:
T* get() const; T* get() const;
void reset(T* v); void reset(T* v);
T* getMake() {
T *t = get();
if( t == 0 )
reset( t = new T() );
return t;
}
}; };
# if defined(_WIN32) # if defined(_WIN32)
# define TSP_DECLARE(T,p) extern TSP<T> p; # define TSP_DECLARE(T,p) extern TSP<T> p;
# define TSP_DEFINE(T,p) __declspec( thread ) T* _ ## p; \ # define TSP_DEFINE(T,p) __declspec( thread ) T* _ ## p; \
TSP<T> p; \ TSP<T> p; \
template<> T* TSP<T>::get() const { return _ ## p; } \ template<> T* TSP<T>::get() const { return _ ## p; } \
void TSP<T>::reset(T* v) { \ void TSP<T>::reset(T* v) { \
skipping to change at line 118 skipping to change at line 126
# endif # endif
#else #else
template< class T > template< class T >
struct TSP { struct TSP {
thread_specific_ptr<T> tsp; thread_specific_ptr<T> tsp;
public: public:
T* get() const { return tsp.get(); } T* get() const { return tsp.get(); }
void reset(T* v) { tsp.reset(v); } void reset(T* v) { tsp.reset(v); }
T* getMake() {
T *t = get();
if( t == 0 )
reset( t = new T() );
return t;
}
}; };
# define TSP_DECLARE(T,p) extern TSP<T> p; # define TSP_DECLARE(T,p) extern TSP<T> p;
# define TSP_DEFINE(T,p) TSP<T> p; # define TSP_DEFINE(T,p) TSP<T> p;
#endif #endif
} }
 End of changes. 4 change blocks. 
0 lines changed or deleted 14 lines changed or added


 time_support.h   time_support.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 "mongo/platform/basic.h"
#include <cstdio> // sscanf #include <cstdio> // sscanf
#include <ctime> #include <ctime>
#include <string>
#include <iostream>
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/thread/tss.hpp> #include <boost/thread/tss.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/xtime.hpp> #include <boost/thread/xtime.hpp>
#undef assert
#define assert MONGO_assert
#include "../bson/util/misc.h" // Date_t #include "../bson/util/misc.h" // Date_t
namespace mongo { namespace mongo {
using std::string;
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 54 skipping to change at line 58
} }
// uses ISO 8601 dates without trailing Z // uses ISO 8601 dates without trailing Z
// colonsOk should be false when creating filenames // colonsOk should be false when creating filenames
inline string terseCurrentTime(bool colonsOk=true) { inline string terseCurrentTime(bool colonsOk=true) {
struct tm t; struct tm t;
time_t_to_Struct( time(0) , &t ); time_t_to_Struct( time(0) , &t );
const char* fmt = (colonsOk ? "%Y-%m-%dT%H:%M:%S" : "%Y-%m-%dT%H-%M -%S"); const char* fmt = (colonsOk ? "%Y-%m-%dT%H:%M:%S" : "%Y-%m-%dT%H-%M -%S");
char buf[32]; char buf[32];
assert(strftime(buf, sizeof(buf), fmt, &t) == 19); verify(strftime(buf, sizeof(buf), fmt, &t) == 19);
return buf; return buf;
} }
inline string timeToISOString(time_t time) { inline string timeToISOString(time_t time) {
struct tm t; struct tm t;
time_t_to_Struct( time, &t ); time_t_to_Struct( time, &t );
const char* fmt = "%Y-%m-%dT%H:%M:%SZ"; const char* fmt = "%Y-%m-%dT%H:%M:%SZ";
char buf[32]; char buf[32];
assert(strftime(buf, sizeof(buf), fmt, &t) == 20); verify(strftime(buf, sizeof(buf), fmt, &t) == 20);
return buf; return buf;
} }
inline boost::gregorian::date currentDate() { inline boost::gregorian::date currentDate() {
boost::posix_time::ptime now = boost::posix_time::second_clock::loc al_time(); boost::posix_time::ptime now = boost::posix_time::second_clock::loc al_time();
return now.date(); return now.date();
} }
// parses time of day in "hh:mm" format assuming 'hh' is 00-23 // parses time of day in "hh:mm" format assuming 'hh' is 00-23
inline bool toPointInTime( const string& str , boost::posix_time::ptime * timeOfDay ) { inline bool toPointInTime( const string& str , boost::posix_time::ptime * timeOfDay ) {
skipping to change at line 91 skipping to change at line 95
// verify that time is well formed // verify that time is well formed
if ( ( hh / 24 ) || ( mm / 60 ) ) { if ( ( hh / 24 ) || ( mm / 60 ) ) {
return false; return false;
} }
boost::posix_time::ptime res( currentDate() , boost::posix_time::ho urs( hh ) + boost::posix_time::minutes( mm ) ); boost::posix_time::ptime res( currentDate() , boost::posix_time::ho urs( hh ) + boost::posix_time::minutes( mm ) );
*timeOfDay = res; *timeOfDay = res;
return true; return true;
} }
#define MONGO_asctime _asctime_not_threadsafe_
#define asctime MONGO_asctime
#define MONGO_gmtime _gmtime_not_threadsafe_
#define gmtime MONGO_gmtime
#define MONGO_localtime _localtime_not_threadsafe_
#define localtime MONGO_localtime
#define MONGO_ctime _ctime_is_not_threadsafe_
#define ctime MONGO_ctime
#if defined(_WIN32) #if defined(_WIN32)
inline void sleepsecs(int s) { inline void sleepsecs(int s) {
// todo : add an assert here that we are not locked in d.dbMutex. there may be debugging things where we // todo : add an assert here that we are not locked in d.dbMutex. there may be debugging things where we
// are but otherwise it's quite likely that would be a mista ke. // are but otherwise it's quite likely that would be a mista ke.
Sleep(s*1000); Sleep(s*1000);
} }
inline void sleepmillis(long long s) { inline void sleepmillis(long long s) {
assert( s <= 0xffffffff ); verify( s <= 0xffffffff );
Sleep((DWORD) s); Sleep((DWORD) s);
} }
inline void sleepmicros(long long 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 += (int)( s / 1000000 ); xt.sec += (int)( s / 1000000 );
xt.nsec += (int)(( s % 1000000 ) * 1000); xt.nsec += (int)(( s % 1000000 ) * 1000);
if ( xt.nsec >= 1000000000 ) { if ( xt.nsec >= 1000000000 ) {
skipping to change at line 160 skipping to change at line 155
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; std::cout << "nanosleep failed" << std::endl;
} }
} }
inline void sleepmicros(long long 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; std::cout << "nanosleep failed" << std::endl;
} }
} }
inline void sleepmillis(long long s) { inline void sleepmillis(long long s) {
sleepmicros( s * 1000 ); sleepmicros( s * 1000 );
} }
#endif #endif
extern long long jsTime_virtual_skew; extern long long jsTime_virtual_skew;
extern boost::thread_specific_ptr<long long> jsTime_virtual_thread_skew ; extern boost::thread_specific_ptr<long long> jsTime_virtual_thread_skew ;
skipping to change at line 258 skipping to change at line 253
return (((unsigned long long) tv.tv_sec) * 1000*1000) + tv.tv_usec; return (((unsigned long long) tv.tv_sec) * 1000*1000) + tv.tv_usec;
} }
inline unsigned curTimeMicros() { inline unsigned curTimeMicros() {
timeval tv; timeval tv;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
unsigned secs = tv.tv_sec % 1024; unsigned secs = tv.tv_sec % 1024;
return secs*1000*1000 + tv.tv_usec; return secs*1000*1000 + tv.tv_usec;
} }
#endif #endif
// these are so that if you use one of them compilation will fail
char *asctime(const struct tm *tm);
char *ctime(const time_t *timep);
struct tm *gmtime(const time_t *timep);
struct tm *localtime(const time_t *timep);
} // namespace mongo } // namespace mongo
 End of changes. 11 change blocks. 
16 lines changed or deleted 17 lines changed or added


 timer.h   timer.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 "time_support.h"
namespace mongo { namespace mongo {
#if !defined(_WIN32)
/** /**
* simple scoped timer * Time tracking object.
*
* Should be of reasonably high performance, though the implementations
are platform-specific.
* Each platform provides a distinct implementation of the now() method
, and sets the
* _countsPerSecond static field to the constant number of ticks per se
cond that now() counts
* in. The maximum span measurable by the counter and convertible to m
icroseconds is about 10
* trillion ticks. As long as there are fewer than 100 ticks per nanos
econd, timer durations of
* 2.5 years will be supported. Since a typical tick duration will be
under 10 per nanosecond,
* if not below 1 per nanosecond, this should not be an issue.
*/ */
class Timer /*copyable*/ { class Timer /*copyable*/ {
public: public:
static const unsigned long long millisPerSecond = 1000;
static const unsigned long long microsPerSecond = 1000 * millisPerS
econd;
static const unsigned long long nanosPerSecond = 1000 * microsPerSe
cond;
Timer() { reset(); } Timer() { reset(); }
int seconds() const { return (int)(micros() / 1000000); } int seconds() const { return (int)(micros() / 1000000); }
int millis() const { return (int)(micros() / 1000); } int millis() const { return (int)(micros() / 1000); }
int minutes() const { return seconds() / 60; } int minutes() const { return seconds() / 60; }
/** gets time interval and resets at the same time. this way we ca /** Get the time interval and reset at the same time.
n call curTimeMicros * @return time in milliseconds.
once instead of twice if one wanted millis() and then reset() */
. inline int millisReset() {
@return time in millis unsigned long long nextNow = now();
*/ unsigned long long deltaMicros =
int millisReset() { ((nextNow - _old) * microsPerSecond) / _countsPerSecond;
unsigned long long now = curTimeMicros64();
int m = (int)((now-old)/1000); _old = nextNow;
old = now; return static_cast<int>(deltaMicros / 1000);
return m; }
}
inline unsigned long long micros() const {
// note: dubious that the resolution is as anywhere near as high as return ((now() - _old) * microsPerSecond) / _countsPerSecond;
ethod name implies! }
unsigned long long micros() const {
unsigned long long n = curTimeMicros64(); inline void reset() { _old = now(); }
return n - old;
} /**
unsigned long long micros(unsigned long long & n) const { // return * Internally, the timer counts platform-dependent ticks of some so
s cur time in addition to timer result rt, and
n = curTimeMicros64(); * must then convert those ticks to microseconds and their ilk. Th
return n - old; is field
} * stores the frequency of the platform-dependent counter.
*
* This value is initialized at program startup, and never changed
after.
* It should be treated as private.
*/
static unsigned long long _countsPerSecond;
void reset() { old = curTimeMicros64(); }
private: private:
unsigned long long old; inline unsigned long long now() const;
};
#else unsigned long long _old;
class Timer /*copyable*/ {
public:
Timer() { reset(); }
int seconds() const {
int s = static_cast<int>((now() - old) / countsPerSecond);
return s;
}
int millis() const {
return (int)
((now() - old) * 1000.0 / countsPerSecond);
}
int minutes() const { return seconds() / 60; }
/** gets time interval and resets at the same time. this way we ca
n call curTimeMicros
once instead of twice if one wanted millis() and then reset()
.
@return time in millis
*/
int millisReset() {
unsigned long long nw = now();
int m = static_cast<int>((nw - old) * 1000.0 / countsPerSecond)
;
old = nw;
return m;
}
void reset() {
old = now();
}
unsigned long long micros() const {
return (unsigned long long)
((now() - old) * 1000000.0 / countsPerSecond);
}
static unsigned long long countsPerSecond;
private:
unsigned long long now() const {
LARGE_INTEGER i;
QueryPerformanceCounter(&i);
return i.QuadPart;
}
unsigned long long old;
}; };
#endif
} // namespace mongo } // namespace mongo
#include "mongo/util/timer-inl.h"
 End of changes. 10 change blocks. 
86 lines changed or deleted 53 lines changed or added


 tool.h   tool.h 
skipping to change at line 29 skipping to change at line 29
#pragma once #pragma once
#include <string> #include <string>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#if defined(_WIN32) #if defined(_WIN32)
#include <io.h> #include <io.h>
#endif #endif
#include "client/dbclient.h"
#include "db/instance.h" #include "db/instance.h"
#include "db/matcher.h" #include "db/matcher.h"
#include "db/security.h" #include "db/security.h"
using std::string; using std::string;
namespace mongo { namespace mongo {
class Tool { class Tool {
public: public:
 End of changes. 1 change blocks. 
1 lines changed or deleted 0 lines changed or added


 top.h   top.h 
skipping to change at line 21 skipping to change at line 21
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#undef 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") { } Top() : _lock("Top") { }
 End of changes. 1 change blocks. 
2 lines changed or deleted 0 lines changed or added


 ucp.h   ucp.h 
/************************************************* /*************************************************
* Unicode Property Table handler * * Unicode Property Table handler *
*************************************************/ *************************************************/
#ifndef _UCP_H #ifndef _UCP_H
#define _UCP_H #define _UCP_H
/* This file contains definitions of the property values that are returned by /* This file contains definitions of the property values that are returned by
the function _pcre_ucp_findprop(). New values that are added for new releas the UCD access macros. New values that are added for new releases of Unicod
es e
of Unicode should always be at the end of each enum, for backwards should always be at the end of each enum, for backwards compatibility. */
compatibility. */
/* These are the general character categories. */ /* These are the general character categories. */
enum { enum {
ucp_C, /* Other */ ucp_C, /* Other */
ucp_L, /* Letter */ ucp_L, /* Letter */
ucp_M, /* Mark */ ucp_M, /* Mark */
ucp_N, /* Number */ ucp_N, /* Number */
ucp_P, /* Punctuation */ ucp_P, /* Punctuation */
ucp_S, /* Symbol */ ucp_S, /* Symbol */
skipping to change at line 124 skipping to change at line 123
ucp_Tagbanwa, ucp_Tagbanwa,
ucp_Tai_Le, ucp_Tai_Le,
ucp_Tamil, ucp_Tamil,
ucp_Telugu, ucp_Telugu,
ucp_Thaana, ucp_Thaana,
ucp_Thai, ucp_Thai,
ucp_Tibetan, ucp_Tibetan,
ucp_Tifinagh, ucp_Tifinagh,
ucp_Ugaritic, ucp_Ugaritic,
ucp_Yi, ucp_Yi,
ucp_Balinese, /* New for Unicode 5.0.0 */ /* New for Unicode 5.0: */
ucp_Cuneiform, /* New for Unicode 5.0.0 */ ucp_Balinese,
ucp_Nko, /* New for Unicode 5.0.0 */ ucp_Cuneiform,
ucp_Phags_Pa, /* New for Unicode 5.0.0 */ ucp_Nko,
ucp_Phoenician /* New for Unicode 5.0.0 */ ucp_Phags_Pa,
ucp_Phoenician,
/* New for Unicode 5.1: */
ucp_Carian,
ucp_Cham,
ucp_Kayah_Li,
ucp_Lepcha,
ucp_Lycian,
ucp_Lydian,
ucp_Ol_Chiki,
ucp_Rejang,
ucp_Saurashtra,
ucp_Sundanese,
ucp_Vai,
/* New for Unicode 5.2: */
ucp_Avestan,
ucp_Bamum,
ucp_Egyptian_Hieroglyphs,
ucp_Imperial_Aramaic,
ucp_Inscriptional_Pahlavi,
ucp_Inscriptional_Parthian,
ucp_Javanese,
ucp_Kaithi,
ucp_Lisu,
ucp_Meetei_Mayek,
ucp_Old_South_Arabian,
ucp_Old_Turkic,
ucp_Samaritan,
ucp_Tai_Tham,
ucp_Tai_Viet,
/* New for Unicode 6.0.0: */
ucp_Batak,
ucp_Brahmi,
ucp_Mandaic
}; };
#endif #endif
/* End of ucp.h */ /* End of ucp.h */
 End of changes. 2 change blocks. 
9 lines changed or deleted 41 lines changed or added


 undef_macros.h   undef_macros.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.
*/ */
// If you define a new global un-prefixed macro, please add it here and in redef_macros // If you define a new global un-prefixed macro, please add it here and in redef_macros
// #pragma once // this file is intended to be processed multiple times // #pragma once // this file is intended to be processed multiple times
/** MONGO_EXPOSE_MACROS - when defined, indicates that you are compiling a #ifdef MONGO_MACROS_PUSHED
mongo program rather
than just using the C++ driver.
*/
#if !defined(MONGO_EXPOSE_MACROS) && !defined(MONGO_MACROS_CLEANED)
// util/allocator.h // util/allocator.h
#undef malloc #undef malloc
#pragma pop_macro("malloc")
#undef realloc #undef realloc
#pragma pop_macro("realloc")
// util/assert_util.h // util/assert_util.h
#undef assert
#undef dassert #undef dassert
#pragma pop_macro("dassert")
#undef wassert #undef wassert
#pragma pop_macro("wassert")
#undef massert #undef massert
#pragma pop_macro("massert")
#undef uassert #undef uassert
#undef BOOST_CHECK_EXCEPTION #pragma pop_macro("uassert")
#undef verify
#pragma pop_macro("verify")
#undef DESTRUCTOR_GUARD #undef DESTRUCTOR_GUARD
#pragma pop_macro("DESTRUCTOR_GUARD")
// util/goodies.h // util/goodies.h
#undef PRINT #undef PRINT
#pragma pop_macro("PRINT")
#undef PRINTFL #undef PRINTFL
#undef asctime #pragma pop_macro("PRINTFL")
#undef gmtime
#undef localtime
#undef ctime
// util/debug_util.h // util/debug_util.h
#undef DEV #undef DEV
#pragma pop_macro("DEV")
#undef DEBUGGING #undef DEBUGGING
#pragma pop_macro("DEBUGGING")
#undef SOMETIMES #undef SOMETIMES
#pragma pop_macro("SOMETIMES")
#undef OCCASIONALLY #undef OCCASIONALLY
#pragma pop_macro("OCCASIONALLY")
#undef RARELY #undef RARELY
#pragma pop_macro("RARELY")
#undef ONCE #undef ONCE
#pragma pop_macro("ONCE")
// util/log.h // util/log.h
#undef LOG #undef LOG
#pragma pop_macro("LOG")
#define MONGO_MACROS_CLEANED #undef MONGO_MACROS_PUSHED
#endif #endif
 End of changes. 19 change blocks. 
12 lines changed or deleted 20 lines changed or added


 unittest.h   unittest.h 
// unittest.h // mongo/unittest/unittest.h
/* Copyright 2009 10gen Inc. /**
* * Copyright (C) 2008 10gen Inc.
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. * This program is free software: you can redistribute it and/or modify
* You may obtain a copy of the License at * it under the terms of the GNU Affero General Public License, version 3
* ,
* http://www.apache.org/licenses/LICENSE-2.0 * as published by the Free Software Foundation.
* *
* Unless required by applicable law or agreed to in writing, software * This program is distributed in the hope that it will be useful,
* distributed under the License is distributed on an "AS IS" BASIS, * but WITHOUT ANY WARRANTY; without even the implied warranty of
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
ed. * GNU Affero General Public License for more details.
* See the License for the specific language governing permissions and *
* limitations under the License. * 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/>.
*/
/*
simple portable regression system
*/ */
#pragma once #include <sstream>
#include <string>
#include <vector>
#include <boost/noncopyable.hpp>
#include <boost/scoped_ptr.hpp>
#include "mongo/util/assert_util.h"
#include "mongo/util/log.h"
#define ASSERT_THROWS(a,b) \
try { \
a; \
mongo::unittest::assert_fail( #a , __FILE__ , __LINE__ ); \
} catch ( b& ){ \
mongo::unittest::assert_pass(); \
}
#define ASSERT_EQUALS(a,b) mongo::unittest::MyAsserts( #a , #b , __FILE__ ,
__LINE__ ).ae( (a) , (b) )
#define ASSERT_NOT_EQUALS(a,b) mongo::unittest::MyAsserts( #a , #b , __FILE
__ , __LINE__ ).nae( (a) , (b) )
#define ASSERT(x) (void)( (!(!(x))) ? mongo::unittest::assert_pass() : FAIL
(x) )
#define FAIL(x) mongo::unittest::assert_fail( #x , __FILE__ , __LINE__ )
namespace mongo { namespace mongo {
/* The idea here is to let all initialization of global variables (clas namespace unittest {
ses inheriting from UnitTest)
complete before we run the tests -- otherwise order of initilization class Result;
being arbitrary may mess
us up. The app's main() function should call runTests(). class TestCase {
public:
To define a unit test, inherit from this and implement run. instanti virtual ~TestCase();
ate one object for the new class virtual void setUp();
as a global. virtual void tearDown();
virtual void run() = 0;
These tests are ran on *every* startup of mongod, so they have to be virtual std::string getName() = 0;
very lightweight. But it is a };
good quick check for a bad build.
*/ class Test : public TestCase {
struct UnitTest { public:
UnitTest() { Test();
registerTest(this); virtual ~Test();
} virtual std::string getName();
virtual ~UnitTest() {}
protected:
// assert if fails void setTestName( const std::string &name );
virtual void run() = 0;
private:
static bool testsInProgress() { return running; } std::string _name;
private: };
static vector<UnitTest*> *tests;
static bool running; template< class T >
public: class TestHolderBase : public TestCase {
static void registerTest(UnitTest *t) { public:
if ( tests == 0 ) TestHolderBase() {}
tests = new vector<UnitTest*>(); virtual ~TestHolderBase() {}
tests->push_back(t); virtual void run() {
} boost::scoped_ptr<T> t;
t.reset( create() );
static void runTests() { t->run();
running = true; }
for ( vector<UnitTest*>::iterator i = tests->begin(); i != test virtual T * create() = 0;
s->end(); i++ ) { virtual std::string getName() {
(*i)->run(); return demangleName( typeid(T) );
} }
running = false; };
}
}; template< class T >
class TestHolder0 : public TestHolderBase<T> {
public:
virtual T * create() {
return new T();
}
};
template< class T , typename A >
class TestHolder1 : public TestHolderBase<T> {
public:
TestHolder1( const A& a ) : _a(a) {}
virtual T * create() {
return new T( _a );
}
const A _a;
};
class Suite {
public:
Suite( const string &name );
virtual ~Suite();
template<class T>
void add() {
_tests.push_back( new TestHolder0<T>() );
}
template<class T , typename A >
void add( const A& a ) {
_tests.push_back( new TestHolder1<T,A>(a) );
}
Result * run( const std::string& filter );
static int run( const std::vector<std::string> &suites , const
std::string& filter );
protected:
virtual void setupTests() = 0;
private:
typedef std::vector<TestCase *> TestCaseList;
std::string _name;
TestCaseList _tests;
bool _ran;
void registerSuite( const std::string &name , Suite *s );
};
void assert_pass();
void assert_fail( const char * exp , const char * file , unsigned l
ine );
class MyAssertionException : private boost::noncopyable {
public:
MyAssertionException() {
ss << "assertion: ";
}
std::stringstream ss;
};
class MyAsserts : private boost::noncopyable {
public:
MyAsserts( const char * aexp , const char * bexp , const char *
file , unsigned line )
: _aexp( aexp ) , _bexp( bexp ) , _file( file ) , _line( li
ne ) {
}
template<typename A,typename B>
void ae( const A &a , const B &b ) {
_gotAssert();
if ( a == b )
return;
printLocation();
MyAssertionException * e = getBase();
e->ss << a << " != " << b << std::endl;
log() << e->ss.str() << std::endl;
throw e;
}
template<typename A,typename B>
void nae( const A &a , const B &b ) {
_gotAssert();
if ( a != b )
return;
printLocation();
MyAssertionException * e = getBase();
e->ss << a << " == " << b << std::endl;
log() << e->ss.str() << std::endl;
throw e;
}
void printLocation();
private:
void _gotAssert();
MyAssertionException * getBase();
std::string _aexp;
std::string _bexp;
std::string _file;
unsigned _line;
};
/**
* Returns the name of the currently executing unit test
*/
std::string getExecutingTestName();
/**
* Return a list of suite names.
*/
std::vector<std::string> getAllSuiteNames();
} // namespace mongo } // namespace unittest
} // namespace mongo
 End of changes. 5 change blocks. 
59 lines changed or deleted 212 lines changed or added


 update.h   update.h 
skipping to change at line 22 skipping to change at line 22
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Lice nse * You should have received a copy of the GNU Affero General Public Lice nse
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "../../pch.h" #include "../../pch.h"
#include "../jsobj.h" #include "../jsobj.h"
#include "../../util/embedded_builder.h" #include "../../util/embedded_builder.h"
#include "../../util/stringutils.h"
#include "../matcher.h" #include "../matcher.h"
namespace mongo { namespace mongo {
// ---------- public ------------- // ---------- public -------------
struct UpdateResult { struct UpdateResult {
const bool existing; // if existing objects were modified const bool existing; // if existing objects were modified
const bool mod; // was this a $ mod const bool mod; // was this a $ mod
const long long num; // how many objects touched const long long num; // how many objects touched
skipping to change at line 50 skipping to change at line 51
} }
} }
}; };
class RemoveSaver; class RemoveSaver;
/* returns true if an existing object was updated, false if no existing object was found. /* returns true if an existing object was updated, false if no existing object was found.
multi - update multiple objects - mostly useful with things like $se t multi - update multiple objects - mostly useful with things like $se t
god - allow access to system namespaces god - allow access to system namespaces
*/ */
UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BS UpdateResult updateObjects(const char *ns,
ONObj pattern, bool upsert, bool multi , bool logop , OpDebug& debug ); const BSONObj& updateobj,
UpdateResult _updateObjects(bool god, const char *ns, const BSONObj& up BSONObj pattern,
dateobj, BSONObj pattern, bool upsert,
bool upsert, bool multi , bool logop , OpDe bool multi ,
bug& debug , RemoveSaver * rs = 0 ); bool logop ,
OpDebug& debug,
bool fromMigrate = false,
const QueryPlanSelectionPolicy &planPolicy =
QueryPlanSelectionPolicy::any());
UpdateResult _updateObjects(bool god,
const char *ns,
const BSONObj& updateobj,
BSONObj pattern,
bool upsert,
bool multi ,
bool logop ,
OpDebug& debug ,
RemoveSaver * rs = 0,
bool fromMigrate = false,
const QueryPlanSelectionPolicy &planPolicy
=
QueryPlanSelectionPolicy::any());
// ---------- private ------------- // ---------- private -------------
class ModState; class ModState;
class ModSetState; class ModSetState;
/* Used for modifiers such as $inc, $set, $push, ... /* Used for modifiers such as $inc, $set, $push, ...
* stores the info about a single operation * stores the info about a single operation
* once created should never be modified * once created should never be modified
*/ */
skipping to change at line 119 skipping to change at line 139
case NumberDouble: case NumberDouble:
manip.setNumber( elt.numberDouble() + in.numberDouble() ); manip.setNumber( elt.numberDouble() + in.numberDouble() );
break; break;
case NumberLong: case NumberLong:
manip.setLong( elt.numberLong() + in.numberLong() ); manip.setLong( elt.numberLong() + in.numberLong() );
break; break;
case NumberInt: case NumberInt:
manip.setInt( elt.numberInt() + in.numberInt() ); manip.setInt( elt.numberInt() + in.numberInt() );
break; break;
default: default:
assert(0); verify(0);
} }
} }
void IncrementMe( BSONElement& in ) const { void IncrementMe( BSONElement& in ) const {
BSONElementManipulator manip( in ); BSONElementManipulator manip( in );
switch ( in.type() ) { switch ( in.type() ) {
case NumberDouble: case NumberDouble:
manip.SetNumber( elt.numberDouble() + in.numberDouble() ); manip.SetNumber( elt.numberDouble() + in.numberDouble() );
break; break;
case NumberLong: case NumberLong:
manip.SetLong( elt.numberLong() + in.numberLong() ); manip.SetLong( elt.numberLong() + in.numberLong() );
break; break;
case NumberInt: case NumberInt:
manip.SetInt( elt.numberInt() + in.numberInt() ); manip.SetInt( elt.numberInt() + in.numberInt() );
break; break;
default: default:
assert(0); verify(0);
} }
} }
template< class Builder > template< class Builder >
void appendIncremented( Builder& bb , const BSONElement& in, ModSta te& ms ) const; void appendIncremented( Builder& bb , const BSONElement& in, ModSta te& ms ) const;
bool operator<( const Mod &other ) const { bool operator<( const Mod &other ) const {
return strcmp( fieldName, other.fieldName ) < 0; return strcmp( fieldName, other.fieldName ) < 0;
} }
skipping to change at line 280 skipping to change at line 300
/** /**
* stores a set of Mods * stores a set of Mods
* once created, should never be changed * once created, should never be changed
*/ */
class ModSet : boost::noncopyable { class ModSet : boost::noncopyable {
typedef map<string,Mod> ModHolder; typedef map<string,Mod> ModHolder;
ModHolder _mods; ModHolder _mods;
int _isIndexed; int _isIndexed;
bool _hasDynamicArray; bool _hasDynamicArray;
static void extractFields( map< string, BSONElement > &fields, cons
t BSONElement &top, const string &base );
FieldCompareResult compare( const ModHolder::iterator &m, map< stri
ng, BSONElement >::iterator &p, const map< string, BSONElement >::iterator
&pEnd ) const {
bool mDone = ( m == _mods.end() );
bool pDone = ( p == pEnd );
assert( ! mDone );
assert( ! pDone );
if ( mDone && pDone )
return SAME;
// If one iterator is done we want to read from the other one,
so say the other one is lower.
if ( mDone )
return RIGHT_BEFORE;
if ( pDone )
return LEFT_BEFORE;
return compareDottedFieldNames( m->first, p->first.c_str() );
}
bool mayAddEmbedded( map< string, BSONElement > &existing, string r
ight ) {
for( string left = EmbeddedBuilder::splitDot( right );
left.length() > 0 && left[ left.length() - 1 ] != '.';
left += "." + EmbeddedBuilder::splitDot( right ) ) {
if ( existing.count( left ) > 0 && existing[ left ].type()
!= Object )
return false;
if ( haveModForField( left.c_str() ) )
return false;
}
return true;
}
static Mod::Op opFromStr( const char *fn ) { static Mod::Op opFromStr( const char *fn ) {
assert( fn[0] == '$' ); verify( fn[0] == '$' );
switch( fn[1] ) { switch( fn[1] ) {
case 'i': { case 'i': {
if ( fn[2] == 'n' && fn[3] == 'c' && fn[4] == 0 ) if ( fn[2] == 'n' && fn[3] == 'c' && fn[4] == 0 )
return Mod::INC; return Mod::INC;
break; break;
} }
case 's': { case 's': {
if ( fn[2] == 'e' && fn[3] == 't' && fn[4] == 0 ) if ( fn[2] == 'e' && fn[3] == 't' && fn[4] == 0 )
return Mod::SET; return Mod::SET;
break; break;
skipping to change at line 395 skipping to change at line 386
} }
public: public:
ModSet( const BSONObj &from , ModSet( const BSONObj &from ,
const set<string>& idxKeys = set<string>(), const set<string>& idxKeys = set<string>(),
const set<string>* backgroundKeys = 0 const set<string>* backgroundKeys = 0
); );
// TODO: this is inefficient - should probably just handle when ite rating // TODO: this is inefficient - should probably just handle when ite rating
ModSet * fixDynamicArray( const char * elemMatchKey ) const; ModSet * fixDynamicArray( const string &elemMatchKey ) const;
bool hasDynamicArray() const { return _hasDynamicArray; } bool hasDynamicArray() const { return _hasDynamicArray; }
/** /**
* creates a ModSetState suitable for operation on obj * creates a ModSetState suitable for operation on obj
* doesn't change or modify this ModSet or any underying Mod * doesn't change or modify this ModSet or any underying Mod
*/ */
auto_ptr<ModSetState> prepare( const BSONObj& obj ) const; auto_ptr<ModSetState> prepare( const BSONObj& obj ) const;
/** /**
skipping to change at line 431 skipping to change at line 422
return _mods.find( fieldName ) != _mods.end(); return _mods.find( fieldName ) != _mods.end();
} }
bool haveConflictingMod( const string& fieldName ) { bool haveConflictingMod( const string& fieldName ) {
size_t idx = fieldName.find( '.' ); size_t idx = fieldName.find( '.' );
if ( idx == string::npos ) if ( idx == string::npos )
idx = fieldName.size(); idx = fieldName.size();
ModHolder::const_iterator start = _mods.lower_bound(fieldName.s ubstr(0,idx)); ModHolder::const_iterator start = _mods.lower_bound(fieldName.s ubstr(0,idx));
for ( ; start != _mods.end(); start++ ) { for ( ; start != _mods.end(); start++ ) {
FieldCompareResult r = compareDottedFieldNames( fieldName , FieldCompareResult r = compareDottedFieldNames( fieldName ,
start->first ); start->first ,
LexNumCmp( t
rue ) );
switch ( r ) { switch ( r ) {
case LEFT_SUBFIELD: return true; case LEFT_SUBFIELD: return true;
case LEFT_BEFORE: return false; case LEFT_BEFORE: return false;
case SAME: return true; case SAME: return true;
case RIGHT_BEFORE: return false; case RIGHT_BEFORE: return false;
case RIGHT_SUBFIELD: return true; case RIGHT_SUBFIELD: return true;
} }
} }
return false; return false;
} }
}; };
/** /**
* stores any information about a single Mod operating on a single Obje ct * stores any information about a single Mod operating on a single Obje ct
*/ */
class ModState { class ModState : boost::noncopyable {
public: public:
const Mod * m; const Mod * m;
BSONElement old; BSONElement old;
BSONElement newVal; BSONElement newVal;
BSONObj _objData; BSONObj _objData;
const char * fixedOpName; const char * fixedOpName;
BSONElement * fixed; BSONElement * fixed;
int pushStartSize; int pushStartSize;
skipping to change at line 523 skipping to change at line 515
const char * n = useFullName ? m->fieldName : m->shortFieldName ; const char * n = useFullName ? m->fieldName : m->shortFieldName ;
switch ( incType ) { switch ( incType ) {
case NumberDouble: case NumberDouble:
b.append( n , incdouble ); break; b.append( n , incdouble ); break;
case NumberLong: case NumberLong:
b.append( n , inclong ); break; b.append( n , inclong ); break;
case NumberInt: case NumberInt:
b.append( n , incint ); break; b.append( n , incint ); break;
default: default:
assert(0); verify(0);
} }
} }
string toString() const; string toString() const;
template< class Builder > template< class Builder >
void handleRename( Builder &newObjBuilder, const char *shortFieldNa me ); void handleRename( Builder &newObjBuilder, const char *shortFieldNa me );
}; };
/** /**
* 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 { typedef map<string,shared_ptr<ModState>,LexNumCmp> ModStateHolder;
bool operator()( const string &l, const string &r ) const; typedef pair<const ModStateHolder::iterator,const ModStateHolder::i
}; terator> ModStateRange;
typedef map<string,ModState,FieldCmp> ModStateHolder;
const BSONObj& _obj; const BSONObj& _obj;
ModStateHolder _mods; ModStateHolder _mods;
bool _inPlacePossible; bool _inPlacePossible;
BSONObj _newFromMods; // keep this data alive, as oplog generation may depend on it BSONObj _newFromMods; // keep this data alive, as oplog generation may depend on it
ModSetState( const BSONObj& obj ) ModSetState( const BSONObj& obj )
: _obj( obj ) , _inPlacePossible(true) { : _obj( obj ) , _mods( LexNumCmp( true ) ) , _inPlacePossible(t rue) {
} }
/** /**
* @return if in place is still possible * @return if in place is still possible
*/ */
bool amIInPlacePossible( bool inPlacePossible ) { bool amIInPlacePossible( bool inPlacePossible ) {
if ( ! inPlacePossible ) if ( ! inPlacePossible )
_inPlacePossible = false; _inPlacePossible = false;
return _inPlacePossible; return _inPlacePossible;
} }
ModStateRange modsForRoot( const string &root );
void createNewObjFromMods( const string &root, BSONObjBuilder &b, c
onst BSONObj &obj );
void createNewArrayFromMods( const string &root, BSONArrayBuilder &
b,
const BSONArray &arr );
template< class Builder > template< class Builder >
void createNewFromMods( const string& root , Builder& b , const BSO void createNewFromMods( const string& root , Builder& b , BSONItera
NObj &obj ); torSorted& es ,
const ModStateRange& modRange , const LexNum
Cmp& lexNumCmp );
template< class Builder > template< class Builder >
void _appendNewFromMods( const string& root , ModState& m , Builder & b , set<string>& onedownseen ); void _appendNewFromMods( const string& root , ModState& m , Builder & b , set<string>& onedownseen );
template< class Builder > template< class Builder >
void appendNewFromMod( ModState& ms , Builder& b ) { void appendNewFromMod( ModState& ms , Builder& b ) {
if ( ms.dontApply ) { if ( ms.dontApply ) {
return; return;
} }
skipping to change at line 642 skipping to change at line 639
ms.handleRename( b, m.shortFieldName ); ms.handleRename( b, m.shortFieldName );
break; break;
default: default:
stringstream ss; stringstream ss;
ss << "unknown mod in appendNewFromMod: " << m.op; ss << "unknown mod in appendNewFromMod: " << m.op;
throw UserException( 9015, ss.str() ); throw UserException( 9015, ss.str() );
} }
} }
/** @return true iff the elements aren't eoo(), are distinct, and s
hare a field name. */
static bool duplicateFieldName( const BSONElement &a, const BSONEle
ment &b );
public: public:
bool canApplyInPlace() const { bool canApplyInPlace() const {
return _inPlacePossible; return _inPlacePossible;
} }
/** /**
* modified underlying _obj * modified underlying _obj
* @param isOnDisk - true means this is an on disk object, and this update needs to be made durable * @param isOnDisk - true means this is an on disk object, and this update needs to be made durable
*/ */
void applyModsInPlace( bool isOnDisk ); void applyModsInPlace( bool isOnDisk );
BSONObj createNewFromMods(); BSONObj createNewFromMods();
// re-writing for oplog // re-writing for oplog
bool needOpLogRewrite() const { bool needOpLogRewrite() const {
for ( ModStateHolder::const_iterator i = _mods.begin(); i != _m ods.end(); i++ ) for ( ModStateHolder::const_iterator i = _mods.begin(); i != _m ods.end(); i++ )
if ( i->second.needOpLogRewrite() ) if ( i->second->needOpLogRewrite() )
return true; return true;
return false; return false;
} }
BSONObj getOpLogRewrite() const { BSONObj getOpLogRewrite() const {
BSONObjBuilder b; BSONObjBuilder b;
for ( ModStateHolder::const_iterator i = _mods.begin(); i != _m ods.end(); i++ ) for ( ModStateHolder::const_iterator i = _mods.begin(); i != _m ods.end(); i++ )
i->second.appendForOpLog( b ); i->second->appendForOpLog( b );
return b.obj(); return b.obj();
} }
bool haveArrayDepMod() const { bool haveArrayDepMod() const {
for ( ModStateHolder::const_iterator i = _mods.begin(); i != _m ods.end(); i++ ) for ( ModStateHolder::const_iterator i = _mods.begin(); i != _m ods.end(); i++ )
if ( i->second.m->arrayDep() ) if ( i->second->m->arrayDep() )
return true; return true;
return false; return false;
} }
void appendSizeSpecForArrayDepMods( BSONObjBuilder &b ) const { void appendSizeSpecForArrayDepMods( BSONObjBuilder &b ) const {
for ( ModStateHolder::const_iterator i = _mods.begin(); i != _m ods.end(); i++ ) { for ( ModStateHolder::const_iterator i = _mods.begin(); i != _m ods.end(); i++ ) {
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; string toString() const;
 End of changes. 19 change blocks. 
60 lines changed or deleted 59 lines changed or added


 util.h   util.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 "../pch.h" #include "mongo/pch.h"
#include "../client/dbclient.h" #include "mongo/db/jsobj.h"
#include "../db/jsobj.h" #include "mongo/util/mongoutils/str.h"
/** /**
some generic sharding utils that can be used in mongod or mongos some generic sharding utils that can be used in mongod or mongos
*/ */
namespace mongo { namespace mongo {
struct ShardChunkVersion { struct ShardChunkVersion {
union { union {
struct { struct {
int _minor; int _minor;
skipping to change at line 58 skipping to change at line 57
ShardChunkVersion( const BSONElement& e ) { ShardChunkVersion( const BSONElement& e ) {
if ( e.type() == Date || e.type() == Timestamp ) { if ( e.type() == Date || e.type() == Timestamp ) {
_combined = e._numberLong(); _combined = e._numberLong();
} }
else if ( e.eoo() ) { else if ( e.eoo() ) {
_combined = 0; _combined = 0;
} }
else { else {
_combined = 0; _combined = 0;
log() << "ShardChunkVersion can't handle type (" << (int)(e .type()) << ") " << e << endl; log() << "ShardChunkVersion can't handle type (" << (int)(e .type()) << ") " << e << endl;
assert(0); verify(0);
} }
} }
void inc( bool major ) { void inc( bool major ) {
if ( major ) if ( major )
incMajor(); incMajor();
else else
incMinor(); incMinor();
} }
skipping to change at line 108 skipping to change at line 107
switch ( elem.type() ) { switch ( elem.type() ) {
case Timestamp: case Timestamp:
case NumberLong: case NumberLong:
case Date: case Date:
_combined = elem._numberLong(); _combined = elem._numberLong();
break; break;
case EOO: case EOO:
_combined = 0; _combined = 0;
break; break;
default: default:
massert( 13657 , str::stream() << "unknown type for ShardCh unkVersion: " << elem , 0 ); massert( 13657 , mongoutils::str::stream() << "unknown type for ShardChunkVersion: " << elem , 0 );
} }
return *this; return *this;
} }
}; };
inline ostream& operator<<( ostream &s , const ShardChunkVersion& v) { inline ostream& operator<<( ostream &s , const ShardChunkVersion& v) {
s << v._major << "|" << v._minor; s << v._major << "|" << v._minor;
return s; return s;
} }
/** /**
* your config info for a given shard/chunk is out of date * your config info for a given shard/chunk is out of date
*/ */
class StaleConfigException : public AssertionException { class StaleConfigException : public AssertionException {
public: public:
StaleConfigException( const string& ns , const string& raw , int co StaleConfigException( const string& ns , const string& raw , int co
de, bool justConnection = false ) de, ShardChunkVersion received, ShardChunkVersion wanted, bool justConnecti
: AssertionException( (string)"ns: " + ns + " " + raw , code ) on = false )
, : AssertionException(
mongoutils::str::stream() << raw << " ( ns : " << ns <<
", received : " << received.to
String() <<
", wanted : " << wanted.toStri
ng() <<
", " << ( code == SendStaleCon
figCode ? "send" : "recv" ) << " )",
code ),
_justConnection(justConnection) , _justConnection(justConnection) ,
_ns(ns) { _ns(ns),
} _received( received ),
_wanted( wanted )
{}
// Preferred if we're rebuilding this from a thrown exception
StaleConfigException( const string& raw , int code, const BSONObj&
error, bool justConnection = false )
: AssertionException(
mongoutils::str::stream() << raw << " ( ns : " << error
["ns"].String() << // Note, this will fail if we don't have a ns
", received : " << ShardChunkV
ersion( error["vReceived"] ).toString() <<
", wanted : " << ShardChunkVer
sion( error["vWanted"] ).toString() <<
", " << ( code == SendStaleCon
figCode ? "send" : "recv" ) << " )",
code ),
_justConnection(justConnection) ,
_ns( error["ns"].String() ),
_received( ShardChunkVersion( error["vReceived"] ) ),
_wanted( ShardChunkVersion( error["vWanted"] ) )
{}
StaleConfigException() : AssertionException( "", 0 ) {}
virtual ~StaleConfigException() throw() {} virtual ~StaleConfigException() throw() {}
virtual void appendPrefix( stringstream& ss ) const { ss << "stale sharding config exception: "; } virtual void appendPrefix( stringstream& ss ) const { ss << "stale sharding config exception: "; }
bool justConnection() const { return _justConnection; } bool justConnection() const { return _justConnection; }
string getns() const { return _ns; } string getns() const { return _ns; }
static bool parse( const string& big , string& ns , string& raw ) { static bool parse( const string& big , string& ns , string& raw ) {
skipping to change at line 150 skipping to change at line 172
if ( start == string::npos ) if ( start == string::npos )
return false; return false;
string::size_type end = big.find( ']' ,start ); string::size_type end = big.find( ']' ,start );
if ( end == string::npos ) if ( end == string::npos )
return false; return false;
ns = big.substr( start + 1 , ( end - start ) - 1 ); ns = big.substr( start + 1 , ( end - start ) - 1 );
raw = big.substr( end + 1 ); raw = big.substr( end + 1 );
return true; return true;
} }
ShardChunkVersion getVersionReceived() const { return _received; }
ShardChunkVersion getVersionWanted() const { return _wanted; }
StaleConfigException& operator=( const StaleConfigException& elem )
{
this->_ei.msg = elem._ei.msg;
this->_ei.code = elem._ei.code;
this->_justConnection = elem._justConnection;
this->_ns = elem._ns;
this->_received = elem._received;
this->_wanted = elem._wanted;
return *this;
}
private: private:
bool _justConnection; bool _justConnection;
string _ns; string _ns;
ShardChunkVersion _received;
ShardChunkVersion _wanted;
}; };
class SendStaleConfigException : public StaleConfigException { class SendStaleConfigException : public StaleConfigException {
public: public:
SendStaleConfigException( const string& ns , const string& raw , bo SendStaleConfigException( const string& ns , const string& raw , Sh
ol justConnection = false ) ardChunkVersion received, ShardChunkVersion wanted, bool justConnection = f
: StaleConfigException( ns, raw + "(send)", SendStaleConfigCode alse )
, justConnection ) {} : StaleConfigException( ns, raw, SendStaleConfigCode, received,
wanted, justConnection ) {}
SendStaleConfigException( const string& raw , const BSONObj& error,
bool justConnection = false )
: StaleConfigException( raw, SendStaleConfigCode, error, justCo
nnection ) {}
}; };
class RecvStaleConfigException : public StaleConfigException { class RecvStaleConfigException : public StaleConfigException {
public: public:
RecvStaleConfigException( const string& ns , const string& raw , bo RecvStaleConfigException( const string& ns , const string& raw , Sh
ol justConnection = false ) ardChunkVersion received, ShardChunkVersion wanted, bool justConnection = f
: StaleConfigException( ns, raw + "(recv)", RecvStaleConfigCode alse )
, justConnection ) {} : StaleConfigException( ns, raw, RecvStaleConfigCode, received,
wanted, justConnection ) {}
RecvStaleConfigException( const string& raw , const BSONObj& error,
bool justConnection = false )
: StaleConfigException( raw, RecvStaleConfigCode, error, justCo
nnection ) {}
}; };
class ShardConnection; class ShardConnection;
class DBClientBase;
class VersionManager { class VersionManager {
public: public:
VersionManager(){}; VersionManager(){};
bool isVersionableCB( DBClientBase* ); bool isVersionableCB( DBClientBase* );
bool initShardVersionCB( DBClientBase*, BSONObj& ); bool initShardVersionCB( DBClientBase*, BSONObj& );
bool forceRemoteCheckShardVersionCB( const string& ); bool forceRemoteCheckShardVersionCB( const string& );
bool checkShardVersionCB( DBClientBase*, const string&, bool, int ) ; bool checkShardVersionCB( DBClientBase*, const string&, bool, int ) ;
bool checkShardVersionCB( ShardConnection*, bool, int ); bool checkShardVersionCB( ShardConnection*, bool, int );
void resetShardVersionCB( DBClientBase* ); void resetShardVersionCB( DBClientBase* );
 End of changes. 10 change blocks. 
20 lines changed or deleted 80 lines changed or added


 v8_db.h   v8_db.h 
skipping to change at line 26 skipping to change at line 26
*/ */
#pragma once #pragma once
#include <v8.h> #include <v8.h>
#include <cstring> #include <cstring>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include "engine_v8.h" #include "engine_v8.h"
#include "../client/dbclient.h"
namespace mongo { namespace mongo {
class DBClientBase;
// These functions may depend on the caller creating a handle scope and context scope. // These functions may depend on the caller creating a handle scope and context scope.
v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate( V8Scope * sc ope, bool local ); v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate( V8Scope * sc ope, bool local );
// void installDBTypes( V8Scope * scope, v8::Handle<v8::ObjectTemplate>& global ); // void installDBTypes( V8Scope * scope, v8::Handle<v8::ObjectTemplate>& global );
void installDBTypes( V8Scope * scope, v8::Handle<v8::Object>& global ); void installDBTypes( V8Scope * scope, v8::Handle<v8::Object>& global );
// the actual globals // the actual globals
mongo::DBClientBase * getConnection( const v8::Arguments& args ); mongo::DBClientBase * getConnection( const v8::Arguments& args );
 End of changes. 2 change blocks. 
2 lines changed or deleted 1 lines changed or added


 v8_utils.h   v8_utils.h 
skipping to change at line 32 skipping to change at line 32
#include <cstring> #include <cstring>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <assert.h> #include <assert.h>
#include <iostream> #include <iostream>
namespace mongo { namespace mongo {
void ReportException(v8::TryCatch* handler); void ReportException(v8::TryCatch* handler);
#define jsassert(x,msg) assert(x) #define jsassert(x,msg) verify(x)
std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::Value> & o ); std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::Value> & o );
std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::TryCatc h> * try_catch ); std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::TryCatc h> * try_catch );
std::string toSTLString( const v8::Handle<v8::Value> & o ); std::string toSTLString( const v8::Handle<v8::Value> & o );
std::string toSTLString( const v8::TryCatch * try_catch ); std::string toSTLString( const v8::TryCatch * try_catch );
class V8Scope; class V8Scope;
void installFork( V8Scope* scope, v8::Handle< v8::Object > &global, v8: :Handle< v8::Context > &context ); void installFork( V8Scope* scope, v8::Handle< v8::Object > &global, v8: :Handle< v8::Context > &context );
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 value.h   value.h 
skipping to change at line 411 skipping to change at line 411
/* ======================= INLINED IMPLEMENTATIONS ======================== == */ /* ======================= INLINED IMPLEMENTATIONS ======================== == */
namespace mongo { namespace mongo {
inline BSONType Value::getType() const { inline BSONType Value::getType() const {
return type; return type;
} }
inline size_t Value::getArrayLength() const { inline size_t Value::getArrayLength() const {
assert(getType() == Array); verify(getType() == Array);
return vpValue.size(); return vpValue.size();
} }
inline intrusive_ptr<const Value> Value::getUndefined() { inline intrusive_ptr<const Value> Value::getUndefined() {
return pFieldUndefined; return pFieldUndefined;
} }
inline intrusive_ptr<const Value> Value::getNull() { inline intrusive_ptr<const Value> Value::getNull() {
return pFieldNull; return pFieldNull;
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 version.h   version.h 
#ifndef UTIL_VERSION_HEADER #ifndef UTIL_VERSION_HEADER
#define UTIL_VERSION_HEADER #define UTIL_VERSION_HEADER
#include <string> #include <string>
#include "mongo/bson/stringdata.h"
namespace mongo { namespace mongo {
struct BSONArray; struct BSONArray;
using std::string;
// mongo version // mongo version
extern const char versionString[]; extern const char versionString[];
extern const BSONArray versionArray; extern const BSONArray versionArray;
string mongodVersion(); std::string mongodVersion();
int versionCmp(StringData rhs, StringData lhs); // like strcmp int versionCmp(StringData rhs, StringData lhs); // like strcmp
const char * gitVersion(); const char * gitVersion();
void printGitVersion(); void printGitVersion();
string sysInfo(); std::string sysInfo();
void printSysInfo(); void printSysInfo();
void show_warnings(); void show_warnings();
} // namespace mongo } // namespace mongo
#endif // UTIL_VERSION_HEADER #endif // UTIL_VERSION_HEADER
 End of changes. 4 change blocks. 
4 lines changed or deleted 4 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/