| btree.h | | btree.h | |
| | | | |
| skipping to change at line 56 | | skipping to change at line 56 | |
| recordLoc.GETOFS() &= ~1; | | recordLoc.GETOFS() &= ~1; | |
| } | | } | |
| void setUnused() { | | void setUnused() { | |
| /* Setting ofs to odd is the sentinel for unused, as real recor
dLoc's are always | | /* Setting ofs to odd is the sentinel for unused, as real recor
dLoc's are always | |
| even numbers. | | even numbers. | |
| Note we need to keep its value basically the same as we use
the recordLoc | | Note we need to keep its value basically the same as we use
the recordLoc | |
| as part of the key in the index (to handle duplicate keys ef
ficiently). | | as part of the key in the index (to handle duplicate keys ef
ficiently). | |
| */ | | */ | |
| recordLoc.GETOFS() |= 1; | | recordLoc.GETOFS() |= 1; | |
| } | | } | |
|
| int isUnused() { | | int isUnused() const { | |
| return recordLoc.getOfs() & 1; | | return recordLoc.getOfs() & 1; | |
| } | | } | |
|
| int isUsed() { | | int isUsed() const { | |
| return !isUnused(); | | return !isUnused(); | |
| } | | } | |
| }; | | }; | |
| | | | |
| #pragma pack() | | #pragma pack() | |
| | | | |
| class BucketBasics; | | class BucketBasics; | |
| | | | |
| /* wrapper - this is our in memory representation of the key. _KeyNode
is the disk representation. */ | | /* wrapper - this is our in memory representation of the key. _KeyNode
is the disk representation. */ | |
| class KeyNode { | | class KeyNode { | |
| | | | |
| skipping to change at line 88 | | skipping to change at line 88 | |
| | | | |
| /* 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 BSONObj &order, bool force = false); | |
| int fullValidate(const DiskLoc& thisLoc, const BSONObj &order); /*
traverses everything */ | | int fullValidate(const DiskLoc& thisLoc, const BSONObj &order); /*
traverses everything */ | |
|
| protected: | | | |
| void modified(const DiskLoc& thisLoc); | | | |
| 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: | |
| | | | |
| | | void modified(const DiskLoc& thisLoc); | |
| | | | |
| 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 BSONObj &order); | |
| | | | |
| skipping to change at line 157 | | skipping to change at line 160 | |
| 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 << " Size: " << _Size << " 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 { | |
| | | 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. | | int _Size; // total size of this btree node in bytes. constant. | |
| 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; | |
| | | | |
| skipping to change at line 373 | | skipping to change at line 380 | |
| | | | |
| const IndexDetails& indexDetails; | | const IndexDetails& indexDetails; | |
| BSONObj order; | | BSONObj order; | |
| DiskLoc bucket; | | DiskLoc bucket; | |
| int keyOfs; | | int keyOfs; | |
| int direction; // 1=fwd,-1=reverse | | int direction; // 1=fwd,-1=reverse | |
| BSONObj keyAtKeyOfs; // so we can tell if things moved around on us
between the query and the getMore call | | BSONObj keyAtKeyOfs; // so we can tell if things moved around on us
between the query and the getMore call | |
| DiskLoc locAtKeyOfs; | | DiskLoc locAtKeyOfs; | |
| BoundList bounds_; | | BoundList bounds_; | |
| unsigned boundIndex_; | | unsigned boundIndex_; | |
|
| | | const IndexSpec& _spec; | |
| }; | | }; | |
| | | | |
| #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, keyPattern()); | |
| } | | } | |
| 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, keyPattern(),
self); | |
| } | | } | |
| | | | |
End of changes. 6 change blocks. |
| 4 lines changed or deleted | | 12 lines changed or added | |
|
| commands.h | | commands.h | |
| | | | |
| skipping to change at line 28 | | skipping to change at line 28 | |
| #pragma once | | #pragma once | |
| | | | |
| #include "../stdafx.h" | | #include "../stdafx.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; | |
| | | | |
| // db "commands" (sent via db.$cmd.findOne(...)) | | // db "commands" (sent via db.$cmd.findOne(...)) | |
| // subclass to make a command. | | // subclass to make a command. | |
| class Command { | | class Command { | |
| public: | | public: | |
|
| | | | |
| | | enum LockType { READ = -1 , NONE = 0 , WRITE = 1 }; | |
| | | | |
| string name; | | 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; | |
| | | | |
|
| /* true if a read lock is sufficient | | /* | |
| note: logTheTop() MUST be false if readOnly | | note: logTheTop() MUST be false if READ | |
| | | if NONE, can't use Client::Context setup | |
| | | use with caution | |
| */ | | */ | |
|
| virtual bool readOnly() { | | virtual LockType locktype() = 0; | |
| return false; | | | |
| } | | | |
| | | | |
| /* Return true if only the admin ns has privileges to run this comm
and. */ | | /* Return true if only the admin ns has privileges to run this comm
and. */ | |
| virtual bool adminOnly() { | | virtual bool adminOnly() { | |
| return false; | | return false; | |
| } | | } | |
| | | | |
| /* 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. | |
| | | | |
| skipping to change at line 108 | | skipping to change at line 112 | |
| 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; | |
| | | | |
| public: | | public: | |
| static bool runAgainstRegistered(const char *ns, BSONObj& jsobj, BS
ONObjBuilder& anObjBuilder); | | static bool runAgainstRegistered(const char *ns, BSONObj& jsobj, BS
ONObjBuilder& anObjBuilder); | |
|
| static bool readOnly( 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. 5 change blocks. |
| 6 lines changed or deleted | | 10 lines changed or added | |
|
| dbclient.h | | dbclient.h | |
| | | | |
| skipping to change at line 24 | | skipping to change at line 24 | |
| * See the License for the specific language governing permissions and | | * See the License for the specific language governing permissions and | |
| * limitations under the License. | | * limitations under the License. | |
| */ | | */ | |
| | | | |
| #pragma once | | #pragma once | |
| | | | |
| #include "../stdafx.h" | | #include "../stdafx.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> | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| /** the query field 'options' can have these bits set: */ | | /** the query field 'options' can have these bits set: */ | |
| enum QueryOptions { | | enum QueryOptions { | |
| /** Tailable means cursor is not closed when the last data is retri
eved. rather, the cursor marks | | /** Tailable means cursor is not closed when the last data is retri
eved. rather, the cursor marks | |
| the final object's position. you can resume using the cursor la
ter, from where it was located, | | the final object's position. you can resume using the cursor la
ter, from where it was located, | |
| if more data were received. Set on dbQuery and dbGetMore. | | if more data were received. Set on dbQuery and dbGetMore. | |
| | | | |
| like any "latent cursor", the cursor may become invalid at some
point -- for example if that | | like any "latent cursor", the cursor may become invalid at some
point -- for example if that | |
| | | | |
| skipping to change at line 213 | | skipping to change at line 214 | |
| bool init(); | | bool init(); | |
| public: | | public: | |
| /** If true, safe to call next(). Requests more from server
if necessary. */ | | /** If true, safe to call next(). Requests more from server
if necessary. */ | |
| bool more(); | | bool more(); | |
| | | | |
| /** If true, there is more in our local buffers to be fetched via n
ext(). Returns | | /** If true, there is more in our local buffers to be fetched via n
ext(). Returns | |
| false when a getMore request back to server would be required.
You can use this | | false when a getMore request back to server would be required.
You can use this | |
| if you want to exhaust whatever data has been fetched to the cl
ient already but | | if you want to exhaust whatever data has been fetched to the cl
ient already but | |
| then perhaps stop. | | then perhaps stop. | |
| */ | | */ | |
|
| bool moreInCurrentBatch() { return pos < nReturned; } | | bool moreInCurrentBatch() { return !_putBack.empty() || pos < nRetu
rned; } | |
| | | | |
| /** next | | /** next | |
| @return next object in the result cursor. | | @return next object in the result cursor. | |
| on an error at the remote server, you will get back: | | on an error at the remote server, you will get back: | |
| { $err: <string> } | | { $err: <string> } | |
| if you do not want to handle that yourself, call nextSafe(). | | if you do not want to handle that yourself, call nextSafe(). | |
| */ | | */ | |
| BSONObj next(); | | 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 : ... } */ | | /** throws AssertionException if get back { $err : ... } */ | |
| BSONObj nextSafe() { | | BSONObj nextSafe() { | |
| BSONObj o = next(); | | BSONObj o = next(); | |
| BSONElement e = o.firstElement(); | | BSONElement e = o.firstElement(); | |
| assert( strcmp(e.fieldName(), "$err") != 0 ); | | assert( strcmp(e.fieldName(), "$err") != 0 ); | |
| return o; | | return o; | |
| } | | } | |
| | | | |
| /** | | /** | |
| iterate the rest of the cursor and return the number if items | | iterate the rest of the cursor and return the number if items | |
| | | | |
| skipping to change at line 256 | | skipping to change at line 262 | |
| available from the dbclientcursor. | | available from the dbclientcursor. | |
| */ | | */ | |
| bool isDead() const { | | bool isDead() const { | |
| return cursorId == 0; | | return cursorId == 0; | |
| } | | } | |
| | | | |
| bool tailable() const { | | bool tailable() const { | |
| return (opts & QueryOption_CursorTailable) != 0; | | 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 ){ | | bool hasResultFlag( int flag ){ | |
| return (resultFlags & flag) != 0; | | return (resultFlags & flag) != 0; | |
| } | | } | |
|
| public: | | | |
| DBClientCursor( DBConnector *_connector, const string &_ns, BSONObj
_query, int _nToReturn, | | DBClientCursor( DBConnector *_connector, const string &_ns, BSONObj
_query, int _nToReturn, | |
|
| int _nToSkip, const BSONObj *_fieldsToReturn, int q
ueryOptions ) : | | int _nToSkip, const BSONObj *_fieldsToReturn, int q
ueryOptions , int bs ) : | |
| connector(_connector), | | connector(_connector), | |
| ns(_ns), | | ns(_ns), | |
| query(_query), | | query(_query), | |
| nToReturn(_nToReturn), | | nToReturn(_nToReturn), | |
|
| | | haveLimit( _nToReturn > 0 && !(queryOptions & QueryOption_C
ursorTailable)), | |
| nToSkip(_nToSkip), | | nToSkip(_nToSkip), | |
| fieldsToReturn(_fieldsToReturn), | | fieldsToReturn(_fieldsToReturn), | |
| opts(queryOptions), | | opts(queryOptions), | |
|
| | | batchSize(bs), | |
| m(new Message()), | | m(new Message()), | |
| cursorId(), | | cursorId(), | |
| nReturned(), | | nReturned(), | |
| pos(), | | pos(), | |
| data(), | | data(), | |
| _ownCursor( true ) { | | _ownCursor( true ) { | |
| } | | } | |
| | | | |
| DBClientCursor( DBConnector *_connector, const string &_ns, long lo
ng _cursorId, int _nToReturn, int options ) : | | DBClientCursor( DBConnector *_connector, const string &_ns, long lo
ng _cursorId, int _nToReturn, int options ) : | |
| connector(_connector), | | connector(_connector), | |
| ns(_ns), | | ns(_ns), | |
| nToReturn( _nToReturn ), | | nToReturn( _nToReturn ), | |
|
| | | haveLimit( _nToReturn > 0 && !(options & QueryOption_Cursor
Tailable)), | |
| opts( options ), | | opts( options ), | |
| m(new Message()), | | m(new Message()), | |
| cursorId( _cursorId ), | | cursorId( _cursorId ), | |
| nReturned(), | | nReturned(), | |
| pos(), | | pos(), | |
| data(), | | data(), | |
| _ownCursor( true ) { | | _ownCursor( true ) { | |
| } | | } | |
| | | | |
| virtual ~DBClientCursor(); | | virtual ~DBClientCursor(); | |
| | | | |
| long long getCursorId() const { return cursorId; } | | long long getCursorId() const { return cursorId; } | |
| | | | |
| /** by default we "own" the cursor and will send the server a KillC
ursor | | /** by default we "own" the cursor and will send the server a KillC
ursor | |
| message when ~DBClientCursor() is called. This function overrid
es that. | | message when ~DBClientCursor() is called. This function overrid
es that. | |
| */ | | */ | |
| void decouple() { _ownCursor = false; } | | void decouple() { _ownCursor = false; } | |
| | | | |
| private: | | private: | |
|
| | | | |
| | | int nextBatchSize(); | |
| | | | |
| DBConnector *connector; | | DBConnector *connector; | |
| string ns; | | string ns; | |
| BSONObj query; | | BSONObj query; | |
| int nToReturn; | | int nToReturn; | |
|
| | | bool haveLimit; | |
| int nToSkip; | | int nToSkip; | |
| const BSONObj *fieldsToReturn; | | const BSONObj *fieldsToReturn; | |
| int opts; | | int opts; | |
|
| | | int batchSize; | |
| auto_ptr<Message> m; | | auto_ptr<Message> m; | |
|
| | | stack< BSONObj > _putBack; | |
| | | | |
| int resultFlags; | | int resultFlags; | |
| long long cursorId; | | long long cursorId; | |
| int nReturned; | | int nReturned; | |
| int pos; | | int pos; | |
| const char *data; | | const char *data; | |
| void dataReceived(); | | void dataReceived(); | |
| void requestMore(); | | void requestMore(); | |
| bool _ownCursor; // see decouple() | | 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) = 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; | |
| | | | |
| virtual void insert( const string &ns, BSONObj obj ) = 0; | | virtual void insert( const string &ns, BSONObj obj ) = 0; | |
| | | | |
| virtual void insert( const string &ns, const vector< BSONObj >& v )
= 0; | | virtual void insert( const string &ns, const vector< BSONObj >& v )
= 0; | |
| | | | |
| virtual void remove( const string &ns , Query query, bool justOne =
0 ) = 0; | | virtual void remove( const string &ns , Query query, bool justOne =
0 ) = 0; | |
| | | | |
| virtual void update( const string &ns , Query query , BSONObj obj ,
bool upsert = 0 , bool multi = 0 ) = 0; | | virtual void update( const string &ns , Query query , BSONObj obj ,
bool upsert = 0 , bool multi = 0 ) = 0; | |
| | | | |
| skipping to change at line 669 | | skipping to change at line 688 | |
| nToReturn: n to return. 0 = unlimited | | nToReturn: n to return. 0 = unlimited | |
| nToSkip: start with the nth item | | nToSkip: start with the nth item | |
| fieldsToReturn: | | fieldsToReturn: | |
| optional template of which fields to select. if unspecified, retur
ns all fields | | optional template of which fields to select. if unspecified, retur
ns all fields | |
| 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); | | 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 | |
| */ | | */ | |
| virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo
ng cursorId, int nToReturn = 0, int options = 0 ); | | virtual auto_ptr<DBClientCursor> getMore( const string &ns, long lo
ng cursorId, int nToReturn = 0, int options = 0 ); | |
| | | | |
| /** | | /** | |
| insert an object into the database | | insert an object into the database | |
| */ | | */ | |
| | | | |
| skipping to change at line 763 | | skipping to change at line 782 | |
| */ | | */ | |
| 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, int nToReturn = 0, int nToSkip = 0, | |
|
| const BSONObj *fieldsToRetur
n = 0, int queryOptions = 0) { | | const BSONObj *fieldsToRetur
n = 0, int queryOptions = 0 , int batchSize = 0 ) { | |
| checkConnection(); | | checkConnection(); | |
|
| return DBClientBase::query( ns, query, nToReturn, nToSkip, fiel
dsToReturn, queryOptions ); | | 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 { | |
| return failed; | | return failed; | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 843 | | skipping to change at line 862 | |
| */ | | */ | |
| bool connect(string hostpairstring); | | bool connect(string hostpairstring); | |
| | | | |
| /** Authorize. Authorizes both sides of the pair as needed. | | /** Authorize. Authorizes both sides of the pair as needed. | |
| */ | | */ | |
| bool auth(const string &dbname, const string &username, const strin
g &pwd, string& errmsg); | | bool auth(const string &dbname, const string &username, const strin
g &pwd, string& errmsg); | |
| | | | |
| /** throws userassertion "no master found" */ | | /** throws userassertion "no master found" */ | |
| virtual | | virtual | |
| auto_ptr<DBClientCursor> query(const string &ns, Query query, int n
ToReturn = 0, int nToSkip = 0, | | auto_ptr<DBClientCursor> query(const string &ns, Query query, int n
ToReturn = 0, int nToSkip = 0, | |
|
| const BSONObj *fieldsToReturn = 0, i
nt queryOptions = 0); | | const BSONObj *fieldsToReturn = 0, i
nt queryOptions = 0 , int batchSize = 0 ); | |
| | | | |
| /** throws userassertion "no master found" */ | | /** throws userassertion "no master found" */ | |
| virtual | | virtual | |
| BSONObj findOne(const string &ns, Query query, const BSONObj *field
sToReturn = 0, int queryOptions = 0); | | BSONObj findOne(const string &ns, Query query, const BSONObj *field
sToReturn = 0, int queryOptions = 0); | |
| | | | |
| /** insert */ | | /** insert */ | |
| virtual void insert( const string &ns , BSONObj obj ) { | | virtual void insert( const string &ns , BSONObj obj ) { | |
| checkMaster().insert(ns, obj); | | checkMaster().insert(ns, obj); | |
| } | | } | |
| | | | |
| | | | |
End of changes. 18 change blocks. |
| 8 lines changed or deleted | | 28 lines changed or added | |
|
| extsort.h | | extsort.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/>. | |
| */ | | */ | |
| | | | |
| #pragma once | | #pragma once | |
| | | | |
| #include "../stdafx.h" | | #include "../stdafx.h" | |
| #include "jsobj.h" | | #include "jsobj.h" | |
| #include "namespace.h" | | #include "namespace.h" | |
| #include "curop.h" | | #include "curop.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 | |
| */ | | */ | |
| class BSONObjExternalSorter : boost::noncopyable { | | class BSONObjExternalSorter : boost::noncopyable { | |
| public: | | public: | |
| | | | |
| typedef pair<BSONObj,DiskLoc> Data; | | typedef pair<BSONObj,DiskLoc> Data; | |
| | | | |
| private: | | private: | |
|
| | | static BSONObj extSortOrder; | |
| | | | |
| | | static int extSortComp( const void *lv, const void *rv ){ | |
| | | RARELY killCurrentOp.checkForInterrupt(); | |
| | | _compares++; | |
| | | Data * l = (Data*)lv; | |
| | | Data * r = (Data*)rv; | |
| | | int cmp = l->first.woCompare( r->first , extSortOrder ); | |
| | | if ( cmp ) | |
| | | return cmp; | |
| | | return l->second.compare( r->second ); | |
| | | }; | |
| | | | |
| class FileIterator : boost::noncopyable { | | class FileIterator : boost::noncopyable { | |
| public: | | public: | |
| FileIterator( string file ); | | FileIterator( string file ); | |
| ~FileIterator(); | | ~FileIterator(); | |
| bool more(); | | bool more(); | |
| Data next(); | | Data next(); | |
| private: | | private: | |
| MemoryMappedFile _file; | | MemoryMappedFile _file; | |
| char * _buf; | | char * _buf; | |
| char * _end; | | char * _end; | |
| | | | |
| skipping to change at line 60 | | skipping to change at line 74 | |
| public: | | public: | |
| MyCmp( const BSONObj & order = BSONObj() ) : _order( order ){} | | MyCmp( const BSONObj & order = BSONObj() ) : _order( order ){} | |
| bool operator()( const Data &l, const Data &r ) const { | | bool operator()( const Data &l, const Data &r ) const { | |
| RARELY killCurrentOp.checkForInterrupt(); | | RARELY killCurrentOp.checkForInterrupt(); | |
| _compares++; | | _compares++; | |
| int x = l.first.woCompare( r.first , _order ); | | int x = l.first.woCompare( r.first , _order ); | |
| if ( x ) | | if ( x ) | |
| return x < 0; | | return x < 0; | |
| return l.second.compare( r.second ) < 0; | | return l.second.compare( r.second ) < 0; | |
| }; | | }; | |
|
| | | | |
| private: | | private: | |
| BSONObj _order; | | BSONObj _order; | |
| }; | | }; | |
| | | | |
| public: | | public: | |
| | | | |
|
| typedef list<Data> InMemory; | | typedef FastArray<Data> InMemory; | |
| | | | |
| class Iterator : boost::noncopyable { | | class Iterator : boost::noncopyable { | |
| public: | | public: | |
| | | | |
| Iterator( BSONObjExternalSorter * sorter ); | | Iterator( BSONObjExternalSorter * sorter ); | |
| ~Iterator(); | | ~Iterator(); | |
| bool more(); | | bool more(); | |
| Data next(); | | Data next(); | |
| | | | |
| private: | | private: | |
| | | | |
| skipping to change at line 106 | | skipping to change at line 121 | |
| | | | |
| auto_ptr<Iterator> iterator(){ | | auto_ptr<Iterator> iterator(){ | |
| uassert( 10052 , "not sorted" , _sorted ); | | uassert( 10052 , "not sorted" , _sorted ); | |
| return auto_ptr<Iterator>( new Iterator( this ) ); | | return auto_ptr<Iterator>( new Iterator( this ) ); | |
| } | | } | |
| | | | |
| int numFiles(){ | | int numFiles(){ | |
| return _files.size(); | | return _files.size(); | |
| } | | } | |
| | | | |
|
| | | long getCurSizeSoFar(){ return _curSizeSoFar; } | |
| | | | |
| | | void hintNumObjects( long long numObjects ){ | |
| | | if ( numObjects < _arraySize ) | |
| | | _arraySize = (int)(numObjects + 100); | |
| | | } | |
| | | | |
| private: | | private: | |
| | | | |
|
| | | void _sortInMem(); | |
| | | | |
| void sort( string file ); | | void sort( string file ); | |
| void finishMap(); | | void finishMap(); | |
| | | | |
| BSONObj _order; | | BSONObj _order; | |
| long _maxFilesize; | | long _maxFilesize; | |
| path _root; | | path _root; | |
| | | | |
|
| | | int _arraySize; | |
| InMemory * _cur; | | InMemory * _cur; | |
| long _curSizeSoFar; | | long _curSizeSoFar; | |
| | | | |
| list<string> _files; | | list<string> _files; | |
| bool _sorted; | | bool _sorted; | |
| | | | |
| static unsigned long long _compares; | | static unsigned long long _compares; | |
| }; | | }; | |
| } | | } | |
| | | | |
End of changes. 7 change blocks. |
| 1 lines changed or deleted | | 26 lines changed or added | |
|
| index.h | | index.h | |
| | | | |
| skipping to change at line 22 | | skipping to change at line 22 | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU Affero General Public License for more details. | | * GNU Affero General Public License for more details. | |
| * | | * | |
| * You should have received a copy of the GNU Affero General Public Licen
se | | * You should have received a copy of the GNU Affero General Public Licen
se | |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. | | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| */ | | */ | |
| | | | |
| #pragma once | | #pragma once | |
| | | | |
| #include "../stdafx.h" | | #include "../stdafx.h" | |
|
| | | #include "diskloc.h" | |
| | | #include "jsobj.h" | |
| | | #include <map> | |
| | | | |
| 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 ; | |
| | | | |
| | | 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 | | /* precomputed details about an index, used for inserting keys on updat
es | |
| stored/cached in NamespaceDetailsTransient, or can be used standalon
e | | stored/cached in NamespaceDetailsTransient, or can be used standalon
e | |
| */ | | */ | |
| class IndexSpec { | | class IndexSpec { | |
| public: | | public: | |
| BSONObj keyPattern; // e.g., { name : 1 } | | BSONObj keyPattern; // e.g., { name : 1 } | |
| BSONObj info; // this is the same as IndexDetails::info.obj() | | BSONObj info; // this is the same as IndexDetails::info.obj() | |
| | | | |
|
| IndexSpec(){ | | IndexSpec() | |
| | | : _details(0) , _finishedInit(false){ | |
| } | | } | |
| | | | |
| IndexSpec( const BSONObj& k , const BSONObj& m = BSONObj() ) | | IndexSpec( const BSONObj& k , const BSONObj& m = BSONObj() ) | |
|
| : keyPattern(k) , info(m){ | | : keyPattern(k) , info(m) , _details(0) , _finishedInit(false){ | |
| _init(); | | _init(); | |
| } | | } | |
| | | | |
| /** | | /** | |
| this is a DiscLoc of an IndexDetails info | | this is a DiscLoc of an IndexDetails info | |
| should have a key field | | should have a key field | |
| */ | | */ | |
| IndexSpec( const DiskLoc& loc ){ | | IndexSpec( const DiskLoc& loc ){ | |
| reset( loc ); | | reset( loc ); | |
| } | | } | |
| | | | |
|
| void reset( const DiskLoc& loc ){ | | void reset( const DiskLoc& loc ); | |
| info = loc.obj(); | | void reset( const IndexDetails * details ); | |
| keyPattern = info["key"].embeddedObjectUserCheck(); | | | |
| if ( keyPattern.objsize() == 0 ) { | | | |
| out() << info.toString() << endl; | | | |
| assert(false); | | | |
| } | | | |
| _init(); | | | |
| } | | | |
| | | | |
| void getKeys( const BSONObj &obj, BSONObjSetDefaultOrder &keys ) co
nst; | | void getKeys( const BSONObj &obj, BSONObjSetDefaultOrder &keys ) co
nst; | |
| | | | |
|
| private: | | 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; | | void _getKeys( vector<const char*> fieldNames , vector<BSONElement>
fixed , const BSONObj &obj, BSONObjSetDefaultOrder &keys ) const; | |
| | | | |
|
| | | BSONSizeTracker _sizeTracker; | |
| | | | |
| vector<const char*> _fieldNames; | | vector<const char*> _fieldNames; | |
| vector<BSONElement> _fixed; | | vector<BSONElement> _fixed; | |
| BSONObj _nullKey; | | BSONObj _nullKey; | |
| | | | |
| BSONObj _nullObj; | | BSONObj _nullObj; | |
| BSONElement _nullElt; | | BSONElement _nullElt; | |
| | | | |
|
| | | shared_ptr<IndexType> _indexType; | |
| | | | |
| | | const IndexDetails * _details; | |
| | | | |
| void _init(); | | 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: | |
| | | | |
| skipping to change at line 178 | | skipping to change at line 274 | |
| /* if set, when building index, if any duplicates, drop the duplica
ting object */ | | /* if set, when building index, if any duplicates, drop the duplica
ting object */ | |
| bool dropDups() const { | | bool dropDups() const { | |
| return info.obj().getBoolField( "dropDups" ); | | return info.obj().getBoolField( "dropDups" ); | |
| } | | } | |
| | | | |
| /* delete this index. does NOT clean up the system catalog | | /* delete this index. does NOT clean up the system catalog | |
| (system.indexes or system.namespaces) -- only NamespaceIndex. | | (system.indexes or system.namespaces) -- only NamespaceIndex. | |
| */ | | */ | |
| void kill_idx(); | | void kill_idx(); | |
| | | | |
|
| | | const IndexSpec& getSpec() const; | |
| | | | |
| operator string() const { | | operator string() const { | |
| return info.obj().toString(); | | return info.obj().toString(); | |
| } | | } | |
| }; | | }; | |
| | | | |
| struct IndexChanges/*on an update*/ { | | struct IndexChanges/*on an update*/ { | |
| BSONObjSetDefaultOrder oldkeys; | | BSONObjSetDefaultOrder oldkeys; | |
| BSONObjSetDefaultOrder newkeys; | | BSONObjSetDefaultOrder newkeys; | |
| vector<BSONObj*> removed; // these keys were removed as part of the
change | | vector<BSONObj*> removed; // these keys were removed as part of the
change | |
| vector<BSONObj*> added; // these keys were added as part of the c
hange | | vector<BSONObj*> added; // these keys were added as part of the c
hange | |
| | | | |
End of changes. 10 change blocks. |
| 12 lines changed or deleted | | 116 lines changed or added | |
|
| jsobj.h | | jsobj.h | |
| | | | |
| skipping to change at line 483 | | skipping to change at line 483 | |
| /** Get the scope SavedContext of a CodeWScope data element. */ | | /** Get the scope SavedContext of a CodeWScope data element. */ | |
| const char * codeWScopeScopeData() const { | | const char * codeWScopeScopeData() const { | |
| // TODO fix | | // TODO fix | |
| return codeWScopeCode() + strlen( codeWScopeCode() ) + 1; | | return codeWScopeCode() + strlen( codeWScopeCode() ) + 1; | |
| } | | } | |
| | | | |
| /** Get the embedded object this element holds. */ | | /** Get the embedded object this element holds. */ | |
| BSONObj embeddedObject() const; | | BSONObj embeddedObject() const; | |
| | | | |
| /* uasserts if not an object */ | | /* uasserts if not an object */ | |
|
| BSONObj embeddedObjectUserCheck(); | | BSONObj embeddedObjectUserCheck() const; | |
| | | | |
| BSONObj codeWScopeObject() const; | | BSONObj codeWScopeObject() const; | |
| | | | |
| string ascode() const { | | string ascode() const { | |
| switch( type() ){ | | switch( type() ){ | |
| case String: | | case String: | |
| case Code: | | case Code: | |
| return valuestr(); | | return valuestr(); | |
| case CodeWScope: | | case CodeWScope: | |
| return codeWScopeCode(); | | return codeWScopeCode(); | |
| | | | |
| skipping to change at line 653 | | skipping to change at line 653 | |
| fieldNameSize_ = (int)strlen( fieldName() ) + 1; | | fieldNameSize_ = (int)strlen( fieldName() ) + 1; | |
| return fieldNameSize_; | | return fieldNameSize_; | |
| } | | } | |
| mutable int totalSize; /* caches the computed size */ | | mutable int totalSize; /* caches the computed size */ | |
| }; | | }; | |
| | | | |
| int getGtLtOp(const BSONElement& e); | | int getGtLtOp(const BSONElement& e); | |
| | | | |
| struct BSONElementCmpWithoutField { | | struct BSONElementCmpWithoutField { | |
| bool operator()( const BSONElement &l, const BSONElement &r ) const
{ | | bool operator()( const BSONElement &l, const BSONElement &r ) const
{ | |
|
| return l.woCompare( r, false ); | | return l.woCompare( r, false ) < 0; | |
| } | | } | |
| }; | | }; | |
| | | | |
| typedef set< BSONElement, BSONElementCmpWithoutField > BSONElementSet; | | typedef set< BSONElement, BSONElementCmpWithoutField > BSONElementSet; | |
| | | | |
| /** | | /** | |
| C++ representation of a "BSON" object -- that is, an extended JSO
N-style | | C++ representation of a "BSON" object -- that is, an extended JSO
N-style | |
| object in a binary representation. | | object in a binary representation. | |
| | | | |
| Note that BSONObj's have a smart pointer capability built in -- so y
ou can | | Note that BSONObj's have a smart pointer capability built in -- so y
ou can | |
| | | | |
| skipping to change at line 995 | | skipping to change at line 995 | |
| opIN = 0x8, // { x : { $in : [1,2,3] } } | | opIN = 0x8, // { x : { $in : [1,2,3] } } | |
| NE = 0x9, | | NE = 0x9, | |
| opSIZE = 0x0A, | | opSIZE = 0x0A, | |
| opALL = 0x0B, | | opALL = 0x0B, | |
| NIN = 0x0C, | | NIN = 0x0C, | |
| opEXISTS = 0x0D, | | opEXISTS = 0x0D, | |
| opMOD = 0x0E, | | opMOD = 0x0E, | |
| opTYPE = 0x0F, | | opTYPE = 0x0F, | |
| opREGEX = 0x10, | | opREGEX = 0x10, | |
| opOPTIONS = 0x11, | | opOPTIONS = 0x11, | |
|
| opELEM_MATCH = 0x12 | | opELEM_MATCH = 0x12, | |
| | | opNEAR = 0x13 | |
| }; | | }; | |
| }; | | }; | |
| ostream& operator<<( ostream &s, const BSONObj &o ); | | ostream& operator<<( ostream &s, const BSONObj &o ); | |
| ostream& operator<<( ostream &s, const BSONElement &e ); | | ostream& operator<<( ostream &s, const BSONElement &e ); | |
| | | | |
| struct BSONArray: BSONObj { | | struct BSONArray: BSONObj { | |
| // Don't add anything other than forwarding constructors!!! | | // Don't add anything other than forwarding constructors!!! | |
| BSONArray(): BSONObj() {} | | BSONArray(): BSONObj() {} | |
| explicit BSONArray(const BSONObj& obj): BSONObj(obj) {} | | explicit BSONArray(const BSONObj& obj): BSONObj(obj) {} | |
| }; | | }; | |
| | | | |
| skipping to change at line 1047 | | skipping to change at line 1048 | |
| BSON( "name" << "joe" << "age" << 33 ) | | BSON( "name" << "joe" << "age" << 33 ) | |
| | | | |
| with auto-generated object id: | | with auto-generated object id: | |
| BSON( GENOID << "name" << "joe" << "age" << 33 ) | | BSON( GENOID << "name" << "joe" << "age" << 33 ) | |
| | | | |
| The labels GT, GTE, LT, LTE, NE can be helpful for stream-oriented cons
truction | | 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, | | of a BSONObj, particularly when assembling a Query. For example, | |
| BSON( "a" << GT << 23.4 << NE << 30 << "b" << 2 ) produces the object | | BSON( "a" << GT << 23.4 << NE << 30 << "b" << 2 ) produces the object | |
| { a: { \$gt: 23.4, \$ne: 30 }, b: 2 }. | | { a: { \$gt: 23.4, \$ne: 30 }, b: 2 }. | |
| */ | | */ | |
|
| #define BSON(x) (( mongo::BSONObjBuilder() << x ).obj()) | | #define BSON(x) (( mongo::BSONObjBuilder(64) << x ).obj()) | |
| | | | |
| /** Use BSON_ARRAY macro like BSON macro, but without keys | | /** Use BSON_ARRAY macro like BSON macro, but without keys | |
| | | | |
| BSONArray arr = BSON_ARRAY( "hello" << 1 << BSON( "foo" << BSON_ARRAY(
"bar" << "baz" << "qux" ) ) ); | | BSONArray arr = BSON_ARRAY( "hello" << 1 << BSON( "foo" << BSON_ARRAY(
"bar" << "baz" << "qux" ) ) ); | |
| | | | |
| */ | | */ | |
| #define BSON_ARRAY(x) (( mongo::BSONArrayBuilder() << x ).arr()) | | #define BSON_ARRAY(x) (( mongo::BSONArrayBuilder() << x ).arr()) | |
| | | | |
| /* Utility class to auto assign object IDs. | | /* Utility class to auto assign object IDs. | |
| Example: | | Example: | |
| cout << BSON( GENOID << "z" << 3 ); // { _id : ..., z : 3 } | | cout << BSON( GENOID << "z" << 3 ); // { _id : ..., z : 3 } | |
| */ | | */ | |
| extern struct IDLabeler { } GENOID; | | extern struct IDLabeler { } GENOID; | |
|
| BSONObjBuilder& operator<<(BSONObjBuilder& b, IDLabeler& id); | | | |
| | | | |
| /* Utility class to add a Date element with the current time | | /* Utility class to add a Date element with the current time | |
| Example: | | Example: | |
| cout << BSON( "created" << DATENOW ); // { created : "2009-10-09 1
1:41:42" } | | cout << BSON( "created" << DATENOW ); // { created : "2009-10-09 1
1:41:42" } | |
| */ | | */ | |
| extern struct DateNowLabeler { } DATENOW; | | extern struct DateNowLabeler { } DATENOW; | |
| | | | |
| // Utility class to implement GT, GTE, etc as described above. | | // Utility class to implement GT, GTE, etc as described above. | |
| class Labeler { | | class Labeler { | |
| public: | | public: | |
| | | | |
| skipping to change at line 1126 | | skipping to change at line 1126 | |
| private: | | private: | |
| const char * _fieldName; | | const char * _fieldName; | |
| BSONObjBuilder * _builder; | | BSONObjBuilder * _builder; | |
| | | | |
| bool haveSubobj() const { return _subobj.get() != 0; } | | bool haveSubobj() const { return _subobj.get() != 0; } | |
| BSONObjBuilder *subobj(); | | BSONObjBuilder *subobj(); | |
| auto_ptr< BSONObjBuilder > _subobj; | | 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 | | utility for creating a BSONObj | |
| */ | | */ | |
| class BSONObjBuilder : boost::noncopyable { | | class BSONObjBuilder : boost::noncopyable { | |
| public: | | public: | |
| /** @param initsize this is just a hint as to the final size of the
object */ | | /** @param initsize this is just a hint as to the final size of the
object */ | |
|
| BSONObjBuilder(int initsize=512) : b(buf_), buf_(initsize), offset_
( 0 ), s_( this ) { | | BSONObjBuilder(int initsize=512) : b(buf_), buf_(initsize), offset_
( 0 ), s_( this ) , _tracker(0) { | |
| b.skip(4); /*leave room for size field*/ | | b.skip(4); /*leave room for size field*/ | |
| } | | } | |
| | | | |
| /** @param baseBuilder construct a BSONObjBuilder using an existing
BufBuilder */ | | /** @param baseBuilder construct a BSONObjBuilder using an existing
BufBuilder */ | |
|
| BSONObjBuilder( BufBuilder &baseBuilder ) : b( baseBuilder ), buf_( | | BSONObjBuilder( BufBuilder &baseBuilder ) : b( baseBuilder ), buf_( | |
| 0 ), offset_( baseBuilder.len() ), s_( this ) { | | 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 ); | | b.skip( 4 ); | |
| } | | } | |
| | | | |
| /** add all the fields from the object specified to this object */ | | /** add all the fields from the object specified to this object */ | |
| BSONObjBuilder& appendElements(BSONObj x); | | BSONObjBuilder& appendElements(BSONObj x); | |
| | | | |
| /** append element to the object we are building */ | | /** append element to the object we are building */ | |
| void append( const BSONElement& e) { | | void append( const BSONElement& e) { | |
| assert( !e.eoo() ); // do not append eoo, that would corrupt us
. the builder auto appends when done() is called. | | 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()); | | b.append((void*) e.rawdata(), e.size()); | |
| | | | |
| skipping to change at line 1249 | | skipping to change at line 1292 | |
| void appendIntOrLL( const string& fieldName , long long n ){ | | void appendIntOrLL( const string& fieldName , long long n ){ | |
| long long x = n; | | long long x = n; | |
| if ( x < 0 ) | | if ( x < 0 ) | |
| x = x * -1; | | x = x * -1; | |
| if ( x < ( numeric_limits<int>::max() / 2 ) ) | | if ( x < ( numeric_limits<int>::max() / 2 ) ) | |
| append( fieldName.c_str() , (int)n ); | | append( fieldName.c_str() , (int)n ); | |
| else | | else | |
| append( fieldName.c_str() , n ); | | 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 ); | |
| | | append( fieldName.c_str() , l ); | |
| | | } | |
| | | | |
| /** Append a double element */ | | /** Append a double element */ | |
| BSONObjBuilder& append(const char *fieldName, double n) { | | BSONObjBuilder& append(const char *fieldName, double n) { | |
| b.append((char) NumberDouble); | | b.append((char) NumberDouble); | |
| b.append(fieldName); | | b.append(fieldName); | |
| b.append(n); | | b.append(n); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
| /** tries to append the data as a number | | /** tries to append the data as a number | |
| * @return true if the data was able to be converted to a number | | * @return true if the data was able to be converted to a number | |
| | | | |
| skipping to change at line 1507 | | skipping to change at line 1573 | |
| char *x = _done(); | | char *x = _done(); | |
| assert( x ); | | assert( x ); | |
| l = b.len(); | | l = b.len(); | |
| b.decouple(); | | b.decouple(); | |
| return x; | | return x; | |
| } | | } | |
| void decouple() { | | void decouple() { | |
| b.decouple(); // post done() call version. be sure jsobj fr
ees... | | b.decouple(); // post done() call version. be sure jsobj fr
ees... | |
| } | | } | |
| | | | |
|
| | | void appendKeys( const BSONObj& keyPattern , const BSONObj& values | |
| | | ); | |
| | | | |
| private: | | private: | |
| static const string numStrs[100]; // cache of 0 to 99 inclusive | | static const string numStrs[100]; // cache of 0 to 99 inclusive | |
| public: | | public: | |
| static string numStr( int i ) { | | static string numStr( int i ) { | |
| if (i>=0 && i<100) | | if (i>=0 && i<100) | |
| return numStrs[i]; | | return numStrs[i]; | |
| | | | |
| stringstream o; | | stringstream o; | |
| o << i; | | o << i; | |
| return o.str(); | | return o.str(); | |
| } | | } | |
| | | | |
| /** Stream oriented way to add field names and values. */ | | /** Stream oriented way to add field names and values. */ | |
| BSONObjBuilderValueStream &operator<<(const char * name ) { | | BSONObjBuilderValueStream &operator<<(const char * name ) { | |
| s_.endField( name ); | | s_.endField( name ); | |
| return s_; | | return s_; | |
| } | | } | |
| | | | |
|
| | | /** Stream oriented way to add field names and values. */ | |
| | | 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 ) | | // prevent implicit string conversions which would allow bad things
like BSON( BSON( "foo" << 1 ) << 2 ) | |
| struct ForceExplicitString { | | struct ForceExplicitString { | |
| ForceExplicitString( const string &str ) : str_( str ) {} | | ForceExplicitString( const string &str ) : str_( str ) {} | |
| string str_; | | string str_; | |
| }; | | }; | |
| | | | |
| /** Stream oriented way to add field names and values. */ | | /** Stream oriented way to add field names and values. */ | |
| BSONObjBuilderValueStream &operator<<( const ForceExplicitString& n
ame ) { | | BSONObjBuilderValueStream &operator<<( const ForceExplicitString& n
ame ) { | |
| return operator<<( name.str_.c_str() ); | | return operator<<( name.str_.c_str() ); | |
| } | | } | |
| | | | |
| skipping to change at line 1557 | | skipping to change at line 1633 | |
| void marshalArray( const char *fieldName, const BSONObj &arr ) { | | void marshalArray( const char *fieldName, const BSONObj &arr ) { | |
| b.append( (char) Array ); | | b.append( (char) Array ); | |
| b.append( fieldName ); | | b.append( fieldName ); | |
| b.append( (void *) arr.objdata(), arr.objsize() ); | | b.append( (void *) arr.objdata(), arr.objsize() ); | |
| } | | } | |
| | | | |
| char* _done() { | | char* _done() { | |
| s_.endField(); | | s_.endField(); | |
| b.append((char) EOO); | | b.append((char) EOO); | |
| char *data = b.buf() + offset_; | | char *data = b.buf() + offset_; | |
|
| *((int*)data) = b.len() - offset_; | | int size = b.len() - offset_; | |
| | | *((int*)data) = size; | |
| | | if ( _tracker ) | |
| | | _tracker->got( size ); | |
| return data; | | return data; | |
| } | | } | |
| | | | |
| BufBuilder &b; | | BufBuilder &b; | |
| BufBuilder buf_; | | BufBuilder buf_; | |
| int offset_; | | int offset_; | |
| BSONObjBuilderValueStream s_; | | BSONObjBuilderValueStream s_; | |
|
| | | BSONSizeTracker * _tracker; | |
| }; | | }; | |
| | | | |
| class BSONArrayBuilder : boost::noncopyable{ | | class BSONArrayBuilder : boost::noncopyable{ | |
| public: | | public: | |
| BSONArrayBuilder() :i(0), b() {} | | BSONArrayBuilder() :i(0), b() {} | |
| | | | |
| template <typename T> | | template <typename T> | |
| BSONArrayBuilder& append(const T& x){ | | BSONArrayBuilder& append(const T& x){ | |
| b.append(num().c_str(), x); | | b.append(num().c_str(), x); | |
| return *this; | | return *this; | |
| | | | |
| skipping to change at line 1695 | | skipping to change at line 1775 | |
| }; | | }; | |
| #pragma pack() | | #pragma pack() | |
| extern JSObj1 js1; | | extern JSObj1 js1; | |
| | | | |
| #ifdef _DEBUG | | #ifdef _DEBUG | |
| #define CHECK_OBJECT( o , msg ) massert( 10337 , (string)"object not valid
" + (msg) , (o).isValid() ) | | #define CHECK_OBJECT( o , msg ) massert( 10337 , (string)"object not valid
" + (msg) , (o).isValid() ) | |
| #else | | #else | |
| #define CHECK_OBJECT( o , msg ) | | #define CHECK_OBJECT( o , msg ) | |
| #endif | | #endif | |
| | | | |
|
| inline BSONObj BSONElement::embeddedObjectUserCheck() { | | inline BSONObj BSONElement::embeddedObjectUserCheck() const { | |
| uassert( 10065 , "invalid parameter: expected an object", isABSONO
bj() ); | | uassert( 10065 , "invalid parameter: expected an object", isABSONO
bj() ); | |
| return BSONObj(value()); | | return BSONObj(value()); | |
| } | | } | |
| | | | |
| inline BSONObj BSONElement::embeddedObject() const { | | inline BSONObj BSONElement::embeddedObject() const { | |
| assert( isABSONObj() ); | | assert( isABSONObj() ); | |
| return BSONObj(value()); | | return BSONObj(value()); | |
| } | | } | |
| | | | |
| inline BSONObj BSONElement::codeWScopeObject() const { | | inline BSONObj BSONElement::codeWScopeObject() const { | |
| | | | |
End of changes. 14 change blocks. |
| 10 lines changed or deleted | | 96 lines changed or added | |
|
| matcher.h | | matcher.h | |
| | | | |
| skipping to change at line 34 | | skipping to change at line 34 | |
| #include <pcrecpp.h> | | #include <pcrecpp.h> | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| class CoveredIndexMatcher; | | class CoveredIndexMatcher; | |
| class Matcher; | | class Matcher; | |
| | | | |
| class RegexMatcher { | | class RegexMatcher { | |
| public: | | public: | |
| const char *fieldName; | | const char *fieldName; | |
|
| | | const char *regex; | |
| | | const char *flags; | |
| | | string prefix; | |
| pcrecpp::RE *re; | | pcrecpp::RE *re; | |
|
| RegexMatcher() { | | bool isNot; | |
| re = 0; | | RegexMatcher() : re( 0 ), isNot() {} | |
| } | | | |
| ~RegexMatcher() { | | ~RegexMatcher() { | |
| delete re; | | delete re; | |
| } | | } | |
| }; | | }; | |
| | | | |
| struct element_lt | | struct element_lt | |
| { | | { | |
| bool operator()(const BSONElement& l, const BSONElement& r) const | | bool operator()(const BSONElement& l, const BSONElement& r) const | |
| { | | { | |
| int x = (int) l.canonicalType() - (int) r.canonicalType(); | | int x = (int) l.canonicalType() - (int) r.canonicalType(); | |
| | | | |
| skipping to change at line 60 | | skipping to change at line 62 | |
| return compareElementValues(l,r) < 0; | | return compareElementValues(l,r) < 0; | |
| } | | } | |
| }; | | }; | |
| | | | |
| class ElementMatcher { | | class ElementMatcher { | |
| public: | | public: | |
| | | | |
| ElementMatcher() { | | ElementMatcher() { | |
| } | | } | |
| | | | |
|
| ElementMatcher( BSONElement _e , int _op ); | | ElementMatcher( BSONElement _e , int _op, bool _isNot ); | |
| | | | |
| ElementMatcher( BSONElement _e , int _op , const BSONObj& array ) : | | | |
| toMatch( _e ) , compareOp( _op ) { | | | |
| | | | |
| myset.reset( new set<BSONElement,element_lt>() ); | | | |
| | | | |
|
| BSONObjIterator i( array ); | | ElementMatcher( BSONElement _e , int _op , const BSONObj& array, bo | |
| while ( i.more() ) { | | ol _isNot ); | |
| BSONElement ie = i.next(); | | | |
| myset->insert(ie); | | | |
| } | | | |
| } | | | |
| | | | |
| ~ElementMatcher() { } | | ~ElementMatcher() { } | |
| | | | |
| BSONElement toMatch; | | BSONElement toMatch; | |
| int compareOp; | | int compareOp; | |
|
| | | bool isNot; | |
| shared_ptr< set<BSONElement,element_lt> > myset; | | shared_ptr< set<BSONElement,element_lt> > myset; | |
| | | | |
| // these are for specific operators | | // these are for specific operators | |
| int mod; | | int mod; | |
| int modm; | | int modm; | |
| BSONType type; | | BSONType type; | |
| | | | |
| shared_ptr<Matcher> subMatcher; | | shared_ptr<Matcher> subMatcher; | |
|
| | | | |
| | | vector< shared_ptr<Matcher> > allMatchers; | |
| }; | | }; | |
| | | | |
| class Where; // used for $where javascript eval | | class Where; // used for $where javascript eval | |
| class DiskLoc; | | class DiskLoc; | |
| | | | |
| /* Match BSON objects against a query pattern. | | /* Match BSON objects against a query pattern. | |
| | | | |
| e.g. | | e.g. | |
| db.foo.find( { a : 3 } ); | | db.foo.find( { a : 3 } ); | |
| | | | |
| | | | |
| skipping to change at line 128 | | skipping to change at line 124 | |
| } | | } | |
| | | | |
| // 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()); | |
| | | | |
| ~Matcher(); | | ~Matcher(); | |
| | | | |
| bool matches(const BSONObj& j); | | bool matches(const BSONObj& j); | |
| | | | |
|
| bool keyMatch() const { return !all && !haveSize && !hasArray; } | | bool keyMatch() const { return !all && !haveSize && !hasArray && !h
aveNot; } | |
| | | | |
| bool atomic() const { return _atomic; } | | bool atomic() const { return _atomic; } | |
| | | | |
| private: | | private: | |
|
| void addBasic(const BSONElement &e, int c) { | | 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 ) ); | | basics.push_back( ElementMatcher( e , c, isNot ) ); | |
| } | | } | |
| | | | |
|
| | | 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 ); | |
| | | | |
| 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); | |
| | | | |
| 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 haveNot; | |
| | | | |
| /* $atomic - if true, a multi document operation (some removes, upd
ates) | | /* $atomic - if true, a multi document operation (some removes, upd
ates) | |
| should be done atomically. in that case, we do not yi
eld - | | should be done atomically. in that case, we do not yi
eld - | |
| 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; | |
| | | | |
| skipping to change at line 171 | | skipping to change at line 171 | |
| vector< shared_ptr< BSONObjBuilder > > _builders; | | vector< shared_ptr< BSONObjBuilder > > _builders; | |
| | | | |
| 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); | | bool matches(const BSONObj &key, const DiskLoc &recLoc , bool * loa
ded = 0 ); | |
| bool needRecord(){ return _needRecord; } | | bool needRecord(){ return _needRecord; } | |
| | | | |
| Matcher& docMatcher() { return _docMatcher; } | | Matcher& docMatcher() { return _docMatcher; } | |
| private: | | private: | |
| Matcher _keyMatcher; | | Matcher _keyMatcher; | |
| Matcher _docMatcher; | | Matcher _docMatcher; | |
| bool _needRecord; | | bool _needRecord; | |
| }; | | }; | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 12 change blocks. |
| 19 lines changed or deleted | | 21 lines changed or added | |
|
| query.h | | query.h | |
| | | | |
| skipping to change at line 74 | | skipping to change at line 74 | |
| Note that on Update, there is only one object, which is different | | Note that on Update, there is only one object, which is different | |
| from insert where you can pass a list of objects to insert in the db. | | from insert where you can pass a list of objects to insert in the db. | |
| Note that the update field layout is very similar layout to Query. | | Note that the update field layout is very similar layout to Query. | |
| */ | | */ | |
| | | | |
| // struct QueryOptions, QueryResult, QueryResultFlags in: | | // struct QueryOptions, QueryResult, QueryResultFlags in: | |
| #include "../client/dbclient.h" | | #include "../client/dbclient.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
|
| | | extern const int MaxBytesToReturnToClientAtOnce; | |
| | | | |
| // for an existing query (ie a ClientCursor), send back additional info
rmation. | | // for an existing query (ie a ClientCursor), send back additional info
rmation. | |
| QueryResult* getMore(const char *ns, int ntoreturn, long long cursorid
, CurOp& op); | | QueryResult* getMore(const char *ns, int ntoreturn, long long cursorid
, CurOp& op); | |
| | | | |
| struct UpdateResult { | | struct UpdateResult { | |
| bool existing; | | bool existing; | |
| bool mod; | | bool mod; | |
| long long num; | | long long num; | |
| | | | |
| UpdateResult( bool e, bool m, unsigned long long n ) | | UpdateResult( bool e, bool m, unsigned long long n ) | |
| : existing(e) , mod(m), num(n ){} | | : existing(e) , mod(m), num(n ){} | |
| | | | |
| skipping to change at line 113 | | skipping to change at line 115 | |
| */ | | */ | |
| 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 ); | |
| | | | |
| // 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). | |
| | | [ { a : ... } , { b : ... } ] -> { a : ..., b : ... } | |
| | | */ | |
| | | inline BSONObj transformOrderFromArrayFormat(BSONObj order) { | |
| | | /* note: this is slow, but that is ok as order will have very few p | |
| | | ieces */ | |
| | | BSONObjBuilder b; | |
| | | char p[2] = "0"; | |
| | | | |
| | | while ( 1 ) { | |
| | | BSONObj j = order.getObjectField(p); | |
| | | if ( j.isEmpty() ) | |
| | | break; | |
| | | BSONElement e = j.firstElement(); | |
| | | uassert( 10102 , "bad order array", !e.eoo()); | |
| | | uassert( 10103 , "bad order array [2]", e.isNumber()); | |
| | | b.append(e); | |
| | | (*p)++; | |
| | | uassert( 10104 , "too many ordering elements", *p <= '9'); | |
| | | } | |
| | | | |
| | | return b.obj(); | |
| | | } | |
| | | | |
| | | /** | |
| | | * this represents a total user query | |
| | | * includes fields from the query message, both possible query levels | |
| | | * parses everything up front | |
| | | */ | |
| | | class ParsedQuery { | |
| | | public: | |
| | | ParsedQuery( QueryMessage& qm ) | |
| | | : _ns( qm.ns ) , _ntoskip( qm.ntoskip ) , _ntoreturn( qm.ntoret | |
| | | urn ) , _options( qm.queryOptions ){ | |
| | | init( qm.query ); | |
| | | initFields( qm.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 ){ | |
| | | init( query ); | |
| | | initFields( fields ); | |
| | | } | |
| | | | |
| | | ~ParsedQuery(){} | |
| | | | |
| | | const char * ns() const { return _ns; } | |
| | | | |
| | | const BSONObj& getFilter() const { return _filter; } | |
| | | FieldMatcher* getFields() const { return _fields.get(); } | |
| | | shared_ptr<FieldMatcher> getFieldPtr() const { return _fields; } | |
| | | | |
| | | int getSkip() const { return _ntoskip; } | |
| | | int getNumToReturn() const { return _ntoreturn; } | |
| | | bool wantMore() const { return _wantMore; } | |
| | | int getOptions() const { return _options; } | |
| | | bool hasOption( int x ) const { return x & _options; } | |
| | | | |
| | | bool isExplain() const { return _explain; } | |
| | | bool isSnapshot() const { return _snapshot; } | |
| | | bool returnKey() const { return _returnKey; } | |
| | | | |
| | | const BSONObj& getMin() const { return _min; } | |
| | | const BSONObj& getMax() const { return _max; } | |
| | | const BSONObj& getOrder() const { return _order; } | |
| | | const BSONElement& getHint() const { return _hint; } | |
| | | | |
| | | bool couldBeCommand() const { | |
| | | /* we assume you are using findOne() for running a cmd... */ | |
| | | return _ntoreturn == 1 && strstr( _ns , ".$cmd" ); | |
| | | } | |
| | | | |
| | | bool hasIndexSpecifier() const { | |
| | | return ! _hint.eoo() || ! _min.isEmpty() || ! _max.isEmpty(); | |
| | | } | |
| | | | |
| | | /* if ntoreturn is zero, we return up to 101 objects. on the subse | |
| | | quent getmore, there | |
| | | is only a size limit. The idea is that on a find() where one do | |
| | | esn't use much results, | |
| | | we don't return much, but once getmore kicks in, we start pushin | |
| | | g significant quantities. | |
| | | | |
| | | The n limit (vs. size) is important when someone fetches only on | |
| | | e small field from big | |
| | | objects, which causes massive scanning server-side. | |
| | | */ | |
| | | bool enoughForFirstBatch( int n , int len ) const { | |
| | | if ( _ntoreturn == 0 ) | |
| | | return ( len > 1024 * 1024 ) || n >= 101; | |
| | | return n >= _ntoreturn || len > MaxBytesToReturnToClientAtOnce; | |
| | | } | |
| | | | |
| | | private: | |
| | | void init( const BSONObj& q ){ | |
| | | _reset(); | |
| | | uassert( 10105 , "bad skip value in query", _ntoskip >= 0); | |
| | | | |
| | | if ( _ntoreturn < 0 ){ | |
| | | /* _ntoreturn greater than zero is simply a hint on how man | |
| | | y objects to send back per | |
| | | "cursor batch". | |
| | | A negative number indicates a hard limit. | |
| | | */ | |
| | | _wantMore = false; | |
| | | _ntoreturn = -_ntoreturn; | |
| | | } | |
| | | | |
| | | BSONElement e = q["query"]; | |
| | | if ( ! e.isABSONObj() ) | |
| | | e = q["$query"]; | |
| | | | |
| | | if ( e.isABSONObj() ){ | |
| | | _filter = e.embeddedObject(); | |
| | | _initTop( q ); | |
| | | } | |
| | | else { | |
| | | _filter = q; | |
| | | } | |
| | | } | |
| | | | |
| | | void _reset(){ | |
| | | _wantMore = true; | |
| | | _explain = false; | |
| | | _snapshot = false; | |
| | | _returnKey = false; | |
| | | } | |
| | | | |
| | | void _initTop( const BSONObj& top ){ | |
| | | BSONObjIterator i( top ); | |
| | | while ( i.more() ){ | |
| | | BSONElement e = i.next(); | |
| | | const char * name = e.fieldName(); | |
| | | | |
| | | if ( strcmp( "$orderby" , name ) == 0 || | |
| | | strcmp( "orderby" , name ) == 0 ){ | |
| | | if ( e.type() == Object ) | |
| | | _order = e.embeddedObject(); | |
| | | else if ( e.type() == Array ) | |
| | | _order = transformOrderFromArrayFormat( _order ); | |
| | | else | |
| | | assert( 0 ); | |
| | | } | |
| | | else if ( strcmp( "$explain" , name ) == 0 ) | |
| | | _explain = e.trueValue(); | |
| | | else if ( strcmp( "$snapshot" , name ) == 0 ) | |
| | | _snapshot = e.trueValue(); | |
| | | else if ( strcmp( "$min" , name ) == 0 ) | |
| | | _min = e.embeddedObject(); | |
| | | else if ( strcmp( "$max" , name ) == 0 ) | |
| | | _max = e.embeddedObject(); | |
| | | else if ( strcmp( "$hint" , name ) == 0 ) | |
| | | _hint = e; | |
| | | else if ( strcmp( "$returnKey" , name ) == 0 ) | |
| | | _returnKey = e.trueValue(); | |
| | | | |
| | | } | |
| | | | |
| | | if ( _snapshot ){ | |
| | | uassert( 12001 , "E12001 can't sort with $snapshot", _order | |
| | | .isEmpty() ); | |
| | | uassert( 12002 , "E12002 can't use hint with $snapshot", _h | |
| | | int.eoo() ); | |
| | | } | |
| | | | |
| | | } | |
| | | | |
| | | void initFields( const BSONObj& fields ){ | |
| | | if ( fields.isEmpty() ) | |
| | | return; | |
| | | _fields.reset( new FieldMatcher() ); | |
| | | _fields->add( fields ); | |
| | | } | |
| | | | |
| | | ParsedQuery( const ParsedQuery& other ){ | |
| | | assert(0); | |
| | | } | |
| | | | |
| | | const char* _ns; | |
| | | int _ntoskip; | |
| | | int _ntoreturn; | |
| | | int _options; | |
| | | | |
| | | BSONObj _filter; | |
| | | shared_ptr< FieldMatcher > _fields; | |
| | | | |
| | | bool _wantMore; | |
| | | | |
| | | bool _explain; | |
| | | bool _snapshot; | |
| | | bool _returnKey; | |
| | | BSONObj _min; | |
| | | BSONObj _max; | |
| | | BSONElement _hint; | |
| | | BSONObj _order; | |
| | | }; | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
| #include "clientcursor.h" | | #include "clientcursor.h" | |
| | | | |
End of changes. 2 change blocks. |
| 0 lines changed or deleted | | 201 lines changed or added | |
|
| queryoptimizer.h | | queryoptimizer.h | |
| | | | |
| skipping to change at line 35 | | skipping to change at line 35 | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| class IndexDetails; | | class IndexDetails; | |
| class QueryPlan : boost::noncopyable { | | class QueryPlan : boost::noncopyable { | |
| public: | | public: | |
| QueryPlan(NamespaceDetails *_d, | | QueryPlan(NamespaceDetails *_d, | |
| int _idxNo, // -1 = no index | | int _idxNo, // -1 = no index | |
| const FieldRangeSet &fbs, | | const FieldRangeSet &fbs, | |
| const BSONObj &order, | | const BSONObj &order, | |
| const BSONObj &startKey = BSONObj(), | | const BSONObj &startKey = BSONObj(), | |
|
| const BSONObj &endKey = BSONObj() ); | | const BSONObj &endKey = BSONObj() , | |
| | | string special="" ); | |
| | | | |
| /* If true, no other index can do better. */ | | /* If true, no other index can do better. */ | |
| bool optimal() const { return optimal_; } | | bool optimal() const { return optimal_; } | |
| /* ScanAndOrder processing will be required if true */ | | /* ScanAndOrder processing will be required if true */ | |
| bool scanAndOrderRequired() const { return scanAndOrderRequired_; } | | bool scanAndOrderRequired() const { return scanAndOrderRequired_; } | |
| /* When true, the index we are using has keys such that it can comp
letely resolve the | | /* When true, the index we are using has keys such that it can comp
letely resolve the | |
| query expression to match by itself without ever checking the main
object. | | query expression to match by itself without ever checking the main
object. | |
| */ | | */ | |
| bool exactKeyMatch() const { return exactKeyMatch_; } | | bool exactKeyMatch() const { return exactKeyMatch_; } | |
| /* If true, the startKey and endKey are unhelpful and the index ord
er doesn't match the | | /* If true, the startKey and endKey are unhelpful and the index ord
er doesn't match the | |
| requested sort order */ | | requested sort order */ | |
| bool unhelpful() const { return unhelpful_; } | | bool unhelpful() const { return unhelpful_; } | |
| int direction() const { return direction_; } | | int direction() const { return direction_; } | |
|
| auto_ptr< Cursor > newCursor( const DiskLoc &startLoc = DiskLoc() )
const; | | auto_ptr< Cursor > newCursor( const DiskLoc &startLoc = DiskLoc() ,
int numWanted=0 ) const; | |
| auto_ptr< Cursor > newReverseCursor() const; | | auto_ptr< Cursor > newReverseCursor() const; | |
| BSONObj indexKey() const; | | BSONObj indexKey() const; | |
| const char *ns() const { return fbs_.ns(); } | | const char *ns() const { return fbs_.ns(); } | |
| NamespaceDetails *nsd() const { return d; } | | NamespaceDetails *nsd() const { return d; } | |
| BSONObj query() const { return fbs_.query(); } | | BSONObj query() const { return fbs_.query(); } | |
| BSONObj simplifiedQuery( const BSONObj& fields = BSONObj() ) const
{ return fbs_.simplifiedQuery( fields ); } | | BSONObj simplifiedQuery( const BSONObj& fields = BSONObj() ) const
{ return fbs_.simplifiedQuery( fields ); } | |
| const FieldRange &range( const char *fieldName ) const { return fbs
_.range( fieldName ); } | | const FieldRange &range( const char *fieldName ) const { return fbs
_.range( fieldName ); } | |
| void registerSelf( long long nScanned ) const; | | void registerSelf( long long nScanned ) const; | |
| // just for testing | | // just for testing | |
| BoundList indexBounds() const { return indexBounds_; } | | BoundList indexBounds() const { return indexBounds_; } | |
| | | | |
| skipping to change at line 73 | | skipping to change at line 74 | |
| const FieldRangeSet &fbs_; | | const FieldRangeSet &fbs_; | |
| const BSONObj &order_; | | const BSONObj &order_; | |
| const IndexDetails *index_; | | const IndexDetails *index_; | |
| bool optimal_; | | bool optimal_; | |
| bool scanAndOrderRequired_; | | bool scanAndOrderRequired_; | |
| bool exactKeyMatch_; | | bool exactKeyMatch_; | |
| int direction_; | | int direction_; | |
| BoundList indexBounds_; | | BoundList indexBounds_; | |
| bool endKeyInclusive_; | | bool endKeyInclusive_; | |
| bool unhelpful_; | | bool unhelpful_; | |
|
| | | string _special; | |
| }; | | }; | |
| | | | |
| // Inherit from this interface to implement a new query operation. | | // Inherit from this interface to implement a new query operation. | |
| // The query optimizer will clone the QueryOp that is provided, giving | | // The query optimizer will clone the QueryOp that is provided, giving | |
| // each clone its own query plan. | | // each clone its own query plan. | |
| class QueryOp { | | class QueryOp { | |
| public: | | public: | |
| QueryOp() : complete_(), qp_(), error_() {} | | QueryOp() : complete_(), qp_(), error_() {} | |
| virtual ~QueryOp() {} | | virtual ~QueryOp() {} | |
|
| | | | |
| | | /** this gets called after a query plan is set? ERH 2/16/10 */ | |
| virtual void init() = 0; | | virtual void init() = 0; | |
| virtual void next() = 0; | | virtual void next() = 0; | |
| virtual bool mayRecordPlan() const = 0; | | virtual bool mayRecordPlan() const = 0; | |
|
| // Return a copy of the inheriting class, which will be run with it | | | |
| s own | | /** @return a copy of the inheriting class, which will be run with | |
| // query plan. | | its own | |
| | | query plan. | |
| | | */ | |
| virtual QueryOp *clone() const = 0; | | virtual QueryOp *clone() const = 0; | |
| bool complete() const { return complete_; } | | bool complete() const { return complete_; } | |
| bool error() const { return error_; } | | bool error() const { return error_; } | |
| string exceptionMessage() const { return exceptionMessage_; } | | string exceptionMessage() const { return exceptionMessage_; } | |
| const QueryPlan &qp() const { return *qp_; } | | const QueryPlan &qp() const { return *qp_; } | |
| // To be called by QueryPlanSet::Runner only. | | // To be called by QueryPlanSet::Runner only. | |
| void setQueryPlan( const QueryPlan *qp ) { qp_ = qp; } | | void setQueryPlan( const QueryPlan *qp ) { qp_ = qp; } | |
| void setExceptionMessage( const string &exceptionMessage ) { | | void setExceptionMessage( const string &exceptionMessage ) { | |
| error_ = true; | | error_ = true; | |
| exceptionMessage_ = exceptionMessage; | | exceptionMessage_ = exceptionMessage; | |
| | | | |
End of changes. 5 change blocks. |
| 5 lines changed or deleted | | 11 lines changed or added | |
|
| queryutil.h | | queryutil.h | |
| | | | |
| skipping to change at line 51 | | skipping to change at line 51 | |
| bool valid() const { | | bool valid() const { | |
| int cmp = lower_.bound_.woCompare( upper_.bound_, false ); | | int cmp = lower_.bound_.woCompare( upper_.bound_, false ); | |
| return ( cmp < 0 || ( cmp == 0 && lower_.inclusive_ && upper_.i
nclusive_ ) ); | | return ( cmp < 0 || ( cmp == 0 && lower_.inclusive_ && upper_.i
nclusive_ ) ); | |
| } | | } | |
| }; | | }; | |
| | | | |
| // range of a field's value that may be determined from query -- used t
o | | // range of a field's value that may be determined from query -- used t
o | |
| // determine index limits | | // determine index limits | |
| class FieldRange { | | class FieldRange { | |
| public: | | public: | |
|
| FieldRange( const BSONElement &e = BSONObj().firstElement() , bool
optimize=true ); | | FieldRange( const BSONElement &e = BSONObj().firstElement() , bool
isNot=false , bool optimize=true ); | |
| const FieldRange &operator&=( const FieldRange &other ); | | const FieldRange &operator&=( const FieldRange &other ); | |
| BSONElement min() const { assert( !empty() ); return intervals_[ 0
].lower_.bound_; } | | BSONElement min() const { assert( !empty() ); return intervals_[ 0
].lower_.bound_; } | |
| BSONElement max() const { assert( !empty() ); return intervals_[ in
tervals_.size() - 1 ].upper_.bound_; } | | BSONElement max() const { assert( !empty() ); return intervals_[ in
tervals_.size() - 1 ].upper_.bound_; } | |
| bool minInclusive() const { assert( !empty() ); return intervals_[
0 ].lower_.inclusive_; } | | bool minInclusive() const { assert( !empty() ); return intervals_[
0 ].lower_.inclusive_; } | |
| bool maxInclusive() const { assert( !empty() ); return intervals_[
intervals_.size() - 1 ].upper_.inclusive_; } | | bool maxInclusive() const { assert( !empty() ); return intervals_[
intervals_.size() - 1 ].upper_.inclusive_; } | |
| bool equality() const { | | bool equality() const { | |
| return | | return | |
| !empty() && | | !empty() && | |
| min().woCompare( max(), false ) == 0 && | | min().woCompare( max(), false ) == 0 && | |
| maxInclusive() && | | maxInclusive() && | |
| minInclusive(); | | minInclusive(); | |
| } | | } | |
| bool nontrivial() const { | | bool nontrivial() const { | |
| return | | return | |
| ! empty() && | | ! empty() && | |
| ( minKey.firstElement().woCompare( min(), false ) != 0 || | | ( minKey.firstElement().woCompare( min(), false ) != 0 || | |
| maxKey.firstElement().woCompare( max(), false ) != 0 ); | | maxKey.firstElement().woCompare( max(), false ) != 0 ); | |
| } | | } | |
| bool empty() const { return intervals_.empty(); } | | bool empty() const { return intervals_.empty(); } | |
| const vector< FieldInterval > &intervals() const { return in
tervals_; } | | const vector< FieldInterval > &intervals() const { return in
tervals_; } | |
|
| | | string getSpecial() const { return _special; } | |
| | | | |
| private: | | private: | |
| BSONObj addObj( const BSONObj &o ); | | BSONObj addObj( const BSONObj &o ); | |
|
| string simpleRegexEnd( string regex ); | | | |
| vector< FieldInterval > intervals_; | | vector< FieldInterval > intervals_; | |
| vector< BSONObj > objData_; | | vector< BSONObj > objData_; | |
|
| | | string _special; | |
| }; | | }; | |
| | | | |
| // implements query pattern matching, used to determine if a query is | | // implements query pattern matching, used to determine if a query is | |
| // similar to an earlier query and should use the same plan | | // similar to an earlier query and should use the same plan | |
| class QueryPattern { | | class QueryPattern { | |
| public: | | public: | |
| friend class FieldRangeSet; | | friend class FieldRangeSet; | |
| enum Type { | | enum Type { | |
| Equality, | | Equality, | |
| LowerBound, | | LowerBound, | |
| | | | |
| skipping to change at line 174 | | skipping to change at line 176 | |
| // if fields is specified, order fields of returned object to match
those of 'fields' | | // if fields is specified, order fields of returned object to match
those of 'fields' | |
| BSONObj simplifiedQuery( const BSONObj &fields = BSONObj() ) const; | | BSONObj simplifiedQuery( const BSONObj &fields = BSONObj() ) const; | |
| bool matchPossible() const { | | bool matchPossible() const { | |
| for( map< string, FieldRange >::const_iterator i = ranges_.begi
n(); i != ranges_.end(); ++i ) | | for( map< string, FieldRange >::const_iterator i = ranges_.begi
n(); i != ranges_.end(); ++i ) | |
| if ( i->second.empty() ) | | if ( i->second.empty() ) | |
| return false; | | return false; | |
| return true; | | return true; | |
| } | | } | |
| QueryPattern pattern( const BSONObj &sort = BSONObj() ) const; | | QueryPattern pattern( const BSONObj &sort = BSONObj() ) const; | |
| BoundList indexBounds( const BSONObj &keyPattern, int direction ) c
onst; | | BoundList indexBounds( const BSONObj &keyPattern, int direction ) c
onst; | |
|
| | | string getSpecial() const; | |
| private: | | private: | |
|
| | | void processOpElement( const char *fieldName, const BSONElement &f,
bool isNot, bool optimize ); | |
| static FieldRange *trivialRange_; | | static FieldRange *trivialRange_; | |
| static FieldRange &trivialRange(); | | static FieldRange &trivialRange(); | |
| mutable map< string, FieldRange > ranges_; | | mutable map< string, FieldRange > ranges_; | |
| const char *ns_; | | const char *ns_; | |
| BSONObj query_; | | BSONObj query_; | |
| }; | | }; | |
| | | | |
| /** | | /** | |
| used for doing field limiting | | used for doing field limiting | |
| */ | | */ | |
| class FieldMatcher { | | class FieldMatcher { | |
| public: | | public: | |
| | | | |
|
| FieldMatcher(bool include=false) : errmsg(NULL), include_(include)
{} | | FieldMatcher(bool include=false) : _include(include){} | |
| | | | |
| 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; | |
|
| | | | |
| const char* errmsg; //null if FieldMatcher is valid | | | |
| private: | | private: | |
| | | | |
| void add( const string& field, bool include ); | | void add( const string& field, bool include ); | |
| 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 | |
| //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; | |
| }; | | }; | |
| | | | |
|
| | | /** returns a string that when used as a matcher, would match a super s | |
| | | et of regex() | |
| | | returns "" for complex regular expressions | |
| | | 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 | |
| | | */ | |
| | | string simpleRegex(const char* regex, const char* flags, bool* purePref | |
| | | ix=NULL); | |
| | | | |
| | | /** returns the upper bound of a query that matches prefix */ | |
| | | string simpleRegexEnd( string prefix ); | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 11 change blocks. |
| 8 lines changed or deleted | | 25 lines changed or added | |
|
| repl.h | | repl.h | |
| | | | |
| skipping to change at line 61 | | skipping to change at line 61 | |
| public: | | public: | |
| SlaveTypes slave; | | SlaveTypes slave; | |
| | | | |
| /* true means we are master and doing replication. if we are not w
riting to oplog (no --master or repl pairing), | | /* true means we are master and doing replication. if we are not w
riting to oplog (no --master or repl pairing), | |
| this won't be true. | | this won't be true. | |
| */ | | */ | |
| bool master; | | bool master; | |
| | | | |
| int opIdMem; | | int opIdMem; | |
| | | | |
|
| | | bool fastsync; | |
| | | | |
| bool autoresync; | | bool autoresync; | |
| | | | |
|
| | | int slavedelay; | |
| | | | |
| ReplSettings() | | ReplSettings() | |
|
| : slave(NotSlave) , master(false) , opIdMem(100000000) , autore
sync(false) { | | : slave(NotSlave) , master(false) , opIdMem(100000000) , fastsy
nc() , autoresync(false), slavedelay() { | |
| } | | } | |
| | | | |
| }; | | }; | |
| | | | |
| extern ReplSettings replSettings; | | extern ReplSettings replSettings; | |
| | | | |
| bool cloneFrom(const char *masterHost, string& errmsg, const string& fr
omdb, bool logForReplication, | | bool cloneFrom(const char *masterHost, string& errmsg, const string& fr
omdb, bool logForReplication, | |
| bool slaveOk, bool useReplAuth, bool snap
shot); | | bool slaveOk, bool useReplAuth, bool snap
shot); | |
| | | | |
| /* A replication exception */ | | /* A replication exception */ | |
| | | | |
| skipping to change at line 131 | | skipping to change at line 135 | |
| void syncToTailOfRemoteLog(); | | void syncToTailOfRemoteLog(); | |
| // call with the db mutex | | // call with the db mutex | |
| OpTime nextLastSavedLocalTs() const; | | OpTime nextLastSavedLocalTs() const; | |
| void setLastSavedLocalTs( const OpTime &nextLocalTs ); | | void setLastSavedLocalTs( const OpTime &nextLocalTs ); | |
| // call without the db mutex | | // call without the db mutex | |
| void resetSlave(); | | void resetSlave(); | |
| // call with the db mutex | | // call with the db mutex | |
| // returns false if the slave has been reset | | // returns false if the slave has been reset | |
| bool updateSetsWithLocalOps( OpTime &localLogTail, bool mayUnlock )
; | | bool updateSetsWithLocalOps( OpTime &localLogTail, bool mayUnlock )
; | |
| string ns() const { return string( "local.oplog.$" ) + sourceName()
; } | | string ns() const { return string( "local.oplog.$" ) + sourceName()
; } | |
|
| | | unsigned _sleepAdviceTime; | |
| | | | |
| public: | | public: | |
| static void applyOperation(const BSONObj& op); | | static void applyOperation(const BSONObj& op); | |
| bool replacing; // in "replace mode" -- see CmdReplacePeer | | bool replacing; // in "replace mode" -- see CmdReplacePeer | |
| bool paired; // --pair in use | | bool paired; // --pair in use | |
| string hostName; // ip addr or hostname plus optionally, ":<port
>" | | string hostName; // ip addr or hostname plus optionally, ":<port
>" | |
| string _sourceName; // a logical source name. | | string _sourceName; // a logical source name. | |
| string sourceName() const { | | string sourceName() const { | |
| return _sourceName.empty() ? "main" : _sourceName; | | return _sourceName.empty() ? "main" : _sourceName; | |
| } | | } | |
| | | | |
| skipping to change at line 176 | | skipping to change at line 181 | |
| // make a jsobj from our member fields of the form | | // make a jsobj from our member fields of the form | |
| // { host: ..., source: ..., syncedTo: ... } | | // { host: ..., source: ..., syncedTo: ... } | |
| BSONObj jsobj(); | | BSONObj jsobj(); | |
| | | | |
| bool operator==(const ReplSource&r) const { | | bool operator==(const ReplSource&r) const { | |
| return hostName == r.hostName && sourceName() == r.sourceName()
; | | return hostName == r.hostName && sourceName() == r.sourceName()
; | |
| } | | } | |
| operator string() const { return sourceName() + "@" + hostName; } | | operator string() const { return sourceName() + "@" + hostName; } | |
| | | | |
| bool haveMoreDbsToSync() const { return !addDbNextPass.empty(); } | | bool haveMoreDbsToSync() const { return !addDbNextPass.empty(); } | |
|
| | | int sleepAdvice() const { | |
| | | if ( !_sleepAdviceTime ) | |
| | | return 0; | |
| | | int wait = _sleepAdviceTime - unsigned( time( 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) | | /* Write operation to the log (local.oplog.$main) | |
| "i" insert | | "i" insert | |
| "u" update | | "u" update | |
| "d" delete | | "d" delete | |
| | | | |
End of changes. 5 change blocks. |
| 1 lines changed or deleted | | 12 lines changed or added | |
|
| update.h | | update.h | |
| | | | |
| skipping to change at line 135 | | skipping to change at line 135 | |
| void _checkForAppending( const BSONElement& e ) const { | | void _checkForAppending( const BSONElement& e ) const { | |
| if ( e.type() == Object ){ | | if ( e.type() == Object ){ | |
| // this is a tiny bit slow, but rare and important | | // this is a tiny bit slow, but rare and important | |
| // only when setting something TO an object, not setting so
mething in an object | | // only when setting something TO an object, not setting so
mething in an object | |
| // and it checks for { $set : { x : { 'a.b' : 1 } } } | | // and it checks for { $set : { x : { 'a.b' : 1 } } } | |
| // which is feel has been common | | // which is feel has been common | |
| uassert( 12527 , "not okForStorage" , e.embeddedObject().ok
ForStorage() ); | | uassert( 12527 , "not okForStorage" , e.embeddedObject().ok
ForStorage() ); | |
| } | | } | |
| } | | } | |
| | | | |
|
| | | bool isEach() const { | |
| | | if ( elt.type() != Object ) | |
| | | return false; | |
| | | BSONElement e = elt.embeddedObject().firstElement(); | |
| | | if ( e.type() != Array ) | |
| | | return false; | |
| | | return strcmp( e.fieldName() , "$each" ) == 0; | |
| | | } | |
| | | | |
| | | BSONObj getEach() const { | |
| | | return elt.embeddedObjectUserCheck().firstElement().embeddedObj | |
| | | ectUserCheck(); | |
| | | } | |
| | | | |
| | | void parseEach( BSONElementSet& s ) const { | |
| | | BSONObjIterator i(getEach()); | |
| | | while ( i.more() ){ | |
| | | s.insert( i.next() ); | |
| | | } | |
| | | } | |
| }; | | }; | |
| | | | |
| /** | | /** | |
| * stores a set of Mods | | * stores a set of Mods | |
| * once created, should never be changed | | * once created, should never be changed | |
| */ | | */ | |
| class ModSet : boost::noncopyable { | | class ModSet : boost::noncopyable { | |
| typedef map<string,Mod> ModHolder; | | typedef map<string,Mod> ModHolder; | |
| ModHolder _mods; | | ModHolder _mods; | |
| int _isIndexed; | | int _isIndexed; | |
| | | | |
| skipping to change at line 407 | | skipping to change at line 426 | |
| void createNewFromMods( const string& root , BSONObjBuilder& b , co
nst BSONObj &obj ); | | void createNewFromMods( const string& root , BSONObjBuilder& b , co
nst BSONObj &obj ); | |
| | | | |
| void _appendNewFromMods( const string& root , ModState& m , BSONObj
Builder& b , set<string>& onedownseen ); | | void _appendNewFromMods( const string& root , ModState& m , BSONObj
Builder& b , set<string>& onedownseen ); | |
| | | | |
| void appendNewFromMod( ModState& ms , BSONObjBuilder& b ){ | | void appendNewFromMod( ModState& ms , BSONObjBuilder& b ){ | |
| //const Mod& m = *(ms.m); // HACK | | //const Mod& m = *(ms.m); // HACK | |
| Mod& m = *((Mod*)(ms.m)); // HACK | | Mod& m = *((Mod*)(ms.m)); // HACK | |
| | | | |
| switch ( m.op ){ | | switch ( m.op ){ | |
| | | | |
|
| case Mod::PUSH: { | | case Mod::PUSH: | |
| BSONObjBuilder arr( b.subarrayStart( m.shortFieldName ) ); | | case Mod::ADDTOSET: { | |
| arr.appendAs( m.elt, "0" ); | | if ( m.isEach() ){ | |
| arr.done(); | | b.appendArray( m.shortFieldName , m.getEach() ); | |
| | | } | |
| | | else { | |
| | | BSONObjBuilder arr( b.subarrayStart( m.shortFieldName ) | |
| | | ); | |
| | | arr.appendAs( m.elt, "0" ); | |
| | | arr.done(); | |
| | | } | |
| break; | | break; | |
| } | | } | |
| | | | |
| case Mod::PUSH_ALL: { | | case Mod::PUSH_ALL: { | |
| b.appendAs( m.elt, m.shortFieldName ); | | b.appendAs( m.elt, m.shortFieldName ); | |
| break; | | break; | |
| } | | } | |
| | | | |
| case Mod::UNSET: | | case Mod::UNSET: | |
| case Mod::PULL: | | case Mod::PULL: | |
| | | | |
End of changes. 2 change blocks. |
| 4 lines changed or deleted | | 31 lines changed or added | |
|