Files
MaxScale/table_replication_consistency/table_replication_consistency.cpp

318 lines
7.6 KiB
C++

/*
Copyright (C) 2013, SkySQL Ab
This file is distributed as part of the SkySQL Gateway. It is free
software: you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation,
version 2.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 51
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author: Jan Lindström jan.lindstrom@skysql.com
Created: 20-06-2013
Updated:
*/
#include <iostream>
#include "my_pthread.h"
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <regex.h>
#include <algorithm>
#include <sstream>
#include <boost/system/system_error.hpp>
#include "table_replication_consistency.h"
#include "table_replication_listener.h"
#include "listener_exception.h"
/* Global memory */
pthread_t *replication_listener_tid = NULL;
unsigned int n_replication_listeners = 0;
/* Namespaces */
using namespace std;
using namespace mysql;
using namespace table_replication_listener;
/***********************************************************************//**
This function will register replication listener for every server
provided and initialize all internal data structures and starts listening
the replication stream.
@return 0 on success, error code at failure. */
int
tb_replication_consistency_init(
/*============================*/
replication_listener_t *rpl, /*!< in: Server
definition. */
size_t n_servers, /*!< in: Number of servers */
unsigned int gateway_server_id) /*!< in: Gateway slave
server id. */
{
boost::uint32_t i;
int err = 0;
string errmsg="";
replication_listener_tid = (pthread_t*)malloc(sizeof(pthread_t) * (n_servers + 1));
if (replication_listener_tid == NULL) {
errmsg = string("Table_Replication_Consistency: out of memory");
goto error_handling;
}
for(i=0;i < n_servers; i++) {
try {
rpl[i].gateway_slave_server_id = gateway_server_id;
rpl[i].listener_id = i;
err = pthread_create(
&replication_listener_tid[i],
NULL,
&(tb_replication_listener_reader),
(void *) &(rpl[i]));
if (err) {
errmsg = string(strerror(err));
goto error_handling;
}
}
catch(ListenerException const& e)
{
errmsg = e.what();
goto error_handling;
}
catch(boost::system::error_code const& e)
{
errmsg = e.message();
goto error_handling;
}
// Try and catch all exceptions
catch(std::exception const& e)
{
errmsg = e.what();
goto error_handling;
}
// Rest of them
catch(...)
{
errmsg = std::string("Unknown exception: ");
goto error_handling;
}
}
n_replication_listeners = i;
/* We will try to join the threads at shutdown */
return (0);
error_handling:
n_replication_listeners = i;
rpl[i].error_message = (char *)malloc(errmsg.size()+1);
strcpy(rpl[i].error_message, errmsg.c_str());
return (1);
}
/***********************************************************************//**
With this fuction client can request table consistency status for a
single table. As a return client will receive a number of consistency
status structures. Client must allocate memory for consistency result
array and provide the maximum number of values returned. At return
there is information how many results where available.
@return 0 on success, error code at failure. */
int
tb_replication_consistency_query(
/*=============================*/
table_consistency_query_t *tb_query, /*!< in: Table consistency
query. */
table_consistency_t *tb_consistency, /*!< in: Table consistency
status structure.*/
size_t *n_servers) /*!< inout: Number of
servers where to get table
consistency status. Out: Number
of successfull consistency
query results. */
{
int err = 0;
boost::uint32_t i = 0;
std::string errmsg ="";
// We need to protect C client from exceptions here
try {
for(i = 0; i < *n_servers; i++) {
err = tb_replication_listener_consistency(tb_query->db_dot_table, &tb_consistency[i], i);
if (err) {
goto err_exit;
}
}
}
catch(mysql::ListenerException const& e)
{
errmsg = e.what();
goto error_handling;
}
catch(boost::system::error_code const& e)
{
errmsg = e.message();
goto error_handling;
}
// Try and catch all exceptions
catch(std::exception const& e)
{
errmsg = e.what();
goto error_handling;
}
// Rest of them
catch(...)
{
errmsg = std::string("Unknown exception: ");
goto error_handling;
}
*n_servers = i;
return (err);
error_handling:
tb_consistency[i].error_message = (char *)malloc(errmsg.size()+1);
strcpy(tb_consistency[i].error_message, errmsg.c_str());
err_exit:
*n_servers=i-1;
tb_consistency[i].error_code = err;
return (1);
}
/***********************************************************************//**
This function will reconnect replication listener to a server
provided.
@return 0 on success, error code at failure. */
int
tb_replication_consistency_reconnect(
/*=================================*/
replication_listener_t* rpl, /*!< in: Server definition.*/
unsigned int gateway_server_id) /*!< in: Gateway slave
server id. */
{
std::string errmsg ="";
int err = 0;
rpl->gateway_slave_server_id = gateway_server_id;
// We need to protect C client from exceptions here
try {
err = tb_replication_listener_reconnect(rpl, &replication_listener_tid[rpl->listener_id]);
if (err) {
goto err_exit;
}
}
catch(ListenerException const& e)
{
errmsg = e.what();
goto error_handling;
}
catch(boost::system::error_code const& e)
{
errmsg = e.message();
goto error_handling;
}
// Try and catch all exceptions
catch(std::exception const& e)
{
errmsg = e.what();
goto error_handling;
}
// Rest of them
catch(...)
{
errmsg = std::string("Unknown exception: ");
goto error_handling;
}
return (err);
error_handling:
rpl->error_message = (char *)malloc(errmsg.size()+1);
strcpy(rpl->error_message, errmsg.c_str());
err_exit:
return (1);
}
/***********************************************************************//**
This function is to shutdown the replication listener and free all
resources on table consistency. This function (TODO) will store
the current status on metadata to MySQL server.
@return 0 on success, error code at failure. */
int
tb_replication_consistency_shutdown(
/*================================*/
char ** error_message) /*!< out: error message */
{
int err = 0;
boost::uint32_t i = 0;
std::string errmsg ="";
// We need to protect C client from exceptions here
try {
for(i = 0; i < n_replication_listeners; i++) {
err = tb_replication_listener_shutdown(i, error_message);
if (err) {
goto err_exit;
}
}
// Need to wait until the thread exits
err = pthread_join(replication_listener_tid[i], (void **)error_message);
if (err) {
goto err_exit;
}
}
catch(mysql::ListenerException const& e)
{
errmsg = e.what();
goto error_handling;
}
catch(boost::system::error_code const& e)
{
errmsg = e.message();
goto error_handling;
}
// Try and catch all exceptions
catch(std::exception const& e)
{
errmsg = e.what();
goto error_handling;
}
// Rest of them
catch(...)
{
errmsg = std::string("Unknown exception: ");
goto error_handling;
}
return (err);
error_handling:
*error_message = (char *)malloc(errmsg.size()+1);
strcpy(*error_message, errmsg.c_str());
err_exit:
return (1);
}