376 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			376 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2018 MariaDB Corporation Ab
 | |
|  *
 | |
|  * Use of this software is governed by the Business Source License included
 | |
|  * in the LICENSE.TXT file and at www.mariadb.com/bsl11.
 | |
|  *
 | |
|  * Change Date: 2022-01-01
 | |
|  *
 | |
|  * On the date above, in accordance with the Business Source License, use
 | |
|  * of this software will be governed by version 2 or later of the General
 | |
|  * Public License.
 | |
|  */
 | |
| #pragma once
 | |
| 
 | |
| #include <maxscale/ccdefs.hh>
 | |
| 
 | |
| #include <list>
 | |
| #include <string>
 | |
| #include <memory>
 | |
| 
 | |
| #include <maxscale/service.hh>
 | |
| #include <maxscale/session_command.hh>
 | |
| #include <maxbase/stopwatch.hh>
 | |
| 
 | |
| 
 | |
| namespace maxscale
 | |
| {
 | |
| 
 | |
| 
 | |
| class Backend
 | |
| {
 | |
|     Backend(const Backend&);
 | |
|     Backend& operator=(const Backend&);
 | |
| public:
 | |
| 
 | |
|     /**
 | |
|      * How is the backend being closed
 | |
|      */
 | |
|     enum close_type
 | |
|     {
 | |
|         CLOSE_NORMAL,
 | |
|         CLOSE_FATAL
 | |
|     };
 | |
| 
 | |
|     /**
 | |
|      * What type of a response we expect from the backend
 | |
|      */
 | |
|     enum response_type
 | |
|     {
 | |
|         EXPECT_RESPONSE,
 | |
|         NO_RESPONSE
 | |
|     };
 | |
| 
 | |
|     /**
 | |
|      * @brief Create new Backend
 | |
|      *
 | |
|      * @param ref Server reference used by this backend
 | |
|      */
 | |
|     Backend(SERVER_REF* ref);
 | |
| 
 | |
|     virtual ~Backend();
 | |
| 
 | |
|     /**
 | |
|      * @brief Execute the next session command in the queue
 | |
|      *
 | |
|      * @return True if the command was executed successfully
 | |
|      */
 | |
|     virtual bool execute_session_command();
 | |
| 
 | |
|     /**
 | |
|      * @brief Add a new session command to the tail of the command queue
 | |
|      *
 | |
|      * @param buffer   Session command to add
 | |
|      * @param sequence Sequence identifier of this session command, returned when
 | |
|      *                 the session command is completed
 | |
|      */
 | |
|     void append_session_command(GWBUF* buffer, uint64_t sequence);
 | |
|     void append_session_command(const SSessionCommand& sescmd);
 | |
|     void append_session_command(const SessionCommandList& sescmdlist);
 | |
| 
 | |
|     /**
 | |
|      * @brief Mark the current session command as successfully executed
 | |
|      *
 | |
|      * This should be called when the response to the command is received
 | |
|      *
 | |
|      * @return The sequence identifier for this session command
 | |
|      */
 | |
|     uint64_t complete_session_command();
 | |
| 
 | |
|     /**
 | |
|      * @brief Get number of session commands
 | |
|      *
 | |
|      * @return Number of session commands
 | |
|      */
 | |
|     size_t session_command_count() const;
 | |
| 
 | |
|     /**
 | |
|      * @brief Check if there are session commands waiting to be executed
 | |
|      *
 | |
|      * @return True if there are session commands waiting to be executed
 | |
|      */
 | |
|     inline bool has_session_commands() const
 | |
|     {
 | |
|         mxb_assert(in_use());
 | |
|         return !m_session_commands.empty();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @brief Get the first session command
 | |
|      *
 | |
|      * Returns the first session command in the list of session commands
 | |
|      * to be executed.
 | |
|      *
 | |
|      * This should only be called when at least one session command has been
 | |
|      * added to the backend. If no session commands have been added, behavior
 | |
|      * is undefined.
 | |
|      *
 | |
|      * @return The first session command
 | |
|      */
 | |
|     const SSessionCommand& next_session_command() const;
 | |
| 
 | |
|     /**
 | |
|      * @brief Get pointer to server reference
 | |
|      *
 | |
|      * @return Pointer to server reference
 | |
|      */
 | |
|     inline SERVER_REF* backend() const
 | |
|     {
 | |
|         mxb_assert(m_backend);
 | |
|         return m_backend;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @brief Get pointer to server
 | |
|      *
 | |
|      * @return Pointer to server
 | |
|      */
 | |
|     inline SERVER* server() const
 | |
|     {
 | |
|         mxb_assert(m_backend);
 | |
|         return m_backend->server;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @brief Check if a connection to this backend can be made
 | |
|      *
 | |
|      * @return True if the backend has not failed and a connection can be attempted
 | |
|      */
 | |
|     inline bool can_connect() const
 | |
|     {
 | |
|         return !has_failed() && server_is_usable(m_backend->server);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @brief Create a new connection
 | |
|      *
 | |
|      * @param session The session to which the connection is linked
 | |
|      * @param sescmd  Pointer to a list of session commands to execute
 | |
|      *
 | |
|      * @return True if connection was successfully created
 | |
|      */
 | |
|     bool connect(MXS_SESSION* session, SessionCommandList* sescmd = NULL);
 | |
| 
 | |
|     /**
 | |
|      * @brief Close the backend
 | |
|      *
 | |
|      * This will close all active connections created by the backend.
 | |
|      */
 | |
|     virtual void close(close_type type = CLOSE_NORMAL);
 | |
| 
 | |
|     /**
 | |
|      * @brief Get a pointer to the internal DCB
 | |
|      *
 | |
|      * @return Pointer to DCB or NULL if not connected
 | |
|      */
 | |
|     inline DCB* dcb() const
 | |
|     {
 | |
|         return m_dcb;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @brief Write data to the backend server
 | |
|      *
 | |
|      * @param buffer          Buffer containing the data to write
 | |
|      * @param expect_response Whether to expect a response to the query
 | |
|      *
 | |
|      * @return True if data was written successfully
 | |
|      */
 | |
|     virtual bool write(GWBUF* buffer, response_type type = EXPECT_RESPONSE);
 | |
| 
 | |
|     /**
 | |
|      * @brief Write an authentication switch request to the backend server
 | |
|      *
 | |
|      * @param buffer Buffer containing the authentication switch request
 | |
|      *
 | |
|      * @return True if request was successfully written
 | |
|      */
 | |
|     bool auth(GWBUF* buffer);
 | |
| 
 | |
|     /**
 | |
|      * @brief Mark that a reply to a query was received and processed
 | |
|      */
 | |
|     void ack_write();
 | |
| 
 | |
|     /**
 | |
|      * @brief Store a command
 | |
|      *
 | |
|      * The command is stored and executed once the session can execute
 | |
|      * the next command.
 | |
|      *
 | |
|      * @param buffer Buffer to store
 | |
|      */
 | |
|     void store_command(GWBUF* buffer);
 | |
| 
 | |
|     /**
 | |
|      * @brief Write the stored command to the backend server
 | |
|      *
 | |
|      * @return True if command was written successfully
 | |
|      */
 | |
|     bool write_stored_command();
 | |
| 
 | |
|     /**
 | |
|      * @brief Check if backend is in use
 | |
|      *
 | |
|      * @return True if backend is in use
 | |
|      */
 | |
|     inline bool in_use() const
 | |
|     {
 | |
|         return m_state & IN_USE;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @brief Check if the backend server reference is active
 | |
|      *
 | |
|      * @return True if the server reference is active
 | |
|      */
 | |
|     inline bool is_active() const
 | |
|     {
 | |
|         return SERVER_REF_IS_ACTIVE(m_backend);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @brief Check if backend is waiting for a result
 | |
|      *
 | |
|      * @return True if backend is waiting for a result
 | |
|      */
 | |
|     inline bool is_waiting_result() const
 | |
|     {
 | |
|         return m_state & WAITING_RESULT;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @brief Check if the backend is closed
 | |
|      *
 | |
|      * @return True if the backend is closed
 | |
|      */
 | |
|     inline bool is_closed() const
 | |
|     {
 | |
|         return m_closed;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @brief Check if the server is a master
 | |
|      *
 | |
|      * @return True if server is a master
 | |
|      */
 | |
|     inline bool is_master() const
 | |
|     {
 | |
|         return server_is_master(m_backend->server);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @brief Check if the server is a slave
 | |
|      *
 | |
|      * @return True if the server is a slave
 | |
|      */
 | |
|     inline bool is_slave() const
 | |
|     {
 | |
|         return server_is_slave(m_backend->server);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @brief Check if the server is a relay server
 | |
|      *
 | |
|      * @return True if the server is a relay server
 | |
|      */
 | |
|     inline bool is_relay() const
 | |
|     {
 | |
|         return server_is_relay(m_backend->server);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @brief Check if the backend has failed fatally
 | |
|      *
 | |
|      * When a fatal failure occurs in a backend, the backend server can no longer
 | |
|      * be used by this session. Fatal failures can occur when the execution of
 | |
|      * a session command fails on the backend but the expected result is different.
 | |
|      *
 | |
|      * @return True if a fatal failure has occurred in the backend server
 | |
|      */
 | |
|     inline bool has_failed() const
 | |
|     {
 | |
|         return m_state & FATAL_FAILURE;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /**
 | |
|      * @brief Get the object name of this server
 | |
|      *
 | |
|      * @return The unique object name of this server
 | |
|      */
 | |
|     inline const char* name() const
 | |
|     {
 | |
|         return m_backend->server->name;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @brief Get the address and port as a string
 | |
|      *
 | |
|      * @return The address and port combined into one string
 | |
|      */
 | |
|     inline const char* uri() const
 | |
|     {
 | |
|         return m_uri.c_str();
 | |
|     }
 | |
| 
 | |
|     void select_started();
 | |
|     void select_ended();
 | |
| 
 | |
|     int64_t                       num_selects() const;
 | |
|     const maxbase::StopWatch&     session_timer() const;
 | |
|     const maxbase::IntervalTimer& select_timer() const;
 | |
| private:
 | |
|     /**
 | |
|      * Internal state of the backend
 | |
|      */
 | |
|     enum backend_state
 | |
|     {
 | |
|         IN_USE         = 0x01,  /**< Backend has been taken into use */
 | |
|         WAITING_RESULT = 0x02,  /**< Waiting for a reply */
 | |
|         FATAL_FAILURE  = 0x04   /**< Backend references that should be dropped */
 | |
|     };
 | |
| 
 | |
|     /**
 | |
|      * @brief Clear state
 | |
|      *
 | |
|      * @param state State to clear
 | |
|      */
 | |
|     void clear_state(backend_state state);
 | |
| 
 | |
|     /**
 | |
|      * @brief Set state
 | |
|      *
 | |
|      * @param state State to set
 | |
|      */
 | |
|     void set_state(backend_state state);
 | |
| 
 | |
| 
 | |
|     bool               m_closed;            /**< True if a connection has been opened and closed */
 | |
|     SERVER_REF*        m_backend;           /**< Backend server */
 | |
|     DCB*               m_dcb;               /**< Backend DCB */
 | |
|     mxs::Buffer        m_pending_cmd;       /**< Pending commands */
 | |
|     int                m_state;             /**< State of the backend */
 | |
|     SessionCommandList m_session_commands;  /**< List of session commands that are
 | |
|                                              * to be executed on this backend server */
 | |
|     std::string m_uri;                      /**< The combined address and port */
 | |
| 
 | |
|     maxbase::StopWatch     m_session_timer;
 | |
|     maxbase::IntervalTimer m_select_timer;
 | |
|     int64_t                m_num_selects = 0;
 | |
| };
 | |
| 
 | |
| typedef std::shared_ptr<Backend> SBackend;
 | |
| typedef std::list<SBackend>      BackendList;
 | |
| }
 | 
