211 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			5.9 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: 2020-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.
 | 
						|
 */
 | 
						|
 | 
						|
#include "utilities.hh"
 | 
						|
 | 
						|
#include <inttypes.h>
 | 
						|
#include <limits>
 | 
						|
#include <stdio.h>
 | 
						|
#include <string>
 | 
						|
#include <sstream>
 | 
						|
#include <maxscale/debug.h>
 | 
						|
#include <maxscale/mysql_utils.h>
 | 
						|
 | 
						|
/** Server id default value */
 | 
						|
const int64_t SERVER_ID_UNKNOWN = -1;
 | 
						|
 | 
						|
Gtid::Gtid()
 | 
						|
    : domain(0)
 | 
						|
    , server_id(SERVER_ID_UNKNOWN)
 | 
						|
    , sequence(0)
 | 
						|
{}
 | 
						|
 | 
						|
Gtid::Gtid(const char* str, int64_t search_domain)
 | 
						|
    : domain(0)
 | 
						|
    , server_id(SERVER_ID_UNKNOWN)
 | 
						|
    , sequence(0)
 | 
						|
{
 | 
						|
    // Autoselect only allowed with one triplet
 | 
						|
    ss_dassert(search_domain >= 0 || strchr(str, ',') == NULL);
 | 
						|
    parse_triplet(str);
 | 
						|
    if (search_domain >= 0 && domain != search_domain)
 | 
						|
    {
 | 
						|
        // Search for the correct triplet.
 | 
						|
        bool found = false;
 | 
						|
        for (const char* next_triplet = strchr(str, ',');
 | 
						|
             next_triplet != NULL && !found;
 | 
						|
             next_triplet = strchr(next_triplet, ','))
 | 
						|
        {
 | 
						|
            parse_triplet(++next_triplet);
 | 
						|
            if (domain == search_domain)
 | 
						|
            {
 | 
						|
                found = true;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        ss_dassert(found);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
bool Gtid::operator == (const Gtid& rhs) const
 | 
						|
{
 | 
						|
    return domain == rhs.domain &&
 | 
						|
        server_id != SERVER_ID_UNKNOWN && server_id == rhs.server_id &&
 | 
						|
        sequence == rhs.sequence;
 | 
						|
}
 | 
						|
 | 
						|
string Gtid::to_string() const
 | 
						|
{
 | 
						|
    std::stringstream ss;
 | 
						|
    if (server_id != SERVER_ID_UNKNOWN)
 | 
						|
    {
 | 
						|
        ss << domain << "-" << server_id << "-" << sequence;
 | 
						|
    }
 | 
						|
    return ss.str();
 | 
						|
}
 | 
						|
 | 
						|
void Gtid::parse_triplet(const char* str)
 | 
						|
{
 | 
						|
    ss_debug(int rv = ) sscanf(str, "%" PRIu32 "-%" PRId64 "-%" PRIu64, &domain, &server_id, &sequence);
 | 
						|
    ss_dassert(rv == 3);
 | 
						|
}
 | 
						|
 | 
						|
SlaveStatusInfo::SlaveStatusInfo()
 | 
						|
    : master_server_id(SERVER_ID_UNKNOWN)
 | 
						|
    , master_port(0)
 | 
						|
    , slave_io_running(false)
 | 
						|
    , slave_sql_running(false)
 | 
						|
    , read_master_log_pos(0)
 | 
						|
{}
 | 
						|
 | 
						|
MySqlServerInfo::MySqlServerInfo()
 | 
						|
    : server_id(SERVER_ID_UNKNOWN)
 | 
						|
    , group(0)
 | 
						|
    , read_only(false)
 | 
						|
    , slave_configured(false)
 | 
						|
    , binlog_relay(false)
 | 
						|
    , n_slaves_configured(0)
 | 
						|
    , n_slaves_running(0)
 | 
						|
    , slave_heartbeats(0)
 | 
						|
    , heartbeat_period(0)
 | 
						|
    , latest_event(0)
 | 
						|
    , gtid_domain_id(-1)
 | 
						|
    , version(MYSQL_SERVER_VERSION_51)
 | 
						|
{}
 | 
						|
 | 
						|
int64_t MySqlServerInfo::relay_log_events()
 | 
						|
{
 | 
						|
    if (slave_status.gtid_io_pos.server_id != SERVER_ID_UNKNOWN &&
 | 
						|
        gtid_current_pos.server_id != SERVER_ID_UNKNOWN &&
 | 
						|
        slave_status.gtid_io_pos.domain == gtid_current_pos.domain &&
 | 
						|
        slave_status.gtid_io_pos.sequence >= gtid_current_pos.sequence)
 | 
						|
    {
 | 
						|
        return slave_status.gtid_io_pos.sequence - gtid_current_pos.sequence;
 | 
						|
    }
 | 
						|
    return -1;
 | 
						|
}
 | 
						|
 | 
						|
int64_t scan_server_id(const char* id_string)
 | 
						|
{
 | 
						|
    int64_t server_id = SERVER_ID_UNKNOWN;
 | 
						|
    ss_debug(int rv = ) sscanf(id_string, "%" PRId64, &server_id);
 | 
						|
    ss_dassert(rv == 1);
 | 
						|
    // Server id can be 0, which was even the default value until 10.2.1.
 | 
						|
    // KB is a bit hazy on this, but apparently when replicating, the server id should not be 0. Not sure,
 | 
						|
    // so MaxScale allows this.
 | 
						|
#if defined(SS_DEBUG)
 | 
						|
    const int64_t SERVER_ID_MIN = std::numeric_limits<uint32_t>::min();
 | 
						|
    const int64_t SERVER_ID_MAX = std::numeric_limits<uint32_t>::max();
 | 
						|
#endif
 | 
						|
    ss_dassert(server_id >= SERVER_ID_MIN && server_id <= SERVER_ID_MAX);
 | 
						|
    return server_id;
 | 
						|
}
 | 
						|
 | 
						|
string generate_master_gtid_wait_cmd(const Gtid& gtid, double timeout)
 | 
						|
{
 | 
						|
    std::stringstream query_ss;
 | 
						|
    query_ss << "SELECT MASTER_GTID_WAIT(\"" << gtid.to_string() << "\", " << timeout << ");";
 | 
						|
    return query_ss.str();
 | 
						|
}
 | 
						|
 | 
						|
bool query_one_row(MXS_MONITORED_SERVER *database, const char* query, unsigned int expected_cols,
 | 
						|
                   StringVector* output)
 | 
						|
{
 | 
						|
    bool rval = false;
 | 
						|
    MYSQL_RES *result;
 | 
						|
    if (mxs_mysql_query(database->con, query) == 0 && (result = mysql_store_result(database->con)) != NULL)
 | 
						|
    {
 | 
						|
        unsigned int columns = mysql_field_count(database->con);
 | 
						|
        if (columns != expected_cols)
 | 
						|
        {
 | 
						|
            mysql_free_result(result);
 | 
						|
            MXS_ERROR("Unexpected result for '%s'. Expected %d columns, got %d. Server version: %s",
 | 
						|
                      query, expected_cols, columns, database->server->version_string);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            MYSQL_ROW row = mysql_fetch_row(result);
 | 
						|
            if (row)
 | 
						|
            {
 | 
						|
                for (unsigned int i = 0; i < columns; i++)
 | 
						|
                {
 | 
						|
                    output->push_back((row[i] != NULL) ? row[i] : "");
 | 
						|
                }
 | 
						|
                rval = true;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                MXS_ERROR("Query '%s' returned no rows.", query);
 | 
						|
            }
 | 
						|
            mysql_free_result(result);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        mon_report_query_error(database);
 | 
						|
    }
 | 
						|
    return rval;
 | 
						|
}
 | 
						|
 | 
						|
string get_connection_errors(const ServerVector& servers)
 | 
						|
{
 | 
						|
    // Get errors from all connections, form a string.
 | 
						|
    std::stringstream ss;
 | 
						|
    for (ServerVector::const_iterator iter = servers.begin(); iter != servers.end(); iter++)
 | 
						|
    {
 | 
						|
        const char* error = mysql_error((*iter)->con);
 | 
						|
        ss_dassert(*error); // Every connection should have an error.
 | 
						|
        ss << (*iter)->server->unique_name << ": '" << error << "'";
 | 
						|
        if (iter + 1 != servers.end())
 | 
						|
        {
 | 
						|
            ss << ", ";
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return ss.str();
 | 
						|
}
 | 
						|
 | 
						|
string monitored_servers_to_string(const ServerVector& array)
 | 
						|
{
 | 
						|
    string rval;
 | 
						|
    size_t array_size = array.size();
 | 
						|
    if (array_size > 0)
 | 
						|
    {
 | 
						|
        const char* separator = "";
 | 
						|
        for (size_t i = 0; i < array_size; i++)
 | 
						|
        {
 | 
						|
            rval += separator;
 | 
						|
            rval += array[i]->server->unique_name;
 | 
						|
            separator = ",";
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return rval;
 | 
						|
} |