diff options
Diffstat (limited to 'client/dbclient.h')
-rw-r--r-- | client/dbclient.h | 543 |
1 files changed, 311 insertions, 232 deletions
diff --git a/client/dbclient.h b/client/dbclient.h index a2fad8e..639d960 100644 --- a/client/dbclient.h +++ b/client/dbclient.h @@ -17,7 +17,7 @@ #pragma once -#include "../stdafx.h" +#include "../pch.h" #include "../util/message.h" #include "../db/jsobj.h" #include "../db/json.h" @@ -51,7 +51,7 @@ namespace mongo { // an extended period of time. QueryOption_OplogReplay = 1 << 3, - /** The server normally times out idle cursors after an inactivy period to prevent excess memory use + /** The server normally times out idle cursors after an inactivy period to prevent excess memory uses Set this option to prevent that. */ QueryOption_NoCursorTimeout = 1 << 4, @@ -59,7 +59,18 @@ namespace mongo { /** Use with QueryOption_CursorTailable. If we are at the end of the data, block for a while rather than returning no data. After a timeout period, we do return as normal. */ - QueryOption_AwaitData = 1 << 5 + QueryOption_AwaitData = 1 << 5, + + /** Stream the data down full blast in multiple "more" packages, on the assumption that the client + will fully read all data queried. Faster when you are pulling a lot of data and know you want to + pull it all down. Note: it is not allowed to not read all the data unless you close the connection. + + Use the query( boost::function<void(const BSONObj&)> f, ... ) version of the connection's query() + method, and it will take care of all the details for you. + */ + QueryOption_Exhaust = 1 << 6, + + QueryOption_AllSupported = QueryOption_CursorTailable | QueryOption_SlaveOk | QueryOption_OplogReplay | QueryOption_NoCursorTimeout | QueryOption_AwaitData | QueryOption_Exhaust }; @@ -69,10 +80,129 @@ namespace mongo { /** Update multiple documents (if multiple documents match query expression). (Default is update a single document and stop.) */ - UpdateOption_Multi = 1 << 1 + UpdateOption_Multi = 1 << 1, + + /** flag from mongo saying this update went everywhere */ + UpdateOption_Broadcast = 1 << 2 + }; + + enum RemoveOptions { + /** only delete one option */ + RemoveOption_JustOne = 1 << 0, + + /** flag from mongo saying this update went everywhere */ + RemoveOption_Broadcast = 1 << 1 + }; + + class DBClientBase; + + class ConnectionString { + public: + enum ConnectionType { INVALID , MASTER , PAIR , SET , SYNC }; + + ConnectionString( const HostAndPort& server ){ + _type = MASTER; + _servers.push_back( server ); + _finishInit(); + } + + ConnectionString( ConnectionType type , const vector<HostAndPort>& servers ) + : _type( type ) , _servers( servers ){ + _finishInit(); + } + + ConnectionString( ConnectionType type , const string& s , const string& setName = "" ){ + _type = type; + _setName = setName; + _fillServers( s ); + + switch ( _type ){ + case MASTER: + assert( _servers.size() == 1 ); + break; + case SET: + assert( _setName.size() ); + assert( _servers.size() >= 1 ); // 1 is ok since we can derive + break; + case PAIR: + assert( _servers.size() == 2 ); + break; + default: + assert( _servers.size() > 0 ); + } + + _finishInit(); + } + + ConnectionString( const string& s , ConnectionType favoredMultipleType ){ + _fillServers( s ); + if ( _servers.size() == 1 ){ + _type = MASTER; + } + else { + _type = favoredMultipleType; + assert( _type != MASTER ); + } + _finishInit(); + } + + bool isValid() const { return _type != INVALID; } + + string toString() const { + return _string; + } + + DBClientBase* connect( string& errmsg ) const; + + static ConnectionString parse( const string& url , string& errmsg ); + + private: + + ConnectionString(){ + _type = INVALID; + } + + void _fillServers( string s ){ + string::size_type idx; + while ( ( idx = s.find( ',' ) ) != string::npos ){ + _servers.push_back( s.substr( 0 , idx ) ); + s = s.substr( idx + 1 ); + } + _servers.push_back( s ); + } + + void _finishInit(){ + stringstream ss; + if ( _type == SET ) + ss << _setName << "/"; + for ( unsigned i=0; i<_servers.size(); i++ ){ + if ( i > 0 ) + ss << ","; + ss << _servers[i].toString(); + } + _string = ss.str(); + } + + ConnectionType _type; + vector<HostAndPort> _servers; + string _string; + string _setName; + }; + + /** + * controls how much a clients cares about writes + * default is NORMAL + */ + enum WriteConcern { + W_NONE = 0 , // TODO: not every connection type fully supports this + W_NORMAL = 1 + // TODO SAFE = 2 }; class BSONObj; + class ScopedDbConnection; + class DBClientCursor; + class DBClientCursorBatchIterator; /** Represents a Mongo query expression. Typically one uses the QUERY(...) macro to construct a Query object. Examples: @@ -160,7 +290,7 @@ namespace mongo { /** * if this query has an orderby, hint, or some other field */ - bool isComplex() const; + bool isComplex( bool * hasDollar = 0 ) const; BSONObj getFilter() const; BSONObj getSort() const; @@ -195,146 +325,12 @@ namespace mongo { 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 string &data, int nReturned ) {} - }; - - /** Queries return a cursor object */ - class DBClientCursor : boost::noncopyable { - friend class DBClientBase; - bool init(); - public: - /** If true, safe to call next(). Requests more from server if necessary. */ - bool more(); + virtual void checkResponse( const char* data, int nReturned ) {} - /** If true, there is more in our local buffers to be fetched via next(). Returns - false when a getMore request back to server would be required. You can use this - if you want to exhaust whatever data has been fetched to the client already but - then perhaps stop. - */ - bool moreInCurrentBatch() { return !_putBack.empty() || pos < nReturned; } - - /** next - @return next object in the result cursor. - on an error at the remote server, you will get back: - { $err: <string> } - if you do not want to handle that yourself, call nextSafe(). - */ - BSONObj next(); - - /** - restore an object previously returned by next() to the cursor - */ - void putBack( const BSONObj &o ) { _putBack.push( o.getOwned() ); } - - /** throws AssertionException if get back { $err : ... } */ - BSONObj nextSafe() { - BSONObj o = next(); - BSONElement e = o.firstElement(); - assert( strcmp(e.fieldName(), "$err") != 0 ); - return o; - } - - /** - iterate the rest of the cursor and return the number if items - */ - int itcount(){ - int c = 0; - while ( more() ){ - next(); - c++; - } - return c; - } - - /** cursor no longer valid -- use with tailable cursors. - note you should only rely on this once more() returns false; - 'dead' may be preset yet some data still queued and locally - available from the dbclientcursor. - */ - bool isDead() const { - return cursorId == 0; - } - - bool tailable() const { - return (opts & QueryOption_CursorTailable) != 0; - } - - /** see QueryResult::ResultFlagType (db/dbmessage.h) for flag values - mostly these flags are for internal purposes - - ResultFlag_ErrSet is the possible exception to that - */ - bool hasResultFlag( int flag ){ - return (resultFlags & flag) != 0; - } - - DBClientCursor( DBConnector *_connector, const string &_ns, BSONObj _query, int _nToReturn, - int _nToSkip, const BSONObj *_fieldsToReturn, int queryOptions , int bs ) : - connector(_connector), - ns(_ns), - query(_query), - nToReturn(_nToReturn), - haveLimit( _nToReturn > 0 && !(queryOptions & QueryOption_CursorTailable)), - nToSkip(_nToSkip), - fieldsToReturn(_fieldsToReturn), - opts(queryOptions), - batchSize(bs), - m(new Message()), - cursorId(), - nReturned(), - pos(), - data(), - _ownCursor( true ) { - } - - DBClientCursor( DBConnector *_connector, const string &_ns, long long _cursorId, int _nToReturn, int options ) : - connector(_connector), - ns(_ns), - nToReturn( _nToReturn ), - haveLimit( _nToReturn > 0 && !(options & QueryOption_CursorTailable)), - opts( options ), - m(new Message()), - cursorId( _cursorId ), - nReturned(), - pos(), - data(), - _ownCursor( true ) { - } - - virtual ~DBClientCursor(); - - long long getCursorId() const { return cursorId; } - - /** by default we "own" the cursor and will send the server a KillCursor - message when ~DBClientCursor() is called. This function overrides that. - */ - void decouple() { _ownCursor = false; } - - private: - - int nextBatchSize(); - - DBConnector *connector; - string ns; - BSONObj query; - int nToReturn; - bool haveLimit; - int nToSkip; - const BSONObj *fieldsToReturn; - int opts; - int batchSize; - auto_ptr<Message> m; - stack< BSONObj > _putBack; - - int resultFlags; - long long cursorId; - int nReturned; - int pos; - const char *data; - void dataReceived(); - void requestMore(); - bool _ownCursor; // see decouple() + /* used by QueryOption_Exhaust. To use that your subclass must implement this. */ + virtual void recv( Message& m ) { assert(false); } }; - + /** The interface that any db connection should implement */ @@ -343,6 +339,7 @@ namespace mongo { virtual auto_ptr<DBClientCursor> query(const string &ns, Query query, int nToReturn = 0, int nToSkip = 0, const BSONObj *fieldsToReturn = 0, int queryOptions = 0 , int batchSize = 0 ) = 0; + /** don't use this - called automatically by DBClientCursor for you */ virtual auto_ptr<DBClientCursor> getMore( const string &ns, long long cursorId, int nToReturn = 0, int options = 0 ) = 0; virtual void insert( const string &ns, BSONObj obj ) = 0; @@ -359,7 +356,7 @@ namespace mongo { @return a single object that matches the query. if none do, then the object is empty @throws AssertionException */ - virtual BSONObj findOne(const string &ns, Query query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0); + virtual BSONObj findOne(const string &ns, const Query& query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0); }; @@ -371,33 +368,38 @@ namespace mongo { class DBClientWithCommands : public DBClientInterface { set<string> _seenIndexes; public: + /** controls how chatty the client is about network errors & such. See log.h */ + int _logLevel; + + DBClientWithCommands() : _logLevel(0), _cachedAvailableOptions( (enum QueryOptions)0 ), _haveCachedAvailableOptions(false) { } - /** helper function. run a simple command where the command expression is simply - { command : 1 } + /** helper function. run a simple command where the command expression is simply + { command : 1 } @param info -- where to put result object. may be null if caller doesn't need that info @param command -- command name - @return true if the command returned "ok". - */ + @return true if the command returned "ok". + */ bool simpleCommand(const string &dbname, BSONObj *info, const string &command); /** 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. + directly call runCommand. @param dbname database name. Use "admin" for global administrative commands. @param cmd the command object to execute. For example, { ismaster : 1 } @param info the result object the database returns. Typically has { ok : ..., errmsg : ... } fields set. - @return true if the command returned "ok". + @param options see enum QueryOptions - normally not needed to run a command + @return true if the command returned "ok". */ virtual bool runCommand(const string &dbname, const BSONObj& cmd, BSONObj &info, int options=0); /** Authorize access to a particular database. - Authentication is separate for each database on the server -- you may authenticate for any - number of databases on a single connection. - The "admin" database is special and once authenticated provides access to all databases on the - server. - @param digestPassword if password is plain text, set this to true. otherwise assumed to be pre-digested + Authentication is separate for each database on the server -- you may authenticate for any + number of databases on a single connection. + The "admin" database is special and once authenticated provides access to all databases on the + server. + @param digestPassword if password is plain text, set this to true. otherwise assumed to be pre-digested @return true if successful */ virtual bool auth(const string &dbname, const string &username, const string &pwd, string& errmsg, bool digestPassword = true); @@ -425,17 +427,17 @@ namespace mongo { 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). + @param ns fully qualified collection name + @param size desired initial extent size for the collection. + Must be <= 1000000000 for normal collections. + For fixed size (capped) collections, this size is the total/max size of the + collection. + @param capped if true, this is a fixed size collection (where old data rolls out). + @param max maximum number of objects if capped (optional). returns true if successful. */ - bool createCollection(const string &ns, unsigned size = 0, bool capped = false, int max = 0, BSONObj *info = 0); + bool createCollection(const string &ns, long long size = 0, bool capped = false, int max = 0, BSONObj *info = 0); /** Get error result from the last operation on this connection. @return error message text, or empty string if no error. @@ -444,7 +446,9 @@ namespace mongo { /** Get error result from the last operation on this connection. @return full error object. */ - BSONObj getLastErrorDetailed(); + virtual BSONObj getLastErrorDetailed(); + + static string getLastErrorString( const BSONObj& res ); /** Return the last error which has occurred, even if not the very last operation. @@ -595,6 +599,8 @@ namespace mongo { /** get a list of all the current databases + uses the { listDatabases : 1 } command. + throws on error */ list<string> getDatabaseNames(); @@ -605,7 +611,6 @@ namespace mongo { bool exists( const string& ns ); - /** Create an index if it does not already exist. ensureIndex calls are remembered so it is safe/fast to call this function many times in your code. @@ -666,25 +671,39 @@ namespace mongo { protected: bool isOk(const BSONObj&); - + + enum QueryOptions availableOptions(); + + private: + enum QueryOptions _cachedAvailableOptions; + bool _haveCachedAvailableOptions; }; /** abstract class that implements the core db operations */ class DBClientBase : public DBClientWithCommands, public DBConnector { + protected: + WriteConcern _writeConcern; + public: + DBClientBase(){ + _writeConcern = W_NORMAL; + } + + WriteConcern getWriteConcern() const { return _writeConcern; } + void setWriteConcern( WriteConcern w ){ _writeConcern = w; } + /** send a query to the database. - ns: namespace to query, format is <dbname>.<collectname>[.<collectname>]* - query: query to perform on the collection. this is a BSONObj (binary JSON) + @param ns namespace to query, format is <dbname>.<collectname>[.<collectname>]* + @param query query to perform on the collection. this is a BSONObj (binary JSON) You may format as { query: { ... }, orderby: { ... } } 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 + @param nToReturn n to return. 0 = unlimited + @param nToSkip start with the nth item + @param fieldsToReturn optional template of which fields to select. if unspecified, returns all fields + @param queryOptions see options enum at top of this file @return cursor. 0 if error (connection failure) @throws AssertionException @@ -692,12 +711,13 @@ namespace mongo { virtual auto_ptr<DBClientCursor> query(const string &ns, Query query, int nToReturn = 0, int nToSkip = 0, const BSONObj *fieldsToReturn = 0, int queryOptions = 0 , int batchSize = 0 ); - /** @param cursorId id of cursor to retrieve + /** don't use this - called automatically by DBClientCursor for you + @param cursorId id of cursor to retrieve @return an handle to a previously allocated cursor @throws AssertionException */ virtual auto_ptr<DBClientCursor> getMore( const string &ns, long long cursorId, int nToReturn = 0, int options = 0 ); - + /** insert an object into the database */ @@ -717,11 +737,13 @@ namespace mongo { /** updates objects matching query */ - virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = 0 , bool multi = 0 ); + virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = false , bool multi = false ); virtual string getServerAddress() const = 0; virtual bool isFailed() const = 0; + + virtual void killCursor( long long cursorID ) = 0; static int countCommas( const string& s ){ int n = 0; @@ -730,9 +752,15 @@ namespace mongo { n++; return n; } - }; + + virtual bool callRead( Message& toSend , Message& response ) = 0; + // virtual bool callWrite( Message& toSend , Message& response ) = 0; // TODO: add this if needed + virtual void say( Message& toSend ) = 0; + + virtual ConnectionString::ConnectionType type() const = 0; + }; // DBClientBase - class DBClientPaired; + class DBClientReplicaSet; class ConnectException : public UserException { public: @@ -744,24 +772,31 @@ namespace mongo { This is the main entry point for talking to a simple Mongo setup */ class DBClientConnection : public DBClientBase { - DBClientPaired *clientPaired; - auto_ptr<MessagingPort> p; - auto_ptr<SockAddr> server; + DBClientReplicaSet *clientSet; + boost::scoped_ptr<MessagingPort> p; + boost::scoped_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 + HostAndPort _server; // remember for reconnects + string _serverString; + int _port; void _checkConnection(); void checkConnection() { if( failed ) _checkConnection(); } map< string, pair<string,string> > authCache; + int _timeout; + + bool _connect( string& errmsg ); public: /** @param _autoReconnect if true, automatically reconnect on a connection failure - @param cp used by DBClientPaired. You do not need to specify this parameter + @param cp used by DBClientReplicaSet. You do not need to specify this parameter + @param timeout tcp timeout in seconds - this is for read/write, not connect. + Connect timeout is fixed, but short, at 5 seconds. */ - DBClientConnection(bool _autoReconnect=false,DBClientPaired* cp=0) : - clientPaired(cp), failed(false), autoReconnect(_autoReconnect), lastReconnectTry(0) { } + DBClientConnection(bool _autoReconnect=false, DBClientReplicaSet* cp=0, int timeout=0) : + clientSet(cp), failed(false), autoReconnect(_autoReconnect), lastReconnectTry(0), _timeout(timeout) { } /** Connect to a Mongo database server. @@ -769,10 +804,27 @@ namespace mongo { false was returned -- it will try to connect again. @param serverHostname host to connect to. can include port number ( 127.0.0.1 , 127.0.0.1:5555 ) + If you use IPv6 you must add a port number ( ::1:27017 ) @param errmsg any relevant error message will appended to the string + @deprecated please use HostAndPort @return false if fails to connect. */ - virtual bool connect(const string &serverHostname, string& errmsg); + virtual bool connect(const char * hostname, string& errmsg){ + // TODO: remove this method + HostAndPort t( hostname ); + return connect( t , errmsg ); + } + + /** Connect to a Mongo database server. + + If autoReconnect is true, you can try to use the DBClientConnection even when + false was returned -- it will try to connect again. + + @param server server to connect to. + @param errmsg any relevant error message will appended to the string + @return false if fails to connect. + */ + virtual bool connect(const HostAndPort& server, string& errmsg); /** Connect to a Mongo database server. Exception throwing version. Throws a UserException if cannot connect. @@ -782,20 +834,26 @@ namespace mongo { @param serverHostname host to connect to. can include port number ( 127.0.0.1 , 127.0.0.1:5555 ) */ - void connect(string serverHostname) { + void connect(const string& serverHostname) { string errmsg; - if( !connect(serverHostname.c_str(), errmsg) ) + if( !connect(HostAndPort(serverHostname), errmsg) ) throw ConnectException(string("can't connect ") + errmsg); } virtual bool auth(const string &dbname, const string &username, const string &pwd, string& errmsg, bool digestPassword = true); - virtual auto_ptr<DBClientCursor> query(const string &ns, Query query, int nToReturn = 0, int nToSkip = 0, + virtual auto_ptr<DBClientCursor> query(const string &ns, Query query=Query(), int nToReturn = 0, int nToSkip = 0, const BSONObj *fieldsToReturn = 0, int queryOptions = 0 , int batchSize = 0 ) { checkConnection(); return DBClientBase::query( ns, query, nToReturn, nToSkip, fieldsToReturn, queryOptions , batchSize ); } + /** uses QueryOption_Exhaust + use DBClientCursorBatchIterator if you want to do items in large blocks, perhpas to avoid granular locking and such. + */ + unsigned long long query( boost::function<void(const BSONObj&)> f, const string& ns, Query query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0); + unsigned long long query( boost::function<void(DBClientCursorBatchIterator&)> f, const string& ns, Query query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0); + /** @return true if this connection is currently in a failed state. When autoreconnect is on, a connection will transition back to an ok state after reconnecting. @@ -805,67 +863,75 @@ namespace mongo { } MessagingPort& port() { - return *p.get(); + return *p; } string toStringLong() const { stringstream ss; - ss << serverAddress; + ss << _serverString; if ( failed ) ss << " failed"; return ss.str(); } /** Returns the address of the server */ string toString() { - return serverAddress; + return _serverString; } string getServerAddress() const { - return serverAddress; + return _serverString; + } + + virtual void killCursor( long long cursorID ); + + virtual bool callRead( Message& toSend , Message& response ){ + return call( toSend , response ); } - virtual bool call( Message &toSend, Message &response, bool assertOk = true ); virtual void say( Message &toSend ); + virtual bool call( Message &toSend, Message &response, bool assertOk = true ); + + virtual ConnectionString::ConnectionType type() const { return ConnectionString::MASTER; } + protected: + friend class SyncClusterConnection; + virtual void recv( Message& m ); 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 server in a replica pair is master, and do failover automatically. - + + /** Use this class to connect to a replica set of servers. The class will manage + checking for which server in a replica set is master, and do failover automatically. + + This can also be used to connect to replica pairs since pairs are a subset of sets + On a failover situation, expect at least one operation to return an error (throw an exception) before the failover is complete. Operations are not retried. */ - class DBClientPaired : public DBClientBase { - DBClientConnection left,right; - enum State { - NotSetL=0, - NotSetR=1, - Left, Right - } master; + class DBClientReplicaSet : public DBClientBase { + string _name; + DBClientConnection * _currentMaster; + vector<HostAndPort> _servers; + vector<DBClientConnection*> _conns; + void _checkMaster(); - DBClientConnection& checkMaster(); + DBClientConnection * checkMaster(); public: - /** Call connect() after constructing. autoReconnect is always on for DBClientPaired connections. */ - DBClientPaired(); + /** Call connect() after constructing. autoReconnect is always on for DBClientReplicaSet connections. */ + DBClientReplicaSet( const string& name , const vector<HostAndPort>& servers ); + virtual ~DBClientReplicaSet(); - /** Returns false is neither member of the pair were reachable, or neither is + /** Returns false if nomember of the set 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 string &serverHostname1, const string &serverHostname2); + bool connect(); - /** Connect to a server pair using a host pair string of the form - hostname[:port],hostname[:port] - */ - bool connect(string hostpairstring); - - /** Authorize. Authorizes both sides of the pair as needed. + /** Authorize. Authorizes all nodes as needed */ - bool auth(const string &dbname, const string &username, const string &pwd, string& errmsg); + virtual bool auth(const string &dbname, const string &username, const string &pwd, string& errmsg, bool digestPassword = true ); /** throws userassertion "no master found" */ virtual @@ -874,56 +940,69 @@ namespace mongo { /** throws userassertion "no master found" */ virtual - BSONObj findOne(const string &ns, Query query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0); + BSONObj findOne(const string &ns, const Query& query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0); /** insert */ virtual void insert( const string &ns , BSONObj obj ) { - checkMaster().insert(ns, obj); + checkMaster()->insert(ns, obj); } /** insert multiple objects. Note that single object insert is asynchronous, so this version is only nominally faster and not worth a special effort to try to use. */ virtual void insert( const string &ns, const vector< BSONObj >& v ) { - checkMaster().insert(ns, v); + checkMaster()->insert(ns, v); } /** remove */ virtual void remove( const string &ns , Query obj , bool justOne = 0 ) { - checkMaster().remove(ns, obj, justOne); + checkMaster()->remove(ns, obj, justOne); } /** update */ virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = 0 , bool multi = 0 ) { - return checkMaster().update(ns, query, obj, upsert,multi); + return checkMaster()->update(ns, query, obj, upsert,multi); } + virtual void killCursor( long long cursorID ){ + checkMaster()->killCursor( cursorID ); + } + string toString(); /* this is the callback from our underlying connections to notify us that we got a "not master" error. */ void isntMaster() { - master = ( ( master == Left ) ? NotSetR : NotSetL ); + _currentMaster = 0; } - string getServerAddress() const { - return left.getServerAddress() + "," + right.getServerAddress(); - } - + string getServerAddress() const; + + DBClientConnection& masterConn(); DBClientConnection& slaveConn(); - /* TODO - not yet implemented. mongos may need these. */ - virtual bool call( Message &toSend, Message &response, bool assertOk=true ) { assert(false); return false; } - virtual void say( Message &toSend ) { assert(false); } + + virtual bool call( Message &toSend, Message &response, bool assertOk=true ) { return checkMaster()->call( toSend , response , assertOk ); } + virtual void say( Message &toSend ) { checkMaster()->say( toSend ); } + virtual bool callRead( Message& toSend , Message& response ){ return checkMaster()->callRead( toSend , response ); } + + virtual ConnectionString::ConnectionType type() const { return ConnectionString::SET; } + + protected: virtual void sayPiggyBack( Message &toSend ) { assert(false); } virtual void checkResponse( const char *data, int nReturned ) { assert(false); } bool isFailed() const { - // TODO: this really should check isFailed on current master as well - return master < Left; + return _currentMaster == 0 || _currentMaster->isFailed(); } }; + /** pings server to check if it's up + */ + bool serverAlive( const string &uri ); DBClientBase * createDirectClient(); } // namespace mongo + +#include "dbclientcursor.h" +#include "undef_macros.h" |