allocator.h | allocator.h | |||
---|---|---|---|---|
skipping to change at line 34 | skipping to change at line 34 | |||
if ( x == 0 ) dbexit( EXIT_OOM_MALLOC , "malloc fails"); | if ( x == 0 ) dbexit( EXIT_OOM_MALLOC , "malloc fails"); | |||
return x; | return x; | |||
} | } | |||
inline void * ourrealloc(void *ptr, size_t size) { | inline void * ourrealloc(void *ptr, size_t size) { | |||
void *x = realloc(ptr, size); | void *x = realloc(ptr, size); | |||
if ( x == 0 ) dbexit( EXIT_OOM_REALLOC , "realloc fails"); | if ( x == 0 ) dbexit( EXIT_OOM_REALLOC , "realloc fails"); | |||
return x; | return x; | |||
} | } | |||
#define malloc mongo::ourmalloc | #define MONGO_malloc mongo::ourmalloc | |||
#define realloc mongo::ourrealloc | #define malloc MONGO_malloc | |||
#define MONGO_realloc mongo::ourrealloc | ||||
#define realloc MONGO_realloc | ||||
} // namespace mongo | } // namespace mongo | |||
End of changes. 1 change blocks. | ||||
2 lines changed or deleted | 4 lines changed or added | |||
assert_util.h | assert_util.h | |||
---|---|---|---|---|
skipping to change at line 139 | skipping to change at line 139 | |||
return "userassert:" + msg; | return "userassert:" + msg; | |||
} | } | |||
}; | }; | |||
class MsgAssertionException : public AssertionException { | class MsgAssertionException : public AssertionException { | |||
public: | public: | |||
MsgAssertionException(int c, const char *m) { | MsgAssertionException(int c, const char *m) { | |||
code = c; | code = c; | |||
msg = m; | msg = m; | |||
} | } | |||
MsgAssertionException(int c, const string& m) { | ||||
code = c; | ||||
msg = m; | ||||
} | ||||
virtual bool severe() { | virtual bool severe() { | |||
return false; | return false; | |||
} | } | |||
virtual string toString() const { | virtual string toString() const { | |||
return "massert:" + msg; | return "massert:" + msg; | |||
} | } | |||
}; | }; | |||
void asserted(const char *msg, const char *file, unsigned line); | void asserted(const char *msg, const char *file, unsigned line); | |||
void wasserted(const char *msg, const char *file, unsigned line); | void wasserted(const char *msg, const char *file, unsigned line); | |||
void uasserted(int msgid, const char *msg); | void uasserted(int msgid, const char *msg); | |||
inline void uasserted(int msgid , string msg) { uasserted(msgid, msg.c_ str()); } | inline void uasserted(int msgid , string msg) { uasserted(msgid, msg.c_ str()); } | |||
void uassert_nothrow(const char *msg); // reported via lasterror, but d on't throw exception | void uassert_nothrow(const char *msg); // reported via lasterror, but d on't throw exception | |||
void msgassertedNoTrace(int msgid, const char *msg); | ||||
void msgasserted(int msgid, const char *msg); | void msgasserted(int msgid, const char *msg); | |||
inline void msgasserted(int msgid, string msg) { msgasserted(msgid, msg .c_str()); } | inline void msgasserted(int msgid, string msg) { msgasserted(msgid, msg .c_str()); } | |||
#ifdef assert | #ifdef assert | |||
#undef assert | #undef assert | |||
#endif | #endif | |||
#define assert(_Expression) (void)( (!!(_Expression)) || (mongo::asserted(# | #define MONGO_assert(_Expression) (void)( (!!(_Expression)) || (mongo::asse | |||
_Expression, __FILE__, __LINE__), 0) ) | rted(#_Expression, __FILE__, __LINE__), 0) ) | |||
#define assert MONGO_assert | ||||
/* "user assert". if asserts, user did something wrong, not our code * / | /* "user assert". if asserts, user did something wrong, not our code * / | |||
//#define uassert( 10269 , _Expression) (void)( (!!(_Expression)) || (uasse | inline void uassert(unsigned msgid, string msg, bool expr) { | |||
rted(#_Expression, __FILE__, __LINE__), 0) ) | if( !expr ) uasserted(msgid, msg.c_str()); | |||
#define uassert(msgid, msg,_Expression) (void)( (!!(_Expression)) || (mongo | } | |||
::uasserted(msgid, msg), 0) ) | ||||
#define xassert(_Expression) (void)( (!!(_Expression)) || (mongo::asserted( | template<class T> | |||
#_Expression, __FILE__, __LINE__), 0) ) | inline void uassert(unsigned msgid, string msg, const T&t , bool expr) | |||
{ | ||||
if( !expr ){ | ||||
stringstream ss; | ||||
ss << msg << " " << t.toString(); | ||||
uasserted(msgid, ss.str()); | ||||
} | ||||
} | ||||
#define yassert 1 | inline void uassert(unsigned msgid, const char * msg, bool expr) { | |||
if( !expr ) uasserted(msgid, msg); | ||||
} | ||||
/* warning only - keeps going */ | /* warning only - keeps going */ | |||
#define wassert(_Expression) (void)( (!!(_Expression)) || (mongo::wasserted | #define MONGO_wassert(_Expression) (void)( (!!(_Expression)) || (mongo::was | |||
(#_Expression, __FILE__, __LINE__), 0) ) | serted(#_Expression, __FILE__, __LINE__), 0) ) | |||
#define wassert MONGO_wassert | ||||
/* display a message, no context, and throw assertionexception | /* display a message, no context, and throw assertionexception | |||
easy way to throw an exception and log something without our stack t race | easy way to throw an exception and log something without our stack t race | |||
display happening. | display happening. | |||
*/ | */ | |||
#define massert(msgid, msg,_Expression) (void)( (!!(_Expression)) || (mongo | inline void massert(unsigned msgid, string msg, bool expr) { | |||
::msgasserted(msgid, msg), 0) ) | if( !expr) msgasserted(msgid, msg.c_str()); | |||
} | ||||
inline void massert(unsigned msgid, const char * msg, bool expr) { | ||||
if( !expr) msgasserted(msgid, msg); | ||||
} | ||||
/* dassert is 'debug assert' -- might want to turn off for production a s these | /* dassert is 'debug assert' -- might want to turn off for production a s these | |||
could be slow. | could be slow. | |||
*/ | */ | |||
#if defined(_DEBUG) | #if defined(_DEBUG) | |||
#define dassert assert | # define MONGO_dassert assert | |||
#else | #else | |||
#define dassert(x) | # define MONGO_dassert(x) | |||
#endif | #endif | |||
#define dassert MONGO_dassert | ||||
// some special ids that we want to duplicate | // some special ids that we want to duplicate | |||
// > 10000 asserts | // > 10000 asserts | |||
// < 10000 UserException | // < 10000 UserException | |||
#define ASSERT_ID_DUPKEY 11000 | enum { ASSERT_ID_DUPKEY = 11000 }; | |||
/* throws a uassertion with an appropriate msg */ | ||||
void streamNotGood( int code , string msg , std::ios& myios ); | void streamNotGood( int code , string msg , std::ios& myios ); | |||
#define ASSERT_STREAM_GOOD(msgid,msg,stream) (void)( (!!((stream).good())) | inline void assertStreamGood(unsigned msgid, string msg, std::ios& myio | |||
|| (mongo::streamNotGood(msgid, msg, stream), 0) ) | s) { | |||
if( !myios.good() ) streamNotGood(msgid, msg, myios); | ||||
} | ||||
string demangleName( const type_info& typeinfo ); | ||||
} // namespace mongo | } // namespace mongo | |||
#define BOOST_CHECK_EXCEPTION( expression ) \ | #define BOOST_CHECK_EXCEPTION MONGO_BOOST_CHECK_EXCEPTION | |||
#define MONGO_BOOST_CHECK_EXCEPTION( expression ) \ | ||||
try { \ | try { \ | |||
expression; \ | expression; \ | |||
} catch ( const std::exception &e ) { \ | } catch ( const std::exception &e ) { \ | |||
problem() << "caught boost exception: " << e.what() << endl; \ | problem() << "caught boost exception: " << e.what() << endl; \ | |||
assert( false ); \ | assert( false ); \ | |||
} catch ( ... ) { \ | } catch ( ... ) { \ | |||
massert( 10437 , "unknown boost failed" , false ); \ | massert( 10437 , "unknown boost failed" , false ); \ | |||
} | } | |||
#define DESTRUCTOR_GUARD( expression ) \ | #define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD | |||
#define MONGO_DESTRUCTOR_GUARD( expression ) \ | ||||
try { \ | try { \ | |||
expression; \ | expression; \ | |||
} catch ( const std::exception &e ) { \ | } catch ( const std::exception &e ) { \ | |||
problem() << "caught exception (" << e.what() << ") in destructor ( " << __FUNCTION__ << ")" << endl; \ | problem() << "caught exception (" << e.what() << ") in destructor ( " << __FUNCTION__ << ")" << endl; \ | |||
} catch ( ... ) { \ | } catch ( ... ) { \ | |||
problem() << "caught unknown exception in destructor (" << __FUNCTI ON__ << ")" << endl; \ | problem() << "caught unknown exception in destructor (" << __FUNCTI ON__ << ")" << endl; \ | |||
} | } | |||
End of changes. 16 change blocks. | ||||
20 lines changed or deleted | 47 lines changed or added | |||
atomic_int.h | atomic_int.h | |||
---|---|---|---|---|
skipping to change at line 25 | skipping to change at line 25 | |||
* See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | |||
* limitations under the License. | * limitations under the License. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#if defined(_WIN32) | #if defined(_WIN32) | |||
# include <windows.h> | # include <windows.h> | |||
#endif | #endif | |||
namespace mongo{ | namespace mongo { | |||
struct AtomicUInt{ | struct AtomicUInt{ | |||
AtomicUInt() : x(0) {} | AtomicUInt() : x(0) {} | |||
AtomicUInt(unsigned z) : x(z) { } | AtomicUInt(unsigned z) : x(z) { } | |||
volatile unsigned x; | volatile unsigned x; | |||
operator unsigned() const { | operator unsigned() const { | |||
return x; | return x; | |||
} | } | |||
inline AtomicUInt operator++(); // ++prefix | inline AtomicUInt operator++(); // ++prefix | |||
inline AtomicUInt operator++(int);// postfix++ | inline AtomicUInt operator++(int);// postfix++ | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
btree.h | btree.h | |||
---|---|---|---|---|
skipping to change at line 21 | skipping to change at line 21 | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | * GNU Affero General Public License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Licen se | * You should have received a copy of the GNU Affero General Public Licen se | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "jsobj.h" | #include "jsobj.h" | |||
#include "diskloc.h" | #include "diskloc.h" | |||
#include "pdfile.h" | #include "pdfile.h" | |||
namespace mongo { | namespace mongo { | |||
#pragma pack(1) | #pragma pack(1) | |||
struct _KeyNode { | struct _KeyNode { | |||
DiskLoc prevChildBucket; // the lchild | DiskLoc prevChildBucket; // the lchild | |||
skipping to change at line 86 | skipping to change at line 86 | |||
#pragma pack(1) | #pragma pack(1) | |||
/* this class is all about the storage management */ | /* this class is all about the storage management */ | |||
class BucketBasics { | class BucketBasics { | |||
friend class BtreeBuilder; | friend class BtreeBuilder; | |||
friend class KeyNode; | friend class KeyNode; | |||
public: | public: | |||
void dumpTree(DiskLoc thisLoc, const BSONObj &order); | void dumpTree(DiskLoc thisLoc, const BSONObj &order); | |||
bool isHead() { return parent.isNull(); } | bool isHead() { return parent.isNull(); } | |||
void assertValid(const BSONObj &order, bool force = false); | void assertValid(const Ordering &order, bool force = false); | |||
void assertValid(const BSONObj &orderObj, bool force = false) { | ||||
return assertValid(Ordering::make(orderObj),force); | ||||
} | ||||
int fullValidate(const DiskLoc& thisLoc, const BSONObj &order); /* traverses everything */ | int fullValidate(const DiskLoc& thisLoc, const BSONObj &order); /* traverses everything */ | |||
KeyNode keyNode(int i) const { | KeyNode keyNode(int i) const { | |||
if ( i >= n ){ | if ( i >= n ){ | |||
massert( 13000 , (string)"invalid keyNode: " + BSON( "i" < < i << "n" << n ).jsonString() , i < n ); | massert( 13000 , (string)"invalid keyNode: " + BSON( "i" < < i << "n" << n ).jsonString() , i < n ); | |||
} | } | |||
return KeyNode(*this, k(i)); | return KeyNode(*this, k(i)); | |||
} | } | |||
protected: | protected: | |||
skipping to change at line 109 | skipping to change at line 112 | |||
char * dataAt(short ofs) { | char * dataAt(short ofs) { | |||
return data + ofs; | return data + ofs; | |||
} | } | |||
void init(); // initialize a new node | void init(); // initialize a new node | |||
/* returns false if node is full and must be split | /* returns false if node is full and must be split | |||
keypos is where to insert -- inserted after that key #. so keyp os=0 is the leftmost one. | keypos is where to insert -- inserted after that key #. so keyp os=0 is the leftmost one. | |||
*/ | */ | |||
bool basicInsert(const DiskLoc& thisLoc, int keypos, const DiskLoc& recordLoc, const BSONObj& key, const BSONObj &order); | bool basicInsert(const DiskLoc& thisLoc, int keypos, const DiskLoc& recordLoc, const BSONObj& key, const Ordering &order); | |||
/** | /** | |||
* @return true if works, false if not enough space | * @return true if works, false if not enough space | |||
*/ | */ | |||
bool _pushBack(const DiskLoc& recordLoc, BSONObj& key, const BSONOb | bool _pushBack(const DiskLoc& recordLoc, BSONObj& key, const Orderi | |||
j &order, DiskLoc prevChild); | ng &order, DiskLoc prevChild); | |||
void pushBack(const DiskLoc& recordLoc, BSONObj& key, const BSONObj | void pushBack(const DiskLoc& recordLoc, BSONObj& key, const Orderin | |||
&order, DiskLoc prevChild){ | g &order, DiskLoc prevChild){ | |||
bool ok = _pushBack( recordLoc , key , order , prevChild ); | bool ok = _pushBack( recordLoc , key , order , prevChild ); | |||
assert(ok); | assert(ok); | |||
} | } | |||
void popBack(DiskLoc& recLoc, BSONObj& key); | void popBack(DiskLoc& recLoc, BSONObj& key); | |||
void _delKeyAtPos(int keypos); // low level version that doesn't de al with child ptrs. | void _delKeyAtPos(int keypos); // low level version that doesn't de al with child ptrs. | |||
/* !Packed means there is deleted fragment space within the bucket. | /* !Packed means there is deleted fragment space within the bucket. | |||
We "repack" when we run out of space before considering the node | We "repack" when we run out of space before considering the node | |||
to be full. | to be full. | |||
*/ | */ | |||
enum Flags { Packed=1 }; | enum Flags { Packed=1 }; | |||
DiskLoc& childForPos(int p) { | DiskLoc& childForPos(int p) { | |||
return p == n ? nextChild : k(p).prevChildBucket; | return p == n ? nextChild : k(p).prevChildBucket; | |||
} | } | |||
int totalDataSize() const; | int totalDataSize() const; | |||
void pack( const BSONObj &order ); | void pack( const Ordering &order ); | |||
void setNotPacked(); | void setNotPacked(); | |||
void setPacked(); | void setPacked(); | |||
int _alloc(int bytes); | int _alloc(int bytes); | |||
void _unalloc(int bytes); | void _unalloc(int bytes); | |||
void truncateTo(int N, const BSONObj &order); | void truncateTo(int N, const Ordering &order); | |||
void markUnused(int keypos); | void markUnused(int keypos); | |||
/* BtreeBuilder uses the parent var as a temp place to maintain a l inked list chain. | /* BtreeBuilder uses the parent var as a temp place to maintain a l inked list chain. | |||
we use tempNext() when we do that to be less confusing. (one mig ht have written a union in C) | we use tempNext() when we do that to be less confusing. (one mig ht have written a union in C) | |||
*/ | */ | |||
DiskLoc& tempNext() { return parent; } | DiskLoc& tempNext() { return parent; } | |||
public: | public: | |||
DiskLoc parent; | DiskLoc parent; | |||
string bucketSummary() const { | string bucketSummary() const { | |||
stringstream ss; | stringstream ss; | |||
ss << " Bucket info:" << endl; | ss << " Bucket info:" << endl; | |||
ss << " n: " << n << endl; | ss << " n: " << n << endl; | |||
ss << " parent: " << parent.toString() << endl; | ss << " parent: " << parent.toString() << endl; | |||
ss << " nextChild: " << parent.toString() << endl; | ss << " nextChild: " << parent.toString() << endl; | |||
ss << " Size: " << _Size << " flags:" << flags << endl; | ss << " flags:" << flags << endl; | |||
ss << " emptySize: " << emptySize << " topSize: " << topSize << endl; | ss << " emptySize: " << emptySize << " topSize: " << topSize << endl; | |||
return ss.str(); | return ss.str(); | |||
} | } | |||
bool isUsed( int i ) const { | bool isUsed( int i ) const { | |||
return k(i).isUsed(); | return k(i).isUsed(); | |||
} | } | |||
protected: | protected: | |||
void _shape(int level, stringstream&); | void _shape(int level, stringstream&); | |||
DiskLoc nextChild; // child bucket off and to the right of the high est key. | DiskLoc nextChild; // child bucket off and to the right of the high est key. | |||
int _Size; // total size of this btree node in bytes. constant. | ||||
private: | ||||
unsigned short _wasSize; // can be reused, value is 8192 in current | ||||
pdfile version Apr2010 | ||||
unsigned short _reserved1; // zero | ||||
protected: | ||||
int Size() const; | int Size() const; | |||
int flags; | int flags; | |||
int emptySize; // size of the empty region | int emptySize; // size of the empty region | |||
int topSize; // size of the data at the top of the bucket (keys are at the beginning or 'bottom') | int topSize; // size of the data at the top of the bucket (keys are at the beginning or 'bottom') | |||
int n; // # of keys so far. | int n; // # of keys so far. | |||
int reserved; | int reserved; | |||
const _KeyNode& k(int i) const { | const _KeyNode& k(int i) const { | |||
return ((_KeyNode*)data)[i]; | return ((_KeyNode*)data)[i]; | |||
} | } | |||
_KeyNode& k(int i) { | _KeyNode& k(int i) { | |||
skipping to change at line 194 | skipping to change at line 202 | |||
friend class BtreeCursor; | friend class BtreeCursor; | |||
public: | public: | |||
void dump(); | void dump(); | |||
/* @return true if key exists in index | /* @return true if key exists in index | |||
order - indicates order of keys in the index. this is basically the index's key pattern, e.g.: | order - indicates order of keys in the index. this is basically the index's key pattern, e.g.: | |||
BSONObj order = ((IndexDetails&)idx).keyPattern(); | BSONObj order = ((IndexDetails&)idx).keyPattern(); | |||
likewise below in bt_insert() etc. | likewise below in bt_insert() etc. | |||
*/ | */ | |||
bool exists(const IndexDetails& idx, DiskLoc thisLoc, const BSONObj & key, BSONObj order); | bool exists(const IndexDetails& idx, DiskLoc thisLoc, const BSONObj & key, const Ordering& order); | |||
bool wouldCreateDup( | bool wouldCreateDup( | |||
const IndexDetails& idx, DiskLoc thisLoc, | const IndexDetails& idx, DiskLoc thisLoc, | |||
const BSONObj& key, BSONObj order, | const BSONObj& key, const Ordering& order, | |||
DiskLoc self); | DiskLoc self); | |||
static DiskLoc addBucket(IndexDetails&); /* start a new index off, empty */ | static DiskLoc addBucket(IndexDetails&); /* start a new index off, empty */ | |||
void deallocBucket(const DiskLoc &thisLoc); // clear bucket memory, placeholder for deallocation | void deallocBucket(const DiskLoc &thisLoc); // clear bucket memory, placeholder for deallocation | |||
static void renameIndexNamespace(const char *oldNs, const char *new Ns); | static void renameIndexNamespace(const char *oldNs, const char *new Ns); | |||
int bt_insert(DiskLoc thisLoc, DiskLoc recordLoc, | int bt_insert(DiskLoc thisLoc, DiskLoc recordLoc, | |||
const BSONObj& key, const BSONObj &order, bool dupsAllow ed, | const BSONObj& key, const Ordering &order, bool dupsAllo wed, | |||
IndexDetails& idx, bool toplevel = true); | IndexDetails& idx, bool toplevel = true); | |||
bool unindex(const DiskLoc& thisLoc, IndexDetails& id, BSONObj& key , const DiskLoc& recordLoc); | bool unindex(const DiskLoc& thisLoc, IndexDetails& id, BSONObj& key , const DiskLoc& recordLoc); | |||
/* locate may return an "unused" key that is just a marker. so be careful. | /* locate may return an "unused" key that is just a marker. so be careful. | |||
looks for a key:recordloc pair. | looks for a key:recordloc pair. | |||
found - returns true if exact match found. note you can get bac k a position | found - returns true if exact match found. note you can get bac k a position | |||
result even if found is false. | result even if found is false. | |||
*/ | */ | |||
DiskLoc locate(const IndexDetails& , const DiskLoc& thisLoc, const BSONObj& key, const BSONObj &order, | DiskLoc locate(const IndexDetails& , const DiskLoc& thisLoc, const BSONObj& key, const Ordering &order, | |||
int& pos, bool& found, DiskLoc recordLoc, int direct ion=1); | int& pos, bool& found, DiskLoc recordLoc, int direct ion=1); | |||
/** | /** | |||
* find the first instance of the key | * find the first instance of the key | |||
* does not handle dups | * does not handle dups | |||
* returned DiskLock isNull if can't find anything with that | * returned DiskLock isNull if can't find anything with that | |||
*/ | */ | |||
DiskLoc findSingle( const IndexDetails& , const DiskLoc& thisLoc, c onst BSONObj& key ); | DiskLoc findSingle( const IndexDetails& , const DiskLoc& thisLoc, c onst BSONObj& key ); | |||
/* advance one key position in the index: */ | /* advance one key position in the index: */ | |||
skipping to change at line 246 | skipping to change at line 254 | |||
private: | private: | |||
void fixParentPtrs(const DiskLoc& thisLoc); | void fixParentPtrs(const DiskLoc& thisLoc); | |||
void delBucket(const DiskLoc& thisLoc, IndexDetails&); | void delBucket(const DiskLoc& thisLoc, IndexDetails&); | |||
void delKeyAtPos(const DiskLoc& thisLoc, IndexDetails& id, int p); | void delKeyAtPos(const DiskLoc& thisLoc, IndexDetails& id, int p); | |||
BSONObj keyAt(int keyOfs) { | BSONObj keyAt(int keyOfs) { | |||
return keyOfs >= n ? BSONObj() : keyNode(keyOfs).key; | return keyOfs >= n ? BSONObj() : keyNode(keyOfs).key; | |||
} | } | |||
static BtreeBucket* allocTemp(); /* caller must release with free() */ | static BtreeBucket* allocTemp(); /* caller must release with free() */ | |||
void insertHere(DiskLoc thisLoc, int keypos, | void insertHere(DiskLoc thisLoc, int keypos, | |||
DiskLoc recordLoc, const BSONObj& key, const BSONOb j &order, | DiskLoc recordLoc, const BSONObj& key, const Orderi ng &order, | |||
DiskLoc lchild, DiskLoc rchild, IndexDetails&); | DiskLoc lchild, DiskLoc rchild, IndexDetails&); | |||
int _insert(DiskLoc thisLoc, DiskLoc recordLoc, | int _insert(DiskLoc thisLoc, DiskLoc recordLoc, | |||
const BSONObj& key, const BSONObj &order, bool dupsAllo wed, | const BSONObj& key, const Ordering &order, bool dupsAll owed, | |||
DiskLoc lChild, DiskLoc rChild, IndexDetails&); | DiskLoc lChild, DiskLoc rChild, IndexDetails&); | |||
bool find(const IndexDetails& idx, const BSONObj& key, DiskLoc reco rdLoc, const BSONObj &order, int& pos, bool assertIfDup); | bool find(const IndexDetails& idx, const BSONObj& key, DiskLoc reco rdLoc, const Ordering &order, int& pos, bool assertIfDup); | |||
static void findLargestKey(const DiskLoc& thisLoc, DiskLoc& largest Loc, int& largestKey); | static void findLargestKey(const DiskLoc& thisLoc, DiskLoc& largest Loc, int& largestKey); | |||
public: | public: | |||
// simply builds and returns a dup key error message string | // simply builds and returns a dup key error message string | |||
static string dupKeyError( const IndexDetails& idx , const BSONObj& key ); | static string dupKeyError( const IndexDetails& idx , const BSONObj& key ); | |||
}; | }; | |||
class BtreeCursor : public Cursor { | class BtreeCursor : public Cursor { | |||
public: | public: | |||
BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int direction ); | BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int direction ); | |||
skipping to change at line 392 | skipping to change at line 400 | |||
BSONObj keyAtKeyOfs; // so we can tell if things moved around on us between the query and the getMore call | BSONObj keyAtKeyOfs; // so we can tell if things moved around on us between the query and the getMore call | |||
DiskLoc locAtKeyOfs; | DiskLoc locAtKeyOfs; | |||
BoundList bounds_; | BoundList bounds_; | |||
unsigned boundIndex_; | unsigned boundIndex_; | |||
const IndexSpec& _spec; | const IndexSpec& _spec; | |||
}; | }; | |||
#pragma pack() | #pragma pack() | |||
inline bool IndexDetails::hasKey(const BSONObj& key) { | inline bool IndexDetails::hasKey(const BSONObj& key) { | |||
return head.btree()->exists(*this, head, key, keyPattern()); | return head.btree()->exists(*this, head, key, Ordering::make(keyPat tern())); | |||
} | } | |||
inline bool IndexDetails::wouldCreateDup(const BSONObj& key, DiskLoc se lf) { | inline bool IndexDetails::wouldCreateDup(const BSONObj& key, DiskLoc se lf) { | |||
return head.btree()->wouldCreateDup(*this, head, key, keyPattern(), self); | return head.btree()->wouldCreateDup(*this, head, key, Ordering::mak e(keyPattern()), self); | |||
} | } | |||
/* build btree from the bottom up */ | /* build btree from the bottom up */ | |||
/* _ TODO dropDups */ | /* _ TODO dropDups */ | |||
class BtreeBuilder { | class BtreeBuilder { | |||
bool dupsAllowed; | bool dupsAllowed; | |||
IndexDetails& idx; | IndexDetails& idx; | |||
unsigned long long n; | unsigned long long n; | |||
BSONObj keyLast; | BSONObj keyLast; | |||
BSONObj order; | BSONObj order; | |||
Ordering ordering; | ||||
bool committed; | bool committed; | |||
DiskLoc cur, first; | DiskLoc cur, first; | |||
BtreeBucket *b; | BtreeBucket *b; | |||
void newBucket(); | void newBucket(); | |||
void buildNextLevel(DiskLoc); | void buildNextLevel(DiskLoc); | |||
public: | public: | |||
~BtreeBuilder(); | ~BtreeBuilder(); | |||
End of changes. 18 change blocks. | ||||
20 lines changed or deleted | 30 lines changed or added | |||
builder.h | builder.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 "../stdafx.h" | #include <string> | |||
#include <string.h> | #include <string.h> | |||
#include <stdio.h> | ||||
#include <boost/shared_ptr.hpp> | ||||
namespace mongo { | namespace mongo { | |||
class StringBuilder; | class StringBuilder; | |||
class BufBuilder { | class BufBuilder { | |||
public: | public: | |||
BufBuilder(int initsize = 512) : size(initsize) { | BufBuilder(int initsize = 512) : size(initsize) { | |||
if ( size > 0 ) { | if ( size > 0 ) { | |||
data = (char *) malloc(size); | data = (char *) malloc(size); | |||
assert(data); | assert(data != 0); | |||
} else { | } else { | |||
data = 0; | data = 0; | |||
} | } | |||
l = 0; | l = 0; | |||
} | } | |||
~BufBuilder() { | ~BufBuilder() { | |||
kill(); | kill(); | |||
} | } | |||
void kill() { | void kill() { | |||
skipping to change at line 94 | skipping to change at line 96 | |||
append<unsigned>(j); | append<unsigned>(j); | |||
} | } | |||
void append(bool j) { | void append(bool j) { | |||
append<bool>(j); | append<bool>(j); | |||
} | } | |||
void append(double j) { | void append(double j) { | |||
append<double>(j); | append<double>(j); | |||
} | } | |||
void append(const void *src, size_t len) { | void append(const void *src, size_t len) { | |||
memcpy(grow(len), src, len); | memcpy(grow((int) len), src, len); | |||
} | } | |||
void append(const char *str) { | void append(const char *str) { | |||
append((void*) str, strlen(str)+1); | append((void*) str, strlen(str)+1); | |||
} | } | |||
void append(const string &str) { | void append(const std::string &str) { | |||
append( (void *)str.c_str(), str.length() + 1 ); | append( (void *)str.c_str(), str.length() + 1 ); | |||
} | } | |||
void append( int val , int padding ){ | ||||
} | ||||
int len() const { | int len() const { | |||
return l; | return l; | |||
} | } | |||
void setlen( int newLen ){ | void setlen( int newLen ){ | |||
l = newLen; | l = newLen; | |||
} | } | |||
private: | private: | |||
/* returns the pre-grow write position */ | /* returns the pre-grow write position */ | |||
skipping to change at line 142 | skipping to change at line 140 | |||
return data + oldlen; | return data + oldlen; | |||
} | } | |||
char *data; | char *data; | |||
int l; | int l; | |||
int size; | int size; | |||
friend class StringBuilder; | friend class StringBuilder; | |||
}; | }; | |||
#if defined(_WIN32) | ||||
#pragma warning( disable : 4996 ) | ||||
#endif | ||||
class StringBuilder { | class StringBuilder { | |||
public: | public: | |||
StringBuilder( int initsize=256 ) | StringBuilder( int initsize=256 ) | |||
: _buf( initsize ){ | : _buf( initsize ){ | |||
} | } | |||
#define SBNUM(val,maxSize,macro) \ | #define SBNUM(val,maxSize,macro) \ | |||
int prev = _buf.l; \ | int prev = _buf.l; \ | |||
int z = sprintf( _buf.grow(maxSize) , macro , (val) ); \ | int z = sprintf( _buf.grow(maxSize) , macro , (val) ); \ | |||
_buf.l = prev + z; \ | _buf.l = prev + z; \ | |||
skipping to change at line 182 | skipping to change at line 184 | |||
StringBuilder& operator<<( unsigned long long x ){ | StringBuilder& operator<<( unsigned long long x ){ | |||
SBNUM( x , 22 , "%llu" ); | SBNUM( x , 22 , "%llu" ); | |||
} | } | |||
StringBuilder& operator<<( short x ){ | StringBuilder& operator<<( short x ){ | |||
SBNUM( x , 8 , "%hd" ); | SBNUM( x , 8 , "%hd" ); | |||
} | } | |||
StringBuilder& operator<<( char c ){ | StringBuilder& operator<<( char c ){ | |||
_buf.grow( 1 )[0] = c; | _buf.grow( 1 )[0] = c; | |||
return *this; | return *this; | |||
} | } | |||
#undef SBNUM | ||||
void append( const char * str ){ | void append( const char * str ){ | |||
int x = strlen( str ); | int x = (int) strlen( str ); | |||
memcpy( _buf.grow( x ) , str , x ); | memcpy( _buf.grow( x ) , str , x ); | |||
} | } | |||
StringBuilder& operator<<( const char * str ){ | StringBuilder& operator<<( const char * str ){ | |||
append( str ); | append( str ); | |||
return *this; | return *this; | |||
} | } | |||
StringBuilder& operator<<( const string& s ){ | StringBuilder& operator<<( const std::string& s ){ | |||
append( s.c_str() ); | append( s.c_str() ); | |||
return *this; | return *this; | |||
} | } | |||
// access | // access | |||
void reset( int maxSize = 0 ){ | void reset( int maxSize = 0 ){ | |||
_buf.reset( maxSize ); | _buf.reset( maxSize ); | |||
} | } | |||
string str(){ | std::string str(){ | |||
return string(_buf.data, _buf.l); | return std::string(_buf.data, _buf.l); | |||
} | } | |||
private: | private: | |||
BufBuilder _buf; | BufBuilder _buf; | |||
}; | }; | |||
} // namespace mongo | } // namespace mongo | |||
End of changes. 11 change blocks. | ||||
12 lines changed or deleted | 15 lines changed or added | |||
chunk.h | chunk.h | |||
---|---|---|---|---|
skipping to change at line 26 | skipping to change at line 26 | |||
* 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 "../stdafx.h" | #include "../pch.h" | |||
#include "../client/dbclient.h" | #include "../client/dbclient.h" | |||
#include "../client/model.h" | #include "../client/model.h" | |||
#include "../bson/util/atomic_int.h" | ||||
#include "shardkey.h" | #include "shardkey.h" | |||
#include <boost/utility.hpp> | #include "shard.h" | |||
#undef assert | ||||
#define assert xassert | ||||
namespace mongo { | namespace mongo { | |||
class DBConfig; | class DBConfig; | |||
class ChunkManager; | class ChunkManager; | |||
class ChunkObjUnitTest; | class ChunkObjUnitTest; | |||
typedef unsigned long long ShardChunkVersion; | typedef unsigned long long ShardChunkVersion; | |||
/** | /** | |||
skipping to change at line 64 | skipping to change at line 63 | |||
const BSONObj& getMin() const { return _min; } | const BSONObj& getMin() const { return _min; } | |||
const BSONObj& getMax() const { return _max; } | const BSONObj& getMax() const { return _max; } | |||
void setMin(const BSONObj& o){ | void setMin(const BSONObj& o){ | |||
_min = o; | _min = o; | |||
} | } | |||
void setMax(const BSONObj& o){ | void setMax(const BSONObj& o){ | |||
_max = o; | _max = o; | |||
} | } | |||
string getShard() const{ | Shard getShard() const{ | |||
return _shard; | return _shard; | |||
} | } | |||
void setShard( string shard ); | void setShard( const Shard& shard ); | |||
bool contains( const BSONObj& obj ) const; | bool contains( const BSONObj& obj ) const; | |||
string toString() const; | string toString() const; | |||
operator string() const { return toString(); } | operator string() const { return toString(); } | |||
friend ostream& operator << (ostream& out, const Chunk& c){ return (out << c.toString()); } | ||||
bool operator==(const Chunk& s) const; | bool operator==(const Chunk& s) const; | |||
bool operator!=(const Chunk& s) const{ | bool operator!=(const Chunk& s) const{ | |||
return ! ( *this == s ); | return ! ( *this == s ); | |||
} | } | |||
void getFilter( BSONObjBuilder& b ) const; | void getFilter( BSONObjBuilder& b ) const; | |||
BSONObj getFilter() const{ BSONObjBuilder b; getFilter( b ); return b.obj(); } | BSONObj getFilter() const{ BSONObjBuilder b; getFilter( b ); return b.obj(); } | |||
skipping to change at line 107 | skipping to change at line 107 | |||
* then we check the real size, and if its too big, we split | * then we check the real size, and if its too big, we split | |||
*/ | */ | |||
bool splitIfShould( long dataWritten ); | bool splitIfShould( long dataWritten ); | |||
/* | /* | |||
* moves either this shard or newShard if it makes sense too | * moves either this shard or newShard if it makes sense too | |||
* @return whether or not a shard was moved | * @return whether or not a shard was moved | |||
*/ | */ | |||
bool moveIfShould( Chunk * newShard = 0 ); | bool moveIfShould( Chunk * newShard = 0 ); | |||
bool moveAndCommit( const string& to , string& errmsg ); | bool moveAndCommit( const Shard& to , string& errmsg ); | |||
virtual const char * getNS(){ return "config.chunks"; } | virtual const char * getNS(){ return "config.chunks"; } | |||
virtual void serialize(BSONObjBuilder& to); | virtual void serialize(BSONObjBuilder& to); | |||
virtual void unserialize(const BSONObj& from); | virtual void unserialize(const BSONObj& from); | |||
virtual string modelServer(); | virtual string modelServer(); | |||
void appendShortVersion( const char * name , BSONObjBuilder& b ); | ||||
virtual void save( bool check=false ); | virtual void save( bool check=false ); | |||
void ensureIndex(); | void ensureIndex(); | |||
void _markModified(); | void _markModified(); | |||
static int MaxChunkSize; | static int MaxChunkSize; | |||
static string genID( const string& ns , const BSONObj& min ); | ||||
private: | private: | |||
// main shard info | // main shard info | |||
ChunkManager * _manager; | ChunkManager * _manager; | |||
ShardKeyPattern skey() const; | ShardKeyPattern skey() const; | |||
string _ns; | string _ns; | |||
BSONObj _min; | BSONObj _min; | |||
BSONObj _max; | BSONObj _max; | |||
string _shard; | Shard _shard; | |||
ShardChunkVersion _lastmod; | ShardChunkVersion _lastmod; | |||
bool _modified; | bool _modified; | |||
// transient stuff | // transient stuff | |||
long _dataWritten; | long _dataWritten; | |||
// methods, etc.. | // methods, etc.. | |||
skipping to change at line 165 | skipping to change at line 169 | |||
class ChunkManager { | class ChunkManager { | |||
public: | public: | |||
ChunkManager( DBConfig * config , string ns , ShardKeyPattern patte rn , bool unique ); | ChunkManager( DBConfig * config , string ns , ShardKeyPattern patte rn , bool unique ); | |||
virtual ~ChunkManager(); | virtual ~ChunkManager(); | |||
string getns(){ | string getns(){ | |||
return _ns; | return _ns; | |||
} | } | |||
int numChunks(){ return _chunks.size(); } | int numChunks(){ rwlock lk( _lock , false ); return _chunks.size(); | |||
Chunk* getChunk( int i ){ return _chunks[i]; } | } | |||
Chunk* getChunk( int i ){ rwlock lk( _lock , false ); return _chunk | ||||
s[i]; } | ||||
bool hasShardKey( const BSONObj& obj ); | bool hasShardKey( const BSONObj& obj ); | |||
Chunk& findChunk( const BSONObj& obj ); | Chunk& findChunk( const BSONObj& obj , bool retry = false ); | |||
Chunk* findChunkOnServer( const string& server ) const; | Chunk* findChunkOnServer( const Shard& shard ) const; | |||
ShardKeyPattern& getShardKey(){ return _key; } | ShardKeyPattern& getShardKey(){ return _key; } | |||
bool isUnique(){ return _unique; } | bool isUnique(){ return _unique; } | |||
/** | /** | |||
* makes sure the shard index is on all servers | * makes sure the shard index is on all servers | |||
*/ | */ | |||
void ensureIndex(); | void ensureIndex(); | |||
/** | /** | |||
* @return number of Chunk added to the vector | * @return number of Chunk added to the vector | |||
*/ | */ | |||
int getChunksForQuery( vector<Chunk*>& chunks , const BSONObj& quer y ); | int getChunksForQuery( vector<Chunk*>& chunks , const BSONObj& quer y ); | |||
void getAllServers( set<string>& allServers ); | /** | |||
* @return number of Shards added to the set | ||||
*/ | ||||
int getShardsForQuery( set<Shard>& shards , const BSONObj& query ); | ||||
void getAllShards( set<Shard>& all ); | ||||
void save(); | void save(); | |||
string toString() const; | string toString() const; | |||
operator string() const { return toString(); } | operator string() const { return toString(); } | |||
ShardChunkVersion getVersion( const string& server ) const; | ShardChunkVersion getVersion( const Shard& shard ) const; | |||
ShardChunkVersion getVersion() const; | ShardChunkVersion getVersion() const; | |||
/** | /** | |||
* this is just an increasing number of how many ChunkManagers we h ave so we know if something has been updated | * this is just an increasing number of how many ChunkManagers we h ave so we know if something has been updated | |||
*/ | */ | |||
unsigned long long getSequenceNumber(){ | unsigned long long getSequenceNumber(){ | |||
return _sequenceNumber; | return _sequenceNumber; | |||
} | } | |||
void drop(); | void drop(); | |||
private: | private: | |||
void _reload(); | ||||
void _load(); | ||||
DBConfig * _config; | DBConfig * _config; | |||
string _ns; | string _ns; | |||
ShardKeyPattern _key; | ShardKeyPattern _key; | |||
bool _unique; | bool _unique; | |||
vector<Chunk*> _chunks; | vector<Chunk*> _chunks; | |||
map<string,unsigned long long> _maxMarkers; | map<string,unsigned long long> _maxMarkers; | |||
typedef map<BSONObj,Chunk*,BSONObjCmp> ChunkMap; | typedef map<BSONObj,Chunk*,BSONObjCmp> ChunkMap; | |||
ChunkMap _chunkMap; | ChunkMap _chunkMap; // max -> Chunk | |||
unsigned long long _sequenceNumber; | unsigned long long _sequenceNumber; | |||
RWLock _lock; | ||||
friend class Chunk; | friend class Chunk; | |||
static unsigned long long NextSequenceNumber; | static AtomicUInt NextSequenceNumber; | |||
/** | ||||
* @return number of Chunk matching the query or -1 for all chunks. | ||||
*/ | ||||
int _getChunksForQuery( vector<Chunk*>& chunks , const BSONObj& que | ||||
ry ); | ||||
}; | }; | |||
// like BSONObjCmp. for use as an STL comparison functor | // like BSONObjCmp. for use as an STL comparison functor | |||
// key-order in "order" argument must match key-order in shardkey | // key-order in "order" argument must match key-order in shardkey | |||
class ChunkCmp { | class ChunkCmp { | |||
public: | public: | |||
ChunkCmp( const BSONObj &order = BSONObj() ) : _cmp( order ) {} | ChunkCmp( const BSONObj &order = BSONObj() ) : _cmp( order ) {} | |||
bool operator()( const Chunk &l, const Chunk &r ) const { | bool operator()( const Chunk &l, const Chunk &r ) const { | |||
return _cmp(l.getMin(), r.getMin()); | return _cmp(l.getMin(), r.getMin()); | |||
} | } | |||
End of changes. 18 change blocks. | ||||
16 lines changed or deleted | 39 lines changed or added | |||
client.h | client.h | |||
---|---|---|---|---|
skipping to change at line 27 | skipping to change at line 27 | |||
*/ | */ | |||
/* Client represents a connection to the database (the server-side) and cor responds | /* Client represents a connection to the database (the server-side) and cor responds | |||
to an open socket (or logical connection if pooling on sockets) from a c lient. | to an open socket (or logical connection if pooling on sockets) from a c lient. | |||
todo: switch to asio...this will fit nicely with that. | todo: switch to asio...this will fit nicely with that. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "security.h" | #include "security.h" | |||
#include "namespace.h" | #include "namespace.h" | |||
#include "lasterror.h" | #include "lasterror.h" | |||
#include "stats/top.h" | #include "stats/top.h" | |||
namespace mongo { | namespace mongo { | |||
class AuthenticationInfo; | class AuthenticationInfo; | |||
class Database; | class Database; | |||
class CurOp; | class CurOp; | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
clientcursor.h | clientcursor.h | |||
---|---|---|---|---|
skipping to change at line 27 | skipping to change at line 27 | |||
*/ | */ | |||
/* Cursor -- and its derived classes -- are our internal cursors. | /* Cursor -- and its derived classes -- are our internal cursors. | |||
ClientCursor is a wrapper that represents a cursorid from our database | ClientCursor is a wrapper that represents a cursorid from our database | |||
application's perspective. | application's perspective. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "cursor.h" | #include "cursor.h" | |||
#include "jsobj.h" | #include "jsobj.h" | |||
#include "../util/message.h" | #include "../util/message.h" | |||
#include "../util/background.h" | ||||
#include "diskloc.h" | #include "diskloc.h" | |||
#include "dbhelpers.h" | #include "dbhelpers.h" | |||
#include "matcher.h" | #include "matcher.h" | |||
#include "../client/dbclient.h" | #include "../client/dbclient.h" | |||
namespace mongo { | namespace mongo { | |||
typedef long long CursorId; /* passed to the client so it can send back on getMore */ | typedef long long CursorId; /* passed to the client so it can send back on getMore */ | |||
class Cursor; /* internal server cursor base class */ | class Cursor; /* internal server cursor base class */ | |||
class ClientCursor; | class ClientCursor; | |||
skipping to change at line 289 | skipping to change at line 290 | |||
void setDoingDeletes( bool doingDeletes ){ | void setDoingDeletes( bool doingDeletes ){ | |||
_doingDeletes = doingDeletes; | _doingDeletes = doingDeletes; | |||
} | } | |||
static unsigned byLocSize(); // just for diagnostics | static unsigned byLocSize(); // just for diagnostics | |||
static void informAboutToDeleteBucket(const DiskLoc& b); | static void informAboutToDeleteBucket(const DiskLoc& b); | |||
static void aboutToDelete(const DiskLoc& dl); | static void aboutToDelete(const DiskLoc& dl); | |||
}; | }; | |||
class ClientCursorMonitor : public BackgroundJob { | ||||
public: | ||||
void run(); | ||||
}; | ||||
extern ClientCursorMonitor clientCursorMonitor; | ||||
} // namespace mongo | } // namespace mongo | |||
End of changes. 3 change blocks. | ||||
1 lines changed or deleted | 9 lines changed or added | |||
cmdline.h | cmdline.h | |||
---|---|---|---|---|
skipping to change at line 19 | skipping to change at line 19 | |||
* 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 "../stdafx.h" | #include "../pch.h" | |||
namespace mongo { | namespace mongo { | |||
/* command line options | /* command line options | |||
*/ | */ | |||
/* concurrency: OK/READ */ | /* concurrency: OK/READ */ | |||
struct CmdLine { | struct CmdLine { | |||
int port; // --port | int port; // --port | |||
bool rest; // --rest | bool rest; // --rest | |||
string replSet; // --replSet <seedlist> | ||||
string source; // --source | string source; // --source | |||
string only; // --only | string only; // --only | |||
bool quiet; // --quiet | bool quiet; // --quiet | |||
bool notablescan; // --notablescan | bool notablescan; // --notablescan | |||
bool prealloc; // --noprealloc | bool prealloc; // --noprealloc | |||
bool smallfiles; // --smallfiles | bool smallfiles; // --smallfiles | |||
bool quota; // --quota | bool quota; // --quota | |||
int quotaFiles; // --quotaFiles | int quotaFiles; // --quotaFiles | |||
End of changes. 2 change blocks. | ||||
1 lines changed or deleted | 2 lines changed or added | |||
commands.h | commands.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 "../stdafx.h" | #include "../pch.h" | |||
#include "jsobj.h" | #include "jsobj.h" | |||
namespace mongo { | namespace mongo { | |||
class BSONObj; | class BSONObj; | |||
class BSONObjBuilder; | class BSONObjBuilder; | |||
class BufBuilder; | class BufBuilder; | |||
class Client; | class Client; | |||
// db "commands" (sent via db.$cmd.findOne(...)) | /** mongodb "commands" (sent via db.$cmd.findOne(...)) | |||
// subclass to make a command. | subclass to make a command. define a singleton object for it. | |||
*/ | ||||
class Command { | class Command { | |||
public: | public: | |||
enum LockType { READ = -1 , NONE = 0 , WRITE = 1 }; | enum LockType { READ = -1 , NONE = 0 , WRITE = 1 }; | |||
string name; | const string name; | |||
/* run the given command | /* run the given command | |||
implement this... | implement this... | |||
fromRepl - command is being invoked as part of replication synci ng. In this situation you | fromRepl - command is being invoked as part of replication synci ng. In this situation you | |||
normally do not want to log the command to the local oplog. | normally do not want to log the command to the local oplog. | |||
return value is true if succeeded. if false, set errmsg text. | return value is true if succeeded. if false, set errmsg text. | |||
*/ | */ | |||
virtual bool run(const char *ns, BSONObj& cmdObj, string& errmsg, B SONObjBuilder& result, bool fromRepl) = 0; | virtual bool run(const char *ns, BSONObj& cmdObj, string& errmsg, B SONObjBuilder& result, bool fromRepl) = 0; | |||
/* | /* | |||
note: logTheTop() MUST be false if READ | note: logTheTop() MUST be false if READ | |||
if NONE, can't use Client::Context setup | if NONE, can't use Client::Context setup | |||
use with caution | use with caution | |||
*/ | */ | |||
virtual LockType locktype() = 0; | virtual LockType locktype() const = 0; | |||
/* Return true if only the admin ns has privileges to run this comm and. */ | /* Return true if only the admin ns has privileges to run this comm and. */ | |||
virtual bool adminOnly() { | virtual bool adminOnly() const { | |||
return false; | return false; | |||
} | } | |||
void htmlHelp(stringstream&) const; | ||||
/* Like adminOnly, but even stricter: we must either be authenticat ed for admin db, | /* Like adminOnly, but even stricter: we must either be authenticat ed for admin db, | |||
or, if running without auth, on the local interface. | or, if running without auth, on the local interface. | |||
When localHostOnlyIfNoAuth() is true, adminOnly() must also be t rue. | When localHostOnlyIfNoAuth() is true, adminOnly() must also be t rue. | |||
*/ | */ | |||
virtual bool localHostOnlyIfNoAuth(const BSONObj& cmdObj) { return false; } | virtual bool localHostOnlyIfNoAuth(const BSONObj& cmdObj) { return false; } | |||
/* Return true if slaves of a replication pair are allowed to execu te the command | /* Return true if slaves of a replication pair are allowed to execu te the command | |||
(the command directly from a client -- if fromRepl, always allow ed). | (the command directly from a client -- if fromRepl, always allow ed). | |||
*/ | */ | |||
virtual bool slaveOk() = 0; | virtual bool slaveOk() const = 0; | |||
/* Return true if the client force a command to be run on a slave b y | /* Return true if the client force a command to be run on a slave b y | |||
turning on the 'slaveok' option in the command query. | turning on the 'slaveok' option in the command query. | |||
*/ | */ | |||
virtual bool slaveOverrideOk() { | virtual bool slaveOverrideOk() { | |||
return false; | return false; | |||
} | } | |||
/* Override and return true to if true,log the operation (logOp()) to the replication log. | /* Override and return true to if true,log the operation (logOp()) to the replication log. | |||
(not done if fromRepl of course) | (not done if fromRepl of course) | |||
skipping to change at line 96 | skipping to change at line 99 | |||
return false; | return false; | |||
} | } | |||
virtual void help( stringstream& help ) const; | virtual void help( stringstream& help ) const; | |||
/* Return true if authentication and security applies to the comman ds. Some commands | /* Return true if authentication and security applies to the comman ds. Some commands | |||
(e.g., getnonce, authenticate) can be done by anyone even unauth orized. | (e.g., getnonce, authenticate) can be done by anyone even unauth orized. | |||
*/ | */ | |||
virtual bool requiresAuth() { return true; } | virtual bool requiresAuth() { return true; } | |||
Command(const char *_name); | /** @param webUI expose the command in the web ui as localhost:2801 | |||
7/<name> | ||||
@param oldName an optional old, deprecated name for the command | ||||
*/ | ||||
Command(const char *_name, bool webUI = false, const char *oldName | ||||
= 0); | ||||
virtual ~Command() {} | virtual ~Command() {} | |||
protected: | protected: | |||
BSONObj getQuery( const BSONObj& cmdObj ){ | BSONObj getQuery( const BSONObj& cmdObj ){ | |||
if ( cmdObj["query"].type() == Object ) | if ( cmdObj["query"].type() == Object ) | |||
return cmdObj["query"].embeddedObject(); | return cmdObj["query"].embeddedObject(); | |||
if ( cmdObj["q"].type() == Object ) | if ( cmdObj["q"].type() == Object ) | |||
return cmdObj["q"].embeddedObject(); | return cmdObj["q"].embeddedObject(); | |||
return BSONObj(); | return BSONObj(); | |||
} | } | |||
static map<string,Command*> * _commands; | static map<string,Command*> * _commands; | |||
static map<string,Command*> * _commandsByBestName; | ||||
static map<string,Command*> * _webCommands; | ||||
public: | public: | |||
static const map<string,Command*>* commandsByBestName() { return _c | ||||
ommandsByBestName; } | ||||
static const map<string,Command*>* webCommands() { return _webComma | ||||
nds; } | ||||
static bool runAgainstRegistered(const char *ns, BSONObj& jsobj, BS ONObjBuilder& anObjBuilder); | static bool runAgainstRegistered(const char *ns, BSONObj& jsobj, BS ONObjBuilder& anObjBuilder); | |||
static LockType locktype( const string& name ); | static LockType locktype( const string& name ); | |||
static Command * findCommand( const string& name ); | static Command * findCommand( const string& name ); | |||
}; | }; | |||
bool _runCommands(const char *ns, BSONObj& jsobj, BufBuilder &b, BSONOb jBuilder& anObjBuilder, bool fromRepl, int queryOptions); | bool _runCommands(const char *ns, BSONObj& jsobj, BufBuilder &b, BSONOb jBuilder& anObjBuilder, bool fromRepl, int queryOptions); | |||
} // namespace mongo | } // namespace mongo | |||
End of changes. 10 change blocks. | ||||
8 lines changed or deleted | 23 lines changed or added | |||
connpool.h | connpool.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 <stack> | #include <stack> | |||
#include "dbclient.h" | #include "dbclient.h" | |||
#include "redef_macros.h" | ||||
namespace mongo { | namespace mongo { | |||
struct PoolForHost { | struct PoolForHost { | |||
PoolForHost() | ||||
: created(0){} | ||||
std::stack<DBClientBase*> pool; | std::stack<DBClientBase*> pool; | |||
long long created; | ||||
}; | }; | |||
class DBConnectionHook { | class DBConnectionHook { | |||
public: | public: | |||
virtual ~DBConnectionHook(){} | virtual ~DBConnectionHook(){} | |||
virtual void onCreate( DBClientBase * conn ){} | virtual void onCreate( DBClientBase * conn ){} | |||
virtual void onHandedOut( DBClientBase * conn ){} | virtual void onHandedOut( DBClientBase * conn ){} | |||
}; | }; | |||
skipping to change at line 54 | skipping to change at line 58 | |||
request... | request... | |||
Usage: | Usage: | |||
{ | { | |||
ScopedDbConnection c("myserver"); | ScopedDbConnection c("myserver"); | |||
c.conn()... | c.conn()... | |||
} | } | |||
*/ | */ | |||
class DBConnectionPool { | class DBConnectionPool { | |||
mongo::mutex poolMutex; | mongo::mutex _mutex; | |||
map<string,PoolForHost*> pools; // servername -> pool | map<string,PoolForHost*> _pools; // servername -> pool | |||
list<DBConnectionHook*> _hooks; | list<DBConnectionHook*> _hooks; | |||
void onCreate( DBClientBase * conn ); | void onCreate( DBClientBase * conn ); | |||
void onHandedOut( DBClientBase * conn ); | void onHandedOut( DBClientBase * conn ); | |||
public: | public: | |||
void flush(); | void flush(); | |||
DBClientBase *get(const string& host); | DBClientBase *get(const string& host); | |||
void release(const string& host, DBClientBase *c) { | void release(const string& host, DBClientBase *c) { | |||
if ( c->isFailed() ) | if ( c->isFailed() ){ | |||
delete c; | ||||
return; | return; | |||
scoped_lock L(poolMutex); | } | |||
pools[host]->pool.push(c); | scoped_lock L(_mutex); | |||
_pools[host]->pool.push(c); | ||||
} | } | |||
void addHook( DBConnectionHook * hook ); | void addHook( DBConnectionHook * hook ); | |||
void appendInfo( BSONObjBuilder& b ); | ||||
}; | }; | |||
extern DBConnectionPool pool; | extern DBConnectionPool pool; | |||
/** 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. | clean up nicely. | |||
*/ | */ | |||
class ScopedDbConnection { | class ScopedDbConnection : boost::noncopyable { | |||
const string host; | const string _host; | |||
DBClientBase *_conn; | DBClientBase *_conn; | |||
public: | public: | |||
/** get the associated connection object */ | /** get the associated connection object */ | |||
DBClientBase* operator->(){ | DBClientBase* operator->(){ | |||
uassert( 11004 , "did you call done already" , _conn ); | uassert( 11004 , "did you call done already" , _conn ); | |||
return _conn; | return _conn; | |||
} | } | |||
/** get the associated connection object */ | /** get the associated connection object */ | |||
DBClientBase& conn() { | DBClientBase& conn() { | |||
uassert( 11005 , "did you call done already" , _conn ); | uassert( 11005 , "did you call done already" , _conn ); | |||
return *_conn; | return *_conn; | |||
} | } | |||
/** get the associated connection object */ | ||||
DBClientBase* get() { | ||||
uassert( 13102 , "did you call done already" , _conn ); | ||||
return _conn; | ||||
} | ||||
ScopedDbConnection() | ||||
: _host( "" ) , _conn(0) { | ||||
} | ||||
/** throws UserException if can't connect */ | /** throws UserException if can't connect */ | |||
ScopedDbConnection(const string& _host) : | ScopedDbConnection(const string& host) | |||
host(_host), _conn( pool.get(_host) ) { | : _host(host), _conn( pool.get(host) ) { | |||
//cout << " for: " << _host << " got conn: " << _conn << endl; | ||||
} | } | |||
ScopedDbConnection(const string& host, DBClientBase* conn ) | ||||
: _host( host ) , _conn( conn ){ | ||||
} | ||||
string getHost() const { return _host; } | ||||
/** Force closure of the connection. You should call this if you l eave it in | /** Force closure of the connection. You should call this if you l eave it in | |||
a bad state. Destructor will do this too, but it is verbose. | a bad state. Destructor will do this too, but it is verbose. | |||
*/ | */ | |||
void kill() { | void kill() { | |||
delete _conn; | delete _conn; | |||
_conn = 0; | _conn = 0; | |||
} | } | |||
/** Call this when you are done with the connection. | /** Call this when you are done with the connection. | |||
skipping to change at line 122 | skipping to change at line 144 | |||
*/ | */ | |||
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 | |||
*/ | */ | |||
pool.release(host, _conn); | pool.release(_host, _conn); | |||
_conn = 0; | _conn = 0; | |||
} | } | |||
ScopedDbConnection * steal(); | ||||
~ScopedDbConnection(); | ~ScopedDbConnection(); | |||
}; | }; | |||
} // namespace mongo | } // namespace mongo | |||
#include "undef_macros.h" | ||||
End of changes. 14 change blocks. | ||||
11 lines changed or deleted | 35 lines changed or added | |||
counters.h | counters.h | |||
---|---|---|---|---|
skipping to change at line 18 | skipping to change at line 18 | |||
* | * | |||
* 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 "../../stdafx.h" | #pragma once | |||
#include "../../pch.h" | ||||
#include "../jsobj.h" | #include "../jsobj.h" | |||
#include "../../util/message.h" | #include "../../util/message.h" | |||
#include "../../util/processinfo.h" | #include "../../util/processinfo.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 | |||
*/ | */ | |||
skipping to change at line 120 | skipping to change at line 122 | |||
void append( BSONObjBuilder& b ); | void append( BSONObjBuilder& b ); | |||
private: | private: | |||
long long _total_time; | long long _total_time; | |||
long long _flushes; | long long _flushes; | |||
int _last_time; | int _last_time; | |||
Date_t _last; | Date_t _last; | |||
}; | }; | |||
extern FlushCounters globalFlushCounters; | extern FlushCounters globalFlushCounters; | |||
class GenericCounter { | ||||
public: | ||||
void hit( const string& name , int count=0 ); | ||||
BSONObj getObj(); | ||||
private: | ||||
map<string,long long> _counts; // TODO: replace with thread safe ma | ||||
p | ||||
mongo::mutex _mutex; | ||||
}; | ||||
} | } | |||
End of changes. 2 change blocks. | ||||
1 lines changed or deleted | 13 lines changed or added | |||
curop.h | curop.h | |||
---|---|---|---|---|
skipping to change at line 22 | skipping to change at line 22 | |||
* GNU Affero General Public License for more details. | * GNU Affero General Public License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Lice nse | * You should have received a copy of the GNU Affero General Public Lice nse | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "namespace.h" | #include "namespace.h" | |||
#include "client.h" | #include "client.h" | |||
#include "../util/atomic_int.h" | #include "../bson/util/atomic_int.h" | |||
#include "db.h" | #include "db.h" | |||
namespace mongo { | namespace mongo { | |||
class OpDebug { | class OpDebug { | |||
public: | public: | |||
StringBuilder str; | StringBuilder str; | |||
void reset(){ | void reset(){ | |||
str.reset(); | str.reset(); | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
cursor.h | cursor.h | |||
---|---|---|---|---|
skipping to change at line 19 | skipping to change at line 19 | |||
* 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 "../stdafx.h" | #include "../pch.h" | |||
#include "jsobj.h" | #include "jsobj.h" | |||
#include "diskloc.h" | #include "diskloc.h" | |||
namespace mongo { | namespace mongo { | |||
class Record; | class Record; | |||
/* Query cursors, base class. This is for our internal cursors. "Clie ntCursor" is a separate | /* Query cursors, base class. This is for our internal cursors. "Clie ntCursor" is a separate | |||
concept and is for the user's cursor. | concept and is for the user's cursor. | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
cursors.h | cursors.h | |||
---|---|---|---|---|
skipping to change at line 20 | skipping to change at line 20 | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | * GNU Affero General Public License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Lice nse | * You should have received a copy of the GNU Affero General Public Lice nse | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "../db/jsobj.h" | #include "../db/jsobj.h" | |||
#include "../db/dbmessage.h" | #include "../db/dbmessage.h" | |||
#include "../client/dbclient.h" | #include "../client/dbclient.h" | |||
#include "../client/parallel.h" | #include "../client/parallel.h" | |||
#include "request.h" | #include "request.h" | |||
namespace mongo { | namespace mongo { | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
d_logic.h | d_logic.h | |||
---|---|---|---|---|
skipping to change at line 20 | skipping to change at line 20 | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | * GNU Affero General Public License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Lice nse | * You should have received a copy of the GNU Affero General Public Lice nse | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
namespace mongo { | namespace mongo { | |||
/** | /** | |||
* @return true if we have any shard info for the ns | * @return true if we have any shard info for the ns | |||
*/ | */ | |||
bool haveLocalShardingInfo( const string& ns ); | bool haveLocalShardingInfo( const string& ns ); | |||
/** | /** | |||
* @return true if the current threads shard version is ok, or not in s harded version | * @return true if the current threads shard version is ok, or not in s harded version | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
db.h | db.h | |||
---|---|---|---|---|
skipping to change at line 19 | skipping to change at line 19 | |||
* 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 "../stdafx.h" | #include "../pch.h" | |||
#include "../util/message.h" | #include "../util/message.h" | |||
#include "boost/version.hpp" | #include "boost/version.hpp" | |||
#include "concurrency.h" | #include "concurrency.h" | |||
#include "pdfile.h" | #include "pdfile.h" | |||
#include "client.h" | #include "client.h" | |||
namespace mongo { | namespace mongo { | |||
// void jniCallback(Message& m, Message& out); | // void jniCallback(Message& m, Message& out); | |||
skipping to change at line 211 | skipping to change at line 211 | |||
real = new dbtemprelease(); | real = new dbtemprelease(); | |||
} | } | |||
~dbtempreleasecond(){ | ~dbtempreleasecond(){ | |||
if ( real ){ | if ( real ){ | |||
delete real; | delete real; | |||
real = 0; | real = 0; | |||
} | } | |||
} | } | |||
bool unlocked(){ | ||||
return real > 0; | ||||
} | ||||
}; | }; | |||
extern TicketHolder connTicketHolder; | ||||
} // namespace mongo | } // namespace mongo | |||
//#include "dbinfo.h" | //#include "dbinfo.h" | |||
#include "concurrency.h" | #include "concurrency.h" | |||
End of changes. 3 change blocks. | ||||
3 lines changed or deleted | 4 lines changed or added | |||
dbclient.h | dbclient.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 "../stdafx.h" | #include "../pch.h" | |||
#include "../util/message.h" | #include "../util/message.h" | |||
#include "../db/jsobj.h" | #include "../db/jsobj.h" | |||
#include "../db/json.h" | #include "../db/json.h" | |||
#include <stack> | #include <stack> | |||
namespace mongo { | namespace mongo { | |||
/** 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 | |||
skipping to change at line 75 | skipping to change at line 75 | |||
enum UpdateOptions { | enum UpdateOptions { | |||
/** Upsert - that is, insert the item if no matching item is found. */ | /** Upsert - that is, insert the item if no matching item is found. */ | |||
UpdateOption_Upsert = 1 << 0, | UpdateOption_Upsert = 1 << 0, | |||
/** Update multiple documents (if multiple documents match query ex pression). | /** Update multiple documents (if multiple documents match query ex pression). | |||
(Default is update a single document and stop.) */ | (Default is update a single document and stop.) */ | |||
UpdateOption_Multi = 1 << 1 | UpdateOption_Multi = 1 << 1 | |||
}; | }; | |||
/** | ||||
* controls how much a clients cares about writes | ||||
* default is NORMAL | ||||
*/ | ||||
enum WriteConcern { | ||||
W_NONE = 0 , // TODO: not every connection type fully supports this | ||||
W_NORMAL = 1 | ||||
// TODO SAFE = 2 | ||||
}; | ||||
class BSONObj; | class BSONObj; | |||
class ScopedDbConnection; | ||||
class DBClientCursor; | ||||
/** Represents a Mongo query expression. Typically one uses the QUERY( ...) macro to construct a Query object. | /** Represents a Mongo query expression. Typically one uses the QUERY( ...) macro to construct a Query object. | |||
Examples: | Examples: | |||
QUERY( "age" << 33 << "school" << "UCLA" ).sort("name") | QUERY( "age" << 33 << "school" << "UCLA" ).sort("name") | |||
QUERY( "age" << GT << 30 << LT << 50 ) | QUERY( "age" << GT << 30 << LT << 50 ) | |||
*/ | */ | |||
class Query { | class Query { | |||
public: | public: | |||
BSONObj obj; | BSONObj obj; | |||
Query() : obj(BSONObj()) { } | Query() : obj(BSONObj()) { } | |||
skipping to change at line 163 | skipping to change at line 175 | |||
Examples: | Examples: | |||
conn.findOne("test.coll", Query("{a:3}").where("this.b == 2 | | this.c == 3")); | conn.findOne("test.coll", Query("{a:3}").where("this.b == 2 | | this.c == 3")); | |||
Query badBalance = Query().where("this.debits - this.credits < 0"); | Query badBalance = Query().where("this.debits - this.credits < 0"); | |||
*/ | */ | |||
Query& where(const string &jscode, BSONObj scope); | Query& where(const string &jscode, BSONObj scope); | |||
Query& where(const string &jscode) { return where(jscode, BSONObj() ); } | Query& where(const string &jscode) { return where(jscode, BSONObj() ); } | |||
/** | /** | |||
* if this query has an orderby, hint, or some other field | * if this query has an orderby, hint, or some other field | |||
*/ | */ | |||
bool isComplex() const; | bool isComplex( bool * hasDollar = 0 ) const; | |||
BSONObj getFilter() const; | BSONObj getFilter() const; | |||
BSONObj getSort() const; | BSONObj getSort() const; | |||
BSONObj getHint() const; | BSONObj getHint() const; | |||
bool isExplain() const; | bool isExplain() const; | |||
string toString() const; | string toString() const; | |||
operator string() const { return toString(); } | operator string() const { return toString(); } | |||
private: | private: | |||
void makeComplex(); | void makeComplex(); | |||
skipping to change at line 201 | skipping to change at line 213 | |||
*/ | */ | |||
class DBConnector { | class DBConnector { | |||
public: | public: | |||
virtual ~DBConnector() {} | virtual ~DBConnector() {} | |||
virtual bool call( Message &toSend, Message &response, bool assertO k=true ) = 0; | virtual bool call( Message &toSend, Message &response, bool assertO k=true ) = 0; | |||
virtual void say( Message &toSend ) = 0; | virtual void say( Message &toSend ) = 0; | |||
virtual void sayPiggyBack( Message &toSend ) = 0; | virtual void sayPiggyBack( Message &toSend ) = 0; | |||
virtual void checkResponse( const string &data, int nReturned ) {} | virtual void checkResponse( const string &data, int nReturned ) {} | |||
}; | }; | |||
/** Queries return a cursor object */ | ||||
class DBClientCursor : boost::noncopyable { | ||||
friend class DBClientBase; | ||||
bool init(); | ||||
public: | ||||
/** If true, safe to call next(). Requests more from server | ||||
if necessary. */ | ||||
bool more(); | ||||
/** If true, there is more in our local buffers to be fetched via n | ||||
ext(). Returns | ||||
false when a getMore request back to server would be required. | ||||
You can use this | ||||
if you want to exhaust whatever data has been fetched to the cl | ||||
ient already but | ||||
then perhaps stop. | ||||
*/ | ||||
bool moreInCurrentBatch() { return !_putBack.empty() || pos < nRetu | ||||
rned; } | ||||
/** next | ||||
@return next object in the result cursor. | ||||
on an error at the remote server, you will get back: | ||||
{ $err: <string> } | ||||
if you do not want to handle that yourself, call nextSafe(). | ||||
*/ | ||||
BSONObj next(); | ||||
/** | ||||
restore an object previously returned by next() to the cursor | ||||
*/ | ||||
void putBack( const BSONObj &o ) { _putBack.push( o.getOwned() ); } | ||||
/** throws AssertionException if get back { $err : ... } */ | ||||
BSONObj nextSafe() { | ||||
BSONObj o = next(); | ||||
BSONElement e = o.firstElement(); | ||||
assert( strcmp(e.fieldName(), "$err") != 0 ); | ||||
return o; | ||||
} | ||||
/** | ||||
iterate the rest of the cursor and return the number if items | ||||
*/ | ||||
int itcount(){ | ||||
int c = 0; | ||||
while ( more() ){ | ||||
next(); | ||||
c++; | ||||
} | ||||
return c; | ||||
} | ||||
/** cursor no longer valid -- use with tailable cursors. | ||||
note you should only rely on this once more() returns false; | ||||
'dead' may be preset yet some data still queued and locally | ||||
available from the dbclientcursor. | ||||
*/ | ||||
bool isDead() const { | ||||
return cursorId == 0; | ||||
} | ||||
bool tailable() const { | ||||
return (opts & QueryOption_CursorTailable) != 0; | ||||
} | ||||
/** see QueryResult::ResultFlagType (db/dbmessage.h) for flag value | ||||
s | ||||
mostly these flags are for internal purposes - | ||||
ResultFlag_ErrSet is the possible exception to that | ||||
*/ | ||||
bool hasResultFlag( int flag ){ | ||||
return (resultFlags & flag) != 0; | ||||
} | ||||
DBClientCursor( DBConnector *_connector, const string &_ns, BSONObj | ||||
_query, int _nToReturn, | ||||
int _nToSkip, const BSONObj *_fieldsToReturn, int q | ||||
ueryOptions , int bs ) : | ||||
connector(_connector), | ||||
ns(_ns), | ||||
query(_query), | ||||
nToReturn(_nToReturn), | ||||
haveLimit( _nToReturn > 0 && !(queryOptions & QueryOption_C | ||||
ursorTailable)), | ||||
nToSkip(_nToSkip), | ||||
fieldsToReturn(_fieldsToReturn), | ||||
opts(queryOptions), | ||||
batchSize(bs), | ||||
m(new Message()), | ||||
cursorId(), | ||||
nReturned(), | ||||
pos(), | ||||
data(), | ||||
_ownCursor( true ) { | ||||
} | ||||
DBClientCursor( DBConnector *_connector, const string &_ns, long lo | ||||
ng _cursorId, int _nToReturn, int options ) : | ||||
connector(_connector), | ||||
ns(_ns), | ||||
nToReturn( _nToReturn ), | ||||
haveLimit( _nToReturn > 0 && !(options & QueryOption_Cursor | ||||
Tailable)), | ||||
opts( options ), | ||||
m(new Message()), | ||||
cursorId( _cursorId ), | ||||
nReturned(), | ||||
pos(), | ||||
data(), | ||||
_ownCursor( true ) { | ||||
} | ||||
virtual ~DBClientCursor(); | ||||
long long getCursorId() const { return cursorId; } | ||||
/** by default we "own" the cursor and will send the server a KillC | ||||
ursor | ||||
message when ~DBClientCursor() is called. This function overrid | ||||
es that. | ||||
*/ | ||||
void decouple() { _ownCursor = false; } | ||||
private: | ||||
int nextBatchSize(); | ||||
DBConnector *connector; | ||||
string ns; | ||||
BSONObj query; | ||||
int nToReturn; | ||||
bool haveLimit; | ||||
int nToSkip; | ||||
const BSONObj *fieldsToReturn; | ||||
int opts; | ||||
int batchSize; | ||||
auto_ptr<Message> m; | ||||
stack< BSONObj > _putBack; | ||||
int resultFlags; | ||||
long long cursorId; | ||||
int nReturned; | ||||
int pos; | ||||
const char *data; | ||||
void dataReceived(); | ||||
void requestMore(); | ||||
bool _ownCursor; // see decouple() | ||||
}; | ||||
/** | /** | |||
The interface that any db connection should implement | The interface that any db connection should implement | |||
*/ | */ | |||
class DBClientInterface : boost::noncopyable { | class DBClientInterface : boost::noncopyable { | |||
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 auto_ptr<DBClientCursor> getMore( const string &ns, long lo ng cursorId, int nToReturn = 0, int options = 0 ) = 0; | virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo ng cursorId, int nToReturn = 0, int options = 0 ) = 0; | |||
skipping to change at line 373 | skipping to change at line 248 | |||
}; | }; | |||
/** | /** | |||
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 */ | ||||
int _logLevel; | ||||
DBClientWithCommands() : _logLevel(0) { } | ||||
/** helper function. run a simple command where the command expression is simply | /** helper function. run a simple command where the command expression is simply | |||
{ command : 1 } | { command : 1 } | |||
@param info -- where to put result object. may be null if call er doesn't need that info | @param info -- where to put result object. may be null if call er doesn't need that info | |||
@param command -- command name | @param command -- command name | |||
@return true if the command returned "ok". | @return true if the command returned "ok". | |||
*/ | */ | |||
bool simpleCommand(const string &dbname, BSONObj *info, const strin g &command); | bool simpleCommand(const string &dbname, BSONObj *info, const strin g &command); | |||
/** Run a database command. Database commands are represented as B SON objects. Common database | /** Run a database command. Database commands are represented as B SON objects. Common database | |||
commands have prebuilt helper functions -- see below. If a hel per is not available you can | commands have prebuilt helper functions -- see below. If a hel per is not available you can | |||
directly call runCommand. | directly call runCommand. | |||
@param dbname database name. Use "admin" for global administra tive commands. | @param dbname database name. Use "admin" for global administra tive commands. | |||
@param cmd the command object to execute. For exam ple, { ismaster : 1 } | @param cmd the command object to execute. For exam ple, { ismaster : 1 } | |||
@param info the result object the database returns. Typically has { ok : ..., errmsg : ... } fields | @param info the result object the database returns. Typically has { ok : ..., errmsg : ... } fields | |||
set. | set. | |||
@param options see enum QueryOptions - normally not needed to r un a command | ||||
@return true if the command returned "ok". | @return true if the command returned "ok". | |||
*/ | */ | |||
virtual bool runCommand(const string &dbname, const BSONObj& cmd, B SONObj &info, int options=0); | virtual bool runCommand(const string &dbname, const BSONObj& cmd, B SONObj &info, int options=0); | |||
/** Authorize access to a particular database. | /** Authorize access to a particular database. | |||
Authentication is separate for each database on the server -- you may authenticate for any | Authentication is separate for each database on the server -- you may authenticate for any | |||
number of databases on a single connection. | number of databases on a single connection. | |||
The "admin" database is special and once authenticat ed provides access to all databases on the | The "admin" database is special and once authenticat ed 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 | |||
skipping to change at line 674 | skipping to change at line 554 | |||
protected: | protected: | |||
bool isOk(const BSONObj&); | bool isOk(const BSONObj&); | |||
}; | }; | |||
/** | /** | |||
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: | ||||
WriteConcern _writeConcern; | ||||
public: | public: | |||
DBClientBase(){ | ||||
_writeConcern = W_NORMAL; | ||||
} | ||||
WriteConcern getWriteConcern() const { return _writeConcern; } | ||||
void setWriteConcern( WriteConcern w ){ _writeConcern = w; } | ||||
/** send a query to the database. | /** send a query to the database. | |||
ns: namespace to query, format is <dbname>.<collectname | @param ns namespace to query, format is <dbname>.<collectname>[.<c | |||
>[.<collectname>]* | ollectname>]* | |||
query: query to perform on the collection. this is a BSON | @param query query to perform on the collection. this is a BSONOb | |||
Obj (binary JSON) | j (binary JSON) | |||
You may format as | You may format as | |||
{ query: { ... }, orderby: { ... } } | { query: { ... }, orderby: { ... } } | |||
to specify a sort order. | to specify a sort order. | |||
nToReturn: n to return. 0 = unlimited | @param nToReturn n to return. 0 = unlimited | |||
nToSkip: start with the nth item | @param nToSkip start with the nth item | |||
fieldsToReturn: | @param fieldsToReturn optional template of which fields to select. | |||
optional template of which fields to select. if unspecified, retur | if unspecified, returns all fields | |||
ns all fields | @param queryOptions see options enum at top of this file | |||
queryOptions: see options enum at top of this file | ||||
@return cursor. 0 if error (connection failure) | @return cursor. 0 if error (connection failure) | |||
@throws AssertionException | @throws AssertionException | |||
*/ | */ | |||
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0, | virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0, | |||
const BSONObj *fieldsToRetur n = 0, int queryOptions = 0 , int batchSize = 0 ); | const BSONObj *fieldsToRetur n = 0, int queryOptions = 0 , int batchSize = 0 ); | |||
/** @param cursorId id of cursor to retrieve | /** @param cursorId id of cursor to retrieve | |||
@return an handle to a previously allocated cursor | @return an handle to a previously allocated cursor | |||
@throws AssertionException | @throws AssertionException | |||
skipping to change at line 718 | skipping to change at line 608 | |||
/** | /** | |||
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 ); | |||
/** | /** | |||
updates objects matching query | updates objects matching query | |||
*/ | */ | |||
virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = 0 , bool multi = 0 ); | virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = false , bool multi = false ); | |||
virtual string getServerAddress() const = 0; | virtual string getServerAddress() const = 0; | |||
virtual bool isFailed() const = 0; | virtual bool isFailed() const = 0; | |||
static int countCommas( const string& s ){ | static int countCommas( const string& s ){ | |||
int n = 0; | int n = 0; | |||
for ( unsigned i=0; i<s.size(); i++ ) | for ( unsigned i=0; i<s.size(); i++ ) | |||
if ( s[i] == ',' ) | if ( s[i] == ',' ) | |||
n++; | n++; | |||
return n; | return n; | |||
} | } | |||
}; | }; // end DBClientBase | |||
class DBClientPaired; | class DBClientPaired; | |||
class ConnectException : public UserException { | class ConnectException : public UserException { | |||
public: | public: | |||
ConnectException(string msg) : UserException(9000,msg) { } | ConnectException(string msg) : UserException(9000,msg) { } | |||
}; | }; | |||
/** | /** | |||
A basic connection to the database. | A basic connection to the database. | |||
skipping to change at line 761 | skipping to change at line 651 | |||
string serverAddress; // remember for reconnects | string serverAddress; // remember for reconnects | |||
void _checkConnection(); | void _checkConnection(); | |||
void checkConnection() { if( failed ) _checkConnection(); } | void checkConnection() { if( failed ) _checkConnection(); } | |||
map< string, pair<string,string> > authCache; | map< string, pair<string,string> > authCache; | |||
int _timeout; | int _timeout; | |||
public: | public: | |||
/** | /** | |||
@param _autoReconnect if true, automatically reconnect on a conn ection failure | @param _autoReconnect if true, automatically reconnect on a conn ection failure | |||
@param cp used by DBClientPaired. You do not need to specify th is parameter | @param cp used by DBClientPaired. You do not need to specify th is parameter | |||
@param timeout tcp timeout in seconds - this is for read/write, | @param timeout tcp timeout in seconds - this is for read/write, | |||
not connect | not connect. | |||
Connect timeout is fixed, but short, at 5 seconds. | ||||
*/ | */ | |||
DBClientConnection(bool _autoReconnect=false,DBClientPaired* cp=0,i nt timeout=0) : | DBClientConnection(bool _autoReconnect=false, DBClientPaired* cp=0, int timeout=0) : | |||
clientPaired(cp), failed(false), autoReconnect(_autoReconne ct), lastReconnectTry(0), _timeout(timeout) { } | clientPaired(cp), failed(false), autoReconnect(_autoReconne ct), lastReconnectTry(0), _timeout(timeout) { } | |||
/** Connect to a Mongo database server. | /** Connect to a Mongo database server. | |||
If autoReconnect is true, you can try to use the DBClientConnect ion even when | If autoReconnect is true, you can try to use the DBClientConnect ion even when | |||
false was returned -- it will try to connect again. | false was returned -- it will try to connect again. | |||
@param serverHostname host to connect to. can include port numb er ( 127.0.0.1 , 127.0.0.1:5555 ) | @param serverHostname host to connect to. can include port numb er ( 127.0.0.1 , 127.0.0.1:5555 ) | |||
If you use IPv6 you must add a port number ( ::1:27017 ) | If you use IPv6 you must add a port number ( ::1:27017 ) | |||
@param errmsg any relevant error message will appended to the st ring | @param errmsg any relevant error message will appended to the st ring | |||
skipping to change at line 794 | skipping to change at line 685 | |||
@param serverHostname host to connect to. can include port numb er ( 127.0.0.1 , 127.0.0.1:5555 ) | @param serverHostname host to connect to. can include port numb er ( 127.0.0.1 , 127.0.0.1:5555 ) | |||
*/ | */ | |||
void connect(string serverHostname) { | void connect(string serverHostname) { | |||
string errmsg; | string errmsg; | |||
if( !connect(serverHostname.c_str(), errmsg) ) | if( !connect(serverHostname.c_str(), errmsg) ) | |||
throw ConnectException(string("can't connect ") + errmsg); | throw ConnectException(string("can't connect ") + errmsg); | |||
} | } | |||
virtual bool auth(const string &dbname, const string &username, con st string &pwd, string& errmsg, bool digestPassword = true); | virtual bool auth(const string &dbname, const string &username, con st string &pwd, string& errmsg, bool digestPassword = true); | |||
virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y, int nToReturn = 0, int nToSkip = 0, | virtual auto_ptr<DBClientCursor> query(const string &ns, Query quer y=Query(), int nToReturn = 0, int nToSkip = 0, | |||
const BSONObj *fieldsToRetur n = 0, int queryOptions = 0 , int batchSize = 0 ) { | const BSONObj *fieldsToRetur n = 0, int queryOptions = 0 , int batchSize = 0 ) { | |||
checkConnection(); | checkConnection(); | |||
return DBClientBase::query( ns, query, nToReturn, nToSkip, fiel dsToReturn, queryOptions , batchSize ); | return DBClientBase::query( ns, query, nToReturn, nToSkip, fiel dsToReturn, queryOptions , batchSize ); | |||
} | } | |||
/** | /** | |||
@return true if this connection is currently in a failed state. When autoreconnect is on, | @return true if this connection is currently in a failed state. When autoreconnect is on, | |||
a connection will transition back to an ok state after r econnecting. | a connection will transition back to an ok state after r econnecting. | |||
*/ | */ | |||
bool isFailed() const { | bool isFailed() const { | |||
skipping to change at line 923 | skipping to change at line 814 | |||
DBClientConnection& slaveConn(); | DBClientConnection& slaveConn(); | |||
/* TODO - not yet implemented. mongos may need these. */ | /* TODO - not yet implemented. mongos may need these. */ | |||
virtual bool call( Message &toSend, Message &response, bool assertO k=true ) { assert(false); return false; } | virtual bool call( Message &toSend, Message &response, bool assertO k=true ) { assert(false); return false; } | |||
virtual void say( Message &toSend ) { assert(false); } | virtual void say( Message &toSend ) { assert(false); } | |||
virtual void sayPiggyBack( Message &toSend ) { assert(false); } | virtual void sayPiggyBack( Message &toSend ) { assert(false); } | |||
virtual void checkResponse( const char *data, int nReturned ) { ass ert(false); } | virtual void checkResponse( const char *data, int nReturned ) { ass ert(false); } | |||
bool isFailed() const { | bool isFailed() const { | |||
// TODO: this really should check isFailed on current master as well | // TODO: this really should check isFailed on current master as well | |||
return master > NotSetR; | return master < Left; | |||
} | } | |||
}; | }; | |||
/** pings server to check if it's up | /** pings server to check if it's up | |||
*/ | */ | |||
bool serverAlive( const string &uri ); | bool serverAlive( const string &uri ); | |||
DBClientBase * createDirectClient(); | DBClientBase * createDirectClient(); | |||
} // namespace mongo | } // namespace mongo | |||
#include "dbclientcursor.h" | ||||
#include "undef_macros.h" | ||||
End of changes. 18 change blocks. | ||||
169 lines changed or deleted | 48 lines changed or added | |||
dbhelpers.h | dbhelpers.h | |||
---|---|---|---|---|
skipping to change at line 25 | skipping to change at line 25 | |||
* You should have received a copy of the GNU Affero General Public Licen se | * You should have received a copy of the GNU Affero General Public Licen se | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
/* db helpers are helper functions and classes that let us easily manipulat e the local | /* db helpers are helper functions and classes that let us easily manipulat e the local | |||
database instance. | database instance. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "client.h" | #include "client.h" | |||
#include "db.h" | #include "db.h" | |||
namespace mongo { | namespace mongo { | |||
class Cursor; | class Cursor; | |||
class CoveredIndexMatcher; | class CoveredIndexMatcher; | |||
class CursorIterator { | class CursorIterator { | |||
public: | public: | |||
skipping to change at line 94 | skipping to change at line 94 | |||
/* Get/put the first object from a collection. Generally only usef ul if the collection | /* Get/put the first object from a collection. Generally only usef ul if the collection | |||
only ever has a single object -- which is a "singleton collectio n". | only ever has a single object -- which is a "singleton collectio n". | |||
You do not need to set the database before calling. | You do not need to set the database before calling. | |||
Returns: true if object exists. | Returns: true if object exists. | |||
*/ | */ | |||
static bool getSingleton(const char *ns, BSONObj& result); | static bool getSingleton(const char *ns, BSONObj& result); | |||
static void putSingleton(const char *ns, BSONObj obj); | static void putSingleton(const char *ns, BSONObj obj); | |||
static void putSingletonGod(const char *ns, BSONObj obj, bool logTh eOp); | ||||
/* Remove all objects from a collection. | /* Remove all objects from a collection. | |||
You do not need to set the database before calling. | You do not need to set the database before calling. | |||
*/ | */ | |||
static void emptyCollection(const char *ns); | static void emptyCollection(const char *ns); | |||
}; | }; | |||
class Database; | class Database; | |||
End of changes. 2 change blocks. | ||||
1 lines changed or deleted | 2 lines changed or added | |||
dbmessage.h | dbmessage.h | |||
---|---|---|---|---|
skipping to change at line 91 | skipping to change at line 91 | |||
public: | public: | |||
DbMessage(const Message& _m) : m(_m) { | DbMessage(const Message& _m) : m(_m) { | |||
theEnd = _m.data->_data + _m.data->dataLen(); | theEnd = _m.data->_data + _m.data->dataLen(); | |||
int *r = (int *) _m.data->_data; | int *r = (int *) _m.data->_data; | |||
reserved = *r; | reserved = *r; | |||
r++; | r++; | |||
data = (const char *) r; | data = (const char *) r; | |||
nextjsobj = data; | nextjsobj = data; | |||
} | } | |||
const char * getns() { | const char * getns() const { | |||
return data; | return data; | |||
} | } | |||
void getns(Namespace& ns) { | void getns(Namespace& ns) const { | |||
ns = data; | ns = data; | |||
} | } | |||
const char * afterNS() const { | ||||
return data + strlen( data ) + 1; | ||||
} | ||||
int getInt( int num ) const { | ||||
const int * foo = (const int*)afterNS(); | ||||
return foo[num]; | ||||
} | ||||
int getQueryNToReturn() const { | ||||
return getInt( 1 ); | ||||
} | ||||
void resetPull(){ | void resetPull(){ | |||
nextjsobj = data; | nextjsobj = data; | |||
} | } | |||
int pullInt() { | int pullInt() { | |||
if ( nextjsobj == data ) | if ( nextjsobj == data ) | |||
nextjsobj += strlen(data) + 1; // skip namespace | nextjsobj += strlen(data) + 1; // skip namespace | |||
int i = *((int *)nextjsobj); | int i = *((int *)nextjsobj); | |||
nextjsobj += 4; | nextjsobj += 4; | |||
return i; | return i; | |||
} | } | |||
skipping to change at line 119 | skipping to change at line 132 | |||
return pullInt64(); | return pullInt64(); | |||
} | } | |||
long long &pullInt64() { | long long &pullInt64() { | |||
if ( nextjsobj == data ) | if ( nextjsobj == data ) | |||
nextjsobj += strlen(data) + 1; // skip namespace | nextjsobj += strlen(data) + 1; // skip namespace | |||
long long &i = *((long long *)nextjsobj); | long long &i = *((long long *)nextjsobj); | |||
nextjsobj += 8; | nextjsobj += 8; | |||
return i; | return i; | |||
} | } | |||
OID* getOID() { | OID* getOID() const { | |||
return (OID *) (data + strlen(data) + 1); // skip namespace | return (OID *) (data + strlen(data) + 1); // skip namespace | |||
} | } | |||
void getQueryStuff(const char *&query, int& ntoreturn) { | void getQueryStuff(const char *&query, int& ntoreturn) { | |||
int *i = (int *) (data + strlen(data) + 1); | int *i = (int *) (data + strlen(data) + 1); | |||
ntoreturn = *i; | ntoreturn = *i; | |||
i++; | i++; | |||
query = (const char *) i; | query = (const char *) i; | |||
} | } | |||
/* for insert and update msgs */ | /* for insert and update msgs */ | |||
bool moreJSObjs() { | bool moreJSObjs() const { | |||
return nextjsobj != 0; | return nextjsobj != 0; | |||
} | } | |||
BSONObj nextJsObj() { | BSONObj nextJsObj() { | |||
if ( nextjsobj == data ) { | if ( nextjsobj == data ) { | |||
nextjsobj += strlen(data) + 1; // skip namespace | nextjsobj += strlen(data) + 1; // skip namespace | |||
massert( 13066 , "Message contains no documents", theEnd > nextjsobj ); | massert( 13066 , "Message contains no documents", theEnd > nextjsobj ); | |||
} | } | |||
massert( 10304 , "Remaining data too small for BSON object", t heEnd - nextjsobj > 3 ); | massert( 10304 , "Remaining data too small for BSON object", t heEnd - nextjsobj > 3 ); | |||
BSONObj js(nextjsobj); | BSONObj js(nextjsobj); | |||
massert( 10305 , "Invalid object size", js.objsize() > 3 ); | massert( 10305 , "Invalid object size", js.objsize() > 3 ); | |||
skipping to change at line 153 | skipping to change at line 166 | |||
js.objsize() < ( theEnd - data ) ); | js.objsize() < ( theEnd - data ) ); | |||
if ( objcheck && !js.valid() ) { | if ( objcheck && !js.valid() ) { | |||
massert( 10307 , "bad object in message", false); | massert( 10307 , "bad object in message", false); | |||
} | } | |||
nextjsobj += js.objsize(); | nextjsobj += js.objsize(); | |||
if ( nextjsobj >= theEnd ) | if ( nextjsobj >= theEnd ) | |||
nextjsobj = 0; | nextjsobj = 0; | |||
return js; | return js; | |||
} | } | |||
const Message& msg() { | const Message& msg() const { | |||
return m; | return m; | |||
} | } | |||
void markSet(){ | void markSet(){ | |||
mark = nextjsobj; | mark = nextjsobj; | |||
} | } | |||
void markReset(){ | void markReset(){ | |||
nextjsobj = mark; | nextjsobj = mark; | |||
} | } | |||
End of changes. 6 change blocks. | ||||
5 lines changed or deleted | 18 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 | |||
#ifndef _WIN32 | #ifndef _WIN32 | |||
#include <signal.h> | #include <signal.h> | |||
#endif // ndef _WIN32 | #endif | |||
namespace mongo { | namespace mongo { | |||
// for debugging | // for debugging | |||
typedef struct _Ints { | typedef struct _Ints { | |||
int i[100]; | int i[100]; | |||
} *Ints; | } *Ints; | |||
typedef struct _Chars { | typedef struct _Chars { | |||
char c[200]; | char c[200]; | |||
} *Chars; | } *Chars; | |||
typedef char CHARS[400]; | typedef char CHARS[400]; | |||
typedef struct _OWS { | typedef struct _OWS { | |||
int size; | int size; | |||
char type; | char type; | |||
char string[400]; | char string[400]; | |||
} *OWS; | } *OWS; | |||
// for now, running on win32 means development not production -- | ||||
// use this to log things just there. | ||||
#if defined(_WIN32) | ||||
#define WIN if( 1 ) | ||||
#else | ||||
#define WIN if( 0 ) | ||||
#endif | ||||
#if defined(_DEBUG) | #if defined(_DEBUG) | |||
#define DEV if( 1 ) | # define MONGO_DEV if( 1 ) | |||
#else | #else | |||
#define DEV if( 0 ) | # define MONGO_DEV if( 0 ) | |||
#endif | #endif | |||
#define DEV MONGO_DEV | ||||
#define DEBUGGING if( 0 ) | #define MONGO_DEBUGGING if( 0 ) | |||
#define DEBUGGING MONGO_DEBUGGING | ||||
// The following declare one unique counter per enclosing function. | // The following declare one unique counter per enclosing function. | |||
// NOTE The implementation double-increments on a match, but we don't reall y care. | // NOTE The implementation double-increments on a match, but we don't reall y care. | |||
#define SOMETIMES( occasion, howOften ) for( static unsigned occasion = 0; | #define MONGO_SOMETIMES( occasion, howOften ) for( static unsigned occasion | |||
++occasion % howOften == 0; ) | = 0; ++occasion % howOften == 0; ) | |||
#define OCCASIONALLY SOMETIMES( occasionally, 16 ) | #define SOMETIMES MONGO_SOMETIMES | |||
#define RARELY SOMETIMES( rarely, 128 ) | ||||
#define ONCE for( static bool undone = true; undone; undone = false ) | #define MONGO_OCCASIONALLY SOMETIMES( occasionally, 16 ) | |||
#define OCCASIONALLY MONGO_OCCASIONALLY | ||||
#define MONGO_RARELY SOMETIMES( rarely, 128 ) | ||||
#define RARELY MONGO_RARELY | ||||
#define MONGO_ONCE for( static bool undone = true; undone; undone = false ) | ||||
#define ONCE MONGO_ONCE | ||||
#if defined(_WIN32) | #if defined(_WIN32) | |||
#define strcasecmp _stricmp | inline int strcasecmp(const char* s1, const char* s2) {return _stricmp( s1, s2);} | |||
#endif | #endif | |||
// Sets SIGTRAP handler to launch GDB | // Sets SIGTRAP handler to launch GDB | |||
// Noop unless on *NIX and compiled with _DEBUG | // Noop unless on *NIX and compiled with _DEBUG | |||
void setupSIGTRAPforGDB(); | void setupSIGTRAPforGDB(); | |||
#if defined(_WIN32) | #if defined(_WIN32) | |||
inline void breakpoint() {} //noop | inline void breakpoint() {} //noop | |||
#else // defined(_WIN32) | #else // defined(_WIN32) | |||
// code to raise a breakpoint in GDB | // code to raise a breakpoint in GDB | |||
End of changes. 8 change blocks. | ||||
18 lines changed or deleted | 19 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 "../stdafx.h" | #include "../pch.h" | |||
#include "../db/jsobj.h" | #include "../db/jsobj.h" | |||
extern const char * jsconcatcode; // TODO: change name to mongoJSCode | extern const char * jsconcatcode; // TODO: change name to mongoJSCode | |||
namespace mongo { | namespace mongo { | |||
typedef unsigned long long ScriptingFunction; | typedef unsigned long long ScriptingFunction; | |||
typedef BSONObj (*NativeFunction) ( const BSONObj &args ); | typedef BSONObj (*NativeFunction) ( const BSONObj &args ); | |||
class Scope : boost::noncopyable { | class Scope : boost::noncopyable { | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
engine_java.h | engine_java.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. | |||
*/ | */ | |||
/* this file contains code to call into java (into the 10gen sandbox) from inside the database */ | /* this file contains code to call into java (into the 10gen sandbox) from inside the database */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include <jni.h> | #include <jni.h> | |||
#include <boost/thread/tss.hpp> | #include <boost/thread/tss.hpp> | |||
#include <errno.h> | #include <errno.h> | |||
#include <sys/types.h> | #include <sys/types.h> | |||
#if !defined(_WIN32) | #if !defined(_WIN32) | |||
#include <dirent.h> | #include <dirent.h> | |||
#endif | #endif | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
engine_spidermonkey.h | engine_spidermonkey.h | |||
---|---|---|---|---|
skipping to change at line 45 | skipping to change at line 45 | |||
#ifdef WIN32 | #ifdef WIN32 | |||
#include "jstypes.h" | #include "jstypes.h" | |||
#undef JS_PUBLIC_API | #undef JS_PUBLIC_API | |||
#undef JS_PUBLIC_DATA | #undef JS_PUBLIC_DATA | |||
#define JS_PUBLIC_API(t) t | #define JS_PUBLIC_API(t) t | |||
#define JS_PUBLIC_DATA(t) t | #define JS_PUBLIC_DATA(t) t | |||
#endif | #endif | |||
#include "jsapi.h" | #include "jsapi.h" | |||
#include "jsobj.h" | ||||
#include "jsdate.h" | #include "jsdate.h" | |||
#include "jsregexp.h" | #include "jsregexp.h" | |||
#else | #else | |||
#include "js/jsapi.h" | #include "js/jsapi.h" | |||
#include "js/jsobj.h" | #include "js/jsobj.h" | |||
#include "js/jsdate.h" | #include "js/jsdate.h" | |||
#include "js/jsregexp.h" | #include "js/jsregexp.h" | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 1 lines changed or added | |||
extsort.h | extsort.h | |||
---|---|---|---|---|
skipping to change at line 21 | skipping to change at line 21 | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | * GNU Affero General Public License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Licen se | * You should have received a copy of the GNU Affero General Public Licen se | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "jsobj.h" | #include "jsobj.h" | |||
#include "namespace.h" | #include "namespace.h" | |||
#include "curop.h" | #include "curop.h" | |||
#include "../util/array.h" | #include "../util/array.h" | |||
namespace mongo { | namespace mongo { | |||
/** | /** | |||
for sorting by BSONObj and attaching a value | for sorting by BSONObj and attaching a value | |||
*/ | */ | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
file.h | file.h | |||
---|---|---|---|---|
skipping to change at line 121 | skipping to change at line 121 | |||
}; | }; | |||
#else | #else | |||
class File : public FileInterface { | class File : public FileInterface { | |||
int fd; | int fd; | |||
bool _bad; | bool _bad; | |||
void err(bool ok) { | void err(bool ok) { | |||
if( !ok && !_bad ) { | if( !ok && !_bad ) { | |||
_bad = true; | _bad = true; | |||
log() << "File I/O " << OUTPUT_ERRNO << '\n'; | log() << "File I/O " << errnoWithDescription() << '\n'; | |||
} | } | |||
} | } | |||
public: | public: | |||
File() { | File() { | |||
fd = -1; | fd = -1; | |||
_bad = true; | _bad = true; | |||
} | } | |||
~File() { | ~File() { | |||
if( is_open() ) ::close(fd); | if( is_open() ) ::close(fd); | |||
fd = -1; | fd = -1; | |||
} | } | |||
#ifndef O_NOATIME | #ifndef O_NOATIME | |||
#define O_NOATIME 0 | #define O_NOATIME 0 | |||
#define lseek64 lseek | #define lseek64 lseek | |||
#endif | #endif | |||
void open(const char *filename, bool readOnly=false ) { | void open(const char *filename, bool readOnly=false ) { | |||
fd = ::open(filename, O_CREAT | ( readOnly ? 0 : O_RDWR ) | O_NOATI ME, S_IRUSR | S_IWUSR); | fd = ::open(filename, O_CREAT | ( readOnly ? 0 : O_RDWR ) | O_NOATI ME, S_IRUSR | S_IWUSR); | |||
if ( fd <= 0 ) { | if ( fd <= 0 ) { | |||
out() << "couldn't open " << filename << ' ' << OUTPUT_ERRNO << endl; | out() << "couldn't open " << filename << ' ' << errnoWithDescri ption() << endl; | |||
return; | return; | |||
} | } | |||
_bad = false; | _bad = false; | |||
} | } | |||
void write(fileofs o, const char *data, unsigned len) { | void write(fileofs o, const char *data, unsigned len) { | |||
lseek64(fd, o, SEEK_SET); | lseek64(fd, o, SEEK_SET); | |||
err( ::write(fd, data, len) == (int) len ); | err( ::write(fd, data, len) == (int) len ); | |||
} | } | |||
void read(fileofs o, char *data, unsigned len) { | void read(fileofs o, char *data, unsigned len) { | |||
lseek(fd, o, SEEK_SET); | lseek(fd, o, SEEK_SET); | |||
End of changes. 2 change blocks. | ||||
2 lines changed or deleted | 2 lines changed or added | |||
file_allocator.h | file_allocator.h | |||
---|---|---|---|---|
skipping to change at line 18 | skipping to change at line 18 | |||
* | * | |||
* http://www.apache.org/licenses/LICENSE-2.0 | * http://www.apache.org/licenses/LICENSE-2.0 | |||
* | * | |||
* Unless required by applicable law or agreed to in writing, software | * Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | * distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. | |||
* See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | |||
* limitations under the License. | * limitations under the License. | |||
*/ | */ | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include <fcntl.h> | #include <fcntl.h> | |||
#include <errno.h> | #include <errno.h> | |||
#if defined(__freebsd__) | #if defined(__freebsd__) | |||
#include <sys/stat.h> | #include <sys/stat.h> | |||
#endif | #endif | |||
#ifndef O_NOATIME | #ifndef O_NOATIME | |||
#define O_NOATIME 0 | #define O_NOATIME 0 | |||
#endif | #endif | |||
skipping to change at line 109 | skipping to change at line 109 | |||
void waitUntilFinished() const { | void waitUntilFinished() const { | |||
#if !defined(_WIN32) | #if !defined(_WIN32) | |||
if ( failed_ ) | if ( failed_ ) | |||
return; | return; | |||
scoped_lock lk( pendingMutex_ ); | scoped_lock lk( pendingMutex_ ); | |||
while( pending_.size() != 0 ) | while( pending_.size() != 0 ) | |||
pendingUpdated_.wait( lk.boost() ); | pendingUpdated_.wait( lk.boost() ); | |||
#endif | #endif | |||
} | } | |||
static void ensureLength( int fd , long size ){ | ||||
#if defined(_WIN32) | ||||
// we don't zero on windows | ||||
// TODO : we should to avoid fragmentation | ||||
#else | ||||
#if defined(__linux__) | ||||
int ret = posix_fallocate(fd,0,size); | ||||
if ( ret == 0 ) | ||||
return; | ||||
log() << "posix_fallocate failed: " << errnoWithDescription( re | ||||
t ) << " falling back" << endl; | ||||
#endif | ||||
off_t filelen = lseek(fd, 0, SEEK_END); | ||||
if ( filelen < size ) { | ||||
massert( 10440 , "failure creating new datafile", filelen | ||||
== 0 ); | ||||
// Check for end of disk. | ||||
massert( 10441 , "Unable to allocate file of desired size" | ||||
, | ||||
size - 1 == lseek(fd, size - 1, SEEK_SET) ); | ||||
massert( 10442 , "Unable to allocate file of desired size" | ||||
, | ||||
1 == write(fd, "", 1) ); | ||||
lseek(fd, 0, SEEK_SET); | ||||
long z = 256 * 1024; | ||||
char buf[z]; | ||||
memset(buf, 0, z); | ||||
long left = size; | ||||
while ( left > 0 ) { | ||||
long towrite = left; | ||||
if ( towrite > z ) | ||||
towrite = z; | ||||
int written = write( fd , buf , towrite ); | ||||
massert( 10443 , errnoWithPrefix("write failed" ), writ | ||||
ten > 0 ); | ||||
left -= written; | ||||
} | ||||
} | ||||
#endif | ||||
} | ||||
private: | private: | |||
#if !defined(_WIN32) | #if !defined(_WIN32) | |||
void checkFailure() { | void checkFailure() { | |||
massert( 12520, "file allocation failure", !failed_ ); | massert( 12520, "file allocation failure", !failed_ ); | |||
} | } | |||
// 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 { | |||
if ( pendingSize_.count( name ) > 0 ) | if ( pendingSize_.count( name ) > 0 ) | |||
skipping to change at line 164 | skipping to change at line 206 | |||
if ( a_.pending_.size() == 0 ) | if ( a_.pending_.size() == 0 ) | |||
break; | break; | |||
name = a_.pending_.front(); | name = a_.pending_.front(); | |||
size = a_.pendingSize_[ name ]; | size = a_.pendingSize_[ name ]; | |||
} | } | |||
try { | try { | |||
log() << "allocating new datafile " << name << ", filling with zeroes..." << endl; | log() << "allocating new datafile " << name << ", filling with zeroes..." << endl; | |||
long fd = open(name.c_str(), O_CREAT | O_RDWR | O_NOATIME, S_IRUSR | S_IWUSR); | long fd = open(name.c_str(), O_CREAT | O_RDWR | O_NOATIME, S_IRUSR | S_IWUSR); | |||
if ( fd <= 0 ) { | if ( fd <= 0 ) { | |||
stringstream ss; | stringstream ss; | |||
ss << "couldn't open " << name << ' ' << OU TPUT_ERRNO; | ss << "couldn't open " << name << ' ' << er rnoWithDescription(); | |||
massert( 10439 , ss.str(), fd <= 0 ); | massert( 10439 , ss.str(), fd <= 0 ); | |||
} | } | |||
#if defined(POSIX_FADV_DONTNEED) | #if defined(POSIX_FADV_DONTNEED) | |||
if( posix_fadvise(fd, 0, size, POSIX_FADV_DONTN EED) ) { | if( posix_fadvise(fd, 0, size, POSIX_FADV_DONTN EED) ) { | |||
log() << "warning: posix_fadvise fails " << name << ' ' << OUTPUT_ERRNO << endl; | log() << "warning: posix_fadvise fails " << name << ' ' << errnoWithDescription() << endl; | |||
} | } | |||
#endif | #endif | |||
Timer t; | ||||
/* make sure the file is the full desired lengt h */ | /* make sure the file is the full desired lengt h */ | |||
off_t filelen = lseek(fd, 0, SEEK_END); | ensureLength( fd , size ); | |||
if ( filelen < size ) { | ||||
massert( 10440 , "failure creating new dat | log() << "done allocating datafile " << name << | |||
afile", filelen == 0 ); | ", " | |||
// Check for end of disk. | << "size: " << size/1024/1024 << "MB, " | |||
massert( 10441 , "Unable to allocate file | << " took " << ((double)t.millis())/1000. | |||
of desired size", | 0 << " secs" | |||
size - 1 == lseek(fd, size - 1, SEE | << endl; | |||
K_SET) ); | ||||
massert( 10442 , "Unable to allocate file | ||||
of desired size", | ||||
1 == write(fd, "", 1) ); | ||||
lseek(fd, 0, SEEK_SET); | ||||
Timer t; | ||||
long z = 256 * 1024; | ||||
char buf[z]; | ||||
memset(buf, 0, z); | ||||
long left = size; | ||||
while ( left > 0 ) { | ||||
long towrite = left; | ||||
if ( towrite > z ) | ||||
towrite = z; | ||||
int written = write( fd , buf , towrite | ||||
); | ||||
massert( 10443 , errnostring("write fai | ||||
led" ), written > 0 ); | ||||
left -= written; | ||||
} | ||||
log() << "done allocating datafile " << nam | ||||
e << ", size: " << size/1024/1024 << "MB, took " << ((double)t.millis())/10 | ||||
00.0 << " secs" << endl; | ||||
} | ||||
close( fd ); | close( fd ); | |||
} catch ( ... ) { | } catch ( ... ) { | |||
problem() << "Failed to allocate new file: " << name | problem() << "Failed to allocate new file: " << name | |||
<< ", size: " << size << ", aborting. " << endl; | << ", size: " << size << ", aborting. " << endl; | |||
try { | try { | |||
BOOST_CHECK_EXCEPTION( boost::filesystem::r emove( name ) ); | BOOST_CHECK_EXCEPTION( boost::filesystem::r emove( name ) ); | |||
} catch ( ... ) { | } catch ( ... ) { | |||
} | } | |||
scoped_lock lk( a_.pendingMutex_ ); | scoped_lock lk( a_.pendingMutex_ ); | |||
End of changes. 7 change blocks. | ||||
35 lines changed or deleted | 60 lines changed or added | |||
framework.h | framework.h | |||
---|---|---|---|---|
skipping to change at line 24 | skipping to change at line 24 | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Licen se | * You should have received a copy of the GNU Affero General Public Licen se | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
/* | /* | |||
simple portable regression system | simple portable regression system | |||
*/ | */ | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#define ASSERT_EXCEPTION(a,b) \ | #define ASSERT_EXCEPTION(a,b) \ | |||
try { \ | try { \ | |||
a; \ | a; \ | |||
mongo::regression::assert_fail( #a , __FILE__ , __LINE__ ); \ | mongo::regression::assert_fail( #a , __FILE__ , __LINE__ ); \ | |||
} catch ( b& ){ \ | } catch ( b& ){ \ | |||
mongo::regression::assert_pass(); \ | mongo::regression::assert_pass(); \ | |||
} | } | |||
#define ASSERT_EQUALS(a,b) (mongo::regression::MyAsserts( #a , #b , __FILE_ _ , __LINE__ ) ).ae( (a) , (b) ) | #define ASSERT_EQUALS(a,b) (mongo::regression::MyAsserts( #a , #b , __FILE_ _ , __LINE__ ) ).ae( (a) , (b) ) | |||
skipping to change at line 46 | skipping to change at line 46 | |||
#define FAIL(x) mongo::regression::fail( #x , __FILE__ , __LINE__ ) | #define FAIL(x) mongo::regression::fail( #x , __FILE__ , __LINE__ ) | |||
#include "../db/instance.h" | #include "../db/instance.h" | |||
namespace mongo { | namespace mongo { | |||
namespace regression { | namespace regression { | |||
class Result; | class Result; | |||
string demangleName( const type_info& typeinfo ); | ||||
class TestCase { | class TestCase { | |||
public: | public: | |||
virtual ~TestCase(){} | virtual ~TestCase(){} | |||
virtual void run() = 0; | virtual void run() = 0; | |||
virtual string getName() = 0; | virtual string getName() = 0; | |||
}; | }; | |||
template< class T > | template< class T > | |||
class TestHolderBase : public TestCase { | class TestHolderBase : public TestCase { | |||
public: | public: | |||
End of changes. 2 change blocks. | ||||
3 lines changed or deleted | 1 lines changed or added | |||
goodies.h | goodies.h | |||
---|---|---|---|---|
skipping to change at line 21 | skipping to change at line 21 | |||
* | * | |||
* Unless required by applicable law or agreed to in writing, software | * Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | * distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. | |||
* See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | |||
* limitations under the License. | * limitations under the License. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../bson/util/misc.h" | ||||
namespace mongo { | namespace mongo { | |||
#if !defined(_WIN32) && !defined(NOEXECINFO) && !defined(__freebsd__) && !d efined(__sun__) | #if !defined(_WIN32) && !defined(NOEXECINFO) && !defined(__freebsd__) && !d efined(__sun__) | |||
} // namespace mongo | } // namespace mongo | |||
#include <pthread.h> | #include <pthread.h> | |||
#include <execinfo.h> | #include <execinfo.h> | |||
namespace mongo { | namespace mongo { | |||
skipping to change at line 104 | skipping to change at line 106 | |||
for ( int i = 0; i < 16; i++ ) | for ( int i = 0; i < 16; i++ ) | |||
cout << (unsigned) ((unsigned char)*p++) << ' '; | cout << (unsigned) ((unsigned char)*p++) << ' '; | |||
cout << endl; | cout << endl; | |||
len -= 16; | len -= 16; | |||
} | } | |||
} catch (...) { | } catch (...) { | |||
} | } | |||
} | } | |||
// PRINT(2+2); prints "2+2: 4" | // PRINT(2+2); prints "2+2: 4" | |||
#define PRINT(x) cout << #x ": " << (x) << endl | #define MONGO_PRINT(x) cout << #x ": " << (x) << endl | |||
#define PRINT MONGO_PRINT | ||||
// PRINTFL; prints file:line | // PRINTFL; prints file:line | |||
#define PRINTFL cout << __FILE__ ":" << __LINE__ << endl | #define MONGO_PRINTFL cout << __FILE__ ":" << __LINE__ << endl | |||
#define PRINTFL MONGO_PRINTFL | ||||
#undef yassert | ||||
#undef assert | #undef assert | |||
#define assert xassert | #define assert MONGO_assert | |||
#define yassert 1 | ||||
struct WrappingInt { | struct WrappingInt { | |||
WrappingInt() { | WrappingInt() { | |||
x = 0; | x = 0; | |||
} | } | |||
WrappingInt(unsigned z) : x(z) { } | WrappingInt(unsigned z) : x(z) { } | |||
unsigned x; | unsigned x; | |||
operator unsigned() const { | operator unsigned() const { | |||
return x; | return x; | |||
} | } | |||
skipping to change at line 143 | skipping to change at line 144 | |||
return !(r<=*this); | return !(r<=*this); | |||
} | } | |||
}; | }; | |||
} // namespace mongo | } // namespace mongo | |||
#include <ctime> | #include <ctime> | |||
namespace mongo { | namespace mongo { | |||
inline void time_t_to_String(time_t t, char *buf) { | ||||
#if defined(_WIN32) | ||||
ctime_s(buf, 64, &t); | ||||
#else | ||||
ctime_r(&t, buf); | ||||
#endif | ||||
buf[24] = 0; // don't want the \n | ||||
} | ||||
inline void time_t_to_Struct(time_t t, struct tm * buf , bool local = f alse ) { | inline void time_t_to_Struct(time_t t, struct tm * buf , bool local = f alse ) { | |||
#if defined(_WIN32) | #if defined(_WIN32) | |||
if ( local ) | if ( local ) | |||
localtime_s( buf , &t ); | localtime_s( buf , &t ); | |||
else | else | |||
gmtime_s(buf, &t); | gmtime_s(buf, &t); | |||
#else | #else | |||
if ( local ) | if ( local ) | |||
localtime_r(&t, buf); | localtime_r(&t, buf); | |||
else | else | |||
gmtime_r(&t, buf); | gmtime_r(&t, buf); | |||
#endif | #endif | |||
} | } | |||
#define asctime _asctime_not_threadsafe_ | inline string terseCurrentTime(){ | |||
#define gmtime _gmtime_not_threadsafe_ | struct tm t; | |||
#define localtime _localtime_not_threadsafe_ | time_t_to_Struct( time(0) , &t ); | |||
#define ctime _ctime_is_not_threadsafe_ | stringstream ss; | |||
ss << ( 1900 + t.tm_year ) << "-" | ||||
<< t.tm_mon << "-" | ||||
<< t.tm_mday << "-" | ||||
<< t.tm_hour << "-" | ||||
<< t.tm_min; | ||||
return ss.str(); | ||||
} | ||||
#define MONGO_asctime _asctime_not_threadsafe_ | ||||
#define asctime MONGO_asctime | ||||
#define MONGO_gmtime _gmtime_not_threadsafe_ | ||||
#define gmtime MONGO_gmtime | ||||
#define MONGO_localtime _localtime_not_threadsafe_ | ||||
#define localtime MONGO_localtime | ||||
#define MONGO_ctime _ctime_is_not_threadsafe_ | ||||
#define ctime MONGO_ctime | ||||
#if defined(_WIN32) || defined(__sunos__) | #if defined(_WIN32) || defined(__sunos__) | |||
inline void sleepsecs(int s) { | inline void sleepsecs(int s) { | |||
boost::xtime xt; | boost::xtime xt; | |||
boost::xtime_get(&xt, boost::TIME_UTC); | boost::xtime_get(&xt, boost::TIME_UTC); | |||
xt.sec += s; | xt.sec += s; | |||
boost::thread::sleep(xt); | boost::thread::sleep(xt); | |||
} | } | |||
inline void sleepmillis(int s) { | inline void sleepmillis(int s) { | |||
boost::xtime xt; | boost::xtime xt; | |||
skipping to change at line 227 | skipping to change at line 235 | |||
struct timespec out; | struct timespec out; | |||
if ( nanosleep( &t , &out ) ){ | if ( nanosleep( &t , &out ) ){ | |||
cout << "nanosleep failed" << endl; | cout << "nanosleep failed" << endl; | |||
} | } | |||
} | } | |||
inline void sleepmillis(int s) { | inline void sleepmillis(int s) { | |||
sleepmicros( s * 1000 ); | sleepmicros( s * 1000 ); | |||
} | } | |||
#endif | #endif | |||
// note this wraps | // note this wraps | |||
inline int tdiff(unsigned told, unsigned tnew) { | inline int tdiff(unsigned told, unsigned tnew) { | |||
return WrappingInt::diff(tnew, told); | return WrappingInt::diff(tnew, told); | |||
} | } | |||
inline unsigned curTimeMillis() { | inline unsigned curTimeMillis() { | |||
boost::xtime xt; | boost::xtime xt; | |||
boost::xtime_get(&xt, boost::TIME_UTC); | boost::xtime_get(&xt, boost::TIME_UTC); | |||
unsigned t = xt.nsec / 1000000; | unsigned t = xt.nsec / 1000000; | |||
return (xt.sec & 0xfffff) * 1000 + t; | return (xt.sec & 0xfffff) * 1000 + t; | |||
} | } | |||
struct Date_t { | ||||
// TODO: make signed (and look for related TODO's) | ||||
unsigned long long millis; | ||||
Date_t(): millis(0) {} | ||||
Date_t(unsigned long long m): millis(m) {} | ||||
operator unsigned long long&() { return millis; } | ||||
operator const unsigned long long&() const { return millis; } | ||||
}; | ||||
inline Date_t jsTime() { | inline Date_t jsTime() { | |||
boost::xtime xt; | boost::xtime xt; | |||
boost::xtime_get(&xt, boost::TIME_UTC); | boost::xtime_get(&xt, boost::TIME_UTC); | |||
unsigned long long t = xt.nsec / 1000000; | unsigned long long t = xt.nsec / 1000000; | |||
return ((unsigned long long) xt.sec * 1000) + t; | return ((unsigned long long) xt.sec * 1000) + t; | |||
} | } | |||
inline unsigned long long curTimeMicros64() { | inline unsigned long long curTimeMicros64() { | |||
boost::xtime xt; | boost::xtime xt; | |||
boost::xtime_get(&xt, boost::TIME_UTC); | boost::xtime_get(&xt, boost::TIME_UTC); | |||
skipping to change at line 360 | skipping to change at line 359 | |||
*/ | */ | |||
//typedef scoped_lock lock; | //typedef scoped_lock lock; | |||
inline bool startsWith(const char *str, const char *prefix) { | inline bool startsWith(const char *str, const char *prefix) { | |||
size_t l = strlen(prefix); | size_t l = strlen(prefix); | |||
if ( strlen(str) < l ) return false; | if ( strlen(str) < l ) return false; | |||
return strncmp(str, prefix, l) == 0; | return strncmp(str, prefix, l) == 0; | |||
} | } | |||
inline bool startsWith(string s, string p) { return startsWith(s.c_str( ), p.c_str()); } | ||||
inline bool endsWith(const char *p, const char *suffix) { | inline bool endsWith(const char *p, const char *suffix) { | |||
size_t a = strlen(p); | size_t a = strlen(p); | |||
size_t b = strlen(suffix); | size_t b = strlen(suffix); | |||
if ( b > a ) return false; | if ( b > a ) return false; | |||
return strcmp(p + a - b, suffix) == 0; | return strcmp(p + a - b, suffix) == 0; | |||
} | } | |||
} // namespace mongo | } // namespace mongo | |||
skipping to change at line 647 | skipping to change at line 647 | |||
size_t _size; | size_t _size; | |||
char * _buf; | char * _buf; | |||
}; | }; | |||
ostream& operator<<( ostream &s, const ThreadSafeString &o ); | ostream& operator<<( ostream &s, const ThreadSafeString &o ); | |||
inline bool isNumber( char c ) { | inline bool isNumber( char c ) { | |||
return c >= '0' && c <= '9'; | return c >= '0' && c <= '9'; | |||
} | } | |||
inline unsigned stringToNum(const char *str) { | ||||
unsigned x = 0; | ||||
const char *p = str; | ||||
while( 1 ) { | ||||
if( !isNumber(*p) ) { | ||||
if( *p == 0 && p != str ) | ||||
break; | ||||
throw 0; | ||||
} | ||||
x = x * 10 + *p++ - '0'; | ||||
} | ||||
return x; | ||||
} | ||||
// for convenience, '{' is greater than anything and stops number parsi ng | // for convenience, '{' is greater than anything and stops number parsi ng | |||
inline int lexNumCmp( const char *s1, const char *s2 ) { | inline int lexNumCmp( const char *s1, const char *s2 ) { | |||
while( *s1 && *s2 ) { | while( *s1 && *s2 ) { | |||
bool p1 = ( *s1 == '{' ); | bool p1 = ( *s1 == '{' ); | |||
bool p2 = ( *s2 == '{' ); | bool p2 = ( *s2 == '{' ); | |||
if ( p1 && !p2 ) | if ( p1 && !p2 ) | |||
return 1; | return 1; | |||
if ( p2 && !p1 ) | if ( p2 && !p1 ) | |||
return -1; | return -1; | |||
End of changes. 10 change blocks. | ||||
29 lines changed or deleted | 43 lines changed or added | |||
gridfs.h | gridfs.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 "dbclient.h" | #include "dbclient.h" | |||
#include "redef_macros.h" | ||||
namespace mongo { | namespace mongo { | |||
typedef unsigned long long gridfs_offset; | typedef unsigned long long gridfs_offset; | |||
class GridFS; | class GridFS; | |||
class GridFile; | class GridFile; | |||
class Chunk { | class Chunk { | |||
public: | public: | |||
skipping to change at line 201 | skipping to change at line 202 | |||
GridFile( GridFS * grid , BSONObj obj ); | GridFile( GridFS * grid , BSONObj obj ); | |||
void _exists(); | void _exists(); | |||
GridFS * _grid; | GridFS * _grid; | |||
BSONObj _obj; | BSONObj _obj; | |||
friend class GridFS; | friend class GridFS; | |||
}; | }; | |||
} | } | |||
#include "undef_macros.h" | ||||
End of changes. 2 change blocks. | ||||
0 lines changed or deleted | 1 lines changed or added | |||
hashtab.h | hashtab.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 "../stdafx.h" | #include "../pch.h" | |||
#include <map> | #include <map> | |||
namespace mongo { | namespace mongo { | |||
#pragma pack(1) | #pragma pack(1) | |||
/* you should define: | /* you should define: | |||
int Key::hash() return > 0 always. | int Key::hash() return > 0 always. | |||
*/ | */ | |||
skipping to change at line 160 | skipping to change at line 160 | |||
n.hash = k.hash(); | n.hash = k.hash(); | |||
} | } | |||
else { | else { | |||
assert( n.hash == k.hash() ); | assert( n.hash == k.hash() ); | |||
} | } | |||
n.value = value; | n.value = value; | |||
return true; | return true; | |||
} | } | |||
typedef void (*IteratorCallback)( const Key& k , Type& v ); | typedef void (*IteratorCallback)( const Key& k , Type& v ); | |||
void iterAll( IteratorCallback callback ){ | void iterAll( IteratorCallback callback ){ | |||
for ( int i=0; i<n; i++ ){ | for ( int i=0; i<n; i++ ){ | |||
if ( ! nodes(i).inUse() ) | if ( ! nodes(i).inUse() ) | |||
continue; | continue; | |||
callback( nodes(i).k , nodes(i).value ); | callback( nodes(i).k , nodes(i).value ); | |||
} | } | |||
} | } | |||
// TODO: should probably use boost::bind for this, but didn't want | ||||
to look at it | ||||
typedef void (*IteratorCallback2)( const Key& k , Type& v , void * | ||||
extra ); | ||||
void iterAll( IteratorCallback2 callback , void * extra ){ | ||||
for ( int i=0; i<n; i++ ){ | ||||
if ( ! nodes(i).inUse() ) | ||||
continue; | ||||
callback( nodes(i).k , nodes(i).value , extra ); | ||||
} | ||||
} | ||||
}; | }; | |||
#pragma pack() | #pragma pack() | |||
} // namespace mongo | } // namespace mongo | |||
End of changes. 3 change blocks. | ||||
2 lines changed or deleted | 13 lines changed or added | |||
httpclient.h | httpclient.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 "../stdafx.h" | #include "../pch.h" | |||
namespace mongo { | namespace mongo { | |||
class HttpClient { | class HttpClient { | |||
public: | public: | |||
class Result { | class Result { | |||
public: | public: | |||
Result(){} | Result(){} | |||
const string& getEntireResponse() const { | const string& getEntireResponse() const { | |||
return _entireResponse; | return _entireResponse; | |||
} | } | |||
const map<string,string> getHeaders() const { | ||||
return _headers; | ||||
} | ||||
const string& getBody() const { | ||||
return _body; | ||||
} | ||||
private: | private: | |||
void _init( int code , string entire ); | ||||
int _code; | int _code; | |||
string _entireResponse; | string _entireResponse; | |||
map<string,string> _headers; | ||||
string _body; | ||||
friend class HttpClient; | friend class HttpClient; | |||
}; | }; | |||
/** | /** | |||
* @return response code | * @return response code | |||
*/ | */ | |||
int get( string url , Result * result = 0 ); | int get( string url , Result * result = 0 ); | |||
/** | /** | |||
* @return response code | * @return response code | |||
End of changes. 4 change blocks. | ||||
1 lines changed or deleted | 17 lines changed or added | |||
index.h | index.h | |||
---|---|---|---|---|
skipping to change at line 21 | skipping to change at line 21 | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | * GNU Affero General Public License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Licen se | * You should have received a copy of the GNU Affero General Public Licen se | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "diskloc.h" | #include "diskloc.h" | |||
#include "jsobj.h" | #include "jsobj.h" | |||
#include <map> | #include "indexkey.h" | |||
namespace mongo { | namespace mongo { | |||
class IndexSpec; | ||||
class IndexType; // TODO: this name sucks | ||||
class IndexPlugin; | ||||
class IndexDetails; | ||||
enum IndexSuitability { USELESS = 0 , HELPFUL = 1 , OPTIMAL = 2 }; | ||||
/** | ||||
* this represents an instance of a index plugin | ||||
* done this way so parsing, etc... can be cached | ||||
* so if there is a FTS IndexPlugin, for each index using FTS | ||||
* there will be 1 of these, and it can have things pre-parsed, etc... | ||||
*/ | ||||
class IndexType : boost::noncopyable { | ||||
public: | ||||
IndexType( const IndexPlugin * plugin , const IndexSpec * spec ); | ||||
virtual ~IndexType(); | ||||
virtual void getKeys( const BSONObj &obj, BSONObjSetDefaultOrder &k | ||||
eys ) const = 0; | ||||
virtual auto_ptr<Cursor> newCursor( const BSONObj& query , const BS | ||||
ONObj& order , int numWanted ) const = 0; | ||||
/** optional op : changes query to match what's in the index */ | ||||
virtual BSONObj fixKey( const BSONObj& in ) { return in; } | ||||
/** optional op : compare 2 objects with regards to this index */ | ||||
virtual int compare( const BSONObj& l , const BSONObj& r ) const; | ||||
/** @return plugin */ | ||||
const IndexPlugin * getPlugin() const { return _plugin; } | ||||
const BSONObj& keyPattern() const; | ||||
virtual IndexSuitability suitability( const BSONObj& query , const | ||||
BSONObj& order ) const ; | ||||
virtual bool scanAndOrderRequired( const BSONObj& query , const BSO | ||||
NObj& order ) const ; | ||||
protected: | ||||
const IndexPlugin * _plugin; | ||||
const IndexSpec * _spec; | ||||
}; | ||||
/** | ||||
* this represents a plugin | ||||
* a plugin could be something like full text search, sparse index, etc | ||||
... | ||||
* 1 of these exists per type of index per server | ||||
* 1 IndexType is created per index using this plugin | ||||
*/ | ||||
class IndexPlugin : boost::noncopyable { | ||||
public: | ||||
IndexPlugin( const string& name ); | ||||
virtual ~IndexPlugin(){} | ||||
virtual IndexType* generate( const IndexSpec * spec ) const = 0; | ||||
static IndexPlugin* get( const string& name ){ | ||||
if ( ! _plugins ) | ||||
return 0; | ||||
map<string,IndexPlugin*>::iterator i = _plugins->find( name ); | ||||
if ( i == _plugins->end() ) | ||||
return 0; | ||||
return i->second; | ||||
} | ||||
string getName() const { return _name; } | ||||
private: | ||||
string _name; | ||||
static map<string,IndexPlugin*> * _plugins; | ||||
}; | ||||
/* precomputed details about an index, used for inserting keys on updat | ||||
es | ||||
stored/cached in NamespaceDetailsTransient, or can be used standalon | ||||
e | ||||
*/ | ||||
class IndexSpec { | ||||
public: | ||||
BSONObj keyPattern; // e.g., { name : 1 } | ||||
BSONObj info; // this is the same as IndexDetails::info.obj() | ||||
IndexSpec() | ||||
: _details(0) , _finishedInit(false){ | ||||
} | ||||
IndexSpec( const BSONObj& k , const BSONObj& m = BSONObj() ) | ||||
: keyPattern(k) , info(m) , _details(0) , _finishedInit(false){ | ||||
_init(); | ||||
} | ||||
/** | ||||
this is a DiscLoc of an IndexDetails info | ||||
should have a key field | ||||
*/ | ||||
IndexSpec( const DiskLoc& loc ){ | ||||
reset( loc ); | ||||
} | ||||
void reset( const DiskLoc& loc ); | ||||
void reset( const IndexDetails * details ); | ||||
void getKeys( const BSONObj &obj, BSONObjSetDefaultOrder &keys ) co | ||||
nst; | ||||
BSONElement missingField() const { return _nullElt; } | ||||
string getTypeName() const { | ||||
if ( _indexType.get() ) | ||||
return _indexType->getPlugin()->getName(); | ||||
return ""; | ||||
} | ||||
IndexType* getType() const { | ||||
return _indexType.get(); | ||||
} | ||||
const IndexDetails * getDetails() const { | ||||
return _details; | ||||
} | ||||
IndexSuitability suitability( const BSONObj& query , const BSONObj& | ||||
order ) const ; | ||||
protected: | ||||
IndexSuitability _suitability( const BSONObj& query , const BSONObj | ||||
& order ) const ; | ||||
void _getKeys( vector<const char*> fieldNames , vector<BSONElement> | ||||
fixed , const BSONObj &obj, BSONObjSetDefaultOrder &keys ) const; | ||||
BSONSizeTracker _sizeTracker; | ||||
vector<const char*> _fieldNames; | ||||
vector<BSONElement> _fixed; | ||||
BSONObj _nullKey; | ||||
BSONObj _nullObj; | ||||
BSONElement _nullElt; | ||||
shared_ptr<IndexType> _indexType; | ||||
const IndexDetails * _details; | ||||
void _init(); | ||||
public: | ||||
bool _finishedInit; | ||||
friend class IndexType; | ||||
}; | ||||
/* Details about a particular index. There is one of these effective ly for each object in | /* Details about a particular index. There is one of these effective ly for each object in | |||
system.namespaces (although this also includes the head pointer, which is not in that | system.namespaces (although this also includes the head pointer, which is not in that | |||
collection). | collection). | |||
** MemoryMapped Record ** (i.e., this is on disk data) | ** MemoryMapped Record ** (i.e., this is on disk data) | |||
*/ | */ | |||
class IndexDetails { | class IndexDetails { | |||
public: | public: | |||
DiskLoc head; /* btree head disk location */ | DiskLoc head; /* btree head disk location */ | |||
skipping to change at line 303 | skipping to change at line 159 | |||
if( added.empty() || !idx.unique() ) | if( added.empty() || !idx.unique() ) | |||
return; | return; | |||
for( vector<BSONObj*>::iterator i = added.begin(); i != added.e nd(); i++ ) { | for( vector<BSONObj*>::iterator i = added.begin(); i != added.e nd(); i++ ) { | |||
bool dup = idx.wouldCreateDup(**i, curObjLoc); | bool dup = idx.wouldCreateDup(**i, curObjLoc); | |||
uassert( 11001 , "E11001 duplicate key on update", !dup); | uassert( 11001 , "E11001 duplicate key on update", !dup); | |||
} | } | |||
} | } | |||
}; | }; | |||
class NamespaceDetails; | class NamespaceDetails; | |||
void getIndexChanges(vector<IndexChanges>& v, NamespaceDetails& d, BSON | // changedId should be initialized to false | |||
Obj newObj, BSONObj oldObj); | void getIndexChanges(vector<IndexChanges>& v, NamespaceDetails& d, BSON | |||
Obj newObj, BSONObj oldObj, bool &cangedId); | ||||
void dupCheck(vector<IndexChanges>& v, NamespaceDetails& d, DiskLoc cur ObjLoc); | void dupCheck(vector<IndexChanges>& v, NamespaceDetails& d, DiskLoc cur ObjLoc); | |||
} // namespace mongo | } // namespace mongo | |||
End of changes. 4 change blocks. | ||||
159 lines changed or deleted | 5 lines changed or added | |||
instance.h | instance.h | |||
---|---|---|---|---|
skipping to change at line 32 | skipping to change at line 32 | |||
#include "../client/dbclient.h" | #include "../client/dbclient.h" | |||
#include "curop.h" | #include "curop.h" | |||
#include "security.h" | #include "security.h" | |||
#include "cmdline.h" | #include "cmdline.h" | |||
#include "client.h" | #include "client.h" | |||
namespace mongo { | namespace mongo { | |||
extern string dbExecCommand; | extern string dbExecCommand; | |||
#define OPWRITE if( _diaglog.level & 1 ) _diaglog.write((char *) m.data, m. | ||||
data->len); | ||||
#define OPREAD if( _diaglog.level & 2 ) _diaglog.readop((char *) m.data, m. | ||||
data->len); | ||||
struct DiagLog { | struct DiagLog { | |||
ofstream *f; | ofstream *f; | |||
/* 0 = off; 1 = writes, 2 = reads, 3 = both | /* 0 = off; 1 = writes, 2 = reads, 3 = both | |||
7 = log a few reads, and all writes. | 7 = log a few reads, and all writes. | |||
*/ | */ | |||
int level; | int level; | |||
mongo::mutex mutex; | mongo::mutex mutex; | |||
DiagLog() : f(0) , level(0) { } | DiagLog() : f(0) , level(0) { } | |||
void init() { | void init() { | |||
End of changes. 1 change blocks. | ||||
5 lines changed or deleted | 0 lines changed or added | |||
introspect.h | introspect.h | |||
---|---|---|---|---|
skipping to change at line 22 | skipping to change at line 22 | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | * GNU Affero General Public License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Licen se | * You should have received a copy of the GNU Affero General Public Licen se | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "jsobj.h" | #include "jsobj.h" | |||
#include "pdfile.h" | #include "pdfile.h" | |||
namespace mongo { | namespace mongo { | |||
/* --- profiling -------------------------------------------- | /* --- profiling -------------------------------------------- | |||
do when database->profile is set | do when database->profile is set | |||
*/ | */ | |||
void profile(const char *str, | void profile(const char *str, | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
jsobj.h | jsobj.h | |||
---|---|---|---|---|
skipping to change at line 26 | skipping to change at line 26 | |||
* 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. | |||
*/ | */ | |||
/** | /** | |||
BSONObj and its helpers | BSONObj and its helpers | |||
"BSON" stands for "binary JSON" -- ie a binary way to represent objects that would be | "BSON" stands for "binary JSON" -- ie a binary way to represent objects that would be | |||
represented in JSON (plus a few extensions useful for databases & other languages). | represented in JSON (plus a few extensions useful for databases & other languages). | |||
http://www.mongodb.org/display/DOCS/BSON | http://www.bsonspec.org/ | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "../util/builder.h" | #include "../bson/util/builder.h" | |||
#include "../util/optime.h" | #include "../util/optime.h" | |||
#include "boost/utility.hpp" | #include "boost/utility.hpp" | |||
#include <set> | #include <set> | |||
#include "../bson/bsontypes.h" | ||||
#include "../bson/oid.h" | ||||
#include "../bson/bsonelement.h" | ||||
#include "../bson/bsonobj.h" | ||||
#include "../bson/bsonmisc.h" | ||||
#include "../bson/bsonobjbuilder.h" | ||||
#include "../bson/bsonobjiterator.h" | ||||
#include "../bson/bsoninlines.h" | ||||
#include "../bson/ordering.h" | ||||
namespace mongo { | #include "../bson/bson_db.h" | |||
class BSONObj; | ||||
struct BSONArray; // empty subclass of BSONObj useful for overloading | ||||
class BSONElement; | ||||
class Record; | ||||
class BSONObjBuilder; | ||||
class BSONArrayBuilder; | ||||
class BSONObjBuilderValueStream; | ||||
#pragma pack(1) | ||||
/** | ||||
the complete list of valid BSON types | ||||
*/ | ||||
enum BSONType { | ||||
/** smaller than all other types */ | ||||
MinKey=-1, | ||||
/** end of object */ | ||||
EOO=0, | ||||
/** double precision floating point value */ | ||||
NumberDouble=1, | ||||
/** character string, stored in utf8 */ | ||||
String=2, | ||||
/** an embedded object */ | ||||
Object=3, | ||||
/** an embedded array */ | ||||
Array=4, | ||||
/** binary data */ | ||||
BinData=5, | ||||
/** Undefined type */ | ||||
Undefined=6, | ||||
/** ObjectId */ | ||||
jstOID=7, | ||||
/** boolean type */ | ||||
Bool=8, | ||||
/** date type */ | ||||
Date=9, | ||||
/** null type */ | ||||
jstNULL=10, | ||||
/** regular expression, a pattern with options */ | ||||
RegEx=11, | ||||
/** deprecated / will be redesigned */ | ||||
DBRef=12, | ||||
/** deprecated / use CodeWScope */ | ||||
Code=13, | ||||
/** a programming language (e.g., Python) symbol */ | ||||
Symbol=14, | ||||
/** javascript code that can execute on the database server, with S | ||||
avedContext */ | ||||
CodeWScope=15, | ||||
/** 32 bit signed integer */ | ||||
NumberInt = 16, | ||||
/** Updated to a Date with value next OpTime on insert */ | ||||
Timestamp = 17, | ||||
/** 64 bit integer */ | ||||
NumberLong = 18, | ||||
/** max type that is not MaxKey */ | ||||
JSTypeMax=18, | ||||
/** larger than all other types */ | ||||
MaxKey=127 | ||||
}; | ||||
/* subtypes of BinData. | ||||
bdtCustom and above are ones that the JS compiler understands, but a | ||||
re | ||||
opaque to the database. | ||||
*/ | ||||
enum BinDataType { Function=1, ByteArray=2, bdtUUID = 3, MD5Type=5, bdt | ||||
Custom=128 }; | ||||
/** Object ID type. | ||||
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 | ||||
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 | ||||
automatically in certain circumstances. | ||||
Warning: You must call OID::newState() after a fork(). | ||||
*/ | ||||
class OID { | ||||
union { | ||||
struct{ | ||||
long long a; | ||||
unsigned b; | ||||
}; | ||||
unsigned char data[12]; | ||||
}; | ||||
static unsigned _machine; | ||||
public: | ||||
/** call this after a fork */ | ||||
static void newState(); | ||||
/** initialize to 'null' */ | ||||
void clear() { a = 0; b = 0; } | ||||
const unsigned char *getData() const { return data; } | ||||
bool operator==(const OID& r) { | ||||
return a==r.a&&b==r.b; | ||||
} | ||||
bool operator!=(const OID& r) { | ||||
return a!=r.a||b!=r.b; | ||||
} | ||||
/** The object ID output as 24 hex digits. */ | ||||
string str() const { | ||||
stringstream s; | ||||
s << hex; | ||||
// s.fill( '0' ); | ||||
// s.width( 2 ); | ||||
// fill wasn't working so doing manually... | ||||
for( int i = 0; i < 8; i++ ) { | ||||
unsigned u = data[i]; | ||||
if( u < 16 ) s << '0'; | ||||
s << u; | ||||
} | ||||
const unsigned char * raw = (const unsigned char*)&b; | ||||
for( int i = 0; i < 4; i++ ) { | ||||
unsigned u = raw[i]; | ||||
if( u < 16 ) s << '0'; | ||||
s << u; | ||||
} | ||||
/* | ||||
s.width( 16 ); | ||||
s << a; | ||||
s.width( 8 ); | ||||
s << b; | ||||
s << dec; | ||||
*/ | ||||
return s.str(); | ||||
} | ||||
/** | ||||
sets the contents to a new oid / randomized value | ||||
*/ | ||||
void init(); | ||||
/** Set to the hex string value specified. */ | ||||
void init( string s ); | ||||
}; | ||||
ostream& operator<<( ostream &s, const OID &o ); | ||||
/** Formatting mode for generating JSON from BSON. | ||||
See <http://mongodb.onconfluence.com/display/DOCS/Mongo+Extended+JS | ||||
ON> | ||||
for details. | ||||
*/ | ||||
enum JsonStringFormat { | ||||
/** strict RFC format */ | ||||
Strict, | ||||
/** 10gen format, which is close to JS format. This form is unders | ||||
tandable by | ||||
javascript running inside the Mongo server via eval() */ | ||||
TenGen, | ||||
/** Javascript JSON compatible */ | ||||
JS | ||||
}; | ||||
/* l and r MUST have same type when called: check that first. */ | ||||
int compareElementValues(const BSONElement& l, const BSONElement& r); | ||||
#pragma pack() | ||||
/* internals | ||||
<type><fieldName ><value> | ||||
-------- size() ------------ | ||||
-fieldNameSize- | ||||
value() | ||||
type() | ||||
*/ | ||||
/** BSONElement represents an "element" in a BSONObj. So for the objec | ||||
t { a : 3, b : "abc" }, | ||||
'a : 3' is the first element (key+value). | ||||
The BSONElement object points into the BSONObj's data. Thus the BSO | ||||
NObj must stay in scope | ||||
for the life of the BSONElement. | ||||
*/ | ||||
class BSONElement { | ||||
friend class BSONObjIterator; | ||||
friend class BSONObj; | ||||
public: | ||||
string toString( bool includeFieldName = true ) const; | ||||
operator string() const { return toString(); } | ||||
string jsonString( JsonStringFormat format, bool includeFieldNames | ||||
= true ) const; | ||||
/** Returns the type of the element */ | ||||
BSONType type() const { | ||||
return (BSONType) *data; | ||||
} | ||||
/** returns the tyoe of the element fixed for the main type | ||||
the main purpose is numbers. any numeric type will return Numb | ||||
erDouble | ||||
Note: if the order changes, indexes have to be re-built or than | ||||
can be corruption | ||||
*/ | ||||
int canonicalType() const { | ||||
BSONType t = type(); | ||||
switch ( t ){ | ||||
case MinKey: | ||||
case MaxKey: | ||||
return t; | ||||
case EOO: | ||||
case Undefined: | ||||
return 0; | ||||
case jstNULL: | ||||
return 5; | ||||
case NumberDouble: | ||||
case NumberInt: | ||||
case NumberLong: | ||||
return 10; | ||||
case String: | ||||
case Symbol: | ||||
return 15; | ||||
case Object: | ||||
return 20; | ||||
case Array: | ||||
return 25; | ||||
case BinData: | ||||
return 30; | ||||
case jstOID: | ||||
return 35; | ||||
case Bool: | ||||
return 40; | ||||
case Date: | ||||
case Timestamp: | ||||
return 45; | ||||
case RegEx: | ||||
return 50; | ||||
case DBRef: | ||||
return 55; | ||||
case Code: | ||||
return 60; | ||||
case CodeWScope: | ||||
return 65; | ||||
default: | ||||
assert(0); | ||||
return -1; | ||||
} | ||||
} | ||||
/** Indicates if it is the end-of-object element, which is present | ||||
at the end of | ||||
every BSON object. | ||||
*/ | ||||
bool eoo() const { | ||||
return type() == EOO; | ||||
} | ||||
/** Size of the element. | ||||
@param maxLen If maxLen is specified, don't scan more than maxL | ||||
en bytes to calculate size. | ||||
*/ | ||||
int size( int maxLen = -1 ) const; | ||||
/** Wrap this element up as a singleton object. */ | ||||
BSONObj wrap() const; | ||||
/** Wrap this element up as a singleton object with a new name. */ | ||||
BSONObj wrap( const char* newName) const; | ||||
/** field name of the element. e.g., for | ||||
name : "Joe" | ||||
"name" is the fieldname | ||||
*/ | ||||
const char * fieldName() const { | ||||
if ( eoo() ) return ""; // no fieldname for it. | ||||
return data + 1; | ||||
} | ||||
/** raw data of the element's value (so be careful). */ | ||||
const char * value() const { | ||||
return (data + fieldNameSize() + 1); | ||||
} | ||||
/** size in bytes of the element's value (when applicable). */ | ||||
int valuesize() const { | ||||
return size() - fieldNameSize() - 1; | ||||
} | ||||
bool isBoolean() const { | ||||
return type() == Bool; | ||||
} | ||||
/** @return value of a boolean element. | ||||
You must assure element is a boolean before | ||||
calling. */ | ||||
bool boolean() const { | ||||
return *value() ? true : false; | ||||
} | ||||
/** Retrieve a java style date value from the element. | ||||
Ensure element is of type Date before calling. | ||||
*/ | ||||
Date_t date() const { | ||||
return *reinterpret_cast< const Date_t* >( value() ); | ||||
} | ||||
/** Convert the value to boolean, regardless of its type, in a java | ||||
script-like fashion | ||||
(i.e., treat zero and null as false). | ||||
*/ | ||||
bool trueValue() const { | ||||
switch( type() ) { | ||||
case NumberLong: | ||||
return *reinterpret_cast< const long long* >( value() ) | ||||
!= 0; | ||||
case NumberDouble: | ||||
return *reinterpret_cast< const double* >( value() ) != | ||||
0; | ||||
case NumberInt: | ||||
return *reinterpret_cast< const int* >( value() ) != 0; | ||||
case Bool: | ||||
return boolean(); | ||||
case EOO: | ||||
case jstNULL: | ||||
case Undefined: | ||||
return false; | ||||
default: | ||||
; | ||||
} | ||||
return true; | ||||
} | ||||
/** True if element is of a numeric type. */ | ||||
bool isNumber() const { | ||||
switch( type() ) { | ||||
case NumberLong: | ||||
case NumberDouble: | ||||
case NumberInt: | ||||
return true; | ||||
default: | ||||
return false; | ||||
} | ||||
} | ||||
bool isSimpleType() const { | ||||
switch( type() ){ | ||||
case NumberLong: | ||||
case NumberDouble: | ||||
case NumberInt: | ||||
case String: | ||||
case Bool: | ||||
case Date: | ||||
case jstOID: | ||||
return true; | ||||
default: | ||||
return false; | ||||
} | ||||
} | ||||
/** Return double value for this field. MUST be NumberDouble type. | ||||
*/ | ||||
double _numberDouble() const {return *reinterpret_cast< const doubl | ||||
e* >( value() ); } | ||||
/** Return double value for this field. MUST be NumberInt type. */ | ||||
int _numberInt() const {return *reinterpret_cast< const int* >( val | ||||
ue() ); } | ||||
/** Return double value for this field. MUST be NumberLong type. */ | ||||
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. */ | ||||
int numberInt() const { | ||||
switch( type() ) { | ||||
case NumberDouble: | ||||
return (int) _numberDouble(); | ||||
case NumberInt: | ||||
return _numberInt(); | ||||
case NumberLong: | ||||
return (int) _numberLong(); | ||||
default: | ||||
return 0; | ||||
} | ||||
} | ||||
/** Retrieve long value for the element safely. Zero returned if n | ||||
ot a number. */ | ||||
long long numberLong() const { | ||||
switch( type() ) { | ||||
case NumberDouble: | ||||
return (long long) _numberDouble(); | ||||
case NumberInt: | ||||
return _numberInt(); | ||||
case NumberLong: | ||||
return _numberLong(); | ||||
default: | ||||
return 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. | ||||
*/ | ||||
double numberDouble() const { | ||||
switch( type() ) { | ||||
case NumberDouble: | ||||
return _numberDouble(); | ||||
case NumberInt: | ||||
return *reinterpret_cast< const int* >( value() ); | ||||
case NumberLong: | ||||
return (double) *reinterpret_cast< const long long* >( | ||||
value() ); | ||||
default: | ||||
return 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. | ||||
*/ | ||||
double number() const { return numberDouble(); } | ||||
/** Retrieve the object ID stored in the object. | ||||
You must ensure the element is of type jstOID first. */ | ||||
const OID &__oid() const { | ||||
return *reinterpret_cast< const OID* >( value() ); | ||||
} | ||||
/** True if element is null. */ | ||||
bool isNull() const { | ||||
return type() == jstNULL; | ||||
} | ||||
/** Size (length) of a string element. | ||||
You must assure of type String first. */ | ||||
int valuestrsize() const { | ||||
return *reinterpret_cast< const int* >( value() ); | ||||
} | ||||
// for objects the size *includes* the size of the size field | ||||
int objsize() const { | ||||
return *reinterpret_cast< const int* >( value() ); | ||||
} | ||||
/** Get a string's value. Also gives you start of the real data fo | ||||
r an embedded object. | ||||
You must assure data is of an appropriate type first -- see als | ||||
o valuestrsafe(). | ||||
*/ | ||||
const char * valuestr() const { | ||||
return value() + 4; | ||||
} | ||||
/** Get the string value of the element. If not a string returns " | ||||
". */ | ||||
const char *valuestrsafe() const { | ||||
return type() == String ? valuestr() : ""; | ||||
} | ||||
/** Get the string value of the element. If not a string returns " | ||||
". */ | ||||
string str() const { return valuestrsafe(); } | ||||
/** Get javascript code of a CodeWScope data element. */ | ||||
const char * codeWScopeCode() const { | ||||
return value() + 8; | ||||
} | ||||
/** Get the scope SavedContext of a CodeWScope data element. */ | ||||
const char * codeWScopeScopeData() const { | ||||
// TODO fix | ||||
return codeWScopeCode() + strlen( codeWScopeCode() ) + 1; | ||||
} | ||||
/** Get the embedded object this element holds. */ | ||||
BSONObj embeddedObject() const; | ||||
/* uasserts if not an object */ | ||||
BSONObj embeddedObjectUserCheck() const; | ||||
BSONObj codeWScopeObject() const; | ||||
string ascode() const { | ||||
switch( type() ){ | ||||
case String: | ||||
case Code: | ||||
return valuestr(); | ||||
case CodeWScope: | ||||
return codeWScopeCode(); | ||||
default: | ||||
log() << "can't convert type: " << (int)(type()) << " to co | ||||
de" << endl; | ||||
} | ||||
uassert( 10062 , "not code" , 0 ); | ||||
return ""; | ||||
} | ||||
/** Get binary data. Element must be of type BinData */ | ||||
const char *binData(int& len) const { | ||||
// BinData: <int len> <byte subtype> <byte[len] data> | ||||
assert( type() == BinData ); | ||||
len = valuestrsize(); | ||||
return value() + 5; | ||||
} | ||||
BinDataType binDataType() const { | ||||
// BinData: <int len> <byte subtype> <byte[len] data> | ||||
assert( type() == BinData ); | ||||
unsigned char c = (value() + 4)[0]; | ||||
return (BinDataType)c; | ||||
} | ||||
/** Retrieve the regex string for a Regex element */ | ||||
const char *regex() const { | ||||
assert(type() == RegEx); | ||||
return value(); | ||||
} | ||||
/** Retrieve the regex flags (options) for a Regex element */ | ||||
const char *regexFlags() const { | ||||
const char *p = regex(); | ||||
return p + strlen(p) + 1; | ||||
} | ||||
/** like operator== but doesn't check the fieldname, | ||||
just the value. | ||||
*/ | ||||
bool valuesEqual(const BSONElement& r) const { | ||||
return woCompare( r , false ) == 0; | ||||
} | ||||
/** Returns true if elements are equal. */ | ||||
bool operator==(const BSONElement& r) const { | ||||
return woCompare( r , true ) == 0; | ||||
} | ||||
/** Well ordered comparison. | ||||
@return <0: l<r. 0:l==r. >0:l>r | ||||
order by type, field name, and field value. | ||||
If considerFieldName is true, pay attention to the field name. | ||||
*/ | ||||
int woCompare( const BSONElement &e, bool considerFieldName = true | ||||
) const; | ||||
const char * rawdata() const { | ||||
return data; | ||||
} | ||||
/** 0 == Equality, just not defined yet */ | ||||
int getGtLtOp( int def = 0 ) const; | ||||
/** Constructs an empty element */ | ||||
BSONElement(); | ||||
/** Check that data is internally consistent. */ | ||||
void validate() const; | ||||
/** True if this element may contain subobjects. */ | ||||
bool mayEncapsulate() const { | ||||
switch ( type() ){ | ||||
case Object: | ||||
case Array: | ||||
case CodeWScope: | ||||
return true; | ||||
default: | ||||
return false; | ||||
} | ||||
} | ||||
/** True if this element can be a BSONObj */ | ||||
bool isABSONObj() const { | ||||
switch( type() ){ | ||||
case Object: | ||||
case Array: | ||||
return true; | ||||
default: | ||||
return false; | ||||
} | ||||
} | ||||
OpTime optime() const { | ||||
return OpTime( *reinterpret_cast< const unsigned long long* >( | ||||
value() ) ); | ||||
} | ||||
Date_t timestampTime() const{ | ||||
unsigned long long t = ((unsigned int*)(value() + 4 ))[0]; | ||||
return t * 1000; | ||||
} | ||||
unsigned int timestampInc() const{ | ||||
return ((unsigned int*)(value() ))[0]; | ||||
} | ||||
const char * dbrefNS() const { | ||||
uassert( 10063 , "not a dbref" , type() == DBRef ); | ||||
return value() + 4; | ||||
} | ||||
const OID& dbrefOID() const { | ||||
uassert( 10064 , "not a dbref" , type() == DBRef ); | ||||
const char * start = value(); | ||||
start += 4 + *reinterpret_cast< const int* >( start ); | ||||
return *reinterpret_cast< const OID* >( start ); | ||||
} | ||||
bool operator<( const BSONElement& other ) const { | ||||
int x = (int)canonicalType() - (int)other.canonicalType(); | ||||
if ( x < 0 ) return true; | ||||
else if ( x > 0 ) return false; | ||||
return compareElementValues(*this,other) < 0; | ||||
} | ||||
// If maxLen is specified, don't scan more than maxLen bytes. | ||||
BSONElement(const char *d, int maxLen = -1) : data(d) { | ||||
fieldNameSize_ = -1; | ||||
if ( eoo() ) | ||||
fieldNameSize_ = 0; | ||||
else { | ||||
if ( maxLen != -1 ) { | ||||
int size = strnlen( fieldName(), maxLen - 1 ); | ||||
massert( 10333 , "Invalid field name", size != -1 ); | ||||
fieldNameSize_ = size + 1; | ||||
} | ||||
} | ||||
totalSize = -1; | ||||
} | ||||
private: | ||||
const char *data; | ||||
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 */ | ||||
}; | ||||
int getGtLtOp(const BSONElement& e); | ||||
struct BSONElementCmpWithoutField { | ||||
bool operator()( const BSONElement &l, const BSONElement &r ) const | ||||
{ | ||||
return l.woCompare( r, false ) < 0; | ||||
} | ||||
}; | ||||
typedef set< BSONElement, BSONElementCmpWithoutField > BSONElementSet; | ||||
/** | ||||
C++ representation of a "BSON" object -- that is, an extended JSO | ||||
N-style | ||||
object in a binary representation. | ||||
Note that BSONObj's have a smart pointer capability built in -- so y | ||||
ou can | ||||
pass them around by value. The reference counts used to implement t | ||||
his | ||||
do not use locking, so copying and destroying BSONObj's are not thre | ||||
ad-safe | ||||
operations. | ||||
BSON object format: | ||||
\code | ||||
<unsigned totalSize> {<byte BSONType><cstring FieldName><Data>}* EOO | ||||
totalSize includes itself. | ||||
Data: | ||||
Bool: <byte> | ||||
EOO: nothing follows | ||||
Undefined: nothing follows | ||||
OID: an OID object | ||||
NumberDouble: <double> | ||||
NumberInt: <int32> | ||||
String: <unsigned32 strsizewithnull><cstring> | ||||
Date: <8bytes> | ||||
Regex: <cstring regex><cstring options> | ||||
Object: a nested object, leading with its entire size, which termin | ||||
ates with EOO. | ||||
Array: same as object | ||||
DBRef: <strlen> <cstring ns> <oid> | ||||
DBRef: a database reference: basically a collection name plus an O | ||||
bject ID | ||||
BinData: <int len> <byte subtype> <byte[len] data> | ||||
Code: a function (not a closure): same format as String. | ||||
Symbol: a language symbol (say a python symbol). same format as St | ||||
ring. | ||||
Code With Scope: <total size><String><Object> | ||||
\endcode | ||||
*/ | ||||
class BSONObj { | ||||
friend class BSONObjIterator; | ||||
class Holder { | ||||
public: | ||||
Holder( const char *objdata ) : | ||||
_objdata( objdata ) { | ||||
} | ||||
~Holder() { | ||||
free((void *)_objdata); | ||||
_objdata = 0; | ||||
} | ||||
private: | ||||
const char *_objdata; | ||||
}; | ||||
const char *_objdata; | ||||
boost::shared_ptr< Holder > _holder; | ||||
void init(const char *data, bool ifree) { | ||||
if ( ifree ) | ||||
_holder.reset( new Holder( data ) ); | ||||
_objdata = data; | ||||
if ( ! isValid() ){ | ||||
stringstream ss; | ||||
ss << "Invalid BSONObj spec size: " << objsize(); | ||||
try { | ||||
BSONElement e = firstElement(); | ||||
ss << " first element:" << e.toString() << " "; | ||||
} | ||||
catch ( ... ){} | ||||
string s = ss.str(); | ||||
massert( 10334 , s , 0 ); | ||||
} | ||||
} | ||||
#pragma pack(1) | ||||
static struct EmptyObject { | ||||
EmptyObject() { | ||||
len = 5; | ||||
jstype = EOO; | ||||
} | ||||
int len; | ||||
char jstype; | ||||
} emptyObject; | ||||
#pragma pack() | ||||
public: | ||||
/** Construct a BSONObj from data in the proper format. | ||||
@param ifree true if the BSONObj should free() the msgdata when | ||||
it destructs. | ||||
*/ | ||||
explicit BSONObj(const char *msgdata, bool ifree = false) { | ||||
init(msgdata, ifree); | ||||
} | ||||
BSONObj(const Record *r); | ||||
/** Construct an empty BSONObj -- that is, {}. */ | ||||
BSONObj() : _objdata( reinterpret_cast< const char * >( &emptyObjec | ||||
t ) ) { } | ||||
// defensive | ||||
~BSONObj() { _objdata = 0; } | ||||
void appendSelfToBufBuilder(BufBuilder& b) const { | ||||
assert( objsize() ); | ||||
b.append(reinterpret_cast<const void *>( objdata() ), objsize() | ||||
); | ||||
} | ||||
/** Readable representation of a BSON object in an extended JSON-st | ||||
yle notation. | ||||
This is an abbreviated representation which might be used for l | ||||
ogging. | ||||
*/ | ||||
string toString( bool isArray = false ) const; | ||||
operator string() const { return toString(); } | ||||
/** Properly formatted JSON string. */ | ||||
string jsonString( JsonStringFormat format = Strict ) const; | ||||
/** note: addFields always adds _id even if not specified */ | ||||
int addFields(BSONObj& from, set<string>& fields); /* returns n add | ||||
ed */ | ||||
/** returns # of top level fields in the object | ||||
note: iterates to count the fields | ||||
*/ | ||||
int nFields() const; | ||||
/** adds the field names to the fields set. does NOT clear it (app | ||||
ends). */ | ||||
int getFieldNames(set<string>& fields) const; | ||||
/** return has eoo() true if no match | ||||
supports "." notation to reach into embedded objects | ||||
*/ | ||||
BSONElement getFieldDotted(const char *name) const; | ||||
/** Like getFieldDotted(), but expands multikey arrays and returns | ||||
all matching objects | ||||
*/ | ||||
void getFieldsDotted(const char *name, BSONElementSet &ret ) const; | ||||
/** Like getFieldDotted(), but returns first array encountered whil | ||||
e traversing the | ||||
dotted fields of name. The name variable is updated to represe | ||||
nt field | ||||
names with respect to the returned element. */ | ||||
BSONElement getFieldDottedOrArray(const char *&name) const; | ||||
/** Get the field of the specified name. eoo() is true on the retur | ||||
ned | ||||
element if not found. | ||||
*/ | ||||
BSONElement getField(const char *name) const; | ||||
/** Get the field of the specified name. eoo() is true on the retur | ||||
ned | ||||
element if not found. | ||||
*/ | ||||
BSONElement getField(const string name) const { | ||||
return getField( name.c_str() ); | ||||
}; | ||||
/** Get the field of the specified name. eoo() is true on the retur | ||||
ned | ||||
element if not found. | ||||
*/ | ||||
BSONElement operator[] (const char *field) const { | ||||
return getField(field); | ||||
} | ||||
BSONElement operator[] (const string& field) const { | ||||
return getField(field); | ||||
} | ||||
BSONElement operator[] (int field) const { | ||||
stringstream ss; | ||||
ss << field; | ||||
string s = ss.str(); | ||||
return getField(s.c_str()); | ||||
} | ||||
/** @return true if field exists */ | ||||
bool hasField( const char * name )const { | ||||
return ! getField( name ).eoo(); | ||||
} | ||||
/** @return "" if DNE or wrong type */ | ||||
const char * getStringField(const char *name) const; | ||||
/** @return subobject of the given name */ | ||||
BSONObj getObjectField(const char *name) const; | ||||
/** @return INT_MIN if not present - does some type conversions */ | ||||
int getIntField(const char *name) const; | ||||
/** @return false if not present */ | ||||
bool getBoolField(const char *name) const; | ||||
/** makes a new BSONObj with the fields specified in pattern. | ||||
fields returned in the order they appear in pattern. | ||||
if any field is missing or undefined in the object, that field i | ||||
n the | ||||
output will be null. | ||||
sets output field names to match pattern field names. | ||||
If an array is encountered while scanning the dotted names in pa | ||||
ttern, | ||||
that field is treated as missing. | ||||
*/ | ||||
BSONObj extractFieldsDotted(BSONObj pattern) const; | ||||
/** | ||||
sets element field names to empty string | ||||
If a field in pattern is missing, it is omitted from the returne | ||||
d | ||||
object. | ||||
*/ | ||||
BSONObj extractFieldsUnDotted(BSONObj pattern) const; | ||||
/** extract items from object which match a pattern object. | ||||
e.g., if pattern is { x : 1, y : 1 }, builds an obje | ||||
ct with | ||||
x and y elements of this object, if they are present | ||||
. | ||||
returns elements with original field names | ||||
*/ | ||||
BSONObj extractFields(const BSONObj &pattern , bool fillWithNull=fa | ||||
lse) const; | ||||
BSONObj filterFieldsUndotted(const BSONObj &filter, bool inFilter) | ||||
const; | ||||
BSONElement getFieldUsingIndexNames(const char *fieldName, const BS | ||||
ONObj &indexKey) const; | ||||
/** @return the raw data of the object */ | ||||
const char *objdata() const { | ||||
return _objdata; | ||||
} | ||||
/** @return total size of the BSON object in bytes */ | ||||
int objsize() const { | ||||
return *(reinterpret_cast<const int*>(objdata())); | ||||
} | ||||
bool isValid(); | ||||
/** @return if the user is a valid user doc | ||||
criter: isValid() no . or $ field names | ||||
*/ | ||||
bool okForStorage() const; | ||||
/** @return true if object is empty -- i.e., {} */ | ||||
bool isEmpty() const { | ||||
return objsize() <= 5; | ||||
} | ||||
void dump() const { | ||||
out() << hex; | ||||
const char *p = objdata(); | ||||
for ( int i = 0; i < objsize(); i++ ) { | ||||
out() << i << '\t' << ( 0xff & ( (unsigned) *p ) ); | ||||
if ( *p >= 'A' && *p <= 'z' ) | ||||
out() << '\t' << *p; | ||||
out() << endl; | ||||
p++; | ||||
} | ||||
} | ||||
// Alternative output format | ||||
string hexDump() const; | ||||
/**wo='well ordered'. fields must be in same order in each object. | ||||
Ordering is with respect to the signs of the elements in idxKey. | ||||
@return <0 if l<r. 0 if l==r. >0 if l>r | ||||
*/ | ||||
int woCompare(const BSONObj& r, const BSONObj &idxKey = BSONObj(), | ||||
bool considerFieldName=true) const; | ||||
int woSortOrder( const BSONObj& r , const BSONObj& sortKey ) const; | ||||
/** This is "shallow equality" -- ints and doubles won't match. fo | ||||
r a | ||||
deep equality test use woCompare (which is slower). | ||||
*/ | ||||
bool woEqual(const BSONObj& r) const { | ||||
int os = objsize(); | ||||
if ( os == r.objsize() ) { | ||||
return (os == 0 || memcmp(objdata(),r.objdata(),os)==0); | ||||
} | ||||
return false; | ||||
} | ||||
/** @return first field of the object */ | ||||
BSONElement firstElement() const { | ||||
return BSONElement(objdata() + 4); | ||||
} | ||||
/** use getField() instead. */ | ||||
//BSONElement getField(const char *name) const; | ||||
//BSONElement getField(string name) const { | ||||
/** @return true if field exists in the object */ | ||||
bool hasElement(const char *name) const; | ||||
/** Get the _id field from the object. For good performance | ||||
drivers should | ||||
assure that _id is the first element of the object; however, co | ||||
rrect operation | ||||
is assured regardless. | ||||
@return true if found | ||||
*/ | ||||
bool getObjectID(BSONElement& e) const; | ||||
/** makes a copy of the object. | ||||
*/ | ||||
BSONObj copy() const; | ||||
/* make sure the data buffer is under the control of BSONObj's and | ||||
not a remote buffer */ | ||||
BSONObj getOwned() const{ | ||||
if ( !isOwned() ) | ||||
return copy(); | ||||
return *this; | ||||
} | ||||
bool isOwned() const { return _holder.get() != 0; } | ||||
/** @return A hash code for the object */ | ||||
int hash() const { | ||||
unsigned x = 0; | ||||
const char *p = objdata(); | ||||
for ( int i = 0; i < objsize(); i++ ) | ||||
x = x * 131 + p[i]; | ||||
return (x & 0x7fffffff) | 0x8000000; // must be > 0 | ||||
} | ||||
// Return a version of this object where top level elements of type | ||||
s | ||||
// that are not part of the bson wire protocol are replaced with | ||||
// string identifier equivalents. | ||||
// TODO Support conversion of element types other than min and max. | ||||
BSONObj clientReadable() const; | ||||
/** Return new object with the field names replaced by those in the | ||||
passed object. */ | ||||
BSONObj replaceFieldNames( const BSONObj &obj ) const; | ||||
/** true unless corrupt */ | ||||
bool valid() const; | ||||
string md5() const; | ||||
bool operator==( const BSONObj& other ){ | ||||
return woCompare( other ) == 0; | ||||
} | ||||
enum MatchType { | ||||
Equality = 0, | ||||
LT = 0x1, | ||||
LTE = 0x3, | ||||
GTE = 0x6, | ||||
GT = 0x4, | ||||
opIN = 0x8, // { x : { $in : [1,2,3] } } | ||||
NE = 0x9, | ||||
opSIZE = 0x0A, | ||||
opALL = 0x0B, | ||||
NIN = 0x0C, | ||||
opEXISTS = 0x0D, | ||||
opMOD = 0x0E, | ||||
opTYPE = 0x0F, | ||||
opREGEX = 0x10, | ||||
opOPTIONS = 0x11, | ||||
opELEM_MATCH = 0x12, | ||||
opNEAR = 0x13, | ||||
opWITHIN = 0x14, | ||||
opMAX_DISTANCE=0x15 | ||||
}; | ||||
}; | ||||
ostream& operator<<( ostream &s, const BSONObj &o ); | ||||
ostream& operator<<( ostream &s, const BSONElement &e ); | ||||
struct BSONArray: BSONObj { | ||||
// Don't add anything other than forwarding constructors!!! | ||||
BSONArray(): BSONObj() {} | ||||
explicit BSONArray(const BSONObj& obj): BSONObj(obj) {} | ||||
}; | ||||
class BSONObjCmp { | ||||
public: | ||||
BSONObjCmp( const BSONObj &_order = BSONObj() ) : order( _order ) { | ||||
} | ||||
bool operator()( const BSONObj &l, const BSONObj &r ) const { | ||||
return l.woCompare( r, order ) < 0; | ||||
} | ||||
private: | ||||
BSONObj order; | ||||
}; | ||||
class BSONObjCmpDefaultOrder : public BSONObjCmp { | ||||
public: | ||||
BSONObjCmpDefaultOrder() : BSONObjCmp( BSONObj() ) {} | ||||
}; | ||||
typedef set< BSONObj, BSONObjCmpDefaultOrder > BSONObjSetDefaultOrder; | ||||
enum FieldCompareResult { | ||||
LEFT_SUBFIELD = -2, | ||||
LEFT_BEFORE = -1, | ||||
SAME = 0, | ||||
RIGHT_BEFORE = 1 , | ||||
RIGHT_SUBFIELD = 2 | ||||
}; | ||||
FieldCompareResult compareDottedFieldNames( const string& l , const str | ||||
ing& r ); | ||||
/** Use BSON macro to build a BSONObj from a stream | ||||
e.g., | ||||
BSON( "name" << "joe" << "age" << 33 ) | ||||
with auto-generated object id: | ||||
BSON( GENOID << "name" << "joe" << "age" << 33 ) | ||||
The labels GT, GTE, LT, LTE, NE can be helpful for stream-oriented cons | ||||
truction | ||||
of a BSONObj, particularly when assembling a Query. For example, | ||||
BSON( "a" << GT << 23.4 << NE << 30 << "b" << 2 ) produces the object | ||||
{ a: { \$gt: 23.4, \$ne: 30 }, b: 2 }. | ||||
*/ | ||||
#define BSON(x) (( mongo::BSONObjBuilder(64) << x ).obj()) | ||||
/** Use BSON_ARRAY macro like BSON macro, but without keys | ||||
BSONArray arr = BSON_ARRAY( "hello" << 1 << BSON( "foo" << BSON_ARRAY( | ||||
"bar" << "baz" << "qux" ) ) ); | ||||
*/ | ||||
#define BSON_ARRAY(x) (( mongo::BSONArrayBuilder() << x ).arr()) | ||||
/* Utility class to auto assign object IDs. | ||||
Example: | ||||
cout << BSON( GENOID << "z" << 3 ); // { _id : ..., z : 3 } | ||||
*/ | ||||
extern struct IDLabeler { } GENOID; | ||||
/* Utility class to add a Date element with the current time | ||||
Example: | ||||
cout << BSON( "created" << DATENOW ); // { created : "2009-10-09 1 | ||||
1:41:42" } | ||||
*/ | ||||
extern struct DateNowLabeler { } DATENOW; | ||||
// Utility class to implement GT, GTE, etc as described above. | ||||
class Labeler { | ||||
public: | ||||
struct Label { | ||||
Label( const char *l ) : l_( l ) {} | ||||
const char *l_; | ||||
}; | ||||
Labeler( const Label &l, BSONObjBuilderValueStream *s ) : l_( l ), | ||||
s_( s ) {} | ||||
template<class T> | ||||
BSONObjBuilder& operator<<( T value ); | ||||
/* the value of the element e is appended i.e. for | ||||
"age" << GT << someElement | ||||
one gets | ||||
{ age : { $gt : someElement's value } } | ||||
*/ | ||||
BSONObjBuilder& operator<<( const BSONElement& e ); | ||||
private: | ||||
const Label &l_; | ||||
BSONObjBuilderValueStream *s_; | ||||
}; | ||||
extern Labeler::Label GT; | ||||
extern Labeler::Label GTE; | ||||
extern Labeler::Label LT; | ||||
extern Labeler::Label LTE; | ||||
extern Labeler::Label NE; | ||||
extern Labeler::Label SIZE; | ||||
// Utility class to implement BSON( key << val ) as described above. | ||||
class BSONObjBuilderValueStream : public boost::noncopyable { | ||||
public: | ||||
friend class Labeler; | ||||
BSONObjBuilderValueStream( BSONObjBuilder * builder ); | ||||
BSONObjBuilder& operator<<( const BSONElement& e ); | ||||
template<class T> | ||||
BSONObjBuilder& operator<<( T value ); | ||||
BSONObjBuilder& operator<<(DateNowLabeler& id); | ||||
Labeler operator<<( const Labeler::Label &l ); | ||||
void endField( const char *nextFieldName = 0 ); | ||||
bool subobjStarted() const { return _fieldName != 0; } | ||||
private: | ||||
const char * _fieldName; | ||||
BSONObjBuilder * _builder; | ||||
bool haveSubobj() const { return _subobj.get() != 0; } | ||||
BSONObjBuilder *subobj(); | ||||
auto_ptr< BSONObjBuilder > _subobj; | ||||
}; | ||||
/** | ||||
used in conjuction with BSONObjBuilder, allows for proper buffer siz | ||||
e to prevent crazy memory usage | ||||
*/ | ||||
class BSONSizeTracker { | ||||
public: | ||||
#define BSONSizeTrackerSize 10 | ||||
BSONSizeTracker(){ | ||||
_pos = 0; | ||||
for ( int i=0; i<BSONSizeTrackerSize; i++ ) | ||||
_sizes[i] = 512; // this is the default, so just be consist | ||||
ent | ||||
} | ||||
~BSONSizeTracker(){ | ||||
} | ||||
void got( int size ){ | ||||
_sizes[_pos++] = size; | ||||
if ( _pos >= BSONSizeTrackerSize ) | ||||
_pos = 0; | ||||
} | ||||
/** | ||||
* right now choosing largest size | ||||
*/ | ||||
int getSize() const { | ||||
int x = 16; // sane min | ||||
for ( int i=0; i<BSONSizeTrackerSize; i++ ){ | ||||
if ( _sizes[i] > x ) | ||||
x = _sizes[i]; | ||||
} | ||||
return x; | ||||
} | ||||
private: | ||||
int _pos; | ||||
int _sizes[BSONSizeTrackerSize]; | ||||
}; | ||||
/** | ||||
utility for creating a BSONObj | ||||
*/ | ||||
class BSONObjBuilder : boost::noncopyable { | ||||
public: | ||||
/** @param initsize this is just a hint as to the final size of the | ||||
object */ | ||||
BSONObjBuilder(int initsize=512) : b(buf_), buf_(initsize), offset_ | ||||
( 0 ), s_( this ) , _tracker(0) { | ||||
b.skip(4); /*leave room for size field*/ | ||||
} | ||||
/** @param baseBuilder construct a BSONObjBuilder using an existing | ||||
BufBuilder */ | ||||
BSONObjBuilder( BufBuilder &baseBuilder ) : b( baseBuilder ), buf_( | ||||
0 ), offset_( baseBuilder.len() ), s_( this ) , _tracker(0) { | ||||
b.skip( 4 ); | ||||
} | ||||
BSONObjBuilder( const BSONSizeTracker & tracker ) : b(buf_) , buf_( | ||||
tracker.getSize() ), offset_(0), s_( this ) , _tracker( (BSONSizeTracker*)( | ||||
&tracker) ){ | ||||
b.skip( 4 ); | ||||
} | ||||
/** add all the fields from the object specified to this object */ | ||||
BSONObjBuilder& appendElements(BSONObj x); | ||||
/** append element to the object we are building */ | ||||
void append( const BSONElement& e) { | ||||
assert( !e.eoo() ); // do not append eoo, that would corrupt us | ||||
. the builder auto appends when done() is called. | ||||
b.append((void*) e.rawdata(), e.size()); | ||||
} | ||||
/** append an element but with a new name */ | ||||
void appendAs(const BSONElement& e, const char *as) { | ||||
assert( !e.eoo() ); // do not append eoo, that would corrupt us | ||||
. the builder auto appends when done() is called. | ||||
b.append((char) e.type()); | ||||
b.append(as); | ||||
b.append((void *) e.value(), e.valuesize()); | ||||
} | ||||
void appendAs(const BSONElement& e, const string& as) { | ||||
appendAs( e , as.c_str() ); | ||||
} | ||||
/** add a subobject as a member */ | ||||
void append(const char *fieldName, BSONObj subObj) { | ||||
b.append((char) Object); | ||||
b.append(fieldName); | ||||
b.append((void *) subObj.objdata(), subObj.objsize()); | ||||
} | ||||
void append(const string& fieldName , BSONObj subObj) { | ||||
append( fieldName.c_str() , subObj ); | ||||
} | ||||
/** add header for a new subobject and return bufbuilder for writin | ||||
g to | ||||
the subobject's body */ | ||||
BufBuilder &subobjStart(const char *fieldName) { | ||||
b.append((char) Object); | ||||
b.append(fieldName); | ||||
return b; | ||||
} | ||||
/** add a subobject as a member with type Array. Thus arr object s | ||||
hould have "0", "1", ... | ||||
style fields in it. | ||||
*/ | ||||
void appendArray(const char *fieldName, BSONObj subObj) { | ||||
b.append((char) Array); | ||||
b.append(fieldName); | ||||
b.append((void *) subObj.objdata(), subObj.objsize()); | ||||
} | ||||
void append(const char *fieldName, BSONArray arr) { appendArray(fie | ||||
ldName, arr); } | ||||
/** add header for a new subarray and return bufbuilder for writing | ||||
to | ||||
the subarray's body */ | ||||
BufBuilder &subarrayStart(const char *fieldName) { | ||||
b.append((char) Array); | ||||
b.append(fieldName); | ||||
return b; | ||||
} | ||||
/** Append a boolean element */ | ||||
void appendBool(const char *fieldName, int val) { | ||||
b.append((char) Bool); | ||||
b.append(fieldName); | ||||
b.append((char) (val?1:0)); | ||||
} | ||||
/** Append a boolean element */ | ||||
void append(const char *fieldName, bool val) { | ||||
b.append((char) Bool); | ||||
b.append(fieldName); | ||||
b.append((char) (val?1:0)); | ||||
} | ||||
/** Append a 32 bit integer element */ | ||||
void append(const char *fieldName, int n) { | ||||
b.append((char) NumberInt); | ||||
b.append(fieldName); | ||||
b.append(n); | ||||
} | ||||
/** Append a 32 bit integer element */ | ||||
void append(const string &fieldName, int n) { | ||||
append( fieldName.c_str(), n ); | ||||
} | ||||
/** Append a 32 bit unsigned element - cast to a signed int. */ | ||||
void append(const char *fieldName, unsigned n) { append(fieldName, | ||||
(int) n); } | ||||
/** Append a NumberLong */ | ||||
void append(const char *fieldName, long long n) { | ||||
b.append((char) NumberLong); | ||||
b.append(fieldName); | ||||
b.append(n); | ||||
} | ||||
/** Append a NumberLong */ | ||||
void append(const string& fieldName, long long n) { | ||||
append( fieldName.c_str() , n ); | ||||
} | ||||
/** appends a number. if n < max(int)/2 then uses int, otherwise l | ||||
ong long */ | ||||
void appendIntOrLL( const string& fieldName , long long n ){ | ||||
long long x = n; | ||||
if ( x < 0 ) | ||||
x = x * -1; | ||||
if ( x < ( numeric_limits<int>::max() / 2 ) ) | ||||
append( fieldName.c_str() , (int)n ); | ||||
else | ||||
append( fieldName.c_str() , n ); | ||||
} | ||||
/** | ||||
* appendNumber is a series of method for appending the smallest se | ||||
nsible type | ||||
* mostly for JS | ||||
*/ | ||||
void appendNumber( const string& fieldName , int n ){ | ||||
append( fieldName.c_str() , n ); | ||||
} | ||||
void appendNumber( const string& fieldName , double d ){ | ||||
append( fieldName.c_str() , d ); | ||||
} | ||||
void appendNumber( const string& fieldName , long long l ){ | ||||
static long long maxInt = (int)pow( 2.0 , 30.0 ); | ||||
static long long maxDouble = (long long)pow( 2.0 , 40.0 ); | ||||
if ( l < maxInt ) | ||||
append( fieldName.c_str() , (int)l ); | ||||
else if ( l < maxDouble ) | ||||
append( fieldName.c_str() , (double)l ); | ||||
else | ||||
append( fieldName.c_str() , l ); | ||||
} | ||||
/** Append a double element */ | ||||
BSONObjBuilder& append(const char *fieldName, double n) { | ||||
b.append((char) NumberDouble); | ||||
b.append(fieldName); | ||||
b.append(n); | ||||
return *this; | ||||
} | ||||
/** tries to append the data as a number | ||||
* @return true if the data was able to be converted to a number | ||||
*/ | ||||
bool appendAsNumber( const string& fieldName , const string& data ) | ||||
; | ||||
/** Append a BSON Object ID (OID type). */ | ||||
void appendOID(const char *fieldName, OID *oid = 0 , bool generateI | ||||
fBlank = false ) { | ||||
b.append((char) jstOID); | ||||
b.append(fieldName); | ||||
if ( oid ) | ||||
b.append( (void *) oid, 12 ); | ||||
else { | ||||
OID tmp; | ||||
if ( generateIfBlank ) | ||||
tmp.init(); | ||||
else | ||||
tmp.clear(); | ||||
b.append( (void *) &tmp, 12 ); | ||||
} | ||||
} | ||||
void append( const char *fieldName, OID oid ) { | ||||
appendOID( fieldName, &oid ); | ||||
} | ||||
/** Append a time_t date. | ||||
@param dt a C-style 32 bit date value, that is | ||||
the number of seconds since January 1, 1970, 00:00:00 | ||||
GMT | ||||
*/ | ||||
void appendTimeT(const char *fieldName, time_t dt) { | ||||
b.append((char) Date); | ||||
b.append(fieldName); | ||||
b.append(static_cast<unsigned long long>(dt) * 1000); | ||||
} | ||||
/** Append a date. | ||||
@param dt a Java-style 64 bit date value, that is | ||||
the number of milliseconds since January 1, 1970, 00: | ||||
00:00 GMT | ||||
*/ | ||||
void appendDate(const char *fieldName, Date_t dt) { | ||||
b.append((char) Date); | ||||
b.append(fieldName); | ||||
b.append(dt); | ||||
} | ||||
void append(const char *fieldName, Date_t dt) { | ||||
appendDate(fieldName, dt); | ||||
} | ||||
/** Append a regular expression value | ||||
@param regex the regular expression pattern | ||||
@param regex options such as "i" or "g" | ||||
*/ | ||||
void appendRegex(const char *fieldName, const char *regex, const ch | ||||
ar *options = "") { | ||||
b.append((char) RegEx); | ||||
b.append(fieldName); | ||||
b.append(regex); | ||||
b.append(options); | ||||
} | ||||
/** Append a regular expression value | ||||
@param regex the regular expression pattern | ||||
@param regex options such as "i" or "g" | ||||
*/ | ||||
void appendRegex(string fieldName, string regex, string options = " | ||||
") { | ||||
appendRegex(fieldName.c_str(), regex.c_str(), options.c_str()); | ||||
} | ||||
void appendCode(const char *fieldName, const char *code) { | ||||
b.append((char) Code); | ||||
b.append(fieldName); | ||||
b.append((int) strlen(code)+1); | ||||
b.append(code); | ||||
} | ||||
/** Append a string element */ | ||||
BSONObjBuilder& append(const char *fieldName, const char *str) { | ||||
b.append((char) String); | ||||
b.append(fieldName); | ||||
b.append((int) strlen(str)+1); | ||||
b.append(str); | ||||
return *this; | ||||
} | ||||
/** Append a string element */ | ||||
void append(const char *fieldName, string str) { | ||||
append(fieldName, str.c_str()); | ||||
} | ||||
void appendSymbol(const char *fieldName, const char *symbol) { | ||||
b.append((char) Symbol); | ||||
b.append(fieldName); | ||||
b.append((int) strlen(symbol)+1); | ||||
b.append(symbol); | ||||
} | ||||
/** Append a Null element to the object */ | ||||
void appendNull( const char *fieldName ) { | ||||
b.append( (char) jstNULL ); | ||||
b.append( fieldName ); | ||||
} | ||||
// Append an element that is less than all other keys. | ||||
void appendMinKey( const char *fieldName ) { | ||||
b.append( (char) MinKey ); | ||||
b.append( fieldName ); | ||||
} | ||||
// Append an element that is greater than all other keys. | ||||
void appendMaxKey( const char *fieldName ) { | ||||
b.append( (char) MaxKey ); | ||||
b.append( fieldName ); | ||||
} | ||||
// Append a Timestamp field -- will be updated to next OpTime on db | ||||
insert. | ||||
void appendTimestamp( const char *fieldName ) { | ||||
b.append( (char) Timestamp ); | ||||
b.append( fieldName ); | ||||
b.append( (unsigned long long) 0 ); | ||||
} | ||||
void appendTimestamp( const char *fieldName , unsigned long long va | ||||
l ) { | ||||
b.append( (char) Timestamp ); | ||||
b.append( fieldName ); | ||||
b.append( val ); | ||||
} | ||||
/** | ||||
* @param time - in millis (but stored in seconds) | ||||
*/ | ||||
void appendTimestamp( const char *fieldName , unsigned long long ti | ||||
me , unsigned int inc ){ | ||||
OpTime t( (unsigned) (time / 1000) , inc ); | ||||
appendTimestamp( fieldName , t.asDate() ); | ||||
} | ||||
/* Deprecated (but supported) */ | ||||
void appendDBRef( const char *fieldName, const char *ns, const OID | ||||
&oid ) { | ||||
b.append( (char) DBRef ); | ||||
b.append( fieldName ); | ||||
b.append( (int) strlen( ns ) + 1 ); | ||||
b.append( ns ); | ||||
b.append( (void *) &oid, 12 ); | ||||
} | ||||
/** Append a binary data element | ||||
@param fieldName name of the field | ||||
@param len length of the binary data in bytes | ||||
@param type type information for the data. @see BinDataType. U | ||||
se ByteArray if you | ||||
don't care about the type. | ||||
@param data the byte array | ||||
*/ | ||||
void appendBinData( const char *fieldName, int len, BinDataType typ | ||||
e, const char *data ) { | ||||
b.append( (char) BinData ); | ||||
b.append( fieldName ); | ||||
b.append( len ); | ||||
b.append( (char) type ); | ||||
b.append( (void *) data, len ); | ||||
} | ||||
void appendBinData( const char *fieldName, int len, BinDataType typ | ||||
e, const unsigned char *data ) { | ||||
appendBinData(fieldName, len, type, (const char *) data); | ||||
} | ||||
/** | ||||
@param len the length of data | ||||
*/ | ||||
void appendBinDataArray( const char * fieldName , const char * data | ||||
, int len ){ | ||||
b.append( (char) BinData ); | ||||
b.append( fieldName ); | ||||
b.append( len + 4 ); | ||||
b.append( (char)0x2 ); | ||||
b.append( len ); | ||||
b.append( (void *) data, len ); | ||||
} | ||||
/** Append to the BSON object a field of type CodeWScope. This is | ||||
a javascript code | ||||
fragment accompanied by some scope that goes with it. | ||||
*/ | ||||
void appendCodeWScope( const char *fieldName, const char *code, con | ||||
st BSONObj &scope ) { | ||||
b.append( (char) CodeWScope ); | ||||
b.append( fieldName ); | ||||
b.append( ( int )( 4 + 4 + strlen( code ) + 1 + scope.objsize() | ||||
) ); | ||||
b.append( ( int ) strlen( code ) + 1 ); | ||||
b.append( code ); | ||||
b.append( ( void * )scope.objdata(), scope.objsize() ); | ||||
} | ||||
void appendUndefined( const char *fieldName ) { | ||||
b.append( (char) Undefined ); | ||||
b.append( fieldName ); | ||||
} | ||||
/* helper function -- see Query::where() for primary way to do this | ||||
. */ | ||||
void appendWhere( const char *code, const BSONObj &scope ){ | ||||
appendCodeWScope( "$where" , code , scope ); | ||||
} | ||||
void appendWhere( const string &code, const BSONObj &scope ){ | ||||
appendWhere( code.c_str(), scope ); | ||||
} | ||||
/** | ||||
these are the min/max when comparing, not strict min/max element | ||||
s for a given type | ||||
*/ | ||||
void appendMinForType( const string& field , int type ); | ||||
void appendMaxForType( const string& field , int type ); | ||||
/** Append an array of values. */ | ||||
template < class T > | ||||
void append( const char *fieldName, const vector< T >& vals ) { | ||||
BSONObjBuilder arrBuilder; | ||||
for ( unsigned int i = 0; i < vals.size(); ++i ) | ||||
arrBuilder.append( numStr( i ).c_str(), vals[ i ] ); | ||||
marshalArray( fieldName, arrBuilder.done() ); | ||||
} | ||||
/* Append an array of ints | ||||
void appendArray( const char *fieldName, const vector< int >& vals | ||||
) { | ||||
BSONObjBuilder arrBuilder; | ||||
for ( unsigned i = 0; i < vals.size(); ++i ) | ||||
arrBuilder.append( numStr( i ).c_str(), vals[ i ] ); | ||||
marshalArray( fieldName, arrBuilder.done() ); | ||||
}*/ | ||||
/** The returned BSONObj will free the buffer when it is finished. | ||||
*/ | ||||
BSONObj obj() { | ||||
massert( 10335 , "builder does not own memory", owned() ); | ||||
int l; | ||||
return BSONObj(decouple(l), true); | ||||
} | ||||
/** Fetch the object we have built. | ||||
BSONObjBuilder still frees the object when the build | ||||
er goes out of | ||||
scope -- very important to keep in mind. Use obj() | ||||
if you | ||||
would like the BSONObj to last longer than the build | ||||
er. | ||||
*/ | ||||
BSONObj done() { | ||||
return BSONObj(_done()); | ||||
} | ||||
/** Peek at what is in the builder, but leave the builder ready for | ||||
more appends. | ||||
The returned object is only valid until the next modification o | ||||
r destruction of the builder. | ||||
Intended use case: append a field if not already there. | ||||
*/ | ||||
BSONObj asTempObj() { | ||||
BSONObj temp(_done()); | ||||
b.setlen(b.len()-1); //next append should overwrite the EOO | ||||
return temp; | ||||
} | ||||
/* assume ownership of the buffer - you must then free it (with fre | ||||
e()) */ | ||||
char* decouple(int& l) { | ||||
char *x = _done(); | ||||
assert( x ); | ||||
l = b.len(); | ||||
b.decouple(); | ||||
return x; | ||||
} | ||||
void decouple() { | ||||
b.decouple(); // post done() call version. be sure jsobj fr | ||||
ees... | ||||
} | ||||
void appendKeys( const BSONObj& keyPattern , const BSONObj& values | ||||
); | ||||
private: | ||||
static const string numStrs[100]; // cache of 0 to 99 inclusive | ||||
public: | ||||
static string numStr( int i ) { | ||||
if (i>=0 && i<100) | ||||
return numStrs[i]; | ||||
stringstream o; | ||||
o << i; | ||||
return o.str(); | ||||
} | ||||
/** Stream oriented way to add field names and values. */ | ||||
BSONObjBuilderValueStream &operator<<(const char * name ) { | ||||
s_.endField( name ); | ||||
return s_; | ||||
} | ||||
/** Stream oriented way to add field names and values. */ | ||||
BSONObjBuilder& operator<<( IDLabeler ) { | ||||
OID oid; | ||||
oid.init(); | ||||
appendOID("_id", &oid); | ||||
return *this; | ||||
} | ||||
// prevent implicit string conversions which would allow bad things | ||||
like BSON( BSON( "foo" << 1 ) << 2 ) | ||||
struct ForceExplicitString { | ||||
ForceExplicitString( const string &str ) : str_( str ) {} | ||||
string str_; | ||||
}; | ||||
/** Stream oriented way to add field names and values. */ | ||||
BSONObjBuilderValueStream &operator<<( const ForceExplicitString& n | ||||
ame ) { | ||||
return operator<<( name.str_.c_str() ); | ||||
} | ||||
Labeler operator<<( const Labeler::Label &l ) { | ||||
massert( 10336 , "No subobject started", s_.subobjStarted() ); | ||||
return s_ << l; | ||||
} | ||||
bool owned() const { | ||||
return &b == &buf_; | ||||
} | ||||
private: | ||||
// Append the provided arr object as an array. | ||||
void marshalArray( const char *fieldName, const BSONObj &arr ) { | ||||
b.append( (char) Array ); | ||||
b.append( fieldName ); | ||||
b.append( (void *) arr.objdata(), arr.objsize() ); | ||||
} | ||||
char* _done() { | ||||
s_.endField(); | ||||
b.append((char) EOO); | ||||
char *data = b.buf() + offset_; | ||||
int size = b.len() - offset_; | ||||
*((int*)data) = size; | ||||
if ( _tracker ) | ||||
_tracker->got( size ); | ||||
return data; | ||||
} | ||||
BufBuilder &b; | ||||
BufBuilder buf_; | ||||
int offset_; | ||||
BSONObjBuilderValueStream s_; | ||||
BSONSizeTracker * _tracker; | ||||
}; | ||||
class BSONArrayBuilder : boost::noncopyable{ | ||||
public: | ||||
BSONArrayBuilder() : _i(0), _b() {} | ||||
BSONArrayBuilder( BufBuilder &b ) : _i(0), _b(b) {} | ||||
template <typename T> | ||||
BSONArrayBuilder& append(const T& x){ | ||||
_b.append(num().c_str(), x); | ||||
return *this; | ||||
} | ||||
BSONArrayBuilder& append(const BSONElement& e){ | ||||
_b.appendAs(e, num()); | ||||
return *this; | ||||
} | ||||
template <typename T> | ||||
BSONArrayBuilder& operator<<(const T& x){ | ||||
return append(x); | ||||
} | ||||
void appendNull() { | ||||
_b.appendNull(num().c_str()); | ||||
} | ||||
BSONArray arr(){ return BSONArray(_b.obj()); } | ||||
BSONObj done() { return _b.done(); } | ||||
template <typename T> | ||||
BSONArrayBuilder& append(const char *name, const T& x){ | ||||
fill( name ); | ||||
append( x ); | ||||
return *this; | ||||
} | ||||
BufBuilder &subobjStart( const char *name ) { | ||||
fill( name ); | ||||
return _b.subobjStart( num().c_str() ); | ||||
} | ||||
BufBuilder &subarrayStart( const char *name ) { | ||||
fill( name ); | ||||
return _b.subarrayStart( num().c_str() ); | ||||
} | ||||
void appendArray( const char *name, BSONObj subObj ) { | ||||
fill( name ); | ||||
_b.appendArray( num().c_str(), subObj ); | ||||
} | ||||
void appendAs( const BSONElement &e, const char *name ) { | ||||
fill( name ); | ||||
append( e ); | ||||
} | ||||
private: | ||||
void fill( const char *name ) { | ||||
char *r; | ||||
int n = strtol( name, &r, 10 ); | ||||
uassert( 13048, "can't append to array using string field name" | ||||
, !*r ); | ||||
while( _i < n ) | ||||
append( nullElt() ); | ||||
} | ||||
static BSONElement nullElt() { | ||||
static BSONObj n = nullObj(); | ||||
return n.firstElement(); | ||||
} | ||||
static BSONObj nullObj() { | ||||
BSONObjBuilder b; | ||||
b.appendNull( "" ); | ||||
return b.obj(); | ||||
} | ||||
string num(){ return _b.numStr(_i++); } | ||||
int _i; | ||||
BSONObjBuilder _b; | ||||
}; | ||||
/** iterator for a BSONObj | ||||
Note each BSONObj ends with an EOO element: so you will get more() o | ||||
n an empty | ||||
object, although next().eoo() will be true. | ||||
todo: we may want to make a more stl-like iterator interface for thi | ||||
s | ||||
with things like begin() and end() | ||||
*/ | ||||
class BSONObjIterator { | ||||
public: | ||||
/** Create an iterator for a BSON object. | ||||
*/ | ||||
BSONObjIterator(const BSONObj& jso) { | ||||
int sz = jso.objsize(); | ||||
if ( sz == 0 ) { | ||||
pos = theend = 0; | ||||
return; | ||||
} | ||||
pos = jso.objdata() + 4; | ||||
theend = jso.objdata() + sz; | ||||
} | ||||
/** @return true if more elements exist to be enumerated. */ | ||||
bool moreWithEOO() { | ||||
return pos < theend; | ||||
} | ||||
bool more(){ | ||||
return pos < theend && pos[0]; | ||||
} | ||||
/** @return the next element in the object. For the final element, | ||||
element.eoo() will be true. */ | ||||
BSONElement next( bool checkEnd = false ) { | ||||
assert( pos < theend ); | ||||
BSONElement e( pos, checkEnd ? (int)(theend - pos) : -1 ); | ||||
pos += e.size( checkEnd ? (int)(theend - pos) : -1 ); | ||||
return e; | ||||
} | ||||
private: | ||||
const char *pos; | ||||
const char *theend; | ||||
}; | ||||
/* iterator a BSONObj which is an array, in array order. | ||||
class JSArrayIter { | ||||
public: | ||||
BSONObjIterator(const BSONObj& jso) { | ||||
... | ||||
} | ||||
bool more() { return ... } | ||||
BSONElement next() { | ||||
... | ||||
} | ||||
}; | ||||
*/ | ||||
extern BSONObj maxKey; | ||||
extern BSONObj minKey; | ||||
// a BoundList contains intervals specified by inclusive start | ||||
// 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} | ||||
// and direction +1, one valid BoundList is: (1, 2); (4, 6). The same | ||||
BoundList | ||||
// would be valid for index {i:-1} with direction -1. | ||||
typedef vector< pair< BSONObj, BSONObj > > BoundList; | ||||
/*- just for testing -- */ | ||||
#pragma pack(1) | ||||
struct JSObj1 { | ||||
JSObj1() { | ||||
totsize=sizeof(JSObj1); | ||||
n = NumberDouble; | ||||
strcpy_s(nname, 5, "abcd"); | ||||
N = 3.1; | ||||
s = String; | ||||
strcpy_s(sname, 7, "abcdef"); | ||||
slen = 10; | ||||
strcpy_s(sval, 10, "123456789"); | ||||
eoo = EOO; | ||||
} | ||||
unsigned totsize; | ||||
char n; | ||||
char nname[5]; | ||||
double N; | ||||
char s; | ||||
char sname[7]; | ||||
unsigned slen; | ||||
char sval[10]; | ||||
char eoo; | ||||
}; | ||||
#pragma pack() | ||||
extern JSObj1 js1; | ||||
#ifdef _DEBUG | ||||
#define CHECK_OBJECT( o , msg ) massert( 10337 , (string)"object not valid | ||||
" + (msg) , (o).isValid() ) | ||||
#else | ||||
#define CHECK_OBJECT( o , msg ) | ||||
#endif | ||||
inline BSONObj BSONElement::embeddedObjectUserCheck() const { | ||||
uassert( 10065 , "invalid parameter: expected an object", isABSONO | ||||
bj() ); | ||||
return BSONObj(value()); | ||||
} | ||||
inline BSONObj BSONElement::embeddedObject() const { | ||||
assert( isABSONObj() ); | ||||
return BSONObj(value()); | ||||
} | ||||
inline BSONObj BSONElement::codeWScopeObject() const { | ||||
assert( type() == CodeWScope ); | ||||
int strSizeWNull = *(int *)( value() + 4 ); | ||||
return BSONObj( value() + 4 + 4 + strSizeWNull ); | ||||
} | ||||
inline BSONObj BSONObj::copy() const { | ||||
char *p = (char*) malloc(objsize()); | ||||
memcpy(p, objdata(), objsize()); | ||||
return BSONObj(p, true); | ||||
} | ||||
// wrap this element up as a singleton object. | ||||
inline BSONObj BSONElement::wrap() const { | ||||
BSONObjBuilder b(size()+6); | ||||
b.append(*this); | ||||
return b.obj(); | ||||
} | ||||
inline BSONObj BSONElement::wrap( const char * newName ) const { | ||||
BSONObjBuilder b(size()+6+strlen(newName)); | ||||
b.appendAs(*this,newName); | ||||
return b.obj(); | ||||
} | ||||
inline bool BSONObj::hasElement(const char *name) const { | ||||
if ( !isEmpty() ) { | ||||
BSONObjIterator it(*this); | ||||
while ( it.moreWithEOO() ) { | ||||
BSONElement e = it.next(); | ||||
if ( strcmp(name, e.fieldName()) == 0 ) | ||||
return true; | ||||
} | ||||
} | ||||
return false; | ||||
} | ||||
inline BSONElement BSONObj::getField(const char *name) const { | ||||
BSONObjIterator i(*this); | ||||
while ( i.more() ) { | ||||
BSONElement e = i.next(); | ||||
if ( strcmp(e.fieldName(), name) == 0 ) | ||||
return e; | ||||
} | ||||
return BSONElement(); | ||||
} | ||||
/* add all the fields from the object specified to this object */ | ||||
inline BSONObjBuilder& BSONObjBuilder::appendElements(BSONObj x) { | ||||
BSONObjIterator it(x); | ||||
while ( it.moreWithEOO() ) { | ||||
BSONElement e = it.next(); | ||||
if ( e.eoo() ) break; | ||||
append(e); | ||||
} | ||||
return *this; | ||||
} | ||||
inline bool BSONObj::isValid(){ | ||||
int x = objsize(); | ||||
return x > 0 && x <= 1024 * 1024 * 8; | ||||
} | ||||
inline bool BSONObj::getObjectID(BSONElement& e) const { | ||||
BSONElement f = getField("_id"); | ||||
if( !f.eoo() ) { | ||||
e = f; | ||||
return true; | ||||
} | ||||
return false; | ||||
} | ||||
inline BSONObjBuilderValueStream::BSONObjBuilderValueStream( BSONObjBui | ||||
lder * builder ) { | ||||
_fieldName = 0; | ||||
_builder = builder; | ||||
} | ||||
template<class T> | ||||
inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<( T value ) | ||||
{ | ||||
_builder->append(_fieldName, value); | ||||
_fieldName = 0; | ||||
return *_builder; | ||||
} | ||||
inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<( const BSO | ||||
NElement& e ) { | ||||
_builder->appendAs( e , _fieldName ); | ||||
_fieldName = 0; | ||||
return *_builder; | ||||
} | ||||
inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<(DateNowLab | ||||
eler& id){ | ||||
_builder->appendDate(_fieldName, jsTime()); | ||||
_fieldName = 0; | ||||
return *_builder; | ||||
} | ||||
inline Labeler BSONObjBuilderValueStream::operator<<( const Labeler::La | ||||
bel &l ) { | ||||
return Labeler( l, this ); | ||||
} | ||||
inline void BSONObjBuilderValueStream::endField( const char *nextFieldN | ||||
ame ) { | ||||
if ( _fieldName && haveSubobj() ) { | ||||
_builder->append( _fieldName, subobj()->done() ); | ||||
} | ||||
_subobj.reset(); | ||||
_fieldName = nextFieldName; | ||||
} | ||||
inline BSONObjBuilder *BSONObjBuilderValueStream::subobj() { | ||||
if ( !haveSubobj() ) | ||||
_subobj.reset( new BSONObjBuilder() ); | ||||
return _subobj.get(); | ||||
} | ||||
template<class T> inline | ||||
BSONObjBuilder& Labeler::operator<<( T value ) { | ||||
s_->subobj()->append( l_.l_, value ); | ||||
return *s_->_builder; | ||||
} | ||||
inline | ||||
BSONObjBuilder& Labeler::operator<<( const BSONElement& e ) { | ||||
s_->subobj()->appendAs( e, l_.l_ ); | ||||
return *s_->_builder; | ||||
} | ||||
// {a: {b:1}} -> {a.b:1} | ||||
void nested2dotted(BSONObjBuilder& b, const BSONObj& obj, const string& | ||||
base=""); | ||||
inline BSONObj nested2dotted(const BSONObj& obj){ | ||||
BSONObjBuilder b; | ||||
nested2dotted(b, obj); | ||||
return b.obj(); | ||||
} | ||||
// {a.b:1} -> {a: {b:1}} | ||||
void dotted2nested(BSONObjBuilder& b, const BSONObj& obj); | ||||
inline BSONObj dotted2nested(const BSONObj& obj){ | ||||
BSONObjBuilder b; | ||||
dotted2nested(b, obj); | ||||
return b.obj(); | ||||
} | ||||
/* WARNING: nested/dotted conversions are not 100% reversible | ||||
* nested2dotted(dotted2nested({a.b: {c:1}})) -> {a.b.c: 1} | ||||
* also, dotted2nested ignores order | ||||
*/ | ||||
typedef map<string, BSONElement> BSONMap; | ||||
inline BSONMap bson2map(const BSONObj& obj){ | ||||
BSONMap m; | ||||
BSONObjIterator it(obj); | ||||
while (it.more()){ | ||||
BSONElement e = it.next(); | ||||
m[e.fieldName()] = e; | ||||
} | ||||
return m; | ||||
} | ||||
struct BSONElementFieldNameCmp { | ||||
bool operator()( const BSONElement &l, const BSONElement &r ) const | ||||
{ | ||||
return strcmp( l.fieldName() , r.fieldName() ) <= 0; | ||||
} | ||||
}; | ||||
typedef set<BSONElement, BSONElementFieldNameCmp> BSONSortedElements; | ||||
inline BSONSortedElements bson2set( const BSONObj& obj ){ | ||||
BSONSortedElements s; | ||||
BSONObjIterator it(obj); | ||||
while ( it.more() ) | ||||
s.insert( it.next() ); | ||||
return s; | ||||
} | ||||
class BSONObjIteratorSorted { | ||||
public: | ||||
BSONObjIteratorSorted( const BSONObj& o ); | ||||
~BSONObjIteratorSorted(){ | ||||
assert( _fields ); | ||||
delete[] _fields; | ||||
_fields = 0; | ||||
} | ||||
bool more(){ | ||||
return _cur < _nfields; | ||||
} | ||||
BSONElement next(){ | ||||
assert( _fields ); | ||||
if ( _cur < _nfields ) | ||||
return BSONElement( _fields[_cur++] ); | ||||
return BSONElement(); | ||||
} | ||||
private: | ||||
const char ** _fields; | ||||
int _nfields; | ||||
int _cur; | ||||
}; | ||||
} // namespace mongo | ||||
End of changes. 5 change blocks. | ||||
4 lines changed or deleted | 12 lines changed or added | |||
jsobjmanipulator.h | jsobjmanipulator.h | |||
---|---|---|---|---|
skipping to change at line 43 | skipping to change at line 43 | |||
} | } | |||
/** Replace a Timestamp type with a Date type initialized to | /** Replace a Timestamp type with a Date type initialized to | |||
OpTime::now().asDate() | OpTime::now().asDate() | |||
*/ | */ | |||
void initTimestamp(); | void initTimestamp(); | |||
/** Change the value, in place, of the number. */ | /** Change the value, in place, of the number. */ | |||
void setNumber(double d) { | void setNumber(double d) { | |||
if ( _element.type() == NumberDouble ) *reinterpret_cast< doubl e * >( value() ) = d; | if ( _element.type() == NumberDouble ) *reinterpret_cast< doubl e * >( value() ) = d; | |||
else if ( _element.type() == NumberInt ) *reinterpret_cast< int * >( value() ) = (int) d; | else if ( _element.type() == NumberInt ) *reinterpret_cast< int * >( value() ) = (int) d; | |||
else assert(0); | ||||
} | } | |||
void setLong(long long n) { | void setLong(long long n) { | |||
if( _element.type() == NumberLong ) *reinterpret_cast< long lon | assert( _element.type() == NumberLong ); | |||
g * >( value() ) = n; | *reinterpret_cast< long long * >( value() ) = n; | |||
} | } | |||
void setInt(int n) { | void setInt(int n) { | |||
assert( _element.type() == NumberInt ); | assert( _element.type() == NumberInt ); | |||
*reinterpret_cast< int * >( value() ) = n; | *reinterpret_cast< int * >( value() ) = n; | |||
} | } | |||
/** Replace the type and value of the element with the type and val ue of e, | /** Replace the type and value of the element with the type and val ue of e, | |||
preserving the original fieldName */ | preserving the original fieldName */ | |||
void replaceTypeAndValue( const BSONElement &e ) { | void replaceTypeAndValue( const BSONElement &e ) { | |||
*data() = e.type(); | *data() = e.type(); | |||
End of changes. 2 change blocks. | ||||
2 lines changed or deleted | 3 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 "../stdafx.h" | #include "../pch.h" | |||
#include "jsobj.h" | #include "jsobj.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 | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
lasterror.h | lasterror.h | |||
---|---|---|---|---|
skipping to change at line 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/thread/tss.hpp> | #include <boost/thread/tss.hpp> | |||
#undef assert | #undef assert | |||
#define assert xassert | #define assert MONGO_assert | |||
namespace mongo { | namespace mongo { | |||
class BSONObjBuilder; | class BSONObjBuilder; | |||
class Message; | class Message; | |||
struct LastError { | struct LastError { | |||
int code; | int code; | |||
string msg; | string msg; | |||
enum UpdatedExistingType { NotUpdate, True, False } updatedExisting ; | enum UpdatedExistingType { NotUpdate, True, False } updatedExisting ; | |||
/* todo: nObjects should be 64 bit */ | /* todo: nObjects should be 64 bit */ | |||
skipping to change at line 90 | skipping to change at line 90 | |||
* id of 0 means should use thread local management | * id of 0 means should use thread local management | |||
*/ | */ | |||
void setID( int id ); | void setID( int id ); | |||
int getID(); | int getID(); | |||
void remove( int id ); | void remove( int id ); | |||
void release(); | void release(); | |||
/** when db receives a message/request, call this */ | /** when db receives a message/request, call this */ | |||
void startRequest( Message& m , LastError * connectionOwned ); | void startRequest( Message& m , LastError * connectionOwned ); | |||
void startRequest( Message& m ); | LastError * startRequest( Message& m , int clientId = 0 ); | |||
// used to disable lastError reporting while processing a killCurso rs message | // used to disable lastError reporting while processing a killCurso rs message | |||
// disable causes get() to return 0. | // disable causes get() to return 0. | |||
LastError *disableForCommand(); // only call once per command invoc ation! | LastError *disableForCommand(); // only call once per command invoc ation! | |||
private: | private: | |||
ThreadLocalValue<int> _id; | ThreadLocalValue<int> _id; | |||
boost::thread_specific_ptr<LastError> _tl; | boost::thread_specific_ptr<LastError> _tl; | |||
struct Status { | struct Status { | |||
time_t time; | time_t time; | |||
End of changes. 2 change blocks. | ||||
2 lines changed or deleted | 2 lines changed or added | |||
locks.h | locks.h | |||
---|---|---|---|---|
skipping to change at line 19 | skipping to change at line 19 | |||
* | * | |||
* This program is distributed in the hope that it will be useful, | * This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | * GNU Affero General Public License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Lice nse | * You should have received a copy of the GNU Affero General Public Lice nse | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
//#include "../stdafx.h" | //#include "../pch.h" | |||
#pragma once | #pragma once | |||
#if defined(_WIN32) | #if defined(_WIN32) | |||
#if BOOST_VERSION >= 103500 | #if BOOST_VERSION >= 103500 | |||
#include <boost/thread/shared_mutex.hpp> | #include <boost/thread/shared_mutex.hpp> | |||
#undef assert | #undef assert | |||
#define assert xassert | #define assert MONGO_assert | |||
#else | #else | |||
#error need boost >= 1.35 for windows | #error need boost >= 1.35 for windows | |||
#endif | #endif | |||
#define BOOST_RWLOCK | #define BOOST_RWLOCK | |||
#else | #else | |||
#include <pthread.h> | #include <pthread.h> | |||
skipping to change at line 68 | skipping to change at line 68 | |||
void unlock_shared(){ | void unlock_shared(){ | |||
_m.unlock_shared(); | _m.unlock_shared(); | |||
} | } | |||
bool lock_shared_try( int millis ){ | bool lock_shared_try( int millis ){ | |||
boost::system_time until = get_system_time(); | boost::system_time until = get_system_time(); | |||
until += boost::posix_time::milliseconds(millis); | until += boost::posix_time::milliseconds(millis); | |||
return _m.timed_lock_shared( until ); | return _m.timed_lock_shared( until ); | |||
} | } | |||
bool lock_try( int millis ){ | ||||
boost::system_time until = get_system_time(); | ||||
until += boost::posix_time::milliseconds(millis); | ||||
return _m.timed_lock( until ); | ||||
} | ||||
}; | }; | |||
#else | #else | |||
class RWLock { | class RWLock { | |||
pthread_rwlock_t _lock; | pthread_rwlock_t _lock; | |||
inline void check( int x ){ | inline void check( int x ){ | |||
if( x == 0 ) | if( x == 0 ) | |||
return; | return; | |||
log() << "pthread rwlock failed: " << x << endl; | log() << "pthread rwlock failed: " << x << endl; | |||
assert( x == 0 ); | assert( x == 0 ); | |||
} | } | |||
public: | public: | |||
RWLock(){ | RWLock(){ | |||
check( pthread_rwlock_init( &_lock , 0 ) ); | check( pthread_rwlock_init( &_lock , 0 ) ); | |||
} | } | |||
~RWLock(){ | ~RWLock(){ | |||
check( pthread_rwlock_destroy( &_lock ) ); | if ( ! __destroyingStatics ){ | |||
check( pthread_rwlock_destroy( &_lock ) ); | ||||
} | ||||
} | } | |||
void lock(){ | void lock(){ | |||
check( pthread_rwlock_wrlock( &_lock ) ); | check( pthread_rwlock_wrlock( &_lock ) ); | |||
} | } | |||
void unlock(){ | void unlock(){ | |||
check( pthread_rwlock_unlock( &_lock ) ); | check( pthread_rwlock_unlock( &_lock ) ); | |||
} | } | |||
void lock_shared(){ | void lock_shared(){ | |||
check( pthread_rwlock_rdlock( &_lock ) ); | check( pthread_rwlock_rdlock( &_lock ) ); | |||
} | } | |||
void unlock_shared(){ | void unlock_shared(){ | |||
check( pthread_rwlock_unlock( &_lock ) ); | check( pthread_rwlock_unlock( &_lock ) ); | |||
} | } | |||
bool lock_shared_try( int millis ){ | bool lock_shared_try( int millis ){ | |||
while ( millis-- ){ | return _try( millis , false ); | |||
int x = pthread_rwlock_tryrdlock( &_lock ); | } | |||
if ( x == 0 ) | ||||
bool lock_try( int millis ){ | ||||
return _try( millis , true ); | ||||
} | ||||
bool _try( int millis , bool write ){ | ||||
while ( true ) { | ||||
int x = write ? | ||||
pthread_rwlock_trywrlock( &_lock ) : | ||||
pthread_rwlock_tryrdlock( &_lock ); | ||||
if ( x <= 0 ) | ||||
return true; | return true; | |||
if ( millis-- <= 0 ) | ||||
return false; | ||||
if ( x == EBUSY ){ | if ( x == EBUSY ){ | |||
sleepmillis(1); | sleepmillis(1); | |||
continue; | continue; | |||
} | } | |||
check(x); | check(x); | |||
} | } | |||
return false; | return false; | |||
} | } | |||
}; | }; | |||
#endif | #endif | |||
struct rwlock { | ||||
rwlock( const RWLock& lock , bool write , bool alreadyHaveLock = fa | ||||
lse ) | ||||
: _lock( (RWLock&)lock ) , _write( write ){ | ||||
if ( ! alreadyHaveLock ){ | ||||
if ( _write ) | ||||
_lock.lock(); | ||||
else | ||||
_lock.lock_shared(); | ||||
} | ||||
} | ||||
~rwlock(){ | ||||
if ( _write ) | ||||
_lock.unlock(); | ||||
else | ||||
_lock.unlock_shared(); | ||||
} | ||||
RWLock& _lock; | ||||
bool _write; | ||||
}; | ||||
} | } | |||
End of changes. 9 change blocks. | ||||
6 lines changed or deleted | 55 lines changed or added | |||
log.h | log.h | |||
---|---|---|---|---|
skipping to change at line 118 | skipping to change at line 118 | |||
virtual Nullstream& operator<< (ostream& ( *endl )(ostream&)) { | virtual Nullstream& operator<< (ostream& ( *endl )(ostream&)) { | |||
return *this; | return *this; | |||
} | } | |||
virtual Nullstream& operator<< (ios_base& (*hex)(ios_base&)) { | virtual Nullstream& operator<< (ios_base& (*hex)(ios_base&)) { | |||
return *this; | return *this; | |||
} | } | |||
virtual void flush(){} | virtual void flush(){} | |||
}; | }; | |||
extern Nullstream nullstream; | extern Nullstream nullstream; | |||
#define LOGIT { ss << x; return *this; } | ||||
class Logstream : public Nullstream { | class Logstream : public Nullstream { | |||
static mongo::mutex mutex; | static mongo::mutex mutex; | |||
static int doneSetup; | static int doneSetup; | |||
stringstream ss; | stringstream ss; | |||
public: | public: | |||
static int magicNumber(){ | static int magicNumber(){ | |||
return 1717; | return 1717; | |||
} | } | |||
void flush() { | void flush() { | |||
// this ensures things are sane | // this ensures things are sane | |||
if ( doneSetup == 1717 ){ | if ( doneSetup == 1717 ){ | |||
scoped_lock lk(mutex); | scoped_lock lk(mutex); | |||
cout << ss.str(); | cout << ss.str(); | |||
cout.flush(); | cout.flush(); | |||
} | } | |||
ss.str(""); | ss.str(""); | |||
} | } | |||
Logstream& operator<<(const char *x) LOGIT | ||||
Logstream& operator<<(char *x) LOGIT | /** note these are virtual */ | |||
Logstream& operator<<(char x) LOGIT | Logstream& operator<<(const char *x) { ss << x; return *this; } | |||
Logstream& operator<<(int x) LOGIT | Logstream& operator<<(char *x) { ss << x; return *this; } | |||
Logstream& operator<<(ExitCode x) LOGIT | Logstream& operator<<(char x) { ss << x; return *this; } | |||
Logstream& operator<<(long x) LOGIT | Logstream& operator<<(int x) { ss << x; return *this; } | |||
Logstream& operator<<(unsigned long x) LOGIT | Logstream& operator<<(ExitCode x) { ss << x; return *this; } | |||
Logstream& operator<<(unsigned x) LOGIT | Logstream& operator<<(long x) { ss << x; return *this; } | |||
Logstream& operator<<(double x) LOGIT | Logstream& operator<<(unsigned long x) { ss << x; return *this; } | |||
Logstream& operator<<(void *x) LOGIT | Logstream& operator<<(unsigned x) { ss << x; return *this; } | |||
Logstream& operator<<(const void *x) LOGIT | Logstream& operator<<(double x) { ss << x; return *this; } | |||
Logstream& operator<<(long long x) LOGIT | Logstream& operator<<(void *x) { ss << x; return *this; } | |||
Logstream& operator<<(unsigned long long x) LOGIT | Logstream& operator<<(const void *x) { ss << x; return *this; } | |||
Logstream& operator<<(bool x) LOGIT | Logstream& operator<<(long long x) { ss << x; return *this; } | |||
Logstream& operator<<(unsigned long long x) { ss << x; return *this | ||||
; } | ||||
Logstream& operator<<(bool x) { ss << x; return *this | ||||
; } | ||||
Logstream& operator<<(const LazyString& x) { | Logstream& operator<<(const LazyString& x) { | |||
ss << x.val(); | ss << x.val(); | |||
return *this; | return *this; | |||
} | } | |||
Logstream& operator<< (ostream& ( *_endl )(ostream&)) { | Logstream& operator<< (ostream& ( *_endl )(ostream&)) { | |||
ss << '\n'; | ss << '\n'; | |||
flush(); | flush(); | |||
return *this; | return *this; | |||
} | } | |||
Logstream& operator<< (ios_base& (*_hex)(ios_base&)) { | Logstream& operator<< (ios_base& (*_hex)(ios_base&)) { | |||
skipping to change at line 245 | skipping to change at line 246 | |||
return l; | return l; | |||
} | } | |||
/** | /** | |||
log to a file rather than stdout | log to a file rather than stdout | |||
defined in assert_util.cpp | defined in assert_util.cpp | |||
*/ | */ | |||
void initLogging( const string& logpath , bool append ); | void initLogging( const string& logpath , bool append ); | |||
void rotateLogs( int signal = 0 ); | void rotateLogs( int signal = 0 ); | |||
#define OUTPUT_ERRNOX(x) "errno:" << x << " " << strerror(x) | inline string errnoWithDescription(int x = errno) { | |||
#define OUTPUT_ERRNO OUTPUT_ERRNOX(errno) | stringstream s; | |||
s << "errno:" << x << ' ' << strerror(x); | ||||
return s.str(); | ||||
} | ||||
string errnostring( const char * prefix = 0 ); | /** output the error # and error message with prefix. | |||
handy for use as parm in uassert/massert. | ||||
*/ | ||||
string errnoWithPrefix( const char * prefix = 0 ); | ||||
} // namespace mongo | } // namespace mongo | |||
End of changes. 4 change blocks. | ||||
19 lines changed or deleted | 28 lines changed or added | |||
lruishmap.h | lruishmap.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 "../stdafx.h" | #include "../pch.h" | |||
#include "../util/goodies.h" | #include "../util/goodies.h" | |||
namespace mongo { | namespace mongo { | |||
/* Your K object must define: | /* Your K object must define: | |||
int hash() - must always return > 0. | int hash() - must always return > 0. | |||
operator== | operator== | |||
*/ | */ | |||
template <class K, class V, int MaxChain> | template <class K, class V, int MaxChain> | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
matcher.h | matcher.h | |||
---|---|---|---|---|
skipping to change at line 138 | skipping to change at line 138 | |||
const BSONElement &toMatch, const BSONObj &obj, | const BSONElement &toMatch, const BSONObj &obj, | |||
const ElementMatcher&bm, MatchDetails * details ); | const ElementMatcher&bm, MatchDetails * details ); | |||
public: | public: | |||
static int opDirection(int op) { | static int opDirection(int op) { | |||
return op <= BSONObj::LTE ? -1 : 1; | return op <= BSONObj::LTE ? -1 : 1; | |||
} | } | |||
// Only specify constrainIndexKey if matches() will be called with | // Only specify constrainIndexKey if matches() will be called with | |||
// index keys having empty string field names. | // index keys having empty string field names. | |||
Matcher(const BSONObj &pattern, const BSONObj &constrainIndexKey = BSONObj()); | Matcher(const BSONObj &pattern, const BSONObj &constrainIndexKey = BSONObj(), bool subMatcher = false); | |||
~Matcher(); | ~Matcher(); | |||
bool matches(const BSONObj& j, MatchDetails * details = 0 ); | bool matches(const BSONObj& j, MatchDetails * details = 0 ); | |||
bool keyMatch() const { return !all && !haveSize && !hasArray && !h | // until SERVER-109 $or is opaque to indexes | |||
aveNeg; } | bool keyMatch() const { return !all && !haveSize && !hasArray && !h | |||
aveNeg && _orMatchers.size() == 0; } | ||||
bool atomic() const { return _atomic; } | bool atomic() const { return _atomic; } | |||
bool hasType( BSONObj::MatchType type ) const; | bool hasType( BSONObj::MatchType type ) const; | |||
string toString() const { | ||||
return jsobj.toString(); | ||||
} | ||||
private: | private: | |||
void addBasic(const BSONElement &e, int c, bool isNot) { | void addBasic(const BSONElement &e, int c, bool isNot) { | |||
// TODO May want to selectively ignore these element types base d on op type. | // TODO May want to selectively ignore these element types base d on op type. | |||
if ( e.type() == MinKey || e.type() == MaxKey ) | if ( e.type() == MinKey || e.type() == MaxKey ) | |||
return; | return; | |||
basics.push_back( ElementMatcher( e , c, isNot ) ); | basics.push_back( ElementMatcher( e , c, isNot ) ); | |||
} | } | |||
void addRegex(const char *fieldName, const char *regex, const char *flags, bool isNot = false); | void addRegex(const char *fieldName, const char *regex, const char *flags, bool isNot = false); | |||
bool addOp( const BSONElement &e, const BSONElement &fe, bool isNot , const char *& regex, const char *&flags ); | bool addOp( const BSONElement &e, const BSONElement &fe, bool isNot , const char *& regex, const char *&flags ); | |||
int valuesMatch(const BSONElement& l, const BSONElement& r, int op, const ElementMatcher& bm); | int valuesMatch(const BSONElement& l, const BSONElement& r, int op, const ElementMatcher& bm); | |||
bool parseOrNor( const BSONElement &e, bool subMatcher ); | ||||
void parseOr( const BSONElement &e, bool subMatcher, vector< shared | ||||
_ptr< Matcher > > &matchers ); | ||||
Where *where; // set if query uses $where | Where *where; // set if query uses $where | |||
BSONObj jsobj; // the query pattern. e.g., { name : "joe" } | BSONObj jsobj; // the query pattern. e.g., { name : "joe" } | |||
BSONObj constrainIndexKey_; | BSONObj constrainIndexKey_; | |||
vector<ElementMatcher> basics; | vector<ElementMatcher> basics; | |||
bool haveSize; | bool haveSize; | |||
bool all; | bool all; | |||
bool hasArray; | bool hasArray; | |||
bool haveNeg; | bool haveNeg; | |||
/* $atomic - if true, a multi document operation (some removes, upd ates) | /* $atomic - if true, a multi document operation (some removes, upd ates) | |||
skipping to change at line 183 | skipping to change at line 192 | |||
i.e. we stay locked the whole time. | i.e. we stay locked the whole time. | |||
http://www.mongodb.org/display/DOCS/Removing[ | http://www.mongodb.org/display/DOCS/Removing[ | |||
*/ | */ | |||
bool _atomic; | bool _atomic; | |||
RegexMatcher regexs[4]; | RegexMatcher regexs[4]; | |||
int nRegex; | int nRegex; | |||
// so we delete the mem when we're done: | // so we delete the mem when we're done: | |||
vector< shared_ptr< BSONObjBuilder > > _builders; | vector< shared_ptr< BSONObjBuilder > > _builders; | |||
vector< shared_ptr< Matcher > > _orMatchers; | ||||
vector< shared_ptr< Matcher > > _norMatchers; | ||||
friend class CoveredIndexMatcher; | friend class CoveredIndexMatcher; | |||
}; | }; | |||
// If match succeeds on index key, then attempt to match full document. | // If match succeeds on index key, then attempt to match full document. | |||
class CoveredIndexMatcher : boost::noncopyable { | class CoveredIndexMatcher : boost::noncopyable { | |||
public: | public: | |||
CoveredIndexMatcher(const BSONObj &pattern, const BSONObj &indexKey Pattern); | CoveredIndexMatcher(const BSONObj &pattern, const BSONObj &indexKey Pattern); | |||
bool matches(const BSONObj &o){ return _docMatcher.matches( o ); } | bool matches(const BSONObj &o){ return _docMatcher.matches( o ); } | |||
bool matches(const BSONObj &key, const DiskLoc &recLoc , MatchDetai ls * details = 0 ); | bool matches(const BSONObj &key, const DiskLoc &recLoc , MatchDetai ls * details = 0 ); | |||
End of changes. 5 change blocks. | ||||
3 lines changed or deleted | 15 lines changed or added | |||
message.h | message.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 "../util/sock.h" | #include "../util/sock.h" | |||
#include "../util/atomic_int.h" | #include "../bson/util/atomic_int.h" | |||
#include "hostandport.h" | ||||
namespace mongo { | namespace mongo { | |||
extern bool noUnixSocket; | extern bool noUnixSocket; | |||
class Message; | class Message; | |||
class MessagingPort; | class MessagingPort; | |||
class PiggyBackData; | class PiggyBackData; | |||
typedef AtomicUInt MSGID; | typedef AtomicUInt MSGID; | |||
class Listener { | class Listener { | |||
public: | public: | |||
Listener(const string &ip, int p, bool logConnect=true ) : _ip(ip), _port(p), _logConnect(logConnect) { } | Listener(const string &ip, int p, bool logConnect=true ) : _port(p) , _ip(ip), _logConnect(logConnect) { } | |||
virtual ~Listener() {} | virtual ~Listener() {} | |||
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(int sock, const SockAddr& from); | virtual void accepted(int sock, const SockAddr& from); | |||
virtual void accepted(MessagingPort *mp){ | virtual void accepted(MessagingPort *mp){ | |||
assert(!"You must overwrite one of the accepted methods"); | assert(!"You must overwrite one of the accepted methods"); | |||
} | } | |||
const int _port; | ||||
private: | private: | |||
string _ip; | string _ip; | |||
int _port; | ||||
bool _logConnect; | bool _logConnect; | |||
}; | }; | |||
class AbstractMessagingPort { | class AbstractMessagingPort { | |||
public: | public: | |||
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 unsigned remotePort() = 0 ; | virtual HostAndPort remote() const = 0; | |||
virtual unsigned remotePort() const = 0; | ||||
}; | }; | |||
class MessagingPort : public AbstractMessagingPort { | class MessagingPort : public AbstractMessagingPort { | |||
public: | public: | |||
MessagingPort(int sock, const SockAddr& farEnd); | MessagingPort(int sock, const SockAddr& farEnd); | |||
// 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(int timeout = 0); | MessagingPort(int timeout = 0, int logLevel = 0 ); | |||
virtual ~MessagingPort(); | virtual ~MessagingPort(); | |||
void shutdown(); | void shutdown(); | |||
bool connect(SockAddr& farEnd); | bool connect(SockAddr& farEnd); | |||
/* it's assumed if you reuse a message object, that it doesn't cros s MessagingPort's. | /* it's assumed if you reuse a message object, that it doesn't cros s MessagingPort's. | |||
also, the Message data will go out of scope on the subsequent re cv call. | also, the Message data will go out of scope on the subsequent re cv call. | |||
*/ | */ | |||
bool recv(Message& m); | bool recv(Message& m); | |||
void reply(Message& received, Message& response, MSGID responseTo); | void reply(Message& received, Message& response, MSGID responseTo); | |||
void reply(Message& received, Message& response); | void reply(Message& received, Message& response); | |||
bool call(Message& toSend, Message& response); | bool call(Message& toSend, Message& response); | |||
void say(Message& toSend, int responseTo = -1); | void say(Message& toSend, int responseTo = -1); | |||
void piggyBack( Message& toSend , int responseTo = -1 ); | void piggyBack( Message& toSend , int responseTo = -1 ); | |||
virtual unsigned remotePort(); | virtual unsigned remotePort() const; | |||
virtual HostAndPort remote() const; | ||||
// send len or throw SocketException | // send len or throw SocketException | |||
void send( const char * data , int len, const char *context ); | void send( const char * data , int len, const char *context ); | |||
// recv len or throw SocketException | // recv len or throw SocketException | |||
void recv( char * data , int len ); | void recv( char * data , int len ); | |||
int unsafe_recv( char *buf, int max ); | int unsafe_recv( char *buf, int max ); | |||
private: | private: | |||
int sock; | int sock; | |||
PiggyBackData * piggyBackData; | PiggyBackData * piggyBackData; | |||
public: | public: | |||
SockAddr farEnd; | SockAddr farEnd; | |||
int _timeout; | int _timeout; | |||
int _logLevel; // passed to log() when logging errors | ||||
friend class PiggyBackData; | friend class PiggyBackData; | |||
}; | }; | |||
//#pragma pack() | //#pragma pack() | |||
#pragma pack(1) | #pragma pack(1) | |||
enum Operations { | enum Operations { | |||
opReply = 1, /* reply. responseTo is set. */ | opReply = 1, /* reply. responseTo is set. */ | |||
dbMsg = 1000, /* generic msg command followed by a string */ | dbMsg = 1000, /* generic msg command followed by a string */ | |||
skipping to change at line 247 | skipping to change at line 252 | |||
class SocketException : public DBException { | class SocketException : public DBException { | |||
public: | public: | |||
virtual const char* what() const throw() { return "socket exception "; } | virtual const char* what() const throw() { return "socket exception "; } | |||
virtual int getCode(){ return 9001; } | virtual int getCode(){ return 9001; } | |||
}; | }; | |||
MSGID nextMessageId(); | MSGID nextMessageId(); | |||
void setClientId( int id ); | void setClientId( int id ); | |||
int getClientId(); | int getClientId(); | |||
extern TicketHolder connTicketHolder; | ||||
} // namespace mongo | } // namespace mongo | |||
End of changes. 9 change blocks. | ||||
6 lines changed or deleted | 14 lines changed or added | |||
message_server.h | message_server.h | |||
---|---|---|---|---|
skipping to change at line 25 | skipping to change at line 25 | |||
* limitations under the License. | * limitations under the License. | |||
*/ | */ | |||
/* | /* | |||
abstract database server | abstract database server | |||
async io core, worker thread system | async io core, worker thread system | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
namespace mongo { | namespace mongo { | |||
class MessageHandler { | class MessageHandler { | |||
public: | public: | |||
virtual ~MessageHandler(){} | virtual ~MessageHandler(){} | |||
virtual void process( Message& m , AbstractMessagingPort* p ) = 0; | virtual void process( Message& m , AbstractMessagingPort* p ) = 0; | |||
}; | }; | |||
class MessageServer { | class MessageServer { | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
miniwebserver.h | miniwebserver.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 "../stdafx.h" | #include "../pch.h" | |||
#include "message.h" | #include "message.h" | |||
#include "../db/jsobj.h" | #include "../db/jsobj.h" | |||
namespace mongo { | namespace mongo { | |||
class MiniWebServer : public Listener { | class MiniWebServer : public Listener { | |||
public: | public: | |||
MiniWebServer(const string &ip, int _port); | MiniWebServer(const string &ip, int _port); | |||
virtual ~MiniWebServer() {} | virtual ~MiniWebServer() {} | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
mockdbclient.h | mockdbclient.h | |||
---|---|---|---|---|
skipping to change at line 23 | skipping to change at line 23 | |||
* GNU Affero General Public License for more details. | * GNU Affero General Public License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Lice nse | * You should have received a copy of the GNU Affero General Public Lice nse | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../client/dbclient.h" | #include "../client/dbclient.h" | |||
#include "../db/commands.h" | #include "../db/commands.h" | |||
#include "../db/replpair.h" | ||||
class MockDBClientConnection : public DBClientConnection { | class MockDBClientConnection : public DBClientConnection { | |||
public: | public: | |||
MockDBClientConnection() : connect_() {} | MockDBClientConnection() : connect_() {} | |||
virtual | virtual | |||
BSONObj findOne(const string &ns, Query query, const BSONObj *fieldsToR eturn = 0, int queryOptions = 0) { | BSONObj findOne(const string &ns, Query query, const BSONObj *fieldsToR eturn = 0, int queryOptions = 0) { | |||
return one_; | return one_; | |||
} | } | |||
virtual | virtual | |||
bool connect(const string &serverHostname, string& errmsg) { | bool connect(const string &serverHostname, string& errmsg) { | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 1 lines changed or added | |||
model.h | model.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 "dbclient.h" | #include "dbclient.h" | |||
#include "redef_macros.h" | ||||
namespace mongo { | namespace mongo { | |||
/** Model is a base class for defining objects which are serializable t o the Mongo | /** Model is a base class for defining objects which are serializable t o the Mongo | |||
database via the database driver. | database via the database driver. | |||
Definition | Definition | |||
Your serializable class should inherit from Model and implement the abstract methods | Your serializable class should inherit from Model and implement the abstract methods | |||
below. | below. | |||
skipping to change at line 43 | skipping to change at line 44 | |||
more than once. | more than once. | |||
*/ | */ | |||
class Model { | class Model { | |||
public: | public: | |||
Model() { } | Model() { } | |||
virtual ~Model() { } | virtual ~Model() { } | |||
virtual const char * getNS() = 0; | virtual const char * getNS() = 0; | |||
virtual void serialize(BSONObjBuilder& to) = 0; | virtual void serialize(BSONObjBuilder& to) = 0; | |||
virtual void unserialize(const BSONObj& from) = 0; | virtual void unserialize(const BSONObj& from) = 0; | |||
virtual BSONObj toObject(); | ||||
virtual void append( const char * name , BSONObjBuilder& b ); | ||||
virtual string modelServer() = 0; | virtual string modelServer() = 0; | |||
/** Load a single object. | /** Load a single object. | |||
@return true if successful. | @return true if successful. | |||
*/ | */ | |||
virtual bool load(BSONObj& query); | virtual bool load(BSONObj& query); | |||
virtual void save( bool safe=false ); | virtual void save( bool safe=false ); | |||
virtual void remove( bool safe=false ); | virtual void remove( bool safe=false ); | |||
protected: | protected: | |||
BSONObj _id; | BSONObj _id; | |||
}; | }; | |||
} // namespace mongo | } // namespace mongo | |||
#include "undef_macros.h" | ||||
End of changes. 3 change blocks. | ||||
0 lines changed or deleted | 3 lines changed or added | |||
module.h | module.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 "../stdafx.h" | #include "../pch.h" | |||
#include <boost/program_options.hpp> | #include <boost/program_options.hpp> | |||
#include <list> | #include <list> | |||
namespace mongo { | namespace mongo { | |||
/** | /** | |||
* Module is the base class for adding modules to MongoDB | * Module is the base class for adding modules to MongoDB | |||
* modules allow adding hooks and features to mongo | * modules allow adding hooks and features to mongo | |||
* the idea is to add hooks into the main code for module support where needed | * the idea is to add hooks into the main code for module support where needed | |||
* some ideas are: monitoring, indexes, full text search | * some ideas are: monitoring, indexes, full text search | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
namespace.h | namespace.h | |||
---|---|---|---|---|
skipping to change at line 21 | skipping to change at line 21 | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | * GNU Affero General Public License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Licen se | * You should have received a copy of the GNU Affero General Public Licen se | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "jsobj.h" | #include "jsobj.h" | |||
#include "queryutil.h" | #include "queryutil.h" | |||
#include "diskloc.h" | #include "diskloc.h" | |||
#include "../util/hashtab.h" | #include "../util/hashtab.h" | |||
#include "../util/mmap.h" | #include "../util/mmap.h" | |||
namespace mongo { | namespace mongo { | |||
class Cursor; | class Cursor; | |||
skipping to change at line 111 | skipping to change at line 111 | |||
/* for more than 10 indexes -- see NamespaceDetails::Extra */ | /* for more than 10 indexes -- see NamespaceDetails::Extra */ | |||
string extraName() { | string extraName() { | |||
string s = string(buf) + "$extra"; | string s = string(buf) + "$extra"; | |||
massert( 10348 , "ns name too long", s.size() < MaxNsLen); | massert( 10348 , "ns name too long", s.size() < MaxNsLen); | |||
return s; | return s; | |||
} | } | |||
bool isExtra() const { | bool isExtra() const { | |||
const char *p = strstr(buf, "$extra"); | const char *p = strstr(buf, "$extra"); | |||
return p && p[6] == 0; //==0 important in case an index uses na me "$extra_1" for example | return p && p[6] == 0; //==0 important in case an index uses na me "$extra_1" for example | |||
} | } | |||
bool hasDollarSign() const { | ||||
return strstr( buf , "$" ) > 0; | ||||
} | ||||
void kill() { | void kill() { | |||
buf[0] = 0x7f; | buf[0] = 0x7f; | |||
} | } | |||
bool operator==(const char *r) { | bool operator==(const char *r) { | |||
return strcmp(buf, r) == 0; | return strcmp(buf, r) == 0; | |||
} | } | |||
bool operator==(const Namespace& r) { | bool operator==(const Namespace& r) { | |||
return strcmp(buf, r.buf) == 0; | return strcmp(buf, r.buf) == 0; | |||
skipping to change at line 664 | skipping to change at line 667 | |||
loc = l->firstExtent; | loc = l->firstExtent; | |||
return true; | return true; | |||
} | } | |||
return false; | return false; | |||
} | } | |||
bool allocated() const { | bool allocated() const { | |||
return ht != 0; | return ht != 0; | |||
} | } | |||
void getNamespaces( list<string>& tofill , bool onlyCollections = t | ||||
rue ) const; | ||||
private: | private: | |||
boost::filesystem::path path() const; | boost::filesystem::path path() const; | |||
void maybeMkdir() const; | void maybeMkdir() const; | |||
MMF f; | MMF f; | |||
HashTable<Namespace,NamespaceDetails,MMF::Pointer> *ht; | HashTable<Namespace,NamespaceDetails,MMF::Pointer> *ht; | |||
string dir_; | string dir_; | |||
string database_; | string database_; | |||
}; | }; | |||
End of changes. 3 change blocks. | ||||
1 lines changed or deleted | 7 lines changed or added | |||
parallel.h | parallel.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. | |||
*/ | */ | |||
/** | /** | |||
tools for wokring in parallel/sharded/clustered environment | tools for wokring in parallel/sharded/clustered environment | |||
*/ | */ | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "dbclient.h" | #include "dbclient.h" | |||
#include "redef_macros.h" | ||||
#include "../db/dbmessage.h" | #include "../db/dbmessage.h" | |||
#include "../db/matcher.h" | ||||
namespace mongo { | namespace mongo { | |||
/** | /** | |||
* this is a cursor that works over a set of servers | * this is a cursor that works over a set of servers | |||
* can be used in serial/paralellel as controlled by sub classes | * can be used in serial/paralellel as controlled by sub classes | |||
*/ | */ | |||
class ClusteredCursor { | class ClusteredCursor { | |||
public: | public: | |||
ClusteredCursor( QueryMessage& q ); | ClusteredCursor( QueryMessage& q ); | |||
skipping to change at line 93 | skipping to change at line 96 | |||
operator string() const { | operator string() const { | |||
return toString(); | return toString(); | |||
} | } | |||
string _server; | string _server; | |||
BSONObj _extra; | BSONObj _extra; | |||
BSONObj _orderObject; | BSONObj _orderObject; | |||
}; | }; | |||
class FilteringClientCursor { | ||||
public: | ||||
FilteringClientCursor( const BSONObj filter = BSONObj() ); | ||||
FilteringClientCursor( auto_ptr<DBClientCursor> cursor , const BSON | ||||
Obj filter = BSONObj() ); | ||||
~FilteringClientCursor(); | ||||
void reset( auto_ptr<DBClientCursor> cursor ); | ||||
bool more(); | ||||
BSONObj next(); | ||||
BSONObj peek(); | ||||
private: | ||||
void _advance(); | ||||
Matcher _matcher; | ||||
auto_ptr<DBClientCursor> _cursor; | ||||
BSONObj _next; | ||||
bool _done; | ||||
}; | ||||
class Servers { | ||||
public: | ||||
Servers(){ | ||||
} | ||||
void add( const ServerAndQuery& s ){ | ||||
add( s._server , s._extra ); | ||||
} | ||||
void add( const string& server , const BSONObj& filter ){ | ||||
vector<BSONObj>& mine = _filters[server]; | ||||
mine.push_back( filter.getOwned() ); | ||||
} | ||||
// TOOO: pick a less horrible name | ||||
class View { | ||||
View( const Servers* s ){ | ||||
for ( map<string, vector<BSONObj> >::const_iterator i=s->_f | ||||
ilters.begin(); i!=s->_filters.end(); ++i ){ | ||||
_servers.push_back( i->first ); | ||||
_filters.push_back( i->second ); | ||||
} | ||||
} | ||||
public: | ||||
int size() const { | ||||
return _servers.size(); | ||||
} | ||||
string getServer( int n ) const { | ||||
return _servers[n]; | ||||
} | ||||
vector<BSONObj> getFilter( int n ) const { | ||||
return _filters[ n ]; | ||||
} | ||||
private: | ||||
vector<string> _servers; | ||||
vector< vector<BSONObj> > _filters; | ||||
friend class Servers; | ||||
}; | ||||
View view() const { | ||||
return View( this ); | ||||
} | ||||
private: | ||||
map<string, vector<BSONObj> > _filters; | ||||
friend class View; | ||||
}; | ||||
/** | /** | |||
* runs a query in serial across any number of servers | * runs a query in serial across any number of servers | |||
* returns all results from 1 server, then the next, etc... | * returns all results from 1 server, then the next, etc... | |||
*/ | */ | |||
class SerialServerClusteredCursor : public ClusteredCursor { | class SerialServerClusteredCursor : public ClusteredCursor { | |||
public: | public: | |||
SerialServerClusteredCursor( const set<ServerAndQuery>& servers , Q ueryMessage& q , int sortOrder=0); | SerialServerClusteredCursor( const set<ServerAndQuery>& servers , Q ueryMessage& q , int sortOrder=0); | |||
virtual bool more(); | virtual bool more(); | |||
virtual BSONObj next(); | virtual BSONObj next(); | |||
virtual string type() const { return "SerialServer"; } | virtual string type() const { return "SerialServer"; } | |||
private: | private: | |||
vector<ServerAndQuery> _servers; | vector<ServerAndQuery> _servers; | |||
unsigned _serverIndex; | unsigned _serverIndex; | |||
auto_ptr<DBClientCursor> _current; | FilteringClientCursor _current; | |||
int _needToSkip; | ||||
}; | }; | |||
/** | /** | |||
* runs a query in parellel across N servers | * runs a query in parellel across N servers | |||
* sots | * sots | |||
*/ | */ | |||
class ParallelSortClusteredCursor : public ClusteredCursor { | class ParallelSortClusteredCursor : public ClusteredCursor { | |||
public: | public: | |||
ParallelSortClusteredCursor( const set<ServerAndQuery>& servers , Q ueryMessage& q , const BSONObj& sortKey ); | ParallelSortClusteredCursor( const set<ServerAndQuery>& servers , Q ueryMessage& q , const BSONObj& sortKey ); | |||
ParallelSortClusteredCursor( const set<ServerAndQuery>& servers , c onst string& ns , | ParallelSortClusteredCursor( const set<ServerAndQuery>& servers , c onst string& ns , | |||
const Query& q , int options=0, const BSONObj& fields=BSONObj() ); | const Query& q , int options=0, const BSONObj& fields=BSONObj() ); | |||
virtual ~ParallelSortClusteredCursor(); | virtual ~ParallelSortClusteredCursor(); | |||
virtual bool more(); | virtual bool more(); | |||
virtual BSONObj next(); | virtual BSONObj next(); | |||
virtual string type() const { return "ParallelSort"; } | virtual string type() const { return "ParallelSort"; } | |||
private: | private: | |||
void _init(); | void _init(); | |||
void advance(); | ||||
int _numServers; | int _numServers; | |||
set<ServerAndQuery> _servers; | set<ServerAndQuery> _servers; | |||
BSONObj _sortKey; | BSONObj _sortKey; | |||
auto_ptr<DBClientCursor> * _cursors; | FilteringClientCursor * _cursors; | |||
BSONObj * _nexts; | int _needToSkip; | |||
}; | }; | |||
/** | /** | |||
* 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 { | |||
skipping to change at line 192 | skipping to change at line 269 | |||
static void commandThread(); | static void commandThread(); | |||
static shared_ptr<CommandResult> spawnCommand( const string& server , const string& db , const BSONObj& cmd ); | static shared_ptr<CommandResult> spawnCommand( const string& server , const string& db , const BSONObj& cmd ); | |||
private: | private: | |||
static shared_ptr<CommandResult> * _grab; | static shared_ptr<CommandResult> * _grab; | |||
}; | }; | |||
} | } | |||
#include "undef_macros.h" | ||||
End of changes. 8 change blocks. | ||||
6 lines changed or deleted | 85 lines changed or added | |||
pdfile.h | pdfile.h | |||
---|---|---|---|---|
skipping to change at line 28 | skipping to change at line 28 | |||
Files: | Files: | |||
database.ns - namespace index | database.ns - namespace index | |||
database.1 - data files | database.1 - data files | |||
database.2 | database.2 | |||
... | ... | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "../util/mmap.h" | #include "../util/mmap.h" | |||
#include "diskloc.h" | #include "diskloc.h" | |||
#include "jsobjmanipulator.h" | #include "jsobjmanipulator.h" | |||
#include "namespace.h" | #include "namespace.h" | |||
#include "client.h" | #include "client.h" | |||
namespace mongo { | namespace mongo { | |||
class DataFileHeader; | class DataFileHeader; | |||
class Extent; | class Extent; | |||
skipping to change at line 103 | skipping to change at line 103 | |||
class DataFileMgr { | class DataFileMgr { | |||
friend class BasicCursor; | friend class BasicCursor; | |||
public: | public: | |||
void init(const string& path ); | void init(const string& path ); | |||
/* see if we can find an extent of the right size in the freelist. */ | /* see if we can find an extent of the right size in the freelist. */ | |||
static Extent* allocFromFreeList(const char *ns, int approxSize, bo ol capped = false); | static Extent* allocFromFreeList(const char *ns, int approxSize, bo ol capped = false); | |||
/** @return DiskLoc where item ends up */ | /** @return DiskLoc where item ends up */ | |||
// changedId should be initialized to false | ||||
const DiskLoc updateRecord( | const DiskLoc updateRecord( | |||
const char *ns, | const char *ns, | |||
NamespaceDetails *d, | NamespaceDetails *d, | |||
NamespaceDetailsTransient *nsdt, | NamespaceDetailsTransient *nsdt, | |||
Record *toupdate, const DiskLoc& dl, | Record *toupdate, const DiskLoc& dl, | |||
const char *buf, int len, OpDebug& debug); | const char *buf, int len, OpDebug& debug, bool &changedId); | |||
// The object o may be updated if modified on insert. | // The object o may be updated if modified on insert. | |||
void insertAndLog( const char *ns, const BSONObj &o, bool god = fal se ); | void insertAndLog( const char *ns, const BSONObj &o, bool god = fal se ); | |||
DiskLoc insert(const char *ns, BSONObj &o, bool god = false); | ||||
/** @param obj both and in and out param -- insert can sometimes mo | ||||
dify an object (such as add _id). */ | ||||
DiskLoc insertWithObjMod(const char *ns, BSONObj &o, bool god = fal | ||||
se); | ||||
/** @param obj in value only for this version. */ | ||||
void insertNoReturnVal(const char *ns, BSONObj o, bool god = false) | ||||
; | ||||
DiskLoc insert(const char *ns, const void *buf, int len, bool god = false, const BSONElement &writeId = BSONElement(), bool mayAddIndex = true ); | DiskLoc insert(const char *ns, const void *buf, int len, bool god = false, const BSONElement &writeId = BSONElement(), bool mayAddIndex = true ); | |||
void deleteRecord(const char *ns, Record *todelete, const DiskLoc& dl, bool cappedOK = false, bool noWarn = false); | void deleteRecord(const char *ns, Record *todelete, const DiskLoc& dl, bool cappedOK = false, bool noWarn = false); | |||
static auto_ptr<Cursor> findAll(const char *ns, const DiskLoc &star tLoc = DiskLoc()); | static auto_ptr<Cursor> findAll(const char *ns, const DiskLoc &star tLoc = DiskLoc()); | |||
/* special version of insert for transaction logging -- streamlined a bit. | /* special version of insert for transaction logging -- streamlined a bit. | |||
assumes ns is capped and no indexes | assumes ns is capped and no indexes | |||
no _id field check | no _id field check | |||
*/ | */ | |||
Record* fast_oplog_insert(NamespaceDetails *d, const char *ns, int len); | Record* fast_oplog_insert(NamespaceDetails *d, const char *ns, int len); | |||
End of changes. 4 change blocks. | ||||
3 lines changed or deleted | 13 lines changed or added | |||
query.h | query.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 "../stdafx.h" | #include "../pch.h" | |||
#include "../util/message.h" | #include "../util/message.h" | |||
#include "dbmessage.h" | #include "dbmessage.h" | |||
#include "jsobj.h" | #include "jsobj.h" | |||
#include "diskloc.h" | #include "diskloc.h" | |||
/* db request message format | /* db request message format | |||
unsigned opid; // arbitary; will be echoed back | unsigned opid; // arbitary; will be echoed back | |||
byte operation; | byte operation; | |||
int options; | int options; | |||
skipping to change at line 107 | skipping to change at line 107 | |||
} | } | |||
if ( mod ) | if ( mod ) | |||
return 3; | return 3; | |||
return 4; | return 4; | |||
} | } | |||
}; | }; | |||
/* 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 and don't yield | god - allow access to system namespaces | |||
*/ | */ | |||
UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BS ONObj pattern, bool upsert, bool multi , bool logop , OpDebug& debug ); | UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BS ONObj pattern, bool upsert, bool multi , bool logop , OpDebug& debug ); | |||
UpdateResult _updateObjects(bool god, const char *ns, const BSONObj& up dateobj, BSONObj pattern, bool upsert, bool multi , bool logop , OpDebug& d ebug ); | ||||
// If justOne is true, deletedId is set to the id of the deleted object . | // If justOne is true, deletedId is set to the id of the deleted object . | |||
long long deleteObjects(const char *ns, BSONObj pattern, bool justOne, bool logop = false, bool god=false); | long long deleteObjects(const char *ns, BSONObj pattern, bool justOne, bool logop = false, bool god=false); | |||
long long runCount(const char *ns, const BSONObj& cmd, string& err); | long long runCount(const char *ns, const BSONObj& cmd, string& err); | |||
auto_ptr< QueryResult > runQuery(Message& m, QueryMessage& q, CurOp& cu rop ); | auto_ptr< QueryResult > runQuery(Message& m, QueryMessage& q, CurOp& cu rop ); | |||
/* This is for languages whose "objects" are not well ordered (JSON is well ordered). | /* This is for languages whose "objects" are not well ordered (JSON is well ordered). | |||
[ { a : ... } , { b : ... } ] -> { a : ..., b : ... } | [ { a : ... } , { b : ... } ] -> { a : ..., b : ... } | |||
skipping to change at line 162 | skipping to change at line 163 | |||
} | } | |||
ParsedQuery( const char* ns , int ntoskip , int ntoreturn , int que ryoptions , const BSONObj& query , const BSONObj& fields ) | ParsedQuery( const char* ns , int ntoskip , int ntoreturn , int que ryoptions , const BSONObj& query , const BSONObj& fields ) | |||
: _ns( ns ) , _ntoskip( ntoskip ) , _ntoreturn( ntoreturn ) , _ options( queryoptions ){ | : _ns( ns ) , _ntoskip( ntoskip ) , _ntoreturn( ntoreturn ) , _ options( queryoptions ){ | |||
init( query ); | init( query ); | |||
initFields( fields ); | initFields( fields ); | |||
} | } | |||
~ParsedQuery(){} | ~ParsedQuery(){} | |||
const char * ns() const { return _ns; } | const char * ns() const { return _ns; } | |||
bool isLocalDB() const { return strncmp(_ns, "local.", 6) == 0; } | ||||
const BSONObj& getFilter() const { return _filter; } | const BSONObj& getFilter() const { return _filter; } | |||
FieldMatcher* getFields() const { return _fields.get(); } | FieldMatcher* getFields() const { return _fields.get(); } | |||
shared_ptr<FieldMatcher> getFieldPtr() const { return _fields; } | shared_ptr<FieldMatcher> getFieldPtr() const { return _fields; } | |||
int getSkip() const { return _ntoskip; } | int getSkip() const { return _ntoskip; } | |||
int getNumToReturn() const { return _ntoreturn; } | int getNumToReturn() const { return _ntoreturn; } | |||
bool wantMore() const { return _wantMore; } | bool wantMore() const { return _wantMore; } | |||
int getOptions() const { return _options; } | int getOptions() const { return _options; } | |||
bool hasOption( int x ) const { return x & _options; } | bool hasOption( int x ) const { return x & _options; } | |||
bool isExplain() const { return _explain; } | bool isExplain() const { return _explain; } | |||
bool isSnapshot() const { return _snapshot; } | bool isSnapshot() const { return _snapshot; } | |||
bool returnKey() const { return _returnKey; } | bool returnKey() const { return _returnKey; } | |||
const BSONObj& getMin() const { return _min; } | const BSONObj& getMin() const { return _min; } | |||
const BSONObj& getMax() const { return _max; } | const BSONObj& getMax() const { return _max; } | |||
const BSONObj& getOrder() const { return _order; } | const BSONObj& getOrder() const { return _order; } | |||
const BSONElement& getHint() const { return _hint; } | const BSONElement& getHint() const { return _hint; } | |||
int getMaxScan() const { return _maxScan; } | ||||
bool couldBeCommand() const { | bool couldBeCommand() const { | |||
/* we assume you are using findOne() for running a cmd... */ | /* we assume you are using findOne() for running a cmd... */ | |||
return _ntoreturn == 1 && strstr( _ns , ".$cmd" ); | return _ntoreturn == 1 && strstr( _ns , ".$cmd" ); | |||
} | } | |||
bool hasIndexSpecifier() const { | bool hasIndexSpecifier() const { | |||
return ! _hint.eoo() || ! _min.isEmpty() || ! _max.isEmpty(); | return ! _hint.eoo() || ! _min.isEmpty() || ! _max.isEmpty(); | |||
} | } | |||
skipping to change at line 242 | skipping to change at line 245 | |||
else { | else { | |||
_filter = q; | _filter = q; | |||
} | } | |||
} | } | |||
void _reset(){ | void _reset(){ | |||
_wantMore = true; | _wantMore = true; | |||
_explain = false; | _explain = false; | |||
_snapshot = false; | _snapshot = false; | |||
_returnKey = false; | _returnKey = false; | |||
_maxScan = 0; | ||||
} | } | |||
void _initTop( const BSONObj& top ){ | void _initTop( const BSONObj& top ){ | |||
BSONObjIterator i( top ); | BSONObjIterator i( top ); | |||
while ( i.more() ){ | while ( i.more() ){ | |||
BSONElement e = i.next(); | BSONElement e = i.next(); | |||
const char * name = e.fieldName(); | const char * name = e.fieldName(); | |||
if ( strcmp( "$orderby" , name ) == 0 || | if ( strcmp( "$orderby" , name ) == 0 || | |||
strcmp( "orderby" , name ) == 0 ){ | strcmp( "orderby" , name ) == 0 ){ | |||
skipping to change at line 271 | skipping to change at line 275 | |||
else if ( strcmp( "$snapshot" , name ) == 0 ) | else if ( strcmp( "$snapshot" , name ) == 0 ) | |||
_snapshot = e.trueValue(); | _snapshot = e.trueValue(); | |||
else if ( strcmp( "$min" , name ) == 0 ) | else if ( strcmp( "$min" , name ) == 0 ) | |||
_min = e.embeddedObject(); | _min = e.embeddedObject(); | |||
else if ( strcmp( "$max" , name ) == 0 ) | else if ( strcmp( "$max" , name ) == 0 ) | |||
_max = e.embeddedObject(); | _max = e.embeddedObject(); | |||
else if ( strcmp( "$hint" , name ) == 0 ) | else if ( strcmp( "$hint" , name ) == 0 ) | |||
_hint = e; | _hint = e; | |||
else if ( strcmp( "$returnKey" , name ) == 0 ) | else if ( strcmp( "$returnKey" , name ) == 0 ) | |||
_returnKey = e.trueValue(); | _returnKey = e.trueValue(); | |||
else if ( strcmp( "$maxScan" , name ) == 0 ) | ||||
_maxScan = e.numberInt(); | ||||
} | } | |||
if ( _snapshot ){ | if ( _snapshot ){ | |||
uassert( 12001 , "E12001 can't sort with $snapshot", _order .isEmpty() ); | uassert( 12001 , "E12001 can't sort with $snapshot", _order .isEmpty() ); | |||
uassert( 12002 , "E12002 can't use hint with $snapshot", _h int.eoo() ); | uassert( 12002 , "E12002 can't use hint with $snapshot", _h int.eoo() ); | |||
} | } | |||
} | } | |||
skipping to change at line 309 | skipping to change at line 315 | |||
bool _wantMore; | bool _wantMore; | |||
bool _explain; | bool _explain; | |||
bool _snapshot; | bool _snapshot; | |||
bool _returnKey; | bool _returnKey; | |||
BSONObj _min; | BSONObj _min; | |||
BSONObj _max; | BSONObj _max; | |||
BSONElement _hint; | BSONElement _hint; | |||
BSONObj _order; | BSONObj _order; | |||
int _maxScan; | ||||
}; | }; | |||
} // namespace mongo | } // namespace mongo | |||
#include "clientcursor.h" | #include "clientcursor.h" | |||
End of changes. 8 change blocks. | ||||
2 lines changed or deleted | 9 lines changed or added | |||
queryutil.h | queryutil.h | |||
---|---|---|---|---|
skipping to change at line 147 | skipping to change at line 147 | |||
if ( e.eoo() ) | if ( e.eoo() ) | |||
break; | break; | |||
b.append( e.fieldName(), direction * ( ( e.number() >= 0 ) ? -1 : 1 ) ); | b.append( e.fieldName(), direction * ( ( e.number() >= 0 ) ? -1 : 1 ) ); | |||
} | } | |||
return b.obj(); | return b.obj(); | |||
} | } | |||
map< string, Type > fieldTypes_; | map< string, Type > fieldTypes_; | |||
BSONObj sort_; | BSONObj sort_; | |||
}; | }; | |||
// a BoundList contains intervals specified by inclusive start | ||||
// 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} | ||||
// and direction +1, one valid BoundList is: (1, 2); (4, 6). The same | ||||
BoundList | ||||
// would be valid for index {i:-1} with direction -1. | ||||
typedef vector< pair< BSONObj, BSONObj > > BoundList; | ||||
// ranges of fields' value that may be determined from query -- used to | // ranges of fields' value that may be determined from query -- used to | |||
// determine index limits | // determine index limits | |||
class FieldRangeSet { | class FieldRangeSet { | |||
public: | public: | |||
FieldRangeSet( const char *ns, const BSONObj &query , bool optimize =true ); | FieldRangeSet( const char *ns, const BSONObj &query , bool optimize =true ); | |||
const FieldRange &range( const char *fieldName ) const { | const FieldRange &range( const char *fieldName ) const { | |||
map< string, FieldRange >::const_iterator f = ranges_.find( fie ldName ); | map< string, FieldRange >::const_iterator f = ranges_.find( fie ldName ); | |||
if ( f == ranges_.end() ) | if ( f == ranges_.end() ) | |||
return trivialRange(); | return trivialRange(); | |||
return f->second; | return f->second; | |||
skipping to change at line 192 | skipping to change at line 199 | |||
mutable map< string, FieldRange > ranges_; | mutable map< string, FieldRange > ranges_; | |||
const char *ns_; | const char *ns_; | |||
BSONObj query_; | BSONObj query_; | |||
}; | }; | |||
/** | /** | |||
used for doing field limiting | used for doing field limiting | |||
*/ | */ | |||
class FieldMatcher { | class FieldMatcher { | |||
public: | public: | |||
FieldMatcher() | ||||
FieldMatcher(bool include=false) : _include(include){} | : _include(true) | |||
, _special(false) | ||||
, _includeID(true) | ||||
, _skip(0) | ||||
, _limit(-1) | ||||
{} | ||||
void add( const BSONObj& o ); | void add( const BSONObj& o ); | |||
void append( BSONObjBuilder& b , const BSONElement& e ) const; | void append( BSONObjBuilder& b , const BSONElement& e ) const; | |||
BSONObj getSpec() const; | BSONObj getSpec() const; | |||
bool includeID() { return _includeID; } | ||||
private: | private: | |||
void add( const string& field, bool include ); | void add( const string& field, bool include ); | |||
void add( const string& field, int skip, int limit ); | ||||
void appendArray( BSONObjBuilder& b , const BSONObj& a ) const; | void appendArray( BSONObjBuilder& b , const BSONObj& a ) 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 | ||||
//TODO: benchmark vector<pair> vs map | //TODO: benchmark vector<pair> vs map | |||
typedef map<string, boost::shared_ptr<FieldMatcher> > FieldMap; | typedef map<string, boost::shared_ptr<FieldMatcher> > FieldMap; | |||
FieldMap _fields; | FieldMap _fields; | |||
BSONObj _source; | BSONObj _source; | |||
bool _includeID; | ||||
// used for $slice operator | ||||
int _skip; | ||||
int _limit; | ||||
}; | }; | |||
/** returns a string that when used as a matcher, would match a super s et of regex() | /** returns a string that when used as a matcher, would match a super s et of regex() | |||
returns "" for complex regular expressions | returns "" for complex regular expressions | |||
used to optimize queries in some simple regex cases that start with '^' | used to optimize queries in some simple regex cases that start with '^' | |||
if purePrefix != NULL, sets it to whether the regex can be converte d to a range query | if purePrefix != NULL, sets it to whether the regex can be converte d to a range query | |||
*/ | */ | |||
string simpleRegex(const char* regex, const char* flags, bool* purePref ix=NULL); | string simpleRegex(const char* regex, const char* flags, bool* purePref ix=NULL); | |||
End of changes. 6 change blocks. | ||||
2 lines changed or deleted | 24 lines changed or added | |||
queue.h | queue.h | |||
---|---|---|---|---|
skipping to change at line 20 | skipping to change at line 20 | |||
* | * | |||
* Unless required by applicable law or agreed to in writing, software | * Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | * distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. | |||
* See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | |||
* limitations under the License. | * limitations under the License. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "../util/goodies.h" | #include "../util/goodies.h" | |||
#include <queue> | #include <queue> | |||
namespace mongo { | namespace mongo { | |||
/** | /** | |||
* simple blocking queue | * simple blocking queue | |||
*/ | */ | |||
template<typename T> class BlockingQueue : boost::noncopyable { | template<typename T> class BlockingQueue : boost::noncopyable { | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
rec.h | rec.h | |||
---|---|---|---|---|
skipping to change at line 43 | skipping to change at line 43 | |||
/* ------------------------------------------------------------------------ -- | /* ------------------------------------------------------------------------ -- | |||
A RecStoreInterface for the normal mongo mem mapped file (MongoDataFile) | A RecStoreInterface for the normal mongo mem mapped file (MongoDataFile) | |||
storage | storage | |||
*/ | */ | |||
NamespaceDetails* nsdetails_notinline(const char *ns); | NamespaceDetails* nsdetails_notinline(const char *ns); | |||
class MongoMemMapped_RecStore : public RecStoreInterface { | class MongoMemMapped_RecStore : public RecStoreInterface { | |||
public: | public: | |||
virtual char* get(DiskLoc d, unsigned len) { return d.rec()->data; } | VIRT char* get(DiskLoc d, unsigned len) { return d.rec()->data; } | |||
virtual DiskLoc insert(const char *ns, const void *obuf, int len, bool god) { | VIRT DiskLoc insert(const char *ns, const void *obuf, int len, bool god ) { | |||
return theDataFileMgr.insert(ns, obuf, len, god); | return theDataFileMgr.insert(ns, obuf, len, god); | |||
} | } | |||
virtual void deleteRecord(const char *ns, DiskLoc d) { | VIRT void deleteRecord(const char *ns, DiskLoc d) { | |||
theDataFileMgr._deleteRecord(nsdetails_notinline(ns), ns, d.rec(), d); | theDataFileMgr._deleteRecord(nsdetails_notinline(ns), ns, d.rec(), d); | |||
} | } | |||
virtual void modified(DiskLoc d) { } | VIRT void modified(DiskLoc d) { } | |||
virtual void drop(const char *ns) { | VIRT void drop(const char *ns) { | |||
dropNS(ns); | dropNS(ns); | |||
} | } | |||
virtual void rename(const char *fromNs, const char *toNs) { | VIRT void rename(const char *fromNs, const char *toNs) { | |||
renameNamespace( fromNs, toNs ); | renameNamespace( fromNs, toNs ); | |||
} | } | |||
/* close datafiles associated with the db specified. */ | /* close datafiles associated with the db specified. */ | |||
virtual void closeFiles(string dbname, string path) { | VIRT void closeFiles(string dbname, string path) { | |||
/* as this is only used for indexes so far, and we are in the same | /* as this is only used for indexes so far, and we are in the same | |||
PDFiles as the nonindex data, we just rely on them having been c losed | PDFiles as the nonindex data, we just rely on them having been c losed | |||
at the same time. one day this may need to change. | at the same time. one day this may need to change. | |||
*/ | */ | |||
} | } | |||
}; | }; | |||
/* An in memory RecStoreInterface implementation -------------------------- -- | /* An in memory RecStoreInterface implementation -------------------------- -- | |||
*/ | */ | |||
skipping to change at line 118 | skipping to change at line 118 | |||
} | } | |||
virtual void rename(const char *fromNs, const char *toNs) { | virtual void rename(const char *fromNs, const char *toNs) { | |||
massert( 10373 , "rename not yet implemented for InMem_RecStore", fa lse ); | massert( 10373 , "rename not yet implemented for InMem_RecStore", fa lse ); | |||
} | } | |||
}; | }; | |||
#endif | #endif | |||
/* Glue btree to RecStoreInterface: ---------------------------- */ | /* Glue btree to RecStoreInterface: ---------------------------- */ | |||
extern RecStoreInterface *btreeStore; | typedef MongoMemMapped_RecStore StoreToUse; | |||
extern StoreToUse *btreeStore; | ||||
const int BucketSize = 8192; | const int BucketSize = 8192; | |||
inline BtreeBucket* DiskLoc::btree() const { | inline BtreeBucket* DiskLoc::btree() const { | |||
assert( fileNo != -1 ); | assert( fileNo != -1 ); | |||
return (BtreeBucket*) btreeStore->get(*this, BucketSize); | return (BtreeBucket*) btreeStore->get(*this, BucketSize); | |||
} | } | |||
inline BtreeBucket* DiskLoc::btreemod() const { | inline BtreeBucket* DiskLoc::btreemod() const { | |||
assert( fileNo != -1 ); | assert( fileNo != -1 ); | |||
End of changes. 8 change blocks. | ||||
8 lines changed or deleted | 10 lines changed or added | |||
reccache.h | reccache.h | |||
---|---|---|---|---|
skipping to change at line 214 | skipping to change at line 214 | |||
void closeFiles(string dbname, string path); | void closeFiles(string dbname, string path); | |||
// at termination: write dirty pages and close all files | // at termination: write dirty pages and close all files | |||
void closing(); | void closing(); | |||
}; | }; | |||
extern RecCache theRecCache; | extern RecCache theRecCache; | |||
class CachedBasicRecStore : public RecStoreInterface { | class CachedBasicRecStore : public RecStoreInterface { | |||
public: | public: | |||
virtual char* get(DiskLoc d, unsigned len) { | VIRT char* get(DiskLoc d, unsigned len) { | |||
return theRecCache.get(d, len); | return theRecCache.get(d, len); | |||
} | } | |||
virtual DiskLoc insert(const char *ns, const void *obuf, int len, bool god) { | VIRT DiskLoc insert(const char *ns, const void *obuf, int len, bool god ) { | |||
return theRecCache.insert(ns, obuf, len, god); | return theRecCache.insert(ns, obuf, len, god); | |||
} | } | |||
virtual void modified(DiskLoc d) { | VIRT void modified(DiskLoc d) { | |||
theRecCache.dirty(d); | theRecCache.dirty(d); | |||
} | } | |||
/* drop collection */ | /* drop collection */ | |||
virtual void drop(const char *ns) { | VIRT void drop(const char *ns) { | |||
theRecCache.drop(ns); | theRecCache.drop(ns); | |||
} | } | |||
virtual void rename(const char *fromNs, const char *toNs) { | VIRT void rename(const char *fromNs, const char *toNs) { | |||
massert( 10378 , "rename not yet implemented for CachedBasicRecStore ", false ); | massert( 10378 , "rename not yet implemented for CachedBasicRecStore ", false ); | |||
} | } | |||
/* close datafiles associated with the db specified. */ | /* close datafiles associated with the db specified. */ | |||
virtual void closeFiles(string dbname, string path) { | VIRT void closeFiles(string dbname, string path) { | |||
theRecCache.closeFiles(dbname, dbpath); | theRecCache.closeFiles(dbname, dbpath); | |||
} | } | |||
}; | }; | |||
/* see concurrency.h - note on a lock reset from read->write we don't | /* see concurrency.h - note on a lock reset from read->write we don't | |||
call dbunlocking_read, we just wait for the final dbunlocking_write | call dbunlocking_read, we just wait for the final dbunlocking_write | |||
call | call | |||
*/ | */ | |||
inline void dbunlocking_read() { | inline void dbunlocking_read() { | |||
End of changes. 6 change blocks. | ||||
6 lines changed or deleted | 6 lines changed or added | |||
reci.h | reci.h | |||
---|---|---|---|---|
skipping to change at line 24 | skipping to change at line 24 | |||
* You should have received a copy of the GNU Affero General Public Lice nse | * You should have received a copy of the GNU Affero General Public Lice nse | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "diskloc.h" | #include "diskloc.h" | |||
namespace mongo { | namespace mongo { | |||
// #define VIRT virtual | ||||
#define VIRT | ||||
/* Subclass this and implement your real storage interface. | /* Subclass this and implement your real storage interface. | |||
*/ | */ | |||
class RecStoreInterface { | class RecStoreInterface { | |||
public: | public: | |||
virtual ~RecStoreInterface() {} | //VIRT ~RecStoreInterface() {} | |||
/* Get a pointer to the data at diskloc d. Pointer guaranteed to stay in | /* Get a pointer to the data at diskloc d. Pointer guaranteed to stay in | |||
scope through the current database operation's life. | scope through the current database operation's life. | |||
*/ | */ | |||
virtual char* get(DiskLoc d, unsigned len) = 0; | //VIRT char* get(DiskLoc d, unsigned len) = 0; | |||
/* indicate that the diskloc specified has been updated. note that as-i s today, the modification may come AFTER this | /* indicate that the diskloc specified has been updated. note that as-i s today, the modification may come AFTER this | |||
call -- we handle that currently -- until the dblock finishes. | call -- we handle that currently -- until the dblock finishes. | |||
*/ | */ | |||
virtual void modified(DiskLoc d) = 0; | //VIRT void modified(DiskLoc d) = 0; | |||
/* insert specified data as a record */ | /* insert specified data as a record */ | |||
virtual DiskLoc insert(const char *ns, const void *obuf, int len, bool god) = 0; | //VIRT DiskLoc insert(const char *ns, const void *obuf, int len, bool g od) = 0; | |||
virtual void deleteRecord(const char *ns, DiskLoc d) { massert( 10379 , "not implemented RecStoreInterface::deleteRecord", false); } | //VIRT void deleteRecord(const char *ns, DiskLoc d) { massert( 10379 , "not implemented RecStoreInterface::deleteRecord", false); } | |||
/* drop the collection */ | /* drop the collection */ | |||
virtual void drop(const char *ns) = 0; | //VIRT void drop(const char *ns) = 0; | |||
/* rename collection */ | /* rename collection */ | |||
virtual void rename(const char *fromNs, const char *toNs) = 0; | //VIRT void rename(const char *fromNs, const char *toNs) = 0; | |||
/* close datafiles associated with the db specified. */ | /* close datafiles associated with the db specified. */ | |||
virtual void closeFiles(string dbname, string path) = 0; | //VIRT void closeFiles(string dbname, string path) = 0; | |||
/* todo add: | /* todo add: | |||
closeFiles(dbname) | closeFiles(dbname) | |||
eraseFiles(dbname) | eraseFiles(dbname) | |||
*/ | */ | |||
}; | }; | |||
} | } | |||
End of changes. 9 change blocks. | ||||
8 lines changed or deleted | 11 lines changed or added | |||
repl.h | repl.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/>. | |||
*/ | */ | |||
/* replication data overview | /* replication data overview | |||
at the slave: | at the slave: | |||
local.sources { host: ..., source: ..., only: ..., syncedTo: ..., loca lLogTs: ..., dbsNextPass: { ... }, incompleteCloneDbs: { ... } } | local.sources { host: ..., source: ..., only: ..., syncedTo: ..., loca lLogTs: ..., dbsNextPass: { ... }, incompleteCloneDbs: { ... } } | |||
at the master: | at the master: | |||
local.oplog.$<source> | local.oplog.$<source> | |||
local.oplog.$main is the default | ||||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "pdfile.h" | #include "pdfile.h" | |||
#include "db.h" | #include "db.h" | |||
#include "dbhelpers.h" | #include "dbhelpers.h" | |||
#include "query.h" | #include "query.h" | |||
#include "queryoptimizer.h" | #include "queryoptimizer.h" | |||
#include "../client/dbclient.h" | #include "../client/dbclient.h" | |||
#include "../util/optime.h" | #include "../util/optime.h" | |||
namespace mongo { | #include "oplog.h" | |||
class DBClientConnection; | namespace mongo { | |||
class DBClientCursor; | ||||
/* replication slave? (possibly with slave or repl pair nonmaster) | /* replication slave? (possibly with slave or repl pair nonmaster) | |||
--slave cmd line setting -> SimpleSlave | --slave cmd line setting -> SimpleSlave | |||
*/ | */ | |||
typedef enum { NotSlave=0, SimpleSlave, ReplPairSlave } SlaveTypes; | typedef enum { NotSlave=0, SimpleSlave, ReplPairSlave } SlaveTypes; | |||
class ReplSettings { | class ReplSettings { | |||
public: | public: | |||
SlaveTypes slave; | SlaveTypes slave; | |||
skipping to change at line 197 | skipping to change at line 195 | |||
return 0; | return 0; | |||
int wait = _sleepAdviceTime - unsigned( time( 0 ) ); | int wait = _sleepAdviceTime - unsigned( time( 0 ) ); | |||
return wait > 0 ? wait : 0; | return wait > 0 ? wait : 0; | |||
} | } | |||
static bool throttledForceResyncDead( const char *requester ); | static bool throttledForceResyncDead( const char *requester ); | |||
static void forceResyncDead( const char *requester ); | static void forceResyncDead( const char *requester ); | |||
void forceResync( const char *requester ); | void forceResync( const char *requester ); | |||
}; | }; | |||
/* Write operation to the log (local.oplog.$main) | ||||
"i" insert | ||||
"u" update | ||||
"d" delete | ||||
"c" db cmd | ||||
"db" declares presence of a database (ns is set to the db name + '.' | ||||
) | ||||
*/ | ||||
void logOp(const char *opstr, const char *ns, const BSONObj& obj, BSONO | ||||
bj *patt = 0, bool *b = 0); | ||||
// class for managing a set of ids in memory | // class for managing a set of ids in memory | |||
class MemIds { | class MemIds { | |||
public: | public: | |||
MemIds() : size_() {} | MemIds() : size_() {} | |||
friend class IdTracker; | friend class IdTracker; | |||
void reset() { imp_.clear(); } | void reset() { | |||
imp_.clear(); | ||||
size_ = 0; | ||||
} | ||||
bool get( const char *ns, const BSONObj &id ) { return imp_[ ns ].c ount( id ); } | bool get( const char *ns, const BSONObj &id ) { return imp_[ ns ].c ount( id ); } | |||
void set( const char *ns, const BSONObj &id, bool val ) { | void set( const char *ns, const BSONObj &id, bool val ) { | |||
if ( val ) { | if ( val ) { | |||
if ( imp_[ ns ].insert( id.getOwned() ).second ) { | if ( imp_[ ns ].insert( id.getOwned() ).second ) { | |||
size_ += id.objsize() + sizeof( BSONObj ); | size_ += id.objsize() + sizeof( BSONObj ); | |||
} | } | |||
} else { | } else { | |||
if ( imp_[ ns ].erase( id ) == 1 ) { | if ( imp_[ ns ].erase( id ) == 1 ) { | |||
size_ -= id.objsize() + sizeof( BSONObj ); | size_ -= id.objsize() + sizeof( BSONObj ); | |||
} | } | |||
skipping to change at line 345 | skipping to change at line 337 | |||
MemIds memModIds_; | MemIds memModIds_; | |||
DbIds dbIds_; | DbIds dbIds_; | |||
DbIds dbModIds_; | DbIds dbModIds_; | |||
bool inMem_; | bool inMem_; | |||
int maxMem_; | int maxMem_; | |||
}; | }; | |||
bool anyReplEnabled(); | bool anyReplEnabled(); | |||
void appendReplicationInfo( BSONObjBuilder& result , bool authed , int level = 0 ); | void appendReplicationInfo( BSONObjBuilder& result , bool authed , int level = 0 ); | |||
void replCheckCloseDatabase( Database * db ); | ||||
extern int __findingStartInitialTimeout; // configurable for testing | ||||
class FindingStartCursor { | ||||
public: | ||||
FindingStartCursor( const QueryPlan & qp ) : | ||||
_qp( qp ), | ||||
_findingStart( true ), | ||||
_findingStartMode(), | ||||
_findingStartTimer( 0 ), | ||||
_findingStartCursor( 0 ) | ||||
{ init(); } | ||||
bool done() const { return !_findingStart; } | ||||
auto_ptr< Cursor > cRelease() { return _c; } | ||||
void next() { | ||||
if ( !_findingStartCursor || !_findingStartCursor->c->ok() ) { | ||||
_findingStart = false; | ||||
_c = _qp.newCursor(); // on error, start from beginning | ||||
destroyClientCursor(); | ||||
return; | ||||
} | ||||
switch( _findingStartMode ) { | ||||
case Initial: { | ||||
if ( !_matcher->matches( _findingStartCursor->c->currKe | ||||
y(), _findingStartCursor->c->currLoc() ) ) { | ||||
_findingStart = false; // found first record out of | ||||
query range, so scan normally | ||||
_c = _qp.newCursor( _findingStartCursor->c->currLoc | ||||
() ); | ||||
destroyClientCursor(); | ||||
return; | ||||
} | ||||
_findingStartCursor->c->advance(); | ||||
RARELY { | ||||
if ( _findingStartTimer.seconds() >= __findingStart | ||||
InitialTimeout ) { | ||||
createClientCursor( startLoc( _findingStartCurs | ||||
or->c->currLoc() ) ); | ||||
_findingStartMode = FindExtent; | ||||
return; | ||||
} | ||||
} | ||||
maybeRelease(); | ||||
return; | ||||
} | ||||
case FindExtent: { | ||||
if ( !_matcher->matches( _findingStartCursor->c->currKe | ||||
y(), _findingStartCursor->c->currLoc() ) ) { | ||||
_findingStartMode = InExtent; | ||||
return; | ||||
} | ||||
DiskLoc prev = prevLoc( _findingStartCursor->c->currLoc | ||||
() ); | ||||
if ( prev.isNull() ) { // hit beginning, so start scann | ||||
ing from here | ||||
createClientCursor(); | ||||
_findingStartMode = InExtent; | ||||
return; | ||||
} | ||||
// There might be a more efficient implementation than | ||||
creating new cursor & client cursor each time, | ||||
// not worrying about that for now | ||||
createClientCursor( prev ); | ||||
maybeRelease(); | ||||
return; | ||||
} | ||||
case InExtent: { | ||||
if ( _matcher->matches( _findingStartCursor->c->currKey | ||||
(), _findingStartCursor->c->currLoc() ) ) { | ||||
_findingStart = false; // found first record in que | ||||
ry range, so scan normally | ||||
_c = _qp.newCursor( _findingStartCursor->c->currLoc | ||||
() ); | ||||
destroyClientCursor(); | ||||
return; | ||||
} | ||||
_findingStartCursor->c->advance(); | ||||
maybeRelease(); | ||||
return; | ||||
} | ||||
default: { | ||||
massert( 12600, "invalid _findingStartMode", false ); | ||||
} | ||||
} | ||||
} | ||||
private: | ||||
enum FindingStartMode { Initial, FindExtent, InExtent }; | ||||
const QueryPlan &_qp; | ||||
bool _findingStart; | ||||
FindingStartMode _findingStartMode; | ||||
auto_ptr< CoveredIndexMatcher > _matcher; | ||||
Timer _findingStartTimer; | ||||
ClientCursor * _findingStartCursor; | ||||
auto_ptr< Cursor > _c; | ||||
DiskLoc startLoc( const DiskLoc &rec ) { | ||||
Extent *e = rec.rec()->myExtent( rec ); | ||||
if ( e->myLoc != _qp.nsd()->capExtent ) | ||||
return e->firstRecord; | ||||
// Likely we are on the fresh side of capExtent, so return firs | ||||
t fresh record. | ||||
// If we are on the stale side of capExtent, then the collectio | ||||
n is small and it | ||||
// doesn't matter if we start the extent scan with capFirstNewR | ||||
ecord. | ||||
return _qp.nsd()->capFirstNewRecord; | ||||
} | ||||
DiskLoc prevLoc( const DiskLoc &rec ) { | ||||
Extent *e = rec.rec()->myExtent( rec ); | ||||
if ( e->xprev.isNull() ) | ||||
e = _qp.nsd()->lastExtent.ext(); | ||||
else | ||||
e = e->xprev.ext(); | ||||
if ( e->myLoc != _qp.nsd()->capExtent ) | ||||
return e->firstRecord; | ||||
return DiskLoc(); // reached beginning of collection | ||||
} | ||||
void createClientCursor( const DiskLoc &startLoc = DiskLoc() ) { | ||||
auto_ptr<Cursor> c = _qp.newCursor( startLoc ); | ||||
_findingStartCursor = new ClientCursor(QueryOption_NoCursorTime | ||||
out, c, _qp.ns()); | ||||
} | ||||
void destroyClientCursor() { | ||||
if ( _findingStartCursor ) { | ||||
ClientCursor::erase( _findingStartCursor->cursorid ); | ||||
_findingStartCursor = 0; | ||||
} | ||||
} | ||||
void maybeRelease() { | ||||
RARELY { | ||||
CursorId id = _findingStartCursor->cursorid; | ||||
_findingStartCursor->updateLocation(); | ||||
{ | ||||
dbtemprelease t; | ||||
} | ||||
_findingStartCursor = ClientCursor::find( id, false ); | ||||
} | ||||
} | ||||
void init() { | ||||
// Use a ClientCursor here so we can release db mutex while sca | ||||
nning | ||||
// oplog (can take quite a while with large oplogs). | ||||
auto_ptr<Cursor> c = _qp.newReverseCursor(); | ||||
_findingStartCursor = new ClientCursor(QueryOption_NoCursorTime | ||||
out, c, _qp.ns()); | ||||
_findingStartTimer.reset(); | ||||
_findingStartMode = Initial; | ||||
BSONElement tsElt = _qp.query()[ "ts" ]; | ||||
massert( 13044, "no ts field in query", !tsElt.eoo() ); | ||||
BSONObjBuilder b; | ||||
b.append( tsElt ); | ||||
BSONObj tsQuery = b.obj(); | ||||
_matcher.reset(new CoveredIndexMatcher(tsQuery, _qp.indexKey()) | ||||
); | ||||
} | ||||
}; | ||||
void updateSlaveLocation( CurOp& curop, const char * ns , OpTime lastOp | ||||
); | ||||
bool opReplicatedEnough( OpTime op , int w ); | ||||
} // namespace mongo | } // namespace mongo | |||
End of changes. 6 change blocks. | ||||
178 lines changed or deleted | 6 lines changed or added | |||
replset.h | replset.h | |||
---|---|---|---|---|
// /db/repl/replset.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 "db.h" | #include "../../util/concurrency/list.h" | |||
#include "dbhelpers.h" | #include "../../util/concurrency/value.h" | |||
#include "json.h" | #include "../../util/hostandport.h" | |||
#include "../client/dbclient.h" | ||||
#include "repl.h" | ||||
#include "cmdline.h" | ||||
namespace mongo { | namespace mongo { | |||
extern const char *replAllDead; | extern bool replSet; // true if using repl sets | |||
extern class ReplSet *theReplSet; // null until initialized | ||||
/* ReplPair is a pair of db servers replicating to one another and coop | ||||
erating. | ||||
Only one member of the pair is active at a time; so this is a smart | ||||
master/slave | ||||
configuration basically. | ||||
You may read from the slave at anytime though (if you don't mind the | ||||
slight lag). | ||||
todo: Could be extended to be more than a pair, thus the name 'Set' | /* information about the entire repl set, such as the various servers i | |||
-- for example, | n the set, and their state */ | |||
a set of 3... | /* note: We currently do not free mem when the set goes away - it is as | |||
sumed the replset is a | ||||
singleton and long lived. | ||||
*/ | */ | |||
class ReplSet { | ||||
class ReplPair { | ||||
public: | public: | |||
enum ReplState { | bool isMaster(const char *client) { | |||
State_CantArb = -3, | //zzz | |||
State_Confused = -2, | return false; | |||
State_Negotiating = -1, | ||||
State_Slave = 0, | ||||
State_Master = 1 | ||||
}; | ||||
int state; | ||||
ThreadSafeString info; // commentary about our current state | ||||
string arbHost; // "-" for no arbiter. "host[:port]" | ||||
int remotePort; | ||||
string remoteHost; | ||||
string remote; // host:port if port specified. | ||||
// int date; // -1 not yet set; 0=slave; 1=master | ||||
string getInfo() { | ||||
stringstream ss; | ||||
ss << " state: "; | ||||
if ( state == 1 ) ss << "1 State_Master "; | ||||
else if ( state == 0 ) ss << "0 State_Slave"; | ||||
else | ||||
ss << "<b>" << state << "</b>"; | ||||
ss << '\n'; | ||||
ss << " info: " << info << '\n'; | ||||
ss << " arbhost: " << arbHost << '\n'; | ||||
ss << " remote: " << remoteHost << ':' << remotePort << '\n'; | ||||
// ss << " date: " << date << '\n'; | ||||
return ss.str(); | ||||
} | ||||
ReplPair(const char *remoteEnd, const char *arbiter); | ||||
virtual ~ReplPair() {} | ||||
bool dominant(const string& myname) { | ||||
if ( myname == remoteHost ) | ||||
return cmdLine.port > remotePort; | ||||
return myname > remoteHost; | ||||
} | ||||
void setMasterLocked( int n, const char *_comment = "" ) { | ||||
dblock p; | ||||
setMaster( n, _comment ); | ||||
} | } | |||
void fillIsMaster(BSONObjBuilder&); | ||||
void setMaster(int n, const char *_comment = ""); | static enum StartupStatus { PRESTART=0, LOADINGCONFIG=1, BADCONFIG= | |||
2, EMPTYCONFIG=3, EMPTYUNREACHABLE=4, FINISHME=5 } startupStatus; | ||||
/* negotiate with our peer who is master; returns state of peer */ | static string startupStatusMsg; | |||
int negotiate(DBClientConnection *conn, string method); | bool fatal; | |||
/* peer unreachable, try our arbitrator */ | ||||
void arbitrate(); | ||||
virtual | bool ok() const { return !fatal; } | |||
DBClientConnection *newClientConnection() const { | ||||
return new DBClientConnection(); | ||||
} | ||||
}; | ||||
extern ReplPair *replPair; | /* @return replica set's logical name */ | |||
string getName() const { return _name; } | ||||
/* note we always return true for the "local" namespace. | /* cfgString format is | |||
replsetname/host1,host2:port,... | ||||
where :port is optional. | ||||
we should not allow most operations when not the master | throws exception if a problem initializing. | |||
also we report not master if we are "dead". | */ | |||
ReplSet(string cfgString); | ||||
See also CmdIsMaster. | // for replSetGetStatus command | |||
void summarizeStatus(BSONObjBuilder&) const; | ||||
If 'client' is not specified, the current client is used. | private: | |||
*/ | string _name; | |||
inline bool isMaster( const char *client = 0 ) { | const vector<HostAndPort> *_seeds; | |||
if( ! replSettings.slave ) | ||||
return true; | ||||
if ( !client ) { | /** load our configuration from admin.replset. try seed machines t | |||
Database *database = cc().database(); | oo. | |||
assert( database ); | throws exception if a problem. | |||
client = database->name.c_str(); | */ | |||
} | void loadConfig(); | |||
if ( replAllDead ) | // void addMemberIfMissing(const HostAndPort& p); | |||
return strcmp( client, "local" ) == 0; | ||||
if ( replPair ) { | struct MemberInfo : public List1<MemberInfo>::Base { | |||
if( replPair->state == ReplPair::State_Master ) | MemberInfo(string h, int p) : _port(p), _host(h) { | |||
return true; | _dead = false; | |||
} | _lastHeartbeat = 0; | |||
else { | _upSince = 0; | |||
if( replSettings.master ) { | _health = -1.0; | |||
// if running with --master --slave, allow. note that mast | ||||
er is also true | ||||
// for repl pairs so the check for replPair above is import | ||||
ant. | ||||
return true; | ||||
} | } | |||
} | string fullName() const { | |||
if( _port < 0 ) return _host; | ||||
if ( cc().isGod() ) | stringstream ss; | |||
return true; | ss << _host << ':' << _port; | |||
return ss.str(); | ||||
return strcmp( client, "local" ) == 0; | } | |||
} | double health() const { return _health; } | |||
inline bool isMasterNs( const char *ns ) { | time_t upSince() const { return _upSince; } | |||
char cl[ 256 ]; | time_t lastHeartbeat() const { return _lastHeartbeat; } | |||
nsToDatabase( ns, cl ); | private: | |||
return isMaster( cl ); | friend class FeedbackThread; // feedbackthread is the primary w | |||
} | riter to these objects | |||
inline ReplPair::ReplPair(const char *remoteEnd, const char *arb) { | ||||
state = -1; | ||||
remote = remoteEnd; | ||||
remotePort = CmdLine::DefaultDBPort; | ||||
remoteHost = remoteEnd; | ||||
const char *p = strchr(remoteEnd, ':'); | ||||
if ( p ) { | ||||
remoteHost = string(remoteEnd, p-remoteEnd); | ||||
remotePort = atoi(p+1); | ||||
uassert( 10125 , "bad port #", remotePort > 0 && remotePort < 0 | ||||
x10000 ); | ||||
if ( remotePort == CmdLine::DefaultDBPort ) | ||||
remote = remoteHost; // don't include ":27017" as it is def | ||||
ault; in case ran in diff ways over time to normalizke the hostname format | ||||
in sources collection | ||||
} | ||||
uassert( 10126 , "arbiter parm is missing, use '-' for none", arb); | ||||
arbHost = arb; | ||||
uassert( 10127 , "arbiter parm is empty", !arbHost.empty()); | ||||
} | ||||
/* This is set to true if we have EVER been up to date -- this way a ne | ||||
w pair member | ||||
which is a replacement won't go online as master until we have initial | ||||
ly fully synced. | ||||
*/ | ||||
class PairSync { | ||||
int initialsynccomplete; | ||||
public: | ||||
PairSync() { | ||||
initialsynccomplete = -1; | ||||
} | ||||
/* call before using the class. from dbmutex */ | ||||
void init() { | ||||
BSONObj o; | ||||
initialsynccomplete = 0; | ||||
if ( Helpers::getSingleton("local.pair.sync", o) ) | ||||
initialsynccomplete = 1; | ||||
} | ||||
bool initialSyncCompleted() { | ||||
return initialsynccomplete != 0; | ||||
} | ||||
void setInitialSyncCompleted() { | bool _dead; | |||
BSONObj o = fromjson("{\"initialsynccomplete\":1}"); | const int _port; | |||
Helpers::putSingleton("local.pair.sync", o); | const string _host; | |||
initialsynccomplete = 1; | double _health; | |||
log() << "pair: initial sync complete" << endl; | time_t _lastHeartbeat; | |||
} | time_t _upSince; | |||
public: | ||||
DiagStr _lastHeartbeatErrMsg; | ||||
}; | ||||
/* all members of the set EXCEPT SELF. */ | ||||
List1<MemberInfo> _members; | ||||
void setInitialSyncCompletedLocking() { | void startHealthThreads(); | |||
if ( initialsynccomplete == 1 ) | friend class FeedbackThread; | |||
return; | ||||
dblock lk; | ||||
setInitialSyncCompleted(); | ||||
} | ||||
}; | }; | |||
} // namespace mongo | } | |||
End of changes. 21 change blocks. | ||||
175 lines changed or deleted | 72 lines changed or added | |||
request.h | request.h | |||
---|---|---|---|---|
skipping to change at line 20 | skipping to change at line 20 | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | * GNU Affero General Public License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Lice nse | * You should have received a copy of the GNU Affero General Public Lice nse | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "../util/message.h" | #include "../util/message.h" | |||
#include "../db/dbmessage.h" | #include "../db/dbmessage.h" | |||
#include "config.h" | #include "config.h" | |||
#include "util.h" | #include "util.h" | |||
namespace mongo { | namespace mongo { | |||
class ClientInfo; | class ClientInfo; | |||
class Request : boost::noncopyable { | class Request : boost::noncopyable { | |||
public: | public: | |||
Request( Message& m, AbstractMessagingPort* p ); | Request( Message& m, AbstractMessagingPort* p ); | |||
// ---- message info ----- | // ---- message info ----- | |||
const char * getns(){ | const char * getns() const { | |||
return _d.getns(); | return _d.getns(); | |||
} | } | |||
int op(){ | int op() const { | |||
return _m.data->operation(); | return _m.data->operation(); | |||
} | } | |||
bool expectResponse(){ | bool expectResponse() const { | |||
return op() == dbQuery || op() == dbGetMore; | return op() == dbQuery || op() == dbGetMore; | |||
} | } | |||
bool isCommand() const; | ||||
MSGID id(){ | MSGID id() const { | |||
return _id; | return _id; | |||
} | } | |||
DBConfig * getConfig(){ | DBConfig * getConfig() const { | |||
return _config; | return _config; | |||
} | } | |||
bool isShardingEnabled(){ | bool isShardingEnabled() const { | |||
return _config->isShardingEnabled(); | return _config->isShardingEnabled(); | |||
} | } | |||
ChunkManager * getChunkManager(){ | ChunkManager * getChunkManager() const { | |||
return _chunkManager; | return _chunkManager; | |||
} | } | |||
int getClientId(){ | int getClientId() const { | |||
return _clientId; | return _clientId; | |||
} | } | |||
ClientInfo * getClientInfo(){ | ClientInfo * getClientInfo() const { | |||
return _clientInfo; | return _clientInfo; | |||
} | } | |||
// ---- remote location info ----- | // ---- remote location info ----- | |||
string singleServerName(); | Shard primaryShard() const ; | |||
const char * primaryName(){ | ||||
return _config->getPrimary().c_str(); | ||||
} | ||||
// ---- low level access ---- | // ---- low level access ---- | |||
void reply( Message & response ){ | void reply( Message & response ){ | |||
_p->reply( _m , response , _id ); | _p->reply( _m , response , _id ); | |||
} | } | |||
Message& m(){ return _m; } | Message& m() { return _m; } | |||
DbMessage& d(){ return _d; } | DbMessage& d() { return _d; } | |||
AbstractMessagingPort* p(){ return _p; } | AbstractMessagingPort* p() const { return _p; } | |||
void process( int attempt = 0 ); | void process( int attempt = 0 ); | |||
private: | private: | |||
void reset( bool reload=false ); | void reset( bool reload=false ); | |||
Message& _m; | Message& _m; | |||
DbMessage _d; | DbMessage _d; | |||
AbstractMessagingPort* _p; | AbstractMessagingPort* _p; | |||
skipping to change at line 111 | skipping to change at line 108 | |||
ClientInfo * _clientInfo; | ClientInfo * _clientInfo; | |||
}; | }; | |||
typedef map<int,ClientInfo*> ClientCache; | typedef map<int,ClientInfo*> ClientCache; | |||
class ClientInfo { | class ClientInfo { | |||
public: | public: | |||
ClientInfo( int clientId ); | ClientInfo( int clientId ); | |||
~ClientInfo(); | ~ClientInfo(); | |||
string getRemote() const { return _remote; } | ||||
void addShard( const string& shard ); | void addShard( const string& shard ); | |||
set<string> * getPrev() const { return _prev; }; | set<string> * getPrev() const { return _prev; }; | |||
void newRequest(); | void newRequest( AbstractMessagingPort* p = 0 ); | |||
void disconnect(); | void disconnect(); | |||
static ClientInfo * get( int clientId = 0 , bool create = true ); | static ClientInfo * get( int clientId = 0 , bool create = true ); | |||
private: | private: | |||
int _id; | int _id; | |||
string _remote; | ||||
set<string> _a; | set<string> _a; | |||
set<string> _b; | set<string> _b; | |||
set<string> * _cur; | set<string> * _cur; | |||
set<string> * _prev; | set<string> * _prev; | |||
int _lastAccess; | int _lastAccess; | |||
static mongo::mutex _clientsLock; | static mongo::mutex _clientsLock; | |||
static ClientCache _clients; | static ClientCache _clients; | |||
static boost::thread_specific_ptr<ClientInfo> _tlInfo; | static boost::thread_specific_ptr<ClientInfo> _tlInfo; | |||
}; | }; | |||
End of changes. 16 change blocks. | ||||
19 lines changed or deleted | 20 lines changed or added | |||
scanandorder.h | scanandorder.h | |||
---|---|---|---|---|
skipping to change at line 57 | skipping to change at line 57 | |||
/* todo: | /* todo: | |||
_ respect limit | _ respect limit | |||
_ check for excess mem usage | _ check for excess mem usage | |||
_ response size limit from runquery; push it up a bit. | _ response size limit from runquery; push it up a bit. | |||
*/ | */ | |||
inline void fillQueryResultFromObj(BufBuilder& bb, FieldMatcher *filter , BSONObj& js) { | inline void fillQueryResultFromObj(BufBuilder& bb, FieldMatcher *filter , BSONObj& js) { | |||
if ( filter ) { | if ( filter ) { | |||
BSONObjBuilder b( bb ); | BSONObjBuilder b( bb ); | |||
BSONObjIterator i( js ); | BSONObjIterator i( js ); | |||
bool gotId = false; | ||||
while ( i.more() ){ | while ( i.more() ){ | |||
BSONElement e = i.next(); | BSONElement e = i.next(); | |||
const char * fname = e.fieldName(); | const char * fname = e.fieldName(); | |||
if ( strcmp( fname , "_id" ) == 0 ){ | if ( strcmp( fname , "_id" ) == 0 ){ | |||
b.append( e ); | if (filter->includeID()) | |||
gotId = true; | b.append( e ); | |||
} else { | } else { | |||
filter->append( b , e ); | filter->append( b , e ); | |||
} | } | |||
} | } | |||
b.done(); | b.done(); | |||
} else { | } else { | |||
bb.append((void*) js.objdata(), js.objsize()); | bb.append((void*) js.objdata(), js.objsize()); | |||
} | } | |||
} | } | |||
End of changes. 2 change blocks. | ||||
3 lines changed or deleted | 2 lines changed or added | |||
security.h | security.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 <boost/thread/tss.hpp> | #include <boost/thread/tss.hpp> | |||
#undef assert | #undef assert | |||
#define assert xassert | #define assert MONGO_assert | |||
#include "nonce.h" | #include "nonce.h" | |||
#include "concurrency.h" | #include "concurrency.h" | |||
namespace mongo { | namespace mongo { | |||
// --noauth cmd line option | // --noauth cmd line option | |||
extern bool noauth; | extern bool noauth; | |||
/* for a particular db */ | /* for a particular db */ | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
shardkey.h | shardkey.h | |||
---|---|---|---|---|
skipping to change at line 77 | skipping to change at line 77 | |||
ShardKey({num:1}).hasShardKey({ name:"joe", num:3 }) is true | ShardKey({num:1}).hasShardKey({ name:"joe", num:3 }) is true | |||
*/ | */ | |||
bool hasShardKey( const BSONObj& obj ); | bool hasShardKey( const BSONObj& obj ); | |||
/** | /** | |||
returns a query that filters results only for the range desired, i.e. returns | returns a query that filters results only for the range desired, i.e. returns | |||
{ "field" : { $gte: keyval(min), $lt: keyval(max) } } | { "field" : { $gte: keyval(min), $lt: keyval(max) } } | |||
*/ | */ | |||
void getFilter( BSONObjBuilder& b , const BSONObj& min, const BSONO bj& max ); | void getFilter( BSONObjBuilder& b , const BSONObj& min, const BSONO bj& max ); | |||
/** @return true if shard s is relevant for query q. | ||||
Example: | ||||
q: { x : 3 } | ||||
*this: { x : 1 } | ||||
s: x:2..x:7 | ||||
-> true | ||||
*/ | ||||
bool relevantForQuery( const BSONObj& q , Chunk * s ); | ||||
/** | /** | |||
Returns if the given sort pattern can be ordered by the shard ke y pattern. | Returns if the given sort pattern can be ordered by the shard ke y pattern. | |||
Example | Example | |||
sort: { ts: -1 } | sort: { ts: -1 } | |||
*this: { ts:1 } | *this: { ts:1 } | |||
-> -1 | -> -1 | |||
@return | @return | |||
0 if sort either doesn't have all the fields or has extra fie lds | 0 if sort either doesn't have all the fields or has extra fie lds | |||
< 0 if sort is descending | < 0 if sort is descending | |||
skipping to change at line 111 | skipping to change at line 101 | |||
BSONObj key() { return pattern; } | BSONObj key() { return pattern; } | |||
string toString() const; | string toString() const; | |||
BSONObj extractKey(const BSONObj& from) const; | BSONObj extractKey(const BSONObj& from) const; | |||
bool partOfShardKey(const string& key ) const { | bool partOfShardKey(const string& key ) const { | |||
return patternfields.count( key ) > 0; | return patternfields.count( key ) > 0; | |||
} | } | |||
bool uniqueAllowd( const BSONObj& otherPattern ) const; | ||||
operator string() const { | operator string() const { | |||
return pattern.toString(); | return pattern.toString(); | |||
} | } | |||
private: | private: | |||
BSONObj pattern; | BSONObj pattern; | |||
BSONObj gMin; | BSONObj gMin; | |||
BSONObj gMax; | BSONObj gMax; | |||
/* question: better to have patternfields precomputed or not? depe nds on if we use copy contructor often. */ | /* question: better to have patternfields precomputed or not? depe nds on if we use copy constructor often. */ | |||
set<string> patternfields; | set<string> patternfields; | |||
bool relevant(const BSONObj& query, const BSONObj& L, const BSONObj & R); | ||||
}; | }; | |||
inline BSONObj ShardKeyPattern::extractKey(const BSONObj& from) const { | inline BSONObj ShardKeyPattern::extractKey(const BSONObj& from) const { | |||
return from.extractFields(pattern); | return from.extractFields(pattern); | |||
} | } | |||
} | } | |||
End of changes. 4 change blocks. | ||||
12 lines changed or deleted | 3 lines changed or added | |||
snapshots.h | snapshots.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 | |||
#include "../../stdafx.h" | #include "../../pch.h" | |||
#include "../jsobj.h" | #include "../jsobj.h" | |||
#include "top.h" | #include "top.h" | |||
#include "../../util/background.h" | #include "../../util/background.h" | |||
/** | /** | |||
handles snapshotting performance metrics and other such things | handles snapshotting performance metrics and other such things | |||
*/ | */ | |||
namespace mongo { | namespace mongo { | |||
class SnapshotThread; | class SnapshotThread; | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
sock.h | sock.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 "../stdafx.h" | #include "../pch.h" | |||
#include <stdio.h> | #include <stdio.h> | |||
#include <sstream> | #include <sstream> | |||
#include "goodies.h" | #include "goodies.h" | |||
#include "../db/jsobj.h" | #include "../db/jsobj.h" | |||
#define SOCK_FAMILY_UNKNOWN_ERROR 13078 | #define SOCK_FAMILY_UNKNOWN_ERROR 13078 | |||
namespace mongo { | namespace mongo { | |||
skipping to change at line 233 | skipping to change at line 233 | |||
}; | }; | |||
extern SockAddr unknownAddress; // ( "0.0.0.0", 0 ) | extern SockAddr unknownAddress; // ( "0.0.0.0", 0 ) | |||
const int MaxMTU = 16384; | const int MaxMTU = 16384; | |||
inline string getHostName() { | inline string getHostName() { | |||
char buf[256]; | char buf[256]; | |||
int ec = gethostname(buf, 127); | int ec = gethostname(buf, 127); | |||
if ( ec || *buf == 0 ) { | if ( ec || *buf == 0 ) { | |||
log() << "can't get this server's hostname " << OUTPUT_ERRNO << endl; | log() << "can't get this server's hostname " << errnoWithDescri ption() << endl; | |||
return ""; | return ""; | |||
} | } | |||
return buf; | return buf; | |||
} | } | |||
class ListeningSockets { | class ListeningSockets { | |||
public: | public: | |||
ListeningSockets() : _sockets( new set<int>() ){ | ListeningSockets() : _sockets( new set<int>() ){ | |||
} | } | |||
skipping to change at line 277 | skipping to change at line 277 | |||
} | } | |||
static ListeningSockets* get(); | static ListeningSockets* get(); | |||
private: | private: | |||
mongo::mutex _mutex; | mongo::mutex _mutex; | |||
set<int>* _sockets; | set<int>* _sockets; | |||
static ListeningSockets* _instance; | static ListeningSockets* _instance; | |||
}; | }; | |||
#undef SOCK_FAMILY_UNKNOWN_ERROR | ||||
} // namespace mongo | } // namespace mongo | |||
End of changes. 3 change blocks. | ||||
2 lines changed or deleted | 4 lines changed or added | |||
strategy.h | strategy.h | |||
---|---|---|---|---|
skipping to change at line 20 | skipping to change at line 20 | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | * GNU Affero General Public License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Lice nse | * You should have received a copy of the GNU Affero General Public Lice nse | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "chunk.h" | #include "chunk.h" | |||
#include "request.h" | #include "request.h" | |||
namespace mongo { | namespace mongo { | |||
class Strategy { | class Strategy { | |||
public: | public: | |||
Strategy(){} | Strategy(){} | |||
virtual ~Strategy() {} | virtual ~Strategy() {} | |||
virtual void queryOp( Request& r ) = 0; | virtual void queryOp( Request& r ) = 0; | |||
virtual void getMore( Request& r ) = 0; | virtual void getMore( Request& r ) = 0; | |||
virtual void writeOp( int op , Request& r ) = 0; | virtual void writeOp( int op , Request& r ) = 0; | |||
protected: | protected: | |||
void doWrite( int op , Request& r , string server ); | void doWrite( int op , Request& r , const Shard& shard ); | |||
void doQuery( Request& r , string server ); | void doQuery( Request& r , const Shard& shard ); | |||
void insert( string server , const char * ns , const BSONObj& obj ) ; | void insert( const Shard& shard , const char * ns , const BSONObj& obj ); | |||
}; | }; | |||
extern Strategy * SINGLE; | extern Strategy * SINGLE; | |||
extern Strategy * SHARDED; | extern Strategy * SHARDED; | |||
bool setShardVersion( DBClientBase & conn , const string& ns , ShardChu nkVersion version , bool authoritative , BSONObj& result ); | bool setShardVersion( DBClientBase & conn , const string& ns , ShardChu nkVersion version , bool authoritative , BSONObj& result ); | |||
bool lockNamespaceOnServer( const string& server , const string& ns ); | bool lockNamespaceOnServer( const Shard& shard , const string& ns ); | |||
bool lockNamespaceOnServer( DBClientBase& conn , const string& ns ); | bool lockNamespaceOnServer( DBClientBase& conn , const string& ns ); | |||
} | } | |||
End of changes. 4 change blocks. | ||||
5 lines changed or deleted | 5 lines changed or added | |||
syncclusterconnection.h | syncclusterconnection.h | |||
---|---|---|---|---|
skipping to change at line 18 | skipping to change at line 18 | |||
* | * | |||
* http://www.apache.org/licenses/LICENSE-2.0 | * http://www.apache.org/licenses/LICENSE-2.0 | |||
* | * | |||
* Unless required by applicable law or agreed to in writing, software | * Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | * distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. | |||
* See the License for the specific language governing permissions and | * See the License for the specific language governing permissions and | |||
* limitations under the License. | * limitations under the License. | |||
*/ | */ | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "dbclient.h" | #include "dbclient.h" | |||
#include "redef_macros.h" | ||||
namespace mongo { | namespace mongo { | |||
/** | /** | |||
* this is a connection to a cluster of servers that operate as one | * this is a connection to a cluster of servers that operate as one | |||
* for super high durability | * for super high durability | |||
*/ | */ | |||
class SyncClusterConnection : public DBClientBase { | class SyncClusterConnection : public DBClientBase { | |||
public: | public: | |||
/** | /** | |||
skipping to change at line 48 | skipping to change at line 49 | |||
*/ | */ | |||
bool prepare( string& errmsg ); | bool prepare( string& errmsg ); | |||
/** | /** | |||
* runs fsync on all servers | * runs fsync on all servers | |||
*/ | */ | |||
bool fsync( string& errmsg ); | bool fsync( string& errmsg ); | |||
// --- from DBClientInterface | // --- from DBClientInterface | |||
virtual BSONObj findOne(const string &ns, Query query, const BSONOb | ||||
j *fieldsToReturn, int queryOptions); | ||||
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 ); | virtual void insert( const string &ns, BSONObj obj ); | |||
virtual void insert( const string &ns, const vector< BSONObj >& v ) ; | virtual void insert( const string &ns, const vector< BSONObj >& v ) ; | |||
virtual void remove( const string &ns , Query query, bool justOne ) ; | virtual void remove( const string &ns , Query query, bool justOne ) ; | |||
skipping to change at line 86 | skipping to change at line 89 | |||
SyncClusterConnection( SyncClusterConnection& prev ); | SyncClusterConnection( SyncClusterConnection& prev ); | |||
string _toString() const; | string _toString() const; | |||
bool _commandOnActive(const string &dbname, const BSONObj& cmd, BSO NObj &info, int options=0); | bool _commandOnActive(const string &dbname, const BSONObj& cmd, BSO NObj &info, int options=0); | |||
auto_ptr<DBClientCursor> _queryOnActive(const string &ns, Query que ry, int nToReturn, int nToSkip, | auto_ptr<DBClientCursor> _queryOnActive(const string &ns, Query que ry, int nToReturn, int nToSkip, | |||
const BSONObj *fieldsToRetu rn, int queryOptions, int batchSize ); | const BSONObj *fieldsToRetu rn, int queryOptions, int batchSize ); | |||
bool _isReadOnly( const string& name ); | int _lockType( const string& name ); | |||
void _checkLast(); | void _checkLast(); | |||
void _connect( string host ); | void _connect( string host ); | |||
string _address; | string _address; | |||
vector<DBClientConnection*> _conns; | vector<DBClientConnection*> _conns; | |||
map<string,int> _lockTypes; | map<string,int> _lockTypes; | |||
mongo::mutex _mutex; | ||||
}; | }; | |||
}; | }; | |||
#include "undef_macros.h" | ||||
End of changes. 7 change blocks. | ||||
2 lines changed or deleted | 8 lines changed or added | |||
thread_pool.h | thread_pool.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 <boost/function.hpp> | #include <boost/function.hpp> | |||
#include <boost/bind.hpp> | #include <boost/bind.hpp> | |||
#undef assert | #undef assert | |||
#define assert xassert | #define assert MONGO_assert | |||
namespace mongo { | namespace mongo { | |||
namespace threadpool { | namespace threadpool { | |||
class Worker; | class Worker; | |||
typedef boost::function<void(void)> Task; //nullary function or functor | typedef boost::function<void(void)> Task; //nullary function or functor | |||
// exported to the mongo namespace | // exported to the mongo namespace | |||
class ThreadPool : boost::noncopyable{ | class ThreadPool : boost::noncopyable{ | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
tool.h | tool.h | |||
---|---|---|---|---|
skipping to change at line 38 | skipping to change at line 38 | |||
#include "client/dbclient.h" | #include "client/dbclient.h" | |||
#include "db/instance.h" | #include "db/instance.h" | |||
using std::string; | using std::string; | |||
namespace mongo { | namespace mongo { | |||
class Tool { | class Tool { | |||
public: | public: | |||
Tool( string name , bool localDBAllowed=true, string defaultDB="tes | Tool( string name , bool localDBAllowed=true, string defaultDB="tes | |||
t" , string defaultCollection=""); | t" , | |||
string defaultCollection="", bool usesstdout=true ); | ||||
virtual ~Tool(); | virtual ~Tool(); | |||
int main( int argc , char ** argv ); | int main( int argc , char ** argv ); | |||
boost::program_options::options_description_easy_init add_options() { | boost::program_options::options_description_easy_init add_options() { | |||
return _options->add_options(); | return _options->add_options(); | |||
} | } | |||
boost::program_options::options_description_easy_init add_hidden_op tions(){ | boost::program_options::options_description_easy_init add_hidden_op tions(){ | |||
return _hidden_options->add_options(); | return _hidden_options->add_options(); | |||
} | } | |||
skipping to change at line 75 | skipping to change at line 76 | |||
} | } | |||
string getNS(){ | string getNS(){ | |||
if ( _coll.size() == 0 ){ | if ( _coll.size() == 0 ){ | |||
cerr << "no collection specified!" << endl; | cerr << "no collection specified!" << endl; | |||
throw -1; | throw -1; | |||
} | } | |||
return _db + "." + _coll; | return _db + "." + _coll; | |||
} | } | |||
virtual void preSetup(){} | ||||
virtual int run() = 0; | virtual int run() = 0; | |||
virtual void printHelp(ostream &out); | virtual void printHelp(ostream &out); | |||
virtual void printExtraHelp( ostream & out ); | virtual void printExtraHelp( ostream & out ); | |||
protected: | protected: | |||
mongo::DBClientBase &conn( bool slaveIfPaired = false ); | mongo::DBClientBase &conn( bool slaveIfPaired = false ); | |||
void auth( string db = "" ); | void auth( string db = "" ); | |||
string _name; | string _name; | |||
string _db; | string _db; | |||
string _coll; | string _coll; | |||
string _username; | string _username; | |||
string _password; | string _password; | |||
bool _usesstdout; | ||||
bool _noconnection; | ||||
void addFieldOptions(); | void addFieldOptions(); | |||
void needFields(); | void needFields(); | |||
vector<string> _fields; | vector<string> _fields; | |||
BSONObj _fieldsObj; | BSONObj _fieldsObj; | |||
private: | ||||
string _host; | string _host; | |||
protected: | ||||
mongo::DBClientBase * _conn; | mongo::DBClientBase * _conn; | |||
bool _paired; | bool _paired; | |||
boost::program_options::options_description * _options; | boost::program_options::options_description * _options; | |||
boost::program_options::options_description * _hidden_options; | boost::program_options::options_description * _hidden_options; | |||
boost::program_options::positional_options_description _positonalOp tions; | boost::program_options::positional_options_description _positonalOp tions; | |||
boost::program_options::variables_map _params; | boost::program_options::variables_map _params; | |||
}; | }; | |||
End of changes. 5 change blocks. | ||||
3 lines changed or deleted | 11 lines changed or added | |||
top.h | top.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/date_time/posix_time/posix_time.hpp> | #include <boost/date_time/posix_time/posix_time.hpp> | |||
#undef assert | #undef assert | |||
#define assert xassert | #define assert MONGO_assert | |||
namespace mongo { | namespace mongo { | |||
/** | /** | |||
* tracks usage by collection | * tracks usage by collection | |||
*/ | */ | |||
class Top { | class Top { | |||
public: | public: | |||
class UsageData { | class UsageData { | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
update.h | update.h | |||
---|---|---|---|---|
skipping to change at line 19 | skipping to change at line 19 | |||
* | * | |||
* This program is distributed in the hope that it will be useful, | * This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | * GNU Affero General Public License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Lice nse | * You should have received a copy of the GNU Affero General Public Lice nse | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "jsobj.h" | #include "jsobj.h" | |||
#include "../util/embedded_builder.h" | #include "../util/embedded_builder.h" | |||
#include "matcher.h" | #include "matcher.h" | |||
namespace mongo { | namespace mongo { | |||
class ModState; | class ModState; | |||
class ModSetState; | class ModSetState; | |||
/* Used for modifiers such as $inc, $set, $push, ... | /* Used for modifiers such as $inc, $set, $push, ... | |||
skipping to change at line 329 | skipping to change at line 329 | |||
}; | }; | |||
/** | /** | |||
* stores any information about a single Mod operating on a single Obje ct | * stores any information about a single Mod operating on a single Obje ct | |||
*/ | */ | |||
class ModState { | class ModState { | |||
public: | public: | |||
const Mod * m; | const Mod * m; | |||
BSONElement old; | BSONElement old; | |||
const char * fixedName; | const char * fixedOpName; | |||
BSONElement * fixed; | BSONElement * fixed; | |||
int pushStartSize; | int pushStartSize; | |||
BSONType incType; | BSONType incType; | |||
int incint; | int incint; | |||
double incdouble; | double incdouble; | |||
long long inclong; | long long inclong; | |||
ModState(){ | ModState(){ | |||
fixedName = 0; | fixedOpName = 0; | |||
fixed = 0; | fixed = 0; | |||
pushStartSize = -1; | pushStartSize = -1; | |||
incType = EOO; | incType = EOO; | |||
} | } | |||
Mod::Op op() const { | Mod::Op op() const { | |||
return m->op; | return m->op; | |||
} | } | |||
const char * fieldName() const { | const char * fieldName() const { | |||
return m->fieldName; | return m->fieldName; | |||
} | } | |||
bool needOpLogRewrite() const { | bool needOpLogRewrite() const { | |||
if ( fixed || fixedName || incType ) | if ( fixed || fixedOpName || incType ) | |||
return true; | return true; | |||
switch( op() ){ | switch( op() ){ | |||
case Mod::BIT: | case Mod::BIT: | |||
case Mod::BITAND: | case Mod::BITAND: | |||
case Mod::BITOR: | case Mod::BITOR: | |||
// TODO: should we convert this to $set? | // TODO: should we convert this to $set? | |||
return false; | return false; | |||
default: | default: | |||
return false; | return false; | |||
skipping to change at line 376 | skipping to change at line 376 | |||
} | } | |||
void appendForOpLog( BSONObjBuilder& b ) const { | void appendForOpLog( BSONObjBuilder& b ) const { | |||
if ( incType ){ | if ( incType ){ | |||
BSONObjBuilder bb( b.subobjStart( "$set" ) ); | BSONObjBuilder bb( b.subobjStart( "$set" ) ); | |||
appendIncValue( bb ); | appendIncValue( bb ); | |||
bb.done(); | bb.done(); | |||
return; | return; | |||
} | } | |||
const char * name = fixedName ? fixedName : Mod::modNames[op()] ; | const char * name = fixedOpName ? fixedOpName : Mod::modNames[o p()]; | |||
BSONObjBuilder bb( b.subobjStart( name ) ); | BSONObjBuilder bb( b.subobjStart( name ) ); | |||
if ( fixed ) | if ( fixed ) | |||
bb.appendAs( *fixed , m->fieldName ); | bb.appendAs( *fixed , m->fieldName ); | |||
else | else | |||
bb.append( m->elt ); | bb.appendAs( m->elt , m->fieldName ); | |||
bb.done(); | bb.done(); | |||
} | } | |||
template< class Builder > | template< class Builder > | |||
void apply( Builder& b , BSONElement in ){ | void apply( Builder& b , BSONElement in ){ | |||
m->apply( b , in , *this ); | m->apply( b , in , *this ); | |||
} | } | |||
template< class Builder > | template< class Builder > | |||
void appendIncValue( Builder& b ) const { | void appendIncValue( Builder& b ) const { | |||
skipping to change at line 472 | skipping to change at line 472 | |||
break; | break; | |||
} | } | |||
case Mod::UNSET: | case Mod::UNSET: | |||
case Mod::PULL: | case Mod::PULL: | |||
case Mod::PULL_ALL: | case Mod::PULL_ALL: | |||
// no-op b/c unset/pull of nothing does nothing | // no-op b/c unset/pull of nothing does nothing | |||
break; | break; | |||
case Mod::INC: | case Mod::INC: | |||
ms.fixedName = "$set"; | ms.fixedOpName = "$set"; | |||
case Mod::SET: { | case Mod::SET: { | |||
m._checkForAppending( m.elt ); | m._checkForAppending( m.elt ); | |||
b.appendAs( m.elt, m.shortFieldName ); | b.appendAs( m.elt, m.shortFieldName ); | |||
break; | break; | |||
} | } | |||
default: | default: | |||
stringstream ss; | stringstream ss; | |||
ss << "unknown mod in appendNewFromMod: " << m.op; | ss << "unknown mod in appendNewFromMod: " << m.op; | |||
throw UserException( 9015, ss.str() ); | throw UserException( 9015, ss.str() ); | |||
} | } | |||
End of changes. 7 change blocks. | ||||
7 lines changed or deleted | 7 lines changed or added | |||
util.h | util.h | |||
---|---|---|---|---|
skipping to change at line 21 | skipping to change at line 21 | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | * GNU Affero General Public License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Affero General Public Licen se | * You should have received a copy of the GNU Affero General Public Licen se | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
#pragma once | #pragma once | |||
#include "../stdafx.h" | #include "../pch.h" | |||
#include "../client/dbclient.h" | #include "../client/dbclient.h" | |||
/** | /** | |||
some generic sharding utils that can be used in mongod or mongos | some generic sharding utils that can be used in mongod or mongos | |||
*/ | */ | |||
namespace mongo { | namespace mongo { | |||
/** | /** | |||
your config info for a given shard/chunk is out of date */ | your config info for a given shard/chunk is out of date */ | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||