diff options
Diffstat (limited to 'src/mongo/client/dbclient_rs.h')
-rw-r--r-- | src/mongo/client/dbclient_rs.h | 568 |
1 files changed, 297 insertions, 271 deletions
diff --git a/src/mongo/client/dbclient_rs.h b/src/mongo/client/dbclient_rs.h index fb29559c80a..3e5a9f07dd2 100644 --- a/src/mongo/client/dbclient_rs.h +++ b/src/mongo/client/dbclient_rs.h @@ -36,277 +36,303 @@ namespace mongo { - class ReplicaSetMonitor; - class TagSet; - struct ReadPreferenceSetting; - typedef std::shared_ptr<ReplicaSetMonitor> ReplicaSetMonitorPtr; - - /** 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 ReplicaSetMonitor; +class TagSet; +struct ReadPreferenceSetting; +typedef std::shared_ptr<ReplicaSetMonitor> ReplicaSetMonitorPtr; + +/** 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 DBClientReplicaSet : public DBClientBase { +public: + using DBClientBase::query; + using DBClientBase::update; + using DBClientBase::remove; + + /** Call connect() after constructing. autoReconnect is always on for DBClientReplicaSet connections. */ + DBClientReplicaSet(const std::string& name, + const std::vector<HostAndPort>& servers, + double so_timeout = 0); + virtual ~DBClientReplicaSet(); + + /** + * Returns false if no member of the set were reachable. This object + * can still be used even when false was returned as it will try to + * reconnect when you use it later. + */ + bool connect(); + + /** + * Logs out the connection for the given database. + * + * @param dbname the database to logout from. + * @param info the result object for the logout command (provided for backwards + * compatibility with mongo shell) + */ + virtual void logout(const std::string& dbname, BSONObj& info); + + // ----------- simple functions -------------- + + /** throws userassertion "no master found" */ + virtual std::unique_ptr<DBClientCursor> query(const std::string& ns, + Query query, + int nToReturn = 0, + int nToSkip = 0, + const BSONObj* fieldsToReturn = 0, + int queryOptions = 0, + int batchSize = 0); + + /** throws userassertion "no master found" */ + virtual BSONObj findOne(const std::string& ns, + const Query& query, + const BSONObj* fieldsToReturn = 0, + int queryOptions = 0); + + virtual void insert(const std::string& ns, BSONObj obj, int flags = 0); + + /** 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 std::string& ns, const std::vector<BSONObj>& v, int flags = 0); + + virtual void remove(const std::string& ns, Query obj, int flags); + + virtual void update(const std::string& ns, Query query, BSONObj obj, int flags); + + virtual void killCursor(long long cursorID); + + // ---- access raw connections ---- + + /** + * WARNING: this method is very dangerous - this object can decide to free the + * returned master connection any time. + * + * @return the reference to the address that points to the master connection. + */ + DBClientConnection& masterConn(); + + /** + * WARNING: this method is very dangerous - this object can decide to free the + * returned master connection any time. This can also unpin the cached + * slaveOk/read preference connection. + * + * @return the reference to the address that points to a secondary connection. + */ + DBClientConnection& slaveConn(); + + // ---- callback pieces ------- + + virtual void say(Message& toSend, bool isRetry = false, std::string* actualServer = 0); + virtual bool recv(Message& toRecv); + virtual void checkResponse(const char* data, + int nReturned, + bool* retry = NULL, + std::string* targetHost = NULL); + + /* this is the callback from our underlying connections to notify us that we got a "not master" error. + */ + void isntMaster(); + + /* this is used to indicate we got a "not master or secondary" error from a secondary. + */ + void isntSecondary(); + + // ----- status ------ + + virtual bool isFailed() const { + return !_master || _master->isFailed(); + } + bool isStillConnected(); + + // ----- informational ---- + + /** + * Gets the replica set name of the set we are connected to. + */ + const std::string& getSetName() const { + return _setName; + } + + /** + * Returns the HostAndPort of the server this connection believes belongs to the primary, + * or returns an empty HostAndPort if it doesn't know about a current primary. + */ + HostAndPort getSuspectedPrimaryHostAndPort() const; + + double getSoTimeout() const { + return _so_timeout; + } + + std::string toString() const { + return getServerAddress(); + } + + std::string getServerAddress() const; + + virtual ConnectionString::ConnectionType type() const { + return ConnectionString::SET; + } + virtual bool lazySupported() const { + return true; + } + + rpc::UniqueReply runCommandWithMetadata(StringData database, + StringData command, + const BSONObj& metadata, + const BSONObj& commandArgs) final; + + void setRequestMetadataWriter(rpc::RequestMetadataWriter writer) final; + + void setReplyMetadataReader(rpc::ReplyMetadataReader reader) final; + // ---- low level ------ + + virtual bool call(Message& toSend, + Message& response, + bool assertOk = true, + std::string* actualServer = 0); + virtual bool callRead(Message& toSend, Message& response) { + return checkMaster()->callRead(toSend, response); + } + + /** + * Returns whether a query or command can be sent to secondaries based on the query object + * and options. + * + * @param ns the namespace of the query. + * @param queryObj the query object to check. + * @param queryOptions the query options + * + * @return true if the query/cmd could potentially be sent to a secondary, false otherwise + */ + static bool isSecondaryQuery(const std::string& ns, const BSONObj& queryObj, int queryOptions); + + /** + * Performs a "soft reset" by clearing all states relating to secondary nodes and + * returning secondary connections to the pool. + */ + virtual void reset(); + + /** + * @bool setting if true, DBClientReplicaSet connections will make sure that secondary + * connections are authenticated and log them before returning them to the pool. + */ + static void setAuthPooledSecondaryConn(bool setting); + +protected: + /** Authorize. Authorizes all nodes as needed */ - class DBClientReplicaSet : public DBClientBase { + virtual void _auth(const BSONObj& params); + + virtual void sayPiggyBack(Message& toSend) { + checkMaster()->say(toSend); + } + +private: + /** + * Used to simplify slave-handling logic on errors + * + * @return back the passed cursor + * @throws DBException if the directed node cannot accept the query because it + * is not a master + */ + std::unique_ptr<DBClientCursor> checkSlaveQueryResult(std::unique_ptr<DBClientCursor> result); + + DBClientConnection* checkMaster(); + + /** + * Helper method for selecting a node based on the read preference. Will advance + * the tag tags object if it cannot find a node that matches the current tag. + * + * @param readPref the preference to use for selecting a node. + * + * @return a pointer to the new connection object if it can find a good connection. + * Otherwise it returns NULL. + * + * @throws DBException when an error occurred either when trying to connect to + * a node that was thought to be ok or when an assertion happened. + */ + DBClientConnection* selectNodeUsingTags(std::shared_ptr<ReadPreferenceSetting> readPref); + + /** + * @return true if the last host used in the last slaveOk query is still in the + * set and can be used for the given read preference. + */ + bool checkLastHost(const ReadPreferenceSetting* readPref); + + /** + * Destroys all cached information about the last slaveOk operation. + */ + void invalidateLastSlaveOkCache(); + + void _auth(DBClientConnection* conn); + + /** + * Calls logout on the connection for all known database this DBClientRS instance has + * logged in. + */ + void logoutAll(DBClientConnection* conn); + + /** + * Clears the master connection. + */ + void resetMaster(); + + /** + * Clears the slaveOk connection and returns it to the pool if not the same as _master. + */ + void resetSlaveOkConn(); + + /** + * Maximum number of retries to make for auto-retry logic when performing a slave ok + * operation. + */ + static const size_t MAX_RETRY; + + // TODO: remove this when processes other than mongos uses the driver version. + static bool _authPooledSecondaryConn; + + // Throws a DBException if the monitor doesn't exist and there isn't a cached seed to use. + ReplicaSetMonitorPtr _getMonitor() const; + + std::string _setName; + + HostAndPort _masterHost; + std::unique_ptr<DBClientConnection> _master; + + // Last used host in a slaveOk query (can be a primary). + HostAndPort _lastSlaveOkHost; + // Last used connection in a slaveOk query (can be a primary). + // Connection can either be owned here or returned to the connection pool. Note that + // if connection is primary, it is owned by _master so it is incorrect to return + // it to the pool. + std::unique_ptr<DBClientConnection> _lastSlaveOkConn; + std::shared_ptr<ReadPreferenceSetting> _lastReadPref; + + double _so_timeout; + + // we need to store so that when we connect to a new node on failure + // we can re-auth + // this could be a security issue, as the password is stored in memory + // not sure if/how we should handle + std::map<std::string, BSONObj> _auths; // dbName -> auth parameters + +protected: + /** + * for storing (non-threadsafe) information between lazy calls + */ + class LazyState { public: - using DBClientBase::query; - using DBClientBase::update; - using DBClientBase::remove; - - /** Call connect() after constructing. autoReconnect is always on for DBClientReplicaSet connections. */ - DBClientReplicaSet( const std::string& name , const std::vector<HostAndPort>& servers, double so_timeout=0 ); - virtual ~DBClientReplicaSet(); - - /** - * Returns false if no member of the set were reachable. This object - * can still be used even when false was returned as it will try to - * reconnect when you use it later. - */ - bool connect(); - - /** - * Logs out the connection for the given database. - * - * @param dbname the database to logout from. - * @param info the result object for the logout command (provided for backwards - * compatibility with mongo shell) - */ - virtual void logout(const std::string& dbname, BSONObj& info); - - // ----------- simple functions -------------- - - /** throws userassertion "no master found" */ - virtual std::unique_ptr<DBClientCursor> query(const std::string &ns, Query query, int nToReturn = 0, int nToSkip = 0, - const BSONObj *fieldsToReturn = 0, int queryOptions = 0 , int batchSize = 0 ); - - /** throws userassertion "no master found" */ - virtual BSONObj findOne(const std::string &ns, const Query& query, const BSONObj *fieldsToReturn = 0, int queryOptions = 0); - - virtual void insert( const std::string &ns , BSONObj obj , int flags=0); - - /** 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 std::string &ns, const std::vector< BSONObj >& v , int flags=0); - - virtual void remove( const std::string &ns , Query obj , int flags ); - - virtual void update( const std::string &ns , Query query , BSONObj obj , int flags ); - - virtual void killCursor( long long cursorID ); - - // ---- access raw connections ---- - - /** - * WARNING: this method is very dangerous - this object can decide to free the - * returned master connection any time. - * - * @return the reference to the address that points to the master connection. - */ - DBClientConnection& masterConn(); - - /** - * WARNING: this method is very dangerous - this object can decide to free the - * returned master connection any time. This can also unpin the cached - * slaveOk/read preference connection. - * - * @return the reference to the address that points to a secondary connection. - */ - DBClientConnection& slaveConn(); - - // ---- callback pieces ------- - - virtual void say( Message &toSend, bool isRetry = false , std::string* actualServer = 0); - virtual bool recv( Message &toRecv ); - virtual void checkResponse( const char* data, int nReturned, bool* retry = NULL, std::string* targetHost = NULL ); - - /* this is the callback from our underlying connections to notify us that we got a "not master" error. - */ - void isntMaster(); - - /* this is used to indicate we got a "not master or secondary" error from a secondary. - */ - void isntSecondary(); - - // ----- status ------ - - virtual bool isFailed() const { return ! _master || _master->isFailed(); } - bool isStillConnected(); - - // ----- informational ---- - - /** - * Gets the replica set name of the set we are connected to. - */ - const std::string& getSetName() const { return _setName; } - - /** - * Returns the HostAndPort of the server this connection believes belongs to the primary, - * or returns an empty HostAndPort if it doesn't know about a current primary. - */ - HostAndPort getSuspectedPrimaryHostAndPort() const; - - double getSoTimeout() const { return _so_timeout; } - - std::string toString() const { return getServerAddress(); } - - std::string getServerAddress() const; - - virtual ConnectionString::ConnectionType type() const { return ConnectionString::SET; } - virtual bool lazySupported() const { return true; } - - rpc::UniqueReply runCommandWithMetadata(StringData database, - StringData command, - const BSONObj& metadata, - const BSONObj& commandArgs) final; - - void setRequestMetadataWriter(rpc::RequestMetadataWriter writer) final; - - void setReplyMetadataReader(rpc::ReplyMetadataReader reader) final; - // ---- low level ------ - - virtual bool call( Message &toSend, Message &response, bool assertOk=true , std::string * actualServer = 0 ); - virtual bool callRead( Message& toSend , Message& response ) { return checkMaster()->callRead( toSend , response ); } - - /** - * Returns whether a query or command can be sent to secondaries based on the query object - * and options. - * - * @param ns the namespace of the query. - * @param queryObj the query object to check. - * @param queryOptions the query options - * - * @return true if the query/cmd could potentially be sent to a secondary, false otherwise - */ - static bool isSecondaryQuery( const std::string& ns, - const BSONObj& queryObj, - int queryOptions ); - - /** - * Performs a "soft reset" by clearing all states relating to secondary nodes and - * returning secondary connections to the pool. - */ - virtual void reset(); - - /** - * @bool setting if true, DBClientReplicaSet connections will make sure that secondary - * connections are authenticated and log them before returning them to the pool. - */ - static void setAuthPooledSecondaryConn(bool setting); - - protected: - /** Authorize. Authorizes all nodes as needed - */ - virtual void _auth(const BSONObj& params); - - virtual void sayPiggyBack( Message &toSend ) { checkMaster()->say( toSend ); } - - private: - /** - * Used to simplify slave-handling logic on errors - * - * @return back the passed cursor - * @throws DBException if the directed node cannot accept the query because it - * is not a master - */ - std::unique_ptr<DBClientCursor> checkSlaveQueryResult( std::unique_ptr<DBClientCursor> result ); - - DBClientConnection * checkMaster(); - - /** - * Helper method for selecting a node based on the read preference. Will advance - * the tag tags object if it cannot find a node that matches the current tag. - * - * @param readPref the preference to use for selecting a node. - * - * @return a pointer to the new connection object if it can find a good connection. - * Otherwise it returns NULL. - * - * @throws DBException when an error occurred either when trying to connect to - * a node that was thought to be ok or when an assertion happened. - */ - DBClientConnection* selectNodeUsingTags(std::shared_ptr<ReadPreferenceSetting> readPref); - - /** - * @return true if the last host used in the last slaveOk query is still in the - * set and can be used for the given read preference. - */ - bool checkLastHost(const ReadPreferenceSetting* readPref); - - /** - * Destroys all cached information about the last slaveOk operation. - */ - void invalidateLastSlaveOkCache(); - - void _auth( DBClientConnection * conn ); - - /** - * Calls logout on the connection for all known database this DBClientRS instance has - * logged in. - */ - void logoutAll(DBClientConnection* conn); - - /** - * Clears the master connection. - */ - void resetMaster(); - - /** - * Clears the slaveOk connection and returns it to the pool if not the same as _master. - */ - void resetSlaveOkConn(); - - /** - * Maximum number of retries to make for auto-retry logic when performing a slave ok - * operation. - */ - static const size_t MAX_RETRY; - - // TODO: remove this when processes other than mongos uses the driver version. - static bool _authPooledSecondaryConn; - - // Throws a DBException if the monitor doesn't exist and there isn't a cached seed to use. - ReplicaSetMonitorPtr _getMonitor() const; - - std::string _setName; - - HostAndPort _masterHost; - std::unique_ptr<DBClientConnection> _master; - - // Last used host in a slaveOk query (can be a primary). - HostAndPort _lastSlaveOkHost; - // Last used connection in a slaveOk query (can be a primary). - // Connection can either be owned here or returned to the connection pool. Note that - // if connection is primary, it is owned by _master so it is incorrect to return - // it to the pool. - std::unique_ptr<DBClientConnection> _lastSlaveOkConn; - std::shared_ptr<ReadPreferenceSetting> _lastReadPref; - - double _so_timeout; - - // we need to store so that when we connect to a new node on failure - // we can re-auth - // this could be a security issue, as the password is stored in memory - // not sure if/how we should handle - std::map<std::string, BSONObj> _auths; // dbName -> auth parameters - - protected: - - /** - * for storing (non-threadsafe) information between lazy calls - */ - class LazyState { - public: - LazyState() : - _lastClient( NULL ), _lastOp( -1 ), _secondaryQueryOk( false ), _retries( 0 ) {} - DBClientConnection* _lastClient; - int _lastOp; - bool _secondaryQueryOk; - int _retries; - - } _lazyState; - - }; - + LazyState() : _lastClient(NULL), _lastOp(-1), _secondaryQueryOk(false), _retries(0) {} + DBClientConnection* _lastClient; + int _lastOp; + bool _secondaryQueryOk; + int _retries; + + } _lazyState; +}; } |