324 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			324 lines
		
	
	
		
			11 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 "mariadbmon_common.hh"
 | 
						|
 | 
						|
#include <string>
 | 
						|
#include <vector>
 | 
						|
#include <maxbase/stopwatch.hh>
 | 
						|
#include <maxscale/mysql_utils.hh>
 | 
						|
 | 
						|
class MariaDBServer;
 | 
						|
 | 
						|
/**
 | 
						|
 * Class which encapsulates a gtid (one domain-server_id-sequence combination)
 | 
						|
 */
 | 
						|
class Gtid
 | 
						|
{
 | 
						|
public:
 | 
						|
 | 
						|
    /**
 | 
						|
     * Constructs an invalid Gtid.
 | 
						|
     */
 | 
						|
    Gtid();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Constructs a gtid with given values. The values are not checked.
 | 
						|
     *
 | 
						|
     * @param domain Domain
 | 
						|
     * @param server_id Server id
 | 
						|
     * @param sequence Sequence
 | 
						|
     */
 | 
						|
    Gtid(uint32_t domain, int64_t server_id, uint64_t sequence);
 | 
						|
 | 
						|
    /**
 | 
						|
     * Parse one gtid from null-terminated string. Handles multi-domain gtid:s properly. Should be called
 | 
						|
     * repeatedly for a multi-domain gtid string by giving the value of @c endptr as @c str.
 | 
						|
     *
 | 
						|
     * @param str First number of a gtid in a gtid-string
 | 
						|
     * @param endptr A pointer to save the position at after the last parsed character.
 | 
						|
     * @return A new gtid. If an error occurs, the server_id of the returned triplet is -1.
 | 
						|
     */
 | 
						|
    static Gtid from_string(const char* str, char** endptr);
 | 
						|
 | 
						|
    bool eq(const Gtid& rhs) const;
 | 
						|
 | 
						|
    std::string to_string() const;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Comparator, used when sorting by domain id.
 | 
						|
     *
 | 
						|
     * @param lhs Left side
 | 
						|
     * @param rhs Right side
 | 
						|
     * @return True if lhs should be before rhs
 | 
						|
     */
 | 
						|
    static bool compare_domains(const Gtid& lhs, const Gtid& rhs)
 | 
						|
    {
 | 
						|
        return lhs.m_domain < rhs.m_domain;
 | 
						|
    }
 | 
						|
 | 
						|
    uint32_t m_domain;
 | 
						|
    int64_t  m_server_id;   // Valid values are 32bit unsigned. 0 is only used by server versions  <= 10.1
 | 
						|
    uint64_t m_sequence;
 | 
						|
};
 | 
						|
 | 
						|
