Merge branch 'develop' into 1.2.1-binlog_router_trx
This commit is contained in:
@ -28,11 +28,14 @@
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
#ifndef PCRE2_CODE_UNIT_WIDTH
|
||||
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||
#endif
|
||||
|
||||
#include <dcb.h>
|
||||
#include <hashtable.h>
|
||||
#include <mysql_client_server_protocol.h>
|
||||
#include <pcre.h>
|
||||
#include <pcre2.h>
|
||||
/**
|
||||
* Bitmask values for the router session's initialization. These values are used
|
||||
* to prevent responses from internal commands being forwarded to the client.
|
||||
@ -330,9 +333,10 @@ typedef struct router_instance {
|
||||
HASHTABLE* ignored_dbs; /*< List of databases to ignore when the
|
||||
* database mapping finds multiple servers
|
||||
* with the same database */
|
||||
pcre* ignore_regex; /*< Databases matching this regex will
|
||||
pcre2_code* ignore_regex; /*< Databases matching this regex will
|
||||
* not cause the session to be terminated
|
||||
* if they are found on more than one server. */
|
||||
pcre2_match_data* ignore_match_data;
|
||||
|
||||
} ROUTER_INSTANCE;
|
||||
|
||||
|
||||
@ -51,8 +51,8 @@
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
|
||||
#include <mysqlmon.h>
|
||||
#include <modutil.h>
|
||||
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
@ -81,7 +81,10 @@ static void set_master_heartbeat(MYSQL_MONITOR *, MONITOR_SERVERS *);
|
||||
static void set_slave_heartbeat(MONITOR *, MONITOR_SERVERS *);
|
||||
static int add_slave_to_master(long *, int, long);
|
||||
bool isMySQLEvent(monitor_event_t event);
|
||||
void check_maxscale_schema_replication(MONITOR *monitor);
|
||||
static bool report_version_err = true;
|
||||
static const char* hb_table_name = "maxscale_schema.replication_heartbeat";
|
||||
|
||||
static MONITOR_OBJECT MyObject = {
|
||||
startMonitor,
|
||||
stopMonitor,
|
||||
@ -219,6 +222,7 @@ startMonitor(void *arg, void* opt)
|
||||
{
|
||||
memset(handle->events,true,sizeof(handle->events));
|
||||
}
|
||||
|
||||
handle->tid = (THREAD)thread_start(monitorMain, monitor);
|
||||
return handle;
|
||||
}
|
||||
@ -734,6 +738,7 @@ int num_servers=0;
|
||||
MONITOR_SERVERS *root_master = NULL;
|
||||
size_t nrounds = 0;
|
||||
int log_no_master = 1;
|
||||
bool heartbeat_checked = false;
|
||||
|
||||
spinlock_acquire(&mon->lock);
|
||||
handle = (MYSQL_MONITOR *)mon->handle;
|
||||
@ -762,6 +767,13 @@ detect_stale_master = handle->detectStaleMaster;
|
||||
}
|
||||
/** Wait base interval */
|
||||
thread_millisleep(MON_BASE_INTERVAL_MS);
|
||||
|
||||
if (handle->replicationHeartbeat && !heartbeat_checked)
|
||||
{
|
||||
check_maxscale_schema_replication(mon);
|
||||
heartbeat_checked = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate how far away the monitor interval is from its full
|
||||
* cycle and if monitor interval time further than the base
|
||||
@ -1465,3 +1477,223 @@ bool isMySQLEvent(monitor_event_t event)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if replicate_ignore_table is defined and if maxscale_schema.replication_hearbeat
|
||||
* table is in the list.
|
||||
* @param database Server to check
|
||||
* @return False if the table is not replicated or an error occurred when querying
|
||||
* the server
|
||||
*/
|
||||
bool check_replicate_ignore_table(MONITOR_SERVERS* database)
|
||||
{
|
||||
MYSQL_RES *result;
|
||||
bool rval = true;
|
||||
|
||||
if (mysql_query(database->con,
|
||||
"show variables like 'replicate_ignore_table'") == 0 &&
|
||||
(result = mysql_store_result(database->con)) &&
|
||||
mysql_num_fields(result) > 1)
|
||||
{
|
||||
MYSQL_ROW row;
|
||||
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
if (strlen(row[1]) > 0 &&
|
||||
strcasestr(row[1], hb_table_name))
|
||||
{
|
||||
skygw_log_write(LE, "Warning: 'replicate_ignore_table' is "
|
||||
"defined on server '%s' and '%s' was found in it. ",
|
||||
database->server->unique_name, hb_table_name);
|
||||
rval = false;
|
||||
}
|
||||
}
|
||||
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE, "Error: Failed to query server %s for "
|
||||
"'replicate_ignore_table': %s",
|
||||
database->server->unique_name,
|
||||
mysql_error(database->con));
|
||||
rval = false;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if replicate_do_table is defined and if maxscale_schema.replication_hearbeat
|
||||
* table is not in the list.
|
||||
* @param database Server to check
|
||||
* @return False if the table is not replicated or an error occurred when querying
|
||||
* the server
|
||||
*/
|
||||
bool check_replicate_do_table(MONITOR_SERVERS* database)
|
||||
{
|
||||
MYSQL_RES *result;
|
||||
bool rval = true;
|
||||
|
||||
if (mysql_query(database->con,
|
||||
"show variables like 'replicate_do_table'") == 0 &&
|
||||
(result = mysql_store_result(database->con)) &&
|
||||
mysql_num_fields(result) > 1)
|
||||
{
|
||||
MYSQL_ROW row;
|
||||
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
if (strlen(row[1]) > 0 &&
|
||||
strcasestr(row[1], hb_table_name) == NULL)
|
||||
{
|
||||
skygw_log_write(LE, "Warning: 'replicate_do_table' is "
|
||||
"defined on server '%s' and '%s' was not found in it. ",
|
||||
database->server->unique_name, hb_table_name);
|
||||
rval = false;
|
||||
}
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE, "Error: Failed to query server %s for "
|
||||
"'replicate_do_table': %s",
|
||||
database->server->unique_name,
|
||||
mysql_error(database->con));
|
||||
rval = false;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if replicate_wild_do_table is defined and if it doesn't match
|
||||
* maxscale_schema.replication_heartbeat.
|
||||
* @param database Database server
|
||||
* @return False if the table is not replicated or an error occurred when trying to
|
||||
* query the server.
|
||||
*/
|
||||
bool check_replicate_wild_do_table(MONITOR_SERVERS* database)
|
||||
{
|
||||
MYSQL_RES *result;
|
||||
bool rval = true;
|
||||
|
||||
if (mysql_query(database->con,
|
||||
"show variables like 'replicate_wild_do_table'") == 0 &&
|
||||
(result = mysql_store_result(database->con)) &&
|
||||
mysql_num_fields(result) > 1)
|
||||
{
|
||||
MYSQL_ROW row;
|
||||
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
if (strlen(row[1]) > 0)
|
||||
{
|
||||
mxs_pcre2_result_t rc = modutil_mysql_wildcard_match(row[1], hb_table_name);
|
||||
if (rc == MXS_PCRE2_NOMATCH)
|
||||
{
|
||||
skygw_log_write(LE, "Warning: 'replicate_wild_do_table' is "
|
||||
"defined on server '%s' and '%s' does not match it. ",
|
||||
database->server->unique_name,
|
||||
hb_table_name);
|
||||
rval = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE, "Error: Failed to query server %s for "
|
||||
"'replicate_wild_do_table': %s",
|
||||
database->server->unique_name,
|
||||
mysql_error(database->con));
|
||||
rval = false;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if replicate_wild_ignore_table is defined and if it matches
|
||||
* maxscale_schema.replication_heartbeat.
|
||||
* @param database Database server
|
||||
* @return False if the table is not replicated or an error occurred when trying to
|
||||
* query the server.
|
||||
*/
|
||||
bool check_replicate_wild_ignore_table(MONITOR_SERVERS* database)
|
||||
{
|
||||
MYSQL_RES *result;
|
||||
bool rval = true;
|
||||
|
||||
if (mysql_query(database->con,
|
||||
"show variables like 'replicate_wild_ignore_table'") == 0 &&
|
||||
(result = mysql_store_result(database->con)) &&
|
||||
mysql_num_fields(result) > 1)
|
||||
{
|
||||
MYSQL_ROW row;
|
||||
|
||||
while ((row = mysql_fetch_row(result)))
|
||||
{
|
||||
if (strlen(row[1]) > 0)
|
||||
{
|
||||
mxs_pcre2_result_t rc = modutil_mysql_wildcard_match(row[1], hb_table_name);
|
||||
if (rc == MXS_PCRE2_MATCH)
|
||||
{
|
||||
skygw_log_write(LE, "Warning: 'replicate_wild_ignore_table' is "
|
||||
"defined on server '%s' and '%s' matches it. ",
|
||||
database->server->unique_name,
|
||||
hb_table_name);
|
||||
rval = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LE, "Error: Failed to query server %s for "
|
||||
"'replicate_wild_do_table': %s",
|
||||
database->server->unique_name,
|
||||
mysql_error(database->con));
|
||||
rval = false;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the maxscale_schema.replication_heartbeat table is replicated on all
|
||||
* servers and log a warning if problems were found.
|
||||
* @param monitor Monitor structure
|
||||
*/
|
||||
void check_maxscale_schema_replication(MONITOR *monitor)
|
||||
{
|
||||
MONITOR_SERVERS* database = monitor->databases;
|
||||
bool err = false;
|
||||
|
||||
while (database)
|
||||
{
|
||||
connect_result_t rval = mon_connect_to_db(monitor, database);
|
||||
if (rval == MONITOR_CONN_OK)
|
||||
{
|
||||
if (!check_replicate_ignore_table(database) ||
|
||||
!check_replicate_do_table(database) ||
|
||||
!check_replicate_wild_do_table(database) ||
|
||||
!check_replicate_wild_ignore_table(database))
|
||||
{
|
||||
err = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mon_log_connect_error(database, rval);
|
||||
}
|
||||
database = database->next;
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
skygw_log_write(LE, "Warning: Problems were encountered when "
|
||||
"checking if '%s' is replicated. Make sure that the table is "
|
||||
"replicated to all slaves.", hb_table_name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -590,29 +590,29 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF **buf) {
|
||||
sizeof(protocol->scramble),
|
||||
username,
|
||||
stage1_hash);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGIF(LM, (skygw_log_write(LOGFILE_MESSAGE,
|
||||
"%s: login attempt for user '%s', user not "
|
||||
"found.",
|
||||
dcb->service->name, username)));
|
||||
}
|
||||
}
|
||||
|
||||
/* Do again the database check */
|
||||
auth_ret = check_db_name_after_auth(dcb, database, auth_ret);
|
||||
/* Do again the database check */
|
||||
auth_ret = check_db_name_after_auth(dcb, database, auth_ret);
|
||||
}
|
||||
}
|
||||
|
||||
/* on succesful auth set user into dcb field */
|
||||
if (auth_ret == 0) {
|
||||
dcb->user = strdup(client_data->user);
|
||||
}
|
||||
else
|
||||
{
|
||||
skygw_log_write(LOGFILE_ERROR,
|
||||
"%s: login attempt for user '%s', authentication failed.",
|
||||
dcb->service->name, username);
|
||||
}
|
||||
{
|
||||
skygw_log_write(LM, "%s: login attempt for user '%s', authentication failed.",
|
||||
dcb->service->name, username);
|
||||
if (dcb->ipv4.sin_addr.s_addr == 0x0100007F &&
|
||||
!dcb->service->localhost_match_wildcard_host)
|
||||
{
|
||||
skygw_log_write_flush(LM, "If you have a wildcard grant that covers"
|
||||
" this address, try adding "
|
||||
"'localhost_match_wildcard_host=true' for "
|
||||
"service '%s'. ", dcb->service->name);
|
||||
}
|
||||
}
|
||||
|
||||
/* let's free the auth_token now */
|
||||
if (auth_token) {
|
||||
|
||||
@ -1489,16 +1489,6 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
|
||||
!dcb->service->localhost_match_wildcard_host)
|
||||
{
|
||||
/* Skip the wildcard check and return 1 */
|
||||
LOGIF(LE,
|
||||
(skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Error : user %s@%s not found, try set "
|
||||
"'localhost_match_wildcard_host=1' in "
|
||||
"service definition of the configuration "
|
||||
"file.",
|
||||
key.user,
|
||||
dcb->remote)));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -41,9 +41,6 @@
|
||||
/** Size of the hashtable used to store ignored databases */
|
||||
#define SCHEMAROUTER_HASHSIZE 100
|
||||
|
||||
/** Size of the offset vector used for regex matching */
|
||||
#define SCHEMA_OVEC_SIZE 24
|
||||
|
||||
MODULE_INFO info = {
|
||||
MODULE_API_ROUTER,
|
||||
MODULE_BETA_RELEASE,
|
||||
@ -380,13 +377,11 @@ showdb_response_t parse_showdb_response(ROUTER_CLIENT_SES* rses, backend_ref_t*
|
||||
}
|
||||
else
|
||||
{
|
||||
const int ovec_count = SCHEMA_OVEC_SIZE;
|
||||
int ovector[ovec_count];
|
||||
|
||||
if (!(hashtable_fetch(rses->router->ignored_dbs, data) ||
|
||||
(rses->router->ignore_regex &&
|
||||
pcre_exec(rses->router->ignore_regex, NULL, data,
|
||||
strlen(data), 0, 0, ovector, ovec_count) >= 0)))
|
||||
pcre2_match(rses->router->ignore_regex, (PCRE2_SPTR)data,
|
||||
PCRE2_ZERO_TERMINATED, 0, 0,
|
||||
rses->router->ignore_match_data, NULL) >= 0)))
|
||||
{
|
||||
duplicate_found = true;
|
||||
skygw_log_write(LE, "Error: Database '%s' found on servers '%s' and '%s' for user %s@%s.",
|
||||
@ -801,19 +796,36 @@ createInstance(SERVICE *service, char **options)
|
||||
|
||||
if((param = config_get_param(conf,"ignore_databases_regex")))
|
||||
{
|
||||
const char* errptr;
|
||||
int erroffset;
|
||||
pcre* re = pcre_compile(param->value, 0, &errptr, &erroffset, NULL);
|
||||
int errcode;
|
||||
PCRE2_SIZE erroffset;
|
||||
pcre2_code* re = pcre2_compile((PCRE2_SPTR)param->value, PCRE2_ZERO_TERMINATED, 0,
|
||||
&errcode, &erroffset, NULL);
|
||||
|
||||
if(re == NULL)
|
||||
{
|
||||
PCRE2_UCHAR errbuf[512];
|
||||
pcre2_get_error_message(errcode, errbuf, sizeof(errbuf));
|
||||
skygw_log_write(LE, "Error: Regex compilation failed at %d for regex '%s': %s",
|
||||
erroffset, param->value, errptr);
|
||||
erroffset, param->value, errbuf);
|
||||
hashtable_free(router->ignored_dbs);
|
||||
free(router);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pcre2_match_data* match_data = pcre2_match_data_create_from_pattern(re, NULL);
|
||||
|
||||
if (match_data == NULL)
|
||||
{
|
||||
skygw_log_write(LE, "Error: PCRE2 match data creation failed. This"
|
||||
" is most likely caused by a lack of available memory.");
|
||||
pcre2_code_free(re);
|
||||
hashtable_free(router->ignored_dbs);
|
||||
free(router);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
router->ignore_regex = re;
|
||||
router->ignore_match_data = match_data;
|
||||
}
|
||||
|
||||
if((param = config_get_param(conf,"ignore_databases")))
|
||||
|
||||
Reference in New Issue
Block a user