diff options
Diffstat (limited to 'client/dbclient.h')
-rw-r--r-- | client/dbclient.h | 798 |
1 files changed, 399 insertions, 399 deletions
diff --git a/client/dbclient.h b/client/dbclient.h index 6135a595bc8..dd3b4ac5716 100644 --- a/client/dbclient.h +++ b/client/dbclient.h @@ -24,424 +24,424 @@ namespace mongo { -/* the query field 'options' can have these bits set: */ -enum QueryOptions { - /* Tailable means cursor is not closed when the last data is retrieved. rather, the cursor marks - the final object's position. you can resume using the cursor later, from where it was located, - if more data were received. Set on dbQuery and dbGetMore. - - like any "latent cursor", the cursor may become invalid at some point -- for example if that - final object it references were deleted. Thus, you should be prepared to requery if you get back - ResultFlag_CursorNotFound. - */ - Option_CursorTailable = 2, - - /* allow query of replica slave. normally these return an error except for namespace "local". - */ - Option_SlaveOk = 4, - - Option_ALLMASK = 6 -}; + /* the query field 'options' can have these bits set: */ + enum QueryOptions { + /* Tailable means cursor is not closed when the last data is retrieved. rather, the cursor marks + the final object's position. you can resume using the cursor later, from where it was located, + if more data were received. Set on dbQuery and dbGetMore. + + like any "latent cursor", the cursor may become invalid at some point -- for example if that + final object it references were deleted. Thus, you should be prepared to requery if you get back + ResultFlag_CursorNotFound. + */ + Option_CursorTailable = 2, + + /* allow query of replica slave. normally these return an error except for namespace "local". + */ + Option_SlaveOk = 4, + + Option_ALLMASK = 6 + }; -class BSONObj; + class BSONObj; -/* db response format + /* db response format - Query or GetMore: // see struct QueryResult - int resultFlags; - int64 cursorID; - int startingFrom; - int nReturned; - list of marshalled JSObjects; -*/ + Query or GetMore: // see struct QueryResult + int resultFlags; + int64 cursorID; + int startingFrom; + int nReturned; + list of marshalled JSObjects; + */ #pragma pack(push,1) -struct QueryResult : public MsgData { - enum { - ResultFlag_CursorNotFound = 1, /* returned, with zero results, when getMore is called but the cursor id is not valid at the server. */ - ResultFlag_ErrSet = 2 /* { $err : ... } is being returned */ + struct QueryResult : public MsgData { + enum { + ResultFlag_CursorNotFound = 1, /* returned, with zero results, when getMore is called but the cursor id is not valid at the server. */ + ResultFlag_ErrSet = 2 /* { $err : ... } is being returned */ + }; + + long long cursorId; + int startingFrom; + int nReturned; + const char *data() { + return (char *) (((int *)&nReturned)+1); + } + int& resultFlags() { + return dataAsInt(); + } }; - - long long cursorId; - int startingFrom; - int nReturned; - const char *data() { - return (char *) (((int *)&nReturned)+1); - } - int& resultFlags() { - return dataAsInt(); - } -}; #pragma pack(pop) -class DBConnector { -public: - virtual bool call( Message &toSend, Message &response, bool assertOk=true ) = 0; - virtual void say( Message &toSend ) = 0; - virtual void sayPiggyBack( Message &toSend ) = 0; - virtual void checkResponse( const char *data, int nReturned ) {} -}; - -class DBClientCursor : boost::noncopyable { -public: - bool more(); // if true, safe to call next() - - /* returns next object in the result cursor. - on an error at the remote server, you will get back: - { $err: <string> } - if you do not want to handle that yourself, call nextSafe(). - */ - BSONObj next(); - - BSONObj nextSafe() { - BSONObj o = next(); - BSONElement e = o.firstElement(); - assert( strcmp(e.fieldName(), "$err") != 0 ); - return o; - } - - /* cursor no longer valid -- use with tailable cursors. - note you should only rely on this once more() returns false; - 'dead' may be preset yet some data still queued and locally - available from the dbclientcursor. - */ - bool isDead() const { - return cursorId == 0; - } - - bool tailable() const { - return (opts & Option_CursorTailable) != 0; - } - - bool init(); - - DBClientCursor( DBConnector *_connector, const char * _ns, BSONObj _query, int _nToReturn, - int _nToSkip, BSONObj *_fieldsToReturn, int queryOptions ) : - connector(_connector), - ns(_ns), - query(_query), - nToReturn(_nToReturn), - nToSkip(_nToSkip), - fieldsToReturn(_fieldsToReturn), - opts(queryOptions), - m(new Message()) { - cursorId = 0; - } - - virtual ~DBClientCursor(); - -private: - DBConnector *connector; - string ns; - BSONObj query; - int nToReturn; - int nToSkip; - BSONObj *fieldsToReturn; - int opts; - auto_ptr<Message> m; - - long long cursorId; - int nReturned; - int pos; - const char *data; - void dataReceived(); - void requestMore(); -}; - -class DBClientInterface : boost::noncopyable { -public: - virtual - auto_ptr<DBClientCursor> query(const char *ns, BSONObj query, int nToReturn = 0, int nToSkip = 0, - BSONObj *fieldsToReturn = 0, int queryOptions = 0) = 0; - - virtual - BSONObj findOne(const char *ns, BSONObj query, BSONObj *fieldsToReturn = 0, int queryOptions = 0) = 0; - - virtual void insert( const char * ns , BSONObj obj ) = 0; -}; - -/* db "commands" - basically just invocations of connection.$cmd.findOne({...}); -*/ -class DBClientWithCommands : public DBClientInterface { - bool isOk(const BSONObj&); - bool simpleCommand(const char *dbname, BSONObj *info, const char *command); -public: - /* Run a database command. Database commands are represented as BSON objects. Common database - commands have prebuilt helper functions -- see below. If a helper is not available you can - directly call runCommand. - - dbname - database name. Use "admin" for global administrative commands. - cmd - the command object to execute. For example, { ismaster : 1 } - info - the result object the database returns. Typically has { ok : ..., errmsg : ... } fields - set. - - returns: true if the command returned "ok". - */ - bool runCommand(const char *dbname, BSONObj cmd, BSONObj &info); - - /* returns true in isMaster parm if this db is the current master - of a replica pair. - - pass in info for more details e.g.: - { "ismaster" : 1.0 , "msg" : "not paired" , "ok" : 1.0 } - - returns true if command invoked successfully. - */ - virtual bool isMaster(bool& isMaster, BSONObj *info=0); - - /* - Create a new collection in the database. Normally, collection creation is automatic. You would - use this function if you wish to specify special options on creation. + class DBConnector { + public: + virtual bool call( Message &toSend, Message &response, bool assertOk=true ) = 0; + virtual void say( Message &toSend ) = 0; + virtual void sayPiggyBack( Message &toSend ) = 0; + virtual void checkResponse( const char *data, int nReturned ) {} + }; - If the collection already exists, no action occurs. + class DBClientCursor : boost::noncopyable { + public: + bool more(); // if true, safe to call next() + + /* returns next object in the result cursor. + on an error at the remote server, you will get back: + { $err: <string> } + if you do not want to handle that yourself, call nextSafe(). + */ + BSONObj next(); + + BSONObj nextSafe() { + BSONObj o = next(); + BSONElement e = o.firstElement(); + assert( strcmp(e.fieldName(), "$err") != 0 ); + return o; + } + + /* cursor no longer valid -- use with tailable cursors. + note you should only rely on this once more() returns false; + 'dead' may be preset yet some data still queued and locally + available from the dbclientcursor. + */ + bool isDead() const { + return cursorId == 0; + } + + bool tailable() const { + return (opts & Option_CursorTailable) != 0; + } + + bool init(); + + DBClientCursor( DBConnector *_connector, const char * _ns, BSONObj _query, int _nToReturn, + int _nToSkip, BSONObj *_fieldsToReturn, int queryOptions ) : + connector(_connector), + ns(_ns), + query(_query), + nToReturn(_nToReturn), + nToSkip(_nToSkip), + fieldsToReturn(_fieldsToReturn), + opts(queryOptions), + m(new Message()) { + cursorId = 0; + } + + virtual ~DBClientCursor(); + + private: + DBConnector *connector; + string ns; + BSONObj query; + int nToReturn; + int nToSkip; + BSONObj *fieldsToReturn; + int opts; + auto_ptr<Message> m; + + long long cursorId; + int nReturned; + int pos; + const char *data; + void dataReceived(); + void requestMore(); + }; - ns: fully qualified collection name - size: desired initial extent size for the collection. - Must be <= 1000000000 for normal collections. - For fixed size (capped) collections, this size is the total/max size of the - collection. - capped: if true, this is a fixed size collection (where old data rolls out). - max: maximum number of objects if capped (optional). + class DBClientInterface : boost::noncopyable { + public: + virtual + auto_ptr<DBClientCursor> query(const char *ns, BSONObj query, int nToReturn = 0, int nToSkip = 0, + BSONObj *fieldsToReturn = 0, int queryOptions = 0) = 0; - returns true if successful. - */ - bool createCollection(const char *ns, unsigned size = 0, bool capped = false, int max = 0, BSONObj *info = 0); + virtual + BSONObj findOne(const char *ns, BSONObj query, BSONObj *fieldsToReturn = 0, int queryOptions = 0) = 0; - /* Erase / drop an entire database */ - bool dropDatabase(const char *dbname, BSONObj *info = 0) { - return simpleCommand(dbname, info, "dropDatabase"); - } + virtual void insert( const char * ns , BSONObj obj ) = 0; + }; - /* Perform a repair and compaction of the specified database. May take a long time to run. Disk space - must be available equal to the size of the database while repairing. + /* db "commands" + basically just invocations of connection.$cmd.findOne({...}); */ - bool repairDatabase(const char *dbname, BSONObj *info = 0) { - return simpleCommand(dbname, info, "repairDatabase"); - } - - /* Copy database from one server or name to another server or name. - - Generally, you should dropDatabase() first as otherwise the copied information will MERGE - into whatever data is already present in this database. - - For security reasons this function only works when you are authorized to access the "admin" db. However, - if you have access to said db, you can copy any database from one place to another. - TODO: this needs enhancement to be more flexible in terms of security. - - This method provides a way to "rename" a database by copying it to a new db name and - location. The copy is "repaired" and compacted. + class DBClientWithCommands : public DBClientInterface { + bool isOk(const BSONObj&); + bool simpleCommand(const char *dbname, BSONObj *info, const char *command); + public: + /* Run a database command. Database commands are represented as BSON objects. Common database + commands have prebuilt helper functions -- see below. If a helper is not available you can + directly call runCommand. + + dbname - database name. Use "admin" for global administrative commands. + cmd - the command object to execute. For example, { ismaster : 1 } + info - the result object the database returns. Typically has { ok : ..., errmsg : ... } fields + set. + + returns: true if the command returned "ok". + */ + bool runCommand(const char *dbname, BSONObj cmd, BSONObj &info); + + /* returns true in isMaster parm if this db is the current master + of a replica pair. + + pass in info for more details e.g.: + { "ismaster" : 1.0 , "msg" : "not paired" , "ok" : 1.0 } + + returns true if command invoked successfully. + */ + virtual bool isMaster(bool& isMaster, BSONObj *info=0); + + /* + Create a new collection in the database. Normally, collection creation is automatic. You would + use this function if you wish to specify special options on creation. + + If the collection already exists, no action occurs. + + ns: fully qualified collection name + size: desired initial extent size for the collection. + Must be <= 1000000000 for normal collections. + For fixed size (capped) collections, this size is the total/max size of the + collection. + capped: if true, this is a fixed size collection (where old data rolls out). + max: maximum number of objects if capped (optional). + + returns true if successful. + */ + bool createCollection(const char *ns, unsigned size = 0, bool capped = false, int max = 0, BSONObj *info = 0); + + /* Erase / drop an entire database */ + bool dropDatabase(const char *dbname, BSONObj *info = 0) { + return simpleCommand(dbname, info, "dropDatabase"); + } + + /* Perform a repair and compaction of the specified database. May take a long time to run. Disk space + must be available equal to the size of the database while repairing. + */ + bool repairDatabase(const char *dbname, BSONObj *info = 0) { + return simpleCommand(dbname, info, "repairDatabase"); + } + + /* Copy database from one server or name to another server or name. + + Generally, you should dropDatabase() first as otherwise the copied information will MERGE + into whatever data is already present in this database. + + For security reasons this function only works when you are authorized to access the "admin" db. However, + if you have access to said db, you can copy any database from one place to another. + TODO: this needs enhancement to be more flexible in terms of security. + + This method provides a way to "rename" a database by copying it to a new db name and + location. The copy is "repaired" and compacted. + + fromdb database name from which to copy. + todb database name to copy to. + fromhost hostname of the database (and optionally, ":port") from which to + copy the data. copies from self if "". + + returns true if successful + */ + bool copyDatabase(const char *fromdb, const char *todb, const char *fromhost = "", BSONObj *info = 0); + + /* The Mongo database provides built-in performance profiling capabilities. Uset setDbProfilingLevel() + to enable. Profiling information is then written to the system.profiling collection, which one can + then query. + */ + enum ProfilingLevel { + ProfileOff = 0, + ProfileSlow = 1, // log very slow (>100ms) operations + ProfileAll = 2 + }; + bool setDbProfilingLevel(const char *dbname, ProfilingLevel level, BSONObj *info = 0); + bool getDbProfilingLevel(const char *dbname, ProfilingLevel& level, BSONObj *info = 0); + + /* Run javascript code on the database server. + dbname database context in which the code runs. The javascript variable 'db' will be assigned + to this database when the function is invoked. + jscode source code for a javascript function. + info the command object which contains any information on the invocation result including + the return value and other information. If an error occurs running the jscode, error + information will be in info. (try "out() << info.toString()") + retValue return value from the jscode function. + args args to pass to the jscode function. when invoked, the 'args' variable will be defined + for use by the jscode. + + returns true if runs ok. + + See testDbEval() in dbclient.cpp for an example of usage. + */ + bool eval(const char *dbname, const char *jscode, BSONObj& info, BSONElement& retValue, BSONObj *args = 0); + + /* The following helpers are simply more convenient forms of eval() for certain common cases */ + + /* invocation with no return value of interest -- with or without one simple parameter */ + bool eval(const char *dbname, const char *jscode); + template< class T > + bool eval(const char *dbname, const char *jscode, T parm1) { + BSONObj info; + BSONElement retValue; + BSONObjBuilder b; + b.append("0", parm1); + BSONObj args = b.done(); + return eval(dbname, jscode, info, retValue, &args); + } + + /* invocation with one parm to server and one numeric field (either int or double) returned */ + template< class T, class NumType > + bool eval(const char *dbname, const char *jscode, T parm1, NumType& ret) { + BSONObj info; + BSONElement retValue; + BSONObjBuilder b; + b.append("0", parm1); + BSONObj args = b.done(); + if ( !eval(dbname, jscode, info, retValue, &args) ) + return false; + ret = (NumType) retValue.number(); + return true; + } + + virtual string toString() = 0; + }; - fromdb database name from which to copy. - todb database name to copy to. - fromhost hostname of the database (and optionally, ":port") from which to - copy the data. copies from self if "". + class DBClientBase : public DBClientWithCommands, public DBConnector { + public: + /* send a query to the database. + ns: namespace to query, format is <dbname>.<collectname>[.<collectname>]* + query: query to perform on the collection. this is a BSONObj (binary JSON) + You may format as + { query: { ... }, order: { ... } } + to specify a sort order. + nToReturn: n to return. 0 = unlimited + nToSkip: start with the nth item + fieldsToReturn: + optional template of which fields to select. if unspecified, returns all fields + queryOptions: see options enum at top of this file + + returns: cursor. + 0 if error (connection failure) + */ + /*throws AssertionException*/ + virtual + auto_ptr<DBClientCursor> query(const char *ns, BSONObj query, int nToReturn = 0, int nToSkip = 0, + BSONObj *fieldsToReturn = 0, int queryOptions = 0); + + /*throws AssertionException*/ + virtual + BSONObj findOne(const char *ns, BSONObj query, BSONObj *fieldsToReturn = 0, int queryOptions = 0); + + virtual void insert( const char * ns , BSONObj obj ); + + virtual void remove( const char * ns , BSONObj obj , bool justOne = 0 ); + + virtual void update( const char * ns , BSONObj query , BSONObj obj , bool upsert = 0 ); + + /** + if name isn't specified, it will be created from the keys (reccomended) + @return whether or not sent message to db + should be true on first call, false on subsequent unless resetIndexCache was called + */ + virtual bool ensureIndex( const char * ns , BSONObj keys , const char * name = 0 ); + virtual void resetIndexCache(); + + private: + set<string> _seenIndexes; + }; - returns true if successful - */ - bool copyDatabase(const char *fromdb, const char *todb, const char *fromhost = "", BSONObj *info = 0); + class DBClientPaired; + + /* A basic connection to the database. */ + class DBClientConnection : public DBClientBase { + DBClientPaired *clientPaired; + auto_ptr<MessagingPort> p; + auto_ptr<SockAddr> server; + bool failed; // true if some sort of fatal error has ever happened + bool autoReconnect; + time_t lastReconnectTry; + string serverAddress; // remember for reconnects + void checkConnection(); + public: + string toStringLong() const { + stringstream ss; + ss << serverAddress; + if ( failed ) ss << " failed"; + return ss.str(); + } + string toString() { + return serverAddress; + } + MessagingPort& port() { + return *p.get(); + } + bool isFailed() const { + return failed; + } + DBClientConnection(bool _autoReconnect=false,DBClientPaired* cp=0) : + clientPaired(cp), failed(false), autoReconnect(_autoReconnect), lastReconnectTry(0) { } + + virtual auto_ptr<DBClientCursor> query(const char *ns, BSONObj query, int nToReturn = 0, int nToSkip = 0, + BSONObj *fieldsToReturn = 0, int queryOptions = 0) { + checkConnection(); + return DBClientBase::query( ns, query, nToReturn, nToSkip, fieldsToReturn, queryOptions ); + } + + /* Returns false if fails to connect. + If autoReconnect is true, you can try to use the DBClientConnection even when + false was returned -- it will try to connect again. + */ + virtual + bool connect(const char *serverHostname, string& errmsg); + + protected: + virtual bool call( Message &toSend, Message &response, bool assertOk = true ); + virtual void say( Message &toSend ); + virtual void sayPiggyBack( Message &toSend ); + virtual void checkResponse( const char *data, int nReturned ); + }; - /* The Mongo database provides built-in performance profiling capabilities. Uset setDbProfilingLevel() - to enable. Profiling information is then written to the system.profiling collection, which one can - then query. + /* Use this class to connect to a replica pair of servers. The class will manage + checking for which is master, and do failover automatically. */ - enum ProfilingLevel { - ProfileOff = 0, - ProfileSlow = 1, // log very slow (>100ms) operations - ProfileAll = 2 + class DBClientPaired : public DBClientWithCommands { + DBClientConnection left,right; + enum State { + NotSetL=0, + NotSetR=1, + Left, Right + } master; + + void _checkMaster(); + DBClientConnection& checkMaster(); + + public: + DBClientPaired(); + + /* Returns false is neither member of the pair were reachable, or neither is + master, although, + when false returned, you can still try to use this connection object, it will + try reconnects. + */ + bool connect(const char *serverHostname1, const char *serverHostname2); + + /* throws userassertion "no master found" */ + virtual + auto_ptr<DBClientCursor> query(const char *ns, BSONObj query, int nToReturn = 0, int nToSkip = 0, + BSONObj *fieldsToReturn = 0, int queryOptions = 0); + + /* throws userassertion "no master found" */ + virtual + BSONObj findOne(const char *ns, BSONObj query, BSONObj *fieldsToReturn = 0, int queryOptions = 0); + + // Not implemented + virtual void insert( const char * ns , BSONObj obj ) { + assert( false ); + } + + string toString(); + + /* notification that we got a "not master" error. + */ + void isntMaster() { + master = ( ( master == Left ) ? NotSetR : NotSetL ); + } }; - bool setDbProfilingLevel(const char *dbname, ProfilingLevel level, BSONObj *info = 0); - bool getDbProfilingLevel(const char *dbname, ProfilingLevel& level, BSONObj *info = 0); - - /* Run javascript code on the database server. - dbname database context in which the code runs. The javascript variable 'db' will be assigned - to this database when the function is invoked. - jscode source code for a javascript function. - info the command object which contains any information on the invocation result including - the return value and other information. If an error occurs running the jscode, error - information will be in info. (try "cout << info.toString()") - retValue return value from the jscode function. - args args to pass to the jscode function. when invoked, the 'args' variable will be defined - for use by the jscode. - - returns true if runs ok. - - See testDbEval() in dbclient.cpp for an example of usage. - */ - bool eval(const char *dbname, const char *jscode, BSONObj& info, BSONElement& retValue, BSONObj *args = 0); - - /* The following helpers are simply more convenient forms of eval() for certain common cases */ - - /* invocation with no return value of interest -- with or without one simple parameter */ - bool eval(const char *dbname, const char *jscode); - template< class T > - bool eval(const char *dbname, const char *jscode, T parm1) { - BSONObj info; - BSONElement retValue; - BSONObjBuilder b; - b.append("0", parm1); - BSONObj args = b.done(); - return eval(dbname, jscode, info, retValue, &args); - } - - /* invocation with one parm to server and one numeric field (either int or double) returned */ - template< class T, class NumType > - bool eval(const char *dbname, const char *jscode, T parm1, NumType& ret) { - BSONObj info; - BSONElement retValue; - BSONObjBuilder b; - b.append("0", parm1); - BSONObj args = b.done(); - if ( !eval(dbname, jscode, info, retValue, &args) ) - return false; - ret = (NumType) retValue.number(); - return true; - } - - virtual string toString() = 0; -}; - -class DBClientBase : public DBClientWithCommands, public DBConnector { -public: - /* send a query to the database. - ns: namespace to query, format is <dbname>.<collectname>[.<collectname>]* - query: query to perform on the collection. this is a BSONObj (binary JSON) - You may format as - { query: { ... }, order: { ... } } - to specify a sort order. - nToReturn: n to return. 0 = unlimited - nToSkip: start with the nth item - fieldsToReturn: - optional template of which fields to select. if unspecified, returns all fields - queryOptions: see options enum at top of this file - - returns: cursor. - 0 if error (connection failure) - */ - /*throws AssertionException*/ - virtual - auto_ptr<DBClientCursor> query(const char *ns, BSONObj query, int nToReturn = 0, int nToSkip = 0, - BSONObj *fieldsToReturn = 0, int queryOptions = 0); - - /*throws AssertionException*/ - virtual - BSONObj findOne(const char *ns, BSONObj query, BSONObj *fieldsToReturn = 0, int queryOptions = 0); - - virtual void insert( const char * ns , BSONObj obj ); - - virtual void remove( const char * ns , BSONObj obj , bool justOne = 0 ); - - virtual void update( const char * ns , BSONObj query , BSONObj obj , bool upsert = 0 ); - - /** - if name isn't specified, it will be created from the keys (reccomended) - @return whether or not sent message to db - should be true on first call, false on subsequent unless resetIndexCache was called - */ - virtual bool ensureIndex( const char * ns , BSONObj keys , const char * name = 0 ); - virtual void resetIndexCache(); - -private: - set<string> _seenIndexes; -}; - -class DBClientPaired; - -/* A basic connection to the database. */ -class DBClientConnection : public DBClientBase { - DBClientPaired *clientPaired; - auto_ptr<MessagingPort> p; - auto_ptr<SockAddr> server; - bool failed; // true if some sort of fatal error has ever happened - bool autoReconnect; - time_t lastReconnectTry; - string serverAddress; // remember for reconnects - void checkConnection(); -public: - string toStringLong() const { - stringstream ss; - ss << serverAddress; - if ( failed ) ss << " failed"; - return ss.str(); - } - string toString() { - return serverAddress; - } - MessagingPort& port() { - return *p.get(); - } - bool isFailed() const { - return failed; - } - DBClientConnection(bool _autoReconnect=false,DBClientPaired* cp=0) : - clientPaired(cp), failed(false), autoReconnect(_autoReconnect), lastReconnectTry(0) { } - - virtual auto_ptr<DBClientCursor> query(const char *ns, BSONObj query, int nToReturn = 0, int nToSkip = 0, - BSONObj *fieldsToReturn = 0, int queryOptions = 0) { - checkConnection(); - return DBClientBase::query( ns, query, nToReturn, nToSkip, fieldsToReturn, queryOptions ); - } - - /* Returns false if fails to connect. - If autoReconnect is true, you can try to use the DBClientConnection even when - false was returned -- it will try to connect again. - */ - virtual - bool connect(const char *serverHostname, string& errmsg); - -protected: - virtual bool call( Message &toSend, Message &response, bool assertOk = true ); - virtual void say( Message &toSend ); - virtual void sayPiggyBack( Message &toSend ); - virtual void checkResponse( const char *data, int nReturned ); -}; - -/* Use this class to connect to a replica pair of servers. The class will manage - checking for which is master, and do failover automatically. -*/ -class DBClientPaired : public DBClientWithCommands { - DBClientConnection left,right; - enum State { - NotSetL=0, - NotSetR=1, - Left, Right - } master; - - void _checkMaster(); - DBClientConnection& checkMaster(); - -public: - DBClientPaired(); - - /* Returns false is neither member of the pair were reachable, or neither is - master, although, - when false returned, you can still try to use this connection object, it will - try reconnects. - */ - bool connect(const char *serverHostname1, const char *serverHostname2); - - /* throws userassertion "no master found" */ - virtual - auto_ptr<DBClientCursor> query(const char *ns, BSONObj query, int nToReturn = 0, int nToSkip = 0, - BSONObj *fieldsToReturn = 0, int queryOptions = 0); - - /* throws userassertion "no master found" */ - virtual - BSONObj findOne(const char *ns, BSONObj query, BSONObj *fieldsToReturn = 0, int queryOptions = 0); - - // Not implemented - virtual void insert( const char * ns , BSONObj obj ) { - assert( false ); - } - - string toString(); - - /* notification that we got a "not master" error. - */ - void isntMaster() { - master = ( ( master == Left ) ? NotSetR : NotSetL ); - } -}; |