MXS-1266: Allow save and read binlog files from a binlog cache directory tree

MXS-1266: Allow save and read binlog files from a binlog cache
directory tree
This commit is contained in:
MassimilianoPinto
2017-06-07 08:56:52 +02:00
parent a79a492601
commit 8f94b27fd5
5 changed files with 927 additions and 175 deletions

View File

@ -61,7 +61,6 @@
*/
#include "blr.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -87,6 +86,7 @@
#include <sys/stat.h>
#include <uuid/uuid.h>
#include <maxscale/alloc.h>
#include <inttypes.h>
/* The router entry points */
static MXS_ROUTER *createInstance(SERVICE *service, char **options);
@ -126,6 +126,8 @@ static void stats_func(void *);
static bool rses_begin_locked_router_action(ROUTER_SLAVE *);
static void rses_end_locked_router_action(ROUTER_SLAVE *);
GWBUF *blr_cache_read_response(ROUTER_INSTANCE *router, char *response);
extern bool blr_load_last_mariadb_gtid(ROUTER_INSTANCE *router,
MARIADB_GTID_INFO *result);
static SPINLOCK instlock;
static ROUTER_INSTANCE *instances;
@ -139,6 +141,13 @@ static const MXS_ENUM_VALUE enc_algo_values[] =
{NULL}
};
static const MXS_ENUM_VALUE binlog_storage_values[] =
{
{"flat", BLR_BINLOG_STORAGE_FLAT},
{"tree", BLR_BINLOG_STORAGE_TREE},
{NULL}
};
/**
* The module entry point routine. It is this routine that
* must populate the structure that is referred to as the
@ -200,6 +209,7 @@ MXS_MODULE* MXS_CREATE_MODULE()
{"encryption_key_file", MXS_MODULE_PARAM_PATH, NULL, MXS_MODULE_OPT_PATH_R_OK},
{"mariadb10_slave_gtid", MXS_MODULE_PARAM_BOOL, "false"},
{"mariadb10_master_gtid", MXS_MODULE_PARAM_BOOL, "false"},
{"binlog_structure", MXS_MODULE_PARAM_ENUM, "flat", MXS_MODULE_OPT_NONE, binlog_storage_values},
{"shortburst", MXS_MODULE_PARAM_COUNT, DEF_SHORT_BURST},
{"longburst", MXS_MODULE_PARAM_COUNT, DEF_LONG_BURST},
{"burstsize", MXS_MODULE_PARAM_SIZE, DEF_BURST_SIZE},
@ -382,6 +392,11 @@ createInstance(SERVICE *service, char **options)
/* Set router uuid */
inst->uuid = config_copy_string(params, "uuid");
/* Enable Flat or Tree storage of binlog files */
inst->storage_type = config_get_enum(params,
"binlog_structure",
binlog_storage_values);
if (inst->uuid == NULL)
{
/* Generate UUID for the router instance */
@ -542,6 +557,13 @@ createInstance(SERVICE *service, char **options)
{
inst->mariadb10_master_gtid = config_truth_value(value);
}
else if (strcmp(options[i], "binlog_structure") == 0)
{
/* Enable Flat or Tree storage of binlog files */
inst->storage_type = strcasecmp(value, "tree") == 0 ?
BLR_BINLOG_STORAGE_TREE :
BLR_BINLOG_STORAGE_FLAT;
}
else if (strcmp(options[i], "encryption_algorithm") == 0)
{
int ret = blr_check_encryption_algorithm(value);
@ -672,7 +694,6 @@ createInstance(SERVICE *service, char **options)
return NULL;
}
/* Get the Encryption key */
if (inst->encryption.enabled && !blr_get_encryption_key(inst))
{
@ -723,6 +744,24 @@ createInstance(SERVICE *service, char **options)
inst->mariadb10_gtid = true;
}
if (!inst->mariadb10_master_gtid &&
inst->storage_type == BLR_BINLOG_STORAGE_TREE)
{
MXS_ERROR("%s: binlog_structure 'tree' mode can be enabled only"
" with MariaDB Master GTID registration feature."
" Please enable it with option"
" 'mariadb10_master_gtid = on'",
service->name);
free_instance(inst);
return NULL;
}
/* Log binlog structure storage mode */
MXS_NOTICE("%s: storing binlog files in %s",
service->name,
inst->storage_type == BLR_BINLOG_STORAGE_FLAT ?
"'flat' mode" :
"'tree' mode using GTID domain_id and server_id");
/* Enable MariaDB the GTID maps store */
if (inst->mariadb10_compat &&
inst->mariadb10_gtid)
@ -889,7 +928,7 @@ createInstance(SERVICE *service, char **options)
/* Read any cached response messages */
blr_cache_read_master_data(inst);
/* Find latest binlog file or create a new one (000001) */
/* Find latest binlog file */
if (blr_file_init(inst) == 0)
{
MXS_ERROR("%s: Service not started due to lack of binlog directory %s",
@ -955,8 +994,18 @@ createInstance(SERVICE *service, char **options)
*/
if (inst->master_state == BLRM_UNCONNECTED)
{
/* Check current binlog */
MXS_NOTICE("Validating binlog file '%s' ...",
char f_prefix[BINLOG_FILE_EXTRA_INFO] = "";
if (inst->storage_type == BLR_BINLOG_STORAGE_TREE)
{
sprintf(f_prefix,
"%" PRIu32 "/%" PRIu32 "/",
inst->mariadb10_gtid_domain,
inst->orig_masterid);
}
/* Log current binlog, possibly with tree prefix */
MXS_NOTICE("Validating last binlog file '%s%s' ...",
f_prefix,
inst->binlog_name);
if (!blr_check_binlog(inst))
@ -974,6 +1023,57 @@ createInstance(SERVICE *service, char **options)
MXS_INFO("Current binlog file is %s, safe pos %lu, current pos is %lu\n",
inst->binlog_name, inst->binlog_position, inst->current_pos);
/**
* Try loading last found GTID if the file size is <= 4 bytes
*/
if (inst->mariadb10_gtid &&
inst->current_pos <= 4)
{
MARIADB_GTID_INFO last_gtid = {};
/* Get last MariaDB GTID from repo */
if (blr_load_last_mariadb_gtid(inst, &last_gtid) &&
last_gtid.gtid != NULL)
{
/* Set MariaDB GTID */
strcpy(inst->last_mariadb_gtid, last_gtid.gtid);
MXS_FREE(last_gtid.gtid);
MXS_FREE(last_gtid.file);
}
else
{
/**
* In case of no GTID, inst->last_mariadb_gtid is empty.
*
* If connecting to master with GTID = "" the server
* will send data from its first binlog and
* this might overwrite existing data.
*
* Binlog server will not connect to master.
*
* It's needed to connect to MySQL admin interface
* and explicitely issue:
* SET @@GLOBAL.GTID_SLAVE_POS =''
* and START SLAVE
*/
/* Force STOPPED state */
inst->master_state = BLRM_SLAVE_STOPPED;
/* Set mysql_errno and error message */
inst->m_errno = BINLOG_FATAL_ERROR_READING;
inst->m_errmsg = MXS_STRDUP_A("HY000 Cannot find any GTID"
" in the GTID maps repo."
" Please issue SET @@GLOBAL.GTID_SLAVE_POS =''"
" and START SLAVE."
" Existing binlogs might be overwritten.");
MXS_ERROR("%s: %s",
inst->service->name,
inst->m_errmsg);
return (MXS_ROUTER *)inst;
}
}
/* Don't start replication if binlog has START_ENCRYPTION_EVENT but binlog encryption is off */
if (!inst->encryption.enabled && inst->encryption_ctx)
{
@ -985,8 +1085,9 @@ createInstance(SERVICE *service, char **options)
inst->master_state = BLRM_SLAVE_STOPPED;
/* Set mysql_errno and error message */
inst->m_errno = BINLOG_FATAL_ERROR_READING;
inst->m_errmsg = mxs_strdup("HY000 Binlog encryption is Off but binlog file has "
"the START_ENCRYPTION_EVENT");
inst->m_errmsg = MXS_STRDUP_A("HY000 Binlog encryption is Off"
" but current binlog file has"
" the START_ENCRYPTION_EVENT");
return (MXS_ROUTER *)inst;
}
@ -998,6 +1099,11 @@ createInstance(SERVICE *service, char **options)
return (MXS_ROUTER *)inst;
}
/**
* Free the router instance
*
* @param instance The router instance
*/
static void
free_instance(ROUTER_INSTANCE *instance)
{
@ -1079,6 +1185,7 @@ newSession(MXS_ROUTER *instance, MXS_SESSION *session)
slave->mariadb_gtid = NULL;
slave->gtid_maps = NULL;
memset(&slave->f_info, 0 , sizeof (MARIADB_GTID_INFO));
/**
* Add this session to the list of active sessions.

View File

@ -104,6 +104,12 @@ MXS_BEGIN_DECLS
* in SHOW FULL BINARY LOGS
*/
#define BINLOG_FILE_EXTRA_INFO GTID_MAX_LEN
enum blr_binlog_storage_type
{
BLR_BINLOG_STORAGE_FLAT,
BLR_BINLOG_STORAGE_TREEE
};
/**
* Supported Encryption algorithms
*
@ -298,6 +304,24 @@ enum blr_event_state
BLR_EVENT_DONE, /*< The complete event was received */
};
/** MariaDB GTID elements */
typedef struct mariadb_gtid_elems
{
uint32_t domain_id; /*< The replication domain */
uint32_t server_id; /*< The serverid */
uint64_t seq_no; /*< The sequence number */
} MARIADB_GTID_ELEMS;
/** MariaDB GTID info */
typedef struct mariadb_gtid_info
{
char *gtid; /** MariaDB 10.x GTID, string value */
char *file; /** The binlog file */
uint64_t start; /** The BEGIN pos: i.e the GTID event */
uint64_t end; /** The next_pos in COMMIT event */
MARIADB_GTID_ELEMS gtid_elms; /** MariaDB 10.x GTID components */
} MARIADB_GTID_INFO;
/* Master Server configuration struct */
typedef struct master_server_config
{
@ -380,6 +404,7 @@ typedef struct blfile
int refcnt; /*< Reference count for file */
BLCACHE *cache; /*< Record cache for this file */
SPINLOCK lock; /*< The file lock */
MARIADB_GTID_ELEMS info; /*< Elements for file prefix */
struct blfile *next; /*< Next file in list */
} BLFILE;
@ -471,6 +496,7 @@ typedef struct router_slave
bool gtid_strict_mode;/*< MariaDB 10 Slave sets gtid_strict_mode */
char *mariadb_gtid; /*< MariaDB 10 Slave connects with GTID */
sqlite3 *gtid_maps; /*< GTID storage client handle, read only*/
MARIADB_GTID_INFO f_info; /*< GTID info for file name prefix */
#if defined(SS_DEBUG)
skygw_chk_t rses_chk_tail;
#endif
@ -553,35 +579,18 @@ typedef enum
BLRM_STANDALONE_SEEN /*< Received a standalone event, ie: a DDL */
} master_transaction_t;
/** MariaDB GTID elements */
typedef struct mariadb_gtid_elems
{
uint32_t domain_id; /*< The replication domain */
uint32_t server_id; /*< The serverid */
uint64_t seq_no; /*< The sequence number */
} MARIADB_GTID_ELEMS;
/** Transaction Details */
typedef struct pending_transaction
{
char gtid[GTID_MAX_LEN + 1]; /** MariaDB 10.x GTID */
master_transaction_t state; /** Transaction state */
uint64_t start_pos; /** The BEGIN pos */
uint64_t end_pos; /** The next_pos in COMMIT event*/
MARIADB_GTID_ELEMS gtid_elms; /* MariaDB 10.x GTID components */
uint64_t end_pos; /** The next_pos in COMMIT event */
MARIADB_GTID_ELEMS gtid_elms; /** MariaDB 10.x GTID components */
bool standalone; /** Standalone event, such as DDL
* no terminating COMMIT */
} PENDING_TRANSACTION;
/** MariaDB GTID info */
typedef struct mariadb_gtid_info
{
char *gtid; /** MariaDB 10.x GTID, string value */
char *file; /** The binlog file */
uint64_t start; /** The BEGIN pos: i.e the GTID event */
uint64_t end; /** The next_pos in COMMIT event*/
} MARIADB_GTID_INFO;
/**
* The per instance data for the router.
*/
@ -673,6 +682,7 @@ typedef struct router_instance
*/
uint32_t mariadb10_gtid_domain;/*< MariaDB 10 GTID Domain ID */
sqlite3 *gtid_maps; /*< MariaDB 10 GTID storage */
enum binlog_storage_type storage_type;/*< Enables hierachical binlog file storage */
struct router_instance *next;
} ROUTER_INSTANCE;
@ -894,7 +904,9 @@ extern int blr_file_init(ROUTER_INSTANCE *);
extern int blr_write_binlog_record(ROUTER_INSTANCE *, REP_HEADER *, uint32_t pos, uint8_t *);
extern int blr_file_rotate(ROUTER_INSTANCE *, char *, uint64_t);
extern void blr_file_flush(ROUTER_INSTANCE *);
extern BLFILE *blr_open_binlog(ROUTER_INSTANCE *, char *);
extern BLFILE *blr_open_binlog(ROUTER_INSTANCE *,
const char *,
const MARIADB_GTID_INFO *);
extern GWBUF *blr_read_binlog(ROUTER_INSTANCE *, BLFILE *, unsigned long, REP_HEADER *, char *,
const SLAVE_ENCRYPTION_CTX *);
extern void blr_close_binlog(ROUTER_INSTANCE *, BLFILE *);
@ -902,7 +914,9 @@ extern unsigned long blr_file_size(BLFILE *);
extern int blr_statistics(ROUTER_INSTANCE *, ROUTER_SLAVE *, GWBUF *);
extern int blr_ping(ROUTER_INSTANCE *, ROUTER_SLAVE *, GWBUF *);
extern int blr_send_custom_error(DCB *, int, int, char *, char *, unsigned int);
extern int blr_file_next_exists(ROUTER_INSTANCE *, ROUTER_SLAVE *);
extern int blr_file_next_exists(ROUTER_INSTANCE *,
ROUTER_SLAVE *,
char *next_file);
uint32_t extract_field(uint8_t *src, int bits);
void blr_cache_read_master_data(ROUTER_INSTANCE *router);
int blr_read_events_all_events(ROUTER_INSTANCE *, BINLOG_FILE_FIX *, int);

View File

@ -226,6 +226,16 @@ static void blr_report_checksum(REP_HEADER hdr,
bool blr_load_last_mariadb_gtid(ROUTER_INSTANCE *router,
MARIADB_GTID_INFO *result);
bool blr_get_last_file(ROUTER_INSTANCE *router,
MARIADB_GTID_INFO *result);
static int gtid_file_select_cb(void *data,
int cols,
char** values,
char** names);
bool blr_compare_binlogs(ROUTER_INSTANCE *router,
const MARIADB_GTID_ELEMS *info,
const char *r_file,
const char *s_file);
/**
* MariaDB 10.1.7 Start Encryption event content
@ -254,7 +264,8 @@ typedef struct start_encryption_event
* binlog to use and initialise it for writing, determining the
* next record to be fetched from the real master.
*
* @param router The router instance this defines the master for this replication chain
* @param router The router instance
* @return 1 on success, 0 otherwise
*/
int
blr_file_init(ROUTER_INSTANCE *router)
@ -265,6 +276,7 @@ blr_file_init(ROUTER_INSTANCE *router)
int root_len, i;
DIR *dirp;
struct dirent *dp;
int ret = 0;
if (router->binlogdir == NULL)
{
@ -303,7 +315,15 @@ blr_file_init(ROUTER_INSTANCE *router)
return 0;
}
/* First try to find a binlog file number by reading the directory */
/**
* Find last written binary log in the binlog cache
* OR
* get it from GTID maps repo
*/
/* - 1 - try to find a binlog file number by reading the directory */
if (router->storage_type == BLR_BINLOG_STORAGE_FLAT)
{
root_len = strlen(router->fileroot);
if ((dirp = opendir(path)) == NULL)
{
@ -325,7 +345,6 @@ blr_file_init(ROUTER_INSTANCE *router)
}
closedir(dirp);
file_found = 0;
do
{
@ -358,6 +377,56 @@ blr_file_init(ROUTER_INSTANCE *router)
blr_file_append(router, filename);
}
return 1;
}
/* - 2 - Get last file in GTID maps repo */
else
{
MARIADB_GTID_INFO last_gtid = {};
char f_prefix[BINLOG_FILE_EXTRA_INFO] = "";
// SELECT LAST FILE
if (!blr_get_last_file(router, &last_gtid) ||
last_gtid.gtid == NULL)
{
MXS_INFO("%s: cannot find any GTID in GTID maps repo",
router->service->name);
return 0;
}
/** We don't care about sequence being 0
* as this is a placeholder for new file in the repo.
* In case of file without transactions
* there is no real GTID with sequence:
* there should be a GTID_LIST event which holds
* the last GTID.
* The event is parsed while reading the binlog.
* Right now we need only the domain_id, server_id
* and filename.
*/
sprintf(f_prefix,
"%" PRIu32 "/%" PRIu32 "",
last_gtid.gtid_elms.domain_id,
last_gtid.gtid_elms.server_id);
router->mariadb10_gtid_domain = last_gtid.gtid_elms.domain_id;
router->orig_masterid = last_gtid.gtid_elms.server_id;
snprintf(filename, PATH_MAX, "%s/%s/%s", path, f_prefix, last_gtid.file);
if (access(filename, R_OK) != -1)
{
blr_file_append(router, last_gtid.file);
ret = 1;
}
else
{
ret = blr_file_create(router, last_gtid.file);
}
MXS_FREE(last_gtid.gtid);
MXS_FREE(last_gtid.file);
return ret;
}
return 0;
}
int
@ -409,6 +478,39 @@ blr_file_create(ROUTER_INSTANCE *router, char *file)
strcpy(path, router->binlogdir);
strcat(path, "/");
/**
* Create file using domain and server_id prefix
*/
if (router->mariadb10_compat &&
router->mariadb10_master_gtid &&
router->storage_type == BLR_BINLOG_STORAGE_TREE)
{
char prefix[BINLOG_FILE_EXTRA_INFO];
sprintf(prefix,
"%" PRIu32 "/%" PRIu32 "/",
router->mariadb10_gtid_domain,
router->orig_masterid);
strcat(path, prefix);
if (access(path, R_OK) == -1)
{
int mkdir_rval;
mkdir_rval = mkdir(path, 0700);
if (mkdir_rval == -1)
{
MXS_ERROR("Service %s, Failed to create binlog"
" directory tree '%s': [%d] %s",
router->service->name,
path,
errno,
mxs_strerror(errno));
return 0;
}
}
}
// Set final file name full path
strcat(path, file);
int fd = open(path, O_RDWR | O_CREAT, 0666);
@ -443,8 +545,10 @@ blr_file_create(ROUTER_INSTANCE *router, char *file)
gtid_elms.domain_id = router->mariadb10_gtid_domain;
// router->orig_masterid keeps the original ID
gtid_elms.server_id = router->orig_masterid;
// Pos 4 only for end_pos
// Pos 4 for start/end_pos
router->pending_transaction.end_pos = 4;
router->pending_transaction.start_pos = 4;
// Update all the gtid_elms
memcpy(&router->pending_transaction.gtid_elms,
&gtid_elms,
sizeof(MARIADB_GTID_ELEMS));
@ -496,6 +600,21 @@ blr_file_append(ROUTER_INSTANCE *router, char *file)
strcpy(path, router->binlogdir);
strcat(path, "/");
// Add file prefix
if (router->mariadb10_compat &&
router->mariadb10_master_gtid &&
router->storage_type == BLR_BINLOG_STORAGE_TREE)
{
char prefix[BINLOG_FILE_EXTRA_INFO];
sprintf(prefix,
"%" PRIu32 "/%" PRIu32 "/",
router->mariadb10_gtid_domain,
router->orig_masterid);
strcat(path, prefix);
}
//Add filename
strcat(path, file);
if ((fd = open(path, flags, 0666)) == -1)
@ -670,10 +789,19 @@ blr_file_flush(ROUTER_INSTANCE *router)
*
* @param router The router instance
* @param binlog The binlog filename
* @param info MariaDB GTID info
* with rep_domain and
* server_id.
* These two fileds are
* used as file prefix
* for binlog file name.
*
* @return a binlog file record
*/
BLFILE *
blr_open_binlog(ROUTER_INSTANCE *router, char *binlog)
blr_open_binlog(ROUTER_INSTANCE *router,
const char *binlog,
const MARIADB_GTID_INFO *info)
{
size_t len = strlen(binlog);
if (len > BINLOG_FNAMELEN)
@ -683,7 +811,7 @@ blr_open_binlog(ROUTER_INSTANCE *router, char *binlog)
return NULL;
}
len += (strlen(router->binlogdir) + 1); // +1 for the /.
len += (strlen(router->binlogdir) + 1); // +1 for the '.'
if (len > PATH_MAX)
{
MXS_ERROR("The length of %s/%s is longer than the maximum allowed length %d.",
@ -716,10 +844,32 @@ blr_open_binlog(ROUTER_INSTANCE *router, char *binlog)
strcpy(file->binlogname, binlog);
file->refcnt = 1;
file->cache = 0;
/* Store additional file informations */
if (info)
{
memcpy(&file->info,
&info->gtid_elms,
sizeof(MARIADB_GTID_ELEMS));
}
spinlock_init(&file->lock);
strcpy(path, router->binlogdir);
strcat(path, "/");
// Add tree prefix: "domain_id/server_id"
if (info)
{
char t_prefix[BINLOG_FILE_EXTRA_INFO];
sprintf(t_prefix,
"%" PRIu32 "/%" PRIu32 "/",
info->gtid_elms.domain_id,
info->gtid_elms.server_id);
strcat(path, t_prefix);
}
// Add file name
strcat(path, binlog);
if ((file->fd = open(path, O_RDONLY, 0666)) == -1)
@ -798,7 +948,11 @@ blr_read_binlog(ROUTER_INSTANCE *router,
spinlock_acquire(&router->binlog_lock);
spinlock_acquire(&file->lock);
if (strcmp(router->binlog_name, file->binlogname) != 0)
/* Check whether is current router file */
if (!blr_compare_binlogs(router,
&file->info,
router->binlog_name,
file->binlogname))
{
snprintf(errmsg, BINLOG_ERROR_MSG_LEN, "Requested position %lu is beyond "
"'closed' binlog file '%s', size %lu. Generating Error '1236'",
@ -824,7 +978,11 @@ blr_read_binlog(ROUTER_INSTANCE *router,
spinlock_acquire(&router->binlog_lock);
spinlock_acquire(&file->lock);
if (strcmp(router->binlog_name, file->binlogname) == 0 &&
/* Check current router file and router position */
if (blr_compare_binlogs(router,
&file->info,
router->binlog_name,
file->binlogname) &&
pos >= router->binlog_position)
{
if (pos > router->binlog_position)
@ -1075,7 +1233,7 @@ blr_read_binlog(ROUTER_INSTANCE *router,
gwbuf_free(result);
/**
* Binlog event check based on Replication Header content and pos
* Binlog event check based on Rep Header content and pos
*/
if (!blr_binlog_event_check(router, pos, hdr, file->binlogname, errmsg))
{
@ -1083,7 +1241,7 @@ blr_read_binlog(ROUTER_INSTANCE *router,
return NULL;
}
/* Set the decrypted event as result*/
/* Set the decrypted event as result */
result = decrypted_event;
}
@ -1143,7 +1301,7 @@ blr_close_binlog(ROUTER_INSTANCE *router, BLFILE *file)
/**
* Log the event header of binlog event
*
* @param priority The syslog priority of the message (LOG_ERR, LOG_WARNING, etc.)
* @param priority The syslog priority (LOG_ERR, LOG_WARNING, etc.)
* @param msg A message strign to preceed the header with
* @param ptr The event header raw data
*/
@ -1294,21 +1452,128 @@ blr_cache_read_response(ROUTER_INSTANCE *router, char *response)
*
* @param router The router instance
* @param slave The slave in question
* @param next_file The next_file buffer
* @return 0 if the next file does not exist
*/
int
blr_file_next_exists(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave)
blr_file_next_exists(ROUTER_INSTANCE *router,
ROUTER_SLAVE *slave,
char *next_file)
{
char *sptr, buf[BLRM_BINLOG_NAME_STR_LEN], bigbuf[PATH_MAX + 1];
int filenum;
char *errmsg = NULL;
char *sptr;
char bigbuf[PATH_MAX + 1];
char select_query[GTID_SQL_BUFFER_SIZE];
const char select_tpl[] = "SELECT "
"(rep_domain || '/' || server_id || '/' || binlog_file) AS file, "
"rep_domain, "
"server_id, "
"binlog_file "
"FROM gtid_maps "
"WHERE id = "
"(SELECT MAX(id) "
"FROM gtid_maps "
"WHERE (binlog_file='%s' AND "
"rep_domain = %" PRIu32 " AND "
"server_id = %" PRIu32 ")) + 1;";
MARIADB_GTID_INFO result = {};
MARIADB_GTID_ELEMS gtid_elms = {};
if ((sptr = strrchr(slave->binlogfile, '.')) == NULL)
{
next_file[0] = '\0';
return 0;
}
/**
* The next file to read could be determined in two ways:
* - 1 - file sequence +1
* - 2 - next file form GTID maps repo
*/
if (router->storage_type == BLR_BINLOG_STORAGE_FLAT)
{
/**
* Next file is the one with +1 in sequence
*/
char buf[BINLOG_FNAMELEN + 1];
int filenum;
filenum = atoi(sptr + 1);
sprintf(buf, BINLOG_NAMEFMT, router->fileroot, filenum + 1);
sprintf(bigbuf, "%s/%s", router->binlogdir, buf);
// Set the new file name in the output
strncpy(next_file, buf, BINLOG_FNAMELEN);
next_file[BINLOG_FNAMELEN] = '\0';
}
else
{
/**
* Next file is selected in GTID maps repo
*/
snprintf(select_query,
GTID_SQL_BUFFER_SIZE,
select_tpl,
slave->binlogfile,
slave->f_info.gtid_elms.domain_id,
slave->f_info.gtid_elms.server_id);
/* Find the GTID */
if (sqlite3_exec(router->gtid_maps,
select_query,
gtid_file_select_cb,
&result,
&errmsg) != SQLITE_OK)
{
MXS_ERROR("Failed to select next file of %s"
" from GTID maps DB: %s, select [%s]",
slave->binlogfile,
errmsg,
select_query);
sqlite3_free(errmsg);
next_file[0] = '\0';
return 0;
}
MXS_INFO("The next Binlog file from GTID maps repo is %s",
result.file);
// Check whether the query has a result
if (result.file)
{
// Full filename path
sprintf(bigbuf,
"%s/%" PRIu32 "/%" PRIu32 "/%s",
router->binlogdir,
result.gtid_elms.domain_id,
result.gtid_elms.server_id,
result.file);
// Set the new file name in the output
strncpy(next_file, result.file, BINLOG_FNAMELEN);
next_file[BINLOG_FNAMELEN] = '\0';
/**
* Update GTID elems in the slave->f_info struct:
* file and domain_id / server_id
*/
if (slave->f_info.file)
{
MXS_FREE(slave->f_info.file);
slave->f_info.file = MXS_STRDUP_A(result.file);
}
slave->f_info.gtid_elms.domain_id = result.gtid_elms.domain_id;
slave->f_info.gtid_elms.server_id = result.gtid_elms.server_id;
MXS_FREE(result.file);
}
else
{
next_file[0] = '\0';
return 0;
}
}
// Check whether the new file exists
if (access(bigbuf, R_OK) == -1)
{
return 0;
@ -2137,6 +2402,7 @@ blr_read_events_all_events(ROUTER_INSTANCE *router,
*/
if (router->mariadb10_compat)
{
char f_prefix[BINLOG_FILE_EXTRA_INFO] = "";
if (hdr.event_type == MARIADB10_GTID_GTID_LIST_EVENT)
{
char mariadb_gtid[GTID_MAX_LEN + 1] = "";
@ -2164,14 +2430,22 @@ blr_read_events_all_events(ROUTER_INSTANCE *router,
snprintf(mariadb_gtid,
GTID_MAX_LEN,
"%u-%u-%lu",
"%" PRIu32 "-%" PRIu32 "-%" PRIu64 "",
domainid,
serverid,
n_sequence);
MXS_DEBUG("GTID List Event has %lu GTIDs, first is %s",
MXS_DEBUG("GTID List Event has %lu GTIDs, first one is %s",
n_gtids,
mariadb_gtid);
if (router->storage_type == BLR_BINLOG_STORAGE_TREE)
{
sprintf(f_prefix,
"%" PRIu32 "/%" PRIu32 "/",
domainid,
serverid);
}
}
else
{
@ -2187,17 +2461,41 @@ blr_read_events_all_events(ROUTER_INSTANCE *router,
"%s",
gtid_info.gtid);
if (router->storage_type == BLR_BINLOG_STORAGE_TREE)
{
sprintf(f_prefix,
"%" PRIu32 "/%" PRIu32 "/",
gtid_info.gtid_elms.domain_id,
gtid_info.gtid_elms.server_id);
}
if (router->mariadb10_gtid)
{
MXS_INFO("Last found MariaDB 10 GTID"
" in GTID maps repo was (%s). File %s%s",
mariadb_gtid,
f_prefix,
gtid_info.file);
}
MXS_FREE(gtid_info.gtid);
MXS_FREE(gtid_info.file);
}
}
/* Set MariaDB GTID */
if (router->mariadb10_gtid)
{
/* Set MariaDB GTID */
strcpy(router->last_mariadb_gtid, mariadb_gtid);
MXS_INFO("Last MariaDB 10 GTID was (%s).",
router->last_mariadb_gtid);
if (router->mariadb10_gtid)
{
MXS_INFO("Last MariaDB 10 GTID (GTID_LIST event)"
" is (%s). File %s%s",
mariadb_gtid,
f_prefix,
router->binlog_name);
}
}
}
}
@ -3438,7 +3736,8 @@ static void blr_report_checksum(REP_HEADER hdr, const uint8_t *buffer, char *out
*/
bool blr_save_mariadb_gtid(ROUTER_INSTANCE *inst)
{
static const char insert_tpl[] = "INSERT OR IGNORE INTO gtid_maps("
int sql_ret;
static const char insert_tpl[] = "INSERT OR FAIL INTO gtid_maps("
"rep_domain, "
"server_id, "
"sequence, "
@ -3452,8 +3751,16 @@ bool blr_save_mariadb_gtid(ROUTER_INSTANCE *inst)
"\"%s\", "
"%" PRIu64 ", "
"%" PRIu64 ");";
static const char update_tpl[] = "UPDATE gtid_maps SET "
"start_pos = %" PRIu64 ", "
"end_pos = %" PRIu64 " "
"WHERE rep_domain = %" PRIu32 " AND "
"server_id = %" PRIu32 " AND "
"sequence = %" PRIu64 " AND "
"binlog_file = \"%s\";";
char *errmsg;
char insert_sql[GTID_SQL_BUFFER_SIZE];
char sql_stmt[GTID_SQL_BUFFER_SIZE];
MARIADB_GTID_INFO gtid_info;
MARIADB_GTID_ELEMS gtid_elms;
@ -3465,8 +3772,8 @@ bool blr_save_mariadb_gtid(ROUTER_INSTANCE *inst)
&inst->pending_transaction.gtid_elms,
sizeof(MARIADB_GTID_ELEMS));
/* Save GTID into repo */
snprintf(insert_sql,
/* Prepare INSERT SQL */
snprintf(sql_stmt,
GTID_SQL_BUFFER_SIZE,
insert_tpl,
gtid_elms.domain_id,
@ -3477,8 +3784,47 @@ bool blr_save_mariadb_gtid(ROUTER_INSTANCE *inst)
gtid_info.end);
/* Save GTID into repo */
if (sqlite3_exec(inst->gtid_maps, insert_sql, NULL, NULL,
&errmsg) != SQLITE_OK)
if ((sql_ret = sqlite3_exec(inst->gtid_maps,
sql_stmt,
NULL,
NULL,
&errmsg)) != SQLITE_OK)
{
if (sql_ret == SQLITE_CONSTRAINT)
{
/* Prepare UPDATE SQL */
snprintf(sql_stmt,
GTID_SQL_BUFFER_SIZE,
update_tpl,
gtid_info.start,
gtid_info.end,
gtid_elms.domain_id,
gtid_elms.server_id,
gtid_elms.seq_no,
gtid_info.file);
/* Update GTID into repo */
if ((sql_ret = sqlite3_exec(inst->gtid_maps,
sql_stmt,
NULL,
NULL,
&errmsg)) != SQLITE_OK)
{
MXS_ERROR("Service %s: failed to update GTID %s for %s:%lu,%lu "
"into gtid_maps database: %s",
inst->service->name,
gtid_info.gtid,
gtid_info.file,
gtid_info.start,
gtid_info.end,
errmsg);
sqlite3_free(errmsg);
return false;
}
/* Remove SQLITE_CONSTRAINT error message */
sqlite3_free(errmsg);
}
else
{
MXS_ERROR("Service %s: failed to insert GTID %s for %s:%lu,%lu "
"into gtid_maps database: %s",
@ -3491,13 +3837,14 @@ bool blr_save_mariadb_gtid(ROUTER_INSTANCE *inst)
sqlite3_free(errmsg);
return false;
}
}
MXS_DEBUG("Saved MariaDB GTID '%s', %s:%lu,%lu, insert SQL [%s]",
MXS_DEBUG("Saved/udated MariaDB GTID '%s', %s:%lu,%lu, SQL [%s]",
gtid_info.gtid,
inst->binlog_name,
gtid_info.start,
gtid_info.end,
insert_sql);
sql_stmt);
return true;
}
@ -3527,8 +3874,22 @@ static int gtid_select_cb(void *data, int cols, char** values, char** names)
result->file = MXS_STRDUP_A(values[1]);
result->start = atoll(values[2]);
result->end = atoll(values[3]);
if (cols > 4)
{
result->gtid_elms.domain_id = atoll(values[4]);
result->gtid_elms.server_id = atoll(values[5]);
result->gtid_elms.seq_no = atoll(values[6]);
}
ss_dassert(result->start > 0 && result->end > result->start);
ss_dassert(result->start > 0 && result->start > 0);
if (result->start > 4)
{
ss_dassert(result->end > result->start);
}
else
{
ss_dassert(result->start > 0 && result->start > 0);
}
}
return 0;
@ -3555,7 +3916,10 @@ bool blr_fetch_mariadb_gtid(ROUTER_SLAVE *slave,
" '-' || sequence) AS gtid, "
"binlog_file, "
"start_pos, "
"end_pos "
"end_pos, "
"rep_domain, "
"server_id, "
"sequence "
"FROM gtid_maps "
"WHERE (rep_domain = %" PRIu32 " AND "
"server_id = %" PRIu32 " AND "
@ -3589,7 +3953,16 @@ bool blr_fetch_mariadb_gtid(ROUTER_SLAVE *slave,
sqlite3_free(errmsg);
return false;
}
else
{
if (result->gtid)
{
MXS_INFO("Binlog file to read from is %" PRIu32 "/%" PRIu32 "/%s",
result->gtid_elms.domain_id,
result->gtid_elms.server_id,
result->file);
}
}
return result->gtid ? true : false;
}
@ -3688,7 +4061,6 @@ bool blr_parse_gtid(const char *gtid, MARIADB_GTID_ELEMS *info)
* Get MariaDB GTID from repo
*
* @param router The current router instance
* @param gtid The GTID to look for
* @param result The (allocated) ouput data to fill
* @return False on sqlite errors
* True even if the gtid_maps is empty
@ -3706,19 +4078,25 @@ bool blr_load_last_mariadb_gtid(ROUTER_INSTANCE *router,
" '-' || sequence) AS gtid, "
"binlog_file, "
"start_pos, "
"end_pos "
"end_pos, "
"rep_domain, "
"server_id, "
"sequence "
"FROM gtid_maps "
"WHERE id = "
"(SELECT MAX(id) FROM gtid_maps);";
"(SELECT MAX(id) "
"FROM gtid_maps "
"WHERE start_pos > 4);";
/* Find the GTID */
/* Find the last GTID */
if (sqlite3_exec(router->gtid_maps,
last_gtid,
gtid_select_cb,
result,
&errmsg) != SQLITE_OK)
{
MXS_ERROR("Failed to select last GTID from GTID maps DB: %s, select [%s]",
MXS_ERROR("Failed to select last GTID"
" from GTID maps DB: %s, select [%s]",
errmsg,
last_gtid);
sqlite3_free(errmsg);
@ -3727,3 +4105,127 @@ bool blr_load_last_mariadb_gtid(ROUTER_INSTANCE *router,
return true;
}
/**
* Select callback for blr_file_next_exists()
*
* @param data Data pointer from caller
* @param cols Number of columns
* @param values The values
* @param names The column names
*
* @return 0 on success, 1 otherwise
*/
static int gtid_file_select_cb(void *data,
int cols,
char** values,
char** names)
{
MARIADB_GTID_INFO *result = (MARIADB_GTID_INFO *)data;
ss_dassert(cols >= 4);
if (values[0] &&
values[1] &&
values[2] &&
values[3])
{
result->file = MXS_STRDUP_A(values[3]);
result->gtid_elms.domain_id = atoll(values[1]);
result->gtid_elms.server_id = atoll(values[2]);
}
return 0;
}
/**
* Get Last file from GTID from repo
*
* @param router The current router instance
* @param result The (allocated) ouput data to fill
* @return False on sqlite errors
* True even if the gtid_maps is empty
* The caller must check result->gtid value
*/
bool blr_get_last_file(ROUTER_INSTANCE *router,
MARIADB_GTID_INFO *result)
{
char *errmsg = NULL;
MARIADB_GTID_ELEMS gtid_elms = {};
static const char last_gtid[] = "SELECT "
"(rep_domain ||"
" '-' || server_id ||"
" '-' || sequence) AS gtid, "
"binlog_file, "
"start_pos, "
"end_pos, "
"rep_domain, "
"server_id, "
"sequence "
"FROM gtid_maps "
"WHERE id = "
"(SELECT MAX(id) FROM gtid_maps);";
/* Find the the last file */
if (sqlite3_exec(router->gtid_maps,
last_gtid,
gtid_select_cb,
result,
&errmsg) != SQLITE_OK)
{
MXS_ERROR("Failed to select last written binlog file"
" from GTID maps DB: %s, select [%s]",
errmsg,
last_gtid);
sqlite3_free(errmsg);
return false;
}
return true;
}
/**
* Compare the specified router file and slave one
*
* @param router The router instance
* @param info Additional file info
* @param r_file The router binlog file
* @param s_file The slave file
* @return True or false
*/
bool blr_compare_binlogs(ROUTER_INSTANCE *router,
const MARIADB_GTID_ELEMS *info,
const char *r_file,
const char *s_file)
{
// Just strcmp()
if (router->storage_type == BLR_BINLOG_STORAGE_FLAT)
{
return strcmp(r_file, s_file) == 0;
}
else
{
// domain_id, server_id and strcmp()
return ((router->mariadb10_gtid_domain == info->domain_id) &&
(router->orig_masterid == info->server_id) &&
strcmp(r_file, r_file) == 0);
}
}
/**
* Check whether the current slave file is the current file
* being written by the router
*
* @param router The router instance
* @param slave The connected slave
* @return True or false
*/
bool blr_is_current_binlog(ROUTER_INSTANCE *router,
ROUTER_SLAVE *slave)
{
return blr_compare_binlogs(router,
&slave->f_info.gtid_elms,
router->binlog_name,
slave->binlogfile);
}

View File

@ -3246,6 +3246,8 @@ static void blr_handle_fake_gtid_list(ROUTER_INSTANCE *router,
router->last_written = hdr->next_pos;
router->last_event_pos = router->current_pos;
router->current_pos = hdr->next_pos;
router->binlog_position = router->current_pos;
router->current_safe_event = router->current_pos;
spinlock_release(&router->binlog_lock);
}

View File

@ -142,7 +142,8 @@ uint8_t *blr_build_header(GWBUF *pkt, REP_HEADER *hdr);
int blr_slave_callback(DCB *dcb, DCB_REASON reason, void *data);
static int blr_slave_fake_rotate(ROUTER_INSTANCE *router,
ROUTER_SLAVE *slave,
BLFILE** filep);
BLFILE** filep,
const char *new_file);
static uint32_t blr_slave_send_fde(ROUTER_INSTANCE *router,
ROUTER_SLAVE *slave,
GWBUF *fde);
@ -313,7 +314,8 @@ static void blr_slave_skip_empty_files(ROUTER_INSTANCE *router,
static inline void blr_get_file_fullpath(const char *binlog_file,
const char *root_dir,
char *full_path);
char *full_path,
const char *f_prefix);
static int blr_show_binary_logs(ROUTER_INSTANCE *router,
ROUTER_SLAVE *slave,
const char *extra_data);
@ -332,6 +334,12 @@ static bool blr_handle_complex_select(ROUTER_INSTANCE *router,
ROUTER_SLAVE *slave,
const char *col1,
const char *coln);
extern bool blr_is_current_binlog(ROUTER_INSTANCE *router,
ROUTER_SLAVE *slave);
extern bool blr_compare_binlogs(ROUTER_INSTANCE *router,
MARIADB_GTID_INFO *slave,
const char *r_file,
const char *s_file);
/**
* Process a request packet from the slave server.
*
@ -1808,7 +1816,7 @@ blr_slave_binlog_dump(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *queue
spinlock_acquire(&router->binlog_lock);
if (router->pending_transaction.state > BLRM_NO_TRANSACTION &&
strcmp(router->binlog_name, slave->binlogfile) == 0 &&
blr_is_current_binlog(router, slave) &&
(slave->binlog_pos > router->binlog_position))
{
force_disconnect = true;
@ -1855,7 +1863,8 @@ blr_slave_binlog_dump(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *queue
/**
* Check whether the request file is empty
* and try using next file in sequence.
* and try using next file in sequence or next one
* based on GTID mpas.
* If one or more files have been skipped then
* the slave->binlog_pos is set to 4 and
* slave->binlogname set to new filename.
@ -2046,6 +2055,9 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large)
int rotating = 0;
long burst_size;
char read_errmsg[BINLOG_ERROR_MSG_LEN + 1];
MARIADB_GTID_INFO *f_tree = router->storage_type == BLR_BINLOG_STORAGE_TREE ?
&slave->f_info :
NULL;
read_errmsg[BINLOG_ERROR_MSG_LEN] = '\0';
@ -2068,7 +2080,7 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large)
/* check for a pending transaction and safe position */
if (router->pending_transaction.state > BLRM_NO_TRANSACTION &&
strcmp(router->binlog_name, slave->binlogfile) == 0 &&
blr_is_current_binlog(router, slave) &&
(slave->binlog_pos > router->binlog_position))
{
do_return = 1;
@ -2098,7 +2110,9 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large)
if (file == NULL)
{
rotating = router->rotating;
if ((file = blr_open_binlog(router, slave->binlogfile)) == NULL)
if ((file = blr_open_binlog(router,
slave->binlogfile,
f_tree)) == NULL)
{
char err_msg[BINLOG_ERROR_MSG_LEN + 1];
err_msg[BINLOG_ERROR_MSG_LEN] = '\0';
@ -2244,9 +2258,13 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large)
beat1 = hkheartbeat;
#ifdef BLFILE_IN_SLAVE
if ((slave->file = blr_open_binlog(router, slave->binlogfile)) == NULL)
if ((slave->file = blr_open_binlog(router,
slave->binlogfile,
f_tree)) == NULL)
#else
if ((file = blr_open_binlog(router, slave->binlogfile)) == NULL)
if ((file = blr_open_binlog(router,
slave->binlogfile,
f_tree)) == NULL)
#endif
{
char err_msg[BINLOG_ERROR_MSG_LEN + 1];
@ -2276,14 +2294,19 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large)
/* Send error that stops slave replication */
blr_send_custom_error(slave->dcb,
(slave->seqno - 1),
slave->seqno,
0,
err_msg,
"HY000",
BINLOG_FATAL_ERROR_READING);
gwbuf_free(record);
record = NULL;
slave->state = BLRS_ERRORED;
dcb_close(slave->dcb);
break;
return 0;
}
#ifdef BLFILE_IN_SLAVE
file = slave->file;
@ -2440,7 +2463,7 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large)
poll_fake_write_event(slave->dcb);
}
else if (slave->binlog_pos == router->binlog_position &&
strcmp(slave->binlogfile, router->binlog_name) == 0)
blr_is_current_binlog(router, slave))
{
spinlock_acquire(&router->binlog_lock);
spinlock_acquire(&slave->catch_lock);
@ -2450,7 +2473,7 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large)
* and slave->catch_lock.
*/
if (slave->binlog_pos != router->binlog_position ||
strcmp(slave->binlogfile, router->binlog_name) != 0)
!blr_is_current_binlog(router, slave))
{
slave->cstate |= CS_EXPECTCB;
spinlock_release(&slave->catch_lock);
@ -2473,10 +2496,11 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large)
}
else
{
if (slave->binlog_pos >= blr_file_size(file)
&& router->rotating == 0
&& strcmp(router->binlog_name, slave->binlogfile) != 0
&& blr_file_next_exists(router, slave))
char next_file[BINLOG_FNAMELEN + 1] = "";
if (slave->binlog_pos >= blr_file_size(file) &&
router->rotating == 0 &&
(!blr_is_current_binlog(router, slave) &&
blr_file_next_exists(router, slave, next_file)))
{
/* We may have reached the end of file of a non-current
* binlog file.
@ -2501,10 +2525,11 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large)
MXS_FREE(slave->encryption_ctx);
slave->encryption_ctx = NULL;
/* Now pass the next_file to blr_slave_fake_rotate() */
#ifdef BLFILE_IN_SLAVE
if (blr_slave_fake_rotate(router, slave, &slave->file))
if (blr_slave_fake_rotate(router, slave, &slave->file, next_file))
#else
if (blr_slave_fake_rotate(router, slave, &file))
if (blr_slave_fake_rotate(router, slave, &file, next_file))
#endif
{
spinlock_acquire(&slave->catch_lock);
@ -2516,6 +2541,10 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large)
{
slave->state = BLRS_ERRORED;
dcb_close(slave->dcb);
#ifndef BLFILE_IN_SLAVE
blr_close_binlog(router, file);
#endif
return 0;
}
}
else
@ -2604,6 +2633,7 @@ blr_slave_callback(DCB *dcb, DCB_REASON reason, void *data)
/**
* Rotate the slave to the new binlog file
*
* @param router The router instance
* @param slave The slave instance
* @param ptr The rotate event (minus header and OK byte)
*/
@ -2632,7 +2662,7 @@ blr_slave_rotate(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, uint8_t *ptr)
/**
* Generate an internal rotate event that we can use to cause
* the slave to move beyond a binlog file
* that is missisng the rotate eent at the end.
* that is missisng the rotate event at the end.
*
* @param router The router instance
* @param slave The slave to rotate
@ -2641,26 +2671,30 @@ blr_slave_rotate(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, uint8_t *ptr)
static int
blr_slave_fake_rotate(ROUTER_INSTANCE *router,
ROUTER_SLAVE *slave,
BLFILE** filep)
BLFILE** filep,
const char *new_file)
{
char *sptr;
int filenum;
GWBUF *r_event;
MARIADB_GTID_INFO *f_tree = router->storage_type == BLR_BINLOG_STORAGE_TREE ?
&slave->f_info :
NULL;
if ((sptr = strrchr(slave->binlogfile, '.')) == NULL)
if ((sptr = strrchr(new_file, '.')) == NULL)
{
return 0;
}
blr_close_binlog(router, *filep);
filenum = atoi(sptr + 1);
sprintf(slave->binlogfile,
BINLOG_NAMEFMT,
router->fileroot,
filenum + 1);
/* Set Pos = 4 */
slave->binlog_pos = 4;
if ((*filep = blr_open_binlog(router, slave->binlogfile)) == NULL)
/* Set Filename */
strcpy(slave->binlogfile, new_file);
if ((*filep = blr_open_binlog(router,
new_file,
f_tree)) == NULL)
{
return 0;
}
@ -2668,7 +2702,7 @@ blr_slave_fake_rotate(ROUTER_INSTANCE *router,
/* Build Fake Rotate Event */
r_event = blr_build_fake_rotate_event(slave,
slave->binlog_pos,
slave->binlogfile,
new_file,
router->masterid);
return r_event ? slave->dcb->func.write(slave->dcb, r_event) : 0;
@ -2690,12 +2724,17 @@ blr_slave_read_fde(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave)
uint8_t *ptr;
uint32_t chksum;
char err_msg[BINLOG_ERROR_MSG_LEN + 1];
MARIADB_GTID_INFO *f_tree = router->storage_type == BLR_BINLOG_STORAGE_TREE ?
&slave->f_info :
NULL;
err_msg[BINLOG_ERROR_MSG_LEN] = '\0';
memset(&hdr, 0, BINLOG_EVENT_HDR_LEN);
if ((file = blr_open_binlog(router, slave->binlogfile)) == NULL)
if ((file = blr_open_binlog(router,
slave->binlogfile,
f_tree)) == NULL)
{
return NULL;
}
@ -5899,13 +5938,18 @@ blr_slave_read_ste(ROUTER_INSTANCE *router,
uint8_t *ptr;
uint32_t chksum;
char err_msg[BINLOG_ERROR_MSG_LEN + 1];
MARIADB_GTID_INFO *f_tree = router->storage_type == BLR_BINLOG_STORAGE_TREE ?
&slave->f_info :
NULL;
err_msg[BINLOG_ERROR_MSG_LEN] = '\0';
memset(&hdr, 0, BINLOG_EVENT_HDR_LEN);
BLFILE *file;
if ((file = blr_open_binlog(router, slave->binlogfile)) == NULL)
if ((file = blr_open_binlog(router,
slave->binlogfile,
f_tree)) == NULL)
{
return 0;
}
@ -6374,6 +6418,26 @@ static bool blr_slave_gtid_request(ROUTER_INSTANCE *router,
bool req_file,
unsigned long req_pos)
{
MARIADB_GTID_INFO f_gtid = {};
uint32_t router_pos;
char router_curr_file[BINLOG_FNAMELEN + 1];
char last_gtid[GTID_MAX_LEN + 1];
spinlock_acquire(&router->binlog_lock);
// Set gtid as current router gtid
strcpy(last_gtid, router->last_mariadb_gtid);
// Set file as router current file
strcpy(router_curr_file, router->binlog_name);
// Set safe postion of current ruter file
router_pos = router->binlog_position;
// Set domain_id, server_id in case of empty/not found GTID
if (router->storage_type == BLR_BINLOG_STORAGE_TREE)
{
f_gtid.gtid_elms.domain_id = router->mariadb10_gtid_domain;
f_gtid.gtid_elms.server_id = router->orig_masterid;
}
spinlock_release(&router->binlog_lock);
MXS_INFO("Slave %lu is registering with MariaDB GTID '%s'",
(unsigned long)slave->serverid,
slave->mariadb_gtid);
@ -6384,15 +6448,22 @@ static bool blr_slave_gtid_request(ROUTER_INSTANCE *router,
* Empty GTID:
* Sending data from the router current file and pos 4
*/
strcpy(slave->binlogfile, router_curr_file);
slave->binlog_pos = 4;
MXS_INFO("Slave %lu is registering with empty GTID:"
" sending events from current binlog file %s, pos %lu",
" sending events from current binlog file %s,"
" pos %" PRIu32 "",
(unsigned long)slave->serverid,
slave->binlogfile,
(unsigned long)slave->binlog_pos);
slave->binlog_pos);
/* Add GTID details to slave struct */
memcpy(&slave->f_info, &f_gtid, sizeof(MARIADB_GTID_INFO));
return true;
}
else
{
MARIADB_GTID_INFO f_gtid = {};
char dbpath[PATH_MAX + 1];
snprintf(dbpath, sizeof(dbpath), "/%s/%s",
router->binlogdir, GTID_MAPS_DB);
@ -6412,6 +6483,7 @@ static bool blr_slave_gtid_request(ROUTER_INSTANCE *router,
sqlite3_errmsg(slave->gtid_maps));
slave->gtid_maps = NULL;
return false;
}
else
{
@ -6447,16 +6519,34 @@ static bool blr_slave_gtid_request(ROUTER_INSTANCE *router,
}
else
{
/* Right now: just use current router binlog file pos 4 */
/* No strict mode: */
// - 1 -Set request GTID as current master one
MXS_FREE(slave->mariadb_gtid);
slave->mariadb_gtid = MXS_STRDUP_A(last_gtid);
// - 2 - Use current router file and position
strcpy(slave->binlogfile, router_curr_file);
slave->binlog_pos = router_pos;
// - 3 Set GTID details for filename
if (router->storage_type == BLR_BINLOG_STORAGE_TREE)
{
memcpy(&slave->f_info, &f_gtid, sizeof(MARIADB_GTID_INFO));
}
}
}
else
{
/* GTID has been found */
MXS_INFO("Found GTID '%s' for slave %lu at %s:%lu",
MXS_INFO("Found GTID '%s' for slave %" PRIu32 ""
" at %" PRIu32 "/%" PRIu32 "/%s:%" PRIu64 ""
". Next event at %" PRIu64 "",
slave->mariadb_gtid,
(unsigned long)slave->serverid,
slave->serverid,
f_gtid.gtid_elms.domain_id,
f_gtid.gtid_elms.server_id,
f_gtid.file,
f_gtid.start,
f_gtid.end);
/**
@ -6487,6 +6577,9 @@ static bool blr_slave_gtid_request(ROUTER_INSTANCE *router,
slave->binlog_pos = req_pos;
}
/* Set GTID details in f_info*/
memcpy(&slave->f_info, &f_gtid, sizeof(MARIADB_GTID_INFO));
/* Free gtid and file from result */
MXS_FREE(f_gtid.gtid);
MXS_FREE(f_gtid.file);
@ -7074,7 +7167,7 @@ static bool blr_handle_set_stmt(ROUTER_INSTANCE *router,
}
return true;
}
else if (strstr(word, "@@global.gtid_slave_pos") != NULL)
else if (strcasecmp(word, "@@global.gtid_slave_pos") == 0)
{
if (slave->serverid != 0)
{
@ -7172,7 +7265,7 @@ static bool blr_handle_set_stmt(ROUTER_INSTANCE *router,
* in case of a fresh new setup.
*/
MXS_FREE(slave->mariadb_gtid);
slave->mariadb_gtid = MXS_STRDUP(heading);
slave->mariadb_gtid = MXS_STRDUP_A(heading);
blr_slave_send_ok(router, slave);
return true;
@ -7598,11 +7691,16 @@ static bool blr_handle_admin_stmt(ROUTER_INSTANCE *router,
static void blr_slave_skip_empty_files(ROUTER_INSTANCE *router,
ROUTER_SLAVE *slave)
{
char binlog_file[BLRM_BINLOG_NAME_STR_LEN + 1];
char router_curr_file[BLRM_BINLOG_NAME_STR_LEN + 1];
char binlog_file[BINLOG_FNAMELEN + 1];
char router_curr_file[BINLOG_FNAMELEN + 1];
char file_path[PATH_MAX + 1] = "";
unsigned int seqno;
bool skipped_files = false;
char t_prefix[BINLOG_FILE_EXTRA_INFO] = "";
MARIADB_GTID_INFO *f_tree = router->storage_type == BLR_BINLOG_STORAGE_TREE ?
&slave->f_info :
NULL;
char next_file[BINLOG_FNAMELEN + 1] = "";
// Save the current router binlog filename
spinlock_acquire(&router->binlog_lock);
@ -7612,18 +7710,32 @@ static void blr_slave_skip_empty_files(ROUTER_INSTANCE *router,
// Set the starting filename
strcpy(binlog_file, slave->binlogfile);
//Add tree prefix
if (f_tree)
{
sprintf(t_prefix,
"%" PRIu32 "/%" PRIu32 "/",
f_tree->gtid_elms.domain_id,
f_tree->gtid_elms.server_id);
}
// Get binlog filename full-path
blr_get_file_fullpath(binlog_file,
router->binlogdir,
file_path);
file_path,
t_prefix[0] ? t_prefix: NULL);
/**
* Set the next file in sequence if current file has 4 bytes size.
* Stop if the new file is the urrent binlog file.
* Get the next file in sequence or next by GTID maps
* if current file has 4 bytes size.
* Stop if the new file is the current binlog file.
*/
while (strcmp(binlog_file, router_curr_file) != 0 &&
while (!blr_compare_binlogs(router,
f_tree,
router_curr_file,
binlog_file) &&
blr_slave_get_file_size(file_path) == 4 &&
(seqno = blr_file_get_next_seqno(binlog_file)) > 0)
blr_file_next_exists(router, slave, next_file))
{
// Log skipped file
MXS_INFO("Slave %s:%i, skip reading empty file '%s' (4 bytes size).",
@ -7631,13 +7743,14 @@ static void blr_slave_skip_empty_files(ROUTER_INSTANCE *router,
dcb_get_port(slave->dcb),
binlog_file);
// Set next in sequence binlog file name
sprintf(binlog_file, BINLOG_NAMEFMT, router->fileroot, seqno);
// Update binlog_file name
sprintf(binlog_file, next_file);
// Get binlog file full-path
blr_get_file_fullpath(binlog_file,
router->binlogdir,
file_path);
file_path,
t_prefix[0] ? t_prefix: NULL);
skipped_files = true;
}
@ -7657,13 +7770,20 @@ static void blr_slave_skip_empty_files(ROUTER_INSTANCE *router,
* @param root_dir The binlog storage directory
* @param full_path The output fullpahth name:
* the memory area must be preallocated.
* @param t_prefix The file_tree prefix with rep_domain
* and server_id.
*/
static inline void blr_get_file_fullpath(const char *binlog_file,
const char *root_dir,
char *full_path)
char *full_path,
const char *t_prefix)
{
strcpy(full_path, root_dir);
strcat(full_path, "/");
if (t_prefix)
{
strcat(full_path, t_prefix);
}
strcat(full_path, binlog_file);
}
@ -7775,6 +7895,7 @@ blr_show_binary_logs(ROUTER_INSTANCE *router,
* Check whether the last file is the current binlog file.
* If not then add the new row.
*/
// TODO: check whether to FIX with prefix
if (strcmp(current_file, result.last_file) != 0)
{
char pos[40];
@ -7871,6 +7992,12 @@ static int binary_logs_select_cb(void *data,
char filename[1 +
strlen(values[0]) +
BINLOG_FILE_EXTRA_INFO];
char t_prefix[BINLOG_FILE_EXTRA_INFO] = "";
sprintf(t_prefix,
"%s/%s/",
values[2], // domain ID
values[3]); // server ID
fsize = atoll(values[1]);
@ -7890,7 +8017,8 @@ static int binary_logs_select_cb(void *data,
//Get binlog filename full-path
blr_get_file_fullpath(values[0],
data_set->binlogdir,
file_path);
file_path,
t_prefix);
//Get the file size
fsize = blr_slave_get_file_size(file_path);
@ -7900,9 +8028,8 @@ static int binary_logs_select_cb(void *data,
if (data_set->extra_info)
{
sprintf(filename,
"%s/%s/%s",
values[2], // domain ID
values[3], // server ID
"%s%s",
t_prefix,
values[0]); // filename
}
else