inline bool operator==(const Gtid& lhs, const Gtid& rhs)
 | 
						|
{
 | 
						|
    return lhs.eq(rhs);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Class which encapsulates a list of gtid:s (e.g. 1-2-3,2-2-4). Server variables such as gtid_binlog_pos
 | 
						|
 * are GtidLists. */
 | 
						|
class GtidList
 | 
						|
{
 | 
						|
public:
 | 
						|
 | 
						|
    // Used with events_ahead()
 | 
						|
    enum substraction_mode_t
 | 
						|
    {
 | 
						|
        MISSING_DOMAIN_IGNORE,
 | 
						|
        MISSING_DOMAIN_LHS_ADD
 | 
						|
    };
 | 
						|
 | 
						|
    /**
 | 
						|
     * Parse the gtid string and return an object. Orders the triplets by domain id.
 | 
						|
     *
 | 
						|
     * @param gtid_string gtid as given by server. String must not be empty.
 | 
						|
     * @return The parsed (possibly multidomain) gtid. In case of error, the gtid will be empty.
 | 
						|
     */
 | 
						|
    static GtidList from_string(const std::string& gtid_string);
 | 
						|
 | 
						|
    /**
 | 
						|
     * Return a string version of the gtid list.
 | 
						|
     *
 | 
						|
     * @return A string similar in form to how the server displays gtid:s
 | 
						|
     */
 | 
						|
    std::string to_string() const;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Check if a server with this gtid can replicate from a master with a given gtid. Only considers
 | 
						|
     * gtid:s and only detects obvious errors. The non-detected errors will mostly be detected once
 | 
						|
     * the slave tries to start replicating.
 | 
						|
     *
 | 
						|
     * TODO: Add support for Replicate_Do/Ignore_Id:s
 | 
						|
     *
 | 
						|
     * @param master_gtid Master server gtid
 | 
						|
     * @return True if replication looks possible
 | 
						|
     */
 | 
						|
    bool can_replicate_from(const GtidList& master_gtid);
 | 
						|
 | 
						|
    /**
 | 
						|
     * Is the gtid empty.
 | 
						|
     *
 | 
						|
     * @return True if gtid has 0 triplets
 | 
						|
     */
 | 
						|
    bool empty() const;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Full comparison.
 | 
						|
     *
 | 
						|
     * @param rhs Other gtid
 | 
						|
     * @return True if both gtid:s have identical triplets or both are empty
 | 
						|
     */
 | 
						|
    bool operator==(const GtidList& rhs) const;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Calculate the number of events this GtidList is ahead of the given GtidList. The
 | 
						|
     * result is always 0 or greater: if a sequence number of a domain on rhs is greater than on the same
 | 
						|
     * domain on the calling GtidList, the sequences are considered identical. Missing domains are
 | 
						|
     * handled depending on the value of @c domain_substraction_mode.
 | 
						|
     *
 | 
						|
     * @param rhs The value doing the substracting
 | 
						|
     * @param domain_substraction_mode How domains that exist on the caller but not on @c rhs are handled.
 | 
						|
     * If MISSING_DOMAIN_IGNORE, these are simply ignored. If MISSING_DOMAIN_LHS_ADD,
 | 
						|
     * the sequence number on lhs is added to the total difference.
 | 
						|
     * @return The number of events between the two gtid:s
 | 
						|
     */
 | 
						|
    uint64_t events_ahead(const GtidList& rhs, substraction_mode_t domain_substraction_mode) const;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Return an individual gtid with the given domain.
 | 
						|
     *
 | 
						|
     * @param domain Which domain to search for
 | 
						|
     * @return The gtid within the list. If domain is not found, an invalid gtid is returned.
 | 
						|
     */
 | 
						|
    Gtid get_gtid(uint32_t domain) const;
 | 
						|
 | 
						|
private:
 | 
						|
    std::vector<Gtid> m_triplets;
 | 
						|
};
 | 
						|
 | 
						|
// Contains data returned by one row of SHOW ALL SLAVES STATUS
 | 
						|
class SlaveStatus
 | 
						|
{
 | 
						|
public:
 | 
						|
    enum slave_io_running_t
 | 
						|
    {
 | 
						|
        SLAVE_IO_YES,
 | 
						|
        SLAVE_IO_CONNECTING,
 | 
						|
        SLAVE_IO_NO,
 | 
						|
    };
 | 
						|
 | 
						|
    std::string owning_server;                          /* Server name of the owner */
 | 
						|
    bool        seen_connected = false;                 /* Has this slave connection been seen connected,
 | 
						|
                                                         * meaning that the master server id is correct? */
 | 
						|
    std::string name;                                   /* Slave connection name. Must be unique for
 | 
						|
                                                         * the server.*/
 | 
						|
    int64_t master_server_id = SERVER_ID_UNKNOWN;       /* The master's server_id value. Valid ids are
 | 
						|
                                                         * 32bit unsigned. -1 is unread/error. */
 | 
						|
    std::string        master_host;                     /* Master server host name. */
 | 
						|
    int                master_port = PORT_UNKNOWN;      /* Master server port. */
 | 
						|
    slave_io_running_t slave_io_running = SLAVE_IO_NO;  /* Slave I/O thread running state: * "Yes",
 | 
						|
                                                         * "Connecting" or "No" */
 | 
						|
    bool        slave_sql_running = false;              /* Slave SQL thread running state, true if "Yes" */
 | 
						|
    GtidList    gtid_io_pos;                            /* Gtid I/O position of the slave thread. */
 | 
						|
    std::string last_error;                             /* Last IO or SQL error encountered. */
 | 
						|
    int64_t     received_heartbeats = 0;                /* How many heartbeats the connection has
 | 
						|
                                                         * received */
 | 
						|
 | 
						|
    int seconds_behind_master = SERVER::RLAG_UNDEFINED;     /* How much behind the slave is. */
 | 
						|
 | 
						|
    /* Time of the latest gtid event or heartbeat the slave connection has received, timed by the monitor. */
 | 
						|
    maxbase::Clock::time_point last_data_time = maxbase::Clock::now();
 | 
						|
 | 
						|
    std::string to_string() const;
 | 
						|
    json_t*     to_json() const;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Create a short description in the form of "Slave connection from <slave> to <master>"
 | 
						|
     *
 | 
						|
     * @return Description
 | 
						|
     */
 | 
						|
    std::string to_short_string() const;
 | 
						|
 | 
						|
    static slave_io_running_t slave_io_from_string(const std::string& str);
 | 
						|
    static std::string        slave_io_to_string(slave_io_running_t slave_io);
 | 
						|
    bool                      should_be_copied(std::string* ignore_reason_out) const;
 | 
						|
};
 | 
						|
 | 
						|
typedef std::vector<SlaveStatus> SlaveStatusArray;
 | 
						|
 | 
						|
enum class OperationType
 | 
						|
{
 | 
						|
    SWITCHOVER,
 | 
						|
    FAILOVER
 | 
						|
};
 | 
						|
 | 
						|
class GeneralOpData
 | 
						|
{
 | 
						|
public:
 | 
						|
    const std::string replication_user;             // User for CHANGE MASTER TO ...
 | 
						|
    const std::string replication_password;         // Password for CHANGE MASTER TO ...
 | 
						|
    json_t** const    error_out;                    // Json error output
 | 
						|
    maxbase::Duration time_remaining;               // How much time remains to complete the operation
 | 
						|
 | 
						|
    GeneralOpData(const std::string& replication_user, const std::string& replication_password,
 | 
						|
                  json_t** error, maxbase::Duration time_remaining);
 | 
						|
};
 | 
						|
 | 
						|
// Operation data which concerns a single server
 | 
						|
class ServerOperation
 | 
						|
{
 | 
						|
public:
 | 
						|
    MariaDBServer* const   target;          // Target server
 | 
						|
    const bool             to_from_master;  // Was the target a master / should it become one
 | 
						|
    const bool             handle_events;   // Should scheduled server events be disabled/enabled?
 | 
						|
    const std::string      sql_file;        // Path to file with SQL commands to run during op
 | 
						|
    const SlaveStatusArray conns_to_copy;   // Slave connections the target should copy/merge
 | 
						|
 | 
						|
    ServerOperation(MariaDBServer* target, bool was_is_master, bool handle_events,
 | 
						|
                    const std::string& sql_file, const SlaveStatusArray& conns_to_copy);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Helper class for simplifying working with resultsets. Used in MariaDBServer.
 | 
						|
 */
 | 
						|
class QueryResult
 | 
						|
{
 | 
						|
    // These need to be banned to avoid premature destruction.
 | 
						|
    QueryResult(const QueryResult&) = delete;
 | 
						|
    QueryResult& operator=(const QueryResult&) = delete;
 | 
						|
 | 
						|
public:
 | 
						|
    QueryResult(MYSQL_RES* resultset = NULL);
 | 
						|
    ~QueryResult();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Advance to next row. Affects all result returning functions.
 | 
						|
     *
 | 
						|
     * @return True if the next row has data, false if the current row was the last one.
 | 
						|
     */
 | 
						|
    bool next_row();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the index of the current row.
 | 
						|
     *
 | 
						|
     * @return Current row index, or -1 if no data or next_row() has not been called yet.
 | 
						|
     */
 | 
						|
    int64_t get_current_row_index() const;
 | 
						|
 | 
						|
    /**
 | 
						|
     * How many columns the result set has.
 | 
						|
     *
 | 
						|
     * @return Column count, or -1 if no data.
 | 
						|
     */
 | 
						|
    int64_t get_col_count() const;
 | 
						|
 | 
						|
    /**
 | 
						|
     * How many rows does the result set have?
 | 
						|
     *
 | 
						|
     * @return The number of rows or -1 on error
 | 
						|
     */
 | 
						|
    int64_t get_row_count() const;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get a numeric index for a column name. May give wrong results if column names are not unique.
 | 
						|
     *
 | 
						|
     * @param col_name Column name
 | 
						|
     * @return Index or -1 if not found.
 | 
						|
     */
 | 
						|
    int64_t get_col_index(const std::string& col_name) const;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Read a string value from the current row and given column. Empty string and (null) are both interpreted
 | 
						|
     * as the empty string.
 | 
						|
     *
 | 
						|
     * @param column_ind Column index
 | 
						|
     * @return Value as string
 | 
						|
     */
 | 
						|
    std::string get_string(int64_t column_ind) const;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Read a non-negative integer value from the current row and given column.
 | 
						|
     *
 | 
						|
     * @param column_ind Column index
 | 
						|
     * @return Value as integer. 0 or greater indicates success, -1 is returned on error.
 | 
						|
     */
 | 
						|
    int64_t get_uint(int64_t column_ind) const;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Read a boolean value from the current row and given column.
 | 
						|
     *
 | 
						|
     * @param column_ind Column index
 | 
						|
     * @return Value as boolean. Returns true if the text is either 'Y' or '1'.
 | 
						|
     */
 | 
						|
    bool get_bool(int64_t column_ind) const;
 | 
						|
 | 
						|
private:
 | 
						|
    MYSQL_RES*                               m_resultset = NULL;    // Underlying result set, freed at dtor.
 | 
						|
    std::unordered_map<std::string, int64_t> m_col_indexes;         // Map of column name -> index
 | 
						|
    MYSQL_ROW                                m_rowdata = NULL;      // Data for current row
 | 
						|
    int64_t                                  m_current_row_ind = -1;// Index of current row
 | 
						|
};
 |