MurmurHash3.h   MurmurHash3.h 
//------------------------------------------------------------------------- ---- //------------------------------------------------------------------------- ----
// MurmurHash3 was written by Austin Appleby, and is placed in the public // MurmurHash3 was written by Austin Appleby, and is placed in the public
// domain. The author hereby disclaims copyright to this source code. // domain. The author hereby disclaims copyright to this source code.
#ifndef _MURMURHASH3_H_ #ifndef _MURMURHASH3_H_
#define _MURMURHASH3_H_ #define _MURMURHASH3_H_
//-------------------------------------------------------------------------
----
// Platform-specific functions and macros
// Microsoft Visual Studio
#if defined(_MSC_VER)
typedef unsigned char uint8_t;
typedef unsigned long uint32_t;
typedef unsigned __int64 uint64_t;
// Other compilers
#else // defined(_MSC_VER)
#include <stdint.h> #include <stdint.h>
#endif // !defined(_MSC_VER)
//------------------------------------------------------------------------- ---- //------------------------------------------------------------------------- ----
void MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed, void * out ); void MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed, void * out );
void MurmurHash3_x86_128 ( const void * key, int len, uint32_t seed, void * out ); void MurmurHash3_x86_128 ( const void * key, int len, uint32_t seed, void * out );
void MurmurHash3_x64_128 ( const void * key, int len, uint32_t seed, void * out ); void MurmurHash3_x64_128 ( const void * key, int len, uint32_t seed, void * out );
//------------------------------------------------------------------------- ---- //------------------------------------------------------------------------- ----
 End of changes. 2 change blocks. 
18 lines changed or deleted 0 lines changed or added


 assert_util.h   assert_util.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 <iostream> #include <iostream>
#include <typeinfo> #include <typeinfo>
#include <string>
#include "mongo/bson/inline_decls.h" #include "mongo/bson/inline_decls.h"
#include "mongo/platform/compiler.h" #include "mongo/platform/compiler.h"
namespace mongo { namespace mongo {
enum CommonErrorCodes { enum CommonErrorCodes {
DatabaseDifferCaseCode = 13297 , DatabaseDifferCaseCode = 13297 ,
SendStaleConfigCode = 13388 , SendStaleConfigCode = 13388 ,
RecvStaleConfigCode = 9996 RecvStaleConfigCode = 9996
skipping to change at line 164 skipping to change at line 165
/** 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.
*/ */
MONGO_COMPILER_NORETURN void uasserted(int msgid, const char *msg); MONGO_COMPILER_NORETURN void uasserted(int msgid, const char *msg);
MONGO_COMPILER_NORETURN void uasserted(int msgid , const std::string &m sg); MONGO_COMPILER_NORETURN void uasserted(int msgid , const std::string &m sg);
/** 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.
*/ */
MONGO_COMPILER_NORETURN void msgassertedNoTrace(int msgid, const char * msg); MONGO_COMPILER_NORETURN void msgassertedNoTrace(int msgid, const char * msg);
inline void msgassertedNoTrace(int msgid, const std::string& msg) { msg MONGO_COMPILER_NORETURN inline void msgassertedNoTrace(int msgid, const
assertedNoTrace( msgid , msg.c_str() ); } std::string& msg) {
msgassertedNoTrace( msgid , msg.c_str() );
}
MONGO_COMPILER_NORETURN void msgasserted(int msgid, const char *msg); MONGO_COMPILER_NORETURN void msgasserted(int msgid, const char *msg);
MONGO_COMPILER_NORETURN 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() ); }
/** abends on condition failure */ /** abends on condition failure */
skipping to change at line 196 skipping to change at line 199
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) )
/* same as massert except no msgid */ /* same as massert except no msgid */
#define MONGO_verify(_Expression) (void)( MONGO_likely(!!(_Expression)) || (mongo::verifyFailed(#_Expression, __FILE__, __LINE__), 0) ) #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 verify # define MONGO_dassert(x) fassert(16199, (x))
#else #else
# define MONGO_dassert(x) # define MONGO_dassert(x)
#endif #endif
#ifdef MONGO_EXPOSE_MACROS #ifdef MONGO_EXPOSE_MACROS
# define dassert MONGO_dassert # define dassert MONGO_dassert
# define verify MONGO_verify # define verify MONGO_verify
# define uassert MONGO_uassert # define uassert MONGO_uassert
# define wassert MONGO_wassert # define wassert MONGO_wassert
# define massert MONGO_massert # define massert MONGO_massert
 End of changes. 3 change blocks. 
3 lines changed or deleted 6 lines changed or added


 atomic_int.h   atomic_int.h 
skipping to change at line 22 skipping to change at line 22
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#if defined(_WIN32) #if defined(_WIN32)
# include <windows.h> #include "mongo/platform/windows_basic.h"
#endif #endif
#include "mongo/platform/compiler.h" #include "mongo/platform/compiler.h"
namespace mongo { namespace mongo {
/** /**
* An unsigned integer supporting atomic read-modify-write operations. * 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 * Many operations on these types depend on natural alignment (4 byte a lignment for 4-byte
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 authlevel.h   authlevel.h 
// mongo/db/authlevel.h // mongo/db/authlevel.h
/** /* Copyright 2012 10gen Inc.
* Copyright (C) 2009 10gen Inc.
* *
* This program is free software: you can redistribute it and/or modify * Licensed under the Apache License, Version 2.0 (the "License");
* it under the terms of the GNU Affero General Public License, version * you may not use this file except in compliance with the License.
3, * You may obtain a copy of the License at
* as published by the Free Software Foundation.
* *
* This program is distributed in the hope that it will be useful, * http://www.apache.org/licenses/LICENSE-2.0
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Lice * Unless required by applicable law or agreed to in writing, software
nse * distributed under the License is distributed on an "AS IS" BASIS,
* along with this program. If not, see <http://www.gnu.org/licenses/>. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli
ed.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ */
#pragma once #pragma once
#include <string> #include <string>
namespace mongo { namespace mongo {
/* /*
* for a particular db * for a particular db
skipping to change at line 41 skipping to change at line 40
*/ */
struct Auth { struct Auth {
enum Level { NONE = 0 , enum Level { NONE = 0 ,
READ = 1 , READ = 1 ,
WRITE = 2 }; WRITE = 2 };
Auth() : level( NONE ) {} Auth() : level( NONE ) {}
Level level; Level level;
string user; std::string user;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 5 change blocks. 
14 lines changed or deleted 12 lines changed or added


 background.h   background.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/>.
*/ */
/* background.h /* background.h
Concurrency coordination for administrative operations. Concurrency coordination for administrative operations.
*/ */
#pragma once #pragma once
#include "mongo/db/namespacestring.h"
namespace mongo { namespace mongo {
/* these are administrative operations / jobs /* these are administrative operations / jobs
for a namespace running in the background, and that only one for a namespace running in the background, and that only one
at a time per namespace is permitted, and that if in progress, at a time per namespace is permitted, and that if in progress,
you aren't allowed to do other NamespaceDetails major manipulations you aren't allowed to do other NamespaceDetails major manipulations
(such as dropping ns or db) even in the foreground and must (such as dropping ns or db) even in the foreground and must
instead uassert. instead uassert.
It's assumed this is not for super-high RPS things, so we don't do It's assumed this is not for super-high RPS things, so we don't do
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 balance.h   balance.h 
skipping to change at line 48 skipping to change at line 48
Balancer(); Balancer();
virtual ~Balancer(); virtual ~Balancer();
// BackgroundJob methods // BackgroundJob methods
virtual void run(); virtual void run();
virtual string name() const { return "Balancer"; } virtual string name() const { return "Balancer"; }
private: private:
typedef BalancerPolicy::ChunkInfo CandidateChunk; typedef MigrateInfo CandidateChunk;
typedef shared_ptr<CandidateChunk> CandidateChunkPtr; typedef shared_ptr<CandidateChunk> CandidateChunkPtr;
// hostname:port of my mongos // hostname:port of my mongos
string _myid; string _myid;
// time the Balancer started running // time the Balancer started running
time_t _started; time_t _started;
// number of moved chunks in last round // number of moved chunks in last round
int _balancedLastTime; int _balancedLastTime;
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 balancer_policy.h   balancer_policy.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/>.
*/ */
#ifndef S_BALANCER_POLICY_HEADER #ifndef S_BALANCER_POLICY_HEADER
#define S_BALANCER_POLICY_HEADER #define S_BALANCER_POLICY_HEADER
#include "../pch.h" #include "mongo/db/jsobj.h"
namespace mongo { namespace mongo {
class BalancerPolicy { struct ChunkInfo {
public: const BSONObj min;
struct ChunkInfo; const BSONObj max;
/** ChunkInfo( const BSONObj& a_min, const BSONObj& a_max )
* Returns a suggested chunk to move whithin a collection's shards, : min( a_min.getOwned() ), max( a_max.getOwned() ){}
given information about
* space usage and number of chunks for that collection. If the pol
icy doesn't recommend
* moving, it returns NULL.
*
* @param ns is the collections namepace.
* @param shardLimitMap is a map from shardId to an object that des
cribes (for now) space
* cap and usage. E.g.: { "maxSize" : <size_in_MB> , "usedSize" : <
size_in_MB> }.
* @param shardToChunksMap is a map from shardId to chunks that liv
e there. A chunk's format
* is { }.
* @param balancedLastTime is the number of chunks effectively move
d in the last round.
* @returns NULL or ChunkInfo of the best move to make towards bala
cing the collection.
*/
typedef map< string,BSONObj > ShardToLimitsMap;
typedef map< string,vector<BSONObj> > ShardToChunksMap;
static ChunkInfo* balance( const string& ns, const ShardToLimitsMap
& shardToLimitsMap,
const ShardToChunksMap& shardToChunksMap
, int balancedLastTime );
// below exposed for testing purposes only -- treat it as private - ChunkInfo( const BSONObj& chunk )
- : min( chunk["min"].Obj().getOwned() ), max( chunk["max"].Obj()
.getOwned() ) {
}
static BSONObj pickChunk( const vector<BSONObj>& from, const vector string toString() const;
<BSONObj>& to ); };
struct TagRange {
BSONObj min;
BSONObj max;
string tag;
TagRange(){}
TagRange( const BSONObj& a_min, const BSONObj& a_max, const string&
a_tag )
: min( a_min.getOwned() ), max( a_max.getOwned() ), tag( a_tag
){}
string toString() const;
};
class ShardInfo {
public:
ShardInfo();
ShardInfo( long long maxSize, long long currSize,
bool draining, bool opsQueued,
const set<string>& tags = set<string>() );
void addTag( const string& tag );
/** @return true if we have the tag OR if the tag is "" */
bool hasTag( const string& tag ) const;
/** /**
* Returns true if a shard cannot receive any new chunks bacause it reache 'shardLimits'. * @return true if a shard cannot receive any new chunks bacause it reache 'shardLimits'.
* Expects the optional fields "maxSize", can in size in MB, and "u sedSize", currently used size * Expects the optional fields "maxSize", can in size in MB, and "u sedSize", currently used size
* in MB, on 'shardLimits'. * in MB, on 'shardLimits'.
*/ */
static bool isSizeMaxed( BSONObj shardLimits ); bool isSizeMaxed() const;
/** /**
* Returns true if 'shardLimist' contains a field "draining". Expec ts the optional field * @return true if 'shardLimist' contains a field "draining". Expec ts the optional field
* "isDraining" on 'shrdLimits'. * "isDraining" on 'shrdLimits'.
*/ */
static bool isDraining( BSONObj shardLimits ); bool isDraining() const { return _draining; }
/** /**
* Returns true if a shard currently has operations in any of its w riteback queues * @return true if a shard currently has operations in any of its w riteback queues
*/ */
static bool hasOpsQueued( BSONObj shardLimits ); bool hasOpsQueued() const { return _hasOpsQueued; }
private: string toString() const;
// Convenience types
typedef ShardToChunksMap::const_iterator ShardToChunksIter;
typedef ShardToLimitsMap::const_iterator ShardToLimitsIter;
private:
long long _maxSize;
long long _currSize;
bool _draining;
bool _hasOpsQueued;
set<string> _tags;
}; };
struct BalancerPolicy::ChunkInfo { struct MigrateInfo {
const string ns; const string ns;
const string to; const string to;
const string from; const string from;
const BSONObj chunk; const ChunkInfo chunk;
ChunkInfo( const string& a_ns , const string& a_to , const string& a_from , const BSONObj& a_chunk ) MigrateInfo( const string& a_ns , const string& a_to , const string & a_from , const BSONObj& a_chunk )
: ns( a_ns ) , to( a_to ) , from( a_from ), chunk( a_chunk ) {} : ns( a_ns ) , to( a_to ) , from( a_from ), chunk( a_chunk ) {}
}; };
/** typedef map< string,ShardInfo > ShardInfoMap;
* Field names used in the 'limits' map. typedef map< string,vector<BSONObj> > ShardToChunksMap;
*/
struct LimitsFields { class DistributionStatus : boost::noncopyable {
// we use 'draining' and 'maxSize' from the 'shards' collection plu public:
s the following DistributionStatus( const ShardInfoMap& shardInfo,
static BSONField<long long> currSize; // currently used disk space const ShardToChunksMap& shardToChunksMap );
in bytes
static BSONField<bool> hasOpsQueued; // writeback queue is not emp // only used when building
ty?
/**
* @return if range is valid
*/
bool addTagRange( const TagRange& range );
// ---- these methods might be better suiting in BalancerPolicy
/**
* @param forTag "" if you don't care, or a tag
* @return shard best suited to receive a chunk
*/
string getBestReceieverShard( const string& forTag ) const;
/**
* @return the shard with the most chunks
* based on # of chunks with the given tag
*/
string getMostOverloadedShard( const string& forTag ) const;
// ---- basic accessors, counters, etc...
/** @return total number of chunks */
unsigned totalChunks() const;
/** @return number of chunks in this shard */
unsigned numberOfChunksInShard( const string& shard ) const;
/** @return number of chunks in this shard with the given tag */
unsigned numberOfChunksInShardWithTag( const string& shard, const s
tring& tag ) const;
/** @return chunks for the shard */
const vector<BSONObj>& getChunks( const string& shard ) const;
/** @return all tags we know about, not include "" */
const set<string>& tags() const { return _allTags; }
/** @return the right tag for chunk, possibly "" */
string getTagForChunk( const BSONObj& chunk ) const;
/** @return all shards we know about */
const set<string>& shards() const { return _shards; }
/** @return the ShardInfo for the shard */
const ShardInfo& shardInfo( const string& shard ) const;
/** writes all state to log() */
void dump() const;
private:
const ShardInfoMap& _shardInfo;
const ShardToChunksMap& _shardChunks;
map<BSONObj,TagRange> _tagRanges;
set<string> _allTags;
set<string> _shards;
};
class BalancerPolicy {
public:
/**
* Returns a suggested chunk to move whithin a collection's shards,
given information about
* space usage and number of chunks for that collection. If the pol
icy doesn't recommend
* moving, it returns NULL.
*
* @param ns is the collections namepace.
* @param DistributionStatus holds all the info about the current s
tate of the cluster/namespace
* @param balancedLastTime is the number of chunks effectively move
d in the last round.
* @returns NULL or MigrateInfo of the best move to make towards ba
lacing the collection.
* caller owns the MigrateInfo instance
*/
static MigrateInfo* balance( const string& ns,
const DistributionStatus& distribution
,
int balancedLastTime );
}; };
} // namespace mongo } // namespace mongo
#endif // S_BALANCER_POLICY_HEADER #endif // S_BALANCER_POLICY_HEADER
 End of changes. 18 change blocks. 
57 lines changed or deleted 146 lines changed or added


 basic.h   basic.h 
// basic.h // basic.h
#pragma once #pragma once
#ifdef _WIN32 #ifdef _WIN32
#include "windows_basic.h" #include "windows_basic.h"
#endif #endif
#if defined(__linux__) #if defined(__linux__)
#include <cstring>
// glibc's optimized versions are better than g++ builtins // glibc's optimized versions are better than g++ builtins
# define __builtin_strcmp strcmp # define __builtin_strcmp strcmp
# define __builtin_strlen strlen # define __builtin_strlen strlen
# define __builtin_memchr memchr # define __builtin_memchr memchr
# define __builtin_memcmp memcmp # define __builtin_memcmp memcmp
# define __builtin_memcpy memcpy # define __builtin_memcpy memcpy
# define __builtin_memset memset # define __builtin_memset memset
# define __builtin_memmove memmove # define __builtin_memmove memmove
#endif #endif
 End of changes. 1 change blocks. 
0 lines changed or deleted 3 lines changed or added


 bench.h   bench.h 
skipping to change at line 230 skipping to change at line 230
bool error; bool error;
unsigned long long errCount; unsigned long long errCount;
BenchRunEventCounter findOneCounter; BenchRunEventCounter findOneCounter;
BenchRunEventCounter updateCounter; BenchRunEventCounter updateCounter;
BenchRunEventCounter insertCounter; BenchRunEventCounter insertCounter;
BenchRunEventCounter deleteCounter; BenchRunEventCounter deleteCounter;
BenchRunEventCounter queryCounter; BenchRunEventCounter queryCounter;
std::map<std::string, long long> opcounters;
std::vector<BSONObj> trappedErrors; std::vector<BSONObj> trappedErrors;
}; };
/** /**
* State of a BenchRun activity. * State of a BenchRun activity.
* *
* Logically, the states are "starting up", "running" and "finished." * Logically, the states are "starting up", "running" and "finished."
*/ */
class BenchRunState : private boost::noncopyable { class BenchRunState : private boost::noncopyable {
public: public:
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 bson-inl.h   bson-inl.h 
skipping to change at line 33 skipping to change at line 33
#include <map> #include <map>
#include <limits> #include <limits>
#if defined(_WIN32) #if defined(_WIN32)
#undef max #undef max
#undef min #undef min
#endif #endif
namespace mongo { namespace mongo {
inline bool isNaN(double d) {
return d != d;
}
inline bool isInf(double d, int* sign = 0) {
volatile double tmp = d;
if ((tmp == d) && ((tmp - d) != 0.0)) {
if ( sign ) {
*sign = (d < 0.0 ? -1 : 1);
}
return true;
}
if ( sign ) {
*sign = 0;
}
return false;
}
/* must be same type when called, unless both sides are #s /* must be same type when called, unless both sides are #s
this large function is in header to facilitate inline-only use of bs on this large function is in header to facilitate inline-only use of bs on
*/ */
inline int compareElementValues(const BSONElement& l, const BSONElement & r) { inline int compareElementValues(const BSONElement& l, const BSONElement & r) {
int f; int f;
switch ( l.type() ) { switch ( l.type() ) {
case EOO: case EOO:
case Undefined: // EOO and Undefined are same canonicalType case Undefined: // EOO and Undefined are same canonicalType
case jstNULL: case jstNULL:
skipping to change at line 159 skipping to change at line 138
return c; return c;
return strcmp(l.regexFlags(), r.regexFlags()); return strcmp(l.regexFlags(), r.regexFlags());
} }
case CodeWScope : { case CodeWScope : {
f = l.canonicalType() - r.canonicalType(); f = l.canonicalType() - r.canonicalType();
if ( f ) if ( f )
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.codeWScopeScopeDataUnsafe() , r.codeWScopeScopeDa taUnsafe() );
if ( f ) if ( f )
return f; return f;
return 0; return 0;
} }
default: default:
verify( false); verify( false);
} }
return -1; return -1;
} }
 End of changes. 2 change blocks. 
22 lines changed or deleted 1 lines changed or added


 bson.h   bson.h 
skipping to change at line 47 skipping to change at line 47
#error this header is for client programs, not the mongo database itself. i nclude jsobj.h instead. #error this header is for client programs, not the mongo database itself. i nclude jsobj.h instead.
/* because we define simplistic assert helpers here that don't pull in a bu nch of util -- so that /* because we define simplistic assert helpers here that don't pull in a bu nch of util -- so that
BSON can be used header only. BSON can be used header only.
*/ */
#endif #endif
#include <cstdlib> #include <cstdlib>
#include <memory> #include <memory>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
//#include <boost/utility.hpp>
#include "mongo/platform/compiler.h"
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 std::string& s ) assertion( unsigned u , const std::string& s )
: id( u ) , msg( s ) { : id( u ) , msg( s ) {
skipping to change at line 82 skipping to change at line 83
namespace mongo { namespace mongo {
#if !defined(verify) #if !defined(verify)
inline void verify(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) { MONGO_COMPILER_NORETURN inline void uasserted(int msgid, const std::str ing &s) {
throw bson::assertion( msgid , s ); throw bson::assertion( msgid , s );
} }
inline void uassert(unsigned msgid, std::string msg, bool expr) { inline void uassert(unsigned msgid, std::string msg, bool expr) {
if( !expr ) if( !expr )
uasserted( msgid , msg ); uasserted( msgid , msg );
} }
inline void msgasserted(int msgid, const char *msg) { MONGO_COMPILER_NORETURN inline void msgasserted(int msgid, const char * msg) {
throw bson::assertion( msgid , msg ); throw bson::assertion( msgid , msg );
} }
inline void msgasserted(int msgid, const std::string &msg) { msgasserte MONGO_COMPILER_NORETURN inline void msgasserted(int msgid, const std::s
d(msgid, msg.c_str()); } tring &msg) {
inline void massert(unsigned msgid, std::string msg, bool expr) { msgasserted(msgid, msg.c_str());
}
inline void massert(int msgid, std::string msg, bool expr) {
if(!expr) { if(!expr) {
std::cout << "assertion failure in bson library: " << msgid << ' ' << msg << std::endl; std::cout << "assertion failure in bson library: " << msgid << ' ' << msg << std::endl;
throw bson::assertion( msgid , msg ); throw bson::assertion( msgid , msg );
} }
} }
#endif #endif
} }
#include "util/builder.h" #include "mongo/bson/bsonelement.h"
#include "bsontypes.h" #include "mongo/bson/bsonobj.h"
#include "oid.h" #include "mongo/bson/bsonobjbuilder.h"
#include "bsonelement.h" #include "mongo/bson/bsonobjiterator.h"
#include "bsonobj.h" #include "mongo/bson/bsontypes.h"
#include "bsonobjbuilder.h" #include "mongo/bson/bson-inl.h"
#include "bsonobjiterator.h" #include "mongo/bson/oid.h"
#include "bson-inl.h" #include "mongo/bson/util/builder.h"
 End of changes. 5 change blocks. 
6 lines changed or deleted 9 lines changed or added


 bsonelement.h   bsonelement.h 
// BSONElement // bsonelement.h
/* Copyright 2009 10gen Inc. /* Copyright 2009 10gen Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include <string.h> // strlen
#include <string>
#include <vector> #include <vector>
#include <string.h>
#include "util/builder.h" #include "mongo/bson/bsontypes.h"
#include "bsontypes.h" #include "mongo/bson/oid.h"
#include "oid.h" #include "mongo/platform/float_utils.h"
namespace mongo { namespace mongo {
class OpTime; class OpTime;
class BSONObj; class BSONObj;
class BSONElement; class BSONElement;
class BSONObjBuilder; class BSONObjBuilder;
} }
namespace bson { namespace bson {
typedef mongo::BSONElement be; typedef mongo::BSONElement be;
skipping to change at line 76 skipping to change at line 78
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 (); }
std::vector<BSONElement> Array() const; // see implementation for d etailed 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 object is out of scope, this pointer will no longer be valid. C
ll getOwned() on the all 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.
*/ */
BSONObj Obj() const; BSONObj Obj() const;
/** 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(); }
skipping to change at line 146 skipping to change at line 148
/** field name of the element. e.g., for /** field name of the element. e.g., for
name : "Joe" name : "Joe"
"name" is the fieldname "name" is the fieldname
*/ */
const char * fieldName() const { const char * fieldName() const {
if ( eoo() ) return ""; // no fieldname for it. if ( eoo() ) return ""; // no fieldname for it.
return data + 1; return data + 1;
} }
int fieldNameSize() const {
if ( fieldNameSize_ == -1 )
fieldNameSize_ = (int)strlen( fieldName() ) + 1;
return fieldNameSize_;
}
/** raw data of the element's value (so be careful). */ /** raw data of the element's value (so be careful). */
const char * value() const { const char * value() const {
return (data + fieldNameSize() + 1); return (data + fieldNameSize() + 1);
} }
/** size in bytes of the element's value (when applicable). */ /** size in bytes of the element's value (when applicable). */
int valuesize() const { int valuesize() const {
return size() - fieldNameSize() - 1; return size() - fieldNameSize() - 1;
} }
bool isBoolean() const { return type() == mongo::Bool; } bool isBoolean() const { return type() == mongo::Bool; }
skipping to change at line 194 skipping to change at line 202
/** 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 Packe dDouble* >( value() ))->d; } 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 /** Retrieve long value for the element safely. Zero returned if n
ot a number. */ ot a number.
* Behavior is not defined for double values that are NaNs, or too
large/small
* to be represented by long longs */
long long numberLong() const; long long numberLong() const;
/** Like numberLong() but with well-defined behavior for doubles th
at
* are NaNs, or too large/small to be represented as long longs.
* NaNs -> 0
* very large doubles -> LLONG_MAX
* very small doubles -> LLONG_MIN */
long long safeNumberLong() 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.
Note: casts to double, data loss may occur with large (>52 bit) NumberLong values. Note: casts to double, data loss may occur with large (>52 bit) NumberLong values.
*/ */
double numberDouble() const; double numberDouble() 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.
Note: casts to double, data loss may occur with large (>52 bit) NumberLong values. Note: casts to double, data loss may occur with large (>52 bit) NumberLong values.
*/ */
double number() const { return numberDouble(); } double number() const { return numberDouble(); }
/** Retrieve the object ID stored in the object. /** Retrieve the object ID stored in the object.
skipping to change at line 245 skipping to change at line 263
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 " ". */
std::string str() const { std::string str() const {
return type() == mongo::String ? std::string(valuestr(), values trsize()-1) : std::string(); return type() == mongo::String ? std::string(valuestr(), values 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; massert( 16177 , "not codeWScope" , type() == CodeWScope );
return value() + 4 + 4; //two ints precede code (see BSON spec)
} }
/** Get the scope SavedContext of a CodeWScope data element. */
const char * codeWScopeScopeData() const { /** Get length of the code part of the CodeWScope object
// TODO fix * This INCLUDES the null char at the end */
int codeWScopeCodeLen() const {
massert( 16178 , "not codeWScope" , type() == CodeWScope );
return *(int *)( value() + 4 );
}
/** Get the scope SavedContext of a CodeWScope data element.
*
* This function is DEPRECATED, since it can error if there are
* null chars in the codeWScopeCode. However, some existing indexe
s
* may be based on an incorrect ordering derived from this functio
n,
* so it may still need to be used in certain cases.
* */
const char * codeWScopeScopeDataUnsafe() const {
//This can error if there are null chars in the codeWScopeCode
return codeWScopeCode() + strlen( codeWScopeCode() ) + 1; return codeWScopeCode() + strlen( codeWScopeCode() ) + 1;
} }
/* Get the scope SavedContext of a CodeWScope data element.
*
* This is the corrected version of codeWScopeScopeDataUnsafe(),
* but note that existing uses might rely on the behavior of
* that function so be careful in choosing which version to use.
*/
const char * codeWScopeScopeData() const {
return codeWScopeCode() + codeWScopeCodeLen();
}
/** Get the embedded object this element holds. */ /** Get the embedded object this element holds. */
BSONObj embeddedObject() const; BSONObj embeddedObject() const;
/* uasserts if not an object */ /* uasserts if not an object */
BSONObj embeddedObjectUserCheck() const; BSONObj embeddedObjectUserCheck() const;
BSONObj codeWScopeObject() const; BSONObj codeWScopeObject() const;
/** Get 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 {
skipping to change at line 415 skipping to change at line 458
totalSize = 1; totalSize = 1;
} }
} }
std::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 {
if ( fieldNameSize_ == -1 )
fieldNameSize_ = (int)strlen( fieldName() ) + 1;
return fieldNameSize_;
}
mutable int totalSize; /* caches the computed size */ mutable int totalSize; /* caches the computed size */
friend class BSONObjIterator; friend class BSONObjIterator;
friend class BSONObj; friend class BSONObj;
const BSONElement& chk(int t) const { const BSONElement& chk(int t) const {
if ( t != type() ) { if ( t != type() ) {
StringBuilder ss; StringBuilder ss;
if( eoo() ) if( eoo() )
ss << "field not found, expected type " << t; ss << "field not found, expected type " << t;
else else
skipping to change at line 575 skipping to change at line 614
return (long long) _numberDouble(); return (long long) _numberDouble();
case NumberInt: case NumberInt:
return _numberInt(); return _numberInt();
case NumberLong: case NumberLong:
return _numberLong(); return _numberLong();
default: default:
return 0; return 0;
} }
} }
/** Like numberLong() but with well-defined behavior for doubles that
* are NaNs, or too large/small to be represented as long longs.
* NaNs -> 0
* very large doubles -> LLONG_MAX
* very small doubles -> LLONG_MIN */
inline long long BSONElement::safeNumberLong() const {
double d;
switch( type() ) {
case NumberDouble:
d = numberDouble();
if ( isNaN( d ) ){
return 0;
}
if ( d > (double) std::numeric_limits<long long>::max() ){
return std::numeric_limits<long long>::max();
}
if ( d < std::numeric_limits<long long>::min() ){
return std::numeric_limits<long long>::min();
}
default:
return numberLong();
}
}
inline BSONElement::BSONElement() { inline BSONElement::BSONElement() {
static char z = 0; static char z = 0;
data = &z; data = &z;
fieldNameSize_ = 0; fieldNameSize_ = 0;
totalSize = 1; totalSize = 1;
} }
} }
 End of changes. 13 change blocks. 
22 lines changed or deleted 89 lines changed or added


 bsonmisc.h   bsonmisc.h 
skipping to change at line 20 skipping to change at line 20
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "mongo/bson/bsonelement.h"
namespace mongo { namespace mongo {
int getGtLtOp(const BSONElement& e); int getGtLtOp(const BSONElement& e);
struct BSONElementCmpWithoutField { struct BSONElementCmpWithoutField {
bool operator()( const BSONElement &l, const BSONElement &r ) const { bool operator()( const BSONElement &l, const BSONElement &r ) const {
return l.woCompare( r, false ) < 0; return l.woCompare( r, false ) < 0;
} }
}; };
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 bsonobj.h   bsonobj.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/noncopyable.hpp>
#include <boost/intrusive_ptr.hpp> #include <boost/intrusive_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <set> #include <set>
#include <list> #include <list>
#include <string>
#include <vector> #include <vector>
#include "util/atomic_int.h"
#include "util/builder.h" #include "mongo/bson/bsonelement.h"
#include "stringdata.h" #include "mongo/bson/stringdata.h"
#include "mongo/bson/util/atomic_int.h"
#include "mongo/bson/util/builder.h"
namespace mongo { namespace mongo {
typedef std::set< BSONElement, BSONElementCmpWithoutField > BSONElement Set; typedef std::set< BSONElement, BSONElementCmpWithoutField > BSONElement Set;
typedef std::multiset< BSONElement, BSONElementCmpWithoutField > BSONEl ementMSet; 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.
skipping to change at line 91 skipping to change at line 94
/** Construct a BSONObj from data in the proper format. /** Construct a BSONObj from data in the proper format.
* Use this constructor when you want BSONObj to free(holder) when it is no longer needed * Use this constructor when you want BSONObj to free(holder) when it is no longer needed
* BSONObj::Holder has an extra 4 bytes for a ref-count before the start of the object * BSONObj::Holder has an extra 4 bytes for a ref-count before the start of the object
*/ */
class Holder; class Holder;
explicit BSONObj(Holder* holder) { explicit BSONObj(Holder* holder) {
init(holder); init(holder);
} }
explicit BSONObj(const Record *r);
/** Construct an empty BSONObj -- that is, {}. */ /** Construct an empty BSONObj -- that is, {}. */
BSONObj(); BSONObj();
static BSONObj make( const Record* r );
~BSONObj() { ~BSONObj() {
_objdata = 0; // defensive _objdata = 0; // defensive
} }
/** /**
A BSONObj can use a buffer it "owns" or one it does not. A BSONObj can use a buffer it "owns" or one it does not.
OWNED CASE OWNED CASE
If the BSONObj owns the buffer, the buffer can be shared among s everal BSONObj's (by assignment). If the BSONObj owns the buffer, the buffer can be shared among s everal BSONObj's (by assignment).
In this case the buffer is basically implemented as a shared_ptr . In this case the buffer is basically implemented as a shared_ptr .
skipping to change at line 242 skipping to change at line 245
BSONObj getObjectField(const char *name) const; BSONObj getObjectField(const char *name) const;
/** @return INT_MIN if not present - does some type conversions */ /** @return INT_MIN if not present - does some type conversions */
int getIntField(const char *name) const; int getIntField(const char *name) const;
/** @return false if not present /** @return false if not present
@see BSONElement::trueValue() @see BSONElement::trueValue()
*/ */
bool getBoolField(const char *name) const; bool getBoolField(const char *name) const;
/** /** @param pattern a BSON obj indicating a set of (un-dotted) field
sets element field names to empty string * names. Element values are ignored.
If a field in pattern is missing, it is omitted from the returne * @return a BSON obj constructed by taking the elements of this o
d bj
object. * that correspond to the fields in pattern. Field names of the
* returned object are replaced with the empty string. If field in
* pattern is missing, it is omitted from the returned object.
*
* Example: if this = {a : 4 , b : 5 , c : 6})
* this.extractFieldsUnDotted({a : 1 , c : 1}) -> {"" : 4 , "" :
6 }
* this.extractFieldsUnDotted({b : "blah"}) -> {"" : 5}
*
*/ */
BSONObj extractFieldsUnDotted(BSONObj pattern) const; BSONObj extractFieldsUnDotted(const BSONObj& pattern) const;
/** extract items from object which match a pattern object. /** extract items from object which match a pattern object.
e.g., if pattern is { x : 1, y : 1 }, builds an 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
*/ */
BSONObj extractFields(const BSONObj &pattern , bool fillWithNull=fa lse) const; BSONObj extractFields(const BSONObj &pattern , bool fillWithNull=fa lse) const;
BSONObj filterFieldsUndotted(const BSONObj &filter, bool inFilter) const; BSONObj filterFieldsUndotted(const BSONObj &filter, bool inFilter) const;
skipping to change at line 316 skipping to change at line 326
bool operator>( const BSONObj& other ) const { return woCompare( ot her ) > 0; } bool operator>( const BSONObj& other ) const { return woCompare( ot her ) > 0; }
bool operator>=( const BSONObj& other ) const { return woCompare( o ther ) >= 0; } bool operator>=( const BSONObj& other ) const { return woCompare( o ther ) >= 0; }
/** /**
* @param useDotted whether to treat sort key fields as possibly do tted and expand into them * @param useDotted whether to treat sort key fields as possibly do tted and expand into them
*/ */
int woSortOrder( const BSONObj& r , const BSONObj& sortKey , bool u seDotted=false ) const; int woSortOrder( const BSONObj& r , const BSONObj& sortKey , bool u seDotted=false ) const;
bool equal(const BSONObj& r) const; bool equal(const BSONObj& r) const;
/**
* @param otherObj
* @return true if 'this' is a prefix of otherObj- in other words i
f
* otherObj contains the same field names and field vals in the sam
e
* order as 'this', plus optionally some additional elements.
*/
bool isPrefixOf( const BSONObj& otherObj ) const;
/** This is "shallow equality" -- ints and doubles won't match. fo r a /** This is "shallow equality" -- ints and doubles won't match. fo r a
deep equality test use woCompare (which is slower). deep equality test use woCompare (which is slower).
*/ */
bool binaryEqual(const BSONObj& r) const { bool binaryEqual(const BSONObj& r) const {
int os = objsize(); int os = objsize();
if ( os == r.objsize() ) { if ( os == r.objsize() ) {
return (os == 0 || memcmp(objdata(),r.objdata(),os)==0); return (os == 0 || memcmp(objdata(),r.objdata(),os)==0);
} }
return false; return false;
} }
 End of changes. 9 change blocks. 
12 lines changed or deleted 33 lines changed or added


 bsonobjbuilder.h   bsonobjbuilder.h 
skipping to change at line 25 skipping to change at line 25
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include <limits>
#include <cmath>
#include <boost/static_assert.hpp> #include <boost/static_assert.hpp>
#if defined(MONGO_EXPOSE_MACROS) #include <cmath>
#define verify MONGO_verify #include <limits>
#endif
#include "bsonelement.h" #include "mongo/bson/bsonelement.h"
#include "bsonobj.h" #include "mongo/bson/bsonobj.h"
#include "bsonmisc.h" #include "mongo/bson/bsonmisc.h"
#include "mongo/bson/bson_builder_base.h"
#if defined(_DEBUG) && defined(MONGO_EXPOSE_MACROS) #if defined(_DEBUG) && defined(MONGO_EXPOSE_MACROS)
#include "../util/log.h" #include "mongo/util/log.h"
#endif #endif
namespace mongo { namespace mongo {
#if defined(_WIN32) #if defined(_WIN32)
// warning: 'this' : used in base member initializer list // warning: 'this' : used in base member initializer list
#pragma warning( disable : 4355 ) #pragma warning( disable : 4355 )
#endif #endif
template<typename T> template<typename T>
skipping to change at line 90 skipping to change at line 90
} }
private: private:
std::string _name; std::string _name;
std::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 : public BSONBuilderBase, private boost::noncopyab le {
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
_b.skip(4); /*leave room for size field and ref-count*/ _b.skip(4); /*leave room for size field and ref-count*/
} }
/** @param baseBuilder construct a BSONObjBuilder using an existing BufBuilder /** @param baseBuilder construct a BSONObjBuilder using an existing BufBuilder
* This is for more efficient adding of subobjects/arrays. See doc s for subobjStart for example. * This is for more efficient adding of subobjects/arrays. See doc s for subobjStart for example.
*/ */
skipping to change at line 261 skipping to change at line 261
*/ */
BSONObjBuilder& appendNumber( const StringData& fieldName , int n ) { BSONObjBuilder& appendNumber( const StringData& fieldName , int n ) {
return append( fieldName , n ); return append( fieldName , n );
} }
BSONObjBuilder& appendNumber( const StringData& fieldName , double d ) { BSONObjBuilder& appendNumber( const StringData& fieldName , double d ) {
return append( fieldName , d ); return append( fieldName , d );
} }
BSONObjBuilder& appendNumber( const StringData& fieldName , size_t n ) { BSONObjBuilder& appendNumber( const StringData& fieldName , size_t n ) {
static size_t maxInt = (size_t)pow( 2.0 , 30.0 ); static const size_t maxInt = ( 1 << 30 );
if ( n < maxInt ) if ( n < maxInt )
append( fieldName , (int)n ); append( fieldName, static_cast<int>( n ) );
else else
append( fieldName , (long long)n ); append( fieldName, static_cast<long long>( n ) );
return *this; return *this;
} }
BSONObjBuilder& appendNumber( const StringData& fieldName , long lo BSONObjBuilder& appendNumber( const StringData& fieldName, long lon
ng l ) { g llNumber ) {
static long long maxInt = (int)pow( 2.0 , 30.0 ); static const long long maxInt = ( 1LL << 30 );
static long long maxDouble = (long long)pow( 2.0 , 40.0 ); static const long long maxDouble = ( 1LL << 40 );
long long x = l >= 0 ? l : -l;
if ( x < maxInt ) long long nonNegative = llNumber >= 0 ? llNumber : -llNumber;
append( fieldName , (int)l ); if ( nonNegative < maxInt )
else if ( x < maxDouble ) append( fieldName, static_cast<int>( llNumber ) );
append( fieldName , (double)l ); else if ( nonNegative < maxDouble )
append( fieldName, static_cast<double>( llNumber ) );
else else
append( fieldName , l ); append( fieldName, llNumber );
return *this; return *this;
} }
/** Append a double element */ /** Append a double element */
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;
} }
skipping to change at line 414 skipping to change at line 415
} }
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;
} }
/** Implements builder interface but no-op in ObjBuilder */
void appendNull() {
msgasserted(16234, "Invalid call to appendNull in BSONObj Build
er.");
}
/** Append a Null element to the object */ /** Append a Null element to the object */
BSONObjBuilder& appendNull( const StringData& fieldName ) { BSONObjBuilder& appendNull( const StringData& fieldName ) {
_b.appendNum( (char) jstNULL ); _b.appendNum( (char) jstNULL );
_b.appendStr( fieldName ); _b.appendStr( fieldName );
return *this; return *this;
} }
// Append an element that is less than all other keys. // Append an element that is less than all other keys.
BSONObjBuilder& appendMinKey( const StringData& fieldName ) { BSONObjBuilder& appendMinKey( const StringData& fieldName ) {
_b.appendNum( (char) MinKey ); _b.appendNum( (char) MinKey );
skipping to change at line 644 skipping to change at line 650
BSONObjBuilder& operator<<( const BSONFieldValue<T>& v ) { BSONObjBuilder& operator<<( const BSONFieldValue<T>& v ) {
append( v.name().c_str() , v.value() ); append( v.name().c_str() , v.value() );
return *this; return *this;
} }
BSONObjBuilder& operator<<( const BSONElement& e ){ BSONObjBuilder& operator<<( const BSONElement& e ){
append( e ); append( e );
return *this; return *this;
} }
bool isArray() const {
return false;
}
/** @return true if we are using our own bufbuilder, and not an alt ernate that was given to us in our constructor */ /** @return true if we are using our own bufbuilder, and not an alt ernate that was given to us in our constructor */
bool owned() const { return &_b == &_buf; } bool owned() const { return &_b == &_buf; }
BSONObjIterator iterator() const ; BSONObjIterator iterator() const ;
bool hasField( const StringData& name ) const ; bool hasField( const StringData& name ) const ;
int len() const { return _b.len(); } int len() const { return _b.len(); }
BufBuilder& bb() { return _b; } BufBuilder& bb() { return _b; }
skipping to change at line 682 skipping to change at line 692
BufBuilder _buf; BufBuilder _buf;
int _offset; int _offset;
BSONObjBuilderValueStream _s; BSONObjBuilderValueStream _s;
BSONSizeTracker * _tracker; BSONSizeTracker * _tracker;
bool _doneCalled; bool _doneCalled;
static const std::string numStrs[100]; // cache of 0 to 99 inclusiv e 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 : public BSONBuilderBase, private boost::noncopy able {
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>
BSONArrayBuilder& append(const T& x) { BSONArrayBuilder& append(const T& x) {
_b.append(num(), x); _b.append(num(), x);
return *this; return *this;
} }
BSONArrayBuilder& append(const BSONElement& e) { BSONArrayBuilder& append(const BSONElement& e) {
_b.appendAs(e, num()); _b.appendAs(e, num());
return *this; return *this;
} }
BSONArrayBuilder& operator<<(const BSONElement& e) {
return append(e);
}
template <typename T> template <typename T>
BSONArrayBuilder& operator<<(const T& x) { BSONArrayBuilder& operator<<(const T& x) {
return append(x); return append(x);
} }
void appendNull() { void appendNull() {
_b.appendNull(num()); _b.appendNull(num());
} }
/** /**
* destructive - ownership moves to returned BSONArray * destructive - ownership moves to returned BSONArray
* @return owned BSONArray * @return owned BSONArray
*/ */
BSONArray arr() { return BSONArray(_b.obj()); } BSONArray arr() { return BSONArray(_b.obj()); }
BSONObj obj() { return _b.obj(); }
BSONObj done() { return _b.done(); } BSONObj done() { return _b.done(); }
void doneFast() { _b.doneFast(); } void doneFast() { _b.doneFast(); }
BSONArrayBuilder& append(const StringData& name, int n) {
fill( name );
append( n );
return *this;
}
BSONArrayBuilder& append(const StringData& name, long long n) {
fill( name );
append( n );
return *this;
}
BSONArrayBuilder& append(const StringData& name, double n) {
fill( name );
append( n );
return *this;
}
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 > template < class T >
BSONArrayBuilder& append( const std::list< T >& vals ); BSONArrayBuilder& append( const std::list< T >& vals );
skipping to change at line 752 skipping to change at line 785
return _b.subarrayStart( num() ); return _b.subarrayStart( num() );
} }
// These should only be used where you really need interface compat ability with BSONObjBuilder // These should only be used where you really need interface compat ability with BSONObjBuilder
// Currently they are only used by update.cpp and it should probabl y stay that way // Currently they are only used by update.cpp and it should probabl y stay that way
BufBuilder &subobjStart( const StringData& name ) { BufBuilder &subobjStart( const StringData& name ) {
fill( name ); fill( name );
return _b.subobjStart( num() ); return _b.subobjStart( num() );
} }
BufBuilder &subarrayStart( const char *name ) { BufBuilder &subarrayStart( const StringData& name ) {
fill( name ); fill( name );
return _b.subarrayStart( num() ); return _b.subarrayStart( num() );
} }
void appendArray( const StringData& name, BSONObj subObj ) { BSONArrayBuilder& appendArray( const StringData& name, const BSONOb j& subObj ) {
fill( name ); fill( name );
_b.appendArray( num(), subObj ); _b.appendArray( num(), subObj );
return *this;
} }
void appendAs( const BSONElement &e, const char *name) { BSONArrayBuilder& appendAs( const BSONElement &e, const StringData& name) {
fill( name ); fill( name );
append( e ); append( e );
return *this;
}
bool isArray() const {
return true;
} }
int len() const { return _b.len(); } int len() const { return _b.len(); }
int arrSize() const { return _i; } int arrSize() const { return _i; }
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);
skipping to change at line 791 skipping to change at line 830
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 )
append( nullElt() ); appendNull();
}
static BSONElement nullElt() {
static BSONObj n = nullObj();
return n.firstElement();
}
static BSONObj nullObj() {
BSONObjBuilder _b;
_b.appendNull( "" );
return _b.obj();
} }
std::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 std::vector< T >& vals ) { inline BSONObjBuilder& BSONObjBuilder::append( const StringData& fieldN ame, const std::vector< T >& vals ) {
BSONObjBuilder arrBuilder; BSONObjBuilder arrBuilder;
 End of changes. 21 change blocks. 
39 lines changed or deleted 68 lines changed or added


 bsonobjiterator.h   bsonobjiterator.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 <boost/preprocessor/cat.hpp> // like the ## operator but works wit h __LINE__ #include <boost/preprocessor/cat.hpp> // like the ## operator but works wit h __LINE__
#include "mongo/bson/bsonobj.h"
namespace mongo { namespace mongo {
/** iterator for a BSONObj /** iterator for a BSONObj
Note each BSONObj ends with an EOO element: so you will get more() o n an empty Note each BSONObj ends with an EOO element: so you will get more() o n an empty
object, although next().eoo() will be true. object, although next().eoo() will be true.
The BSONObj must stay in scope for the duration of the iterator's ex ecution. The BSONObj must stay in scope for the duration of the iterator's ex ecution.
todo: we may want to make a more stl-like iterator interface for thi s todo: we may want to make a more stl-like iterator interface for thi s
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 bsontypes.h   bsontypes.h 
skipping to change at line 20 skipping to change at line 20
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "util/misc.h"
namespace bson { } namespace bson { }
namespace mongo { namespace mongo {
class BSONArrayBuilder; class BSONArrayBuilder;
class BSONElement; class BSONElement;
class BSONObj; class BSONObj;
class BSONObjBuilder; class BSONObjBuilder;
class BSONObjBuilderValueStream; class BSONObjBuilderValueStream;
class BSONObjIterator; class BSONObjIterator;
skipping to change at line 100 skipping to change at line 98
/* subtypes of BinData. /* subtypes of BinData.
bdtCustom and above are ones that the JS compiler understands, but a re bdtCustom and above are ones that the JS compiler understands, but a re
opaque to the database. opaque to the database.
*/ */
enum BinDataType { enum BinDataType {
BinDataGeneral=0, BinDataGeneral=0,
Function=1, Function=1,
ByteArrayDeprecated=2, /* use BinGeneral instead */ ByteArrayDeprecated=2, /* use BinGeneral instead */
bdtUUID = 3, /* deprecated */ bdtUUID = 3, /* deprecated */
newUUID=4, /* language-independent UUID format across all drivers */ newUUID=4, /* language-independent UUID format across all drivers * /
MD5Type=5, MD5Type=5,
bdtCustom=128 bdtCustom=128
}; };
} }
 End of changes. 2 change blocks. 
3 lines changed or deleted 1 lines changed or added


 btree.h   btree.h 
skipping to change at line 1018 skipping to change at line 1018
* position after a write (checkLoc()). A recorded btree position cons ists of a btree bucket, * 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 * 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 * 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, * 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 * 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 * search. If the recorded btree bucket is invalidated, the initial re corded bucket check is
* not attempted (see SERVER-4575). * not attempted (see SERVER-4575).
*/ */
class BtreeCursor : public Cursor { class BtreeCursor : public Cursor {
protected: protected:
BtreeCursor( NamespaceDetails* nsd , int theIndexNo, const IndexDet
ails& idxDetails );
/*
BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int direction ); BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int direction );
BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails& _id, BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails& _id,
const shared_ptr< FieldRangeVector > &_bounds, int sing leIntervalLimit, const shared_ptr< FieldRangeVector > &_bounds, int sing leIntervalLimit,
int _direction ); int _direction );
*/
virtual void init( const BSONObj &startKey, const BSONObj &endKey,
bool endKeyInclusive, int direction );
virtual void init( const shared_ptr< FieldRangeVector > &_bounds, i
nt singleIntervalLimit, int _direction );
private:
void _finishConstructorInit();
static BtreeCursor* make( NamespaceDetails * nsd , int idxNo , cons
t IndexDetails& indexDetails );
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 ndexDetails& _id, static BtreeCursor* make( NamespaceDetails *_d, int _idxNo, const I ndexDetails& _id,
const shared_ptr< FieldRangeVector > &_bou nds, const shared_ptr< FieldRangeVector > &_bou nds,
int singleIntervalLimit, int _direction ); int singleIntervalLimit, int _direction );
skipping to change at line 1068 skipping to change at line 1079
verify( !bucket.isNull() ); verify( !bucket.isNull() );
const _KeyNode& kn = keyNode(keyOfs); const _KeyNode& kn = keyNode(keyOfs);
verify( 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 _order; }
virtual void aboutToDeleteBucket(const DiskLoc& b) { virtual void aboutToDeleteBucket(const DiskLoc& b) {
if ( bucket == b ) if ( bucket == b )
keyOfs = -1; keyOfs = -1;
} }
virtual DiskLoc currLoc() = 0; // { return !bucket.isNull() ? _cur rKeyNode().recordLoc : DiskLoc(); } virtual DiskLoc currLoc() = 0; // { return !bucket.isNull() ? _cur rKeyNode().recordLoc : DiskLoc(); }
virtual DiskLoc refLoc() { return currLoc(); } virtual DiskLoc refLoc() { return currLoc(); }
virtual Record* _current() { return currLoc().rec(); } virtual Record* _current() { return currLoc().rec(); }
virtual BSONObj current() { return BSONObj(_current()); } virtual BSONObj current() { return BSONObj::make(_current()); }
virtual string toString(); virtual string toString();
BSONObj prettyKey( const BSONObj &key ) const { BSONObj prettyKey( const BSONObj &key ) const {
return key.replaceFieldNames( indexDetails.keyPattern() ).clien tReadable(); return key.replaceFieldNames( indexDetails.keyPattern() ).clien tReadable();
} }
virtual BSONObj prettyIndexBounds() const; virtual 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; }
skipping to change at line 1132 skipping to change at line 1143
virtual DiskLoc _locate(const BSONObj& key, const DiskLoc& loc) = 0 ; virtual DiskLoc _locate(const BSONObj& key, const DiskLoc& loc) = 0 ;
virtual DiskLoc _advance(const DiskLoc& thisLoc, int& keyOfs, int d irection, const char *caller) = 0; virtual DiskLoc _advance(const DiskLoc& thisLoc, int& keyOfs, int d irection, const char *caller) = 0;
virtual void _advanceTo(DiskLoc &thisLoc, int &keyOfs, const BSONOb j &keyBegin, int keyBeginLen, bool afterKey, const vector< const BSONElemen t * > &keyEnd, const vector< bool > &keyEndInclusive, const Ordering &order , int direction ) = 0; virtual void _advanceTo(DiskLoc &thisLoc, int &keyOfs, const BSONOb j &keyBegin, int keyBeginLen, bool afterKey, const vector< const BSONElemen t * > &keyEnd, const vector< bool > &keyEndInclusive, const Ordering &order , int direction ) = 0;
/** set initial bucket */ /** set initial bucket */
void initWithoutIndependentFieldRanges(); void initWithoutIndependentFieldRanges();
/** if afterKey is true, we want the first key with values of the k eyBegin fields greater than keyBegin */ /** if afterKey is true, we want the first key with values of the k eyBegin fields greater than keyBegin */
void advanceTo( const BSONObj &keyBegin, int keyBeginLen, bool afte rKey, const vector< const BSONElement * > &keyEnd, const vector< bool > &ke yEndInclusive ); void advanceTo( const BSONObj &keyBegin, int keyBeginLen, bool afte rKey, const vector< const BSONElement * > &keyEnd, const vector< bool > &ke yEndInclusive );
set<DiskLoc> _dups; // these are set in the construtor
NamespaceDetails * const d; NamespaceDetails * const d;
const int idxNo; const int idxNo;
const IndexDetails& indexDetails;
// these are all set in init()
set<DiskLoc> _dups;
BSONObj startKey; BSONObj startKey;
BSONObj endKey; BSONObj endKey;
bool _endKeyInclusive; bool _endKeyInclusive;
bool _multikey; // this must be updated every getmore batch in case someone added a multikey bool _multikey; // this must be updated every getmore batch in case someone added a multikey
const IndexDetails& indexDetails; BSONObj _order; // this is the same as indexDetails.keyPattern()
const BSONObj _order; Ordering _ordering;
const Ordering _ordering;
DiskLoc bucket; DiskLoc bucket;
int keyOfs; int keyOfs;
const int _direction; // 1=fwd,-1=reverse int _direction; // 1=fwd,-1=reverse
BSONObj keyAtKeyOfs; // so we can tell if things moved around on us between the query and the getMore call BSONObj keyAtKeyOfs; // so we can tell if things moved around on us between the query and the getMore call
DiskLoc locAtKeyOfs; DiskLoc locAtKeyOfs;
const shared_ptr< FieldRangeVector > _bounds; 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; shared_ptr<Projection::KeyOnly> _keyFieldsOnly;
bool _independentFieldRanges; bool _independentFieldRanges;
long long _nscanned; long long _nscanned;
}; };
/** Renames the index namespace for this btree's index. */
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 {
verify( _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 ) );
} }
 End of changes. 10 change blocks. 
11 lines changed or deleted 26 lines changed or added


 builder.h   builder.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 <cfloat> #include <cfloat>
#include <string>
#include <sstream>
#include <iostream> #include <iostream>
#include <string.h> #include <sstream>
#include <stdio.h> #include <stdio.h>
#include "../inline_decls.h" #include <string>
#include "../stringdata.h" #include <string.h>
#include "mongo/bson/inline_decls.h"
#include "mongo/bson/stringdata.h"
namespace mongo { namespace mongo {
/* Accessing unaligned doubles on ARM generates an alignment trap and a borts with SIGBUS on Linux. /* 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. 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 The generated code for other architectures (which already allow unal igned accesses) is the same as if
there was a direct pointer access. there was a direct pointer access.
*/ */
struct PackedDouble { struct PackedDouble {
double d; double d;
} PACKED_DECL; } PACKED_DECL;
 End of changes. 3 change blocks. 
5 lines changed or deleted 6 lines changed or added


 chunk.h   chunk.h 
skipping to change at line 57 skipping to change at line 57
/** /**
config.chunks config.chunks
{ ns : "alleyinsider.fs.chunks" , min : {} , max : {} , server : "lo calhost:30001" } { ns : "alleyinsider.fs.chunks" , min : {} , max : {} , server : "lo calhost:30001" }
x is in a shard iff x is in a shard iff
min <= x < max min <= x < max
*/ */
class Chunk : boost::noncopyable { class Chunk : boost::noncopyable {
public: public:
Chunk( const ChunkManager * info , BSONObj from); Chunk( const ChunkManager * info , BSONObj from);
Chunk( const ChunkManager * info , const BSONObj& min, const BSONOb Chunk( const ChunkManager * info ,
j& max, const Shard& shard); const BSONObj& min,
const BSONObj& max,
const Shard& shard,
ShardChunkVersion lastmod = ShardChunkVersion() );
// //
// serialization support // serialization support
// //
void serialize(BSONObjBuilder& to, ShardChunkVersion myLastMod=0); void serialize(BSONObjBuilder& to, ShardChunkVersion myLastMod=Shar dChunkVersion(0,OID()));
// //
// chunk boundary support // chunk boundary support
// //
const BSONObj& getMin() const { return _min; } const BSONObj& getMin() const { return _min; }
const BSONObj& getMax() const { return _max; } const BSONObj& getMax() const { return _max; }
// if min/max key is pos/neg infinity // if min/max key is pos/neg infinity
bool minIsInf() const; bool minIsInf() const;
skipping to change at line 299 skipping to change at line 303
/* config.sharding /* config.sharding
{ ns: 'alleyinsider.fs.chunks' , { ns: 'alleyinsider.fs.chunks' ,
key: { ts : 1 } , key: { ts : 1 } ,
shards: [ { min: 1, max: 100, server: a } , { min: 101, max: 200 , server : b } ] shards: [ { min: 1, max: 100, server: a } , { min: 101, max: 200 , server : b } ]
} }
*/ */
class ChunkManager { class ChunkManager {
public: public:
typedef map<Shard,ShardChunkVersion> ShardVersionMap; typedef map<Shard,ShardChunkVersion> ShardVersionMap;
ChunkManager( string ns , ShardKeyPattern pattern , bool unique ); // Loads a new chunk manager from a collection document
ChunkManager( const BSONObj& collDoc );
// Creates an empty chunk manager for the namespace
ChunkManager( const string& ns, const ShardKeyPattern& pattern, boo
l unique );
// Updates a chunk manager based on an older manager
ChunkManager( ChunkManagerPtr oldManager );
string getns() const { return _ns; } string getns() const { return _ns; }
int numChunks() const { return _chunkMap.size(); } const ShardKeyPattern& getShardKey() const { return _key; }
bool hasShardKey( const BSONObj& obj ) const; bool hasShardKey( const BSONObj& obj ) const;
void createFirstChunks( const Shard& primary , vector<BSONObj>* ini bool isUnique() const { return _unique; }
tPoints , vector<Shard>* initShards ) const; // only call from DBConfig::sh
ardCollection /**
* this is just an increasing number of how many ChunkManagers we h
ave so we know if something has been updated
*/
unsigned long long getSequenceNumber() const { return _sequenceNumb
er; }
//
// After constructor is invoked, we need to call loadExistingRanges
. If this is a new
// sharded collection, we can call createFirstChunks first.
//
// Creates new chunks based on info in chunk manager
void createFirstChunks( const string& config,
const Shard& primary,
const vector<BSONObj>* initPoints,
const vector<Shard>* initShards );
// Loads existing ranges based on info in chunk manager
void loadExistingRanges( const string& config );
// Helpers for load
void calcInitSplitsAndShards( const Shard& primary,
const vector<BSONObj>* initPoints,
const vector<Shard>* initShards,
vector<BSONObj>* splitPoints,
vector<Shard>* shards ) const;
//
// Methods to use once loaded / created
//
int numChunks() const { return _chunkMap.size(); }
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; }
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;
/** @param shards set to the shards covered by the interval [min, m ax], see SERVER-4791 */ /** @param shards set to the shards covered by the interval [min, m ax], see SERVER-4791 */
void getShardsForRange(set<Shard>& shards, const BSONObj& min, cons t BSONObj& max, bool fullKeyReq = true) const; 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
*/ */
skipping to change at line 334 skipping to change at line 376
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;
bool compatibleWith( ChunkPtr other ) const { if( ! other ) return false; return compatibleWith( *other ); } bool compatibleWith( ChunkPtr other ) const { if( ! other ) return false; return compatibleWith( *other ); }
string toString() const; string toString() const;
ShardChunkVersion getVersion( const Shard& shard ) const; ShardChunkVersion getVersion( const Shard& shard ) const;
ShardChunkVersion getVersion() const; ShardChunkVersion getVersion() const;
/**
* this is just an increasing number of how many ChunkManagers we h
ave so we know if something has been updated
*/
unsigned long long getSequenceNumber() const { return _sequenceNumb
er; }
void getInfo( BSONObjBuilder& b ) const { void getInfo( BSONObjBuilder& b ) const {
b.append( "key" , _key.key() ); b.append( "key" , _key.key() );
b.appendBool( "unique" , _unique ); b.appendBool( "unique" , _unique );
_version.addEpochToBSON( b, "lastmod" );
} }
/** /**
* @param me - so i don't get deleted before i'm done * @param me - so i don't get deleted before i'm done
*/ */
void drop( ChunkManagerPtr me ) const; void drop( ChunkManagerPtr me ) const;
void _printChunks() const; void _printChunks() const;
int getCurrentDesiredChunkSize() const; int getCurrentDesiredChunkSize() const;
private:
ChunkManagerPtr reload(bool force=true) const; // doesn't modify se lf! ChunkManagerPtr reload(bool force=true) const; // doesn't modify se lf!
// helpers for constructor void markMinorForReload( ShardChunkVersion majorVersion ) const;
void _load(ChunkMap& chunks, set<Shard>& shards, ShardVersionMap& s void getMarkedMinorVersions( set<ShardChunkVersion>& minorVersions
hardVersions); ) const;
private:
// helpers for loading
// returns true if load was consistent
bool _load( const string& config, ChunkMap& chunks, set<Shard>& sha
rds,
ShardVersionMap& shardVersions, ChunkMa
nagerPtr oldManager);
static bool _isValid(const ChunkMap& chunks); static bool _isValid(const ChunkMap& chunks);
// end helpers
// All members should be const for thread-safety // All members should be const for thread-safety
const string _ns; const string _ns;
const ShardKeyPattern _key; const ShardKeyPattern _key;
const bool _unique; const bool _unique;
const ChunkMap _chunkMap; const ChunkMap _chunkMap;
const ChunkRangeManager _chunkRanges; const ChunkRangeManager _chunkRanges;
const set<Shard> _shards; const set<Shard> _shards;
const ShardVersionMap _shardVersions; // max version per shard const ShardVersionMap _shardVersions; // max version per shard
ShardChunkVersion _version; // max version of any chunk // max version of any chunk
ShardChunkVersion _version;
// the previous manager this was based on
// cleared after loading chunks
ChunkManagerPtr _oldManager;
mutable mutex _mutex; // only used with _nsLock mutable mutex _mutex; // only used with _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 // Split Heuristic info
//
class SplitHeuristics {
public:
SplitHeuristics() :
_splitTickets( maxParallelSplits ),
_staleMinorSetMutex( "SplitHeuristics::staleMinorSet" ),
_staleMinorCount( 0 ) {}
void markMinorForReload( const string& ns, ShardChunkVersion ma
jorVersion );
void getMarkedMinorVersions( set<ShardChunkVersion>& minorVersi
ons );
TicketHolder _splitTickets;
mutex _staleMinorSetMutex;
// mutex protects below
int _staleMinorCount;
set<ShardChunkVersion> _staleMinorSet;
// Test whether we should split once data * splitTestFactor > c
hunkSize (approximately)
static const int splitTestFactor = 5;
// Maximum number of parallel threads requesting a split
static const int maxParallelSplits = 5;
// The idea here is that we're over-aggressive on split testing
by a factor of
// splitTestFactor, so we can safely wait until we get to split
TestFactor invalid splits
// before changing. Unfortunately, we also potentially over-re
quest the splits by a
// factor of maxParallelSplits, but since the factors are ident
ical it works out
// (for now) for parallel or sequential oversplitting.
// TODO: Make splitting a separate thread with notifications?
static const int staleMinorReloadThreshold = maxParallelSplits;
};
mutable SplitHeuristics _splitHeuristics;
//
// End split heuristics
//
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 */ /** Just for testing */
friend class TestableChunkManager; friend class TestableChunkManager;
ChunkManager(); ChunkManager();
}; };
 End of changes. 14 change blocks. 
26 lines changed or deleted 126 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/db/lockstate.h"
#include "mongo/util/paths.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;
skipping to change at line 59 skipping to change at line 60
class PageFaultRetryableSection; class PageFaultRetryableSection;
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.
skipping to change at line 130 skipping to change at line 129
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; } void newTopLevelRequest() { _hasWrittenThisPass = false; }
bool allowedToThrowPageFaultException() const; bool allowedToThrowPageFaultException() const;
LockState& lockState() { return _ls; }
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 std::string _desc; 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;
LockState _ls;
friend class PageFaultRetryableSection; // TEMP friend class PageFaultRetryableSection; // TEMP
friend class NoPageFaultsAllowed; // TEMP
public: public:
/** the concept here is the same as MONGO_SOMETIMES. however that /** the concept here is the same as MONGO_SOMETIMES. however that
macro uses a static that will be shared by all threads, and eac h macro uses a static that will be shared by all threads, and eac h
time incremented it might eject that line from the other cpu ca ches (?), time incremented it might eject that line from the other cpu ca ches (?),
so idea is that this is better. so idea is that this is better.
*/ */
bool sometimes(unsigned howOften) { return ++_sometimes % howOften == 0; } bool sometimes(unsigned howOften) { return ++_sometimes % howOften == 0; }
/* set _god=true temporarily, safely */ /* set _god=true temporarily, safely */
skipping to change at line 238 skipping to change at line 242
void checkNotStale() const; void checkNotStale() const;
void checkNsAccess( bool doauth ); void checkNsAccess( bool doauth );
void checkNsAccess( bool doauth, int lockState ); 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;
Timer _timer;
}; // class Client::Context }; // class Client::Context
class WriteContext : boost::noncopyable { class WriteContext : boost::noncopyable {
public: public:
WriteContext(const string& ns, string path=dbpath, bool doauth= true ); WriteContext(const string& ns, string path=dbpath, bool doauth= true );
Context& ctx() { return _c; } Context& ctx() { return _c; }
private: private:
Lock::DBWrite _lk; Lock::DBWrite _lk;
Context _c; Context _c;
}; };
 End of changes. 7 change blocks. 
3 lines changed or deleted 9 lines changed or added


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


 client_common.h   client_common.h 
skipping to change at line 32 skipping to change at line 32
//#include "security.h" //#include "security.h"
#include "../util/net/hostandport.h" #include "../util/net/hostandport.h"
namespace mongo { namespace mongo {
class AuthenticationInfo; class AuthenticationInfo;
/** /**
* this is the base class for Client and ClientInfo * this is the base class for Client and ClientInfo
* Client is for mongod * Client is for mongod
* Client is for mongos * ClientInfo is for mongos
* They should converge slowly * They should converge slowly
* The idea is this has the basic api so that not all code has to be du plicated * The idea is this has the basic api so that not all code has to be du plicated
*/ */
class ClientBasic : boost::noncopyable { class ClientBasic : boost::noncopyable {
public: public:
virtual ~ClientBasic(){} virtual ~ClientBasic(){}
virtual const AuthenticationInfo * getAuthenticationInfo() const = 0; virtual const AuthenticationInfo * getAuthenticationInfo() const = 0;
virtual AuthenticationInfo * getAuthenticationInfo() = 0; virtual AuthenticationInfo * getAuthenticationInfo() = 0;
virtual bool hasRemote() const = 0; virtual bool hasRemote() const = 0;
 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 46 skipping to change at line 46
#include "diskloc.h" #include "diskloc.h"
#include "dbhelpers.h" #include "dbhelpers.h"
#include "matcher.h" #include "matcher.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 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 */
static const CursorId INVALID_CURSOR_ID = -1; // But see SERVER-5726.
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() ); }
static ByLocKey max( const DiskLoc& l ) { return ByLocKey( l , nume ric_limits<long long>::max() ); } static ByLocKey max( const DiskLoc& l ) { return ByLocKey( l , nume ric_limits<long long>::max() ); }
skipping to change at line 88 skipping to change at line 89
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 Pin : boost::noncopyable {
ClientCursor *_c;
public: public:
ClientCursor * c() { return _c; } Pin( long long cursorid ) :
void release() { _cursorid( INVALID_CURSOR_ID ) {
if( _c ) { recursive_scoped_lock lock( ccmutex );
verify( _c->_pinValue >= 100 ); ClientCursor *cursor = ClientCursor::find_inlock( cursorid,
_c->_pinValue -= 100; true );
_c = 0; if ( cursor ) {
uassert( 12051, "clientcursor already in use? driver pr
oblem?",
cursor->_pinValue < 100 );
cursor->_pinValue += 100;
_cursorid = cursorid;
} }
} }
/** void release() {
* call this if during a yield, the cursor got deleted ClientCursor *cursor = c();
* if so, we don't want to use the point address _cursorid = INVALID_CURSOR_ID;
*/ if ( cursor ) {
void deleted() { verify( cursor->_pinValue >= 100 );
_c = 0; cursor->_pinValue -= 100;
}
~Pointer() { release(); }
Pointer(long long cursorid) {
recursive_scoped_lock lock(ccmutex);
_c = ClientCursor::find_inlock(cursorid, true);
if( _c ) {
if( _c->_pinValue >= 100 ) {
_c = 0;
uasserted(12051, "clientcursor already in use? driv
er problem?");
}
_c->_pinValue += 100;
} }
} }
~Pin() { DESTRUCTOR_GUARD( release(); ) }
ClientCursor *c() const { return ClientCursor::find( _cursorid
); }
private:
CursorId _cursorid;
}; };
// This object assures safe and reliable cleanup of a ClientCursor. /** Assures safe and reliable cleanup of a ClientCursor. */
class CleanupPointer : boost::noncopyable { class Holder : boost::noncopyable {
public: public:
CleanupPointer() : _c( 0 ), _id( -1 ) {} Holder( ClientCursor *c = 0 ) :
_c( 0 ),
_id( INVALID_CURSOR_ID ) {
reset( c );
}
void reset( ClientCursor *c = 0 ) { void reset( ClientCursor *c = 0 ) {
if ( c == _c ) if ( c == _c )
return; return;
if ( _c ) { if ( _c ) {
// be careful in case cursor was deleted by someone els e // be careful in case cursor was deleted by someone els e
ClientCursor::erase( _id ); ClientCursor::erase( _id );
} }
if ( c ) { if ( c ) {
_c = c; _c = c;
_id = c->_cursorid; _id = c->_cursorid;
} }
else { else {
_c = 0; _c = 0;
_id = -1; _id = INVALID_CURSOR_ID;
} }
} }
~CleanupPointer() { ~Holder() {
DESTRUCTOR_GUARD ( reset(); ); DESTRUCTOR_GUARD ( reset(); );
} }
operator bool() { return _c; } operator bool() { return _c; }
ClientCursor * operator-> () { return _c; } ClientCursor * operator-> () { return _c; }
const ClientCursor * operator-> () const { return _c; }
/** Release ownership of the ClientCursor. */ /** Release ownership of the ClientCursor. */
void release() { void release() {
_c = 0; _c = 0;
_id = -1; _id = INVALID_CURSOR_ID;
} }
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.
*/ */
skipping to change at line 289 skipping to change at line 290
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; void fillQueryResultFromObj( BufBuilder &b, const MatchDetails* det ails = NULL ) 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; }
skipping to change at line 420 skipping to change at line 421
unsigned _pinValue; unsigned _pinValue;
bool _doingDeletes; // when true we are the delete and aboutToDelet e shouldn't manipulate us bool _doingDeletes; // when true we are the delete and aboutToDelet e shouldn't manipulate us
ElapsedTracker _yieldSometimesTracker; ElapsedTracker _yieldSometimesTracker;
ShardChunkManagerPtr _chunkManager; ShardChunkManagerPtr _chunkManager;
public: public:
shared_ptr<ParsedQuery> pq; shared_ptr<ParsedQuery> pq;
shared_ptr<Projection> fields; // which fields query wants returned shared_ptr<Projection> fields; // which fields query wants returned
// TODO Maybe helper objects should manage their own memory rather
than rely on the
// original message being valid.
Message originalMessage; // this is effectively an auto ptr for dat
a the matcher points to
private: // static members private: // static members
static CCById clientCursorsById; static CCById clientCursorsById;
static long long numberTimedOut; static long long numberTimedOut;
static boost::recursive_mutex& ccmutex; // must use this for all statics above! static boost::recursive_mutex& ccmutex; // must use this for all statics above!
static CursorId allocCursorId_inlock(); static CursorId allocCursorId_inlock();
}; };
skipping to change at line 445 skipping to change at line 443
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 // Instead of auto_ptr<>, which still requires some degree of manual manage ment
// of this, consider using ClientCursor::CleanupPointer which handles // of this, consider using ClientCursor::Holder which handles ClientCursor'
// ClientCursor's unusual self-deletion mechanics 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. 14 change blocks. 
40 lines changed or deleted 39 lines changed or added


 cloner.h   cloner.h 
skipping to change at line 25 skipping to change at line 25
* You should have received a copy of the GNU Affero General Public 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 "jsobj.h" #include "jsobj.h"
namespace mongo { namespace mongo {
struct CloneOptions {
CloneOptions() {
logForRepl = true;
slaveOk = false;
useReplAuth = false;
snapshot = true;
mayYield = true;
mayBeInterrupted = false;
syncData = true;
syncIndexes = true;
}
string fromDB;
set<string> collsToIgnore;
bool logForRepl;
bool slaveOk;
bool useReplAuth;
bool snapshot;
bool mayYield;
bool mayBeInterrupted;
bool syncData;
bool syncIndexes;
};
bool cloneFrom( const string& masterHost ,
const CloneOptions& options ,
string& errmsg /* out */ ,
int* errCode = 0 /* out */ ,
set<string>* clonedCollections = 0 /* out */ );
/** /**
* @param slaveOk - if true it is ok if the source of the data is ! ismaster. * @param slaveOk - if true it is ok if the source of the data is ! ismaster.
* @param useReplAuth - use the credentials we normally use as a replic ation slave for the cloning * @param useReplAuth - use the credentials we normally use as a replic ation slave for the cloning
* @param snapshot - use $snapshot mode for copying collections. no te this should not be used when it isn't required, as it will be slower. * @param snapshot - use $snapshot mode for copying collections. no te this should not be used when it isn't required, as it will be slower.
* for example repairDatabase need not use it. * for example repairDatabase need not use it.
* @param errCode - If provided, this will be set on error to the s erver's error code. Currently * @param errCode - If provided, this will be set on error to the s erver's error code. Currently
* this will only be set if there is an error in t he initial system.namespaces query. * this will only be set if there is an error in t he initial system.namespaces query.
*/ */
bool cloneFrom(const char *masterHost, string& errmsg, const string& fr omdb, bool logForReplication, bool cloneFrom(const char *masterHost, string& errmsg, const string& fr omdb, bool logForReplication,
bool slaveOk, bool useReplAuth, bool snapshot, bool mayY ield, bool slaveOk, bool useReplAuth, bool snapshot, bool mayY ield,
 End of changes. 1 change blocks. 
0 lines changed or deleted 34 lines changed or added


 cmdline.h   cmdline.h 
skipping to change at line 109 skipping to change at line 109
DurAlwaysRemap = 32, // remap the private view after every gro up commit (may lag to the next write lock acquisition, but will do all file s then) DurAlwaysRemap = 32, // remap the private view after every gro up commit (may lag to the next write lock acquisition, but will do all file s then)
DurNoCheckSpace = 64 // don't check that there is enough room for journal files before startup (for diskfull tests) DurNoCheckSpace = 64 // don't check that there is enough room for journal files before startup (for diskfull tests)
}; };
int durOptions; // --durOptions <n> for debugging int durOptions; // --durOptions <n> for debugging
bool objcheck; // --objcheck bool objcheck; // --objcheck
long long oplogSize; // --oplogSize long long oplogSize; // --oplogSize
int defaultProfile; // --profile int defaultProfile; // --profile
int slowMS; // --time in ms that is "slow" int slowMS; // --time in ms that is "slow"
int defaultLocalThresholdMillis; // --localThreshold in ms to co nsider a node local
int pretouch; // --pretouch for replication application (e xperimental) int pretouch; // --pretouch for replication application (e xperimental)
bool moveParanoia; // for move chunk paranoia bool moveParanoia; // for move chunk paranoia
double syncdelay; // seconds between fsyncs double syncdelay; // seconds between fsyncs
bool noUnixSocket; // --nounixsocket bool noUnixSocket; // --nounixsocket
bool doFork; // --fork bool doFork; // --fork
string socket; // UNIX domain socket directory string socket; // UNIX domain socket directory
bool keyFile; bool keyFile;
skipping to change at line 156 skipping to change at line 156
boost::program_options::options_description& vis ible, boost::program_options::options_description& vis ible,
boost::program_options::options_description& hid den, boost::program_options::options_description& hid den,
boost::program_options::positional_options_descr iption& positional, boost::program_options::positional_options_descr iption& positional,
boost::program_options::variables_map &output ); boost::program_options::variables_map &output );
time_t started; time_t started;
}; };
// todo move to cmdline.cpp? // todo move to cmdline.cpp?
inline CmdLine::CmdLine() : inline CmdLine::CmdLine() :
port(DefaultDBPort), rest(false), jsonp(false), quiet(false), noTab port(DefaultDBPort), rest(false), jsonp(false), quiet(false),
leScan(false), prealloc(true), preallocj(true), smallfiles(sizeof(int*) == noTableScan(false), prealloc(true), preallocj(true), smallfiles(siz
4), eof(int*) == 4),
configsvr(false), configsvr(false), quota(false), quotaFiles(8), cpu(false),
quota(false), quotaFiles(8), cpu(false), durOptions(0), objcheck(fa durOptions(0), objcheck(false), oplogSize(0), defaultProfile(0),
lse), oplogSize(0), defaultProfile(0), slowMS(100), pretouch(0), moveParano slowMS(100), defaultLocalThresholdMillis(10), pretouch(0), movePara
ia( true ), noia( true ),
syncdelay(60), noUnixSocket(false), doFork(0), socket("/tmp") syncdelay(60), noUnixSocket(false), doFork(0), socket("/tmp")
{ {
started = time(0); started = time(0);
journalCommitInterval = 0; // 0 means use default journalCommitInterval = 0; // 0 means use default
dur = false; dur = false;
#if defined(_DURABLEDEFAULTON) #if defined(_DURABLEDEFAULTON)
dur = true; dur = true;
#endif #endif
if( sizeof(void*) == 8 ) if( sizeof(void*) == 8 )
 End of changes. 2 change blocks. 
8 lines changed or deleted 8 lines changed or added


 compact.h   compact.h 
// compact.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/>.
*/ */
#pragma once #pragma once
#include "mongo/db/extsort.h"
namespace mongo { namespace mongo {
/** for bottom up fastbuildindex (where we presort keys) */ /** for bottom up fastbuildindex (where we presort keys) */
struct SortPhaseOne { struct SortPhaseOne {
SortPhaseOne() { SortPhaseOne() {
n = 0; n = 0;
nkeys = 0; nkeys = 0;
multi = false; multi = false;
} }
shared_ptr<BSONObjExternalSorter> sorter; shared_ptr<BSONObjExternalSorter> sorter;
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 config.h   config.h 
skipping to change at line 28 skipping to change at line 28
/* 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/model.h" #include "../client/model.h"
#include "mongo/client/dbclient_rs.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;
static string database; static string database;
static string collection; static string collection;
static string chunk; static string chunk;
static string tags;
static string mongos; static string mongos;
static string settings; static string settings;
}; };
/** /**
* Field names used in the 'shards' collection. * Field names used in the 'shards' collection.
*/ */
struct ShardFields { struct ShardFields {
static BSONField<bool> draining; // is it draining chunks? static BSONField<bool> draining; // is it draining chunks?
skipping to change at line 90 skipping to change at line 92
ChunkManagerPtr getCM() const { ChunkManagerPtr getCM() const {
return _cm; return _cm;
} }
void resetCM( ChunkManager * cm ) { void resetCM( ChunkManager * cm ) {
verify(cm); verify(cm);
verify(_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( ChunkManager* cm );
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 );
bool unique() const { return _unqiue; } bool unique() const { return _unqiue; }
BSONObj key() const { return _key; } BSONObj key() const { return _key; }
skipping to change at line 123 skipping to change at line 125
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" ) {
verify( name.size() ); verify( name.size() );
} }
virtual ~DBConfig() {} virtual ~DBConfig() {}
string getName() { return _name; }; string getName() const { 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;
} }
void enableSharding(); void enableSharding( bool save = true );
ChunkManagerPtr shardCollection( const string& ns , ShardKeyPattern fieldsAndOrder , bool unique , vector<BSONObj>* initPoints=0, vector<Shard >* initShards=0 ); ChunkManagerPtr shardCollection( const string& ns , ShardKeyPattern fieldsAndOrder , bool unique , vector<BSONObj>* initPoints=0, vector<Shard >* initShards=0 );
/** /**
@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
*/ */
 End of changes. 5 change blocks. 
3 lines changed or deleted 5 lines changed or added


 connections.h   connections.h 
skipping to change at line 50 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() {
x->cc.reset(new DBClientConnection(true, 0, 10)); connInfo->cc.reset(new DBClientConnection(true, 0, 10));
x->cc->_logLevel = 2; connInfo->cc->_logLevel = 2;
x->connected = false; connInfo->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 & bool runCommand(const string &dbname,
info, int options=0) { const BSONObj& cmd,
return conn()->runCommand(dbname, cmd, info, options); BSONObj &info,
int options=0,
const AuthenticationTable* auth=NULL) {
return conn()->runCommand(dbname, cmd, info, options, auth);
} }
unsigned long long count(const string &ns) { unsigned long long count(const string &ns) {
return conn()->count(ns); return conn()->count(ns);
} }
BSONObj findOne(const string &ns, const Query& q, const BSONObj *fi eldsToReturn = 0, int queryOptions = 0) { BSONObj findOne(const string &ns, const Query& q, const BSONObj *fi eldsToReturn = 0, int queryOptions = 0) {
return conn()->findOne(ns, q, fieldsToReturn, queryOptions); return conn()->findOne(ns, q, fieldsToReturn, queryOptions);
} }
private: private:
auto_ptr<scoped_lock> connLock; auto_ptr<scoped_lock> connLock;
static mongo::mutex mapMutex; static mongo::mutex mapMutex;
struct X { struct ConnectionInfo {
mongo::mutex z; mongo::mutex lock;
scoped_ptr<DBClientConnection> cc; scoped_ptr<DBClientConnection> cc;
bool connected; bool connected;
X() : z("X"), cc(new DBClientConnection(/*reconnect*/ true, 0, ConnectionInfo() : lock("ConnectionInfo"),
/*timeout*/ 10.0)), connected(false) { cc(new DBClientConnection(/*reconnect*/ true
, 0, /*timeout*/ 10.0)),
connected(false) {
cc->_logLevel = 2; cc->_logLevel = 2;
} }
} *x; } *connInfo;
typedef map<string,ScopedConn::X*> M; typedef map<string,ScopedConn::ConnectionInfo*> M;
static M& _map; static M& _map;
scoped_ptr<DBClientConnection>& conn() { return x->cc; } scoped_ptr<DBClientConnection>& conn() { return connInfo->cc; }
const string _hostport; const string _hostport;
// we should already be locked... // we should already be locked...
bool connect() { bool connect() {
string err; string err;
if (!x->cc->connect(_hostport, err)) { if (!connInfo->cc->connect(_hostport, err)) {
log() << "couldn't connect to " << _hostport << ": " << err << rsLog; log() << "couldn't connect to " << _hostport << ": " << err << rsLog;
return false; return false;
} }
x->connected = true; connInfo->connected = true;
// if we cannot authenticate against a member, then either its ke y file // if we cannot authenticate against a member, then either its ke y file
// or our key file has to change. if our key file has to change, we'll // or our key file has to change. if our key file has to change, we'll
// be rebooting. if their file has to change, they'll be rebooted so the // be rebooting. if their file has to change, they'll be rebooted so the
// connection created above will go dead, reconnect, and reauth. // connection created above will go dead, reconnect, and reauth.
if (!noauth && !x->cc->auth("local", internalSecurity.user, inter if (!noauth) {
nalSecurity.pwd, err, false)) { if (!connInfo->cc->auth("local",
log() << "could not authenticate against " << _hostport << ", " internalSecurity.user,
<< err << rsLog; internalSecurity.pwd,
return false; err,
false)) {
log() << "could not authenticate against " << _hostport <
< ", " << err << rsLog;
return false;
}
connInfo->cc->setAuthenticationTable(
AuthenticationTable::getInternalSecurityAuthenticatio
nTable() );
} }
return true; return true;
} }
}; };
inline ScopedConn::ScopedConn(string hostport) : _hostport(hostport) { inline ScopedConn::ScopedConn(string hostport) : _hostport(hostport) {
bool first = false; bool first = false;
{ {
scoped_lock lk(mapMutex); scoped_lock lk(mapMutex);
x = _map[_hostport]; connInfo = _map[_hostport];
if( x == 0 ) { if( connInfo == 0 ) {
x = _map[_hostport] = new X(); connInfo = _map[_hostport] = new ConnectionInfo();
first = true; first = true;
connLock.reset( new scoped_lock(x->z) ); connLock.reset( new scoped_lock(connInfo->lock) );
} }
} }
// already locked connLock above // already locked connLock above
if (first) { if (first) {
connect(); connect();
return; return;
} }
connLock.reset( new scoped_lock(x->z) ); connLock.reset( new scoped_lock(connInfo->lock) );
if (x->connected) { if (connInfo->connected) {
return; return;
} }
// Keep trying to connect if we're not yet connected // Keep trying to connect if we're not yet connected
connect(); connect();
} }
} }
 End of changes. 12 change blocks. 
26 lines changed or deleted 39 lines changed or added


 connpool.h   connpool.h 
skipping to change at line 59 skipping to change at line 59
void createdOne( DBClientBase * base ); void createdOne( DBClientBase * base );
long long numCreated() const { return _created; } long long numCreated() const { return _created; }
ConnectionString::ConnectionType type() const { verify(_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 );
// Deletes all connections in the pool
void clear();
void done( DBConnectionPool * pool , DBClientBase * c ); void done( DBConnectionPool * pool , DBClientBase * c );
void flush(); void flush();
void getStaleConnections( vector<DBClientBase*>& stale ); void getStaleConnections( vector<DBClientBase*>& stale );
static void setMaxPerHost( unsigned max ) { _maxPerHost = max; } static void setMaxPerHost( unsigned max ) { _maxPerHost = max; }
static unsigned getMaxPerHost() { return _maxPerHost; } static unsigned getMaxPerHost() { return _maxPerHost; }
private: private:
skipping to change at line 133 skipping to change at line 136
void flush(); void flush();
DBClientBase *get(const string& host, double socketTimeout = 0); DBClientBase *get(const string& host, double socketTimeout = 0);
DBClientBase *get(const ConnectionString& host, double socketTimeou t = 0); DBClientBase *get(const ConnectionString& host, double socketTimeou t = 0);
void release(const string& host, DBClientBase *c); void release(const string& host, DBClientBase *c);
void addHook( DBConnectionHook * hook ); // we take ownership void addHook( DBConnectionHook * hook ); // we take ownership
void appendInfo( BSONObjBuilder& b ); void appendInfo( BSONObjBuilder& b );
// Removes and deletes all connections from the pool for the host (
regardless of timeout)
void removeHost( const string& host );
/** compares server namees, but is smart about replica set names */ /** compares server namees, but is smart about replica set names */
struct serverNameCompare { struct serverNameCompare {
bool operator()( const string& a , const string& b ) const; bool operator()( const string& a , const string& b ) const;
}; };
virtual string taskName() const { return "DBConnectionPool-cleaner" ; } virtual string taskName() const { return "DBConnectionPool-cleaner" ; }
virtual void taskDoWork(); virtual void taskDoWork();
private: private:
DBConnectionPool( DBConnectionPool& p ); DBConnectionPool( DBConnectionPool& p );
skipping to change at line 201 skipping to change at line 207
private: private:
static AtomicUInt _numConnections; static AtomicUInt _numConnections;
}; };
/** Use to get a connection from the pool. On exceptions things /** Use to get a connection from the pool. On exceptions things
clean up nicely (i.e. the socket gets closed automatically when the clean up nicely (i.e. the socket gets closed automatically when the
scopeddbconnection goes out of scope). scopeddbconnection goes out of scope).
*/ */
class ScopedDbConnection : public AScopedConnection { class ScopedDbConnection : public AScopedConnection {
public: private:
/** the main constructor you want to use /** the main constructor you want to use
throws UserException if can't connect throws UserException if can't connect
*/ */
explicit ScopedDbConnection(const string& host, double socketTimeou t = 0) : _host(host), _conn( pool.get(host, socketTimeout) ), _socketTimeou t( socketTimeout ) { explicit ScopedDbConnection(const string& host, double socketTimeou t = 0) : _host(host), _conn( pool.get(host, socketTimeout) ), _socketTimeou t( socketTimeout ) {
_setSocketTimeout(); _setSocketTimeout();
} }
ScopedDbConnection() : _host( "" ) , _conn(0), _socketTimeout( 0 ) {} ScopedDbConnection() : _host( "" ) , _conn(0), _socketTimeout( 0 ) {}
/* @param conn - bind to an existing connection */ /* @param conn - bind to an existing connection */
ScopedDbConnection(const string& host, DBClientBase* conn, double s ocketTimeout = 0 ) : _host( host ) , _conn( conn ), _socketTimeout( socketT imeout ) { ScopedDbConnection(const string& host, DBClientBase* conn, double s ocketTimeout = 0 ) : _host( host ) , _conn( conn ), _socketTimeout( socketT imeout ) {
_setSocketTimeout(); _setSocketTimeout();
} }
public:
/** throws UserException if can't connect */ // Factory functions for getting ScopedDbConnections. The caller o
explicit ScopedDbConnection(const ConnectionString& url, double soc wns the resulting object
ketTimeout = 0 ) : _host(url.toString()), _conn( pool.get(url, socketTimeou // and is responsible for deleting it when finished. This should be
t) ), _socketTimeout( socketTimeout ) { used when running a
_setSocketTimeout(); // command on a shard from the mongos and the command should run wi
} th the client's
// authentication. If the command should be run with full permissi
ons regardless
// of whether or not the user is authorized, then use getInternalSc
opedDbConnection().
static ScopedDbConnection* getScopedDbConnection(const string& host
,
double socketTimeo
ut = 0);
static ScopedDbConnection* getScopedDbConnection();
/** throws UserException if can't connect */ // Gets a ScopedDbConnection designed to be used for internal commu
explicit ScopedDbConnection(const Shard& shard, double socketTimeou nication within a cluster
t = 0 ); // The mongod/mongos implementations of these set the Authenticatio
explicit ScopedDbConnection(const Shard* shard, double socketTimeou nTable on the underlying
t = 0 ); // connection to the internalSecurity permissions. All commands ru
n on the shard mongods
// using this connection will have full access. If the command sho
uld only be run on the
// shard if the client has permission to do so, then use getScopedD
bConnection().
// These functions should not be called by consumers of the C++ cli
ent library.
static ScopedDbConnection* getInternalScopedDbConnection(const stri
ng& host,
double soc
ketTimeout = 0);
static ScopedDbConnection* getInternalScopedDbConnection();
~ScopedDbConnection(); ~ScopedDbConnection();
/** get the associated connection object */ /** get the associated connection object */
DBClientBase* operator->() { DBClientBase* operator->() {
uassert( 11004 , "connection was returned to the pool already" , _conn ); uassert( 11004 , "connection was returned to the pool already" , _conn );
return _conn; return _conn;
} }
/** get the associated connection object */ /** get the associated connection object */
skipping to change at line 272 skipping to change at line 289
*/ */
void done() { void done() {
if ( ! _conn ) if ( ! _conn )
return; return;
/* we could do this, but instead of assume one is using autorec onnect mode on the connection /* we could do this, but instead of assume one is using autorec onnect mode on the connection
if ( _conn->isFailed() ) if ( _conn->isFailed() )
kill(); kill();
else else
*/ */
_conn->clearAuthenticationTable();
pool.release(_host, _conn); pool.release(_host, _conn);
_conn = 0; _conn = 0;
} }
ScopedDbConnection * steal();
private: private:
void _setSocketTimeout(); void _setSocketTimeout();
const string _host; const string _host;
DBClientBase *_conn; DBClientBase *_conn;
const double _socketTimeout; const double _socketTimeout;
}; };
 End of changes. 8 change blocks. 
14 lines changed or deleted 42 lines changed or added


 core.h   core.h 
skipping to change at line 507 skipping to change at line 507
double _x; double _x;
double _y; double _y;
}; };
extern const double EARTH_RADIUS_KM; extern const double EARTH_RADIUS_KM;
extern const double EARTH_RADIUS_MILES; extern const double EARTH_RADIUS_MILES;
// Technically lat/long bounds, not really tied to earth radius. // Technically lat/long bounds, not really tied to earth radius.
inline void checkEarthBounds( Point p ) { inline void checkEarthBounds( Point p ) {
uassert( 14808, str::stream() << "point " << p.toString() << " must uassert( 14808, str::stream() << "point " << p.toString() << " must
be in earth-like bounds of long : [-180, 180), lat : [-90, 90] ", be in earth-like bounds of long : [-180, 180], lat : [-90, 90] ",
p._x >= -180 && p._x < 180 && p._y >= -90 && p._y <= 90 ); p._x >= -180 && p._x <= 180 && p._y >= -90 && p._y <= 90 )
;
} }
inline double deg2rad(double deg) { return deg * (M_PI/180); } inline double deg2rad(double deg) { return deg * (M_PI/180); }
inline double rad2deg(double rad) { return rad * (180/M_PI); } inline double rad2deg(double rad) { return rad * (180/M_PI); }
// WARNING: _x and _y MUST be longitude and latitude in that order // WARNING: _x and _y MUST be longitude and latitude in that order
// note: multiply by earth radius for distance // note: multiply by earth radius for distance
inline double spheredist_rad( const Point& p1, const Point& p2 ) { inline double spheredist_rad( const Point& p1, const Point& p2 ) {
// this uses the n-vector formula: http://en.wikipedia.org/wiki/N-v ector // this uses the n-vector formula: http://en.wikipedia.org/wiki/N-v ector
// If you try to match the code to the formula, note that I inline the cross-product. // If you try to match the code to the formula, note that I inline the cross-product.
 End of changes. 1 change blocks. 
3 lines changed or deleted 4 lines changed or added


 count.h   count.h 
skipping to change at line 28 skipping to change at line 28
#include "../jsobj.h" #include "../jsobj.h"
#include "../diskloc.h" #include "../diskloc.h"
namespace mongo { namespace mongo {
/** /**
* { count: "collectionname"[, query: <query>] } * { count: "collectionname"[, query: <query>] }
* @return -1 on ns does not exist error and other errors, 0 on other e rrors, otherwise the match count. * @return -1 on ns does not exist error and other errors, 0 on other e rrors, otherwise the match count.
*/ */
long long runCount(const char *ns, const BSONObj& cmd, string& err); long long runCount(const char *ns, const BSONObj& cmd, string& err, int & errCode );
} // namespace mongo } // namespace mongo
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 counters.h   counters.h 
skipping to change at line 25 skipping to change at line 25
* 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 "../../util/net/message.h" #include "../../util/net/message.h"
#include "../../util/processinfo.h" #include "../../util/processinfo.h"
#include "../../util/concurrency/spin_lock.h" #include "../../util/concurrency/spin_lock.h"
#include "mongo/db/pdfile.h"
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:
skipping to change at line 71 skipping to change at line 72
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)
void btree( char * node ) { void btree( char * node ) {
if ( ! _memSupported ) if ( ! _memSupported )
return; return;
if ( _sampling++ % _samplingrate ) btree( Record::likelyInPhysicalMemory( node ) );
return;
btree( _pi.blockInMemory( node ) );
} }
void btree( bool memHit ) { void btree( bool memHit ) {
if ( memHit ) if ( memHit )
_btreeMemHits++; _btreeMemHits++;
else else
_btreeMemMisses++; _btreeMemMisses++;
_btreeAccesses++; _btreeAccesses++;
} }
void btreeHit() { _btreeMemHits++; _btreeAccesses++; } void btreeHit() { _btreeMemHits++; _btreeAccesses++; }
void btreeMiss() { _btreeMemMisses++; _btreeAccesses++; } void btreeMiss() { _btreeMemMisses++; _btreeAccesses++; }
void append( BSONObjBuilder& b ); void append( BSONObjBuilder& b );
private: private:
ProcessInfo _pi;
bool _memSupported; bool _memSupported;
int _sampling;
int _samplingrate;
int _resets; int _resets;
long long _maxAllowed; long long _maxAllowed;
long long _btreeMemMisses; long long _btreeMemMisses;
long long _btreeMemHits; long long _btreeMemHits;
long long _btreeAccesses; long long _btreeAccesses;
}; };
extern IndexCounters globalIndexCounters; extern IndexCounters globalIndexCounters;
 End of changes. 4 change blocks. 
7 lines changed or deleted 2 lines changed or added


 curop.h   curop.h 
skipping to change at line 40 skipping to change at line 40
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(); }
void reset(); void reset();
string toString() const; string report( const CurOp& curop ) const;
void append( const CurOp& curop, BSONObjBuilder& b ) const; void append( const CurOp& curop, BSONObjBuilder& b ) const;
// ------------------- // -------------------
StringBuilder extra; // weird things we need to fix later StringBuilder extra; // weird things we need to fix later
// basic options // basic options
int op; int op;
bool iscommand; bool iscommand;
Namespace ns; Namespace ns;
skipping to change at line 157 skipping to change at line 157
*/ */
class CurOp : boost::noncopyable { class CurOp : boost::noncopyable {
public: public:
CurOp( Client * client , CurOp * wrapped = 0 ); CurOp( Client * client , CurOp * wrapped = 0 );
~CurOp(); ~CurOp();
bool haveQuery() const { return _query.have(); } bool haveQuery() const { return _query.have(); }
BSONObj query() { return _query.get(); } BSONObj query() { return _query.get(); }
void appendQuery( BSONObjBuilder& b , const StringData& name ) cons t { _query.append( b , name ); } void appendQuery( BSONObjBuilder& b , const StringData& name ) cons t { _query.append( b , name ); }
void ensureStarted() { void ensureStarted();
if ( _start == 0 )
_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 ) {
_waitingForLock = true;
_lockType = type;
}
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; }
char lockType() const { return _lockType; }
bool displayInCurop() const { return _active && ! _suppressFromCuro p; } bool displayInCurop() const { return _active && ! _suppressFromCuro p; }
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();
} }
unsigned long long totalTimeMicros() { unsigned long long totalTimeMicros() {
skipping to change at line 222 skipping to change at line 212
BSONObj info(); BSONObj info();
BSONObj infoNoauth(); BSONObj infoNoauth();
string getRemoteString( bool includePort = true ) { return _remote. toString(includePort); } string getRemoteString( bool includePort = true ) { return _remote. toString(includePort); }
ProgressMeter& setMessage( const char * msg , unsigned long long pr ogressMeterTotal = 0 , int secondsBetween = 3 ); ProgressMeter& setMessage( const char * msg , unsigned long long pr ogressMeterTotal = 0 , int secondsBetween = 3 );
string getMessage() const { return _message.toString(); } string getMessage() const { return _message.toString(); }
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) { int numYields() const { return _numYields; }
strncpy(_ns, ns, Namespace::MaxNsLen);
_ns[Namespace::MaxNsLen] = 0;
}
void suppressFromCurop() { _suppressFromCurop = true; } void suppressFromCurop() { _suppressFromCurop = true; }
long long getExpectedLatencyMs() const { return _expectedLatencyMs; } long long getExpectedLatencyMs() const { return _expectedLatencyMs; }
void setExpectedLatencyMs( long long latency ) { _expectedLatencyMs = latency; } void setExpectedLatencyMs( long long latency ) { _expectedLatencyMs = latency; }
void recordGlobalTime( long long micros ) const;
const LockStat& lockStat() const { return _lockStat; }
LockStat& lockStat() { return _lockStat; }
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 _end; unsigned long long _end;
bool _active; bool _active;
bool _suppressFromCurop; // unless $all is set bool _suppressFromCurop; // unless $all is set
int _op; int _op;
bool _command; bool _command;
char _lockType; // r w R W
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;
LockStat _lockStat;
// this is how much "extra" time a query might take // this is how much "extra" time a query might take
// a writebacklisten for example will block for 30s // a writebacklisten for example will block for 30s
// so this should be 30000 in that case // so this should be 30000 in that case
long long _expectedLatencyMs; 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
 End of changes. 10 change blocks. 
20 lines changed or deleted 8 lines changed or added


 cursor.h   cursor.h 
skipping to change at line 48 skipping to change at line 48
* *
* Two general techniques may be used to ensure a Cursor is in a consis tent state after a write. * 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 be advanced before the document at its current position is deleted.
* - The Cursor may record its position and then relocate this posi tion. * - 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 * 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. * 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 * When the document at a Cursor's current position is deleted (or move d to a new location) the
* following pattern is used: * following pattern is used:
* DiskLoc toDelete = cursor->currLoc(); * DiskLoc toDelete = cursor->currLoc();
* cursor->advance(); * while( cursor->ok() && cursor->currLoc() == toDelete ) {
* cursor->advance();
* }
* cursor->prepareToTouchEarlierIterate(); * cursor->prepareToTouchEarlierIterate();
* delete( toDelete ); * delete( toDelete );
* cursor->recoverFromTouchingEarlierIterate(); * cursor->recoverFromTouchingEarlierIterate();
* *
* When a cursor yields, the following pattern is used: * When a cursor yields, the following pattern is used:
* cursor->prepareToYield(); * cursor->prepareToYield();
* while( Op theOp = nextOp() ) { * while( Op theOp = nextOp() ) {
* if ( theOp.type() == INSERT || theOp.type() == UPDATE_IN_PLA CE ) { * if ( theOp.type() == INSERT || theOp.type() == UPDATE_IN_PLA CE ) {
* theOp.run(); * theOp.run();
* } * }
* else if ( theOp.type() == DELETE ) { * else if ( theOp.type() == DELETE ) {
* if ( cursor->refLoc() == theOp.toDelete() ) { * if ( cursor->refLoc() == theOp.toDelete() ) {
* cursor->recoverFromYield(); * cursor->recoverFromYield();
* cursor->advance(); * while ( cursor->ok() && cursor->refLoc() == theOp.to
Delete() ) {
* cursor->advance();
* }
* cursor->prepareToYield(); * cursor->prepareToYield();
* } * }
* theOp.run(); * theOp.run();
* } * }
* } * }
* cursor->recoverFromYield(); * cursor->recoverFromYield();
* *
* The break before a getMore request is typically treated as a yield, but if a Cursor supports * 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: * getMore but not yield the following pattern is currently used:
* cursor->noteLocation(); * cursor->noteLocation();
* runOtherOps(); * runOtherOps();
* cursor->checkLocation(); * cursor->checkLocation();
* *
* But see SERVER-5725.
*
* A Cursor may rely on additional callbacks not listed above to reloca te its position after a * A Cursor may rely on additional callbacks not listed above to reloca te its position after a
* write. * 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;
skipping to change at line 244 skipping to change at line 250
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() {
verify( ok() ); verify( ok() );
return curr.rec(); return curr.rec();
} }
BSONObj current() { BSONObj current() {
Record *r = _current(); Record *r = _current();
BSONObj j(r); return BSONObj::make(r);
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();
virtual string toString() { return "BasicCursor"; } virtual string toString() { return "BasicCursor"; }
virtual void setTailable() { virtual void setTailable() {
if ( !curr.isNull() || !last.isNull() ) if ( !curr.isNull() || !last.isNull() )
tailable_ = true; tailable_ = true;
} }
virtual bool tailable() { return tailable_; } virtual bool tailable() { return tailable_; }
skipping to change at line 292 skipping to change at line 297
/* 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"; }
}; };
class ForwardCappedCursor : public BasicCursor, public AdvanceStrategy { class ForwardCappedCursor : public BasicCursor, public AdvanceStrategy {
public: public:
ForwardCappedCursor( NamespaceDetails *nsd = 0, const DiskLoc &star static ForwardCappedCursor* make( NamespaceDetails* nsd = 0,
tLoc = DiskLoc() ); const DiskLoc& startLoc = DiskLoc
() );
virtual string toString() { virtual string toString() {
return "ForwardCappedCursor"; return "ForwardCappedCursor";
} }
virtual DiskLoc next( const DiskLoc &prev ) const; virtual DiskLoc next( const DiskLoc &prev ) const;
virtual bool capped() const { return true; } virtual bool capped() const { return true; }
private: private:
ForwardCappedCursor( NamespaceDetails* nsd );
void init( const DiskLoc& startLoc );
NamespaceDetails *nsd; NamespaceDetails *nsd;
}; };
class ReverseCappedCursor : public BasicCursor, public AdvanceStrategy { class ReverseCappedCursor : public BasicCursor, public AdvanceStrategy {
public: public:
ReverseCappedCursor( NamespaceDetails *nsd = 0, const DiskLoc &star tLoc = DiskLoc() ); ReverseCappedCursor( NamespaceDetails *nsd = 0, const DiskLoc &star tLoc = DiskLoc() );
virtual string toString() { virtual string toString() {
return "ReverseCappedCursor"; return "ReverseCappedCursor";
} }
virtual DiskLoc next( const DiskLoc &prev ) const; virtual DiskLoc next( const DiskLoc &prev ) const;
 End of changes. 6 change blocks. 
6 lines changed or deleted 15 lines changed or added


 d_chunk_manager.h   d_chunk_manager.h 
skipping to change at line 30 skipping to change at line 30
#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; class DBClientCursorInterface;
class ShardChunkManager;
typedef shared_ptr<ShardChunkManager> ShardChunkManagerPtr;
/** /**
* 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
skipping to change at line 56 skipping to change at line 60
* Loads the ShardChunkManager with all boundaries for chunks of a given collection that live in an given * Loads the ShardChunkManager with all boundaries for chunks of a given collection that live in an given
* shard. * shard.
* *
* @param configServer name of the server where the configDB curren tly is. Can be empty to indicate * @param configServer name of the server where the configDB curren tly is. Can be empty to indicate
* that the configDB is running locally * that the configDB is running locally
* @param ns namespace for the collections whose chunks we're inter ested * @param ns namespace for the collections whose chunks we're inter ested
* @param shardName name of the shard that this chunk matcher shoul d track * @param shardName name of the shard that this chunk matcher shoul d track
* *
* This constructor throws if collection is dropped/malformed and o n connectivity errors * This constructor throws if collection is dropped/malformed and o n connectivity errors
*/ */
ShardChunkManager( const string& configServer , const string& ns , const string& shardName ); static ShardChunkManager* make( const string& configServer , const string& ns , const string& shardName, ShardChunkManagerPtr oldManager = Sha rdChunkManagerPtr() );
/** /**
* Same as the regular constructor but used in unittest (no access to configDB required). * Same as the regular constructor but used in unittest (no access to configDB required).
* *
* @param collectionDoc simulates config.collection's entry for one colleciton * @param collectionDoc simulates config.collection's entry for one colleciton
* @param chunksDocs simulates config.chunks' entries for one colle ction's shard * @param chunksDocs simulates config.chunks' entries for one colle ction's shard
*/ */
ShardChunkManager( const BSONObj& collectionDoc , const BSONArray& chunksDoc ); ShardChunkManager( const BSONObj& collectionDoc , const BSONArray& chunksDoc );
~ShardChunkManager() {} ~ShardChunkManager() {}
skipping to change at line 127 skipping to change at line 131
* @param lookupKey is the min key for a previously obtained chunk or the empty document * @param lookupKey is the min key for a previously obtained chunk or the empty document
* @param foundMin IN/OUT min for chunk following the one starting at lookupKey * @param foundMin IN/OUT min for chunk following the one starting at lookupKey
* @param foundMax IN/OUT max for the above chunk * @param foundMax IN/OUT max for the above chunk
* @return true if the chunk returned is the last one * @return true if the chunk returned is the last one
*/ */
bool getNextChunk( const BSONObj& lookupKey, BSONObj* foundMin , BS ONObj* foundMax ) const; bool getNextChunk( const BSONObj& lookupKey, BSONObj* foundMin , BS ONObj* foundMax ) const;
// accessors // accessors
ShardChunkVersion getVersion() const { return _version; } ShardChunkVersion getVersion() const { return _version; }
ShardChunkVersion getCollVersion() const { return _collVersion; }
BSONObj getKey() const { return _key.getOwned(); } BSONObj getKey() const { return _key.getOwned(); }
unsigned getNumChunks() const { return _chunksMap.size(); } unsigned getNumChunks() const { return _chunksMap.size(); }
string toString() const; string toString() const;
private: private:
void _init( const string& configServer , const string& ns , const s tring& shardName, ShardChunkManagerPtr oldManager = ShardChunkManagerPtr() );
/** /**
* @same as belongsToMe to but key has to be the shard key * @same as belongsToMe to but key has to be the shard key
*/ */
bool _belongsToMe( const BSONObj& key ) const; bool _belongsToMe( const BSONObj& key ) const;
ShardChunkVersion _collVersion;
// highest ShardChunkVersion for which this ShardChunkManager's inf ormation is accurate // highest ShardChunkVersion for which this ShardChunkManager's inf ormation is accurate
ShardChunkVersion _version; ShardChunkVersion _version;
// key pattern for chunks under this range // key pattern for chunks under this range
BSONObj _key; BSONObj _key;
// a map from a min key into the chunk's (or range's) max boundary // a map from a min key into the chunk's (or range's) max boundary
typedef map< BSONObj, BSONObj , BSONObjCmp > RangeMap; typedef map< BSONObj, BSONObj , BSONObjCmp > RangeMap;
RangeMap _chunksMap; RangeMap _chunksMap;
skipping to change at line 164 skipping to change at line 171
void _fillChunks( DBClientCursorInterface* cursor ); void _fillChunks( DBClientCursorInterface* cursor );
void _fillRanges(); void _fillRanges();
/** throws if the exact chunk is not in the chunks' map */ /** throws if the exact chunk is not in the chunks' map */
void _assertChunkExists( const BSONObj& min , const BSONObj& max ) const; void _assertChunkExists( const BSONObj& min , const BSONObj& max ) const;
/** can only be used in the cloning calls */ /** can only be used in the cloning calls */
ShardChunkManager() {} ShardChunkManager() {}
}; };
typedef shared_ptr<ShardChunkManager> ShardChunkManagerPtr;
} // namespace mongo } // namespace mongo
 End of changes. 6 change blocks. 
3 lines changed or deleted 8 lines changed or added


 d_concurrency.h   d_concurrency.h 
// @file d_concurrency.h // @file d_concurrency.h
/**
* Copyright (C) 2008 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3
,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public Licen
se
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// only used by mongod, thus the name ('d') // only used by mongod, thus the name ('d')
// (also used by dbtests test binary, which is running mongod test code) // (also used by dbtests test binary, which is running mongod test code)
#pragma once #pragma once
#include "mongo/util/concurrency/qlock.h"
#include "mongo/util/concurrency/mutex.h"
#include "mongo/bson/stringdata.h" #include "mongo/bson/stringdata.h"
#include "mongo/db/jsobj.h" #include "mongo/db/jsobj.h"
#include "mongo/db/lockstat.h" #include "mongo/db/lockstat.h"
#include "mongo/util/concurrency/mutex.h"
#include "mongo/util/concurrency/rwlock.h"
namespace mongo { namespace mongo {
class WrapperForRWLock; class WrapperForRWLock;
class LockState; class LockState;
class Lock : boost::noncopyable { class Lock : boost::noncopyable {
public: public:
enum Nestable { notnestable=0, local, admin }; enum Nestable { notnestable=0, local, admin };
static int isLocked(); // true if *anything* is locked (by us) static int isLocked(); // true if *anything* is locked (by us)
skipping to change at line 35 skipping to change at line 52
static bool isR(); static bool isR();
static bool isRW(); // R or W. i.e., we are write-exclusive static bool isRW(); // R or W. i.e., we are write-exclusive
static bool nested(); static bool nested();
static bool isWriteLocked(const StringData& ns); static bool isWriteLocked(const StringData& ns);
static bool atLeastReadLocked(const StringData& ns); // true if thi s db is locked static bool atLeastReadLocked(const StringData& ns); // true if thi s db is locked
static void assertAtLeastReadLocked(const StringData& ns); static void assertAtLeastReadLocked(const StringData& ns);
static void assertWriteLocked(const StringData& ns); static void assertWriteLocked(const StringData& ns);
static bool dbLevelLockingEnabled(); static bool dbLevelLockingEnabled();
static LockStat* globalLockStat();
static LockStat* nestableLockStat( Nestable db );
class ScopedLock; class ScopedLock;
// note: avoid TempRelease when possible. not a good thing. // note: avoid TempRelease when possible. not a good thing.
struct TempRelease { struct TempRelease {
TempRelease(); TempRelease();
~TempRelease(); ~TempRelease();
const bool cant; // true if couldn't because of recursive locki ng const bool cant; // true if couldn't because of recursive locki ng
ScopedLock *scopedLk; ScopedLock *scopedLk;
}; };
/** turn on "parallel batch writer mode". blocks all other threads
. this mode is off
by default. note only one thread creates a ParallelBatchWriterM
ode object; the rest just
call iAmABatchParticipant(). Note that this lock is not releas
ed on a temprelease, just
the normal lock things below.
*/
class ParallelBatchWriterMode : boost::noncopyable {
RWLockRecursive::Exclusive _lk;
public:
ParallelBatchWriterMode() : _lk(_batchLock) {}
static void iAmABatchParticipant();
static RWLockRecursive &_batchLock;
};
private:
class ParallelBatchWriterSupport : boost::noncopyable {
scoped_ptr<RWLockRecursive::Shared> _lk;
public:
ParallelBatchWriterSupport();
};
public:
class ScopedLock : boost::noncopyable { class ScopedLock : boost::noncopyable {
protected:
friend struct TempRelease;
ScopedLock();
virtual void tempRelease() = 0;
virtual void relock() = 0;
public: public:
virtual ~ScopedLock(); virtual ~ScopedLock();
/** @return micros since we started acquiring */
long long acquireFinished( LockStat* stat );
protected:
friend struct TempRelease;
explicit ScopedLock( char type );
void tempRelease();
void relock();
void _recordTime( long long micros );
virtual void _tempRelease() = 0;
virtual void _relock() = 0;
ParallelBatchWriterSupport _lk;
private:
Timer _timer; // this is counting the current state
char _type;
LockStat* _stat; // the stat for the relevant lock to increment
when we're done
}; };
// note that for these classes recursive locking is ok if the recur sive locking "makes sense" // note that for these classes recursive locking is ok if the recur sive locking "makes sense"
// i.e. you could grab globalread after globalwrite. // i.e. you could grab globalread after globalwrite.
class GlobalWrite : public ScopedLock { class GlobalWrite : public ScopedLock {
bool stoppedGreed;
bool noop; bool noop;
protected: protected:
void tempRelease(); void _tempRelease();
void relock(); void _relock();
public: public:
/** @param stopGreed after acquisition stop greediness of other // stopGreed is removed and does NOT work
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 // timeoutms is only for writelocktry -- deprecated -- do not u se
GlobalWrite(bool stopGreed = false, int timeoutms = -1 ); GlobalWrite(bool stopGreed = false, int timeoutms = -1 );
virtual ~GlobalWrite(); virtual ~GlobalWrite();
void downgrade(); // W -> R void downgrade(); // W -> R
bool upgrade(); // caution see notes void upgrade(); // caution see notes
}; };
class GlobalRead : public ScopedLock { // recursive is ok class GlobalRead : public ScopedLock { // recursive is ok
public: public:
bool noop; bool noop;
protected: protected:
void tempRelease(); void _tempRelease();
void relock(); void _relock();
public: public:
// timeoutms is only for readlocktry -- deprecated -- do not us e // timeoutms is only for readlocktry -- deprecated -- do not us e
GlobalRead( int timeoutms = -1 ); GlobalRead( int timeoutms = -1 );
virtual ~GlobalRead(); virtual ~GlobalRead();
}; };
// lock this database. do not shared_lock globally first, that is h andledin herein. // lock this database. do not shared_lock globally first, that is h andledin herein.
class DBWrite : public ScopedLock { class DBWrite : public ScopedLock {
bool isW(LockState&) const; /**
* flow
* 1) lockDB
* a) lockTop
* b) lockNestable or lockOther
* 2) unlockDB
*/
void lockTop(LockState&); void lockTop(LockState&);
void lockNestable(Nestable db); void lockNestable(Nestable db);
void lockOther(const string& 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 lockDB(const string& ns);
void unlockDB(); void unlockDB();
protected: protected:
void tempRelease(); void _tempRelease();
void relock(); void _relock();
public: public:
DBWrite(const StringData& dbOrNs); DBWrite(const StringData& dbOrNs);
virtual ~DBWrite(); virtual ~DBWrite();
class UpgradeToExclusive : private boost::noncopyable {
public:
UpgradeToExclusive();
~UpgradeToExclusive();
bool gotUpgrade() const { return _gotUpgrade; }
private:
bool _gotUpgrade;
};
private:
bool _locked_w;
bool _locked_W;
WrapperForRWLock *_weLocked;
const string _what;
bool _nested;
}; };
// lock this database for reading. do not shared_lock globally firs t, that is handledin herein. // lock this database for reading. do not shared_lock globally firs t, that is handledin herein.
class DBRead : public ScopedLock { class DBRead : public ScopedLock {
bool isRW(LockState&) const;
void lockTop(LockState&); void lockTop(LockState&);
void lockNestable(Nestable db); void lockNestable(Nestable db);
void lockOther(const string& db); void lockOther(const string& db);
bool locked_r;
WrapperForRWLock *weLocked;
string what;
bool _nested;
void lockDB(const string& ns); void lockDB(const string& ns);
void unlockDB(); void unlockDB();
protected: protected:
void tempRelease(); void _tempRelease();
void relock(); void _relock();
public: public:
DBRead(const StringData& dbOrNs); DBRead(const StringData& dbOrNs);
virtual ~DBRead(); virtual ~DBRead();
private:
bool _locked_r;
WrapperForRWLock *_weLocked;
string _what;
bool _nested;
}; };
}; };
class readlocktry : boost::noncopyable { class readlocktry : boost::noncopyable {
bool _got; bool _got;
scoped_ptr<Lock::GlobalRead> _dbrlock; scoped_ptr<Lock::GlobalRead> _dbrlock;
public: public:
readlocktry( int tryms ); readlocktry( int tryms );
~readlocktry(); ~readlocktry();
skipping to change at line 155 skipping to change at line 237
/** a mutex, but reported in curop() - thus a "high level" (HL) one /** a mutex, but reported in curop() - thus a "high level" (HL) one
some overhead so we don't use this for everything. the externalobj sort mutex some overhead so we don't use this for everything. the externalobj sort mutex
uses this, as it can be held for eons. implementation still needed. */ uses this, as it can be held for eons. implementation still needed. */
class HLMutex : public SimpleMutex { class HLMutex : public SimpleMutex {
LockStat ls; LockStat ls;
public: public:
HLMutex(const char *name); HLMutex(const char *name);
}; };
// implementation stuff
// per thread
class LockState {
public:
LockState();
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;
};
} }
 End of changes. 25 change blocks. 
102 lines changed or deleted 120 lines changed or added


 d_globals.h   d_globals.h 
skipping to change at line 12 skipping to change at line 12
// //
// 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 RWLockRecursive; class RWLockRecursive;
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:
MongoMutex &dbMutex;
ClientCursorMonitor& clientCursorMonitor; ClientCursorMonitor& clientCursorMonitor;
}; };
extern DGlobals d; extern DGlobals d;
}; };
 End of changes. 2 change blocks. 
2 lines changed or deleted 0 lines changed or added


 database.h   database.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 "mongo/db/cmdline.h" #include "mongo/db/cmdline.h"
#include "mongo/db/namespace_details.h" #include "mongo/db/namespace_details.h"
#include "mongo/db/record.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;
/** /**
skipping to change at line 112 skipping to change at line 113
/** /**
* @return true if ns is part of the database * @return true if ns is part of the database
* ns=foo.bar, db=foo returns true * ns=foo.bar, db=foo returns true
*/ */
bool ownsNS( const string& ns ) const { bool ownsNS( const string& ns ) const {
if ( ! startsWith( ns , name ) ) if ( ! startsWith( ns , name ) )
return false; return false;
return ns[name.size()] == '.'; return ns[name.size()] == '.';
} }
const RecordStats& recordStats() const { return _recordStats; }
RecordStats& recordStats() { return _recordStats; }
private: private:
/** /**
* @throws DatabaseDifferCaseCode if the name is a duplicate based on * @throws DatabaseDifferCaseCode if the name is a duplicate based on
* case insensitive matching. * case insensitive matching.
*/ */
void checkDuplicateUncasedNames(bool inholderlockalready) const; void checkDuplicateUncasedNames(bool inholderlockalready) const;
public: public:
/** /**
* @return name of an existing database with same text name but dif ferent * @return name of an existing database with same text name but dif ferent
* casing, if one exists. Otherwise the empty string is returned. If * casing, if one exists. Otherwise the empty string is returned. If
skipping to change at line 143 skipping to change at line 148
// to others and we are in the dbholder lock then. // to others and we are in the dbholder lock then.
vector<MongoDataFile*> _files; vector<MongoDataFile*> _files;
public: // this should be private later public: // this should be private later
NamespaceIndex namespaceIndex; NamespaceIndex namespaceIndex;
int profile; // 0=off. int profile; // 0=off.
const string profileName; // "alleyinsider.system.profile" const string profileName; // "alleyinsider.system.profile"
CCByLoc ccByLoc; CCByLoc ccByLoc;
int magic; // used for making sure the object is still loaded in me mory int magic; // used for making sure the object is still loaded in me mory
private:
RecordStats _recordStats;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 3 change blocks. 
0 lines changed or deleted 9 lines changed or added


 databaseholder.h   databaseholder.h 
// @file databaseholder.h // @file databaseholder.h
#pragma once #pragma once
#include "mongo/db/database.h"
#include "mongo/db/namespacestring.h"
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: // todo: we want something faster than this if called a lot:
mutable SimpleMutex _m; mutable SimpleMutex _m;
skipping to change at line 70 skipping to change at line 73
} }
/** @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; }
/** /**
* gets all unique db names, ignoring paths * gets all unique db names, ignoring paths
* need some lock
*/ */
void getAllShortNames( bool locked, set<string>& all ) const { void getAllShortNames( set<string>& all ) const {
SimpleMutex::scoped_lock lk(_m); 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:
 End of changes. 3 change blocks. 
1 lines changed or deleted 5 lines changed or added


 db.h   db.h 
skipping to change at line 21 skipping to change at line 21
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "../util/net/message.h" #include "../util/net/message.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. // todo: relocked is being called when there was no unlock below.
// that is weird. // that is weird.
 End of changes. 1 change blocks. 
1 lines changed or deleted 0 lines changed or added


 dbclient_rs.h   dbclient_rs.h 
skipping to change at line 49 skipping to change at line 49
* can hand a slave to someone for SLAVE_OK * can hand a slave to someone for SLAVE_OK
* one instace per process per replica set * one instace per process per replica set
* TODO: we might be able to use a regular Node * to avoid _lock * TODO: we might be able to use a regular Node * to avoid _lock
*/ */
class ReplicaSetMonitor { class ReplicaSetMonitor {
public: public:
typedef boost::function1<void,const ReplicaSetMonitor*> ConfigChang eHook; typedef boost::function1<void,const ReplicaSetMonitor*> ConfigChang eHook;
/** /**
* gets a cached Monitor per name or will create if doesn't exist * Data structure for keeping track of the states of individual rep
lica
* members. This class is not thread-safe so proper measures should
be taken
* when sharing this object across multiple threads.
*
* Note: these get copied around in the nodes vector so be sure to
maintain
* copyable semantics here
*/ */
static ReplicaSetMonitorPtr get( const string& name , const vector< struct Node {
HostAndPort>& servers ); Node( const HostAndPort& a , DBClientConnection* c ) :
addr( a ),
conn(c),
ok( c != NULL ),
ismaster(false),
secondary( false ),
hidden( false ),
pingTimeMillis( 0 ) {
}
bool okForSecondaryQueries() const {
return ok && secondary && ! hidden;
}
/**
* Checks if the given tag matches the tag attached to this nod
e.
*
* Example:
*
* Tag of this node: { "dc": "nyc", "region": "na", "rack": "4"
}
*
* match: {}
* match: { "dc": "nyc", "rack": 4 }
* match: { "region": "na", "dc": "nyc" }
* not match: { "dc: "nyc", "rack": 2 }
* not match: { "dc": "sf" }
*
* @param tag the tag to use to compare. Should not contain any
* embedded documents.
*
* @return true if the given tag matches the this node's tag
* specification
*/
bool matchesTag( const BSONObj& tag ) const;
/**
* @param threshold max ping time (in ms) to be considered lo
cal
* @return true if node is a local secondary, and can handle qu
eries
**/
bool isLocalSecondary( const int threshold ) const {
return pingTimeMillis < threshold;
}
BSONObj toBSON() const;
string toString() const {
return toBSON().toString();
}
HostAndPort addr;
boost::shared_ptr<DBClientConnection> conn;
// if this node is in a failure state
// used for slave routing
// this is too simple, should make it better
bool ok;
// as reported by ismaster
BSONObj lastIsMaster;
bool ismaster;
bool secondary;
bool hidden;
int pingTimeMillis;
};
/** /**
* gets a cached Monitor per name or will return none if it doesn't * Selects the right node given the nodes to pick from and the pref
exist erence.
*
* @param nodes the nodes to select from
* @param readPreference the read mode to use
* @param readPreferenceTag the tags used for filtering nodes
* @param localThresholdMillis the exclusive upper bound of ping ti
me to be
* considered as a local node. Local nodes are favored over non
-local
* nodes if multiple nodes matches the other criteria.
* @param primaryNodeIndex the index of the primary node
* @param nextNodeIndex the index of the next node to begin from ch
ecking.
* Can advance to a different index (mainly used for doing roun
d-robin).
*
* @return the host object of the node selected. If none of the nod
es are
* eligible, returns an empty host.
*/ */
static ReplicaSetMonitorPtr get( const string& name ); static HostAndPort selectNode( const std::vector<Node>& nodes,
ReadPreference readPreference,
const BSONObj& readPreferenceTag,
int localThresholdMillis,
int primaryNodeIndex,
int& nextNodeIndex );
/**
* Creates a new ReplicaSetMonitor, if it doesn't already exist.
*/
static void createIfNeeded( const string& name , const vector<HostA
ndPort>& servers );
/**
* gets a cached Monitor per name. If the monitor is not found and
createFromSeed is false,
* it will return none. If createFromSeed is true, it will try to l
ook up the last known
* servers list for this set and will create a new monitor using th
at as the seed list.
*/
static ReplicaSetMonitorPtr get( const string& name, const bool cre
ateFromSeed = false );
/** /**
* 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 );
/** /**
* deletes the ReplicaSetMonitor for the given set name. * Removes the ReplicaSetMonitor for the given set name from _sets,
which will delete it.
* If clearSeedCache is true, then the cached seed string for this
Replica Set will be removed
* from _setServers.
*/ */
static void remove( const string& name ); static void remove( const string& name, bool clearSeedCache = false
);
static int getMaxFailedChecks() { return _maxFailedChecks; };
static void setMaxFailedChecks(int numChecks) { _maxFailedChecks =
numChecks; };
/** /**
* this is called whenever the config of any replica set changes * 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();
skipping to change at line 90 skipping to change at line 197
HostAndPort getMaster(); HostAndPort getMaster();
/** /**
* notify the monitor that server has faild * notify the monitor that server has faild
*/ */
void notifyFailure( const HostAndPort& server ); void notifyFailure( const HostAndPort& server );
/** @return prev if its still ok, and if not returns a random slave that is ok for reads */ /** @return prev if its still ok, and if not returns a random slave that is ok for reads */
HostAndPort getSlave( const HostAndPort& prev ); HostAndPort getSlave( const HostAndPort& prev );
/** @return a random slave that is ok for reads */ /**
HostAndPort getSlave(); * @param preferLocal Prefer a local secondary, otherwise pick an
y
* secondary, or fall back to primary
* @return a random slave that is ok for reads
*/
HostAndPort getSlave( bool preferLocal = true );
/** /**
* notify the monitor that server has faild * notify the monitor that server has faild
*/ */
void notifySlaveFailure( const HostAndPort& server ); void notifySlaveFailure( const HostAndPort& server );
/** /**
* checks for current master and new secondaries * checks for current master and new secondaries
*/ */
void check( bool checkAllSecondaries ); void check( bool checkAllSecondaries );
string getName() const { return _name; } string getName() const { return _name; }
string getServerAddress() const; string getServerAddress() const;
bool contains( const string& server ) const; bool contains( const string& server ) const;
void appendInfo( BSONObjBuilder& b ) const; void appendInfo( BSONObjBuilder& b ) const;
/**
* Set the threshold value (in ms) for a node to be considered loca
l.
* NOTE: This function acquires the _lock mutex.
**/
void setLocalThresholdMillis( const int millis );
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). Should only be called from within _setsLock.
* @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 );
static void _remove_inlock( const string& name, bool clearSeedCache
= false );
/** /**
* Checks all connections from the host list and sets the current * Checks all connections from the host list and sets the current
* master. * master.
* *
* @param checkAllSecondaries if set to false, stop immediately whe n * @param checkAllSecondaries if set to false, stop immediately whe n
* the master is found or when _master is not -1. * the master is found or when _master is not -1.
*/ */
void _check( bool checkAllSecondaries ); void _check( bool checkAllSecondaries );
/** /**
skipping to change at line 159 skipping to change at line 278
* @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 true if the connection is good or false if invariant * @return true if the connection is good or false if invariant
* is broken * is broken
*/ */
bool _checkConnection( DBClientConnection* conn, string& maybePrima ry, bool _checkConnection( DBClientConnection* conn, string& maybePrima ry,
bool verbose, int nodesOffset ); bool verbose, int nodesOffset );
/**
* Save the seed list for the current set into the _setServers map
* Should only be called if you're already holding _setsLock and th
is
* monitor's _lock.
*/
void _cacheServerAddresses_inlock();
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. * @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 ;
/** /**
* Checks whether the given connection matches the connection store d in _nodes. * Checks whether the given connection matches the connection store d in _nodes.
* Mainly used for sanity checking to confirm that nodeOffset still * Mainly used for sanity checking to confirm that nodeOffset still
* refers to the right connection after releasing and reacquiring * refers to the right connection after releasing and reacquiring
* a mutex. * a mutex.
*/ */
bool _checkConnMatch_inlock( DBClientConnection* conn, size_t nodeO ffset ) const; bool _checkConnMatch_inlock( DBClientConnection* conn, size_t nodeO ffset ) const;
// protects _nodes and indices pointing to it (_master & _nextSlave /**
) * Selects the right node given the nodes to pick from and the pref
erence.
*
* @param nodes the nodes to select from
* @param readPreferenceTag the tags to use for choosing the right
node
* @param secOnly never select a primary if true
* @param localThresholdMillis the exclusive upper bound of ping ti
me to be
* considered as a local node. Local nodes are favored over non
-local
* nodes if multiple nodes matches the other criteria.
* @param nextNodeIndex the index of the next node to begin from ch
ecking.
* Can advance to a different index (mainly used for doing roun
d-robin).
*
* @return the host object of the node selected. If none of the nod
es are
* eligible, returns an empty host.
*/
static HostAndPort selectNode( const std::vector<Node>& nodes,
const BSONObj& readPreferenceTag,
bool secOnly,
int localThresholdMillis,
int& nextNodeIndex );
/**
* @return the primary if it is ok to use, otherwise returns an emp
ty
* HostAndPort object.
*/
static HostAndPort checkPrimary( const std::vector<Node>& nodes,
int primaryNodeIndex );
// protects _localThresholdMillis, _nodes and refs to _nodes (eg. _
master & _nextSlave)
mutable mongo::mutex _lock; mutable mongo::mutex _lock;
/** /**
* "Synchronizes" the _checkConnection method. Should ideally be on e mutex per * "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 * 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 * the reply from the connection the lock holder got is the actual response
* to what it sent. * to what it sent.
* *
* Deadlock WARNING: never acquire this while holding _lock * 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
struct Node {
Node( const HostAndPort& a , DBClientConnection* c )
: addr( a ) , conn(c) , ok(true) ,
ismaster(false), secondary( false ) , hidden( false ) , p
ingTimeMillis(0) {
ok = conn.get() == NULL;
}
bool okForSecondaryQueries() const {
return ok && secondary && ! hidden;
}
BSONObj toBSON() const {
return BSON( "addr" << addr.toString() <<
"isMaster" << ismaster <<
"secondary" << secondary <<
"hidden" << hidden <<
"ok" << ok );
}
string toString() const {
return toBSON().toString();
}
HostAndPort addr;
shared_ptr<DBClientConnection> conn;
// if this node is in a failure state
// used for slave routing
// this is too simple, should make it better
bool ok;
// as reported by ismaster
BSONObj lastIsMaster;
bool ismaster;
bool secondary;
bool hidden;
int pingTimeMillis;
};
/** /**
* Host list. * Host list.
*/ */
vector<Node> _nodes; std::vector<Node> _nodes;
int _master; // which node is the current master. -1 means no mast er is known int _master; // which node is the current master. -1 means no mast er is known
int _nextSlave; // which node is the current slave int _nextSlave; // which node is the current slave
// The number of consecutive times the set has been checked and eve
ry member in the set was down.
int _failedChecks;
static mongo::mutex _setsLock; // protects _sets static mongo::mutex _setsLock; // protects _sets and _setServers
static map<string,ReplicaSetMonitorPtr> _sets; // set name to Monit or static map<string,ReplicaSetMonitorPtr> _sets; // set name to Monit or
static map<string,vector<HostAndPort> > _setServers; // set name to seed list. Used to rebuild the monitor if it is cleaned up but then the se t is accessed again.
static ConfigChangeHook _hook; static ConfigChangeHook _hook;
int _localThresholdMillis; // local ping latency threshold (protect
ed by _lock)
static int _maxFailedChecks;
}; };
/** 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; using DBClientBase::query;
using DBClientBase::update;
using DBClientBase::remove;
/** 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.
*/ */
skipping to change at line 292 skipping to change at line 411
/** throws userassertion "no master found" */ /** throws userassertion "no master found" */
virtual BSONObj findOne(const string &ns, const Query& query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0); virtual BSONObj findOne(const string &ns, const Query& query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0);
virtual void insert( const string &ns , BSONObj obj , int flags=0); virtual void insert( const string &ns , BSONObj obj , int flags=0);
/** insert multiple objects. Note that single object insert is asy nchronous, so this version /** insert multiple objects. Note that single object insert is asy nchronous, so this version
is only nominally faster and not worth a special effort to try to use. */ is only nominally faster and not worth a special effort to try to use. */
virtual void insert( const string &ns, const vector< BSONObj >& v , int flags=0); virtual void insert( const string &ns, const vector< BSONObj >& v , int flags=0);
virtual void remove( const string &ns , Query obj , bool justOne = 0 ); virtual void remove( const string &ns , Query obj , int flags );
virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = 0 , bool multi = 0 ); virtual void update( const string &ns , Query query , BSONObj obj , int flags );
virtual void killCursor( long long cursorID ); virtual void killCursor( long long cursorID );
// ---- access raw connections ---- // ---- access raw connections ----
DBClientConnection& masterConn(); DBClientConnection& masterConn();
DBClientConnection& slaveConn(); DBClientConnection& slaveConn();
// ---- callback pieces ------- // ---- callback pieces -------
skipping to change at line 327 skipping to change at line 446
// ----- status ------ // ----- status ------
virtual bool isFailed() const { return ! _master || _master->isFail ed(); } virtual bool isFailed() const { return ! _master || _master->isFail ed(); }
// ----- informational ---- // ----- informational ----
double getSoTimeout() const { return _so_timeout; } double getSoTimeout() const { return _so_timeout; }
string toString() { return getServerAddress(); } string toString() { return getServerAddress(); }
string getServerAddress() const { return _monitor->getServerAddress (); } string getServerAddress() const;
virtual ConnectionString::ConnectionType type() const { return Conn ectionString::SET; } virtual ConnectionString::ConnectionType type() const { return Conn ectionString::SET; }
virtual bool lazySupported() const { return true; } virtual bool lazySupported() const { return true; }
// ---- low level ------ // ---- low level ------
virtual bool call( Message &toSend, Message &response, bool assertO k=true , string * actualServer = 0 ); virtual bool call( Message &toSend, Message &response, bool assertO k=true , string * actualServer = 0 );
virtual bool callRead( Message& toSend , Message& response ) { retu rn checkMaster()->callRead( toSend , response ); } virtual bool callRead( Message& toSend , Message& response ) { retu rn checkMaster()->callRead( toSend , response ); }
protected: protected:
skipping to change at line 350 skipping to change at line 469
private: private:
// Used to simplify slave-handling logic on errors // Used to simplify slave-handling logic on errors
auto_ptr<DBClientCursor> checkSlaveQueryResult( auto_ptr<DBClientCu rsor> result ); auto_ptr<DBClientCursor> checkSlaveQueryResult( auto_ptr<DBClientCu rsor> result );
DBClientConnection * checkMaster(); DBClientConnection * checkMaster();
DBClientConnection * checkSlave(); DBClientConnection * checkSlave();
void _auth( DBClientConnection * conn ); void _auth( DBClientConnection * conn );
ReplicaSetMonitorPtr _monitor; // Throws a DBException if the monitor doesn't exist and there isn'
t a cached seed to use.
ReplicaSetMonitorPtr _getMonitor() const;
string _setName;
HostAndPort _masterHost; HostAndPort _masterHost;
scoped_ptr<DBClientConnection> _master; scoped_ptr<DBClientConnection> _master;
HostAndPort _slaveHost; HostAndPort _slaveHost;
scoped_ptr<DBClientConnection> _slave; scoped_ptr<DBClientConnection> _slave;
double _so_timeout; double _so_timeout;
/** /**
 End of changes. 23 change blocks. 
64 lines changed or deleted 219 lines changed or added


 dbclientcursor.h   dbclientcursor.h 
skipping to change at line 174 skipping to change at line 174
*/ */
void decouple() { _ownCursor = false; } void decouple() { _ownCursor = false; }
void attach( AScopedConnection * conn ); void attach( AScopedConnection * conn );
string originalHost() const { return _originalHost; } string originalHost() const { return _originalHost; }
Message* getMessage(){ return batch.m.get(); } Message* getMessage(){ return batch.m.get(); }
/** /**
* Used mainly to run commands on connections that doesn't support
lazy initialization and
* does not support commands through the call interface.
*
* @param cmd The BSON representation of the command to send.
*
* @return true if command was sent successfully
*/
bool initCommand();
/**
* actually does the query * actually does the query
*/ */
bool init(); bool init();
void initLazy( bool isRetry = false ); void initLazy( bool isRetry = false );
bool initLazyFinish( bool& retry ); bool initLazyFinish( bool& retry );
class Batch : boost::noncopyable { class Batch : boost::noncopyable {
friend class DBClientCursor; friend class DBClientCursor;
auto_ptr<Message> m; auto_ptr<Message> m;
 End of changes. 1 change blocks. 
0 lines changed or deleted 11 lines changed or added


 dbclientinterface.h   dbclientinterface.h 
skipping to change at line 25 skipping to change at line 25
* 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 "mongo/db/authlevel.h" #include "mongo/client/authlevel.h"
#include "mongo/client/authentication_table.h"
#include "mongo/db/jsobj.h" #include "mongo/db/jsobj.h"
#include "mongo/util/net/message.h" #include "mongo/util/net/message.h"
#include "mongo/util/net/message_port.h" #include "mongo/util/net/message_port.h"
namespace mongo { namespace mongo {
/** the query field 'options' can have these bits set: */ /** the query field 'options' can have these bits set: */
enum QueryOptions { enum QueryOptions {
/** Tailable means cursor is not closed when the last data is retri eved. rather, the cursor marks /** 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, the final object's position. you can resume using the cursor la ter, from where it was located,
skipping to change at line 115 skipping to change at line 116
}; };
/** /**
* need to put in DbMesssage::ReservedOptions as well * need to put in DbMesssage::ReservedOptions as well
*/ */
enum InsertOptions { enum InsertOptions {
/** With muli-insert keep processing inserts if one fails */ /** With muli-insert keep processing inserts if one fails */
InsertOption_ContinueOnError = 1 << 0 InsertOption_ContinueOnError = 1 << 0
}; };
/**
* Start from *top* of bits, these are generic write options that apply
to all
*/
enum WriteOptions {
/** logical writeback option */
WriteOption_FromWriteback = 1 << 31
};
//
// For legacy reasons, the reserved field pre-namespace of certain type
s of messages is used
// to store options as opposed to the flags after the namespace. This
should be transparent to
// the api user, but we need these constants to disassemble/reassemble
the messages correctly.
//
enum ReservedOptions {
Reserved_InsertOption_ContinueOnError = 1 << 0 ,
Reserved_FromWriteback = 1 << 1
};
enum ReadPreference {
/**
* Read from primary only. All operations produce an error (throw a
n
* exception where applicable) if primary is unavailable. Cannot be
* combined with tags.
*/
ReadPreference_PrimaryOnly = 0,
/**
* Read from primary if available, otherwise a secondary. Tags will
* only be applied in the event that the primary is unavailable and
* a secondary is read from. In this event only secondaries matchin
g
* the tags provided would be read from.
*/
ReadPreference_PrimaryPreferred,
/**
* Read from secondary if available, otherwise error.
*/
ReadPreference_SecondaryOnly,
/**
* Read from a secondary if available, otherwise read from the prim
ary.
*/
ReadPreference_SecondaryPreferred,
/**
* Read from any member.
*/
ReadPreference_Nearest,
};
class DBClientBase; class DBClientBase;
/** /**
* ConnectionString handles parsing different ways to connect to mongo and determining method * ConnectionString handles parsing different ways to connect to mongo and determining method
* samples: * samples:
* server * server
* server:port * server:port
* foo/server:port,server:port SET * foo/server:port,server:port SET
* server,server,server SYNC * server,server,server SYNC
* *
* tyipcal use * tyipcal use
* string errmsg, * string errmsg,
* ConnectionString cs = ConnectionString::parse( url , errmsg ); * ConnectionString cs = ConnectionString::parse( url , errmsg );
* if ( ! cs.isValid() ) throw "bad: " + errmsg; * if ( ! cs.isValid() ) throw "bad: " + errmsg;
* DBClientBase * conn = cs.connect( errmsg ); * DBClientBase * conn = cs.connect( errmsg );
*/ */
class ConnectionString { class ConnectionString {
public: public:
enum ConnectionType { INVALID , MASTER , PAIR , SET , SYNC }; enum ConnectionType { INVALID , MASTER , PAIR , SET , SYNC, CUSTOM };
ConnectionString() { ConnectionString() {
_type = INVALID; _type = INVALID;
} }
ConnectionString( const HostAndPort& server ) { ConnectionString( const HostAndPort& server ) {
_type = MASTER; _type = MASTER;
_servers.push_back( server ); _servers.push_back( server );
_finishInit(); _finishInit();
} }
skipping to change at line 201 skipping to change at line 253
string getSetName() const { return _setName; } string getSetName() const { return _setName; }
vector<HostAndPort> getServers() const { return _servers; } vector<HostAndPort> getServers() const { return _servers; }
ConnectionType type() const { return _type; } ConnectionType type() const { return _type; }
static ConnectionString parse( const string& url , string& errmsg ) ; static ConnectionString parse( const string& url , string& errmsg ) ;
static string typeToString( ConnectionType type ); static string typeToString( ConnectionType type );
//
// Allow overriding the default connection behavior
// This is needed for some tests, which otherwise would fail becaus
e they are unable to contact
// the correct servers.
//
class ConnectionHook {
public:
virtual ~ConnectionHook(){}
// Returns an alternative connection object for a string
virtual DBClientBase* connect( const ConnectionString& c,
string& errmsg,
double socketTimeout ) = 0;
};
static void setConnectionHook( ConnectionHook* hook ){
scoped_lock lk( _connectHookMutex );
_connectHook = hook;
}
private: private:
void _fillServers( string s ); void _fillServers( string s );
void _finishInit(); void _finishInit();
ConnectionType _type; ConnectionType _type;
vector<HostAndPort> _servers; vector<HostAndPort> _servers;
string _string; string _string;
string _setName; string _setName;
static mutex _connectHookMutex;
static ConnectionHook* _connectHook;
}; };
/** /**
* controls how much a clients cares about writes * controls how much a clients cares about writes
* default is NORMAL * default is NORMAL
*/ */
enum WriteConcern { enum WriteConcern {
W_NONE = 0 , // TODO: not every connection type fully supports this W_NONE = 0 , // TODO: not every connection type fully supports this
W_NORMAL = 1 W_NORMAL = 1
// TODO SAFE = 2 // TODO SAFE = 2
skipping to change at line 431 skipping to change at line 507
public: public:
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0, virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0,
const BSONObj *fieldsToRetur n = 0, int queryOptions = 0 , int batchSize = 0 ) = 0; const BSONObj *fieldsToRetur n = 0, int queryOptions = 0 , int batchSize = 0 ) = 0;
virtual void insert( const string &ns, BSONObj obj , int flags=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 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 remove( const string &ns , Query query, bool justOne = 0 ) = 0;
virtual void update( const string &ns , Query query , BSONObj obj , virtual void remove( const string &ns , Query query, int flags ) =
bool upsert = 0 , bool multi = 0 ) = 0; 0;
virtual void update( const string &ns,
Query query,
BSONObj obj,
bool upsert = false, bool multi = false ) = 0;
virtual void update( const string &ns, Query query, BSONObj obj, in
t flags ) = 0;
virtual ~DBClientInterface() { } virtual ~DBClientInterface() { }
/** /**
@return a single object that matches the query. if none do, the n the object is empty @return a single object that matches the query. if none do, the n the object is empty
@throws AssertionException @throws AssertionException
*/ */
virtual BSONObj findOne(const string &ns, const Query& query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0); 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 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
skipping to change at line 462 skipping to change at line 545
/** /**
DB "commands" DB "commands"
Basically just invocations of connection.$cmd.findOne({...}); Basically just invocations of connection.$cmd.findOne({...});
*/ */
class DBClientWithCommands : public DBClientInterface { class DBClientWithCommands : public DBClientInterface {
set<string> _seenIndexes; set<string> _seenIndexes;
public: public:
/** controls how chatty the client is about network errors & such. See log.h */ /** controls how chatty the client is about network errors & such. See log.h */
int _logLevel; int _logLevel;
DBClientWithCommands() : _logLevel(0), _cachedAvailableOptions( (en DBClientWithCommands() : _logLevel(0),
um QueryOptions)0 ), _haveCachedAvailableOptions(false) { } _cachedAvailableOptions( (enum QueryOptions)0 ),
_haveCachedAvailableOptions(false),
_hasAuthentication(false) { }
/** helper function. run a simple command where the command expres sion is simply /** helper function. run a simple command where the command expres sion is simply
{ command : 1 } { command : 1 }
@param info -- where to put result object. may be null if call er doesn't need that info @param info -- where to put result object. may be null if call er doesn't need that info
@param command -- command name @param command -- command name
@return true if the command returned "ok". @return true if the command returned "ok".
*/ */
bool simpleCommand(const string &dbname, BSONObj *info, const strin g &command); bool simpleCommand(const string &dbname, BSONObj *info, const strin g &command);
/** Run a database command. Database commands are represented as B SON objects. Common database /** Run a database command. Database commands are represented as B SON objects. Common database
commands have prebuilt helper functions -- see below. If a hel per is not available you can commands have prebuilt helper functions -- see below. If a hel per is not available you can
directly call runCommand. directly call runCommand. If _authTable has been set, will app
end a BSON representation of
that AuthenticationTable to the command object, unless an Authe
nticationTable object has been
passed to this method directly, in which case it will use that
instead of _authTable.
@param dbname database name. Use "admin" for global administra tive commands. @param dbname database name. Use "admin" for global administra tive commands.
@param cmd the command object to execute. For example, { isma ster : 1 } @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 @param info the result object the database returns. Typically h as { ok : ..., errmsg : ... } fields
set. set.
@param options see enum QueryOptions - normally not needed to r un a command @param options see enum QueryOptions - normally not needed to r un a command
@param auth if set, the BSONObj representation will be appended
to the command object sent
@return true if the command returned "ok". @return true if the command returned "ok".
*/ */
virtual bool runCommand(const string &dbname, const BSONObj& cmd, B virtual bool runCommand(const string &dbname, const BSONObj& cmd, B
SONObj &info, int options=0); SONObj &info,
int options=0, const AuthenticationTable* a
uth = NULL);
/** Authorize access to a particular database. /** Authorize access to a particular database.
Authentication is separate for each database on the server -- y ou may authenticate for any Authentication is separate for each database on the server -- y ou may authenticate for any
number of databases on a single connection. number of databases on a single connection.
The "admin" database is special and once authenticated provides access to all databases on the The "admin" database is special and once authenticated provides access to all databases on the
server. server.
@param digestPassword if password is plain text, set this to true. otherwise assumed to be pre-digested @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 @param[out] authLevel level of authentication for the giv en user
@return true if successful @return true if successful
*/ */
skipping to change at line 563 skipping to change at line 654
result.err will be null if no error has occurred. result.err will be null if no error has occurred.
*/ */
BSONObj getPrevError(); BSONObj getPrevError();
/** Reset the previous error state for this connection (accessed vi a getLastError and /** Reset the previous error state for this connection (accessed vi a getLastError and
getPrevError). Useful when performing several operations at on ce and then checking getPrevError). Useful when performing several operations at on ce and then checking
for an error after attempting all operations. for an error after attempting all operations.
*/ */
bool resetError() { return simpleCommand("admin", 0, "reseterror"); } bool resetError() { return simpleCommand("admin", 0, "reseterror"); }
/** Delete the specified collection. */ /** Delete the specified collection.
virtual bool dropCollection( const string &ns ) { * @param info An optional output parameter that receives the resu
lt object the database
* returns from the drop command. May be null if the caller doesn
't need that info.
*/
virtual bool dropCollection( const string &ns, BSONObj* info = NULL
) {
string db = nsGetDB( ns ); string db = nsGetDB( ns );
string coll = nsGetCollection( ns ); string coll = nsGetCollection( ns );
uassert( 10011 , "no collection name", coll.size() ); uassert( 10011 , "no collection name", coll.size() );
BSONObj info; BSONObj temp;
if ( info == NULL ) {
info = &temp;
}
bool res = runCommand( db.c_str() , BSON( "drop" << coll ) , in fo ); bool res = runCommand( db.c_str() , BSON( "drop" << coll ) , *i nfo );
resetIndexCache(); resetIndexCache();
return res; return res;
} }
/** Perform a repair and compaction of the specified database. May take a long time to run. Disk space /** 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. must be available equal to the size of the database while repair ing.
*/ */
bool repairDatabase(const string &dbname, BSONObj *info = 0) { bool repairDatabase(const string &dbname, BSONObj *info = 0) {
return simpleCommand(dbname, info, "repairDatabase"); return simpleCommand(dbname, info, "repairDatabase");
} }
skipping to change at line 722 skipping to change at line 819
*/ */
list<string> getDatabaseNames(); list<string> getDatabaseNames();
/** /**
get a list of all the current collections in db get a list of all the current collections in db
*/ */
list<string> getCollectionNames( const string& db ); list<string> getCollectionNames( const string& db );
bool exists( const string& ns ); bool exists( const string& ns );
virtual void setAuthenticationTable( const AuthenticationTable& aut
h );
virtual void clearAuthenticationTable();
/** Create an index if it does not already exist. /** Create an index if it does not already exist.
ensureIndex calls are remembered so it is safe/fast to call thi s function many ensureIndex calls are remembered so it is safe/fast to call thi s function many
times in your code. times in your code.
@param ns collection to be indexed @param ns collection to be indexed
@param keys the "key pattern" for the index. e.g., { name : 1 } @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 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 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 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 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.) @param v index version. leave at default value. (unit tests set this parameter.)
skipping to change at line 783 skipping to change at line 883
BSONObj _countCmd(const string &ns, const BSONObj& query, int optio ns, int limit, int skip ); BSONObj _countCmd(const string &ns, const BSONObj& query, int optio ns, int limit, int skip );
/** /**
* Look up the options available on this client. Caches the answer from * Look up the options available on this client. Caches the answer from
* _lookupAvailableOptions(), below. * _lookupAvailableOptions(), below.
*/ */
QueryOptions availableOptions(); QueryOptions availableOptions();
virtual QueryOptions _lookupAvailableOptions(); virtual QueryOptions _lookupAvailableOptions();
bool hasAuthenticationTable();
AuthenticationTable& getAuthenticationTable();
private: private:
enum QueryOptions _cachedAvailableOptions; enum QueryOptions _cachedAvailableOptions;
bool _haveCachedAvailableOptions; bool _haveCachedAvailableOptions;
AuthenticationTable _authTable;
bool _hasAuthentication;
}; };
/** /**
abstract class that implements the core db operations abstract class that implements the core db operations
*/ */
class DBClientBase : public DBClientWithCommands, public DBConnector { class DBClientBase : public DBClientWithCommands, public DBConnector {
protected: protected:
WriteConcern _writeConcern; WriteConcern _writeConcern;
public: public:
skipping to change at line 858 skipping to change at line 963
insert an object into the database insert an object into the database
*/ */
virtual void insert( const string &ns , BSONObj obj , int flags=0); virtual void insert( const string &ns , BSONObj obj , int flags=0);
/** /**
insert a vector of objects into the database insert a vector of objects into the database
*/ */
virtual void insert( const string &ns, const vector< BSONObj >& v , int flags=0); virtual void insert( const string &ns, const vector< BSONObj >& v , int flags=0);
/** /**
updates objects matching query
*/
virtual void update( const string &ns,
Query query,
BSONObj obj,
bool upsert = false, bool multi = false );
virtual void update( const string &ns, Query query, BSONObj obj, in
t flags );
/**
remove matching objects from the database remove matching objects from the database
@param justOne if this true, then once a single match is found w ill stop @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 ); virtual void remove( const string &ns , Query q , bool justOne = 0 );
/** virtual void remove( const string &ns , Query query, int flags );
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 bool isFailed() const = 0;
virtual void killCursor( long long cursorID ) = 0; virtual void killCursor( long long cursorID ) = 0;
virtual bool callRead( Message& toSend , Message& response ) = 0; virtual bool callRead( Message& toSend , Message& response ) = 0;
// virtual bool callWrite( Message& toSend , Message& response ) = 0; // TODO: add this if needed // virtual bool callWrite( Message& toSend , Message& response ) = 0; // TODO: add this if needed
virtual ConnectionString::ConnectionType type() const = 0; virtual ConnectionString::ConnectionType type() const = 0;
skipping to change at line 967 skipping to change at line 1079
checkConnection(); checkConnection();
return DBClientBase::query( ns, query, nToReturn, nToSkip, fiel dsToReturn, queryOptions , batchSize ); return DBClientBase::query( ns, query, nToReturn, nToSkip, fiel dsToReturn, queryOptions , batchSize );
} }
virtual unsigned long long query( boost::function<void(DBClientCurs orBatchIterator &)> f, virtual unsigned long long query( boost::function<void(DBClientCurs orBatchIterator &)> f,
const string& ns, const string& ns,
Query query, Query query,
const BSONObj *fieldsToReturn, const BSONObj *fieldsToReturn,
int queryOptions ); int queryOptions );
virtual bool runCommand(const string &dbname, const BSONObj& cmd, B virtual bool runCommand(const string &dbname,
SONObj &info, int options=0); const BSONObj& cmd,
BSONObj &info,
int options=0,
const AuthenticationTable* auth=NULL);
/** /**
@return true if this connection is currently in a failed state. When autoreconnect is on, @return true if this connection is currently in a failed state. When autoreconnect is on,
a connection will transition back to an ok state after r econnecting. a connection will transition back to an ok state after r econnecting.
*/ */
bool isFailed() const { return _failed; } bool isFailed() const { return _failed; }
MessagingPort& port() { verify(p); return *p; } MessagingPort& port() { verify(p); return *p; }
string toStringLong() const { string toStringLong() const {
 End of changes. 19 change blocks. 
20 lines changed or deleted 152 lines changed or added


 dbhelpers.h   dbhelpers.h 
skipping to change at line 31 skipping to change at line 31
*/ */
#pragma once #pragma once
#include "../pch.h" #include "../pch.h"
#include "client.h" #include "client.h"
#include "db.h" #include "db.h"
namespace mongo { namespace mongo {
const BSONObj reverseNaturalObj = BSON( "$natural" << -1 ); extern const BSONObj reverseNaturalObj; // {"$natural": -1 }
class Cursor; class Cursor;
class CoveredIndexMatcher; class CoveredIndexMatcher;
/** /**
all helpers assume locking is handled above them all helpers assume locking is handled above them
*/ */
struct Helpers { struct Helpers {
/* ensure the specified index exists. /* ensure the specified index exists.
skipping to change at line 65 skipping to change at line 65
set your db SavedContext first. set your db SavedContext first.
@param query - the query to perform. note this is the low level portion of query so "orderby : ..." @param query - the query to perform. note this is the low level portion of query so "orderby : ..."
won't work. won't work.
@param requireIndex if true, assert if no index for the query. a way to guard against @param requireIndex if true, assert if no index for the query. a way to guard against
writing a slow query. writing a slow query.
@return true if object found @return true if object found
*/ */
static bool findOne(const char *ns, const BSONObj &query, BSONObj& static bool findOne(const StringData& ns, const BSONObj &query, BSO
result, bool requireIndex = false); NObj& result, bool requireIndex = false);
static DiskLoc findOne(const char *ns, const BSONObj &query, bool r static DiskLoc findOne(const StringData& ns, const BSONObj &query,
equireIndex); bool requireIndex);
/**
* have to be locked already
*/
static vector<BSONObj> findAll( const string& ns , const BSONObj& q
uery );
/** /**
* @param foundIndex if passed in will be set to 1 if ns and index found * @param foundIndex if passed in will be set to 1 if ns and index found
* @return true if object found * @return true if object found
*/ */
static bool findById(Client&, const char *ns, BSONObj query, BSONOb j& result , static bool findById(Client&, const char *ns, BSONObj query, BSONOb j& result ,
bool * nsFound = 0 , bool * indexFound = 0 ); bool * nsFound = 0 , bool * indexFound = 0 );
/* uasserts if no _id index. /* uasserts if no _id index.
@return null loc if not found */ @return null loc if not found */
skipping to change at line 105 skipping to change at line 110
* 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, bool fromM igrate = false ); 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
/* Takes object o, and returns a new object with the
* same field elements but the names stripped out. Also,
* fills in "key" with an ascending keyPattern that matches o
* Example:
* o = {a : 5 , b : 6} -->
* sets key= {a : 1, b :1}, returns {"" : 5, "" : 6}
*/
static BSONObj toKeyFormat( const BSONObj& o , BSONObj& key ); static BSONObj toKeyFormat( const BSONObj& o , BSONObj& key );
/* Takes a BSONObj indicating the min or max boundary of a range,
* and a keyPattern corresponding to an index that is useful
* for locating items in the range, and returns an "extension"
* of the bound, modified to fit the given pattern. In other words
,
* it appends MinKey or MaxKey values to the bound, so that the ext
ension
* has the same number of fields as keyPattern.
* minOrMax should be -1/+1 to indicate whether the extension
* corresponds to the min or max bound for the range.
* Also, strips out the field names to put the bound in key format.
* Examples:
* {a : 55}, {a :1}, -1 --> {"" : 55}
* {a : 55}, {a : 1, b : 1}, -1 -> {"" : 55, "" : minKey}
* {a : 55}, {a : 1, b : 1}, 1 -> {"" : 55, "" : maxKey}
* {a : 55}, {a : 1, b : -1}, -1 -> {"" : 55, "" : maxKey}
* {a : 55}, {a : 1, b : -1}, 1 -> {"" : 55, "" : minKey}
*
* This function is useful for modifying chunk ranges in sharding,
* when the shard key is a prefix of the index actually used
* (also useful when the shard key is equal to the index used,
* since it strips out the field names).
*/
static BSONObj modifiedRangeBound( const BSONObj& bound ,
const BSONObj& keyPattern ,
int minOrMax );
class RemoveCallback { class RemoveCallback {
public: public:
virtual ~RemoveCallback() {} virtual ~RemoveCallback() {}
virtual void goingToDelete( const BSONObj& o ) = 0; virtual void goingToDelete( const BSONObj& o ) = 0;
}; };
/** /**
* Remove all documents in the range. * Takes a range, specified by a min and max, and an index, specifi
ed by
* keyPattern, and removes all the documents in that range found by
iterating
* over the given index. Caller is responsible for insuring that mi
n/max are
* compatible with the given keyPattern (e.g min={a:100} is compati
ble with
* keyPattern={a:1,b:1} since it can be extended to {a:100,b:minKey
}, but
* min={b:100} is not compatible).
*
* Caller must hold a write lock on 'ns'
*
* Does oplog the individual document deletions. * Does oplog the individual document deletions.
*/ */
static long long removeRange( const string& ns , static long long removeRange( const string& ns ,
const BSONObj& min , const BSONObj& min ,
const BSONObj& max , const BSONObj& max ,
bool yield = false , const BSONObj& keyPattern ,
bool maxInclusive = false , bool maxInclusive = false ,
RemoveCallback * callback = 0, RemoveCallback * callback = 0,
bool fromMigrate = false ); bool fromMigrate = false );
/** /**
* Remove all documents from a collection. * Remove all documents from a collection.
* You do not need to set the database before calling. * You do not need to set the database before calling.
* Does not oplog the operation. * Does not oplog the operation.
*/ */
static void emptyCollection(const char *ns); static void emptyCollection(const char *ns);
 End of changes. 6 change blocks. 
7 lines changed or deleted 60 lines changed or added


 dbmessage.h   dbmessage.h 
skipping to change at line 231 skipping to change at line 231
} }
private: private:
const Message& m; const Message& m;
int* reserved; int* reserved;
const char *data; const char *data;
const char *nextjsobj; const char *nextjsobj;
const char *theEnd; const char *theEnd;
const char * mark; const char * mark;
public:
enum ReservedOptions {
Reserved_InsertOption_ContinueOnError = 1 << 0 ,
Reserved_FromWriteback = 1 << 1
};
}; };
/* a request to run a query, received from the database */ /* a request to run a query, received from the database */
class QueryMessage { class QueryMessage {
public: public:
const char *ns; const char *ns;
int ntoskip; int ntoskip;
int ntoreturn; int ntoreturn;
int queryOptions; int queryOptions;
BSONObj query; BSONObj query;
skipping to change at line 275 skipping to change at line 269
int nReturned, int startingFrom = 0, int nReturned, int startingFrom = 0,
long long cursorId = 0 long long cursorId = 0
); );
/* object reply helper. */ /* object reply helper. */
void replyToQuery(int queryResultFlags, void replyToQuery(int queryResultFlags,
AbstractMessagingPort* p, Message& requestMsg, AbstractMessagingPort* p, Message& requestMsg,
BSONObj& responseObj); BSONObj& responseObj);
/* helper to do a reply using a DbResponse object */ /* helper to do a reply using a DbResponse object */
void replyToQuery(int queryResultFlags, Message &m, DbResponse &dbrespo nse, BSONObj obj); void replyToQuery( int queryResultFlags, Message& m, DbResponse& dbresp onse, BSONObj obj );
/**
* Helper method for setting up a response object.
*
* @param queryResultFlags The flags to set to the response object.
* @param response The object to be used for building the response. The
internal buffer of
* this object will contain the raw data from resultObj after a suc
cessful call.
* @param resultObj The bson object that contains the reply data.
*/
void replyToQuery( int queryResultFlags, Message& response, const BSONO
bj& resultObj );
} // namespace mongo } // namespace mongo
 End of changes. 3 change blocks. 
7 lines changed or deleted 13 lines changed or added


 debug_util.h   debug_util.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
namespace mongo { namespace mongo {
// for debugging
typedef struct _Ints {
int i[100];
} *Ints;
typedef struct _Chars {
char c[200];
} *Chars;
typedef char CHARS[400];
typedef struct _OWS {
int size;
char type;
char string[400];
} *OWS;
#if defined(_DEBUG) #if defined(_DEBUG)
enum {DEBUG_BUILD = 1}; enum {DEBUG_BUILD = 1};
const bool debug=true; const bool debug=true;
#else #else
enum {DEBUG_BUILD = 0}; enum {DEBUG_BUILD = 0};
const bool debug=false; 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
 End of changes. 1 change blocks. 
16 lines changed or deleted 0 lines changed or added


 document_source.h   document_source.h 
skipping to change at line 167 skipping to change at line 167
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.
@param explain create explain output
*/ */
virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const; virtual void addToBsonArray(BSONArrayBuilder *pBuilder,
bool explain = false) const;
protected: protected:
/** /**
Base constructor. Base constructor.
*/ */
DocumentSource(const intrusive_ptr<ExpressionContext> &pExpCtx); 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
@param explain create explain output
*/ */
virtual void sourceToBson(BSONObjBuilder *pBuilder) const = 0; virtual void sourceToBson(BSONObjBuilder *pBuilder,
bool explain) 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 verify(). The default is to need a source, override that to verify(). The default is to
verify() if this has already been set. verify() if this has already been set.
*/ */
DocumentSource *pSource; DocumentSource *pSource;
/* /*
The zero-based user-specified pipeline step. Used for diagnostic s. 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 Will be set to -1 for artificial pipeline steps that were not par t
of the original user specification. of the original user specification.
*/ */
int step; int step;
intrusive_ptr<ExpressionContext> pExpCtx; intrusive_ptr<ExpressionContext> pExpCtx;
/*
for explain: # of rows returned by this source
This is *not* unsigned so it can be passed to BSONObjBuilder.appe
nd().
*/
long long nRowsOut;
}; };
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();
skipping to change at line 236 skipping to change at line 247
@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 @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); const intrusive_ptr<ExpressionContext> &pExpCtx);
protected: protected:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual void sourceToBson(BSONObjBuilder *pBuilder) const; virtual void sourceToBson(BSONObjBuilder *pBuilder, bool explain) c onst;
private: private:
DocumentSourceBsonArray(BSONElement *pBsonElement, DocumentSourceBsonArray(BSONElement *pBsonElement,
const intrusive_ptr<ExpressionContext> &pExpCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
BSONObj embeddedObject; BSONObj embeddedObject;
BSONObjIterator arrayIterator; BSONObjIterator arrayIterator;
BSONElement currentElement; BSONElement currentElement;
bool haveCurrent; bool haveCurrent;
}; };
skipping to change at line 276 skipping to change at line 287
@param pList the list of futures @param pList the list of futures
@param pExpCtx the expression context for the pipeline @param pExpCtx the expression context for the pipeline
@returns the newly created DocumentSource @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); const intrusive_ptr<ExpressionContext> &pExpCtx);
protected: protected:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual void sourceToBson(BSONObjBuilder *pBuilder) const; virtual void sourceToBson(BSONObjBuilder *pBuilder, bool explain) c onst;
private: private:
DocumentSourceCommandFutures(string &errmsg, FuturesList *pList, DocumentSourceCommandFutures(string &errmsg, FuturesList *pList,
const intrusive_ptr<ExpressionContext> &pExpCtx); 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
skipping to change at line 325 skipping to change at line 336
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 @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 string &ns,
const intrusive_ptr<ExpressionContext> &pExpCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
/** /*
Add a BSONObj dependency. Record the namespace. Required for explain.
Some Cursor creation functions rely on BSON objects to specify @param namespace the namespace
their query predicate or sort. These often take a BSONObj */
by reference for these, but to not copy it. As a result, the void setNamespace(const string &ns);
BSONObjs specified must outlive the Cursor. In order to ensure
that, use this to preserve a pointer to the BSONObj here.
From the outside, you must also make sure the BSONObjBuilder /*
creates a lasting copy of the data, otherwise it will go away Record the query that was specified for the cursor this wraps, if
when the builder goes out of scope. Therefore, the typical usag any.
e
pattern for this is
{
BSONObjBuilder builder;
// do stuff to the builder
shared_ptr<BSONObj> pBsonObj(new BSONObj(builder.obj()));
pDocumentSourceCursor->addBsonDependency(pBsonObj);
}
@param pBsonObj pointer to the BSON object to preserve This should be captured after any optimizations are applied to
the pipeline so that it reflects what is really used.
This gets used for explain output.
@param pBsonObj the query to record
*/ */
void addBsonDependency(const shared_ptr<BSONObj> &pBsonObj); void setQuery(const shared_ptr<BSONObj> &pBsonObj);
/*
Record the sort that was specified for the cursor this wraps, if
any.
This should be captured after any optimizations are applied to
the pipeline so that it reflects what is really used.
This gets used for explain output.
@param pBsonObj the sort to record
*/
void setSort(const shared_ptr<BSONObj> &pBsonObj);
/**
Release the cursor, but without changing the other data. This
is used for the explain version of pipeline execution.
*/
void releaseCursor();
protected: protected:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual void sourceToBson(BSONObjBuilder *pBuilder) const; virtual void sourceToBson(BSONObjBuilder *pBuilder, bool explain) c onst;
private: private:
DocumentSourceCursor( DocumentSourceCursor(
const shared_ptr<Cursor> &pTheCursor, const string &ns, const shared_ptr<Cursor> &pTheCursor, const string &ns,
const intrusive_ptr<ExpressionContext> &pExpCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
void findNext(); void findNext();
intrusive_ptr<Document> pCurrent; intrusive_ptr<Document> pCurrent;
string ns; // namespace
/* /*
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 cause its destructor to be called *after* pCursor's. in order cause its destructor to be called *after* pCursor's.
*/ */
shared_ptr<BSONObj> pQuery;
shared_ptr<BSONObj> pSort;
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. In order to yield, we need a ClientCursor.
*/ */
ClientCursor::CleanupPointer pClientCursor; ClientCursor::Holder pClientCursor;
/* /*
Advance the cursor, and yield sometimes. Advance the cursor, and yield sometimes.
If the state of the world changed during the yield such that we 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 are unable to continue execution of the query, this will release the
client cursor, and throw an error. client cursor, and throw an error.
*/ */
void advanceAndYield(); void advanceAndYield();
/* /*
This document source hangs on to the dependency tracker when it This document source hangs on to the dependency tracker when it
gets it so that it can be used for selective reification of gets it so that it can be used for selective reification of
fields in order to avoid fields that are not required through the fields in order to avoid fields that are not required through the
pipeline. pipeline.
*/ */
intrusive_ptr<DependencyTracker> pDependencies; intrusive_ptr<DependencyTracker> pDependencies;
/**
(5/14/12 - moved this to private because it's not used atm)
Add a BSONObj dependency.
Some Cursor creation functions rely on BSON objects to specify
their query predicate or sort. These often take a BSONObj
by reference for these, but do not copy it. As a result, the
BSONObjs specified must outlive the Cursor. In order to ensure
that, use this to preserve a pointer to the BSONObj here.
From the outside, you must also make sure the BSONObjBuilder
creates a lasting copy of the data, otherwise it will go away
when the builder goes out of scope. Therefore, the typical usag
e
pattern for this is
{
BSONObjBuilder builder;
// do stuff to the builder
shared_ptr<BSONObj> pBsonObj(new BSONObj(builder.obj()));
pDocumentSourceCursor->addBsonDependency(pBsonObj);
}
@param pBsonObj pointer to the BSON object to preserve
*/
void addBsonDependency(const shared_ptr<BSONObj> &pBsonObj);
}; };
/* /*
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 490 skipping to change at line 545
find() Cursor mechanism. find() Cursor mechanism.
@param pBuilder the builder to write to @param pBuilder the builder to write to
*/ */
void toMatcherBson(BSONObjBuilder *pBuilder) const; void toMatcherBson(BSONObjBuilder *pBuilder) const;
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, bool explain) c onst;
// 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); const intrusive_ptr<ExpressionContext> &pExpCt x);
intrusive_ptr<Expression> pFilter; intrusive_ptr<Expression> pFilter;
}; };
skipping to change at line 576 skipping to change at line 631
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, bool explain) c onst;
private: private:
DocumentSourceGroup(const intrusive_ptr<ExpressionContext> &pExpCtx ); 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.
*/ */
skipping to change at line 656 skipping to change at line 711
find() Cursor mechanism. find() Cursor mechanism.
@param pBuilder the builder to write to @param pBuilder the builder to write to
*/ */
void toMatcherBson(BSONObjBuilder *pBuilder) const; void toMatcherBson(BSONObjBuilder *pBuilder) const;
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, bool explain) c onst;
// 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); const intrusive_ptr<ExpressionContext> &pExpCtx);
Matcher matcher; Matcher matcher;
}; };
skipping to change at line 696 skipping to change at line 751
@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); 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, bool explain) c onst;
private: private:
DocumentSourceOut(BSONElement *pBsonElement, DocumentSourceOut(BSONElement *pBsonElement,
const intrusive_ptr<ExpressionContext> &pExpCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
}; };
class DocumentSourceProject : class DocumentSourceProject :
public DocumentSource { public DocumentSource {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
skipping to change at line 769 skipping to change at line 824
@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> &pExpCtx); 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, bool explain) c onst;
private: private:
DocumentSourceProject(const intrusive_ptr<ExpressionContext> &pExpC tx); 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(). Utility object used by manageDependencies().
skipping to change at line 903 skipping to change at line 958
@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> &pExpCtx); 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, bool explain) c onst;
private: private:
DocumentSourceSort(const intrusive_ptr<ExpressionContext> &pExpCtx) ; 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 */
typedef vector<intrusive_ptr<ExpressionFieldPath> > SortPaths; typedef vector<intrusive_ptr<ExpressionFieldPath> > SortPaths;
SortPaths vSortKey; SortPaths vSortKey;
vector<bool> vAscending; vector<bool> vAscending;
class Carrier {
public:
/*
We need access to the key for compares, so we have to carry
this around.
*/
DocumentSourceSort *pSort;
intrusive_ptr<Document> pDocument;
Carrier(DocumentSourceSort *pSort,
const intrusive_ptr<Document> &pDocument);
static bool lessThan(const Carrier &rL, const Carrier &rR);
};
/* /*
Compare two documents according to the specified sort key. Compare two documents according to the specified sort key.
@param rL reference to the left document @param rL reference to the left document
@param rR reference to the right document @param rR reference to the right document
@returns a number less than, equal to, or greater than zero, @returns a number less than, equal to, or greater than zero,
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; /*
ListType documents; This is a utility class just for the STL sort that is done
inside.
*/
class Comparator {
public:
bool operator()(
const intrusive_ptr<Document> &pL,
const intrusive_ptr<Document> &pR) {
return (pSort->compare(pL, pR) < 0);
}
ListType::iterator listIterator; inline Comparator(DocumentSourceSort *pS):
pSort(pS) {
}
private:
DocumentSourceSort *pSort;
};
typedef vector<intrusive_ptr<Document> > VectorType;
VectorType documents;
VectorType::iterator docIterator;
intrusive_ptr<Document> pCurrent; intrusive_ptr<Document> pCurrent;
}; };
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();
skipping to change at line 996 skipping to change at line 1055
@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> &pExpCtx); 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, bool explain) c onst;
private: private:
DocumentSourceLimit( DocumentSourceLimit(
const intrusive_ptr<ExpressionContext> &pExpCtx); 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;
}; };
skipping to change at line 1046 skipping to change at line 1105
@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> &pExpCtx); 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, bool explain) c onst;
private: private:
DocumentSourceSkip(const intrusive_ptr<ExpressionContext> &pExpCtx) ; DocumentSourceSkip(const intrusive_ptr<ExpressionContext> &pExpCtx) ;
/* /*
Skips initial documents. Skips initial documents.
*/ */
void skipper(); void skipper();
long long skip; long long skip;
skipping to change at line 1108 skipping to change at line 1167
@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> &pExpCtx); 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, bool explain) c onst;
private: private:
DocumentSourceUnwind(const intrusive_ptr<ExpressionContext> &pExpCt x); 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 */
skipping to change at line 1187 skipping to change at line 1246
pThis(pT) { 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(
DocumentSourceSort *pTheSort,
const intrusive_ptr<Document> &pTheDocument):
pSort(pTheSort),
pDocument(pTheDocument) {
}
} }
 End of changes. 30 change blocks. 
60 lines changed or deleted 114 lines changed or added


 dur.h   dur.h 
skipping to change at line 20 skipping to change at line 20
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(); 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) const unsigned UncommittedBytesLimit = (sizeof(void*)==4) ? 50 * 10
const unsigned UncommittedBytesLimit = 50 * 1024 * 1024; 24 * 1024 : 100 * 1024 * 1024;
#else
const unsigned UncommittedBytesLimit = 100 * 1024 * 1024;
#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
*/ */
void startup(); void startup();
class DurableInterface : boost::noncopyable { class DurableInterface : boost::noncopyable {
public: public:
virtual ~DurableInterface() { log() << "ERROR warning ~DurableI nterface not intended to be called" << endl; } virtual ~DurableInterface() { log() << "ERROR warning ~DurableI nterface not intended to be called" << endl; }
skipping to change at line 184 skipping to change at line 180
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(bool) { return false; } bool commitIfNeeded(bool) { return false; }
bool aCommitIsNeeded() const { return false; } bool aCommitIsNeeded() const { return false; }
void syncDataAndTruncateJournal() {} void syncDataAndTruncateJournal() {}
}; };
class DurableImpl : public DurableInterface { class DurableImpl : public DurableInterface {
bool _aCommitIsNeeded();
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); bool commitIfNeeded(bool);
void syncDataAndTruncateJournal(); void syncDataAndTruncateJournal();
 End of changes. 2 change blocks. 
5 lines changed or deleted 3 lines changed or added


 dur_journal.h   dur_journal.h 
skipping to change at line 58 skipping to change at line 58
(not for recovery mode) (not for recovery mode)
*/ */
void journalingFailure(const char *msg); void journalingFailure(const char *msg);
/** read lsn from disk from the last run before doing recovery */ /** read lsn from disk from the last run before doing recovery */
unsigned long long journalReadLSN(); unsigned long long journalReadLSN();
unsigned long long getLastDataFileFlushTime(); unsigned long long getLastDataFileFlushTime();
/** never throws. /** never throws.
@param anyFiles by default we only look at j._* files. If anyFi
les is true, return true
if there are any files in the journal directory. acquire
PathLock() uses this to
make sure that the journal directory is mounted.
@return true if there are any journal files in the journal dir. @return true if there are any journal files in the journal dir.
*/ */
bool haveJournalFiles(); bool haveJournalFiles(bool anyFiles=false);
// in case disk controller buffers writes // in case disk controller buffers writes
const long long ExtraKeepTimeMs = 10000; const long long ExtraKeepTimeMs = 10000;
const unsigned JournalCommitIntervalDefault = 100; const unsigned JournalCommitIntervalDefault = 100;
} }
} }
 End of changes. 2 change blocks. 
1 lines changed or deleted 6 lines changed or added


 engine.h   engine.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 "mongo/db/jsobj.h"
#include "../db/jsobj.h"
namespace mongo { namespace mongo {
struct JSFile { struct JSFile {
const char* name; const char* name;
const StringData& source; const StringData& source;
}; };
typedef unsigned long long ScriptingFunction; typedef unsigned long long ScriptingFunction;
typedef BSONObj (*NativeFunction) ( const BSONObj &args, void* data ); typedef BSONObj (*NativeFunction) ( const BSONObj &args, void* data );
 End of changes. 1 change blocks. 
2 lines changed or deleted 1 lines changed or added


 engine_spidermonkey.h   engine_spidermonkey.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 "engine.h" #include "mongo/scripting/engine.h"
// START inc hacking // START inc hacking
#ifdef WIN32 #ifdef WIN32
#include "jstypes.h" #include <third_party/js-1.7/jstypes.h>
#undef JS_PUBLIC_API #undef JS_PUBLIC_API
#undef JS_PUBLIC_DATA #undef JS_PUBLIC_DATA
#define JS_PUBLIC_API(t) t __cdecl #define JS_PUBLIC_API(t) t __cdecl
#define JS_PUBLIC_DATA(t) t #define JS_PUBLIC_DATA(t) t
#endif #endif
#include "jsapi.h" #include <third_party/js-1.7/jsapi.h>
#include "jsobj.h"
#include "jsdate.h"
#include "jsregexp.h"
// END inc hacking // END inc hacking
// -- SM 1.6 hacks --- // -- SM 1.6 hacks ---
#ifndef JSCLASS_GLOBAL_FLAGS #ifndef JSCLASS_GLOBAL_FLAGS
#error old version of spider monkey ( probably 1.6 ) you should upgrade to at least 1.7 #error old version of spider monkey ( probably 1.6 ) you should upgrade to at least 1.7
#endif #endif
// -- END SM 1.6 hacks --- // -- END SM 1.6 hacks ---
#ifdef JSVAL_IS_TRACEABLE #ifdef JSVAL_IS_TRACEABLE
 End of changes. 3 change blocks. 
6 lines changed or deleted 3 lines changed or added


 explain.h   explain.h 
skipping to change at line 54 skipping to change at line 54
/** Data describing execution of a query plan. */ /** Data describing execution of a query plan. */
class ExplainPlanInfo { class ExplainPlanInfo {
public: public:
ExplainPlanInfo(); ExplainPlanInfo();
/** Note information about the plan. */ /** Note information about the plan. */
void notePlan( const Cursor &cursor, bool scanAndOrder, bool indexO nly ); void notePlan( const Cursor &cursor, bool scanAndOrder, bool indexO nly );
/** Note an iteration of the plan. */ /** Note an iteration of the plan. */
void noteIterate( bool match, bool loadedRecord, const Cursor &curs or ); void noteIterate( bool match, bool loadedRecord, const Cursor &curs or );
/** Note that the plan yielded. */
void noteYield();
/** Note that the plan finished execution. */ /** Note that the plan finished execution. */
void noteDone( const Cursor &cursor ); void noteDone( const Cursor &cursor );
/** Note that the plan was chosen over others by the query optimize r. */ /** Note that the plan was chosen over others by the query optimize r. */
void notePicked(); void notePicked();
/** BSON summary of the plan. */ /** BSON summary of the plan. */
BSONObj bson() const; BSONObj bson() const;
/** Combined details of both the plan and its clause. */ /** Combined details of both the plan and its clause. */
BSONObj pickedPlanBson( const ExplainClauseInfo &clauseInfo ) const ; BSONObj pickedPlanBson( const ExplainClauseInfo &clauseInfo ) const ;
skipping to change at line 80 skipping to change at line 78
private: private:
void noteCursorUpdate( const Cursor &cursor ); void noteCursorUpdate( const Cursor &cursor );
string _cursorName; string _cursorName;
bool _isMultiKey; bool _isMultiKey;
long long _n; long long _n;
long long _nscannedObjects; long long _nscannedObjects;
long long _nscanned; long long _nscanned;
bool _scanAndOrder; bool _scanAndOrder;
bool _indexOnly; bool _indexOnly;
int _nYields;
BSONObj _indexBounds; BSONObj _indexBounds;
bool _picked; bool _picked;
bool _done; bool _done;
BSONObj _details; BSONObj _details;
}; };
/** Data describing execution of a query clause. */ /** Data describing execution of a query clause. */
class ExplainClauseInfo { class ExplainClauseInfo {
public: public:
ExplainClauseInfo(); ExplainClauseInfo();
/** Note an iteration of the clause. */ /** Note an iteration of the clause. */
void noteIterate( bool match, bool loadedRecord, bool chunkSkip ); void noteIterate( bool match, bool loadedRecord, bool chunkSkip );
/** Note a yield for the clause. */
void noteYield();
/** Revise the total number of documents returned to match an exter nal count. */ /** Revise the total number of documents returned to match an exter nal count. */
void reviseN( long long n ); void reviseN( long long n );
/** Stop the clauses's timer. */ /** Stop the clauses's timer. */
void stopTimer(); void stopTimer();
/** Add information about a plan to this clause. */ /** Add information about a plan to this clause. */
void addPlanInfo( const shared_ptr<ExplainPlanInfo> &info ); void addPlanInfo( const shared_ptr<ExplainPlanInfo> &info );
BSONObj bson() const; BSONObj bson() const;
long long n() const { return _n; } long long n() const { return _n; }
long long nscannedObjects() const { return _nscannedObjects; } long long nscannedObjects() const { return _nscannedObjects; }
long long nscanned() const; long long nscanned() const;
long long nChunkSkips() const { return _nChunkSkips; } long long nChunkSkips() const { return _nChunkSkips; }
int nYields() const { return _nYields; }
int millis() const { return _timer.duration(); } int millis() const { return _timer.duration(); }
private: private:
const ExplainPlanInfo &virtualPickedPlan() const; const ExplainPlanInfo &virtualPickedPlan() const;
list<shared_ptr<const ExplainPlanInfo> > _plans; list<shared_ptr<const ExplainPlanInfo> > _plans;
long long _n; long long _n;
long long _nscannedObjects; long long _nscannedObjects;
long long _nChunkSkips; long long _nChunkSkips;
int _nYields;
DurationTimer _timer; DurationTimer _timer;
}; };
/** Data describing execution of a query. */ /** Data describing execution of a query. */
class ExplainQueryInfo { class ExplainQueryInfo {
public: public:
/** Note an iteration of the query's current clause. */ /** Note an iteration of the query's current clause. */
void noteIterate( bool match, bool loadedRecord, bool chunkSkip ); void noteIterate( bool match, bool loadedRecord, bool chunkSkip );
/** Note a yield of the query's current clause. */
void noteYield();
/** Revise the number of documents returned by the current clause. */ /** Revise the number of documents returned by the current clause. */
void reviseN( long long n ); void reviseN( long long n );
/* Additional information describing the query. */ /* Additional information describing the query. */
struct AncillaryInfo { struct AncillaryInfo {
BSONObj _oldPlan; BSONObj _oldPlan;
}; };
void setAncillaryInfo( const AncillaryInfo &ancillaryInfo ); void setAncillaryInfo( const AncillaryInfo &ancillaryInfo );
/* Add information about a clause to this query. */ /* Add information about a clause to this query. */
skipping to change at line 158 skipping to change at line 161
/** Note information about the plan. */ /** Note information about the plan. */
void notePlan( const Cursor &cursor, bool scanAndOrder, bool indexO nly ) { void notePlan( const Cursor &cursor, bool scanAndOrder, bool indexO nly ) {
_planInfo->notePlan( cursor, scanAndOrder, indexOnly ); _planInfo->notePlan( cursor, scanAndOrder, indexOnly );
} }
/** Note an iteration of the plan and the clause. */ /** Note an iteration of the plan and the clause. */
void noteIterate( bool match, bool loadedRecord, bool chunkSkip, co nst Cursor &cursor ) { void noteIterate( bool match, bool loadedRecord, bool chunkSkip, co nst Cursor &cursor ) {
_planInfo->noteIterate( match, loadedRecord, cursor ); _planInfo->noteIterate( match, loadedRecord, cursor );
_queryInfo->noteIterate( match, loadedRecord, chunkSkip ); _queryInfo->noteIterate( match, loadedRecord, chunkSkip );
} }
/** Note that the plan yielded. */ /** Note a yield for the clause. */
void noteYield() { void noteYield() {
_planInfo->noteYield(); _queryInfo->noteYield();
} }
/** Note that the plan finished execution. */ /** Note that the plan finished execution. */
void noteDone( const Cursor &cursor ) { void noteDone( const Cursor &cursor ) {
_planInfo->noteDone( cursor ); _planInfo->noteDone( cursor );
} }
/** Return the corresponding ExplainQueryInfo for further use. */ /** Return the corresponding ExplainQueryInfo for further use. */
shared_ptr<ExplainQueryInfo> queryInfo() const { shared_ptr<ExplainQueryInfo> queryInfo() const {
return _queryInfo; return _queryInfo;
} }
 End of changes. 8 change blocks. 
5 lines changed or deleted 8 lines changed or added


 expression.h   expression.h 
skipping to change at line 808 skipping to change at line 808
Check that the named argument fits in an integer. Check that the named argument fits in an integer.
@params pName the name of the argument @params pName the name of the argument
@params value the long value of the argument @params value the long value of the argument
@returns the integer value @returns the integer value
@throws uassert if the value is out of range @throws uassert if the value is out of range
*/ */
int checkIntRange(const char *pName, long long value) const; int checkIntRange(const char *pName, long long value) const;
}; };
class ExpressionLiteral :
public ExpressionNary {
public:
// virtuals from ExpressionNary
virtual ~ExpressionLiteral();
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:
ExpressionLiteral();
};
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);
 End of changes. 1 change blocks. 
0 lines changed or deleted 17 lines changed or added


 extsort.h   extsort.h 
skipping to change at line 139 skipping to change at line 139
boost::filesystem::path _root; boost::filesystem::path _root;
int _arraySize; int _arraySize;
InMemory * _cur; InMemory * _cur;
long _curSizeSoFar; long _curSizeSoFar;
list<string> _files; list<string> _files;
bool _sorted; bool _sorted;
static unsigned long long _compares; static unsigned long long _compares;
static unsigned long long _uniqueNumber;
}; };
} }
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 file_allocator.h   file_allocator.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.
*/ */
#include "pch.h" #include "pch.h"
#include <list> #include <list>
#include <boost/filesystem/path.hpp>
#include <boost/thread/condition.hpp> #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 56 skipping to change at line 56
/** /**
* Returns when file has been allocated. If file exists, size is * Returns when file has been allocated. If file exists, size is
* updated to match existing file size. * updated to match existing file size.
*/ */
void allocateAsap( const string &name, unsigned long long &size ); void allocateAsap( const string &name, unsigned long long &size );
void waitUntilFinished() const; void waitUntilFinished() const;
bool hasFailed() const; bool hasFailed() const;
static void ensureLength(int fd , long size); static void ensureLength(int fd, long size);
/** @return the singletone */ /** @return the singletone */
static FileAllocator * get(); static FileAllocator * get();
private: private:
FileAllocator(); FileAllocator();
#if !defined(_WIN32)
void checkFailure(); void checkFailure();
// caller must hold pendingMutex_ lock. Returns size if allocated or // caller must hold pendingMutex_ lock. Returns size if allocated or
// allocation requested, -1 otherwise. // allocation requested, -1 otherwise.
long prevSize( const string &name ) const; long prevSize( const string &name ) const;
// 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 );
// generate a unique name for temporary files
string makeTempFileName( boost::filesystem::path root );
mutable mongo::mutex _pendingMutex; mutable mongo::mutex _pendingMutex;
mutable boost::condition _pendingUpdated; mutable boost::condition _pendingUpdated;
std::list< string > _pending; std::list< string > _pending;
mutable map< string, long > _pendingSize; mutable map< string, long > _pendingSize;
// unique number for temporary files
static unsigned long long _uniqueNumber;
bool _failed; bool _failed;
#endif
static FileAllocator* _instance; static FileAllocator* _instance;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 6 change blocks. 
4 lines changed or deleted 8 lines changed or added


 goodies.h   goodies.h 
skipping to change at line 26 skipping to change at line 26
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include <boost/detail/endian.hpp> #include <boost/detail/endian.hpp>
#include <boost/thread/condition_variable.hpp> #include <boost/thread/condition_variable.hpp>
#include "mongo/bson/util/misc.h" #include "mongo/bson/util/misc.h"
#include "mongo/util/concurrency/mutex.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);
/** void setThreadName(const char * name);
* @return if this name has an increasing counter associated, return th
e value
* otherwise 0
*/
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();
} }
bool isPrime(int n); bool isPrime(int n);
 End of changes. 2 change blocks. 
7 lines changed or deleted 1 lines changed or added


 grid.h   grid.h 
skipping to change at line 51 skipping to change at line 51
*/ */
DBConfigPtr getDBConfig( string ns , bool create=true , const strin g& shardNameHint="" ); DBConfigPtr getDBConfig( string ns , bool create=true , const strin g& shardNameHint="" );
/** /**
* removes db entry. * removes db entry.
* on next getDBConfig call will fetch from db * on next getDBConfig call will fetch from db
*/ */
void removeDB( string db ); void removeDB( string db );
/** /**
* removes db entry - only this DBConfig object will be removed,
* other DBConfigs which may have been created in the meantime wil
l not be harmed
* on next getDBConfig call will fetch from db
*
* Using this method avoids race conditions where multiple threads
detect a database
* reload has failed.
*
* Example : N threads receive version exceptions and dbConfig.rel
oad(), while
* simultaneously a dropDatabase is occurring. In the meantime, t
he dropDatabase call
* attempts to create a DBConfig object if one does not exist, to
load the db info,
* but the config is repeatedly deleted as soon as it is created.
Using this method
* prevents the deletion of configs we don't know about.
*
*/
void removeDBIfExists( const DBConfig& database );
/**
* @return true if shards and config servers are allowed to use 'lo calhost' in address * @return true if shards and config servers are allowed to use 'lo calhost' in address
*/ */
bool allowLocalHost() const; bool allowLocalHost() const;
/** /**
* @param whether to allow shards and config servers to use 'localh ost' in address * @param whether to allow shards and config servers to use 'localh ost' in address
*/ */
void setAllowLocalHost( bool allow ); void setAllowLocalHost( bool allow );
/** /**
skipping to change at line 83 skipping to change at line 100
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 string& ns = "" ) const; bool shouldBalance( const string& ns = "", BSONObj* balancerDocOut = 0 ) 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. 2 change blocks. 
1 lines changed or deleted 24 lines changed or added


 gridfs.h   gridfs.h 
skipping to change at line 70 skipping to change at line 70
* @param prefix - if you want your data somewhere besides <dbname> .fs * @param prefix - if you want your data somewhere besides <dbname> .fs
*/ */
GridFS( DBClientBase& client , const string& dbName , const string& prefix="fs" ); GridFS( DBClientBase& client , const string& dbName , const string& prefix="fs" );
~GridFS(); ~GridFS();
/** /**
* @param * @param
*/ */
void setChunkSize(unsigned int size); void setChunkSize(unsigned int size);
unsigned int getChunkSize() const;
/** /**
* puts the file reference by fileName into the db * puts the file reference by fileName into the db
* @param fileName local filename relative to process * @param fileName local filename relative to process
* @param remoteName optional filename to use for file stored in Gr idFS * @param remoteName optional filename to use for file stored in Gr idFS
* (default is to use fileName parameter) * (default is to use fileName parameter)
* @param contentType optional MIME type for this object. * @param contentType optional MIME type for this object.
* (default is to omit) * (default is to omit)
* @return the file object * @return the file object
*/ */
BSONObj storeFile( const string& fileName , const string& remoteNam e="" , const string& contentType=""); BSONObj storeFile( const string& fileName , const string& remoteNam e="" , const string& contentType="");
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 hex.h   hex.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 "mongo/bson/util/builder.h"
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;
verify( 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 std::string toHex(const void* inRaw, int len) {
static const char hexchars[] = "0123456789ABCDEF"; static const char hexchars[] = "0123456789ABCDEF";
StringBuilder out; StringBuilder out;
const char* in = reinterpret_cast<const char*>(inRaw); const char* in = reinterpret_cast<const char*>(inRaw);
for (int i=0; i<len; ++i) { for (int i=0; i<len; ++i) {
char c = in[i]; char c = in[i];
char hi = hexchars[(c & 0xF0) >> 4]; char hi = hexchars[(c & 0xF0) >> 4];
char lo = hexchars[(c & 0x0F)]; char lo = hexchars[(c & 0x0F)];
out << hi << lo; out << hi << lo;
} }
return out.str(); return out.str();
} }
inline string toHexLower(const void* inRaw, int len) { inline std::string toHexLower(const void* inRaw, int len) {
static const char hexchars[] = "0123456789abcdef"; static const char hexchars[] = "0123456789abcdef";
StringBuilder out; StringBuilder out;
const char* in = reinterpret_cast<const char*>(inRaw); const char* in = reinterpret_cast<const char*>(inRaw);
for (int i=0; i<len; ++i) { for (int i=0; i<len; ++i) {
char c = in[i]; char c = in[i];
char hi = hexchars[(c & 0xF0) >> 4]; char hi = hexchars[(c & 0xF0) >> 4];
char lo = hexchars[(c & 0x0F)]; char lo = hexchars[(c & 0x0F)];
out << hi << lo; out << hi << lo;
 End of changes. 3 change blocks. 
2 lines changed or deleted 6 lines changed or added


 hostandport.h   hostandport.h 
skipping to change at line 48 skipping to change at line 48
*/ */
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) {
verify( !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 static HostAndPort me();
ort); }
/* uses real hostname instead of localhost */
static HostAndPort Me();
bool operator<(const HostAndPort& r) const { bool operator<(const HostAndPort& r) const {
string h = host(); string h = host();
string rh = r.host(); string rh = r.host();
if( h < rh ) if( h < rh )
return true; return true;
if( h == rh ) if( h == rh )
return port() < r.port(); return port() < r.port();
return false; return false;
} }
skipping to change at line 135 skipping to change at line 132
private: private:
bool dyn() const { return !_dynName.empty(); } bool dyn() const { return !_dynName.empty(); }
void init(const char *); void init(const char *);
// invariant (except full obj assignment): // invariant (except full obj assignment):
string _dynName; // when this is set, _host and _port aren't used, rather, we look up the dyn info every time. string _dynName; // when this is set, _host and _port aren't used, rather, we look up the dyn info every time.
string _host; string _host;
int _port; // -1 indicates unspecified int _port; // -1 indicates unspecified
}; };
inline HostAndPort HostAndPort::Me() { inline HostAndPort HostAndPort::me() {
{ {
string s = dynHostMyName(); string s = dynHostMyName();
if( !s.empty() ) if( !s.empty() )
return HostAndPort(s); return HostAndPort(s);
} }
const char* ips = cmdLine.bind_ip.c_str(); const char* ips = cmdLine.bind_ip.c_str();
while(*ips) { while(*ips) {
string ip; string ip;
const char * comma = strchr(ips, ','); const char * comma = strchr(ips, ',');
 End of changes. 2 change blocks. 
6 lines changed or deleted 2 lines changed or added


 index.h   index.h 
skipping to change at line 158 skipping to change at line 158
} }
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");
} }
static bool isIdIndexPattern( const BSONObj &pattern ) { static bool isIdIndexPattern( const BSONObj &pattern ) {
BSONObjIterator i(pattern); BSONObjIterator i(pattern);
BSONElement e = i.next(); BSONElement e = i.next();
if( strcmp(e.fieldName(), "_id") != 0 ) return false; //_id index must have form exactly {_id : 1} or {_id : -1}.
//Allows an index of form {_id : "hashed"} to exist but
//do not consider it to be the primary _id index
if(! ( strcmp(e.fieldName(), "_id") == 0
&& (e.numberInt() == 1 || e.numberInt() == -1)))
return false;
return i.next().eoo(); return i.next().eoo();
} }
/* returns true if this is the _id index. */ /* returns true if this is the _id index. */
bool isIdIndex() const { bool isIdIndex() const {
return isIdIndexPattern( keyPattern() ); return isIdIndexPattern( keyPattern() );
} }
/* gets not our namespace name (indexNamespace for that), /* gets not our namespace name (indexNamespace for that),
but the collection we index, its name. but the collection we index, its name.
skipping to change at line 253 skipping to change at line 258
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, const char *ns, Namespace Details& d, void getIndexChanges(vector<IndexChanges>& v, const char *ns, Namespace Details& d,
BSONObj newObj, BSONObj oldObj, bool &cangedId); 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);
void assureSysIndexesEmptied(const char *ns, IndexDetails *exceptForIdI
ndex);
int removeFromSysIndexes(const char *ns, const char *idxName);
} // namespace mongo } // namespace mongo
 End of changes. 2 change blocks. 
1 lines changed or deleted 11 lines changed or added


 indexkey.h   indexkey.h 
skipping to change at line 166 skipping to change at line 166
IndexType* getType() const { IndexType* getType() const {
return _indexType.get(); return _indexType.get();
} }
const IndexDetails * getDetails() const { const IndexDetails * getDetails() const {
return _details; return _details;
} }
IndexSuitability suitability( const BSONObj& query , const BSONObj& order ) const ; IndexSuitability suitability( const BSONObj& query , const BSONObj& order ) const ;
bool isSparse() const { return _sparse; }
protected: protected:
int indexVersion() const; int indexVersion() const;
IndexSuitability _suitability( const BSONObj& query , const BSONObj & order ) const ; IndexSuitability _suitability( const BSONObj& query , const BSONObj & order ) const ;
BSONSizeTracker _sizeTracker; BSONSizeTracker _sizeTracker;
vector<const char*> _fieldNames; vector<const char*> _fieldNames;
vector<BSONElement> _fixed; vector<BSONElement> _fixed;
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 instance.h   instance.h 
skipping to change at line 64 skipping to change at line 64
}; };
extern DiagLog _diaglog; extern DiagLog _diaglog;
/* we defer response until we unlock. don't want a blocked socket to /* we defer response until we unlock. don't want a blocked socket to
keep things locked. keep things locked.
*/ */
struct DbResponse { struct DbResponse {
Message *response; Message *response;
MSGID responseTo; MSGID responseTo;
const char *exhaust; /* points to ns if exhaust mode. 0=normal mode string exhaustNS; /* points to ns if exhaust mode. 0=normal mode*/
*/ DbResponse(Message *r, MSGID rt) : response(r), responseTo(rt){ }
DbResponse(Message *r, MSGID rt) : response(r), responseTo(rt), exh
aust(0) { }
DbResponse() { DbResponse() {
response = 0; response = 0;
exhaust = 0;
} }
~DbResponse() { delete response; } ~DbResponse() { delete response; }
}; };
void assembleResponse( Message &m, DbResponse &dbresponse, const HostAn dPort &client ); void assembleResponse( Message &m, DbResponse &dbresponse, const HostAn dPort &client );
void getDatabaseNames( vector< string > &names , const string& usePath = dbpath ); void getDatabaseNames( vector< string > &names , const string& usePath = dbpath );
/* returns true if there is no data on this server. useful when starti ng replication. /* returns true if there is no data on this server. useful when starti ng replication.
local database does NOT count. local database does NOT count.
 End of changes. 2 change blocks. 
5 lines changed or deleted 2 lines changed or added


 json.h   json.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 <string>
#include "jsobj.h"
#include "mongo/bson/bsonobj.h"
namespace mongo { namespace mongo {
/** Create a BSONObj from a JSON <http://www.json.org> string. In addi tion /** Create a BSONObj from a JSON <http://www.json.org> string. In addi tion
to the JSON extensions extensions described here to the JSON extensions extensions described here
<http://mongodb.onconfluence.com/display/DOCS/Mongo+Extended+JSON>, <http://mongodb.onconfluence.com/display/DOCS/Mongo+Extended+JSON>,
this function accepts certain unquoted field names and allows single q uotes this function accepts certain unquoted field names and allows single q uotes
to optionally be used when specifying field names and string values in stead to optionally be used when specifying field names and string values in stead
of double quotes. JSON unicode escape sequences (of the form \uXXXX) are of double quotes. JSON unicode escape sequences (of the form \uXXXX) are
converted to utf8. converted to utf8.
\throws MsgAssertionException if parsing fails. The message included with \throws MsgAssertionException if parsing fails. The message included with
this assertion includes a rough indication of where parsing failed. this assertion includes a rough indication of where parsing failed.
*/ */
BSONObj fromjson(const string &str); BSONObj fromjson(const std::string &str);
/** len will be size of JSON object in text chars. */ /** len will be size of JSON object in text chars. */
BSONObj fromjson(const char *str, int* len=NULL); BSONObj fromjson(const char *str, int* len=NULL);
} // namespace mongo } // namespace mongo
 End of changes. 2 change blocks. 
3 lines changed or deleted 4 lines changed or added


 linenoise_utf8.h   linenoise_utf8.h 
skipping to change at line 19 skipping to change at line 19
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#include <boost/smart_ptr/scoped_array.hpp> #include <boost/smart_ptr/scoped_array.hpp>
#include <string.h>
namespace linenoise_utf8 { namespace linenoise_utf8 {
typedef unsigned char UChar8; // UTF-8 octet typedef unsigned char UChar8; // UTF-8 octet
typedef unsigned int UChar32; // Unicode code point typedef unsigned int UChar32; // Unicode code point
// Error bits (or-ed together) returned from utf8toUChar32string // Error bits (or-ed together) returned from utf8toUChar32string
// //
enum BadUTF8 { enum BadUTF8 {
BadUTF8_no_error = 0x00, BadUTF8_no_error = 0x00,
skipping to change at line 111 skipping to change at line 112
* @return Negative if first < second, positive if first > second, zero if equal * @return Negative if first < second, positive if first > second, zero if equal
*/ */
int strncmp32( UChar32* first32, UChar32* second32, size_t length ); int strncmp32( UChar32* first32, UChar32* second32, size_t length );
/** /**
* Internally convert an array of UChar32 characters of specified length to UTF-8 and write it to fileHandle * Internally convert an array of UChar32 characters of specified length to UTF-8 and write it to fileHandle
* *
* @param fileHandle File handle to write to * @param fileHandle File handle to write to
* @param string32 Source UChar32 character array, may not be null terminated * @param string32 Source UChar32 character array, may not be null terminated
* @param sourceLengthInCharacters Number of source characters to convert and write * @param sourceLengthInCharacters Number of source characters to convert and write
* @return Number of bytes written, -1 on error
*/ */
int write32( int fileHandle, const UChar32* string32, unsigned int sourceLe ngthInCharacters ); int write32( int fileHandle, const UChar32* string32, unsigned int sourceLe ngthInCharacters );
/** /**
* Template and classes for UChar8 and UChar32 strings * Template and classes for UChar8 and UChar32 strings
*/ */
template <typename char_type> template <typename char_type>
struct UtfStringMixin { struct UtfStringMixin {
typedef char_type char_t; // inherited typedef char_type char_t; // inherited
 End of changes. 2 change blocks. 
0 lines changed or deleted 2 lines changed or added


 listen.h   listen.h 
skipping to change at line 25 skipping to change at line 25
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "sock.h" #include "sock.h"
#include "mongo/util/concurrency/ticketholder.h" #include "mongo/util/concurrency/ticketholder.h"
namespace mongo { namespace mongo {
const int DEFAULT_MAX_CONN = 20000;
const int MAX_MAX_CONN = 20000;
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 );
virtual ~Listener(); virtual ~Listener();
#ifdef MONGO_SSL #ifdef MONGO_SSL
skipping to change at line 47 skipping to change at line 50
* 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(boost::shared_ptr<Socket> psocket); virtual void accepted(boost::shared_ptr<Socket> psocket, long long connectionId );
virtual void acceptedMP(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() {
 End of changes. 2 change blocks. 
1 lines changed or deleted 4 lines changed or added


 lockstat.h   lockstat.h 
// lockstat.h // lockstat.h
/**
* Copyright (C) 2008 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3
,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public Licen
se
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once #pragma once
#include "util/timer.h" #include "util/timer.h"
#include "mongo/platform/atomic_uint64.h" #include "mongo/platform/atomic_word.h"
namespace mongo { namespace mongo {
class BSONObj; class BSONObj;
class LockStat { class LockStat {
enum { N = 4 }; enum { N = 4 };
public: public:
Timer W_Timer; void recordAcquireTimeMicros( char type , long long micros );
void recordLockTimeMicros( char type , long long micros );
struct Acquiring {
Timer tmr;
LockStat& ls;
unsigned type;
explicit Acquiring(LockStat&, char type);
~Acquiring();
};
void unlocking(char type);
BSONObj report() const; BSONObj report() const;
void report( StringBuilder& builder ) const;
long long getTimeLocked( char type ) const { return timeLocked[mapN o(type)].load(); }
private: private:
static void _append( BSONObjBuilder& builder, const AtomicInt64* da
ta );
// RWrw // RWrw
AtomicUInt64 timeAcquiring[N]; // in micros
AtomicUInt64 timeLocked[N]; AtomicInt64 timeAcquiring[N];
AtomicInt64 timeLocked[N];
static unsigned mapNo(char type); static unsigned mapNo(char type);
static char nameFor(unsigned offset);
}; };
} }
 End of changes. 8 change blocks. 
14 lines changed or deleted 31 lines changed or added


 log.h   log.h 
skipping to change at line 29 skipping to change at line 29
#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 "mongo/bson/util/builder.h" #include "mongo/bson/util/builder.h"
#include "mongo/util/concurrency/mutex.h"
#include "mongo/util/debug_util.h" #include "mongo/util/debug_util.h"
#include "mongo/util/exit_code.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;
skipping to change at line 82 skipping to change at line 83
case LL_SEVERE: case LL_SEVERE:
return LOG_CRIT; return LOG_CRIT;
default: default:
return LL_INFO; return LL_INFO;
} }
} }
#endif #endif
class LabeledLevel { class LabeledLevel {
public: public:
LabeledLevel( int level ) : _level( level ) {}
LabeledLevel( const char* label, int level ) : _label( label ), _le
vel( level ) {}
LabeledLevel( const string& label, int level ) : _label( label ), _
level( level ) {}
LabeledLevel( int level ) : _level( level ) {} LabeledLevel operator+( int i ) const {
LabeledLevel( const char* label, int level ) : _label( label ), _lev return LabeledLevel( _label, _level + i );
el( level ) {} }
LabeledLevel( const string& label, int level ) : _label( label ), _l
evel( level ) {}
LabeledLevel operator+( int i ) const {
return LabeledLevel( _label, _level + i );
}
LabeledLevel operator+( const char* label ) const { LabeledLevel operator+( const char* label ) const {
if( _label == "" ) if( _label == "" )
return LabeledLevel( label, _level ); return LabeledLevel( label, _level );
return LabeledLevel( _label + string("::") + label, _level ); return LabeledLevel( _label + string("::") + label, _level );
} }
LabeledLevel operator+( string& label ) const { LabeledLevel operator+( string& label ) const {
return LabeledLevel( _label + string("::") + label, _level ); return LabeledLevel( _label + string("::") + label, _level );
} }
LabeledLevel operator-( int i ) const { LabeledLevel operator-( int i ) const {
return LabeledLevel( _label, _level - i ); return LabeledLevel( _label, _level - i );
} }
const string& getLabel() const { return _label; } const string& getLabel() const { return _label; }
int getLevel() const { return _level; } int getLevel() const { return _level; }
private: private:
string _label; string _label;
int _level; int _level;
}; };
class LazyString { class LazyString {
public: public:
virtual ~LazyString() {} virtual ~LazyString() {}
virtual string val() const = 0; virtual string val() const = 0;
}; };
// Utility class for stringifying object only when val() called. // Utility class for stringifying object only when val() called.
template< class T > template< class T >
skipping to change at line 450 skipping to change at line 450
~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 ); void rawOut( const string &s );
/**
* Write the current context (backtrace), along with the optional "msg"
.
*/
void logContext(const char *msg = NULL);
} // namespace mongo } // namespace mongo
 End of changes. 9 change blocks. 
24 lines changed or deleted 30 lines changed or added


 matcher.h   matcher.h 
skipping to change at line 30 skipping to change at line 30
#pragma once #pragma once
#include "jsobj.h" #include "jsobj.h"
#include "pcrecpp.h" #include "pcrecpp.h"
namespace mongo { namespace mongo {
class Cursor; class Cursor;
class CoveredIndexMatcher; class CoveredIndexMatcher;
class ElementMatcher;
class Matcher; class Matcher;
class FieldRangeVector; class FieldRangeVector;
class RegexMatcher { class RegexMatcher {
public: public:
const char *_fieldName; const char *_fieldName;
const char *_regex; const char *_regex;
const char *_flags; const char *_flags;
string _prefix; string _prefix;
shared_ptr< pcrecpp::RE > _re; shared_ptr< pcrecpp::RE > _re;
skipping to change at line 53 skipping to change at line 54
struct element_lt { struct element_lt {
bool operator()(const BSONElement& l, const BSONElement& r) const { bool operator()(const BSONElement& l, const BSONElement& r) const {
int x = (int) l.canonicalType() - (int) r.canonicalType(); int x = (int) l.canonicalType() - (int) r.canonicalType();
if ( x < 0 ) return true; if ( x < 0 ) return true;
else if ( x > 0 ) return false; else if ( x > 0 ) return false;
return compareElementValues(l,r) < 0; return compareElementValues(l,r) < 0;
} }
}; };
/**
* An interface for visiting a Matcher and all of its nested Matchers a
nd ElementMatchers.
* RegexMatchers are not visited.
*/
class MatcherVisitor {
public:
virtual ~MatcherVisitor() {}
virtual void visitMatcher( const Matcher& matcher ) {}
virtual void visitElementMatcher( const ElementMatcher& elementMatc
her ) {}
};
class ElementMatcher { class ElementMatcher {
public: public:
ElementMatcher() { ElementMatcher() {
} }
ElementMatcher( BSONElement e , int op, bool isNot ); ElementMatcher( BSONElement e , int op, bool isNot );
ElementMatcher( BSONElement e , int op , const BSONObj& array, bool isNot ); ElementMatcher( BSONElement e , int op , const BSONObj& array, bool isNot );
~ElementMatcher() { } ~ElementMatcher() { }
bool negativeCompareOp() const { return _compareOp == BSONObj::NE | | _compareOp == BSONObj::NIN; } bool negativeCompareOp() const { return _compareOp == BSONObj::NE | | _compareOp == BSONObj::NIN; }
int inverseOfNegativeCompareOp() const; int inverseOfNegativeCompareOp() const;
bool negativeCompareOpContainsNull() const; bool negativeCompareOpContainsNull() const;
void visit( MatcherVisitor& visitor ) const;
BSONElement _toMatch; BSONElement _toMatch;
int _compareOp; int _compareOp;
bool _isNot; bool _isNot;
shared_ptr< set<BSONElement,element_lt> > _myset; shared_ptr< set<BSONElement,element_lt> > _myset;
shared_ptr< vector<RegexMatcher> > _myregex; shared_ptr< vector<RegexMatcher> > _myregex;
// these are for specific operators // these are for specific operators
int _mod; int _mod;
int _modm; int _modm;
BSONType _type; BSONType _type;
skipping to change at line 184 skipping to change at line 198
This can be used to gather a list of all the references made by This can be used to gather a list of all the references made by
this matcher. The implementation of this parallels that of this matcher. The implementation of this parallels that of
matches() above. matches() above.
@param pSink a FieldSink that the caller will use to gather or @param pSink a FieldSink that the caller will use to gather or
process the references process the references
*/ */
void visitReferences(FieldSink *pSink) const; void visitReferences(FieldSink *pSink) const;
#endif /* MONGO_LATER_SERVER_4644 */ #endif /* MONGO_LATER_SERVER_4644 */
/**
* Visit this Matcher and all of its nested Matchers and ElementMat
chers. All top level
* ElementMatchers of a Matcher are visited immediately after the M
atcher itself (before any
* other Matcher is visited).
*/
void visit( MatcherVisitor& visitor ) const;
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 ) {
_orDedupConstraints.push_back( frv );
}
void popOrClause() {
_orMatchers.pop_front();
}
/** /**
* @return true if this key matcher will return the same true/false * @return true if this key matcher will return the same true/false
* value as the provided doc matcher. * value as the provided doc matcher.
*/ */
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
skipping to change at line 262 skipping to change at line 275
*/ */
bool _atomic; bool _atomic;
vector<RegexMatcher> _regexs; vector<RegexMatcher> _regexs;
// so we delete the mem when we're done: // so we delete the mem when we're done:
vector< shared_ptr< BSONObjBuilder > > _builders; vector< shared_ptr< BSONObjBuilder > > _builders;
list< shared_ptr< Matcher > > _andMatchers; list< shared_ptr< Matcher > > _andMatchers;
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;
friend class CoveredIndexMatcher; friend class CoveredIndexMatcher;
}; };
// If match succeeds on index key, then attempt to match full document. // If match succeeds on index key, then attempt to match full document.
class CoveredIndexMatcher : boost::noncopyable { class CoveredIndexMatcher : boost::noncopyable {
public: public:
CoveredIndexMatcher(const BSONObj &pattern, const BSONObj &indexKey Pattern); CoveredIndexMatcher(const BSONObj &pattern, const BSONObj &indexKey Pattern);
bool matchesWithSingleKeyIndex(const BSONObj &key, const DiskLoc &r bool matchesWithSingleKeyIndex( const BSONObj& key, const DiskLoc&
ecLoc , MatchDetails * details = 0 ) { recLoc,
MatchDetails* details = 0 ) const {
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 )
; const;
bool needRecord() { return _needRecord; } bool needRecord() const { return _needRecord; }
Matcher& docMatcher() { return *_docMatcher; }
// once this is called, shouldn't use this matcher for matching any const Matcher &docMatcher() const { return *_docMatcher; }
more
void advanceOrClause( const shared_ptr< FieldRangeVector > &frv ) {
_docMatcher->addOrDedupConstraint( frv );
// TODO this is not yet optimal. Since we could skip an entire
// or clause (if a match is impossible) between calls to advanc
eOrClause()
// we may not pop all the clauses we can.
_docMatcher->popOrClause();
}
CoveredIndexMatcher *nextClauseMatcher( const BSONObj &indexKeyPatt /**
ern ) { * @return a matcher for a following $or clause.
return new CoveredIndexMatcher( _docMatcher, indexKeyPattern ); * @param prevClauseFrs The index range scanned by the previous $or
clause. May be empty.
* @param nextClauseIndexKeyPattern The index key of the following
$or clause.
*/
CoveredIndexMatcher *nextClauseMatcher( const shared_ptr<FieldRange
Vector>& prevClauseFrv,
const BSONObj& nextClauseIn
dexKeyPattern ) const {
return new CoveredIndexMatcher( *this, prevClauseFrv, nextClaus
eIndexKeyPattern );
} }
string toString() const; string toString() const;
private: private:
bool matches(const BSONObj &key, const DiskLoc &recLoc , MatchDetai bool matches( const BSONObj& key, const DiskLoc& recLoc, MatchDetai
ls * details = 0 , bool keyUsable = true ); ls* details = 0,
CoveredIndexMatcher(const shared_ptr< Matcher > &docMatcher, const bool keyUsable = true ) const;
BSONObj &indexKeyPattern); bool isOrClauseDup( const BSONObj &obj ) const;
CoveredIndexMatcher( const CoveredIndexMatcher &prevClauseMatcher,
const shared_ptr<FieldRangeVector> &prevClauseF
rv,
const BSONObj &nextClauseIndexKeyPattern );
void init(); void init();
shared_ptr< Matcher > _docMatcher; shared_ptr< Matcher > _docMatcher;
Matcher _keyMatcher; Matcher _keyMatcher;
vector<shared_ptr<FieldRangeVector> > _orDedupConstraints;
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. 12 change blocks. 
34 lines changed or deleted 54 lines changed or added


 md5.h   md5.h 
skipping to change at line 63 skipping to change at line 63
/* /*
* This package supports both compile-time and run-time determination of CP U * This package supports both compile-time and run-time determination of CP U
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
* defined as non-zero, the code will be compiled to run only on big-endian * defined as non-zero, the code will be compiled to run only on big-endian
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
* run on either big- or little-endian CPUs, but will run slightly less * run on either big- or little-endian CPUs, but will run slightly less
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
*/ */
// Don't do this. Turns out its actually slower...
// #define ARCH_IS_BIG_ENDIAN 0
typedef unsigned char md5_byte_t; /* 8-bit byte */ typedef unsigned char md5_byte_t; /* 8-bit byte */
typedef unsigned int md5_word_t; /* 32-bit word */ typedef unsigned int md5_word_t; /* 32-bit word */
/* Define the state of the MD5 Algorithm. */ /* Define the state of the MD5 Algorithm. */
typedef struct md5_state_s { typedef struct md5_state_s {
md5_word_t count[2]; /* message length in bits, lsw first */ md5_word_t count[2]; /* message length in bits, lsw first */
md5_word_t abcd[4]; /* digest buffer */ md5_word_t abcd[4]; /* digest buffer */
md5_byte_t buf[64]; /* accumulate block */ md5_byte_t buf[64]; /* accumulate block */
} md5_state_t; } md5_state_t;
 End of changes. 1 change blocks. 
0 lines changed or deleted 3 lines changed or added


 message_port.h   message_port.h 
skipping to change at line 32 skipping to change at line 32
namespace mongo { namespace mongo {
class MessagingPort; class MessagingPort;
class PiggyBackData; class PiggyBackData;
typedef AtomicUInt MSGID; typedef AtomicUInt MSGID;
class AbstractMessagingPort : boost::noncopyable { class AbstractMessagingPort : boost::noncopyable {
public: public:
AbstractMessagingPort() : tag(0) {} AbstractMessagingPort() : tag(0), _connectionId(0) {}
virtual ~AbstractMessagingPort() { } virtual ~AbstractMessagingPort() { }
virtual void reply(Message& received, Message& response, MSGID resp onseTo) = 0; // like the reply below, but doesn't rely on received.data sti ll being available virtual void reply(Message& received, Message& response, MSGID resp onseTo) = 0; // like the reply below, but doesn't rely on received.data sti ll being available
virtual void reply(Message& received, Message& response) = 0; virtual void reply(Message& received, Message& response) = 0;
virtual HostAndPort remote() const = 0; virtual HostAndPort remote() const = 0;
virtual unsigned remotePort() const = 0; virtual unsigned remotePort() const = 0;
virtual void assertStillConnected() = 0; virtual void assertStillConnected() = 0;
long long connectionId() const { return _connectionId; }
void setConnectionId( long long connectionId );
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;
private:
long long _connectionId;
}; };
class MessagingPort : public AbstractMessagingPort { 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 );
 End of changes. 3 change blocks. 
1 lines changed or deleted 6 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(boost::shared_ptr<Socket> psocket); void accepted(boost::shared_ptr<Socket> psocket, long long connecti onId );
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 24 skipping to change at line 24
* 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> #include <limits>
#include <string>
#include "mongo/util/assert_util.h"
namespace mongo { namespace mongo {
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
 End of changes. 1 change blocks. 
0 lines changed or deleted 3 lines changed or added


 mmap.h   mmap.h 
skipping to change at line 24 skipping to change at line 24
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include <boost/thread/xtime.hpp> #include <boost/thread/xtime.hpp>
#include "concurrency/rwlock.h" #include "concurrency/rwlock.h"
namespace mongo { namespace mongo {
extern const size_t g_minOSPageSizeBytes;
void minOSPageSizeBytesTest(size_t minOSPageSizeBytes); // lame-o
class MAdvise { class MAdvise {
void *_p; void *_p;
unsigned _len; unsigned _len;
public: public:
enum Advice { Sequential=1 , Random=2 }; 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;
public: public:
LockMongoFilesShared() : lk(mmmutex) { } LockMongoFilesShared() : lk(mmmutex) { }
/** era changes anytime memory maps come and go. thus you can use /** era changes anytime memory maps come and go. thus you can use
this as a cheap way to verify this as a cheap way to check
that things are still in the condition you expected. of course if nothing has changed since the last time you locked. Of cour
you must be shared locked se you must be shared locked
otherwise someone could be in progress. if you have unlocked t at the time of this call, otherwise someone could be in progres
his is a reasonable way to s.
check your memory mapped pointer is still good.
This is used for yielding; see PageFaultException::touch().
*/ */
static unsigned getEra() { return era; } static unsigned getEra() { return era; }
static void assertExclusivelyLocked() { mmmutex.assertExclusivelyLo cked(); } static void assertExclusivelyLocked() { mmmutex.assertExclusivelyLo cked(); }
}; };
class LockMongoFilesExclusive { class LockMongoFilesExclusive {
RWLockRecursive::Exclusive lk; RWLockRecursive::Exclusive lk;
public: public:
LockMongoFilesExclusive() : lk(LockMongoFilesShared::mmmutex) { LockMongoFilesExclusive() : lk(LockMongoFilesShared::mmmutex) {
skipping to change at line 191 skipping to change at line 195
/* Create. Must not exist. /* Create. Must not exist.
@param zero fill file with zeros when true @param zero fill file with zeros when true
*/ */
void* create(string filename, unsigned long long len, bool zero); void* create(string filename, unsigned long long len, bool zero);
void flush(bool sync); void flush(bool sync);
virtual Flushable * prepareFlush(); virtual Flushable * prepareFlush();
long shortLength() const { return (long) len; } long shortLength() const { return (long) len; }
unsigned long long length() const { return len; } unsigned long long length() const { return len; }
HANDLE getFd() const { return fd; }
/** create a new view with the specified properties. /** create a new view with the specified properties.
automatically cleaned up upon close/destruction of the MemoryMa ppedFile object. automatically cleaned up upon close/destruction of the MemoryMa ppedFile object.
*/ */
void* createReadOnlyMap(); void* createReadOnlyMap();
void* createPrivateMap(); void* createPrivateMap();
/** make the private map range writable (necessary for our windows implementation) */ /** make the private map range writable (necessary for our windows implementation) */
static void makeWritable(void *, unsigned len) static void makeWritable(void *, unsigned len)
#if defined(_WIN32) #if defined(_WIN32)
; ;
 End of changes. 3 change blocks. 
8 lines changed or deleted 12 lines changed or added


 mongommf.h   mongommf.h 
skipping to change at line 83 skipping to change at line 83
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 verify( !_p._p.empty() ); DEV verify( !_p._p.empty() );
return _p; return _p;
} }
int fileSuffixNo() const { return _fileSuffixNo; } int fileSuffixNo() const { return _fileSuffixNo; }
HANDLE getFd() { return MemoryMappedFile::getFd(); }
/** 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; }
void remapThePrivateView(); void remapThePrivateView();
virtual bool isMongoMMF() { return true; } virtual bool isMongoMMF() { return true; }
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 mutex.h   mutex.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
#ifdef _WIN32 #ifdef _WIN32
# include <concrt.h> #include "mongo/platform/windows_basic.h"
#endif #endif
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <boost/thread/xtime.hpp> #include <boost/thread/xtime.hpp>
#include "mongo/util/assert_util.h" #include "mongo/util/assert_util.h"
#include "mongo/util/heapcheck.h" #include "mongo/util/heapcheck.h"
#include "mongo/util/concurrency/threadlocal.h" #include "mongo/util/concurrency/threadlocal.h"
skipping to change at line 130 skipping to change at line 130
}; };
typedef mongo::mutex::scoped_lock scoped_lock; typedef mongo::mutex::scoped_lock 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 { class SimpleMutex : boost::noncopyable {
public: public:
SimpleMutex( const char * ) {} SimpleMutex( const char * ) { InitializeCriticalSection( &_cs ); }
void dassertLocked() const { } void dassertLocked() const { }
void lock() { _cs.lock(); } void lock() { EnterCriticalSection( &_cs ); }
void unlock() { _cs.unlock(); } void unlock() { LeaveCriticalSection( &_cs ); }
class scoped_lock { class scoped_lock {
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:
Concurrency::critical_section _cs; 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) { verify( 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 ) {
verify( pthread_mutex_destroy(&_lock) == 0 ); verify( pthread_mutex_destroy(&_lock) == 0 );
} }
 End of changes. 5 change blocks. 
6 lines changed or deleted 6 lines changed or added


 namespace_details-inl.h   namespace_details-inl.h 
skipping to change at line 49 skipping to change at line 49
if ( ! e ) { if ( ! e ) {
if ( missingExpected ) if ( missingExpected )
throw MsgAssertionException( 14823 , "missing extra" ); throw MsgAssertionException( 14823 , "missing extra" );
massert(14824, "missing Extra", e); massert(14824, "missing Extra", e);
} }
i -= NIndexesExtra; i -= NIndexesExtra;
} }
return e->details[i]; return e->details[i];
} }
inline int NamespaceDetails::idxNo(IndexDetails& idx) { inline int NamespaceDetails::idxNo(const IndexDetails& idx) {
IndexIterator i = ii(); IndexIterator i = ii();
while( i.more() ) { while( i.more() ) {
if( &i.next() == &idx ) if( &i.next() == &idx )
return i.pos()-1; return i.pos()-1;
} }
massert( 10349 , "E12000 idxNo fails", false); massert( 10349 , "E12000 idxNo fails", false);
return -1; return -1;
} }
inline int NamespaceDetails::findIndexByKeyPattern(const BSONObj& keyPa ttern) { inline int NamespaceDetails::findIndexByKeyPattern(const BSONObj& keyPa ttern) {
IndexIterator i = ii(); IndexIterator i = ii();
while( i.more() ) { while( i.more() ) {
if( i.next().keyPattern() == keyPattern ) if( i.next().keyPattern() == keyPattern )
return i.pos()-1; return i.pos()-1;
} }
return -1; return -1;
} }
inline const IndexDetails* NamespaceDetails::findIndexByPrefix( const B
SONObj &keyPattern ,
bool re
quireSingleKey ) {
const IndexDetails* bestMultiKeyIndex = NULL;
IndexIterator i = ii();
while( i.more() ) {
const IndexDetails& currentIndex = i.next();
if( keyPattern.isPrefixOf( currentIndex.keyPattern() ) ){
if( ! isMultikey( i.pos()-1 ) ){
return &currentIndex;
} else {
bestMultiKeyIndex = &currentIndex;
}
}
}
return requireSingleKey ? NULL : bestMultiKeyIndex;
}
// @return offset in indexes[] // @return offset in indexes[]
inline int NamespaceDetails::findIndexByName(const char *name) { inline int NamespaceDetails::findIndexByName(const char *name) {
IndexIterator i = ii(); IndexIterator i = ii();
while( i.more() ) { while( i.more() ) {
if ( strcmp(i.next().info.obj().getStringField("name"),name) == 0 ) if ( strcmp(i.next().info.obj().getStringField("name"),name) == 0 )
return i.pos()-1; return i.pos()-1;
} }
return -1; return -1;
} }
 End of changes. 2 change blocks. 
1 lines changed or deleted 20 lines changed or added


 namespace_details.h   namespace_details.h 
skipping to change at line 218 skipping to change at line 218
private: private:
friend class NamespaceDetails; friend class NamespaceDetails;
int i, n; int i, n;
NamespaceDetails *d; NamespaceDetails *d;
IndexIterator(NamespaceDetails *_d); IndexIterator(NamespaceDetails *_d);
}; };
IndexIterator ii() { return IndexIterator(this); } IndexIterator ii() { return IndexIterator(this); }
/* hackish - find our index # in the indexes array */ /* hackish - find our index # in the indexes array */
int idxNo(IndexDetails& idx); int idxNo(const IndexDetails& idx);
/* multikey indexes are indexes where there are more than one key i n the index /* multikey indexes are indexes where there are more than one key i n the index
for a single document. see multikey in wiki. for a single document. see multikey in wiki.
for these, we have to do some dedup work on queries. 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; } bool isMultikey(int i) const { return (multiKeyIndexBits & (((unsig ned long long) 1) << i)) != 0; }
void setIndexIsMultikey(const char *thisns, int i); void setIndexIsMultikey(const char *thisns, int i);
/* add a new index. does not add to system.indexes etc. - just to NamespaceDetails. /* add a new index. does not add to system.indexes etc. - just to NamespaceDetails.
caller must populate returned object. caller must populate returned object.
skipping to change at line 300 skipping to change at line 300
int findIndexByKeyPattern(const BSONObj& keyPattern); int findIndexByKeyPattern(const BSONObj& keyPattern);
void findIndexByType( const string& name , vector<int>& matches ) { void findIndexByType( const string& name , vector<int>& matches ) {
IndexIterator i = ii(); IndexIterator i = ii();
while ( i.more() ) { while ( i.more() ) {
if ( i.next().getSpec().getTypeName() == name ) if ( i.next().getSpec().getTypeName() == name )
matches.push_back( i.pos() - 1 ); matches.push_back( i.pos() - 1 );
} }
} }
/* Returns the index entry for the first index whose prefix contain
s
* 'keyPattern'. If 'requireSingleKey' is true, skip indices that c
ontain
* array attributes. Otherwise, returns NULL.
*/
const IndexDetails* findIndexByPrefix( const BSONObj &keyPattern ,
bool requireSingleKey );
const int systemFlags() const { return _systemFlags; } const int systemFlags() const { return _systemFlags; }
bool isSystemFlagSet( int flag ) const { return _systemFlags & flag ; } bool isSystemFlagSet( int flag ) const { return _systemFlags & flag ; }
void setSystemFlag( int flag ); void setSystemFlag( int flag );
void clearSystemFlag( int flag ); void clearSystemFlag( int flag );
const int userFlags() const { return _userFlags; } const int userFlags() const { return _userFlags; }
bool isUserFlagSet( int flag ) const { return _userFlags & flag; } bool isUserFlagSet( int flag ) const { return _userFlags & flag; }
void setUserFlag( int flag );
void clearUserFlag( int flag ); /**
* these methods only modify NamespaceDetails and do not
* sync changes back to system.namespaces
* a typical call might
if ( nsd->setUserFlag( 4 ) ) {
nsd->syncUserFlags();
}
* these methods all return true iff only something was modified
*/
bool setUserFlag( int flag );
bool clearUserFlag( int flag );
bool replaceUserFlags( int flags );
void syncUserFlags( const string& ns );
/* @return -1 = not found /* @return -1 = not found
generally id is first index, so not that expensive an operation (assuming present). generally id is first index, so not that expensive an operation (assuming present).
*/ */
int findIdIndex() { int findIdIndex() {
IndexIterator i = ii(); IndexIterator i = ii();
while( i.more() ) { while( i.more() ) {
if( i.next().isIdIndex() ) if( i.next().isIdIndex() )
return i.pos()-1; return i.pos()-1;
} }
skipping to change at line 441 skipping to change at line 462
* @param order - Required ordering spec for documents produced by this cursor, empty object * @param order - Required ordering spec for documents produced by this cursor, empty object
* default indicates no order requirement. If no index exists that satisfies the required * default indicates no order requirement. If no index exists that satisfies the required
* sort order, an empty shared_ptr is returned unless parsedQuery i s also provided. This is * sort order, an empty shared_ptr is returned unless parsedQuery i s also provided. This is
* not copied if unowned. * not copied if unowned.
* *
* @param planPolicy - A policy for selecting query plans - see que ryoptimizercursor.h * @param planPolicy - A policy for selecting query plans - see que ryoptimizercursor.h
* *
* @param simpleEqualityMatch - Set to true for certain simple quer ies - see * @param simpleEqualityMatch - Set to true for certain simple quer ies - see
* queryoptimizer.cpp. * queryoptimizer.cpp.
* *
* @param parsedQuery - Additional query parameters, as from a clie * @param parsedQuery - Additional query parameters, as from a clie
nt query request. If nt query request.
* specified, the resulting cursor may return results from out of o *
rder plans. See * @param requireOrder - If false, the resulting cursor may return
* queryoptimizercursor.h for information on handling these results results in an order
. * inconsistent with the @param order spec. See queryoptimizercurs
or.h for information on
* handling these results properly.
* *
* @param singlePlanSummary - Query plan summary information that m ay be provided when a * @param singlePlanSummary - Query plan summary information that m ay be provided when a
* cursor running a single plan is returned. * cursor running a single plan is returned.
* *
* The returned cursor may @throw inside of advance() or recoverFro mYield() in certain error * The returned cursor may @throw inside of advance() or recoverFro mYield() in certain error
* cases, for example if a capped overrun occurred during a yield. This indicates that the * cases, for example if a capped overrun occurred during a yield. This indicates that the
* cursor was unable to perform a complete scan. * cursor was unable to perform a complete scan.
* *
* This is a work in progress. Partial list of features not yet im plemented through this * This is a work in progress. Partial list of features not yet im plemented through this
* interface: * interface:
skipping to change at line 465 skipping to change at line 488
* - covered indexes * - covered indexes
* - in memory sorting * - in memory sorting
*/ */
static shared_ptr<Cursor> getCursor( const char *ns, const BSONObj &query, static shared_ptr<Cursor> getCursor( const char *ns, const BSONObj &query,
const BSONObj &order = BSONObj( ), const BSONObj &order = BSONObj( ),
const QueryPlanSelectionPolicy &planPolicy = const QueryPlanSelectionPolicy &planPolicy =
QueryPlanSelectionPolicy::any() , QueryPlanSelectionPolicy::any() ,
bool *simpleEqualityMatch = 0, bool *simpleEqualityMatch = 0,
const shared_ptr<const ParsedQu ery> &parsedQuery = const shared_ptr<const ParsedQu ery> &parsedQuery =
shared_ptr<const ParsedQuery>() , shared_ptr<const ParsedQuery>() ,
bool requireOrder = true,
QueryPlanSummary *singlePlanSum mary = 0 ); QueryPlanSummary *singlePlanSum mary = 0 );
/** /**
* @return a single cursor that may work well for the given query. A $or style query will * @return a single cursor that may work well for the given query. A $or style query will
* produce a single cursor, not a MultiCursor. * produce a single cursor, not a MultiCursor.
* It is possible no cursor is returned if the sort is not supporte d by an index. Clients are responsible * 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 * 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. * no suitable indices exist.
*/ */
static shared_ptr<Cursor> bestGuessCursor( const char *ns, const BS ONObj &query, const BSONObj &sort ); static shared_ptr<Cursor> bestGuessCursor( const char *ns, const BS ONObj &query, const BSONObj &sort );
 End of changes. 5 change blocks. 
9 lines changed or deleted 35 lines changed or added


 namespacestring.h   namespacestring.h 
skipping to change at line 48 skipping to change at line 48
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")
NamespaceString( const char * ns ) { init(ns); } NamespaceString( const char * ns ) { init(ns); }
NamespaceString( const string& ns ) { init(ns.c_str()); } NamespaceString( const string& ns ) { init(ns.c_str()); }
string ns() const { return db + '.' + coll; } string ns() const { return db + '.' + coll; }
bool isSystem() const { return strncmp(coll.c_str(), "system.", 7) == 0; } bool isSystem() const { return strncmp(coll.c_str(), "system.", 7) == 0; }
bool isCommand() const { return coll == "$cmd"; } bool isCommand() const { return coll == "$cmd"; }
/**
* @return true if the namespace is valid. Special namespaces for i
nternal use are considered as valid.
*/
bool isValid() const {
return validDBName( db ) && !coll.empty();
}
operator string() const { return ns(); } operator string() const { return ns(); }
bool operator==( const string& nsIn ) const { return nsIn == ns(); } bool operator==( const string& nsIn ) const { return nsIn == ns(); }
bool operator==( const char* nsIn ) const { return (string)nsIn == ns(); } bool operator==( const char* nsIn ) const { return (string)nsIn == ns(); }
bool operator==( const NamespaceString& nsIn ) const { return nsIn. db == db && nsIn.coll == coll; } bool operator==( const NamespaceString& nsIn ) const { return nsIn. db == db && nsIn.coll == coll; }
bool operator!=( const string& nsIn ) const { return nsIn != ns(); } bool operator!=( const string& nsIn ) const { return nsIn != ns(); }
bool operator!=( const char* nsIn ) const { return (string)nsIn != ns(); } bool operator!=( const char* nsIn ) const { return (string)nsIn != ns(); }
bool operator!=( const NamespaceString& nsIn ) const { return nsIn. db != db || nsIn.coll != coll; } bool operator!=( const NamespaceString& nsIn ) const { return nsIn. db != db || nsIn.coll != coll; }
size_t size() const { return ns().size(); }
string toString() const { return ns(); } string toString() const { return ns(); }
/** /**
* @return true if ns is 'normal'. $ used for collections holding index data, which do not contain BSON objects in their records. * @return true if ns is 'normal'. $ used for collections holding index data, which do not contain BSON objects in their records.
* special case for the local.oplog.$main ns -- naming it as such w as a mistake. * special case for the local.oplog.$main ns -- naming it as such w as a mistake.
*/ */
static bool normal(const char* ns) { static bool normal(const char* ns) {
const char *p = strchr(ns, '$'); const char *p = strchr(ns, '$');
if( p == 0 ) if( p == 0 )
return true; return true;
 End of changes. 2 change blocks. 
0 lines changed or deleted 10 lines changed or added


 nonce.h   nonce.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 <iostream>
namespace mongo { namespace mongo {
typedef unsigned long long nonce64; typedef unsigned long long nonce64;
struct Security { struct Security {
Security(); Security();
static nonce64 getNonce(); static nonce64 getNonce();
static nonce64 getNonceDuringInit(); // use this version during glo bal var constructors static nonce64 getNonceDuringInit(); // use this version during glo bal var constructors
private: private:
nonce64 _getNonce(); nonce64 _getNonce();
nonce64 __getNonce(); nonce64 __getNonce();
ifstream *_devrandom; std::ifstream *_devrandom;
bool _initialized; bool _initialized;
void init(); // can call more than once void init(); // can call more than once
}; };
} // namespace mongo } // namespace mongo
 End of changes. 2 change blocks. 
1 lines changed or deleted 3 lines changed or added


 oid.h   oid.h 
skipping to change at line 20 skipping to change at line 20
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "../util/hex.h" #include <string>
#include "mongo/bson/util/misc.h"
#include "mongo/util/hex.h"
namespace mongo { namespace mongo {
#pragma pack(1) #pragma pack(1)
/** Object ID type. /** Object ID type.
BSON objects typically have an _id field for the object id. This f ield should be the first BSON objects typically have an _id field for the object id. This f ield should be the first
member of the object when present. class OID is a special type tha t is a 12 byte id which member of the object when present. class OID is a special type tha t is a 12 byte id which
is likely to be unique to the system. You may also use other types for _id's. is likely to be unique to the system. You may also use other types for _id's.
When _id field is missing from a BSON object, on an insert the data base may insert one When _id field is missing from a BSON object, on an insert the data base may insert one
automatically in certain circumstances. automatically in certain circumstances.
skipping to change at line 66 skipping to change at line 69
/** @return the object ID output as 24 hex digits */ /** @return the object ID output as 24 hex digits */
std::string str() const { return toHexLower(data, 12); } std::string str() const { return toHexLower(data, 12); }
std::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();
/** sets the contents to a new oid
* guaranteed to be sequential
* NOT guaranteed to be globally unique
* only unique for this process
* */
void initSequential();
/** init from a 24 char hex string */ /** init from a 24 char hex string */
void init( std::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; }
 End of changes. 2 change blocks. 
1 lines changed or deleted 11 lines changed or added


 oplog.h   oplog.h 
skipping to change at line 75 skipping to change at line 75
class QueryPlan; class QueryPlan;
/** Implements an optimized procedure for finding the first op in the o plog. */ /** Implements an optimized procedure for finding the first op in the o plog. */
class FindingStartCursor { class FindingStartCursor {
public: public:
/** /**
* 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 ); static FindingStartCursor *make( 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( 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();
skipping to change at line 113 skipping to change at line 113
/** /**
* @return a BasicCursor constructed using a FindingStartCursor wit h the provided query and * @return a BasicCursor constructed using a FindingStartCursor wit h the provided query and
* order parameters. * order parameters.
* @yields the db lock. * @yields the db lock.
* @asserts on yield recovery failure. * @asserts on yield recovery failure.
*/ */
static shared_ptr<Cursor> getCursor( const char *ns, const BSONObj &query, const BSONObj &order ); static shared_ptr<Cursor> getCursor( const char *ns, const BSONObj &query, const BSONObj &order );
private: private:
FindingStartCursor( const QueryPlan &qp );
void init();
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::Holder _findingStartCursor;
shared_ptr<Cursor> _c; shared_ptr<Cursor> _c;
ClientCursor::YieldData _yieldData; ClientCursor::YieldData _yieldData;
DiskLoc extentFirstLoc( const DiskLoc &rec ); DiskLoc extentFirstLoc( const DiskLoc &rec );
DiskLoc prevExtentFirstLoc( const DiskLoc &rec ); DiskLoc prevExtentFirstLoc( const DiskLoc &rec );
void createClientCursor( const DiskLoc &startLoc = DiskLoc() ); void createClientCursor( const DiskLoc &startLoc = DiskLoc() );
void destroyClientCursor() { void destroyClientCursor() {
_findingStartCursor.reset( 0 ); _findingStartCursor.reset( 0 );
} }
void init();
bool firstDocMatchesOrEmpty() const; bool firstDocMatchesOrEmpty() const;
}; };
class Sync { class Sync {
protected: protected:
string hn; string hn;
public: public:
Sync(const string& hostname) : hn(hostname) {} Sync(const string& hostname) : hn(hostname) {}
virtual ~Sync() {} virtual ~Sync() {}
virtual BSONObj getMissingDoc(const BSONObj& o); virtual BSONObj getMissingDoc(const BSONObj& o);
 End of changes. 4 change blocks. 
3 lines changed or deleted 5 lines changed or added


 pagefault.h   pagefault.h 
skipping to change at line 26 skipping to change at line 26
}; };
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();
}; };
/**
* this turns off page faults in a scope
* there are just certain arease where its dangerous
* this might mean the code is dangerous anyway....
*/
class NoPageFaultsAllowed : boost::noncopyable {
public:
NoPageFaultsAllowed();
~NoPageFaultsAllowed();
private:
PageFaultRetryableSection* _saved;
};
#if 0 #if 0
inline void how_to_use_example() { inline void how_to_use_example() {
// ... // ...
{ {
PageFaultRetryableSection s; PageFaultRetryableSection s;
while( 1 ) { while( 1 ) {
try { try {
writelock lk; // or readlock writelock lk; // or readlock
// do work // do work
break; break;
 End of changes. 1 change blocks. 
0 lines changed or deleted 14 lines changed or added


 parallel.h   parallel.h 
skipping to change at line 387 skipping to change at line 387
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;
map<Shard,PCMData> _cursorMap; map<Shard,PCMData> _cursorMap;
// LEGACY BELOW // LEGACY BELOW
int _numServers; int _numServers;
int _lastFrom;
set<ServerAndQuery> _servers; set<ServerAndQuery> _servers;
BSONObj _sortKey; BSONObj _sortKey;
FilteringClientCursor * _cursors; FilteringClientCursor * _cursors;
int _needToSkip; int _needToSkip;
private:
/**
* Setups the shard version of the connection. When using a replica
* set connection and the primary cannot be reached, the version
* will not be set if the slaveOk flag is set.
*/
void setupVersionAndHandleSlaveOk( PCStatePtr state /* in & out */,
const Shard& shard,
ShardPtr primary /* in */,
const NamespaceString& ns,
const std::string& vinfo,
ChunkManagerPtr manager /* in */ );
}; };
/** /**
* tools for doing asynchronous operations * tools for doing asynchronous operations
* right now uses underlying sync network ops and uses another thread * right now uses underlying sync network ops and uses another thread
* should be changed to use non-blocking io * should be changed to use non-blocking io
*/ */
class Future { class Future {
public: public:
class CommandResult { class CommandResult {
 End of changes. 2 change blocks. 
0 lines changed or deleted 14 lines changed or added


 pdfile.h   pdfile.h 
skipping to change at line 36 skipping to change at line 36
#pragma once #pragma once
#include "mongo/db/client.h" #include "mongo/db/client.h"
#include "mongo/db/diskloc.h" #include "mongo/db/diskloc.h"
#include "mongo/db/jsobjmanipulator.h" #include "mongo/db/jsobjmanipulator.h"
#include "mongo/db/memconcept.h" #include "mongo/db/memconcept.h"
#include "mongo/db/mongommf.h" #include "mongo/db/mongommf.h"
#include "mongo/db/namespace-inl.h" #include "mongo/db/namespace-inl.h"
#include "mongo/db/namespace_details-inl.h" #include "mongo/db/namespace_details-inl.h"
#include "mongo/db/namespacestring.h" #include "mongo/db/namespacestring.h"
#include "mongo/util/log.h"
#include "mongo/util/mmap.h" #include "mongo/util/mmap.h"
#include "mongo/util/util.h"
namespace mongo { namespace mongo {
// pdfile versions // pdfile versions
const int PDFILE_VERSION = 4; const int PDFILE_VERSION = 4;
const int PDFILE_VERSION_MINOR = 5; const int PDFILE_VERSION_MINOR = 5;
class DataFileHeader; class DataFileHeader;
class Extent; class Extent;
class Record; class Record;
skipping to change at line 85 skipping to change at line 85
/** creates if DNE */ /** creates if DNE */
void open(const char *filename, int requestedDataSize = 0, bool pre allocateOnly = false); void open(const char *filename, int requestedDataSize = 0, bool pre allocateOnly = false);
/* allocate a new extent from this datafile. /* allocate a new extent from this datafile.
@param capped - true if capped collection @param capped - true if capped collection
@param loops is our recursion check variable - you want to pass in zero @param loops is our recursion check variable - you want to pass in zero
*/ */
Extent* createExtent(const char *ns, int approxSize, bool capped = false, int loops = 0); Extent* createExtent(const char *ns, int approxSize, bool capped = false, int loops = 0);
DataFileHeader *getHeader() { return header(); } DataFileHeader *getHeader() { return header(); }
HANDLE getFd() { return mmf.getFd(); }
unsigned long long length() const { return mmf.length(); } unsigned long long length() const { return mmf.length(); }
/* return max size an extent may be */ /* return max size an extent may be */
static int maxSize(); static int maxSize();
/** fsync */ /** fsync */
void flush( bool sync ); void flush( bool sync );
/** only use fore debugging */ /** only use fore debugging */
Extent* debug_getExtent(DiskLoc loc) { return _getExtent( loc ); } Extent* debug_getExtent(DiskLoc loc) { return _getExtent( loc ); }
skipping to change at line 277 skipping to change at line 277
* 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() const ; 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();
static bool likelyInPhysicalMemory( const char* data );
static bool blockCheckSupported();
/**
* this adds stats about page fault exceptions currently
* specically how many times we call _accessing where the record is
not in memory
* and how many times we throw a PageFaultException
*/
static void appendStats( BSONObjBuilder& b );
private: private:
int _netLength() const { return _lengthWithHeaders - HeaderSize; } int _netLength() const { return _lengthWithHeaders - HeaderSize; }
/** /**
* call this when accessing a field which could hit disk * call this when accessing a field which could hit disk
*/ */
void _accessing() const; void _accessing() const;
int _lengthWithHeaders; int _lengthWithHeaders;
skipping to change at line 500 skipping to change at line 510
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) {
_accessing(); _accessing();
if ( _nextOfs != DiskLoc::NullOfs ) { 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?"); logContext("Assertion failure - Record::getNext() referenci ng 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();
skipping to change at line 528 skipping to change at line 538
_accessing(); _accessing();
if ( _prevOfs != DiskLoc::NullOfs ) if ( _prevOfs != DiskLoc::NullOfs )
return DiskLoc(myLoc.a(), _prevOfs); 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::make(rec()->accessed());
} }
inline DeletedRecord* DiskLoc::drec() const { inline DeletedRecord* DiskLoc::drec() const {
verify( _a != -1 ); verify( _a != -1 );
DeletedRecord* dr = (DeletedRecord*) rec(); DeletedRecord* dr = (DeletedRecord*) rec();
memconcept::is(dr, memconcept::concept::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);
} }
skipping to change at line 604 skipping to change at line 614
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) {
verify( 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 inline BSONObj BSONObj::make(const Record* r ) {
, string &errmsg, BSONObjBuilder &anObjBuilder, bool maydeleteIdIndex ); return BSONObj( r->data() );
inline BSONObj::BSONObj(const Record *r) {
init(r->data());
} }
} // namespace mongo } // namespace mongo
 End of changes. 7 change blocks. 
9 lines changed or deleted 17 lines changed or added


 pipeline.h   pipeline.h 
skipping to change at line 121 skipping to change at line 121
command. command.
The split itself is handled by the caller, which is currently The split itself is handled by the caller, which is currently
pipeline_command.cpp. pipeline_command.cpp.
@returns true if the pipeline is to be split @returns true if the pipeline is to be split
*/ */
bool getSplitMongodPipeline() const; bool getSplitMongodPipeline() const;
/** /**
Ask if this is for an explain request.
@returns true if this is an explain
*/
bool isExplain() const;
/**
The aggregation command name. The aggregation command name.
*/ */
static const char commandName[]; static const char commandName[];
/* /*
PipelineD is a "sister" class that has additional functionality PipelineD is a "sister" class that has additional functionality
for the Pipeline. It exists because of linkage requirements. for the Pipeline. It exists because of linkage requirements.
Pipeline needs to function in mongod and mongos. PipelineD Pipeline needs to function in mongod and mongos. PipelineD
contains extra functionality required in mongod, and which can't contains extra functionality required in mongod, and which can't
appear in mongos because the required symbols are unavailable appear in mongos because the required symbols are unavailable
for linking there. Consider PipelineD to be an extension of this for linking there. Consider PipelineD to be an extension of this
class for mongod only. class for mongod only.
*/ */
friend class PipelineD; friend class PipelineD;
private: private:
static const char pipelineName[]; static const char pipelineName[];
static const char explainName[];
static const char fromRouterName[]; static const char fromRouterName[];
static const char splitMongodPipelineName[]; static const char splitMongodPipelineName[];
static const char serverPipelineName[];
static const char mongosPipelineName[];
Pipeline(const intrusive_ptr<ExpressionContext> &pCtx); Pipeline(const intrusive_ptr<ExpressionContext> &pCtx);
/*
Write the pipeline's operators to the given array, with the
explain flag true (for DocumentSource::addToBsonArray()).
@param pArrayBuilder where to write the ops to
*/
void writeExplainOps(BSONArrayBuilder *pArrayBuilder) const;
/*
Write the pipeline's operators to the given result document,
for a shard server (or regular server, in an unsharded setup).
This uses writeExplainOps() and adds that array to the result
with the serverPipelineName. That will be preceded by explain
information for the input source.
@param result the object to add the explain information to
@param pInputSource source for the pipeline
*/
void writeExplainShard(BSONObjBuilder &result,
const intrusive_ptr<DocumentSource> &pInputSource) const;
/*
Write the pipeline's operators to the given result document,
for a mongos instance.
This first adds the serverPipeline obtained from the input
source.
Then this uses writeExplainOps() and adds that array to the resul
t
with the serverPipelineName. That will be preceded by explain
information for the input source.
@param result the object to add the explain information to
@param pInputSource source for the pipeline; expected to be the
output of a shard
*/
void writeExplainMongos(BSONObjBuilder &result,
const intrusive_ptr<DocumentSource> &pInputSource) const;
string collectionName; string collectionName;
typedef vector<intrusive_ptr<DocumentSource> > SourceVector; typedef vector<intrusive_ptr<DocumentSource> > SourceVector;
SourceVector sourceVector; SourceVector sourceVector;
bool explain;
bool splitMongodPipeline; bool splitMongodPipeline;
intrusive_ptr<ExpressionContext> pCtx; intrusive_ptr<ExpressionContext> pCtx;
}; };
} // namespace mongo } // namespace mongo
/* ======================= INLINED IMPLEMENTATIONS ======================== == */ /* ======================= INLINED IMPLEMENTATIONS ======================== == */
namespace mongo { namespace mongo {
skipping to change at line 168 skipping to change at line 219
return collectionName; return collectionName;
} }
inline bool Pipeline::getSplitMongodPipeline() const { inline bool Pipeline::getSplitMongodPipeline() const {
if (!DEBUG_BUILD) if (!DEBUG_BUILD)
return false; return false;
return splitMongodPipeline; return splitMongodPipeline;
} }
inline bool Pipeline::isExplain() const {
return explain;
}
} // namespace mongo } // namespace mongo
 End of changes. 6 change blocks. 
0 lines changed or deleted 56 lines changed or added


 pipeline_d.h   pipeline_d.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 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"
namespace mongo { namespace mongo {
class DocumentSource; class DocumentSourceCursor;
class Pipeline; class Pipeline;
/* /*
PipelineD is an extension of the Pipeline class, but with additional PipelineD is an extension of the Pipeline class, but with additional
material that references symbols that are not available in mongos, material that references symbols that are not available in mongos,
where the remainder of the Pipeline class also functions. PipelineD where the remainder of the Pipeline class also functions. PipelineD
is a friend of Pipeline so that it can have equal access to Pipeline' s is a friend of Pipeline so that it can have equal access to Pipeline' s
members. members.
See the friend declaration in Pipeline. See the friend declaration in Pipeline.
*/ */
class PipelineD { class PipelineD {
public: public:
/** /**
Create a Cursor wrapped in a DocumentSource, which is suitable Create a Cursor wrapped in a DocumentSourceCursor, which is suit able
to be the first source for a pipeline to begin with. This sourc e to be the first source for a pipeline to begin with. This sourc e
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 @param pExpCtx the expression context for this pipeline
@returns a document source that wraps an appropriate cursor to @returns the cursor that was created
be at the beginning of this pipeline
*/ */
static intrusive_ptr<DocumentSource> prepareCursorSource( static intrusive_ptr<DocumentSourceCursor> prepareCursorSource(
const intrusive_ptr<Pipeline> &pPipeline, const intrusive_ptr<Pipeline> &pPipeline,
const string &dbName, const string &dbName,
const intrusive_ptr<ExpressionContext> &pExpCtx); 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. 4 change blocks. 
5 lines changed or deleted 4 lines changed or added


 projection.h   projection.h 
skipping to change at line 25 skipping to change at line 25
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "pch.h" #include "pch.h"
#include "jsobj.h" #include "jsobj.h"
namespace mongo { namespace mongo {
// fwd decls
class Matcher;
class MatchDetails;
/** /**
* given a document and a projection specification * given a document and a projection specification
* can transform the document * can transform the document
* currently supports specifying which fields and $slice * currently supports specifying which fields and $slice
*/ */
class Projection { class Projection {
public: public:
class KeyOnly { class KeyOnly {
public: public:
skipping to change at line 57 skipping to change at line 61
_names.push_back( name ); _names.push_back( name );
_stringSize += name.size(); _stringSize += name.size();
} }
vector<bool> _include; // one entry per field in key. true iff should be in output vector<bool> _include; // one entry per field in key. true iff should be in output
vector<string> _names; // name of field since key doesn't have names vector<string> _names; // name of field since key doesn't have names
int _stringSize; int _stringSize;
}; };
enum ArrayOpType {
ARRAY_OP_NORMAL = 0,
ARRAY_OP_ELEM_MATCH,
ARRAY_OP_POSITIONAL
};
Projection() : Projection() :
_include(true) , _include(true) ,
_special(false) , _special(false) ,
_includeID(true) , _includeID(true) ,
_skip(0) , _skip(0) ,
_limit(-1) , _limit(-1) ,
_arrayOpType(ARRAY_OP_NORMAL),
_hasNonSimple(false) { _hasNonSimple(false) {
} }
/** /**
* called once per lifetime * called once per lifetime
* e.g. { "x" : 1 , "a.y" : 1 } * e.g. { "x" : 1 , "a.y" : 1 }
*/ */
void init( const BSONObj& spec ); void init( const BSONObj& spec );
/** /**
* @return the spec init was called with * @return the spec init was called with
*/ */
BSONObj getSpec() const { return _source; } BSONObj getSpec() const { return _source; }
/** /**
* transforms in according to spec * transforms in according to spec
*/ */
BSONObj transform( const BSONObj& in ) const; BSONObj transform( const BSONObj& in, const MatchDetails* details = NULL ) const;
/** /**
* transforms in according to spec * transforms in according to spec
*/ */
void transform( const BSONObj& in , BSONObjBuilder& b ) const; void transform( const BSONObj& in , BSONObjBuilder& b, const MatchD etails* details = NULL ) const;
/** /**
* @return if the keyPattern has all the information needed to retu rn then * @return if the keyPattern has all the information needed to retu rn then
* return a new KeyOnly otherwise null * return a new KeyOnly otherwise null
* NOTE: a key may have modified the actual data * NOTE: a key may have modified the actual data
* which has to be handled above this (arrays, geo) * which has to be handled above this (arrays, geo)
*/ */
KeyOnly* checkKey( const BSONObj& keyPattern ) const; KeyOnly* checkKey( const BSONObj& keyPattern ) const;
bool includeID() const { return _includeID; } bool includeID() const { return _includeID; }
/**
* get the type of array operator for the projection
* @return ARRAY_OP_NORMAL if no array projection modifier,
* ARRAY_OP_ELEM_MATCH if one or more $elemMatch speci
fier,
* ARRAY_OP_POSITIONAL if one '.$' projection specifie
d
*/
ArrayOpType getArrayOpType() const;
/**
* Validate the given query satisfies this projection's positional
operator.
* NOTE: this function is only used to validate projections with a
positional operator.
* @param query User-supplied query specifier
* @return Field name if found, empty string otherwise.
*/
void validateQuery( const BSONObj query ) const;
private: private:
/** /**
* appends e to b if user wants it * appends e to b if user wants it
* will descend into e if needed * will descend into e if needed
*/ */
void append( BSONObjBuilder& b , const BSONElement& e ) const; void append( BSONObjBuilder& b , const BSONElement& e, const MatchD
etails* details = NULL,
const ArrayOpType arrayOpType = ARRAY_OP_NORMAL ) cons
t;
void add( const string& field, bool include ); void add( const string& field, bool include );
void add( const string& field, int skip, int limit ); void add( const string& field, int skip, int limit );
void appendArray( BSONObjBuilder& b , const BSONObj& a , bool neste d=false) const; void appendArray( BSONObjBuilder& b , const BSONObj& a , bool neste d=false) const;
bool _include; // true if default at this level is to include bool _include; // true if default at this level is to include
bool _special; // true if this level can't be skipped or included w ithout recursing bool _special; // true if this level can't be skipped or included w ithout recursing
//TODO: benchmark vector<pair> vs map //TODO: benchmark vector<pair> vs map
typedef map<string, boost::shared_ptr<Projection> > FieldMap; typedef map<string, boost::shared_ptr<Projection> > FieldMap;
FieldMap _fields; FieldMap _fields;
BSONObj _source; BSONObj _source;
bool _includeID; bool _includeID;
// used for $slice operator // used for $slice operator
int _skip; int _skip;
int _limit; int _limit;
// used for $elemMatch and positional operator ($)
typedef map<string, shared_ptr<Matcher> > Matchers;
Matchers _matchers;
ArrayOpType _arrayOpType;
bool _hasNonSimple; bool _hasNonSimple;
}; };
} }
 End of changes. 8 change blocks. 
3 lines changed or deleted 42 lines changed or added


 qlock.h   qlock.h 
skipping to change at line 32 skipping to change at line 32
w - i will write, and i will granularly lock after the qlock acqu isition w - i will write, and i will granularly lock after the qlock acqu isition
r - i will read, and i will granularly lock after the qlock acqu isition r - i will read, and i will granularly lock after the qlock acqu isition
W - i will write globally. stop the world. W - i will write globally. stop the world.
R - i will read globally. stop any writer. R - i will read globally. stop any writer.
For example there is a point during journal batch commits where we wish to block all writers For example there is a point during journal batch commits where we wish to block all writers
but no readers. but no readers.
Non-recursive. Non-recursive.
r w R W <== lock that was around r w R W X <== lock that was around
r - - - X r * * * - -
w - - X X - allowed w * * - - - * allowed
R - X - X X not allowed (blocks) R * - * - - - not allowed (blocks)
W X X X X W - - - - - ! See NOTE(!).
X - ! - - -
^ ^
lock we are requesting lock we are requesting
NOTE(!): The "X" state can only be reached from the "w" state. A t
hread successfully
transitions from "w" to "X" when w_to_X() returns true, and fails t
o transition to that
state (remaining in "w") when that function returns false. For one
thread to successfully
transition, all threads in the "w" state must be blocked in w_to_X(
). When all threads in
the "w" state are blocked in w_to_X(), one thread will be released
in the X state. The
other threads remain blocked in w_to_X() until the thread in the X
state calls X_to_w().
*/ */
class QLock : boost::noncopyable { class QLock : boost::noncopyable {
struct Z { struct Z {
Z() : n(0) { } Z() : n(0) { }
boost::condition c; boost::condition c;
int n; int n;
}; };
boost::mutex m; boost::mutex m;
Z r,w,R,W,U,X; // X is used by QLock::runExclusively Z r,w,R,W,U,X;
int greed; // >0 if someone wants to acquire a write lock int numPendingGlobalWrites; // >0 if someone wants to acquire a wr
int greedyWrites; // 0=no, 1=true ite lock
int greedSuspended; long long generationX;
void _stop_greed(); // we are already inlock for these underscore long long generationXExit;
methods
void _lock_W(); void _lock_W();
bool W_legal() const { return r.n + w.n + R.n + W.n == 0; } void _unlock_R();
bool R_legal() const { return w.n + + W.n == 0; } bool _areQueueJumpingGlobalWritesPending() const {
bool w_legal() const { return R.n + W.n == 0; } return numPendingGlobalWrites > 0;
bool r_legal() const { return W.n == 0; } }
bool W_legal() const { return r.n + w.n + R.n + W.n + X.n == 0; }
bool R_legal_ignore_greed() const { return w.n + W.n + X.n == 0; }
bool r_legal_ignore_greed() const { return W.n + X.n == 0; }
bool w_legal_ignore_greed() const { return R.n + W.n + X.n == 0; }
bool R_legal() const {
return !_areQueueJumpingGlobalWritesPending() && R_legal_ignore
_greed();
}
bool w_legal() const {
return !_areQueueJumpingGlobalWritesPending() && w_legal_ignore
_greed();
}
bool r_legal() const {
return !_areQueueJumpingGlobalWritesPending() && r_legal_ignore
_greed();
}
bool X_legal() const { return w.n + r.n + R.n + W.n == 0; }
void notifyWeUnlocked(char me); void notifyWeUnlocked(char me);
static bool i_block(char me, char them); static bool i_block(char me, char them);
public: public:
QLock() : greed(0), greedyWrites(1), greedSuspended(0) { } QLock() :
numPendingGlobalWrites(0),
generationX(0),
generationXExit(0) {
}
void lock_r(); void lock_r();
void lock_w(); void lock_w();
void lock_R(); void lock_R();
bool lock_R_try(int millis); bool lock_R_try(int millis);
void lock_W(); void lock_W();
bool lock_W_try(int millis); bool lock_W_try(int millis);
void lock_W_stop_greed();
void unlock_r(); void unlock_r();
void unlock_w(); void unlock_w();
void unlock_R(); void unlock_R();
void unlock_W(); void unlock_W();
void start_greed();
void stop_greed();
void W_to_R(); void W_to_R();
bool R_to_W(); // caution see notes below void R_to_W(); // caution see notes below
void runExclusively(void (*f)(void)); bool w_to_X();
void X_to_w();
}; };
inline bool QLock::i_block(char me, char them) { inline bool QLock::i_block(char me, char them) {
switch( me ) { switch( me ) {
case 'W' : return true; case 'W' : return true;
case 'R' : return them == 'W' || them == 'w'; case 'R' : return them == 'W' || them == 'w' || them == 'X';
case 'w' : return them == 'W' || them == 'R'; case 'w' : return them == 'W' || them == 'R' || them == 'X';
case 'r' : return them == 'W'; case 'r' : return them == 'W' || them == 'X';
default : verify(false); case 'X' : return true;
default : fassertFailed(16200);
} }
return false; return false;
} }
inline void QLock::notifyWeUnlocked(char me) { inline void QLock::notifyWeUnlocked(char me) {
verify( W.n == 0 ); fassert(16201, W.n == 0);
if ( me == 'X' ) {
X.c.notify_all();
}
if( U.n ) { if( U.n ) {
// U is highest priority // U is highest priority
if( r.n + w.n + W.n == 0 ) if( (r.n + w.n + W.n + X.n == 0) && (R.n == 1) ) {
U.c.notify_one(); U.c.notify_one();
return; return;
}
} }
if( W_legal() /*&& i_block(me,'W')*/ ) { if ( X_legal() && i_block(me, 'X') ) {
int g = greed; X.c.notify_one();
}
if ( W_legal() && i_block(me, 'W') ) {
W.c.notify_one(); W.c.notify_one();
if( g ) // g>0 indicates someone was definitely waiting for W, so we can stop here if( _areQueueJumpingGlobalWritesPending() )
return; return;
} }
if( R_legal() && i_block(me,'R') ) { if ( R_legal_ignore_greed() && i_block(me, 'R') ) {
R.c.notify_all(); R.c.notify_all();
} }
if( w_legal() && i_block(me,'w') ) { if ( w_legal_ignore_greed() && i_block(me, 'w') ) {
w.c.notify_all(); w.c.notify_all();
} }
if( r_legal() && i_block(me,'r') ) { if ( r_legal_ignore_greed() && i_block(me, 'r') ) {
r.c.notify_all(); r.c.notify_all();
} }
} }
inline void QLock::_stop_greed() {
if( ++greedSuspended == 1 ) // recursion on stop_greed/start_greed
is ok
greedyWrites = 0;
}
inline void QLock::stop_greed() {
boost::mutex::scoped_lock lk(m);
_stop_greed();
}
inline void QLock::start_greed() {
boost::mutex::scoped_lock lk(m);
if( --greedSuspended == 0 )
greedyWrites = 1;
}
// "i will be reading. i promise to coordinate my activities with w's a s i go with more // "i will be reading. i promise to coordinate my activities with w's a s i go with more
// granular locks." // granular locks."
inline void QLock::lock_r() { inline void QLock::lock_r() {
boost::mutex::scoped_lock lk(m); boost::mutex::scoped_lock lk(m);
while( greed + W.n ) { while( !r_legal() ) {
r.c.wait(m); r.c.wait(m);
} }
r.n++; r.n++;
} }
// "i will be writing. i promise to coordinate my activities with w's a nd r's as i go with more // "i will be writing. i promise to coordinate my activities with w's a nd r's as i go with more
// granular locks." // granular locks."
inline void QLock::lock_w() { inline void QLock::lock_w() {
boost::mutex::scoped_lock lk(m); boost::mutex::scoped_lock lk(m);
while( greed + W.n + R.n ) { while( !w_legal() ) {
w.c.wait(m); w.c.wait(m);
} }
w.n++; w.n++;
} }
// "i will be reading. i will coordinate with no one. you better stop t hem if they // "i will be reading. i will coordinate with no one. you better stop t hem if they
// are writing." // are writing."
inline void QLock::lock_R() { inline void QLock::lock_R() {
boost::mutex::scoped_lock lk(m); boost::mutex::scoped_lock lk(m);
while( greed + W.n + w.n ) { while( ! R_legal() ) {
R.c.wait(m); R.c.wait(m);
} }
R.n++; R.n++;
} }
inline bool QLock::lock_R_try(int millis) { inline bool QLock::lock_R_try(int millis) {
unsigned long long end = curTimeMillis64() + millis; unsigned long long end = curTimeMillis64() + millis;
boost::mutex::scoped_lock lk(m); boost::mutex::scoped_lock lk(m);
while( 1 ) { while( !R_legal() && curTimeMillis64() < end ) {
if( greed + W.n + w.n == 0 )
break;
R.c.timed_wait(m, boost::posix_time::milliseconds(millis)); R.c.timed_wait(m, boost::posix_time::milliseconds(millis));
if( greed + W.n + w.n == 0 )
break;
if( curTimeMillis64() >= end )
return false;
} }
R.n++; if ( R_legal() ) {
return true; R.n++;
return true;
}
return false;
} }
inline bool QLock::lock_W_try(int millis) { inline bool QLock::lock_W_try(int millis) {
unsigned long long end = curTimeMillis64() + millis; unsigned long long end = curTimeMillis64() + millis;
boost::mutex::scoped_lock lk(m); boost::mutex::scoped_lock lk(m);
int g = greedyWrites;
greed += g; ++numPendingGlobalWrites;
while( 1 ) { while (!W_legal() && curTimeMillis64() < end) {
if( W.n + R.n + w.n + r.n == 0 )
break;
W.c.timed_wait(m, boost::posix_time::milliseconds(millis)); W.c.timed_wait(m, boost::posix_time::milliseconds(millis));
if( W.n + R.n + w.n + r.n == 0 )
break;
if( curTimeMillis64() >= end ) {
greed -= g;
dassert( greed >= 0 );
// should we do notify_one on W.c so we should be careful n
ot to leave someone
// else waiting when we give up here perhaps. it is very po
ssible this code
// is unnecessary:
// W.c.notify_one();
return false;
}
} }
W.n += 1; --numPendingGlobalWrites;
dassert( W.n == 1 );
greed -= g; if (W_legal()) {
return true; W.n++;
fassert( 16202, W.n == 1 );
return true;
}
return false;
} }
// downgrade from W state to R state // downgrade from W state to R state
inline void QLock::W_to_R() { inline void QLock::W_to_R() {
boost::mutex::scoped_lock lk(m); boost::mutex::scoped_lock lk(m);
verify( W.n == 1 ); fassert(16203, W.n == 1);
verify( R.n == 0 ); fassert(16204, R.n == 0);
verify( U.n == 0 ); fassert(16205, U.n == 0);
W.n = 0; W.n = 0;
R.n = 1; R.n = 1;
notifyWeUnlocked('W'); notifyWeUnlocked('W');
} }
// upgrade from R to W state. // upgrade from R to W state.
//
// This transition takes precedence over all pending requests by thread
s to enter
// any state other than '\0'.
//
// there is no "upgradable" state so this is NOT a classic upgrade - // there is no "upgradable" state so this is NOT a classic upgrade -
// if two threads try to do this you will deadlock. // if two threads try to do this you will deadlock.
inline bool QLock::R_to_W() { //
// NOTE: ONLY CALL THIS FUNCTION ON A THREAD THAT GOT TO R BY CALLING W
_to_R(), OR
// YOU MAY DEADLOCK WITH THREADS LEAVING THE X STATE.
inline void QLock::R_to_W() {
boost::mutex::scoped_lock lk(m); boost::mutex::scoped_lock lk(m);
verify( R.n > 0 && W.n == 0 ); fassert(16206, R.n > 0);
U.n++; fassert(16207, W.n == 0);
fassert( 16136, U.n == 1 ); // for now we only allow one upgrade at fassert(16208, U.n == 0);
tempter
int pass = 0; U.n = 1;
++numPendingGlobalWrites;
while( W.n + R.n + w.n + r.n > 1 ) { while( W.n + R.n + w.n + r.n > 1 ) {
if( ++pass >= 3 ) { U.c.wait(m);
U.n--;
return false;
}
U.c.timed_wait(m, boost::posix_time::milliseconds(300));
} }
R.n--; --numPendingGlobalWrites;
W.n++;
U.n--; fassert(16209, R.n == 1);
verify( R.n == 0 && W.n == 1 && U.n == 0 ); fassert(16210, W.n == 0);
return true; fassert(16211, U.n == 1);
R.n = 0;
W.n = 1;
U.n = 0;
}
inline bool QLock::w_to_X() {
boost::mutex::scoped_lock lk(m);
fassert( 16212, w.n > 0 );
++X.n;
--w.n;
long long myGeneration = generationX;
while ( !X_legal() && (myGeneration == generationX) )
X.c.wait(m);
if ( myGeneration == generationX ) {
fassert( 16214, X_legal() );
fassert( 16215, w.n == 0 );
++generationX;
notifyWeUnlocked('w');
return true;
}
while ( myGeneration == generationXExit )
X.c.wait(m);
fassert( 16216, R.n == 0 );
fassert( 16217, w.n > 0 );
return false;
}
inline void QLock::X_to_w() {
boost::mutex::scoped_lock lk(m);
fassert( 16219, W.n == 0 );
fassert( 16220, R.n == 0 );
fassert( 16221, w.n == 0 );
fassert( 16222, X.n > 0 );
w.n = X.n;
X.n = 0;
++generationXExit;
notifyWeUnlocked('X');
} }
// "i will be writing. i will coordinate with no one. you better stop t hem all" // "i will be writing. i will coordinate with no one. you better stop t hem all"
inline void QLock::_lock_W() { inline void QLock::_lock_W() {
int g = greedyWrites; ++numPendingGlobalWrites;
greed += g; while( !W_legal() ) {
while( W.n + R.n + w.n + r.n ) {
W.c.wait(m); W.c.wait(m);
} }
--numPendingGlobalWrites;
W.n++; W.n++;
greed -= g;
} }
inline void QLock::lock_W() { inline void QLock::lock_W() {
boost::mutex::scoped_lock lk(m); boost::mutex::scoped_lock lk(m);
_lock_W(); _lock_W();
} }
inline void QLock::lock_W_stop_greed() {
boost::mutex::scoped_lock lk(m);
_lock_W();
_stop_greed();
}
inline void QLock::unlock_r() { inline void QLock::unlock_r() {
boost::mutex::scoped_lock lk(m); boost::mutex::scoped_lock lk(m);
fassert(16137, r.n > 0); fassert(16137, r.n > 0);
if( --r.n == 0 ) --r.n;
notifyWeUnlocked('r'); notifyWeUnlocked('r');
} }
inline void QLock::unlock_w() { inline void QLock::unlock_w() {
boost::mutex::scoped_lock lk(m); boost::mutex::scoped_lock lk(m);
fassert(16138, w.n > 0); fassert(16138, w.n > 0);
if( --w.n == 0 ) --w.n;
notifyWeUnlocked('w'); notifyWeUnlocked('w');
X.c.notify_one();
} }
inline void QLock::unlock_R() { inline void QLock::unlock_R() {
boost::mutex::scoped_lock lk(m); boost::mutex::scoped_lock lk(m);
_unlock_R();
}
inline void QLock::_unlock_R() {
fassert(16139, R.n > 0); fassert(16139, R.n > 0);
if( --R.n == 0 ) --R.n;
notifyWeUnlocked('R'); notifyWeUnlocked('R');
} }
inline void QLock::unlock_W() { inline void QLock::unlock_W() {
boost::mutex::scoped_lock lk(m); boost::mutex::scoped_lock lk(m);
fassert(16140, W.n == 1); fassert(16140, W.n == 1);
W.n--; --W.n;
notifyWeUnlocked('W'); notifyWeUnlocked('W');
} }
} }
 End of changes. 44 change blocks. 
120 lines changed or deleted 191 lines changed or added


 query.h   query.h 
skipping to change at line 39 skipping to change at line 39
// struct QueryOptions, QueryResult, QueryResultFlags in: // struct QueryOptions, QueryResult, QueryResultFlags in:
namespace mongo { namespace mongo {
class ParsedQuery; class ParsedQuery;
class QueryOptimizerCursor; class QueryOptimizerCursor;
class QueryPlanSummary; 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); string runQuery(Message& m, QueryMessage& q, CurOp& curop, Message &res ult);
/** Exception indicating that a query should be retried from the beginn ing. */ /** Exception indicating that a query should be retried from the beginn ing. */
class QueryRetryException : public DBException { class QueryRetryException : public DBException {
public: public:
QueryRetryException() : DBException( "query retry exception" , 1608 3 ) { QueryRetryException() : DBException( "query retry exception" , 1608 3 ) {
return; return;
massert( 16083, "reserve 16083", true ); // Reserve 16083. massert( 16083, "reserve 16083", true ); // Reserve 16083.
} }
}; };
skipping to change at line 121 skipping to change at line 121
* Record explain events for a QueryOptimizerCursor, which may record s ome explain information * Record explain events for a QueryOptimizerCursor, which may record s ome explain information
* for multiple clauses and plans through an internal implementation. * for multiple clauses and plans through an internal implementation.
*/ */
class QueryOptimizerCursorExplainStrategy : public MatchCountingExplain Strategy { class QueryOptimizerCursorExplainStrategy : public MatchCountingExplain Strategy {
public: public:
QueryOptimizerCursorExplainStrategy( const ExplainQueryInfo::Ancill aryInfo &ancillaryInfo, QueryOptimizerCursorExplainStrategy( const ExplainQueryInfo::Ancill aryInfo &ancillaryInfo,
const shared_ptr<QueryOptimizer Cursor> &cursor ); const shared_ptr<QueryOptimizer Cursor> &cursor );
private: private:
virtual void _noteIterate( bool match, bool orderedMatch, bool load edRecord, virtual void _noteIterate( bool match, bool orderedMatch, bool load edRecord,
bool chunkSkip ); bool chunkSkip );
virtual void noteYield();
virtual shared_ptr<ExplainQueryInfo> _doneQueryInfo(); virtual shared_ptr<ExplainQueryInfo> _doneQueryInfo();
shared_ptr<QueryOptimizerCursor> _cursor; shared_ptr<QueryOptimizerCursor> _cursor;
}; };
/** Interface for building a query response in a supplied BufBuilder. * / /** Interface for building a query response in a supplied BufBuilder. * /
class ResponseBuildStrategy { class ResponseBuildStrategy {
public: public:
/** /**
* @param queryPlan must be supplied if @param cursor is not a Quer yOptimizerCursor and * @param queryPlan must be supplied if @param cursor is not a Quer yOptimizerCursor and
* results must be sorted or read with a covered index. * results must be sorted or read with a covered index.
*/ */
ResponseBuildStrategy( const ParsedQuery &parsedQuery, const shared _ptr<Cursor> &cursor, ResponseBuildStrategy( const ParsedQuery &parsedQuery, const shared _ptr<Cursor> &cursor,
BufBuilder &buf, const QueryPlanSummary &quer yPlan ); BufBuilder &buf );
virtual ~ResponseBuildStrategy() {} virtual ~ResponseBuildStrategy() {}
/** /**
* Handle the current iterate of the supplied cursor as a (possibly duplicate) match. * Handle the current iterate of the supplied cursor as a (possibly duplicate) match.
* @return true if a match is found. * @return true if a match is found.
* @param orderedMatch set if it is an ordered match. * @param orderedMatch set if it is an ordered match.
*/ */
virtual bool handleMatch( bool &orderedMatch ) = 0; virtual bool handleMatch( bool& orderedMatch, MatchDetails& details
) = 0;
/** /**
* Write all matches into the buffer, overwriting existing data. * Write all matches into the buffer, overwriting existing data.
* @return number of matches written, or -1 if no op. * @return number of matches written, or -1 if no op.
*/ */
virtual int rewriteMatches() { return -1; } virtual int rewriteMatches() { return -1; }
/** @return the number of matches that have been written to the buf fer. */ /** @return the number of matches that have been written to the buf fer. */
virtual int bufferedMatches() const = 0; virtual int bufferedMatches() const = 0;
/** /**
* Callback when enough results have been read for the first batch, with potential handoff * Callback when enough results have been read for the first batch, with potential handoff
* to getMore. * to getMore.
skipping to change at line 171 skipping to change at line 173
const ParsedQuery &_parsedQuery; const ParsedQuery &_parsedQuery;
shared_ptr<Cursor> _cursor; shared_ptr<Cursor> _cursor;
shared_ptr<QueryOptimizerCursor> _queryOptimizerCursor; shared_ptr<QueryOptimizerCursor> _queryOptimizerCursor;
BufBuilder &_buf; BufBuilder &_buf;
}; };
/** Build strategy for a cursor returning in order results. */ /** Build strategy for a cursor returning in order results. */
class OrderedBuildStrategy : public ResponseBuildStrategy { class OrderedBuildStrategy : public ResponseBuildStrategy {
public: public:
OrderedBuildStrategy( const ParsedQuery &parsedQuery, const shared_ ptr<Cursor> &cursor, OrderedBuildStrategy( const ParsedQuery &parsedQuery, const shared_ ptr<Cursor> &cursor,
BufBuilder &buf, const QueryPlanSummary &query BufBuilder &buf );
Plan ); virtual bool handleMatch( bool& orderedMatch, MatchDetails& details
virtual bool handleMatch( bool &orderedMatch ); );
virtual int bufferedMatches() const { return _bufferedMatches; } virtual int bufferedMatches() const { return _bufferedMatches; }
private: private:
int _skip; int _skip;
int _bufferedMatches; int _bufferedMatches;
}; };
class ScanAndOrder; class ScanAndOrder;
/** Build strategy for a cursor returning out of order results. */ /** Build strategy for a cursor returning out of order results. */
class ReorderBuildStrategy : public ResponseBuildStrategy { class ReorderBuildStrategy : public ResponseBuildStrategy {
public: public:
ReorderBuildStrategy( const ParsedQuery &parsedQuery, static ReorderBuildStrategy* make( const ParsedQuery& parsedQuery,
const shared_ptr<Cursor> &cursor, const shared_ptr<Cursor>& cursor
BufBuilder &buf, ,
const QueryPlanSummary &queryPlan ); BufBuilder& buf,
virtual bool handleMatch( bool &orderedMatch ); const QueryPlanSummary& queryPla
n );
virtual bool handleMatch( bool &orderedMatch, MatchDetails& details
);
/** Handle a match without performing deduping. */ /** Handle a match without performing deduping. */
void _handleMatchNoDedup(); void _handleMatchNoDedup();
virtual int rewriteMatches(); virtual int rewriteMatches();
virtual int bufferedMatches() const { return _bufferedMatches; } virtual int bufferedMatches() const { return _bufferedMatches; }
private: private:
ReorderBuildStrategy( const ParsedQuery& parsedQuery,
const shared_ptr<Cursor>& cursor,
BufBuilder& buf );
void init( const QueryPlanSummary& queryPlan );
ScanAndOrder *newScanAndOrder( const QueryPlanSummary &queryPlan ) const; ScanAndOrder *newScanAndOrder( const QueryPlanSummary &queryPlan ) const;
shared_ptr<ScanAndOrder> _scanAndOrder; shared_ptr<ScanAndOrder> _scanAndOrder;
int _bufferedMatches; int _bufferedMatches;
}; };
/** Helper class for deduping DiskLocs */ /** Helper class for deduping DiskLocs */
class DiskLocDupSet { class DiskLocDupSet {
public: public:
/** @return true if dup, otherwise return false and insert. */ /** @return true if dup, otherwise return false and insert. */
bool getsetdup( const DiskLoc &loc ) { bool getsetdup( const DiskLoc &loc ) {
skipping to change at line 217 skipping to change at line 223
private: private:
set<DiskLoc> _dups; set<DiskLoc> _dups;
}; };
/** /**
* Build strategy for a QueryOptimizerCursor containing some in order a nd some out of order * Build strategy for a QueryOptimizerCursor containing some in order a nd some out of order
* candidate plans. * candidate plans.
*/ */
class HybridBuildStrategy : public ResponseBuildStrategy { class HybridBuildStrategy : public ResponseBuildStrategy {
public: public:
static HybridBuildStrategy* make( const ParsedQuery& parsedQuery,
const shared_ptr<QueryOptimizerCu
rsor>& cursor,
BufBuilder& buf );
private:
HybridBuildStrategy( const ParsedQuery &parsedQuery, HybridBuildStrategy( const ParsedQuery &parsedQuery,
const shared_ptr<QueryOptimizerCursor> &cursor, const shared_ptr<QueryOptimizerCursor> &cursor,
BufBuilder &buf ); BufBuilder &buf );
private: void init();
virtual bool handleMatch( bool &orderedMatch ); virtual bool handleMatch( bool &orderedMatch, MatchDetails &details
);
virtual int rewriteMatches(); virtual int rewriteMatches();
virtual int bufferedMatches() const; virtual int bufferedMatches() const;
virtual void finishedFirstBatch(); virtual void finishedFirstBatch();
bool handleReorderMatch(); bool handleReorderMatch();
DiskLocDupSet _scanAndOrderDups; DiskLocDupSet _scanAndOrderDups;
OrderedBuildStrategy _orderedBuild; OrderedBuildStrategy _orderedBuild;
ReorderBuildStrategy _reorderBuild; scoped_ptr<ReorderBuildStrategy> _reorderBuild;
bool _reorderedMatches; bool _reorderedMatches;
}; };
/** /**
* Builds a query response with the help of an ExplainRecordingStrategy and a * Builds a query response with the help of an ExplainRecordingStrategy and a
* ResponseBuildStrategy. * ResponseBuildStrategy.
*/ */
class QueryResponseBuilder { class QueryResponseBuilder {
public: public:
/** /**
* @param queryPlan must be supplied if @param cursor is not a Quer yOptimizerCursor and * @param queryPlan must be supplied if @param cursor is not a Quer yOptimizerCursor and
* results must be sorted or read with a covered index. * results must be sorted or read with a covered index.
*/ */
QueryResponseBuilder( const ParsedQuery &parsedQuery, const shared_ static QueryResponseBuilder *make( const ParsedQuery &parsedQuery,
ptr<Cursor> &cursor, const shared_ptr<Cursor> &cursor,
const QueryPlanSummary &queryPlan, const BSONO const QueryPlanSummary &queryPlan
bj &oldPlan ); ,
const BSONObj &oldPlan );
/** @return true if the current iterate matches and is added. */ /** @return true if the current iterate matches and is added. */
bool addMatch(); bool addMatch();
/** Note that a yield occurred. */ /** Note that a yield occurred. */
void noteYield(); void noteYield();
/** @return true if there are enough results to return the first ba tch. */ /** @return true if there are enough results to return the first ba tch. */
bool enoughForFirstBatch() const; bool enoughForFirstBatch() const;
/** @return true if there are enough results to return the full res ult set. */ /** @return true if there are enough results to return the full res ult set. */
bool enoughTotalResults() const; bool enoughTotalResults() const;
/** /**
* Callback when enough results have been read for the first batch, with potential handoff * Callback when enough results have been read for the first batch, with potential handoff
skipping to change at line 264 skipping to change at line 276
* to getMore. * to getMore.
*/ */
void finishedFirstBatch(); void finishedFirstBatch();
/** /**
* Set the data portion of the supplied Message to a buffer contain ing the query results. * Set the data portion of the supplied Message to a buffer contain ing the query results.
* @return the number of results in the buffer. * @return the number of results in the buffer.
*/ */
int handoff( Message &result ); int handoff( Message &result );
/** A chunk manager found at the beginning of the query. */ /** A chunk manager found at the beginning of the query. */
ShardChunkManagerPtr chunkManager() const { return _chunkManager; } ShardChunkManagerPtr chunkManager() const { return _chunkManager; }
private: private:
QueryResponseBuilder( const ParsedQuery &parsedQuery, const shared_
ptr<Cursor> &cursor );
void init( const QueryPlanSummary &queryPlan, const BSONObj &oldPla
n );
ShardChunkManagerPtr newChunkManager() const; ShardChunkManagerPtr newChunkManager() const;
shared_ptr<ExplainRecordingStrategy> newExplainRecordingStrategy shared_ptr<ExplainRecordingStrategy> newExplainRecordingStrategy
( const QueryPlanSummary &queryPlan, const BSONObj &oldPlan ) const ; ( const QueryPlanSummary &queryPlan, const BSONObj &oldPlan ) const ;
shared_ptr<ResponseBuildStrategy> newResponseBuildStrategy shared_ptr<ResponseBuildStrategy> newResponseBuildStrategy
( const QueryPlanSummary &queryPlan ); ( const QueryPlanSummary &queryPlan );
bool currentMatches(); bool currentMatches( MatchDetails& details );
bool chunkMatches(); bool chunkMatches();
const ParsedQuery &_parsedQuery; const ParsedQuery &_parsedQuery;
shared_ptr<Cursor> _cursor; shared_ptr<Cursor> _cursor;
shared_ptr<QueryOptimizerCursor> _queryOptimizerCursor; shared_ptr<QueryOptimizerCursor> _queryOptimizerCursor;
BufBuilder _buf; BufBuilder _buf;
ShardChunkManagerPtr _chunkManager; ShardChunkManagerPtr _chunkManager;
shared_ptr<ExplainRecordingStrategy> _explain; shared_ptr<ExplainRecordingStrategy> _explain;
shared_ptr<ResponseBuildStrategy> _builder; shared_ptr<ResponseBuildStrategy> _builder;
}; };
 End of changes. 14 change blocks. 
19 lines changed or deleted 42 lines changed or added


 queryoptimizer.h   queryoptimizer.h 
skipping to change at line 34 skipping to change at line 34
#include "explain.h" #include "explain.h"
#include "../util/net/listen.h" #include "../util/net/listen.h"
#include "mongo/db/querypattern.h" #include "mongo/db/querypattern.h"
namespace mongo { namespace mongo {
class IndexDetails; class IndexDetails;
class IndexType; class IndexType;
class QueryPlanSummary; 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 FieldRan
geSet. An object of this
* class may only be used by one thread at a time.
*/
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, static QueryPlan *make( 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,
const shared_ptr<const ParsedQuery> &parsedQuery = const shared_ptr<const ParsedQuery> &parsedQ
shared_ptr<const ParsedQuery>(), uery =
const BSONObj &startKey = BSONObj(), shared_ptr<const ParsedQuery>(),
const BSONObj &endKey = BSONObj(), const BSONObj &startKey = BSONObj(),
string special="" ); const BSONObj &endKey = BSONObj(),
string special="" );
/** @return true iff this plan cannot return any documents. */ /** Categorical classification of a QueryPlan's utility. */
bool impossible() const { return _impossible; } enum Utility {
/** Impossible, // Cannot produce any matches, so the query must ha
* @return true iff this plan should run as the only candidate plan ve an empty result set.
in the absence of an // No other plans need to be considered.
* impossible plan. Optimal, // Should run as the only candidate plan in the abs
*/ ence of an Impossible
bool optimal() const { return _optimal; } // plan.
/** @return true iff this plan should not be considered at all. */ Helpful, // Should be considered.
bool unhelpful() const { return _unhelpful; } Unhelpful, // Should not be considered.
/** @return true iff ScanAndOrder processing will be required for r Disallowed // Must not be considered unless explicitly hinted.
esult set. */ May produce a
// semantically incorrect result set.
};
Utility utility() const { return _utility; }
/** @return true if ScanAndOrder processing will be required for re
sult set. */
bool scanAndOrderRequired() const { return _scanAndOrderRequired; } bool scanAndOrderRequired() const { return _scanAndOrderRequired; }
/** /**
* @return true iff the index we are using has keys such that it ca n completely resolve the * @return true if the index we are using has keys such that it can 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 if this QueryPlan would perform an unindexed scan.
. */ */
bool willScanTable() const { return _idxNo < 0 && !_impossible; } bool willScanTable() const { return _idxNo < 0 && ( _utility != Imp
ossible ); }
/** @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() ) 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, CandidatePlanCharacter candi datePlans ) const; void registerSelf( long long nScanned, CandidatePlanCharacter candi datePlans ) const;
skipping to change at line 95 skipping to change at line 103
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; }
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; }
shared_ptr<Projection::KeyOnly> keyFieldsOnly() const { return _key FieldsOnly; } shared_ptr<Projection::KeyOnly> keyFieldsOnly() const { return _key FieldsOnly; }
/** @return a shared, lazily initialized matcher for the query plan
. */
shared_ptr<CoveredIndexMatcher> matcher() const;
QueryPlanSummary summary() const; QueryPlanSummary summary() const;
/** The following member functions are for testing, or public for t esting. */ /** 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; string toString() const;
bool queryFiniteSetOrderSuffix() const; bool queryBoundsExactOrderSuffix() const;
private: private:
QueryPlan(NamespaceDetails *d,
int idxNo,
const FieldRangeSetPair &frsp,
const BSONObj &originalQuery,
const BSONObj &order,
const shared_ptr<const ParsedQuery> &parsedQuery,
string special );
void init( const FieldRangeSetPair *originalFrsp,
const BSONObj &startKey,
const BSONObj &endKey );
void checkTableScanAllowed() const; void checkTableScanAllowed() const;
int independentRangesSingleIntervalLimit() const; int independentRangesSingleIntervalLimit() const;
/** @return true when the plan's query may contains an $exists:fals
e predicate. */
bool hasPossibleExistsFalsePredicate() 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; shared_ptr<const ParsedQuery> _parsedQuery;
const IndexDetails * _index; const IndexDetails * _index;
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; Utility _utility;
bool _impossible;
string _special; string _special;
IndexType * _type; IndexType * _type;
bool _startOrEndSpec; bool _startOrEndSpec;
shared_ptr<Projection::KeyOnly> _keyFieldsOnly; shared_ptr<Projection::KeyOnly> _keyFieldsOnly;
mutable shared_ptr<CoveredIndexMatcher> _matcher; // Lazy initializ ation.
}; };
std::ostream &operator<< ( std::ostream &out, const QueryPlan::Utility
&utility );
/** /**
* A QueryPlanSummary owns its own attributes and may be shared. Curre ntly a QueryPlan * A QueryPlanSummary owns its own attributes and may be shared. Curre ntly a QueryPlan
* should only be owned by a QueryPlanSet. * should only be owned by a QueryPlanSet.
*/ */
class QueryPlanSummary { class QueryPlanSummary {
public: public:
QueryPlanSummary() : QueryPlanSummary() :
_scanAndOrderRequired() { _scanAndOrderRequired() {
} }
QueryPlanSummary( const QueryPlan &queryPlan ) : QueryPlanSummary( const QueryPlan &queryPlan ) :
skipping to change at line 154 skipping to change at line 180
_keyFieldsOnly( queryPlan.keyFieldsOnly() ), _keyFieldsOnly( queryPlan.keyFieldsOnly() ),
_scanAndOrderRequired( queryPlan.scanAndOrderRequired() ) { _scanAndOrderRequired( queryPlan.scanAndOrderRequired() ) {
} }
bool valid() const { return _fieldRangeSetMulti; } bool valid() const { return _fieldRangeSetMulti; }
shared_ptr<FieldRangeSet> _fieldRangeSetMulti; shared_ptr<FieldRangeSet> _fieldRangeSetMulti;
shared_ptr<Projection::KeyOnly> _keyFieldsOnly; shared_ptr<Projection::KeyOnly> _keyFieldsOnly;
bool _scanAndOrderRequired; bool _scanAndOrderRequired;
}; };
/** /**
* NOTE This interface is deprecated and will be replaced by a special
purpose delegation class
* for the query optimizer cursor (QueryOptimizerCursorOp).
*
* 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().
* 3) _init() is called on the QueryPlan. * 3) _init() is called on the QueryPlan.
* 4) next() is called repeatedly, with nscanned() checked after each c all. * 4) next() is called repeatedly, with nscanned() checked after each c all.
* 5) In one of these calls to next(), setComplete() is called. * 5) In one of these calls to next(), setComplete() is called.
* 6) The QueryPattern for the QueryPlan may be recorded as a winner. * 6) The QueryPattern for the QueryPlan may be recorded as a winner.
*/ */
class QueryOp { class QueryOp : private boost::noncopyable {
public: public:
QueryOp() : _complete(), _stopRequested(), _qp(), _error() {} QueryOp() : _complete(), _stopRequested(), _queryPlan(), _error() {
}
/** Used when handing off from one QueryOp to another. */
QueryOp( const QueryOp &other ) :
_complete(), _stopRequested(), _qp(), _error(), _matcher( other
._matcher ),
_orConstraint( other._orConstraint ) {}
virtual ~QueryOp() {} virtual ~QueryOp() {}
/** @return QueryPlan assigned to this QueryOp by the query optimiz er. */ /** @return QueryPlan assigned to this QueryOp by the query optimiz er. */
const QueryPlan &qp() const { return *_qp; } const QueryPlan &queryPlan() const { return *_queryPlan; }
/** 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 void prepareToYield() = 0; virtual void prepareToYield() = 0;
skipping to change at line 210 skipping to change at line 234
/** @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(); } 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(); /**
void setQueryPlan( const QueryPlan *qp ) { _qp = qp; verify( _qp != * @return a copy of the inheriting class, which will be run with i
NULL ); } ts own query plan. The
void init(); * child QueryOp will assume its parent QueryOp has completed execu
tion.
*/
virtual QueryOp *createChild() const = 0;
void setQueryPlan( const QueryPlan *queryPlan ) {
_queryPlan = queryPlan;
verify( _queryPlan != NULL );
}
/** Handle initialization after a QueryPlan has been set. */
virtual void init() = 0;
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 {
return matcher( c.get() );
}
shared_ptr<CoveredIndexMatcher> matcher( Cursor* c ) const {
if( ! c ) return _matcher;
return c->matcher() ? c->matcherPtr() : _matcher;
}
/** @return an ExplainPlanInfo object that will be updated as the q uery runs. */ /** @return an ExplainPlanInfo object that will be updated as the q uery runs. */
virtual shared_ptr<ExplainPlanInfo> generateExplainInfo() { virtual shared_ptr<ExplainPlanInfo> generateExplainInfo() {
return shared_ptr<ExplainPlanInfo>( new ExplainPlanInfo() ); 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() { _complete = true; }
_orConstraint = qp().originalFrv();
_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. */
virtual void _init() = 0;
/** @return a copy of the inheriting class, which will be run with
its own query plan. */
virtual QueryOp *_createChild() const = 0;
private: private:
bool _complete; bool _complete;
bool _stopRequested; bool _stopRequested;
ExceptionInfo _exception; ExceptionInfo _exception;
const QueryPlan *_qp; const QueryPlan *_queryPlan;
bool _error; bool _error;
shared_ptr<CoveredIndexMatcher> _matcher;
shared_ptr<CoveredIndexMatcher> _oldMatcher;
shared_ptr<FieldRangeVector> _orConstraint;
}; };
// temp. this class works if T::operator< is variant unlike a regular stl priority queue. // temp. this class works if T::operator< is variant unlike a regular stl priority queue.
// but it's very slow. however if v.size() is always very small, it wo uld be fine, // but it's very slow. however if v.size() is always very small, it wo uld be fine,
// maybe even faster than a smart impl that does more memory allocation s. // maybe even faster than a smart impl that does more memory allocation s.
template<class T> template<class T>
class our_priority_queue : boost::noncopyable { class our_priority_queue : boost::noncopyable {
vector<T> v; vector<T> v;
public: public:
our_priority_queue() { our_priority_queue() {
skipping to change at line 304 skipping to change at line 316
Use // Always use the recorded plan. Use // Always use the recorded plan.
} RecordedPlanPolicy; } RecordedPlanPolicy;
/** @param qps The QueryPlanSet to which plans will be provided. */ /** @param qps The QueryPlanSet to which plans will be provided. */
QueryPlanGenerator( QueryPlanSet &qps, QueryPlanGenerator( QueryPlanSet &qps,
auto_ptr<FieldRangeSetPair> originalFrsp, auto_ptr<FieldRangeSetPair> originalFrsp,
const shared_ptr<const ParsedQuery> &parsedQuery , const shared_ptr<const ParsedQuery> &parsedQuery ,
const BSONObj &hint, const BSONObj &hint,
RecordedPlanPolicy recordedPlanPolicy, RecordedPlanPolicy recordedPlanPolicy,
const BSONObj &min, const BSONObj &min,
const BSONObj &max ); const BSONObj &max,
bool allowSpecial );
/** Populate the provided QueryPlanSet with an initial set of plans . */ /** Populate the provided QueryPlanSet with an initial set of plans . */
void addInitialPlans(); void addInitialPlans();
/** Supplement a cached plan provided earlier by adding additional query plans. */ /** Supplement a cached plan provided earlier by adding additional query plans. */
void addFallbackPlans(); void addFallbackPlans();
private: private:
bool addShortCircuitPlan( NamespaceDetails *d ); bool addShortCircuitPlan( NamespaceDetails *d );
bool addHintPlan( NamespaceDetails *d ); bool addHintPlan( NamespaceDetails *d );
bool addSpecialPlan( NamespaceDetails *d ); bool addSpecialPlan( NamespaceDetails *d );
void addStandardPlans( NamespaceDetails *d ); void addStandardPlans( NamespaceDetails *d );
bool addCachedPlan( NamespaceDetails *d ); bool addCachedPlan( NamespaceDetails *d );
shared_ptr<QueryPlan> newPlan( NamespaceDetails *d, shared_ptr<QueryPlan> newPlan( NamespaceDetails *d,
int idxNo, int idxNo,
const BSONObj &min = BSONObj(), const BSONObj &min = BSONObj(),
const BSONObj &max = BSONObj(), const BSONObj &max = BSONObj(),
const string &special = "" ) const; const string &special = "" ) const;
bool setUnindexedPlanIf( bool set, NamespaceDetails *d ); bool setUnindexedPlanIf( bool set, NamespaceDetails *d );
void setSingleUnindexedPlan( NamespaceDetails *d ); void setSingleUnindexedPlan( NamespaceDetails *d );
void setHintedPlan( IndexDetails &id ); void setHintedPlanForIndex( IndexDetails& id );
void validateAndSetHintedPlan( const shared_ptr<QueryPlan>& plan );
void warnOnCappedIdTableScan() const; void warnOnCappedIdTableScan() const;
QueryPlanSet &_qps; QueryPlanSet &_qps;
auto_ptr<FieldRangeSetPair> _originalFrsp; auto_ptr<FieldRangeSetPair> _originalFrsp;
shared_ptr<const ParsedQuery> _parsedQuery; shared_ptr<const ParsedQuery> _parsedQuery;
BSONObj _hint; BSONObj _hint;
RecordedPlanPolicy _recordedPlanPolicy; RecordedPlanPolicy _recordedPlanPolicy;
BSONObj _min; BSONObj _min;
BSONObj _max; BSONObj _max;
bool _allowSpecial;
}; };
/** /**
* A set of candidate query plans for a query. This class can return a best guess 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 ; if null, frsp will be * @param originalFrsp - original constraints for this query clause ; if null, frsp will be
* used. * used.
*/ */
QueryPlanSet( const char *ns, static QueryPlanSet* make( const char* ns,
auto_ptr<FieldRangeSetPair> frsp, auto_ptr<FieldRangeSetPair> frsp,
auto_ptr<FieldRangeSetPair> originalFrsp, auto_ptr<FieldRangeSetPair> originalFrsp
const BSONObj &originalQuery, ,
const BSONObj &order, const BSONObj& originalQuery,
const shared_ptr<const ParsedQuery> &parsedQuery = const BSONObj& order,
shared_ptr<const ParsedQuery>(), const shared_ptr<const ParsedQuery>& par
const BSONObj &hint = BSONObj(), sedQuery,
QueryPlanGenerator::RecordedPlanPolicy recordedPlanPol const BSONObj& hint,
icy = QueryPlanGenerator::RecordedPlanPolicy r
QueryPlanGenerator::Use, ecordedPlanPolicy,
const BSONObj &min = BSONObj(), const BSONObj& min,
const BSONObj &max = BSONObj() ); const BSONObj& max,
bool allowSpecial );
/** @return number of candidate plans. */ /** @return number of candidate plans. */
int nPlans() const { return _plans.size(); } int nPlans() const { return _plans.size(); }
QueryPlanPtr firstPlan() const { return _plans[ 0 ]; } QueryPlanPtr firstPlan() const { return _plans[ 0 ]; }
/** @return true if a plan is selected based on previous success of this plan. */ /** @return true if a plan is selected based on previous success of 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. */ /** @return true if some candidate plans may have been excluded due to plan caching. */
bool hasPossiblyExcludedPlans() const; bool hasPossiblyExcludedPlans() const;
skipping to change at line 451 skipping to change at line 465
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; shared_ptr<ExplainClauseInfo> _explainClauseInfo;
bool _done; bool _done;
}; };
private: private:
void addFallbackPlans();
QueryPlanSet( const char *ns,
auto_ptr<FieldRangeSetPair> frsp,
auto_ptr<FieldRangeSetPair> originalFrsp,
const BSONObj &originalQuery,
const BSONObj &order,
const shared_ptr<const ParsedQuery> &parsedQuery,
const BSONObj &hint,
QueryPlanGenerator::RecordedPlanPolicy recordedPlanPol
icy,
const BSONObj &min,
const BSONObj &max,
bool allowSpecial );
void init(); void init();
void addFallbackPlans();
void pushPlan( const QueryPlanPtr& plan );
QueryPlanGenerator _generator; QueryPlanGenerator _generator;
BSONObj _originalQuery; BSONObj _originalQuery;
auto_ptr<FieldRangeSetPair> _frsp; auto_ptr<FieldRangeSetPair> _frsp;
PlanSet _plans; PlanSet _plans;
bool _mayRecordPlan; bool _mayRecordPlan;
bool _usingCachedPlan; bool _usingCachedPlan;
CandidatePlanCharacter _cachedPlanCharacter; CandidatePlanCharacter _cachedPlanCharacter;
BSONObj _order; BSONObj _order;
long long _oldNScanned; long long _oldNScanned;
ElapsedTracker _yieldSometimesTracker; ElapsedTracker _yieldSometimesTracker;
bool _allowSpecial;
}; };
/** 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,
const BSONObj &query, static MultiPlanScanner *make( const char *ns,
const BSONObj &order, const BSONObj &query,
const shared_ptr<const ParsedQuery> &parsedQuery const BSONObj &order,
= const shared_ptr<const ParsedQuery> &
shared_ptr<const ParsedQuery>(), parsedQuery =
const BSONObj &hint = BSONObj(), shared_ptr<const ParsedQuery>(
QueryPlanGenerator::RecordedPlanPolicy recordedPl ),
anPolicy = const BSONObj &hint = BSONObj(),
QueryPlanGenerator::Use, QueryPlanGenerator::RecordedPlanPolic
const BSONObj &min = BSONObj(), y recordedPlanPolicy =
const BSONObj &max = BSONObj() ); QueryPlanGenerator::Use,
const BSONObj &min = BSONObj(),
const BSONObj &max = BSONObj() );
/** Set the initial QueryOp for QueryPlanSet iteration. */ /** Set the initial QueryOp for QueryPlanSet iteration. */
void initialOp( const shared_ptr<QueryOp> &originalOp ) { _baseOp = originalOp; } void initialOp( const shared_ptr<QueryOp> &originalOp ) { _baseOp = originalOp; }
/** /**
* Advance to the next QueryOp, if not doneOps(). * Advance to the next QueryOp, if not doneOps().
* @return the next non error op if there is one, otherwise an erro r op. * @return the next non error op if there is one, otherwise an erro r op.
* If the returned op is complete() or error(), the MultiPlanScanne r becomes doneOps() and * If the returned op is complete() or error(), the MultiPlanScanne r becomes doneOps() and
* no further QueryOp iteration is possible. * no further QueryOp iteration is possible.
*/ */
shared_ptr<QueryOp> nextOp(); shared_ptr<QueryOp> nextOp();
skipping to change at line 565 skipping to change at line 595
/** @return true if an active or fallback plan of _currentQps is in order. */ /** @return true if an active or fallback plan of _currentQps is in order. */
bool possibleInOrderPlan() const; bool possibleInOrderPlan() const;
/** @return true if an active or fallback plan of _currentQps is ou t of order. */ /** @return true if an active or fallback plan of _currentQps is ou t of order. */
bool possibleOutOfOrderPlan() const; bool possibleOutOfOrderPlan() const;
int i() const { return _i; } int i() const { return _i; }
string toString() const; string toString() const;
private: private:
MultiPlanScanner( const char *ns,
const BSONObj &query,
const shared_ptr<const ParsedQuery> &parsedQuery,
const BSONObj &hint,
QueryPlanGenerator::RecordedPlanPolicy recordedPla
nPolicy );
void init( const BSONObj &order,
const BSONObj &min,
const BSONObj &max );
/** Initialize or iterate a runner generated from @param originalOp . */ /** Initialize or iterate a runner generated from @param originalOp . */
shared_ptr<QueryOp> iterateRunner( QueryOp &originalOp, bool retrie d = false ); shared_ptr<QueryOp> iterateRunner( QueryOp &originalOp, bool retrie d = false );
shared_ptr<QueryOp> nextOpSimple(); shared_ptr<QueryOp> nextOpSimple();
shared_ptr<QueryOp> nextOpOr(); shared_ptr<QueryOp> nextOpOr();
void updateCurrentQps( QueryPlanSet *qps ); 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 );
skipping to change at line 607 skipping to change at line 647
scoped_ptr<QueryPlanSet::Runner> _runner; scoped_ptr<QueryPlanSet::Runner> _runner;
shared_ptr<ExplainQueryInfo> _explainQueryInfo; shared_ptr<ExplainQueryInfo> _explainQueryInfo;
bool _doneOps; bool _doneOps;
}; };
/** /**
* Provides a cursor interface for serial single Cursor iteration using a MultiPlanScanner. * Provides a cursor interface for serial single Cursor iteration using a MultiPlanScanner.
* Currently used internally by a QueryOptimizerCursor. * Currently used internally by a QueryOptimizerCursor.
* *
* A MultiCursor is backed by one BasicCursor or BtreeCursor at a time and forwards calls for * 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 * ensuring a consistent state after a write to its backing Cursor.
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:
/** @param nscanned is the initial nscanned value. */ /** @param nscanned is the initial nscanned value. */
MultiCursor( auto_ptr<MultiPlanScanner> mps, const shared_ptr<Curso r> &c, MultiCursor( auto_ptr<MultiPlanScanner> mps, const shared_ptr<Curso r> &c,
const shared_ptr<CoveredIndexMatcher> &matcher, const shared_ptr<CoveredIndexMatcher> &matcher,
const shared_ptr<ExplainPlanInfo> &explainPlanInfo, const shared_ptr<ExplainPlanInfo> &explainPlanInfo,
const QueryOp &op, long long nscanned ); const QueryOp &op, long long nscanned );
virtual bool ok() { return _c->ok(); } virtual bool ok() { return _c->ok(); }
skipping to change at line 635 skipping to change at line 674
virtual void noteLocation() { _c->noteLocation(); } virtual void noteLocation() { _c->noteLocation(); }
virtual void checkLocation() { _c->checkLocation(); } virtual void checkLocation() { _c->checkLocation(); }
virtual void recoverFromYield(); virtual void recoverFromYield();
virtual bool supportGetMore() { return true; } virtual bool supportGetMore() { return true; }
virtual bool supportYields() { return true; } 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 r. */ /** Deduping documents from a prior cursor is handled by the matche r. */
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 modifiedKeys() const { return true; } 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(); }
virtual long long nscanned() { return _nscanned + _c->nscanned(); } virtual long long nscanned() { return _nscanned + _c->nscanned(); }
void noteIterate( bool match, bool loadedRecord ); void noteIterate( bool match, bool loadedRecord );
void noteYield();
const QueryPlan &queryPlan() const { const QueryPlan &queryPlan() const {
verify( _c->ok() && _queryPlan ); verify( _c->ok() && _queryPlan );
return *_queryPlan; return *_queryPlan;
} }
const Projection::KeyOnly *keyFieldsOnly() const { const Projection::KeyOnly *keyFieldsOnly() const {
verify( _c->ok() && _queryPlan ); verify( _c->ok() && _queryPlan );
return _queryPlan->keyFieldsOnly().get(); return _queryPlan->keyFieldsOnly().get();
} }
private: private:
void nextClause(); void advanceClause();
void advanceExhaustedClauses();
auto_ptr<MultiPlanScanner> _mps; auto_ptr<MultiPlanScanner> _mps;
shared_ptr<Cursor> _c; shared_ptr<Cursor> _c;
shared_ptr<CoveredIndexMatcher> _matcher; shared_ptr<CoveredIndexMatcher> _matcher;
const QueryPlan *_queryPlan; const QueryPlan *_queryPlan;
long long _nscanned; long long _nscanned;
shared_ptr<ExplainPlanInfo> _explainPlanInfo; 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 );
 End of changes. 36 change blocks. 
107 lines changed or deleted 153 lines changed or added


 queryoptimizercursor.h   queryoptimizercursor.h 
skipping to change at line 121 skipping to change at line 121
*/ */
virtual bool completePlanOfHybridSetScanAndOrderRequired() const = 0; virtual bool completePlanOfHybridSetScanAndOrderRequired() const = 0;
/** Clear recorded indexes for the current clause's query patterns. */ /** Clear recorded indexes for the current clause's query patterns. */
virtual void clearIndexesForPatterns() = 0; virtual void clearIndexesForPatterns() = 0;
/** Stop returning results from out of order plans and do not allow them to complete. */ /** Stop returning results from out of order plans and do not allow them to complete. */
virtual void abortOutOfOrderPlans() = 0; virtual void abortOutOfOrderPlans() = 0;
/** Note match information for the current iterate, to generate exp lain output. */ /** Note match information for the current iterate, to generate exp lain output. */
virtual void noteIterate( bool match, bool loadedDocument, bool chu nkSkip ) = 0; virtual void noteIterate( bool match, bool loadedDocument, bool chu nkSkip ) = 0;
/** Note a lock yield for explain output reporting. */
virtual void noteYield() = 0;
/** @return explain output for the query run by this cursor. */ /** @return explain output for the query run by this cursor. */
virtual shared_ptr<ExplainQueryInfo> explainQueryInfo() const = 0; virtual shared_ptr<ExplainQueryInfo> explainQueryInfo() const = 0;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 queryoptimizercursorimpl.h   queryoptimizercursorimpl.h 
skipping to change at line 186 skipping to change at line 186
* outlive its constructor arguments. * outlive its constructor arguments.
*/ */
class CursorGenerator { class CursorGenerator {
public: public:
CursorGenerator( const char *ns, CursorGenerator( const char *ns,
const BSONObj &query, const BSONObj &query,
const BSONObj &order, const BSONObj &order,
const QueryPlanSelectionPolicy &planPolicy, const QueryPlanSelectionPolicy &planPolicy,
bool *simpleEqualityMatch, bool *simpleEqualityMatch,
const shared_ptr<const ParsedQuery> &parsedQuery, const shared_ptr<const ParsedQuery> &parsedQuery,
bool requireOrder,
QueryPlanSummary *singlePlanSummary ); QueryPlanSummary *singlePlanSummary );
shared_ptr<Cursor> generate(); shared_ptr<Cursor> generate();
private: private:
bool snapshot() const { return _parsedQuery && _parsedQuery->isSnap shot(); } bool snapshot() const { return _parsedQuery && _parsedQuery->isSnap shot(); }
bool explain() const { return _parsedQuery && _parsedQuery->isExpla in(); } bool explain() const { return _parsedQuery && _parsedQuery->isExpla in(); }
BSONObj min() const { return _parsedQuery ? _parsedQuery->getMin() : BSONObj(); } BSONObj min() const { return _parsedQuery ? _parsedQuery->getMin() : BSONObj(); }
BSONObj max() const { return _parsedQuery ? _parsedQuery->getMax() : BSONObj(); } BSONObj max() const { return _parsedQuery ? _parsedQuery->getMax() : BSONObj(); }
bool hasFields() const { return _parsedQuery && _parsedQuery->getFi eldPtr(); } bool hasFields() const { return _parsedQuery && _parsedQuery->getFi eldPtr(); }
/** If no ParsedQuery was supplied, it's assumed no reordering will bool isOrderRequired() const { return _requireOrder; }
be applied. */
bool requireOrder() const { return !_parsedQuery; }
bool mayShortcutQueryOptimizer() const { bool mayShortcutQueryOptimizer() const {
return min().isEmpty() && max().isEmpty() && !hasFields() && _a rgumentsHint.isEmpty(); return min().isEmpty() && max().isEmpty() && !hasFields() && _a rgumentsHint.isEmpty();
} }
BSONObj hint() const { BSONObj hint() const {
return _argumentsHint.isEmpty() ? _planPolicy.planHint( _ns ) : _argumentsHint; return _argumentsHint.isEmpty() ? _planPolicy.planHint( _ns ) : _argumentsHint;
} }
void setArgumentsHint(); void setArgumentsHint();
shared_ptr<Cursor> shortcutCursor() const; shared_ptr<Cursor> shortcutCursor() const;
void setMultiPlanScanner(); void setMultiPlanScanner();
shared_ptr<Cursor> singlePlanCursor(); shared_ptr<Cursor> singlePlanCursor();
const char *_ns; const char *_ns;
BSONObj _query; BSONObj _query;
BSONObj _order; BSONObj _order;
const QueryPlanSelectionPolicy &_planPolicy; const QueryPlanSelectionPolicy &_planPolicy;
bool *_simpleEqualityMatch; bool *_simpleEqualityMatch;
shared_ptr<const ParsedQuery> _parsedQuery; shared_ptr<const ParsedQuery> _parsedQuery;
bool _requireOrder;
QueryPlanSummary *_singlePlanSummary; QueryPlanSummary *_singlePlanSummary;
BSONObj _argumentsHint; BSONObj _argumentsHint;
auto_ptr<MultiPlanScanner> _mps; auto_ptr<MultiPlanScanner> _mps;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 queryutil.h   queryutil.h 
skipping to change at line 151 skipping to change at line 151
if ( ! e.isABSONObj() ) if ( ! e.isABSONObj() )
e = q["$query"]; e = q["$query"];
if ( e.isABSONObj() ) { if ( e.isABSONObj() ) {
_filter = e.embeddedObject(); _filter = e.embeddedObject();
_initTop( q ); _initTop( q );
} }
else { else {
_filter = q; _filter = q;
} }
_filter = _filter.getOwned();
} }
void _reset() { void _reset() {
_wantMore = true; _wantMore = true;
_explain = false; _explain = false;
_snapshot = false; _snapshot = false;
_returnKey = false; _returnKey = false;
_showDiskLoc = false; _showDiskLoc = false;
_maxScan = 0; _maxScan = 0;
} }
skipping to change at line 217 skipping to change at line 219
uassert( 12001 , "E12001 can't sort with $snapshot", _order .isEmpty() ); uassert( 12001 , "E12001 can't sort with $snapshot", _order .isEmpty() );
uassert( 12002 , "E12002 can't use hint with $snapshot", _h int.isEmpty() ); uassert( 12002 , "E12002 can't use hint with $snapshot", _h int.isEmpty() );
} }
} }
void initFields( const BSONObj& fields ) { void initFields( const BSONObj& fields ) {
if ( fields.isEmpty() ) if ( fields.isEmpty() )
return; return;
_fields.reset( new Projection() ); _fields.reset( new Projection() );
_fields->init( fields ); _fields->init( fields.getOwned() );
} }
const char * const _ns; const char * const _ns;
const int _ntoskip; const int _ntoskip;
int _ntoreturn; int _ntoreturn;
BSONObj _filter; BSONObj _filter;
BSONObj _order; BSONObj _order;
const int _options; const int _options;
shared_ptr< Projection > _fields; shared_ptr< Projection > _fields;
bool _wantMore; bool _wantMore;
skipping to change at line 261 skipping to change at line 263
/** An interval defined between 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 when the interval can contain one or more values.
bool strictValid() const { * NOTE May also return true in certain 'empty' discrete cases like
x > false && x < true.
*/
bool isStrictValid() const {
int cmp = _lower._bound.woCompare( _upper._bound, false ); int cmp = _lower._bound.woCompare( _upper._bound, false );
return ( cmp < 0 || ( cmp == 0 && _lower._inclusive && _upper._ inclusive ) ); return ( cmp < 0 || ( cmp == 0 && _lower._inclusive && _upper._ inclusive ) );
} }
/** @return true iff the interval is an equality constraint. */ /** @return true if the interval is an equality constraint. */
bool equality() const; bool equality() const;
mutable int _cachedEquality; mutable int _cachedEquality;
string toString() const; string toString() const;
}; };
/** /**
* An ordered list of FieldIntervals expressing constraints on valid * An ordered list of FieldIntervals expressing constraints on valid
* BSONElement values for a field. * BSONElement values for a field.
*/ */
class FieldRange { class FieldRange {
public: public:
FieldRange( const BSONElement &e , bool singleKey , bool isNot=fals /**
e , bool optimize=true ); * Creates a FieldRange representing a superset of the BSONElement
values matching a query
* expression element.
* @param e - The query expression element.
* @param isNot - Indicates that 'e' appears within a query $not cl
ause and its matching
* semantics are inverted.
* @param optimize - If true, the range may be bracketed by 'e''s d
ata type.
* TODO It is unclear why 'optimize' is optional, see SERVER-51
65.
*/
FieldRange( const BSONElement &e , bool isNot, bool optimize );
/** @return Range intersection with 'other'. */ /**
const FieldRange &operator&=( const FieldRange &other ); * @return Range intersection with 'other'.
* @param singleKey - Indicate whether intersection will be perform
ed in a single value or
* multi value context.
*/
const FieldRange &intersect( const FieldRange &other, bool singleKe
y );
/** @return Range union with 'other'. */ /** @return Range union with 'other'. */
const FieldRange &operator|=( const FieldRange &other ); const FieldRange &operator|=( const FieldRange &other );
/** @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.
skipping to change at line 310 skipping to change at line 328
/** @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 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 * @return true in many cases when this FieldRange represents the e
te set of BSONElements, xact set of BSONElement
* all of which will be matched by the query BSONElement that gener * values matching the query expression element used to construct t
ated this FieldRange. he FieldRange. This
* This attribute is used to implement higher level optimizations a * attribute is used to implement higher level optimizations and is
nd is computed with a computed with a simple
* simple implementation that identifies common (but not all) cases * implementation that identifies common (but not all) cases of thi
satisfying the stated s property and may return
* properties. * false negatives.
*/ */
bool simpleFiniteSet() const { return _simpleFiniteSet; } bool mustBeExactMatchRepresentation() const { return _exactMatchRep
resentation; }
/* Checks whether this FieldRange is a non-empty union of point-int
ervals.
* Examples:
* FieldRange( { a:3 } ), isPointIntervalSet() -> true
* FieldRange( { a:{ $in:[ 1, 2 ] } } ), isPointIntervalSet() -> t
rue
* FieldRange( { a:{ $gt:5 } } ), isPointIntervalSet() -> false
* FieldRange( {} ), isPointIntervalSet() -> false
*/
bool isPointIntervalSet() const;
/** 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 nst FieldRange &other, void finishOperation( const vector<FieldInterval> &newIntervals, co nst FieldRange &other,
bool simpleFiniteSet ); bool exactMatchRepresentation );
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 _exactMatchRepresentation;
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 363 skipping to change at line 388
class QueryPattern; class QueryPattern;
/** /**
* A set of FieldRanges determined from constraints on the fields of a query, * A set of FieldRanges determined from constraints on the fields of a query,
* that may be used to determine index bounds. * that may be used to determine index bounds.
*/ */
class FieldRangeSet { class FieldRangeSet {
public: public:
friend class OrRangeGenerator; friend class OrRangeGenerator;
friend class FieldRangeVector; friend class FieldRangeVector;
FieldRangeSet( const char *ns, const BSONObj &query , bool singleKe /**
y , bool optimize=true ); * Creates a FieldRangeSet representing a superset of the documents
matching a query.
* @param ns - The query's namespace.
* @param query - The query.
* @param singleKey - Indicates that document fields contain single
values (there are no
* multiply valued fields).
* @param optimize - If true, each field's value range may be brack
eted by data type.
* TODO It is unclear why 'optimize' is optional, see SERVER-51
65.
*/
FieldRangeSet( const char *ns, const BSONObj &query , bool singleKe
y , bool optimize );
/** @return range for the given field. */ /** @return range for the given field. */
const FieldRange &range( const char *fieldName ) const; const FieldRange &range( const char *fieldName ) const;
/** @return range for the given field. */ /** @return range for the given field. Public for testing. */
FieldRange &range( const char *fieldName ); FieldRange &range( const char *fieldName );
/** @return the number of non universal ranges. */ /** @return the number of non universal ranges. */
int numNonUniversalRanges() const; int numNonUniversalRanges() const;
/** @return the field ranges comprising this set. */ /** @return the field ranges comprising this set. */
const map<string,FieldRange> &ranges() const { return _ranges; } const map<string,FieldRange> &ranges() const { return _ranges; }
/** /**
* @return true if a match could be possible on every field. Genera lly this * @return true if a match could be possible on every field. Genera lly this
* 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 * @return true in many cases when this FieldRangeSet represents th
inite set of BSONObjs, e exact set of BSONObjs
* all of which will be matched by the query BSONObj that generated * matching the query expression used to construct the FieldRangeSe
this FieldRangeSet. t. This attribute is
* This attribute is used to implement higher level optimizations a * used to implement higher level optimizations and is computed wit
nd is computed with a h a simple implementation
* simple implementation that identifies common (but not all) cases * that identifies common (but not all) cases of this property and
satisfying the stated may return false
* properties. * negatives.
*/ */
bool simpleFiniteSet() const { return _simpleFiniteSet; } bool mustBeExactMatchRepresentation() const { return _exactMatchRep
resentation; }
/* Checks whether this FieldRangeSet is a non-empty union of point-
intervals
* on a given field.
* Examples:
* FieldRangeSet({a : 3}), isPointIntervalSet("a") -> true
* FieldRangeSet({a : {$in : [1 , 2]}}), isPointIntervalSet("a") -
> true
* FieldRangeSet({}), isPointIntervalSet("a") -> false
* FieldRangeSet({b : 1}), isPointIntervalSet("a") -> false
*
* Used in determining "suitability" for hashedindexes, and also in
* sharding for determining the relevant shards for a query.
*
* TODO: move this into FieldRange instead of FieldRangeSet
*/
bool isPointIntervalSet( const string& fieldname ) const;
const char *ns() const { return _ns.c_str(); } 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;
skipping to change at line 436 skipping to change at line 485
BoundList indexBounds( const BSONObj &keyPattern, int direction ) c onst; BoundList indexBounds( const BSONObj &keyPattern, int direction ) c onst;
/** /**
* @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;
/**
* @return A new FieldRangeSet based on this FieldRangeSet, but wit
h all field names
* prefixed by the specified @param prefix field name.
*/
FieldRangeSet* prefixed( const string& prefix ) 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; string toString() const;
private: private:
/**
* Private constructor for implementation specific delegate objects
.
* @param boundElemMatch - If false, FieldRanges will not be comput
ed for $elemMatch
* expressions.
*/
FieldRangeSet( const char* ns, const BSONObj& query, bool singleKey
, bool optimize,
bool boundElemMatch );
/** Initializer shared by the constructors. */
void init( bool optimize );
void appendQueries( const FieldRangeSet &other ); void appendQueries( const FieldRangeSet &other );
void makeEmpty(); void makeEmpty();
void processQueryField( const BSONElement &e, bool optimize );
void processOpElement( const char *fieldName, const BSONElement &f, /**
bool isNot, bool optimize ); * Query parsing routines.
* TODO integrate these with an external query parser shared by the
matcher. SERVER-1009
*/
void handleMatchField( const BSONElement& matchElement, bool optimi
ze );
void handleOp( const char* matchFieldName, const BSONElement& op, b
ool isNot,
bool optimize );
void handleNotOp( const char* matchFieldName, const BSONElement& no
tOp, bool optimize );
void handleElemMatch( const char* matchFieldName, const BSONElement
& elemMatch, bool isNot,
bool optimize );
/** Must be called when a match element is skipped or modified to g enerate a FieldRange. */ /** Must be called when a match element is skipped or modified to g enerate a FieldRange. */
void adjustMatchField(); void adjustMatchField();
void intersectMatchField( const char *fieldName, const BSONElement &matchElement, void intersectMatchField( const char *fieldName, const BSONElement &matchElement,
bool isNot, bool optimize ); bool isNot, bool optimize );
static FieldRange *__singleKeyUniversalRange; static FieldRange *__universalRange;
static FieldRange *__multiKeyUniversalRange;
const FieldRange &universalRange() const; const FieldRange &universalRange() const;
map<string,FieldRange> _ranges; map<string,FieldRange> _ranges;
string _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; bool _exactMatchRepresentation;
bool _boundElemMatch;
}; };
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 595 skipping to change at line 671
/** /**
* 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:
/** /**
* @param v - a FieldRangeVector representing matching keys. * @param v - a FieldRangeVector representing matching keys.
* @param singleIntervalLimit - The maximum number of keys to match a single (compound) * @param singleIntervalLimit - The maximum number of keys to match a single (compound)
* interval before advancing to the next interval. Limit check * interval before advancing to the next interval. Limit check
ing is disabled if 0 and ing is disabled if 0.
* must be disabled if v contains FieldIntervals that are not e
quality().
*/ */
FieldRangeVectorIterator( const FieldRangeVector &v, int singleInte rvalLimit ); FieldRangeVectorIterator( const FieldRangeVector &v, int singleInte rvalLimit );
/** /**
* @return Suggested advance method through an ordered list of keys with lookup support * @return Suggested advance method through an ordered list of keys with lookup support
* (generally a btree). * (generally a btree).
* -2 Iteration is complete, no need to advance further. * -2 Iteration is complete, no need to advance further.
* -1 Advance to the next ordered key, without skipping. * -1 Advance to the next ordered key, without skipping.
* >=0 Skip parameter, let's call it 'r'. If after() is true, ski p past the key prefix * >=0 Skip parameter, let's call it 'r'. If after() is true, ski p past the key prefix
* comprised of the first r elements of curr. For example, if curr is {a:1,b:1}, the * comprised of the first r elements of curr. For example, if curr is {a:1,b:1}, the
skipping to change at line 642 skipping to change at line 717
void inc( int i ); void inc( int i );
void setZeroes( int i ); void setZeroes( int i );
void setUnknowns( int i ); void setUnknowns( int i );
void incSingleIntervalCount() { void incSingleIntervalCount() {
if ( isTrackingIntervalCounts() ) ++_singleIntervalCount; if ( isTrackingIntervalCounts() ) ++_singleIntervalCount;
} }
bool hasSingleIntervalCountReachedLimit() const { bool hasSingleIntervalCountReachedLimit() const {
return isTrackingIntervalCounts() && _singleIntervalCount > = _singleIntervalLimit; return isTrackingIntervalCounts() && _singleIntervalCount > = _singleIntervalLimit;
} }
void resetIntervalCount() { _singleIntervalCount = 0; } void resetIntervalCount() { _singleIntervalCount = 0; }
string toString() const;
private: private:
bool isTrackingIntervalCounts() const { return _singleIntervalL imit > 0; } bool isTrackingIntervalCounts() const { return _singleIntervalL imit > 0; }
vector<int> _i; vector<int> _i;
int _singleIntervalCount; int _singleIntervalCount;
int _singleIntervalLimit; int _singleIntervalLimit;
}; };
/** /**
* Helper class for matching a BSONElement with the bounds of a Fie ldInterval. Some * Helper class for matching a BSONElement with the bounds of a Fie ldInterval. Some
* internal comparison results are cached. Public for testing. * internal comparison results are cached. Public for testing.
skipping to change at line 706 skipping to change at line 782
bool reverse, bool first, bool &eqInclu siveUpperBound ); bool reverse, bool first, bool &eqInclu siveUpperBound );
/** Skip to curr / i / nextbounds. */ /** Skip to curr / i / nextbounds. */
int advanceToLowerBound( int i ); int advanceToLowerBound( int i );
/** Skip to curr / i / superlative. */ /** Skip to curr / i / superlative. */
int advancePast( int i ); int advancePast( int i );
/** Skip to curr / i / superlative and reset following interval pos itions. */ /** Skip to curr / i / superlative and reset following interval pos itions. */
int advancePastZeroed( int i ); int advancePastZeroed( int i );
bool hasReachedLimitForLastInterval( int intervalIdx ) const { bool hasReachedLimitForLastInterval( int intervalIdx ) const {
return _i.hasSingleIntervalCountReachedLimit() && ( intervalIdx return
+ 1 == _i.size() ); _i.hasSingleIntervalCountReachedLimit() &&
( intervalIdx + 1 == _endNonUniversalRanges );
} }
/** @return the index of the last non universal range + 1. */
int endNonUniversalRanges() const;
const FieldRangeVector &_v; const FieldRangeVector &_v;
CompoundRangeCounter _i; CompoundRangeCounter _i;
vector<const BSONElement*> _cmp; vector<const BSONElement*> _cmp;
vector<bool> _inc; vector<bool> _inc;
bool _after; bool _after;
int _endNonUniversalRanges;
}; };
/** /**
* 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.
*/ */
class OrRangeGenerator { class OrRangeGenerator {
public: public:
OrRangeGenerator( const char *ns, const BSONObj &query , bool optim ize=true ); OrRangeGenerator( const char *ns, const BSONObj &query , bool optim ize=true );
 End of changes. 25 change blocks. 
47 lines changed or deleted 150 lines changed or added


 queue.h   queue.h 
skipping to change at line 29 skipping to change at line 29
#include "pch.h" #include "pch.h"
#include <limits> #include <limits>
#include <queue> #include <queue>
#include "mongo/util/timer.h" #include "mongo/util/timer.h"
namespace mongo { namespace mongo {
template <typename T>
size_t _getSizeDefault(const T& t) {
return 1;
}
/** /**
* simple blocking queue * Simple blocking queue with optional max size.
* A custom sizing function can optionally be given. By default, size
is calculated as
* _queue.size().
*/ */
template<typename T> template<typename T>
class BlockingQueue : boost::noncopyable { class BlockingQueue : boost::noncopyable {
typedef size_t (*getSizeFunc)(const T& t);
public: public:
BlockingQueue() : BlockingQueue() :
_lock("BlockingQueue"), _lock("BlockingQueue"),
_size(std::numeric_limits<std::size_t>::max()) { } _maxSize(std::numeric_limits<std::size_t>::max()),
_currentSize(0),
_getSize(&_getSizeDefault) {}
BlockingQueue(size_t size) : BlockingQueue(size_t size) :
_lock("BlockingQueue(bounded)"), _lock("BlockingQueue(bounded)"),
_size(size) { } _maxSize(size),
_currentSize(0),
_getSize(&_getSizeDefault) {}
BlockingQueue(size_t size, getSizeFunc f) :
_lock("BlockingQueue(custom size)"),
_maxSize(size),
_currentSize(0),
_getSize(f) {}
void push(T const& t) { void push(T const& t) {
scoped_lock l( _lock ); scoped_lock l( _lock );
while (_queue.size() >= _size) { size_t tSize = _getSize(t);
while (_queue.size()+tSize >= _maxSize) {
_cvNoLongerFull.wait( l.boost() ); _cvNoLongerFull.wait( l.boost() );
} }
_queue.push( t ); _queue.push( t );
_currentSize += tSize;
_cvNoLongerEmpty.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 _currentSize;
}
void clear() {
scoped_lock l(_lock);
_queue = std::queue<T>();
_currentSize = 0;
} }
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();
_currentSize -= _getSize(t);
_cvNoLongerFull.notify_one(); _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() )
_cvNoLongerEmpty.wait( l.boost() ); _cvNoLongerEmpty.wait( l.boost() );
T t = _queue.front(); T t = _queue.front();
_queue.pop(); _queue.pop();
_currentSize -= _getSize(t);
_cvNoLongerFull.notify_one(); _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
*/ */
skipping to change at line 107 skipping to change at line 134
xt.sec += maxSecondsToWait; xt.sec += maxSecondsToWait;
scoped_lock l( _lock ); scoped_lock l( _lock );
while( _queue.empty() ) { while( _queue.empty() ) {
if ( ! _cvNoLongerEmpty.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();
_currentSize -= _getSize(t);
_cvNoLongerFull.notify_one(); _cvNoLongerFull.notify_one();
return true; return true;
} }
// Obviously, this should only be used when you have
// only one consumer
bool blockingPeek(T& t, int maxSecondsToWait) {
Timer timer;
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += maxSecondsToWait;
scoped_lock l( _lock );
while( _queue.empty() ) {
if ( ! _cvNoLongerEmpty.timed_wait( l.boost() , xt ) )
return false;
}
t = _queue.front();
return true;
}
// Obviously, this should only be used when you have
// only one consumer
bool peek(T& t) {
scoped_lock l( _lock );
if (_queue.empty()) {
return false;
}
t = _queue.front();
return true;
}
private: private:
mutable mongo::mutex _lock; mutable mongo::mutex _lock;
std::queue<T> _queue; std::queue<T> _queue;
size_t _size; const size_t _maxSize;
size_t _currentSize;
getSizeFunc _getSize;
boost::condition _cvNoLongerFull; boost::condition _cvNoLongerFull;
boost::condition _cvNoLongerEmpty; boost::condition _cvNoLongerEmpty;
}; };
} }
 End of changes. 13 change blocks. 
6 lines changed or deleted 70 lines changed or added


 race.h   race.h 
#pragma once #pragma once
#include "../goodies.h" // printStackTrace #include "../goodies.h" // printStackTrace
#include "mutexdebugger.h" #include "mutexdebugger.h"
#include "mongo/util/stacktrace.h"
namespace mongo { namespace mongo {
namespace race { namespace race {
#ifdef _WIN32 #ifdef _WIN32
typedef unsigned threadId_t; typedef unsigned threadId_t;
#else #else
typedef pthread_t threadId_t; typedef pthread_t threadId_t;
#endif #endif
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 replutil.h   replutil.h 
skipping to change at line 25 skipping to change at line 25
*/ */
#pragma once #pragma once
#include "db.h" #include "db.h"
#include "dbhelpers.h" #include "dbhelpers.h"
#include "json.h" #include "json.h"
#include "repl.h" #include "repl.h"
#include "cmdline.h" #include "cmdline.h"
#include "repl/rs.h" #include "repl/rs.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 86 skipping to change at line 85
verify( 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 */ class ParsedQuery;
inline void replVerifyReadsOk(ParsedQuery* pq = 0) {
if( replSet ) { void replVerifyReadsOk(const ParsedQuery* pq = 0);
/* todo: speed up the secondary case. as written here there ar
e 2 mutex entries, it can b 1. */
if( isMaster() ) return;
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() );
}
else {
notMasterUnless(isMaster() || (!pq || pq->hasOption(QueryOption
_SlaveOk)) || replSettings.slave == SimpleSlave );
}
}
} // namespace mongo } // namespace mongo
 End of changes. 2 change blocks. 
17 lines changed or deleted 3 lines changed or added


 rs.h   rs.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 "../../util/concurrency/list.h" #include "mongo/db/commands.h"
#include "../../util/concurrency/value.h" #include "mongo/db/oplog.h"
#include "../../util/concurrency/msg.h" #include "mongo/db/oplogreader.h"
#include "../../util/net/hostandport.h" #include "mongo/db/repl/rs_config.h"
#include "../commands.h" #include "mongo/db/repl/rs_exception.h"
#include "../oplog.h" #include "mongo/db/repl/rs_member.h"
#include "../oplogreader.h" #include "mongo/db/repl/rs_optime.h"
#include "rs_exception.h" #include "mongo/db/repl/rs_sync.h"
#include "rs_optime.h" #include "mongo/util/concurrency/list.h"
#include "rs_member.h" #include "mongo/util/concurrency/msg.h"
#include "rs_config.h" #include "mongo/util/concurrency/thread_pool.h"
#include "mongo/util/concurrency/value.h"
#include "mongo/util/net/hostandport.h"
/** /**
* Order of Events * Order of Events
* *
* On startup, if the --replSet option is present, startReplSets is called. * On startup, if the --replSet option is present, startReplSets is called.
* startReplSets forks off a new thread for replica set activities. It cre ates * startReplSets forks off a new thread for replica set activities. It cre ates
* the global theReplSet variable and calls go() on it. * the global theReplSet variable and calls go() on it.
* *
* theReplSet's constructor changes the replica set's state to RS_STARTUP, * theReplSet's constructor changes the replica set's state to RS_STARTUP,
* starts the replica set manager, and loads the config (if the replica set * starts the replica set manager, and loads the config (if the replica set
skipping to change at line 84 skipping to change at line 86
bool potentiallyHot() const { return _config.potentiallyHot(); } // not arbiter, not priority 0 bool potentiallyHot() const { return _config.potentiallyHot(); } // not arbiter, not priority 0
void summarizeMember(stringstream& s) const; void summarizeMember(stringstream& s) const;
private: private:
friend class ReplSetImpl; friend class ReplSetImpl;
ReplSetConfig::MemberCfg _config; ReplSetConfig::MemberCfg _config;
const HostAndPort _h; const HostAndPort _h;
HeartbeatInfo _hbinfo; HeartbeatInfo _hbinfo;
}; };
namespace replset {
/**
* "Normal" replica set syncing
*/
class SyncTail : public Sync {
public:
virtual ~SyncTail() {}
SyncTail(const string& host) : Sync(host) {}
virtual bool syncApply(const BSONObj &o);
};
/**
* Initial clone and sync
*/
class InitialSync : public SyncTail {
public:
InitialSync(const string& host) : SyncTail(host) {}
virtual ~InitialSync() {}
bool oplogApplication(OplogReader& r, const Member* source, con
st OpTime& applyGTE, const OpTime& minValid);
virtual void applyOp(const BSONObj& o, const OpTime& minvalid);
};
// TODO: move hbmsg into an error-keeping class (SERVER-4444)
void sethbmsg(const string& s, const int logLevel=0);
} // namespace replset
class Manager : public task::Server { class Manager : public task::Server {
ReplSetImpl *rs; ReplSetImpl *rs;
bool busyWithElectSelf; bool busyWithElectSelf;
int _primary; int _primary;
/** @param two - if true two primaries were seen. this can happen transiently, in addition to our /** @param two - if true two primaries were seen. this can happen transiently, in addition to our
polling being only occasional. in this case null is returned, but the caller should polling being only occasional. in this case null is returned, but the caller should
not assume primary itself in that situation. not assume primary itself in that situation.
*/ */
const Member* findOtherPrimary(bool& two); const Member* findOtherPrimary(bool& two);
skipping to change at line 313 skipping to change at line 288
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);
verify( !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() ) verify(!sp.state.primary());
sp.state = MemberState::RS_RECOVERING;
sp.primary = remote; sp.primary = remote;
} }
StateBox() : m("StateBox") { } StateBox() : m("StateBox") { }
private: private:
RWLock m; RWLock m;
SP sp; SP sp;
}; };
void parseReplsetCmdLine(string cfgString, string& setname, vector<Host AndPort>& seeds, set<HostAndPort>& seedSet ); void parseReplsetCmdLine(string cfgString, string& setname, vector<Host AndPort>& seeds, set<HostAndPort>& seedSet );
skipping to change at line 359 skipping to change at line 333
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); bool forceSyncFrom(const string& host, string& errmsg, BSONObjBuild er& result);
/**
* Find the closest member (using ping time) with a higher latest o
ptime.
*/
Member* getMemberToSyncTo();
void veto(const string& host, unsigned secs=10);
bool gotForceSync();
void goStale(const Member* m, const BSONObj& o);
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);
bool _freeze(int secs); bool _freeze(int secs);
private: private:
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.
*/
Member* getMemberToSyncTo();
void veto(const string& host, unsigned secs=10);
Member* _currentSyncTarget;
Member* _forceSyncTarget; 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"
skipping to change at line 455 skipping to change at line 431
const ReplSetConfig& config() { return *_cfg; } const ReplSetConfig& config() { return *_cfg; }
string name() const { return _name; } /* @return replica set's logi cal name */ string name() const { return _name; } /* @return replica set's logi cal name */
MemberState state() const { return box.getState(); } MemberState state() const { return box.getState(); }
void _fatal(); void _fatal();
void _getOplogDiagsAsHtml(unsigned server_id, stringstream& ss) con st; void _getOplogDiagsAsHtml(unsigned server_id, stringstream& ss) con st;
void _summarizeAsHtml(stringstream&) const; void _summarizeAsHtml(stringstream&) const;
void _summarizeStatus(BSONObjBuilder&) const; // for replSetGetStat us command void _summarizeStatus(BSONObjBuilder&) const; // for replSetGetStat us command
/* throws exception if a problem initializing. */ /* throws exception if a problem initializing. */
ReplSetImpl(ReplSetCmdline&); ReplSetImpl(ReplSetCmdline&);
// used for testing
ReplSetImpl();
/* call afer constructing to start - returns fairly quickly after l aunching its threads */ /* call afer constructing to start - returns fairly quickly after l aunching its threads */
void _go(); void _go();
private: private:
string _name; string _name;
const vector<HostAndPort> *_seeds; const vector<HostAndPort> *_seeds;
ReplSetConfig *_cfg; ReplSetConfig *_cfg;
/** /**
skipping to change at line 477 skipping to change at line 455
*/ */
bool _loadConfigFinish(vector<ReplSetConfig>& v); bool _loadConfigFinish(vector<ReplSetConfig>& v);
/** /**
* Gather all possible configs (from command line seeds, our own co nfig * Gather all possible configs (from command line seeds, our own co nfig
* doc, and any hosts listed therein) and try to initiate from the most * doc, and any hosts listed therein) and try to initiate from the most
* recent config we find. * recent config we find.
*/ */
void loadConfig(); void loadConfig();
list<HostAndPort> memberHostnames() const; list<HostAndPort> memberHostnames() const;
const ReplSetConfig::MemberCfg& myConfig() const { return _config; }
bool iAmArbiterOnly() const { return myConfig().arbiterOnly; } bool iAmArbiterOnly() const { return myConfig().arbiterOnly; }
bool iAmPotentiallyHot() const { bool iAmPotentiallyHot() const {
return myConfig().potentiallyHot() && // not an arbiter return myConfig().potentiallyHot() && // not an arbiter
elect.steppedDown <= time(0) && // not stepped down/frozen elect.steppedDown <= time(0) && // not stepped down/frozen
state() == MemberState::RS_SECONDARY; // not stale state() == MemberState::RS_SECONDARY; // not stale
} }
protected: protected:
Member *_self; Member *_self;
bool _buildIndexes; // = _self->config().buildIndexes bool _buildIndexes; // = _self->config().buildIndexes
void setSelfTo(Member *); // use this as it sets buildIndexes var void setSelfTo(Member *); // use this as it sets buildIndexes var
skipping to change at line 522 skipping to change at line 499
void getTargets(list<Target>&, int &configVersion); void getTargets(list<Target>&, int &configVersion);
void startThreads(); void startThreads();
friend class FeedbackThread; friend class FeedbackThread;
friend class CmdReplSetElect; friend class CmdReplSetElect;
friend class Member; friend class Member;
friend class Manager; friend class Manager;
friend class GhostSync; friend class GhostSync;
friend class Consensus; friend class Consensus;
private: private:
bool initialSyncOplogApplication(const OpTime& applyGTE, const OpTi bool _syncDoInitialSync_clone( const char *master, const list<strin
me& minValid); g>& dbs , bool dataPass );
bool _syncDoInitialSync_applyToHead( replset::InitialSync& init, Op
logReader* r ,
const Member* source, const BS
ONObj& lastOp,
BSONObj& minValidOut);
void _syncDoInitialSync(); void _syncDoInitialSync();
void syncDoInitialSync(); void syncDoInitialSync();
void _syncThread(); void _syncThread();
bool tryToGoLiveAsASecondary(OpTime&); // readlocks
void syncTail(); void syncTail();
unsigned _syncRollback(OplogReader& r); unsigned _syncRollback(OplogReader& r);
void syncRollback(OplogReader& r);
void syncFixUp(HowToFixUp& h, OplogReader& r); void syncFixUp(HowToFixUp& h, OplogReader& r);
// get an oplog reader for a server with an oplog entry timestamp g
reater
// than or equal to minTS, if set.
Member* _getOplogReader(OplogReader& r, const OpTime& minTS);
// check lastOpTimeWritten against the remote's earliest op, fillin
g in
// remoteOldestOp.
bool _isStale(OplogReader& r, const OpTime& minTS, BSONObj& remoteO
ldestOp);
// keep a list of hosts that we've tried recently that didn't work // keep a list of hosts that we've tried recently that didn't work
map<string,time_t> _veto; map<string,time_t> _veto;
// persistent pool of worker threads for writing ops to the databas
es
threadpool::ThreadPool _writerPool;
// persistent pool of worker threads for prefetching
threadpool::ThreadPool _prefetcherPool;
public: public:
static const int replWriterThreadCount;
static const int replPrefetcherThreadCount;
threadpool::ThreadPool& getPrefetchPool() { return _prefetcherPool;
}
threadpool::ThreadPool& getWriterPool() { return _writerPool; }
const ReplSetConfig::MemberCfg& myConfig() const { return _config;
}
bool tryToGoLiveAsASecondary(OpTime&); // readlocks
void syncRollback(OplogReader& r);
void syncThread(); void syncThread();
const OpTime lastOtherOpTime() const; const OpTime lastOtherOpTime() const;
}; };
class ReplSet : public ReplSetImpl { class ReplSet : public ReplSetImpl {
public: public:
ReplSet(ReplSetCmdline& replSetCmdline) : ReplSetImpl(replSetCmdlin ReplSet();
e) { } ReplSet(ReplSetCmdline& replSetCmdline);
virtual ~ReplSet() {}
// 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() {
verify( _self ); verify( _self );
return _self->fullName(); return _self->fullName();
} }
bool buildIndexes() const { return _buildIndexes; } virtual 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 launching its threads */
void go() { _go(); } void go() { _go(); }
void shutdown();
void fatal() { _fatal(); } void fatal() { _fatal(); }
bool isPrimary() { return box.getState().primary(); } virtual bool isPrimary() { return box.getState().primary(); }
bool isSecondary() { return box.getState().secondary(); } virtual bool isSecondary() { return box.getState().secondary(); }
MemberState state() const { return ReplSetImpl::state(); } MemberState state() const { return ReplSetImpl::state(); }
string name() const { return ReplSetImpl::name(); } string name() const { return ReplSetImpl::name(); }
const ReplSetConfig& config() { return ReplSetImpl::config(); } virtual const ReplSetConfig& config() { return ReplSetImpl::config( ); }
void getOplogDiagsAsHtml(unsigned server_id, stringstream& ss) cons t { _getOplogDiagsAsHtml(server_id,ss); } void getOplogDiagsAsHtml(unsigned server_id, stringstream& ss) cons t { _getOplogDiagsAsHtml(server_id,ss); }
void summarizeAsHtml(stringstream& ss) const { _summarizeAsHtml(ss) ; } void summarizeAsHtml(stringstream& ss) const { _summarizeAsHtml(ss) ; }
void summarizeStatus(BSONObjBuilder& b) const { _summarizeStatus(b ); } void summarizeStatus(BSONObjBuilder& b) const { _summarizeStatus(b ); }
void fillIsMaster(BSONObjBuilder& b) { _fillIsMaster(b); } void fillIsMaster(BSONObjBuilder& b) { _fillIsMaster(b); }
threadpool::ThreadPool& getPrefetchPool() { return ReplSetImpl::get
PrefetchPool(); }
threadpool::ThreadPool& getWriterPool() { return ReplSetImpl::getWr
iterPool(); }
/** /**
* We have a new config (reconfig) - apply it. * We have a new config (reconfig) - apply it.
* @param comment write a no-op comment to the oplog about it. onl y * @param comment write a no-op comment to the oplog about it. onl y
* makes sense if one is primary and initiating the reconf. * makes sense if one is primary and initiating the reconf.
* *
* The slaves are updated when they get a heartbeat indicating the new * The slaves are updated when they get a heartbeat indicating the new
* config. The comment is a no-op. * config. The comment is a no-op.
*/ */
void haveNewConfig(ReplSetConfig& c, bool comment); void haveNewConfig(ReplSetConfig& c, bool comment);
 End of changes. 20 change blocks. 
71 lines changed or deleted 61 lines changed or added


 rs_config.h   rs_config.h 
skipping to change at line 23 skipping to change at line 23
* 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 "../../util/net/hostandport.h" #include "mongo/db/repl/health.h"
#include "../../util/concurrency/race.h" #include "mongo/util/concurrency/list.h"
#include "health.h" #include "mongo/util/concurrency/race.h"
#include "mongo/util/net/hostandport.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. // Protects _groups.
skipping to change at line 106 skipping to change at line 107
map<string,string>::const_iterator rit = r.tags.fin d((*lit).first); map<string,string>::const_iterator rit = r.tags.fin d((*lit).first);
if (rit == r.tags.end() || (*lit).second != (*rit). second) { if (rit == r.tags.end() || (*lit).second != (*rit). second) {
return false; return false;
} }
} }
} }
return _id==r._id && votes == r.votes && h == r.h && priori ty == r.priority && return _id==r._id && votes == r.votes && h == r.h && priori ty == r.priority &&
arbiterOnly == r.arbiterOnly && slaveDelay == r.slav eDelay && hidden == r.hidden && arbiterOnly == r.arbiterOnly && slaveDelay == r.slav eDelay && hidden == r.hidden &&
buildIndexes == buildIndexes; buildIndexes == r.buildIndexes;
} }
bool operator!=(const MemberCfg& r) const { return !(*this == r ); } bool operator!=(const MemberCfg& r) const { return !(*this == r ); }
}; };
vector<MemberCfg> members; vector<MemberCfg> members;
string _id; string _id;
int version; int version;
HealthOptions ho; HealthOptions ho;
string md5; string md5;
BSONObj getLastErrorDefaults; BSONObj getLastErrorDefaults;
 End of changes. 2 change blocks. 
4 lines changed or deleted 5 lines changed or added


 scanandorder.h   scanandorder.h 
skipping to change at line 56 skipping to change at line 56
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.
*/ */
inline void fillQueryResultFromObj(BufBuilder& bb, const Projection *fi lter, const BSONObj& js, inline void fillQueryResultFromObj(BufBuilder& bb, const Projection *fi lter, const BSONObj& js,
const MatchDetails* details = NULL,
const DiskLoc* loc=NULL) { const DiskLoc* loc=NULL) {
if ( filter ) { if ( filter ) {
BSONObjBuilder b( bb ); BSONObjBuilder b( bb );
filter->transform( js , b ); filter->transform( js , b, details );
if (loc) if (loc)
b.append("$diskLoc", loc->toBSONObj()); b.append("$diskLoc", loc->toBSONObj());
b.done(); b.done();
} }
else if (loc) { else if (loc) {
BSONObjBuilder b( bb ); BSONObjBuilder b( bb );
b.appendElements(js); b.appendElements(js);
b.append("$diskLoc", loc->toBSONObj()); b.append("$diskLoc", loc->toBSONObj());
b.done(); b.done();
} }
skipping to change at line 96 skipping to change at line 97
int size() const { return _best.size(); } int size() const { return _best.size(); }
/** /**
* @throw ScanAndOrderMemoryLimitExceededAssertionCode if adding wo uld grow memory usage * @throw ScanAndOrderMemoryLimitExceededAssertionCode if adding wo uld grow memory usage
* to ScanAndOrder::MaxScanAndOrderBytes. * to ScanAndOrder::MaxScanAndOrderBytes.
*/ */
void add(const BSONObj &o, const DiskLoc* loc); void add(const BSONObj &o, const DiskLoc* loc);
/* scanning complete. stick the query result in b for n objects. */ /* scanning complete. stick the query result in b for n objects. */
void fill(BufBuilder& b, const Projection *filter, int& nout ) cons t; void fill(BufBuilder& b, const ParsedQuery *query, int& nout) const ;
/** Functions for testing. */ /** Functions for testing. */
protected: protected:
unsigned approxSize() const { return _approxSize; } unsigned approxSize() const { return _approxSize; }
private: private:
void _add(const BSONObj& k, const BSONObj& o, const DiskLoc* loc); void _add(const BSONObj& k, const BSONObj& o, const DiskLoc* loc);
 End of changes. 3 change blocks. 
2 lines changed or deleted 3 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 "mongo/db/authlevel.h" #include <string>
#include "mongo/db/nonce.h" #include "mongo/db/nonce.h"
#include "mongo/db/security_common.h" #include "mongo/db/security_common.h"
#include "mongo/client/authentication_table.h"
#include "mongo/client/authlevel.h"
#include "mongo/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 object */ /** An AuthenticationInfo object is present within every mongo::Client object */
class AuthenticationInfo : boost::noncopyable { class AuthenticationInfo : boost::noncopyable {
bool _isLocalHost; bool _isLocalHost;
bool _isLocalHostAndLocalHostIsAuthorizedForAll; bool _isLocalHostAndLocalHostIsAuthorizedForAll;
public: public:
void startRequest(); // need to call at the beginning of each reque st void startRequest(); // need to call at the beginning of each reque st
void setIsALocalHostConnectionWithSpecialAuthPowers(); // called, i f localhost, when conneciton established. void setIsALocalHostConnectionWithSpecialAuthPowers(); // called, i f localhost, when conneciton established.
AuthenticationInfo() { AuthenticationInfo() {
_isLocalHost = false; _isLocalHost = false;
_isLocalHostAndLocalHostIsAuthorizedForAll = false; _isLocalHostAndLocalHostIsAuthorizedForAll = false;
_usingTempAuth = false;
} }
~AuthenticationInfo() {} ~AuthenticationInfo() {}
bool isLocalHost() const { return _isLocalHost; } // why are you ca lling this? makes no sense to be externalized 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 std::string& dbname ) {
scoped_spinlock lk(_lock); scoped_spinlock lk(_lock);
_dbs.erase(dbname); _authTable.removeAuth( dbname );
} }
void authorize(const string& dbname , const string& user ) { void authorize(const std::string& dbname , const std::string& user ) {
scoped_spinlock lk(_lock); scoped_spinlock lk(_lock);
_dbs[dbname].level = Auth::WRITE; _authTable.addAuth( dbname, user, Auth::WRITE );
_dbs[dbname].user = user;
} }
void authorizeReadOnly(const string& dbname , const string& user ) { void authorizeReadOnly(const std::string& dbname , const std::strin g& user ) {
scoped_spinlock lk(_lock); scoped_spinlock lk(_lock);
_dbs[dbname].level = Auth::READ; _authTable.addAuth( dbname, user, Auth::READ );
_dbs[dbname].user = user;
} }
// -- accessors --- // -- accessors ---
bool isAuthorized(const string& dbname) const { bool isAuthorized(const std::string& dbname) const {
return _isAuthorized( dbname, Auth::WRITE ); return _isAuthorized( dbname, Auth::WRITE );
} }
bool isAuthorizedReads(const string& dbname) const { bool isAuthorizedReads(const std::string& dbname) const {
return _isAuthorized( dbname, Auth::READ ); return _isAuthorized( dbname, Auth::READ );
} }
/** /**
* @param lockType - this is from dbmutex 1 is write, 0 is read * @param lockType - this is from dbmutex 1 is write, 0 is read
*/ */
bool isAuthorizedForLock(const string& dbname, int lockType ) const { bool isAuthorizedForLock(const std::string& dbname, int lockType ) const {
return _isAuthorized( dbname , lockType > 0 ? Auth::WRITE : Aut h::READ ); return _isAuthorized( dbname , lockType > 0 ? Auth::WRITE : Aut h::READ );
} }
bool isAuthorizedForLevel( const string& dbname , Auth::Level level ) const { bool isAuthorizedForLevel( const std::string& dbname , Auth::Level level ) const {
return _isAuthorized( dbname , level ); return _isAuthorized( dbname , level );
} }
string getUser( const string& dbname ) const; std::string getUser( const std::string& dbname ) const;
void print() const; void print() const;
BSONObj toBSON() const;
void setTemporaryAuthorization( BSONObj& obj );
void clearTemporaryAuthorization();
bool hasTemporaryAuthorization();
// Returns true if this AuthenticationInfo has been auth'd to use t
he internal user
bool usingInternalUser();
const AuthenticationTable getAuthTable() const;
// When TemporaryAuthReleaser goes out of scope it clears the tempo
rary authentication set
// in its AuthenticationInfo object, unless that AuthenticationInfo
already had temporary
// auth set at the time that the TemporaryAuthReleaser was initiali
zed.
class TemporaryAuthReleaser : boost::noncopyable {
public:
TemporaryAuthReleaser ( AuthenticationInfo* ai );
~TemporaryAuthReleaser();
private:
AuthenticationInfo* _ai;
bool _hadTempAuthFromStart;
};
private: private:
void _checkLocalHostSpecialAdmin(); void _checkLocalHostSpecialAdmin();
/** takes a lock */ /** takes a lock */
bool _isAuthorized(const string& dbname, Auth::Level level) const; bool _isAuthorized(const std::string& dbname, Auth::Level level) co nst;
bool _isAuthorizedSingle_inlock(const string& dbname, Auth::Level l // Must be in _lock
evel) const; bool _isAuthorizedSingle_inlock(const std::string& dbname, Auth::Le
vel level) const;
/** cannot call this locked */ /** cannot call this locked */
bool _isAuthorizedSpecialChecks( const string& dbname ) const ; bool _isAuthorizedSpecialChecks( const std::string& dbname ) const
;
// Must be in _lock
void _addTempAuth_inlock( const std::string& dbname, const std::str
ing& user,
Auth::Level level);
private: private:
// while most access to _dbs is from our thread (the TLS thread), c // while most access to _authTable is from our thread (the TLS thre
urrentOp() inspects ad), currentOp()
// it too thus we need this // inspects it too thus we need this.
// This protects _authTable, _tempAuthTable, and _usingTempAuth.
mutable SpinLock _lock; mutable SpinLock _lock;
// todo: caching should not last forever // todo: caching should not last forever
typedef map<string,Auth> MA; AuthenticationTable _authTable;
MA _dbs; // dbname -> auth // when _usingTempAuth is true, this is used for all auth checks in
stead of _authTable
AuthenticationTable _tempAuthTable;
bool _usingTempAuth;
static bool _warned; static bool _warned;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 21 change blocks. 
23 lines changed or deleted 63 lines changed or added


 security_common.h   security_common.h 
skipping to change at line 39 skipping to change at line 39
struct AuthInfo { struct AuthInfo {
AuthInfo() { AuthInfo() {
user = "__system"; user = "__system";
} }
string user; string user;
string pwd; string pwd;
}; };
// --noauth cmd line option // --noauth cmd line option
extern bool noauth; extern bool noauth;
extern AuthInfo internalSecurity; extern AuthInfo internalSecurity; // set at startup and not changed aft er initialization.
/** /**
* This method checks the validity of filename as a security key, hashe s its * This method checks the validity of filename as a security key, hashe s its
* contents, and stores it in the internalSecurity variable. Prints an * contents, and stores it in the internalSecurity variable. Prints an
* error message to the logs if there's an error. * error message to the logs if there's an error.
* @param filename the file containing the key * @param filename the file containing the key
* @return if the key was successfully stored * @return if the key was successfully stored
*/ */
bool setUpSecurityKey(const string& filename); bool setUpSecurityKey(const string& filename);
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 shard.h   shard.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 "mongo/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 52 skipping to change at line 51
: _name(name) , _addr( addr ) , _maxSize( maxSize ) , _isDraini ng( isDraining ) { : _name(name) , _addr( addr ) , _maxSize( maxSize ) , _isDraini ng( isDraining ) {
_setAddr( addr ); _setAddr( addr );
} }
Shard( const string& ident ) { Shard( const string& ident ) {
reset( ident ); reset( ident );
} }
Shard( const Shard& other ) Shard( const Shard& other )
: _name( other._name ) , _addr( other._addr ) , _cs( other._cs ) , : _name( other._name ) , _addr( other._addr ) , _cs( other._cs ) ,
_maxSize( other._maxSize ) , _isDraining( other._isDraining ) _maxSize( other._maxSize ) , _isDraining( other._isDraining )
, _rs( other._rs ) { ,
_tags( other._tags ) {
} }
Shard( const Shard* other ) Shard( const Shard* other )
: _name( other->_name ) , _addr( other->_addr ), _cs( other->_c s ) , : _name( other->_name ) , _addr( other->_addr ), _cs( other->_c s ) ,
_maxSize( other->_maxSize ) , _isDraining( other->_isDraining ) , _rs( other->_rs ) { _maxSize( other->_maxSize ) , _isDraining( other->_isDraining ) {
} }
static Shard make( const string& ident ) { static Shard make( const string& ident ) {
Shard s; Shard s;
s.reset( ident ); s.reset( ident );
return s; return s;
} }
/** /**
* @param ident either name or address * @param ident either name or address
skipping to change at line 129 skipping to change at line 129
bool operator!=( const string& s ) const { bool operator!=( const string& s ) const {
return _name != s && _addr != s; return _name != s && _addr != s;
} }
bool operator<(const Shard& o) const { bool operator<(const Shard& o) const {
return _name < o._name; return _name < o._name;
} }
bool ok() const { return _addr.size() > 0; } bool ok() const { return _addr.size() > 0; }
BSONObj runCommand( const string& db , const string& simple ) const // Set internal to true to run the command with internal authentica
{ tion privileges.
return runCommand( db , BSON( simple << 1 ) ); BSONObj runCommand( const string& db , const string& simple , bool
internal = false ) const {
return runCommand( db , BSON( simple << 1 ) , internal );
} }
BSONObj runCommand( const string& db , const BSONObj& cmd ) const ; BSONObj runCommand( const string& db , const BSONObj& cmd , bool in ternal = false) const ;
ShardStatus getStatus() const ; ShardStatus getStatus() const ;
/** /**
* mostly for replica set * mostly for replica set
* retursn true if node is the shard * retursn true if node is the shard
* of if the replica set contains node * of if the replica set contains node
*/ */
bool containsNode( const string& node ) const; bool containsNode( const string& node ) const;
const set<string>& tags() const { return _tags; }
void addTag( const string& tag ) { _tags.insert( tag ); }
static void getAllShards( vector<Shard>& all ); static void getAllShards( vector<Shard>& all );
static void printShardInfo( ostream& out ); static void printShardInfo( ostream& out );
static Shard lookupRSName( const string& name); static Shard lookupRSName( const string& name);
/** /**
* @parm current - shard where the chunk/database currently lives i n * @parm current - shard where the chunk/database currently lives i n
* @return the currently emptiest shard, if best then current, or E MPTY * @return the currently emptiest shard, if best then current, or E MPTY
*/ */
static Shard pick( const Shard& current = EMPTY ); static Shard pick( const Shard& current = EMPTY );
static void reloadShardInfo(); static void reloadShardInfo();
static void removeShard( const string& name ); static void removeShard( const string& name );
static bool isAShardNode( const string& ident ); static bool isAShardNode( const string& ident );
static Shard EMPTY; static Shard EMPTY;
private: private:
void _rsInit();
void _setAddr( const string& addr ); void _setAddr( const string& addr );
string _name; string _name;
string _addr; string _addr;
ConnectionString _cs; ConnectionString _cs;
long long _maxSize; // in MBytes, 0 is unlimited long long _maxSize; // in MBytes, 0 is unlimited
bool _isDraining; // shard is currently being removed bool _isDraining; // shard is currently being removed
ReplicaSetMonitorPtr _rs; set<string> _tags;
}; };
class ShardStatus { class ShardStatus {
public: public:
ShardStatus( const Shard& shard , const BSONObj& obj ); ShardStatus( const Shard& shard , const BSONObj& obj );
friend ostream& operator << (ostream& out, const ShardStatus& s) { friend ostream& operator << (ostream& out, const ShardStatus& s) {
out << s.toString(); out << s.toString();
return out; return out;
skipping to change at line 245 skipping to change at line 248
verify( _conn ); verify( _conn );
return _conn; return _conn;
} }
DBClientBase* get() { DBClientBase* get() {
_finishInit(); _finishInit();
verify( _conn ); verify( _conn );
return _conn; return _conn;
} }
/**
* @return the connection object underneath without setting the sha
rd version.
* @throws AssertionException if _conn is uninitialized.
*/
DBClientBase* getRawConn() const {
verify( _conn );
return _conn;
}
string getHost() const { string getHost() const {
return _addr; return _addr;
} }
string getNS() const { string getNS() const {
return _ns; return _ns;
} }
ChunkManagerPtr getManager() const { ChunkManagerPtr getManager() const {
return _manager; return _manager;
 End of changes. 9 change blocks. 
10 lines changed or deleted 24 lines changed or added


 shell_utils_launcher.h   shell_utils_launcher.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 <boost/filesystem/convenience.hpp> #include <boost/filesystem/convenience.hpp>
#include <boost/thread/recursive_mutex.hpp> #include <boost/thread/recursive_mutex.hpp>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include <utility>
#include "mongo/bson/bsonobj.h"
#ifdef _WIN32 #ifdef _WIN32
typedef int pid_t; typedef int pid_t;
#endif #endif
namespace mongo { namespace mongo {
class Scope; class Scope;
namespace shell_utils { namespace shell_utils {
skipping to change at line 49 skipping to change at line 56
void KillMongoProgramInstances(); void KillMongoProgramInstances();
void goingAwaySoon(); void goingAwaySoon();
void installShellUtilsLauncher( Scope& scope ); void installShellUtilsLauncher( Scope& scope );
/** Record log lines from concurrent programs. All public members are thread safe. */ /** Record log lines from concurrent programs. All public members are thread safe. */
class ProgramOutputMultiplexer { class ProgramOutputMultiplexer {
public: public:
void appendLine( int port, int pid, const char *line ); void appendLine( int port, int pid, const char *line );
/** @return up to 100000 characters of the most recent log outp ut. */ /** @return up to 100000 characters of the most recent log outp ut. */
string str() const; std::string str() const;
void clear(); void clear();
private: private:
stringstream _buffer; std::stringstream _buffer;
}; };
/** /**
* A registry of spawned programs that are identified by a bound po rt or else a system pid. * A registry of spawned programs that are identified by a bound po rt or else a system pid.
* All public member functions are thread safe. * All public member functions are thread safe.
*/ */
class ProgramRegistry { class ProgramRegistry {
public: public:
bool isPortRegistered( int port ) const; bool isPortRegistered( int port ) const;
/** @return pid for a registered port. */ /** @return pid for a registered port. */
pid_t pidForPort( int port ) const; pid_t pidForPort( int port ) const;
/** Register an unregistered port. */ /** Register an unregistered port. */
void registerPort( int port, pid_t pid, int output ); void registerPort( int port, pid_t pid, int output );
void deletePort( int port ); void deletePort( int port );
void getRegisteredPorts( vector<int> &ports ); void getRegisteredPorts( std::vector<int> &ports );
bool isPidRegistered( pid_t pid ) const; bool isPidRegistered( pid_t pid ) const;
/** Register an unregistered pid. */ /** Register an unregistered pid. */
void registerPid( pid_t pid, int output ); void registerPid( pid_t pid, int output );
void deletePid( pid_t pid ); void deletePid( pid_t pid );
void getRegisteredPids( vector<pid_t> &pids ); void getRegisteredPids( vector<pid_t> &pids );
private: private:
map<int,pair<pid_t,int> > _ports; std::map<int,std::pair<pid_t,int> > _ports;
map<pid_t,int> _pids; std::map<pid_t,int> _pids;
mutable boost::recursive_mutex _mutex; mutable boost::recursive_mutex _mutex;
#ifdef _WIN32 #ifdef _WIN32
public: public:
map<pid_t,HANDLE> _handles; std::map<pid_t,HANDLE> _handles;
#endif #endif
}; };
/** Helper class for launching a program and logging its output. */ /** Helper class for launching a program and logging its output. */
class ProgramRunner { class ProgramRunner {
public: public:
/** @param args The program's arguments, including the program name. */ /** @param args The program's arguments, including the program name. */
ProgramRunner( const BSONObj &args ); ProgramRunner( const BSONObj &args );
/** Launch the program. */ /** Launch the program. */
void start(); void start();
/** Continuously read the program's output, generally from a sp ecial purpose thread. */ /** Continuously read the program's output, generally from a sp ecial purpose thread. */
void operator()(); void operator()();
pid_t pid() const { return _pid; } pid_t pid() const { return _pid; }
int port() const { return _port; } int port() const { return _port; }
private: private:
boost::filesystem::path findProgram( const string &prog ); boost::filesystem::path findProgram( const string &prog );
void launchProcess( int child_stdout ); void launchProcess( int child_stdout );
vector<string> _argv; std::vector<std::string> _argv;
int _port; int _port;
int _pipe; int _pipe;
pid_t _pid; pid_t _pid;
}; };
} }
} }
 End of changes. 7 change blocks. 
7 lines changed or deleted 14 lines changed or added


 simplerwlock.h   simplerwlock.h 
#pragma once #pragma once
#include "mongo/bson/util/atomic_int.h" #include "mongo/bson/util/atomic_int.h"
namespace mongo { namespace mongo {
/** separated out as later the implementation of this may be different than RWLock, /** separated out as later the implementation of this may be different than RWLock,
depending on OS, as there is no upgrade etc. facility herein. depending on OS, as there is no upgrade etc. facility herein.
*/ */
class SimpleRWLock : boost::noncopyable { class SimpleRWLock : boost::noncopyable {
#if defined(_WIN32) #if defined(_WIN32) && defined(MONGO_USE_SRW_ON_WINDOWS)
SRWLOCK _lock; SRWLOCK _lock;
#else #else
RWLockBase m; RWLockBase m;
#endif #endif
#if defined(_WIN32) && defined(_DEBUG) #if defined(_WIN32) && defined(_DEBUG)
AtomicUInt shares; AtomicUInt shares;
ThreadLocalValue<int> s; ThreadLocalValue<int> s;
unsigned tid; unsigned tid;
#endif #endif
public: public:
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 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 #ifdef _WIN32
#include <windows.h> #include "mongo/platform/windows_basic.h"
#endif #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.
*/ */
 End of changes. 2 change blocks. 
1 lines changed or deleted 2 lines changed or added


 stat_util.h   stat_util.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 "../db/jsobj.h" #include "../db/jsobj.h"
namespace mongo { namespace mongo {
struct NamespaceInfo {
string ns;
// these need to be in millis
long long read;
long long write;
string toString() const {
stringstream ss;
ss << ns << " r: " << read << " w: " << write;
return ss.str();
}
};
struct NamespaceDiff {
string ns;
long long read;
long long write;
NamespaceDiff( NamespaceInfo prev , NamespaceInfo now ) {
ns = prev.ns;
read = now.read - prev.read;
write = now.write - prev.write;
}
long long total() const { return read + write; }
bool operator<(const NamespaceDiff& r) const {
return total() < r.total();
}
};
typedef map<string,NamespaceInfo> NamespaceStats;
/** /**
* static methods useful for computing status from serverStatus type th ings * static methods useful for computing status from serverStatus type th ings
*/ */
class StatUtil { class StatUtil {
public: public:
/** /**
* @param seconds - seconds between calls to serverStatus * @param seconds - seconds between calls to serverStatus
* @param all - show all fields * @param all - show all fields
*/ */
StatUtil( double seconds = 1 , bool all = false ); StatUtil( double seconds = 1 , bool all = false );
skipping to change at line 49 skipping to change at line 85
* @param b newer serverStatus * @param b newer serverStatus
*/ */
BSONObj doRow( const BSONObj& a , const BSONObj& b ); BSONObj doRow( const BSONObj& a , const BSONObj& b );
double getSeconds() const { return _seconds; } double getSeconds() const { return _seconds; }
bool getAll() const { return _all; } bool getAll() const { return _all; }
void setSeconds( double seconds ) { _seconds = seconds; } void setSeconds( double seconds ) { _seconds = seconds; }
void setAll( bool all ) { _all = all; } void setAll( bool all ) { _all = all; }
static NamespaceStats parseServerStatusLocks( const BSONObj& server
Status );
static vector<NamespaceDiff> computeDiff( const NamespaceStats& pre
v , const NamespaceStats& current );
private: private:
double percent( const char * outof , const char * val , const BSONO bj& a , const BSONObj& b ); double percent( const char * outof , const char * val , const BSONO bj& a , const BSONObj& b );
double diff( const string& name , const BSONObj& a , const BSONObj& b ); double diff( const string& name , const BSONObj& a , const BSONObj& b );
void _appendMem( BSONObjBuilder& result , const string& name , unsi gned width , double sz ); void _appendMem( BSONObjBuilder& result , const string& name , unsi gned width , double sz );
void _appendNet( BSONObjBuilder& result , const string& name , doub le diff ); void _appendNet( BSONObjBuilder& result , const string& name , doub le diff );
 End of changes. 2 change blocks. 
0 lines changed or deleted 40 lines changed or added


 stringdata.h   stringdata.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 <cstring> #include <cstring>
#include <string>
namespace mongo { namespace mongo {
using std::string; using std::string;
/** A StringData object wraps a 'const string&' or a 'const char*' with out /** A StringData object wraps a 'const string&' or a 'const char*' with out
* copying its contents. The most common usage is as a function argumen t that * copying its contents. The most common usage is as a function argumen t that
* takes any of the two forms of strings above. Fundamentally, this cla ss tries * takes any of the two forms of strings above. Fundamentally, this cla ss tries
* go around the fact that string literals in C++ are char[N]'s. * go around the fact that string literals in C++ are char[N]'s.
* *
 End of changes. 2 change blocks. 
1 lines changed or deleted 1 lines changed or added


 syncclusterconnection.h   syncclusterconnection.h 
skipping to change at line 45 skipping to change at line 45
* *
* 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; using DBClientBase::query;
using DBClientBase::update;
using DBClientBase::remove;
/** /**
* @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();
/** /**
skipping to change at line 77 skipping to change at line 79
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn, int nToSkip, virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn, int nToSkip,
const BSONObj *fieldsToRetur n, int queryOptions, int batchSize ); const BSONObj *fieldsToRetur n, int queryOptions, int batchSize );
virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo ng cursorId, int nToReturn, int options ); virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo ng cursorId, int nToReturn, int options );
virtual void insert( const string &ns, BSONObj obj, int flags=0); virtual void insert( const string &ns, BSONObj obj, int flags=0);
virtual void insert( const string &ns, const vector< BSONObj >& v, int flags=0); virtual void insert( const string &ns, const vector< BSONObj >& v, int flags=0);
virtual void remove( const string &ns , Query query, bool justOne ) ; virtual void remove( const string &ns , Query query, int flags );
virtual void update( const string &ns , Query query , BSONObj obj , bool upsert , bool multi ); virtual void update( const string &ns , Query query , BSONObj obj , int flags );
virtual bool call( Message &toSend, Message &response, bool assertO k , string * actualServer ); virtual bool call( Message &toSend, Message &response, bool assertO k , string * actualServer );
virtual void say( Message &toSend, bool isRetry = false , string * actualServer = 0 ); virtual void say( Message &toSend, bool isRetry = false , string * actualServer = 0 );
virtual void sayPiggyBack( Message &toSend ); virtual void sayPiggyBack( Message &toSend );
virtual void killCursor( long long cursorID ); virtual void killCursor( long long cursorID );
virtual string getServerAddress() const { return _address; } virtual string getServerAddress() const { return _address; }
virtual bool isFailed() const { return false; } virtual bool isFailed() const { return false; }
virtual string toString() { return _toString(); } virtual string toString() { return _toString(); }
skipping to change at line 102 skipping to change at line 104
virtual bool callRead( Message& toSend , Message& response ); virtual bool callRead( Message& toSend , Message& response );
virtual ConnectionString::ConnectionType type() const { return Conn ectionString::SYNC; } virtual ConnectionString::ConnectionType type() const { return Conn ectionString::SYNC; }
void setAllSoTimeouts( double socketTimeout ); void setAllSoTimeouts( double socketTimeout );
double getSoTimeout() const { return _socketTimeout; } double getSoTimeout() const { return _socketTimeout; }
virtual bool auth(const string &dbname, const string &username, con st string &password_text, string& errmsg, bool digestPassword, Auth::Level* level=NULL); virtual bool auth(const string &dbname, const string &username, con st string &password_text, string& errmsg, bool digestPassword, Auth::Level* level=NULL);
virtual void setAuthenticationTable( const AuthenticationTable& aut
h );
virtual void clearAuthenticationTable();
virtual bool lazySupported() const { return false; } virtual bool lazySupported() const { return false; }
private: private:
SyncClusterConnection( SyncClusterConnection& prev, double socketTi meout = 0 ); SyncClusterConnection( SyncClusterConnection& prev, double socketTi meout = 0 );
string _toString() const; string _toString() const;
bool _commandOnActive(const string &dbname, const BSONObj& cmd, BSO NObj &info, int options=0); bool _commandOnActive(const string &dbname, const BSONObj& cmd, BSO NObj &info, int options=0);
auto_ptr<DBClientCursor> _queryOnActive(const string &ns, Query que ry, int nToReturn, int nToSkip, auto_ptr<DBClientCursor> _queryOnActive(const string &ns, Query que ry, int nToReturn, int nToSkip,
const BSONObj *fieldsToRetu rn, int queryOptions, int batchSize ); const BSONObj *fieldsToRetu rn, int queryOptions, int batchSize );
int _lockType( const string& name ); int _lockType( const string& name );
void _checkLast(); void _checkLast();
void _connect( string host ); void _connect( string host );
 End of changes. 4 change blocks. 
2 lines changed or deleted 8 lines changed or added


 taskqueue.h   taskqueue.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 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"
// if you turn this back on be sure to enable TaskQueueTest again // if you turn this back on be sure to enable TaskQueueTest again
#if 0 #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.
 End of changes. 1 change blocks. 
2 lines changed or deleted 0 lines changed or added


 text.h   text.h 
skipping to change at line 35 skipping to change at line 35
* *
* 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 <vector>
#include <string>
namespace mongo { namespace mongo {
class StringSplitter { class StringSplitter {
public: public:
/** @param big the string to be split /** @param big the string to be split
@param splitter the delimiter @param splitter the delimiter
*/ */
StringSplitter( const char * big , const char * splitter ) StringSplitter( const char * big , const char * splitter )
: _big( big ) , _splitter( splitter ) { : _big( big ) , _splitter( splitter ) {
} }
/** @return true if more to be taken via next() */ /** @return true if more to be taken via next() */
bool more() { bool more() const { return _big[0] != 0; }
return _big[0] != 0;
}
/** get next split string fragment */ /** get next split string fragment */
string next() { std::string next();
const char * foo = strstr( _big , _splitter );
if ( foo ) {
string s( _big , foo - _big );
_big = foo + 1;
while ( *_big && strstr( _big , _splitter ) == _big )
_big++;
return s;
}
string s = _big;
_big += strlen( _big );
return s;
}
void split( vector<string>& l ) { void split( std::vector<std::string>& l );
while ( more() ) {
l.push_back( next() );
}
}
vector<string> split() { std::vector<std::string> split();
vector<string> l;
split( l );
return l;
}
static vector<string> split( const string& big , const string& spli static std::vector<std::string> split( const std::string& big , con
tter ) { st std::string& splitter );
StringSplitter ss( big.c_str() , splitter.c_str() );
return ss.split();
}
static string join( vector<string>& l , const string& split ) { static std::string join( std::vector<std::string>& l , const std::s
stringstream ss; tring& split );
for ( unsigned i=0; i<l.size(); i++ ) {
if ( i > 0 )
ss << split;
ss << l[i];
}
return ss.str();
}
private: private:
const char * _big; const char * _big;
const char * _splitter; const char * _splitter;
}; };
/* This doesn't defend against ALL bad UTF8, but it will guarantee that the /* This doesn't defend against ALL bad UTF8, but it will guarantee that the
* string can be converted to sequence of codepoints. However, it doesn 't * string can be converted to sequence of codepoints. However, it doesn 't
* guarantee that the codepoints are valid. * guarantee that the codepoints are valid.
*/ */
bool isValidUTF8(const char *s); bool isValidUTF8(const char *s);
inline bool isValidUTF8(string s) { return isValidUTF8(s.c_str()); } bool isValidUTF8(std::string s);
// expect that n contains a base ten number and nothing else after it
// NOTE win version hasn't been tested directly
long long parseLL( const char *n );
#if defined(_WIN32) #if defined(_WIN32)
std::string toUtf8String(const std::wstring& wide); std::string toUtf8String(const std::wstring& wide);
std::wstring toWideString(const char *s); std::wstring toWideString(const char *s);
bool writeUtf8ToWindowsConsole( const char* utf8String, unsigned int ut
f8StringSize );
/* like toWideString but UNICODE macro sensitive */ /* like toWideString but UNICODE macro sensitive */
# if !defined(_UNICODE) # if !defined(_UNICODE)
#error temp error #error temp error
inline std::string toNativeString(const char *s) { return s; } inline std::string toNativeString(const char *s) { return s; }
# else # else
inline std::wstring toNativeString(const char *s) { return toWideString (s); } inline std::wstring toNativeString(const char *s) { return toWideString (s); }
# endif # endif
#endif
// expect that n contains a base ten number and nothing else after it
// NOTE win version hasn't been tested directly
inline long long parseLL( const char *n ) {
long long ret;
uassert( 13307, "cannot convert empty string to long long", *n != 0
);
#if !defined(_WIN32)
char *endPtr = 0;
errno = 0;
ret = strtoll( n, &endPtr, 10 );
uassert( 13305, "could not convert string to long long", *endPtr ==
0 && errno == 0 );
#elif _MSC_VER>=1600 // 1600 is VS2k10 1500 is VS2k8
size_t endLen = 0;
try {
ret = stoll( n, &endLen, 10 );
}
catch ( ... ) {
endLen = 0;
}
uassert( 13306, "could not convert string to long long", endLen !=
0 && n[ endLen ] == 0 );
#else // stoll() wasn't introduced until VS 2010.
char* endPtr = 0;
ret = _strtoi64( n, &endPtr, 10 );
uassert( 13310, "could not convert string to long long", (*endPtr =
= 0) && (ret != _I64_MAX) && (ret != _I64_MIN) );
#endif // !defined(_WIN32)
return ret;
}
#if defined(_WIN32)
class WindowsCommandLine { class WindowsCommandLine {
char** _argv; char** _argv;
public: public:
WindowsCommandLine( int argc, wchar_t* argvW[] ); WindowsCommandLine( int argc, wchar_t* argvW[] );
~WindowsCommandLine(); ~WindowsCommandLine();
char** argv( void ) const { return _argv; }; char** argv( void ) const { return _argv; };
}; };
#endif // #if defined(_WIN32) #endif // #if defined(_WIN32)
 End of changes. 10 change blocks. 
77 lines changed or deleted 19 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 <ctime> #include <ctime>
#include <string> #include <string>
#include <iostream>
#include <boost/thread/thread.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 "../bson/util/misc.h" // Date_t
namespace mongo { #include "mongo/bson/util/misc.h" // Date_t
using std::string; namespace mongo {
inline void time_t_to_Struct(time_t t, struct tm * buf , bool local = f void time_t_to_Struct(time_t t, struct tm * buf , bool local = false );
alse ) {
#if defined(_WIN32)
if ( local )
localtime_s( buf , &t );
else
gmtime_s(buf, &t);
#else
if ( local )
localtime_r(&t, buf);
else
gmtime_r(&t, buf);
#endif
}
// 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) { std::string terseCurrentTime(bool colonsOk=true);
struct tm t;
time_t_to_Struct( time(0) , &t );
const char* fmt = (colonsOk ? "%Y-%m-%dT%H:%M:%S" : "%Y-%m-%dT%H-%M
-%S");
char buf[32];
verify(strftime(buf, sizeof(buf), fmt, &t) == 19);
return buf;
}
inline string timeToISOString(time_t time) {
struct tm t;
time_t_to_Struct( time, &t );
const char* fmt = "%Y-%m-%dT%H:%M:%SZ"; std::string timeToISOString(time_t time);
char buf[32];
verify(strftime(buf, sizeof(buf), fmt, &t) == 20);
return buf;
}
inline boost::gregorian::date currentDate() { boost::gregorian::date currentDate();
boost::posix_time::ptime now = boost::posix_time::second_clock::loc
al_time();
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 bool toPointInTime( const std::string& str , boost::posix_time::ptime*
* timeOfDay ) { timeOfDay );
int hh = 0;
int mm = 0;
if ( 2 != sscanf( str.c_str() , "%d:%d" , &hh , &mm ) ) {
return false;
}
// verify that time is well formed
if ( ( hh / 24 ) || ( mm / 60 ) ) {
return false;
}
boost::posix_time::ptime res( currentDate() , boost::posix_time::ho
urs( hh ) + boost::posix_time::minutes( mm ) );
*timeOfDay = res;
return true;
}
#if defined(_WIN32)
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
// are but otherwise it's quite likely that would be a mista
ke.
Sleep(s*1000);
}
inline void sleepmillis(long long s) {
verify( s <= 0xffffffff );
Sleep((DWORD) s);
}
inline void sleepmicros(long long s) {
if ( s <= 0 )
return;
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += (int)( s / 1000000 );
xt.nsec += (int)(( s % 1000000 ) * 1000);
if ( xt.nsec >= 1000000000 ) {
xt.nsec -= 1000000000;
xt.sec++;
}
boost::thread::sleep(xt);
}
#elif defined(__sunos__)
inline void sleepsecs(int s) {
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += s;
boost::thread::sleep(xt);
}
inline void sleepmillis(long long s) {
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += (int)( s / 1000 );
xt.nsec += (int)(( s % 1000 ) * 1000000);
if ( xt.nsec >= 1000000000 ) {
xt.nsec -= 1000000000;
xt.sec++;
}
boost::thread::sleep(xt);
}
inline void sleepmicros(long long s) {
if ( s <= 0 )
return;
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += (int)( s / 1000000 );
xt.nsec += (int)(( s % 1000000 ) * 1000);
if ( xt.nsec >= 1000000000 ) {
xt.nsec -= 1000000000;
xt.sec++;
}
boost::thread::sleep(xt);
}
#else
inline void sleepsecs(int s) {
struct timespec t;
t.tv_sec = s;
t.tv_nsec = 0;
if ( nanosleep( &t , 0 ) ) {
std::cout << "nanosleep failed" << std::endl;
}
}
inline void sleepmicros(long long s) {
if ( s <= 0 )
return;
struct timespec t;
t.tv_sec = (int)(s / 1000000);
t.tv_nsec = 1000 * ( s % 1000000 );
struct timespec out;
if ( nanosleep( &t , &out ) ) {
std::cout << "nanosleep failed" << std::endl;
}
}
inline void sleepmillis(long long s) {
sleepmicros( s * 1000 );
}
#endif
extern long long jsTime_virtual_skew; void sleepsecs(int s);
extern boost::thread_specific_ptr<long long> jsTime_virtual_thread_skew void sleepmillis(long long ms);
; void sleepmicros(long long micros);
// DO NOT TOUCH except for testing // DO NOT TOUCH except for testing
inline void jsTimeVirtualSkew( long long skew ){ void jsTimeVirtualSkew( long long skew );
jsTime_virtual_skew = skew;
}
inline long long getJSTimeVirtualSkew(){
return jsTime_virtual_skew;
}
inline void jsTimeVirtualThreadSkew( long long skew ){ void jsTimeVirtualThreadSkew( long long skew );
jsTime_virtual_thread_skew.reset(new long long(skew)); long long getJSTimeVirtualThreadSkew();
}
inline long long getJSTimeVirtualThreadSkew(){
if(jsTime_virtual_thread_skew.get()){
return *(jsTime_virtual_thread_skew.get());
}
else return 0;
}
/** Date_t is milliseconds since epoch */ /** Date_t is milliseconds since epoch */
inline Date_t jsTime(); Date_t jsTime();
/** warning this will wrap */ /** warning this will wrap */
inline unsigned curTimeMicros(); unsigned curTimeMicros();
unsigned long long curTimeMicros64();
inline unsigned long long curTimeMicros64(); unsigned long long curTimeMillis64();
#ifdef _WIN32 // no gettimeofday on windows
inline unsigned long long curTimeMillis64() {
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
return ((unsigned long long)xt.sec) * 1000 + xt.nsec / 1000000;
}
inline Date_t jsTime() {
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
unsigned long long t = xt.nsec / 1000000;
return ((unsigned long long) xt.sec * 1000) + t + getJSTimeVirtualS
kew() + getJSTimeVirtualThreadSkew();
}
inline unsigned long long curTimeMicros64() {
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
unsigned long long t = xt.nsec / 1000;
return (((unsigned long long) xt.sec) * 1000000) + t;
}
inline unsigned curTimeMicros() {
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
unsigned t = xt.nsec / 1000;
unsigned secs = xt.sec % 1024;
return secs*1000000 + t;
}
#else
# include <sys/time.h>
inline unsigned long long curTimeMillis64() {
timeval tv;
gettimeofday(&tv, NULL);
return ((unsigned long long)tv.tv_sec) * 1000 + tv.tv_usec / 1000;
}
inline Date_t jsTime() {
timeval tv;
gettimeofday(&tv, NULL);
unsigned long long t = tv.tv_usec / 1000;
return ((unsigned long long) tv.tv_sec * 1000) + t + getJSTimeVirtu
alSkew() + getJSTimeVirtualThreadSkew();
}
inline unsigned long long curTimeMicros64() {
timeval tv;
gettimeofday(&tv, NULL);
return (((unsigned long long) tv.tv_sec) * 1000*1000) + tv.tv_usec;
}
inline unsigned curTimeMicros() {
timeval tv;
gettimeofday(&tv, NULL);
unsigned secs = tv.tv_sec % 1024;
return secs*1000*1000 + tv.tv_usec;
}
#endif
// these are so that if you use one of them compilation will fail // these are so that if you use one of them compilation will fail
char *asctime(const struct tm *tm); char *asctime(const struct tm *tm);
char *ctime(const time_t *timep); char *ctime(const time_t *timep);
struct tm *gmtime(const time_t *timep); struct tm *gmtime(const time_t *timep);
struct tm *localtime(const time_t *timep); struct tm *localtime(const time_t *timep);
} // namespace mongo } // namespace mongo
 End of changes. 15 change blocks. 
221 lines changed or deleted 18 lines changed or added


 unittest.h   unittest.h 
// mongo/unittest/unittest.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/>.
*/ */
/* /*
* A C++ unit testing framework.
simple portable regression system *
* For examples of basic usage, see mongo/unittest/unittest_test.cpp.
*/ */
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include "mongo/util/assert_util.h" #include "mongo/util/assert_util.h"
#include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h"
#define ASSERT_THROWS(a,b) \ /**
try { \ * Fail unconditionally, reporting the given message.
a; \ */
mongo::unittest::assert_fail( #a , __FILE__ , __LINE__ ); \ #define FAIL(MESSAGE) ::mongo::unittest::TestAssertion( __FILE__ , __LINE__
} catch ( b& ){ \ ).fail( (MESSAGE) )
mongo::unittest::assert_pass(); \
}
#define ASSERT_EQUALS(a,b) mongo::unittest::MyAsserts( #a , #b , __FILE__ , /**
__LINE__ ).ae( (a) , (b) ) * Fails unless "EXPRESSION" is true.
#define ASSERT_NOT_EQUALS(a,b) mongo::unittest::MyAsserts( #a , #b , __FILE */
__ , __LINE__ ).nae( (a) , (b) ) #define ASSERT_TRUE(EXPRESSION) ::mongo::unittest::TestAssertion( __FILE__,
__LINE__ ).failUnless( \
(EXPRESSION), "Expected: " #EXPRESSION )
#define ASSERT(EXPRESSION) ASSERT_TRUE(EXPRESSION)
#define ASSERT(x) (void)( (!(!(x))) ? mongo::unittest::assert_pass() : FAIL /**
(x) ) * Fails if "EXPRESSION" is true.
#define FAIL(x) mongo::unittest::assert_fail( #x , __FILE__ , __LINE__ ) */
#define ASSERT_FALSE(EXPRESSION) ::mongo::unittest::TestAssertion( __FILE__
, __LINE__ ).failIf( \
(EXPRESSION), "Expected: !(" #EXPRESSION ")" )
/*
* Binary comparison assertions.
*/
#define ASSERT_EQUALS(a,b) _ASSERT_COMPARISON(Equal, a, b)
#define ASSERT_NOT_EQUALS(a,b) _ASSERT_COMPARISON(NotEqual, a, b)
#define ASSERT_LESS_THAN(a, b) _ASSERT_COMPARISON(LessThan, a, b)
#define ASSERT_NOT_LESS_THAN(a, b) _ASSERT_COMPARISON(NotLessThan, a, b)
#define ASSERT_GREATER_THAN(a, b) _ASSERT_COMPARISON(GreaterThan, a, b)
#define ASSERT_NOT_GREATER_THAN(a, b) _ASSERT_COMPARISON(NotGreaterThan, a,
b)
#define ASSERT_LESS_THAN_OR_EQUALS(a, b) ASSERT_NOT_GREATER_THAN(a, b)
#define ASSERT_GREATER_THAN_OR_EQUALS(a, b) ASSERT_NOT_LESS_THAN(a, b)
/**
* Binary comparison utility macro. Do not use directly.
*/
#define _ASSERT_COMPARISON(COMPARISON, a, b) mongo::unittest::ComparisonAss
ertion( \
#a, #b , __FILE__ , __LINE__ ).assert##COMPARISON( (a), (b) )
/**
* Verify that the evaluation of "EXPRESSION" throws an exception of type E
XCEPTION_TYPE.
*
* If "EXPRESSION" throws no exception, or one that is neither of type "EXC
EPTION_TYPE" nor
* of a subtype of "EXCEPTION_TYPE", the test is considered a failure and f
urther evaluation
* halts.
*/
#define ASSERT_THROWS(EXPRESSION, EXCEPTION_TYPE) \
do { \
bool threw = false; \
::mongo::unittest::TestAssertion _testAssertion( __FILE__, __LINE__
); \
try { \
EXPRESSION; \
} catch ( const EXCEPTION_TYPE& ) { threw = true; } \
if (!threw) \
_testAssertion.fail("Expected expression " #EXPRESSION \
" to throw " #EXCEPTION_TYPE " but it threw
nothing."); \
} while( false )
/**
* Construct a single test, named "TEST_NAME" within the test case "CASE_NA
ME".
*
* Usage:
*
* TEST(MyModuleTests, TestThatFooFailsOnErrors) {
* ASSERT_EQUALS(error_success, foo(invalidValue));
* }
*/
#define TEST(CASE_NAME, TEST_NAME) \
class _TEST_TYPE_NAME(CASE_NAME, TEST_NAME) : public ::mongo::unittest:
:Test { \
private: \
virtual void _doTest(); \
\
static const RegistrationAgent<_TEST_TYPE_NAME(CASE_NAME, TEST_NAME
) > _agent; \
}; \
const ::mongo::unittest::Test::RegistrationAgent<_TEST_TYPE_NAME(CASE_N
AME, TEST_NAME) > \
_TEST_TYPE_NAME(CASE_NAME, TEST_NAME)::_agent(#CASE_NAME, #TEST
_NAME); \
void _TEST_TYPE_NAME(CASE_NAME, TEST_NAME)::_doTest()
/**
* Macro to construct a type name for a test, from its "CASE_NAME" and "TES
T_NAME".
* Do not use directly in test code.
*/
#define _TEST_TYPE_NAME(CASE_NAME, TEST_NAME) \
UnitTest__##CASE_NAME##__##TEST_NAME
namespace mongo { namespace mongo {
namespace unittest { namespace unittest {
class Result; class Result;
class TestCase { /**
* Type representing the function composing a test.
*/
typedef boost::function<void (void)> TestFunction;
/**
* Container holding a test function and its name. Suites
* contain lists of these.
*/
class TestHolder : private boost::noncopyable {
public: public:
virtual ~TestCase(); TestHolder(const std::string& name, const TestFunction& fn)
virtual void setUp(); : _name(name), _fn(fn) {}
virtual void tearDown();
virtual void run() = 0; ~TestHolder() {}
virtual std::string getName() = 0; void run() const { _fn(); }
std::string getName() const { return _name; }
private:
std::string _name;
TestFunction _fn;
}; };
class Test : public TestCase { /**
* Base type for unit test fixtures. Also, the default fixture typ
e used
* by the TEST() macro.
*
* TODO(schwerin): Implement a TEST_F macro that allows testers to
specify
* different subclasses of Test to be used as the test fixture. Th
ese subclasses
* could then provide per-test set-up and tear-down code by overrid
ing the
* setUp and tearDown methods.
*/
class Test : private boost::noncopyable {
public: public:
Test(); Test();
virtual ~Test(); virtual ~Test();
virtual std::string getName();
void run();
protected: protected:
void setTestName( const std::string &name ); /**
* Registration agent for adding tests to suites, used by TEST
macro.
*/
template <typename T>
class RegistrationAgent : private boost::noncopyable {
public:
RegistrationAgent(const std::string& suiteName, const std::
string& testName);
};
private: private:
std::string _name; /**
}; * Called on the test object before running the test.
*/
template< class T > virtual void setUp();
class TestHolderBase : public TestCase {
public:
TestHolderBase() {}
virtual ~TestHolderBase() {}
virtual void run() {
boost::scoped_ptr<T> t;
t.reset( create() );
t->run();
}
virtual T * create() = 0;
virtual std::string getName() {
return demangleName( typeid(T) );
}
};
template< class T > /**
class TestHolder0 : public TestHolderBase<T> { * Called on the test object after running the test.
public: */
virtual T * create() { virtual void tearDown();
return new T();
}
};
template< class T , typename A > /**
class TestHolder1 : public TestHolderBase<T> { * The test itself.
public: */
TestHolder1( const A& a ) : _a(a) {} virtual void _doTest() = 0;
virtual T * create() {
return new T( _a );
}
const A _a;
}; };
class Suite { /**
* Representation of a collection of tests.
*
* One suite is constructed for each "CASE_NAME" when using the TES
T macro.
* Additionally, tests that are part of dbtests are manually assign
ed to suites
* by the programmer by overriding setupTests() in a subclass of Su
ite. This
* approach is deprecated.
*/
class Suite : private boost::noncopyable {
public: public:
Suite( const string &name ); Suite( const string& name );
virtual ~Suite(); virtual ~Suite();
template<class T> template<class T>
void add() { void add() { add<T>(demangleName(typeid(T))); }
_tests.push_back( new TestHolder0<T>() );
}
template<class T , typename A > template<class T , typename A >
void add( const A& a ) { void add( const A& a ) {
_tests.push_back( new TestHolder1<T,A>(a) ); add(demangleName(typeid(T)), boost::bind(&Suite::runTestObj ectWithArg<T, A>, a));
} }
Result * run( const std::string& filter ); template<class T>
void add(const std::string& name) {
add(name, &Suite::runTestObject<T>);
}
static int run( const std::vector<std::string> &suites , const void add(const std::string& name, const TestFunction& testFn);
std::string& filter );
Result * run( const std::string& filter , int runsPerTest );
static int run( const std::vector<std::string>& suites , const
std::string& filter , int runsPerTest );
/**
* Get a suite with the given name, creating it if necessary.
*
* The implementation of this function must be safe to call dur
ing the global static
* initialization block before main() executes.
*/
static Suite *getSuite(const string& name);
protected: protected:
virtual void setupTests() = 0; virtual void setupTests();
private: private:
typedef std::vector<TestCase *> TestCaseList; typedef std::vector<TestHolder *> TestHolderList;
template <typename T>
static void runTestObject() {
T testObj;
testObj.run();
}
template <typename T, typename A>
static void runTestObjectWithArg(const A& a) {
T testObj(a);
testObj.run();
}
std::string _name; std::string _name;
TestCaseList _tests; TestHolderList _tests;
bool _ran; bool _ran;
void registerSuite( const std::string &name , Suite *s ); void registerSuite( const std::string& name , Suite* s );
}; };
void assert_pass(); /**
void assert_fail( const char * exp , const char * file , unsigned l * Collection of information about failed tests. Used in reporting
ine ); * failures.
*/
class TestAssertionFailureDetails : private boost::noncopyable {
public:
TestAssertionFailureDetails( const std::string& theFile,
unsigned theLine,
const std::string& theMessage );
class MyAssertionException : private boost::noncopyable { const std::string file;
const unsigned line;
const std::string message;
};
/**
* Exception thrown when a test assertion fails.
*
* Typically thrown by helpers in the TestAssertion class and its i
lk, below.
*
* NOTE(schwerin): This intentionally does _not_ extend std::except
ion, so that code under
* test that (foolishly?) catches std::exception won't swallow test
failures. Doesn't
* protect you from code that foolishly catches ..., but you do wha
t you can.
*/
class TestAssertionFailureException {
public: public:
MyAssertionException() { TestAssertionFailureException( const std::string& theFile,
ss << "assertion: "; unsigned theLine,
} const std::string& theMessage );
std::stringstream ss;
const std::string& getFile() const { return _details->file; }
unsigned getLine() const { return _details->line; }
const std::string& getMessage() const { return _details->messag
e; }
std::string toString() const;
private:
boost::shared_ptr<TestAssertionFailureDetails> _details;
}; };
class MyAsserts : private boost::noncopyable { /**
* Object representing an assertion about some condition.
*/
class TestAssertion : private boost::noncopyable {
public: public:
MyAsserts( const char * aexp , const char * bexp , const char * TestAssertion( const std::string& file, unsigned line );
file , unsigned line ) ~TestAssertion();
: _aexp( aexp ) , _bexp( bexp ) , _file( file ) , _line( li
ne ) {
void fail( const std::string& message) const;
void failIf( bool flag, const std::string &message ) const {
if ( flag ) fail( message );
}
void failUnless( bool flag, const std::string& message ) const
{
failIf( !flag, message );
} }
template<typename A,typename B> private:
void ae( const A &a , const B &b ) { const std::string _file;
_gotAssert(); const unsigned _line;
if ( a == b ) };
return;
printLocation(); /**
* Specialization of TestAssertion for binary comparisons.
*/
class ComparisonAssertion : private TestAssertion {
public:
ComparisonAssertion( const std::string& aexp , const std::strin
g& bexp ,
const std::string& file , unsigned line );
MyAssertionException * e = getBase(); template<typename A,typename B>
e->ss << a << " != " << b << std::endl; void assertEqual( const A& a , const B& b ) {
log() << e->ss.str() << std::endl; failUnless(a == b, getComparisonFailureMessage("==", a, b))
throw e; ;
} }
template<typename A,typename B> template<typename A,typename B>
void nae( const A &a , const B &b ) { void assertNotEqual( const A& a , const B& b ) {
_gotAssert(); failUnless(a != b, getComparisonFailureMessage("!=", a, b))
if ( a != b ) ;
return; }
printLocation();
MyAssertionException * e = getBase(); template<typename A,typename B>
e->ss << a << " == " << b << std::endl; void assertLessThan( const A& a , const B& b ) {
log() << e->ss.str() << std::endl; failUnless(a < b, getComparisonFailureMessage("<", a, b));
throw e;
} }
void printLocation(); template<typename A,typename B>
void assertNotLessThan( const A& a , const B& b ) {
failUnless(a >= b, getComparisonFailureMessage(">=", a, b))
;
}
private: template<typename A,typename B>
void assertGreaterThan( const A& a , const B& b ) {
failUnless(a > b, getComparisonFailureMessage(">", a, b));
}
void _gotAssert(); template<typename A,typename B>
void assertNotGreaterThan( const A& a , const B& b ) {
failUnless(a <= b, getComparisonFailureMessage("<=", a, b))
;
}
MyAssertionException * getBase(); private:
template< typename A, typename B>
std::string getComparisonFailureMessage(const std::string &theO
perator,
const A& a, const B& b)
;
std::string _aexp; std::string _aexp;
std::string _bexp; std::string _bexp;
std::string _file;
unsigned _line;
}; };
/** /**
* Returns the name of the currently executing unit test * Hack to support the runaway test observer in dbtests. This is a
hook that
* unit test running harnesses (unittest_main and dbtests) must imp
lement.
*/ */
std::string getExecutingTestName(); void onCurrentTestNameChange( const std::string& testName );
/** /**
* Return a list of suite names. * Return a list of suite names.
*/ */
std::vector<std::string> getAllSuiteNames(); std::vector<std::string> getAllSuiteNames();
} // namespace unittest } // namespace unittest
} // namespace mongo } // namespace mongo
#include "mongo/unittest/unittest-inl.h"
 End of changes. 45 change blocks. 
115 lines changed or deleted 314 lines changed or added


 update.h   update.h 
// update.h //@file update.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 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 "../../util/embedded_builder.h" #include "mongo/db/jsobj.h"
#include "../../util/stringutils.h" #include "mongo/db/curop.h"
#include "../matcher.h" #include "mongo/db/queryoptimizercursor.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
OID upserted; // if something was upserted, the new _id of the obj ect OID upserted; // if something was upserted, the new _id of the obj ect
UpdateResult( bool e, bool m, unsigned long long n , const BSONObj& upsertedObject = BSONObj() ) UpdateResult( bool e, bool m, unsigned long long n , const BSONObj& upsertedObject )
: existing(e) , mod(m), num(n) { : existing(e) , mod(m), num(n) {
upserted.clear(); upserted.clear();
BSONElement id = upsertedObject["_id"]; BSONElement id = upsertedObject["_id"];
if ( ! e && n == 1 && id.type() == jstOID ) { if ( ! e && n == 1 && id.type() == jstOID ) {
upserted = id.OID(); upserted = id.OID();
} }
} }
}; };
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 su - allow access to system namespaces (super user)
*/ */
UpdateResult updateObjects(const char *ns, UpdateResult updateObjects(const char* ns,
const BSONObj& updateobj, const BSONObj& updateobj,
BSONObj pattern, const BSONObj& pattern,
bool upsert, bool upsert,
bool multi , bool multi,
bool logop , bool logop,
OpDebug& debug, OpDebug& debug,
bool fromMigrate = false, bool fromMigrate = false,
const QueryPlanSelectionPolicy &planPolicy = const QueryPlanSelectionPolicy& planPolicy =
QueryPlanSelectionPolicy::any()); QueryPlanSelectionPolicy::any());
UpdateResult _updateObjects(bool god,
const char *ns, UpdateResult _updateObjects(bool su,
const char* ns,
const BSONObj& updateobj, const BSONObj& updateobj,
BSONObj pattern, const BSONObj& pattern,
bool upsert, bool upsert,
bool multi , bool multi,
bool logop , bool logop,
OpDebug& debug , OpDebug& debug,
RemoveSaver * rs = 0, RemoveSaver* rs = 0,
bool fromMigrate = false, bool fromMigrate = false,
const QueryPlanSelectionPolicy &planPolicy const QueryPlanSelectionPolicy& planPolicy
= = QueryPlanSelectionPolicy::any());
QueryPlanSelectionPolicy::any());
// ---------- private -------------
class ModState;
class ModSetState;
/* Used for modifiers such as $inc, $set, $push, ...
* stores the info about a single operation
* once created should never be modified
*/
struct Mod {
// See opFromStr below
// 0 1 2 3 4 5 6 7 8
9 10 11 12 13
enum Op { INC, SET, PUSH, PUSH_ALL, PULL, PULL_ALL , POP, UNSET, BI
TAND, BITOR , BIT , ADDTOSET, RENAME_FROM, RENAME_TO } op;
static const char* modNames[];
static unsigned modNamesNum;
const char *fieldName;
const char *shortFieldName;
BSONElement elt; // x:5 note: this is the actual element from the u
pdateobj
boost::shared_ptr<Matcher> matcher;
bool matcherOnPrimitive;
void init( Op o , BSONElement& e ) {
op = o;
elt = e;
if ( op == PULL && e.type() == Object ) {
BSONObj t = e.embeddedObject();
if ( t.firstElement().getGtLtOp() == 0 ) {
matcher.reset( new Matcher( t ) );
matcherOnPrimitive = false;
}
else {
matcher.reset( new Matcher( BSON( "" << t ) ) );
matcherOnPrimitive = true;
}
}
}
void setFieldName( const char * s ) {
fieldName = s;
shortFieldName = strrchr( fieldName , '.' );
if ( shortFieldName )
shortFieldName++;
else
shortFieldName = fieldName;
}
/**
* @param in incrememnts the actual value inside in
*/
void incrementMe( BSONElement& in ) const {
BSONElementManipulator manip( in );
switch ( in.type() ) {
case NumberDouble:
manip.setNumber( elt.numberDouble() + in.numberDouble() );
break;
case NumberLong:
manip.setLong( elt.numberLong() + in.numberLong() );
break;
case NumberInt:
manip.setInt( elt.numberInt() + in.numberInt() );
break;
default:
verify(0);
}
}
void IncrementMe( BSONElement& in ) const {
BSONElementManipulator manip( in );
switch ( in.type() ) {
case NumberDouble:
manip.SetNumber( elt.numberDouble() + in.numberDouble() );
break;
case NumberLong:
manip.SetLong( elt.numberLong() + in.numberLong() );
break;
case NumberInt:
manip.SetInt( elt.numberInt() + in.numberInt() );
break;
default:
verify(0);
}
}
template< class Builder >
void appendIncremented( Builder& bb , const BSONElement& in, ModSta
te& ms ) const;
bool operator<( const Mod &other ) const {
return strcmp( fieldName, other.fieldName ) < 0;
}
bool arrayDep() const {
switch (op) {
case PUSH:
case PUSH_ALL:
case POP:
return true;
default:
return false;
}
}
static bool isIndexed( const string& fullName , const set<string>&
idxKeys ) {
const char * fieldName = fullName.c_str();
// check if there is an index key that is a parent of mod
for( const char *dot = strchr( fieldName, '.' ); dot; dot = str
chr( dot + 1, '.' ) )
if ( idxKeys.count( string( fieldName, dot - fieldName ) )
)
return true;
// check if there is an index key equal to mod
if ( idxKeys.count(fullName) )
return true;
// check if there is an index key that is a child of mod
set< string >::const_iterator j = idxKeys.upper_bound( fullName
);
if ( j != idxKeys.end() && j->find( fullName ) == 0 && (*j)[ful
lName.size()] == '.' )
return true;
return false;
}
bool isIndexed( const set<string>& idxKeys ) const {
string fullName = fieldName;
if ( isIndexed( fullName , idxKeys ) )
return true;
if ( strstr( fieldName , "." ) ) {
// check for a.0.1
StringBuilder buf;
for ( size_t i=0; i<fullName.size(); i++ ) {
char c = fullName[i];
if ( c == '$' &&
i > 0 && fullName[i-1] == '.' &&
i+1<fullName.size() &&
fullName[i+1] == '.' ) {
i++;
continue;
}
buf << c;
if ( c != '.' )
continue;
if ( ! isdigit( fullName[i+1] ) )
continue;
bool possible = true;
size_t j=i+2;
for ( ; j<fullName.size(); j++ ) {
char d = fullName[j];
if ( d == '.' )
break;
if ( isdigit( d ) )
continue;
possible = false;
break;
}
if ( possible )
i = j;
}
string x = buf.str();
if ( isIndexed( x , idxKeys ) )
return true;
}
return false;
}
template< class Builder >
void apply( Builder& b , BSONElement in , ModState& ms ) const;
/**
* @return true iff toMatch should be removed from the array
*/
bool _pullElementMatch( BSONElement& toMatch ) const;
void _checkForAppending( const BSONElement& e ) const {
if ( e.type() == Object ) {
// this is a tiny bit slow, but rare and important
// only when setting something TO an object, not setting so
mething in an object
// and it checks for { $set : { x : { 'a.b' : 1 } } }
// which is feel has been common
uassert( 12527 , "not okForStorage" , e.embeddedObject().ok
ForStorage() );
}
}
bool isEach() const {
if ( elt.type() != Object )
return false;
BSONElement e = elt.embeddedObject().firstElement();
if ( e.type() != Array )
return false;
return strcmp( e.fieldName() , "$each" ) == 0;
}
BSONObj getEach() const {
return elt.embeddedObjectUserCheck().firstElement().embeddedObj
ectUserCheck();
}
void parseEach( BSONElementSet& s ) const {
BSONObjIterator i(getEach());
while ( i.more() ) {
s.insert( i.next() );
}
}
const char *renameFrom() const {
massert( 13492, "mod must be RENAME_TO type", op == Mod::RENAME
_TO );
return elt.fieldName();
}
};
/**
* stores a set of Mods
* once created, should never be changed
*/
class ModSet : boost::noncopyable {
typedef map<string,Mod> ModHolder;
ModHolder _mods;
int _isIndexed;
bool _hasDynamicArray;
static Mod::Op opFromStr( const char *fn ) {
verify( fn[0] == '$' );
switch( fn[1] ) {
case 'i': {
if ( fn[2] == 'n' && fn[3] == 'c' && fn[4] == 0 )
return Mod::INC;
break;
}
case 's': {
if ( fn[2] == 'e' && fn[3] == 't' && fn[4] == 0 )
return Mod::SET;
break;
}
case 'p': {
if ( fn[2] == 'u' ) {
if ( fn[3] == 's' && fn[4] == 'h' ) {
if ( fn[5] == 0 )
return Mod::PUSH;
if ( fn[5] == 'A' && fn[6] == 'l' && fn[7] == 'l' &
& fn[8] == 0 )
return Mod::PUSH_ALL;
}
else if ( fn[3] == 'l' && fn[4] == 'l' ) {
if ( fn[5] == 0 )
return Mod::PULL;
if ( fn[5] == 'A' && fn[6] == 'l' && fn[7] == 'l' &
& fn[8] == 0 )
return Mod::PULL_ALL;
}
}
else if ( fn[2] == 'o' && fn[3] == 'p' && fn[4] == 0 )
return Mod::POP;
break;
}
case 'u': {
if ( fn[2] == 'n' && fn[3] == 's' && fn[4] == 'e' && fn[5]
== 't' && fn[6] == 0 )
return Mod::UNSET;
break;
}
case 'b': {
if ( fn[2] == 'i' && fn[3] == 't' ) {
if ( fn[4] == 0 )
return Mod::BIT;
if ( fn[4] == 'a' && fn[5] == 'n' && fn[6] == 'd' && fn
[7] == 0 )
return Mod::BITAND;
if ( fn[4] == 'o' && fn[5] == 'r' && fn[6] == 0 )
return Mod::BITOR;
}
break;
}
case 'a': {
if ( fn[2] == 'd' && fn[3] == 'd' ) {
// add
if ( fn[4] == 'T' && fn[5] == 'o' && fn[6] == 'S' && fn
[7] == 'e' && fn[8] == 't' && fn[9] == 0 )
return Mod::ADDTOSET;
}
break;
}
case 'r': {
if ( fn[2] == 'e' && fn[3] == 'n' && fn[4] == 'a' && fn[5]
== 'm' && fn[6] =='e' ) {
return Mod::RENAME_TO; // with this return code we hand
le both RENAME_TO and RENAME_FROM
}
break;
}
default: break;
}
uassert( 10161 , "Invalid modifier specified " + string( fn ),
false );
return Mod::INC;
}
ModSet() {}
void updateIsIndexed( const Mod &m, const set<string> &idxKeys, con
st set<string> *backgroundKeys ) {
if ( m.isIndexed( idxKeys ) ||
(backgroundKeys && m.isIndexed(*backgroundKeys)) ) {
_isIndexed++;
}
}
public:
ModSet( const BSONObj &from ,
const set<string>& idxKeys = set<string>(),
const set<string>* backgroundKeys = 0
);
// TODO: this is inefficient - should probably just handle when ite
rating
ModSet * fixDynamicArray( const string &elemMatchKey ) const;
bool hasDynamicArray() const { return _hasDynamicArray; }
/**
* creates a ModSetState suitable for operation on obj
* doesn't change or modify this ModSet or any underying Mod
*/
auto_ptr<ModSetState> prepare( const BSONObj& obj ) const;
/**
* given a query pattern, builds an object suitable for an upsert
* will take the query spec and combine all $ operators
*/
BSONObj createNewFromQuery( const BSONObj& query );
/**
*
*/
int isIndexed() const {
return _isIndexed;
}
unsigned size() const { return _mods.size(); }
bool haveModForField( const char *fieldName ) const {
return _mods.find( fieldName ) != _mods.end();
}
bool haveConflictingMod( const string& fieldName ) {
size_t idx = fieldName.find( '.' );
if ( idx == string::npos )
idx = fieldName.size();
ModHolder::const_iterator start = _mods.lower_bound(fieldName.s
ubstr(0,idx));
for ( ; start != _mods.end(); start++ ) {
FieldCompareResult r = compareDottedFieldNames( fieldName ,
start->first ,
LexNumCmp( t
rue ) );
switch ( r ) {
case LEFT_SUBFIELD: return true;
case LEFT_BEFORE: return false;
case SAME: return true;
case RIGHT_BEFORE: return false;
case RIGHT_SUBFIELD: return true;
}
}
return false;
}
};
/**
* stores any information about a single Mod operating on a single Obje
ct
*/
class ModState : boost::noncopyable {
public:
const Mod * m;
BSONElement old;
BSONElement newVal;
BSONObj _objData;
const char * fixedOpName;
BSONElement * fixed;
int pushStartSize;
BSONType incType;
int incint;
double incdouble;
long long inclong;
bool dontApply;
ModState() {
fixedOpName = 0;
fixed = 0;
pushStartSize = -1;
incType = EOO;
dontApply = false;
}
Mod::Op op() const {
return m->op;
}
const char * fieldName() const {
return m->fieldName;
}
bool needOpLogRewrite() const {
if ( dontApply )
return false;
if ( fixed || fixedOpName || incType )
return true;
switch( op() ) {
case Mod::RENAME_FROM:
case Mod::RENAME_TO:
return true;
case Mod::BIT:
case Mod::BITAND:
case Mod::BITOR:
// TODO: should we convert this to $set?
return false;
default:
return false;
}
}
void appendForOpLog( BSONObjBuilder& b ) const;
template< class Builder >
void apply( Builder& b , BSONElement in ) {
m->apply( b , in , *this );
}
template< class Builder >
void appendIncValue( Builder& b , bool useFullName ) const {
const char * n = useFullName ? m->fieldName : m->shortFieldName
;
switch ( incType ) {
case NumberDouble:
b.append( n , incdouble ); break;
case NumberLong:
b.append( n , inclong ); break;
case NumberInt:
b.append( n , incint ); break;
default:
verify(0);
}
}
string toString() const;
template< class Builder >
void handleRename( Builder &newObjBuilder, const char *shortFieldNa
me );
};
/** /**
* this is used to hold state, meta data while applying a ModSet to a B * takes the from document and returns a new document
SONObj * after apply all the operators
* the goal is to make ModSet const so its re-usable * e.g.
* applyUpdateOperators( BSON( "x" << 1 ) , BSON( "$inc" << BSON( "x"
<< 1 ) ) );
* returns: { x : 2 }
*/ */
class ModSetState : boost::noncopyable { BSONObj applyUpdateOperators( const BSONObj& from, const BSONObj& opera
typedef map<string,shared_ptr<ModState>,LexNumCmp> ModStateHolder; tors );
typedef pair<const ModStateHolder::iterator,const ModStateHolder::i
terator> ModStateRange;
const BSONObj& _obj;
ModStateHolder _mods;
bool _inPlacePossible;
BSONObj _newFromMods; // keep this data alive, as oplog generation
may depend on it
ModSetState( const BSONObj& obj )
: _obj( obj ) , _mods( LexNumCmp( true ) ) , _inPlacePossible(t
rue) {
}
/**
* @return if in place is still possible
*/
bool amIInPlacePossible( bool inPlacePossible ) {
if ( ! inPlacePossible )
_inPlacePossible = false;
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 >
void createNewFromMods( const string& root , Builder& b , BSONItera
torSorted& es ,
const ModStateRange& modRange , const LexNum
Cmp& lexNumCmp );
template< class Builder >
void _appendNewFromMods( const string& root , ModState& m , Builder
& b , set<string>& onedownseen );
template< class Builder >
void appendNewFromMod( ModState& ms , Builder& b ) {
if ( ms.dontApply ) {
return;
}
//const Mod& m = *(ms.m); // HACK
Mod& m = *((Mod*)(ms.m)); // HACK
switch ( m.op ) {
case Mod::PUSH: {
if ( m.isEach() ) {
b.appendArray( m.shortFieldName, m.getEach() );
} else {
BSONObjBuilder arr( b.subarrayStart( m.shortFieldName )
);
arr.appendAs( m.elt, "0" );
arr.done();
}
break;
}
case Mod::ADDTOSET: {
if ( m.isEach() ) {
// Remove any duplicates in given array
BSONObjBuilder arr( b.subarrayStart( m.shortFieldName )
);
BSONElementSet toadd;
m.parseEach( toadd );
BSONObjIterator i( m.getEach() );
int n = 0;
while ( i.more() ) {
BSONElement e = i.next();
if ( toadd.count(e) ) {
arr.appendAs( e , BSONObjBuilder::numStr( n++ )
);
toadd.erase( e );
}
}
arr.done();
}
else {
BSONObjBuilder arr( b.subarrayStart( m.shortFieldName )
);
arr.appendAs( m.elt, "0" );
arr.done();
}
break;
}
case Mod::PUSH_ALL: {
b.appendAs( m.elt, m.shortFieldName );
break;
}
case Mod::UNSET:
case Mod::PULL:
case Mod::PULL_ALL:
// no-op b/c unset/pull of nothing does nothing
break;
case Mod::INC:
ms.fixedOpName = "$set";
case Mod::SET: {
m._checkForAppending( m.elt );
b.appendAs( m.elt, m.shortFieldName );
break;
}
// shouldn't see RENAME_FROM here
case Mod::RENAME_TO:
ms.handleRename( b, m.shortFieldName );
break;
default:
stringstream ss;
ss << "unknown mod in appendNewFromMod: " << m.op;
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:
bool canApplyInPlace() const {
return _inPlacePossible;
}
/**
* modified underlying _obj
* @param isOnDisk - true means this is an on disk object, and this
update needs to be made durable
*/
void applyModsInPlace( bool isOnDisk );
BSONObj createNewFromMods();
// re-writing for oplog
bool needOpLogRewrite() const {
for ( ModStateHolder::const_iterator i = _mods.begin(); i != _m
ods.end(); i++ )
if ( i->second->needOpLogRewrite() )
return true;
return false;
}
BSONObj getOpLogRewrite() const {
BSONObjBuilder b;
for ( ModStateHolder::const_iterator i = _mods.begin(); i != _m
ods.end(); i++ )
i->second->appendForOpLog( b );
return b.obj();
}
bool haveArrayDepMod() const {
for ( ModStateHolder::const_iterator i = _mods.begin(); i != _m
ods.end(); i++ )
if ( i->second->m->arrayDep() )
return true;
return false;
}
void appendSizeSpecForArrayDepMods( BSONObjBuilder &b ) const {
for ( ModStateHolder::const_iterator i = _mods.begin(); i != _m
ods.end(); i++ ) {
const ModState& m = *i->second;
if ( m.m->arrayDep() ) {
if ( m.pushStartSize == -1 )
b.appendNull( m.fieldName() );
else
b << m.fieldName() << BSON( "$size" << m.pushStartS
ize );
}
}
}
string toString() const;
friend class ModSet;
};
} } // namespace mongo
 End of changes. 14 change blocks. 
693 lines changed or deleted 32 lines changed or added


 util.h   util.h 
skipping to change at line 30 skipping to change at line 30
#include "mongo/pch.h" #include "mongo/pch.h"
#include "mongo/db/jsobj.h" #include "mongo/db/jsobj.h"
#include "mongo/util/mongoutils/str.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 {
//
// ShardChunkVersions consist of a major/minor version scoped to a vers
ion epoch
//
struct ShardChunkVersion { struct ShardChunkVersion {
union { union {
struct { struct {
int _minor; int _minor;
int _major; int _major;
}; };
unsigned long long _combined; unsigned long long _combined;
}; };
OID _epoch;
ShardChunkVersion( int major=0, int minor=0 ) ShardChunkVersion() : _minor(0), _major(0), _epoch(OID()) {}
: _minor(minor),_major(major) {
}
ShardChunkVersion( unsigned long long ll ) //
: _combined( ll ) { // Constructors shouldn't have default parameters here, since it's
vital we track from
// here on the epochs of versions, even if not used.
//
ShardChunkVersion( int major, int minor, const OID& epoch )
: _minor(minor),_major(major), _epoch(epoch) {
} }
ShardChunkVersion( const BSONElement& e ) { ShardChunkVersion( unsigned long long ll, const OID& epoch )
if ( e.type() == Date || e.type() == Timestamp ) { : _combined( ll ), _epoch(epoch) {
_combined = e._numberLong();
}
else if ( e.eoo() ) {
_combined = 0;
}
else {
_combined = 0;
log() << "ShardChunkVersion can't handle type (" << (int)(e
.type()) << ") " << e << endl;
verify(0);
}
} }
void inc( bool major ) { void inc( bool major ) {
if ( major ) if ( major )
incMajor(); incMajor();
else else
incMinor(); incMinor();
} }
void incMajor() { void incMajor() {
_major++; _major++;
_minor = 0; _minor = 0;
} }
void incMinor() { void incMinor() {
_minor++; _minor++;
} }
// Incrementing an epoch creates a new, randomly generated identifi
er
void incEpoch() {
_epoch = OID::gen();
_major = 0;
_minor = 0;
}
// Note: this shouldn't be used as a substitute for version except
in specific cases -
// epochs make versions more complex
unsigned long long toLong() const { unsigned long long toLong() const {
return _combined; return _combined;
} }
bool isSet() const { bool isSet() const {
return _combined > 0; return _combined > 0;
} }
bool isEpochSet() const {
return _epoch.isSet();
}
string toString() const { string toString() const {
stringstream ss; stringstream ss;
ss << _major << "|" << _minor; // Similar to month/day/year. For the most part when debugging
, we care about major
// so it's first
ss << _major << "|" << _minor << "||" << _epoch;
return ss.str(); return ss.str();
} }
int majorVersion() const { return _major; } int majorVersion() const { return _major; }
int minorVersion() const { return _minor; } int minorVersion() const { return _minor; }
OID epoch() const { return _epoch; }
operator unsigned long long() const { return _combined; } //
// Explicit comparison operators - versions with epochs have non-tr
ivial comparisons.
// > < operators do not check epoch cases. Generally if using == w
e need to handle
// more complex cases.
//
ShardChunkVersion& operator=( const BSONElement& elem ) { bool operator>( const ShardChunkVersion& otherVersion ) const {
switch ( elem.type() ) { return this->_combined > otherVersion._combined;
case Timestamp: }
case NumberLong:
case Date: bool operator>=( const ShardChunkVersion& otherVersion ) const {
_combined = elem._numberLong(); return this->_combined >= otherVersion._combined;
break; }
case EOO:
_combined = 0; bool operator<( const ShardChunkVersion& otherVersion ) const {
break; return this->_combined < otherVersion._combined;
default: }
massert( 13657 , mongoutils::str::stream() << "unknown type
for ShardChunkVersion: " << elem , 0 ); bool operator<=( const ShardChunkVersion& otherVersion ) const {
return this->_combined < otherVersion._combined;
}
//
// Equivalence comparison types.
//
// Can we write to this data and not have a problem?
bool isWriteCompatibleWith( const ShardChunkVersion& otherVersion )
const {
if( ! hasCompatibleEpoch( otherVersion ) ) return false;
return otherVersion._major == _major;
}
// Is this the same version?
bool isEquivalentTo( const ShardChunkVersion& otherVersion ) const
{
if( ! hasCompatibleEpoch( otherVersion ) ) return false;
return otherVersion._combined == _combined;
}
// Is this in the same epoch?
bool hasCompatibleEpoch( const ShardChunkVersion& otherVersion ) co
nst {
return hasCompatibleEpoch( otherVersion._epoch );
}
bool hasCompatibleEpoch( const OID& otherEpoch ) const {
// TODO : Change logic from eras are not-unequal to eras are eq
ual
if( otherEpoch.isSet() && _epoch.isSet() && otherEpoch != _epoc
h ) return false;
return true;
}
//
// BSON input/output
//
// The idea here is to make the BSON input style very flexible righ
t now, so we
// can then tighten it up in the next version. We can accept eithe
r a BSONObject field
// with version and epoch, or version and epoch in different fields
(either is optional).
// In this case, epoch always is stored in a field name of the vers
ion field name + "Epoch"
//
//
// { version : <TS> } and { version : [<TS>,<OID>] } format
//
static bool canParseBSON( const BSONElement& el, const string& pref
ix="" ){
bool canParse;
fromBSON( el, prefix, &canParse );
return canParse;
}
static ShardChunkVersion fromBSON( const BSONElement& el, const str
ing& prefix="" ){
bool canParse;
return fromBSON( el, prefix, &canParse );
}
static ShardChunkVersion fromBSON( const BSONElement& el,
const string& prefix,
bool* canParse )
{
*canParse = true;
int type = el.type();
if( type == Array ){
return fromBSON( BSONArray( el.Obj() ), canParse );
} }
return *this;
if( type == jstOID ){
return ShardChunkVersion( 0, 0, el.OID() );
}
if( el.isNumber() ){
return ShardChunkVersion( static_cast<unsigned long long>(
el.numberLong() ), OID() );
}
if( type == Timestamp || type == Date ){
return ShardChunkVersion( el._numberLong(), OID() );
}
// Note - we used to throw here, we can't anymore b/c debug bui
lds will be unhappy
warning() << "can't load version from element type (" << (int)(
el.type()) << ") "
<< el << endl;
*canParse = false;
return ShardChunkVersion( 0, OID() );
}
//
// { version : <TS>, versionEpoch : <OID> } object format
//
static bool canParseBSON( const BSONObj& obj, const string& prefix=
"" ){
bool canParse;
fromBSON( obj, prefix, &canParse );
return canParse;
}
static ShardChunkVersion fromBSON( const BSONObj& obj, const string
& prefix="" ){
bool canParse;
return fromBSON( obj, prefix, &canParse );
}
static ShardChunkVersion fromBSON( const BSONObj& obj,
const string& prefixIn,
bool* canParse )
{
*canParse = true;
string prefix = prefixIn;
if( prefixIn == "" && ! obj[ "version" ].eoo() ){
prefix = (string)"version";
}
else if( prefixIn == "" && ! obj[ "lastmod" ].eoo() ){
prefix = (string)"lastmod";
}
ShardChunkVersion version = fromBSON( obj[ prefix ], prefixIn,
canParse );
if( obj[ prefix + "Epoch" ].type() == jstOID ){
version._epoch = obj[ prefix + "Epoch" ].OID();
*canParse = true;
}
return version;
}
//
// { version : [<TS>, <OID>] } format
//
static bool canParseBSON( const BSONArray& arr ){
bool canParse;
fromBSON( arr, &canParse );
return canParse;
}
static ShardChunkVersion fromBSON( const BSONArray& arr ){
bool canParse;
return fromBSON( arr, &canParse );
} }
static ShardChunkVersion fromBSON( const BSONArray& arr,
bool* canParse )
{
*canParse = false;
ShardChunkVersion version;
BSONObjIterator it( arr );
if( ! it.more() ) return version;
version = fromBSON( it.next(), "", canParse );
if( ! canParse ) return version;
*canParse = true;
if( ! it.more() ) return version;
BSONElement next = it.next();
if( next.type() != jstOID ) return version;
version._epoch = next.OID();
return version;
}
//
// Currently our BSON output is to two different fields, to cleanly
work with older
// versions that know nothing about epochs.
//
BSONObj toBSON( const string& prefixIn="" ) const {
BSONObjBuilder b;
string prefix = prefixIn;
if( prefix == "" ) prefix = "version";
b.appendTimestamp( prefix, _combined );
b.append( prefix + "Epoch", _epoch );
return b.obj();
}
void addToBSON( BSONObjBuilder& b, const string& prefix="" ) const
{
b.appendElements( toBSON( prefix ) );
}
void addEpochToBSON( BSONObjBuilder& b, const string& prefix="" ) c
onst {
b.append( prefix + "Epoch", _epoch );
}
}; };
inline ostream& operator<<( ostream &s , const ShardChunkVersion& v) { inline ostream& operator<<( ostream &s , const ShardChunkVersion& v) {
s << v._major << "|" << v._minor; s << v.toString();
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 de, ShardChunkVersion received, ShardChunkVersion wanted, bool justConnecti on = false ) StaleConfigException( const string& ns , const string& raw , int co de, ShardChunkVersion received, ShardChunkVersion wanted, bool justConnecti on = false )
: AssertionException( : AssertionException(
skipping to change at line 138 skipping to change at line 342
", " << ( code == SendStaleCon figCode ? "send" : "recv" ) << " )", ", " << ( code == SendStaleCon figCode ? "send" : "recv" ) << " )",
code ), code ),
_justConnection(justConnection) , _justConnection(justConnection) ,
_ns(ns), _ns(ns),
_received( received ), _received( received ),
_wanted( wanted ) _wanted( wanted )
{} {}
// Preferred if we're rebuilding this from a thrown exception // Preferred if we're rebuilding this from a thrown exception
StaleConfigException( const string& raw , int code, const BSONObj& error, bool justConnection = false ) StaleConfigException( const string& raw , int code, const BSONObj& error, bool justConnection = false )
: AssertionException( : AssertionException( mongoutils::str::stream()
mongoutils::str::stream() << raw << " ( ns : " << error << raw << " ( ns : " << ( error["ns"].type() == String ? er
["ns"].String() << // Note, this will fail if we don't have a ns ror["ns"].String() : string("<unknown>") )
", received : " << ShardChunkV << ", received : " << ShardChunkVersion::fromBSON( error, "
ersion( error["vReceived"] ).toString() << vReceived" ).toString()
", wanted : " << ShardChunkVer << ", wanted : " << ShardChunkVersion::fromBSON( error, "vW
sion( error["vWanted"] ).toString() << anted" ).toString()
", " << ( code == SendStaleCon << ", " << ( code == SendStaleConfigCode ? "send" : "recv"
figCode ? "send" : "recv" ) << " )", ) << " )",
code ), code ),
_justConnection(justConnection) , _justConnection(justConnection) ,
_ns( error["ns"].String() ), // For legacy reasons, we may not always get a namespace here
_received( ShardChunkVersion( error["vReceived"] ) ), _ns( error["ns"].type() == String ? error["ns"].String() : ""
_wanted( ShardChunkVersion( error["vWanted"] ) ) ),
_received( ShardChunkVersion::fromBSON( error, "vReceived" )
),
_wanted( ShardChunkVersion::fromBSON( error, "vWanted" ) )
{} {}
StaleConfigException() : AssertionException( "", 0 ) {} // Needs message so when we trace all exceptions on construction we
get a useful
// message
StaleConfigException() :
AssertionException( "initializing empty stale config exception
object", 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; }
/**
* true if this exception would require a full reload of config dat
a to resolve
*/
bool requiresFullReload() const {
return ! _received.hasCompatibleEpoch( _wanted ) ||
_received.isSet() != _wanted.isSet();
}
static bool parse( const string& big , string& ns , string& raw ) { static bool parse( const string& big , string& ns , string& raw ) {
string::size_type start = big.find( '[' ); string::size_type start = big.find( '[' );
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 );
 End of changes. 18 change blocks. 
49 lines changed or deleted 296 lines changed or added


 windows_basic.h   windows_basic.h 
// windows_basic.h // windows_basic.h
#pragma once #pragma once
#if defined(_WIN32) #if defined(_WIN32)
// for rand_s() usage: // for rand_s() usage:
# define _CRT_RAND_S # define _CRT_RAND_S
# ifndef NOMINMAX # ifndef NOMINMAX
# define NOMINMAX # define NOMINMAX
# endif # endif
// tell windows.h not to include a bunch of headers // tell windows.h not to include a bunch of headers we don't need:
// we don't need:
# define WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN
# include "targetver.h" # include "mongo/targetver.h"
# include <winsock2.h> //this must be included before the first windows.h i nclude # include <winsock2.h> //this must be included before the first windows.h i nclude
# include <ws2tcpip.h> # include <ws2tcpip.h>
# include <wspiapi.h> # include <wspiapi.h>
# include <windows.h> # include <windows.h>
#endif #endif
 End of changes. 2 change blocks. 
3 lines changed or deleted 2 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/