From 755a3601ecc6f8c28adb69e9f018550ecc682163 Mon Sep 17 00:00:00 2001 From: MassimilianoPinto Date: Thu, 16 Feb 2017 09:45:43 +0100 Subject: [PATCH] MXS-1141: maxbinlogcheck to replace an event with ignorable event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit maxbinlogcheck utility can replace an event at pos with an ignorable event New option is -R, —replace -R $pos The -R needs -f as file will be modified --- server/modules/routing/binlogrouter/blr.c | 3 +- server/modules/routing/binlogrouter/blr.h | 20 ++++++++++- .../modules/routing/binlogrouter/blr_file.c | 34 ++++++++++++++++--- .../routing/binlogrouter/maxbinlogcheck.c | 19 +++++++---- 4 files changed, 61 insertions(+), 15 deletions(-) diff --git a/server/modules/routing/binlogrouter/blr.c b/server/modules/routing/binlogrouter/blr.c index 553b483d7..58dc408ed 100644 --- a/server/modules/routing/binlogrouter/blr.c +++ b/server/modules/routing/binlogrouter/blr.c @@ -111,7 +111,6 @@ static int blr_handler_config(void *userdata, const char *section, const char *n static int blr_handle_config_item(const char *name, const char *value, ROUTER_INSTANCE *inst); static int blr_load_dbusers(const ROUTER_INSTANCE *router); static int blr_check_binlog(ROUTER_INSTANCE *router); -int blr_read_events_all_events(ROUTER_INSTANCE *router, int fix, int debug); void blr_master_close(ROUTER_INSTANCE *); void blr_free_ssl_data(ROUTER_INSTANCE *inst); static void destroyInstance(MXS_ROUTER *instance); @@ -2304,7 +2303,7 @@ static int blr_check_binlog(ROUTER_INSTANCE *router) * router->current_pos is the last event found. */ - n = blr_read_events_all_events(router, 0, 0); + n = blr_read_events_all_events(router, NULL, 0); MXS_DEBUG("blr_read_events_all_events() ret = %i\n", n); diff --git a/server/modules/routing/binlogrouter/blr.h b/server/modules/routing/binlogrouter/blr.h index d865314d2..06e14921a 100644 --- a/server/modules/routing/binlogrouter/blr.h +++ b/server/modules/routing/binlogrouter/blr.h @@ -73,6 +73,7 @@ MXS_BEGIN_DECLS /* BINLOG_EVENT_LEN_OFFSET points to event_size in event_header */ #define BINLOG_EVENT_LEN_OFFSET 9 #define BINLOG_FATAL_ERROR_READING 1236 +#define BINLOG_DATA_TRUNCATED 2032 /* Binlog Encryption */ #define BINLOG_ENC_ALGO_NAME_LEN 13 @@ -638,6 +639,23 @@ typedef struct binlog_encryption_ctx char *binlog_file; /**< Current binlog file being encrypted */ } BINLOG_ENCRYPTION_CTX; +/** + * Holds information about: + * truncating a corrupted file + * or replace an event at specified pos + * or replace a transaction that start + * at specified pos + */ + +typedef struct binlog_pos_fix +{ + bool fix; /**< Truncate file to last safe pos */ + uint64_t pos; /**< Position of the event to be replaced + * by an Ignorable Event */ + bool replace_trx; /**< Replace all events belonging to + * a transaction starting at pos */ +} BINLOG_FILE_FIX; + /** * Defines and offsets for binlog encryption * @@ -809,7 +827,7 @@ extern int blr_send_custom_error(DCB *, int, int, char *, char *, unsigned int); extern int blr_file_next_exists(ROUTER_INSTANCE *, ROUTER_SLAVE *); 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 *router, int fix, int debug); +int blr_read_events_all_events(ROUTER_INSTANCE *, const BINLOG_FILE_FIX *, int); int blr_save_dbusers(const ROUTER_INSTANCE *router); char *blr_get_event_description(ROUTER_INSTANCE *router, uint8_t event); void blr_file_append(ROUTER_INSTANCE *router, char *file); diff --git a/server/modules/routing/binlogrouter/blr_file.c b/server/modules/routing/binlogrouter/blr_file.c index 86d5e4175..fce54c176 100644 --- a/server/modules/routing/binlogrouter/blr_file.c +++ b/server/modules/routing/binlogrouter/blr_file.c @@ -1297,13 +1297,15 @@ blr_file_next_exists(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave) * * Routine detects errors and pending transactions * - * @param router The router instance - * @param fix Whether to fix or not errors - * @param debug Whether to enable or not the debug for events - * @return 0 on success, >0 on failure + * @param router The router instance + * @param action Whether to fix errors or blank events at pos + * @param debug Whether to enable or not the debug for events + * @return 0 on success, >0 on failure */ int -blr_read_events_all_events(ROUTER_INSTANCE *router, int fix, int debug) +blr_read_events_all_events(ROUTER_INSTANCE *router, + const BINLOG_FILE_FIX *action, + int debug) { unsigned long filelen = 0; struct stat statb; @@ -1337,6 +1339,7 @@ blr_read_events_all_events(ROUTER_INSTANCE *router, int fix, int debug) BINLOG_EVENT_DESC fde_event; int fde_seen = 0; int start_encryption_seen = 0; + bool fix = action ? action->fix : false; memset(&first_event, '\0', sizeof(first_event)); memset(&last_event, '\0', sizeof(last_event)); @@ -1973,6 +1976,27 @@ blr_read_events_all_events(ROUTER_INSTANCE *router, int fix, int debug) } } + /** + * Replace event at pos with an IGNORABLE EVENT + */ + + if (fix && + action->pos > 4 && + pos == action->pos) + { + char *event_desc = blr_get_event_description(router, hdr.event_type); + + MXS_DEBUG("*** Filling event (%s) at pos %lu with an IGNORABLE EVENT\n", + event_desc ? event_desc : "unknown", + action->pos); + + router->last_written = action->pos; + router->master_chksum = found_chksum; + + /* Create and write Ingonrable event into binlog file at action->pos */ + blr_write_special_event(router, pos, hdr.event_size, &hdr, BLRM_IGNORABLE); + } + /* If MariaDB 10 compatibility: * check for MARIADB10_GTID_EVENT with flags * This marks the transaction starts instead of diff --git a/server/modules/routing/binlogrouter/maxbinlogcheck.c b/server/modules/routing/binlogrouter/maxbinlogcheck.c index 820b9aa3d..2a0877323 100644 --- a/server/modules/routing/binlogrouter/maxbinlogcheck.c +++ b/server/modules/routing/binlogrouter/maxbinlogcheck.c @@ -65,11 +65,12 @@ static struct option long_options[] = {"header", no_argument, 0, 'H'}, {"key_file", required_argument, 0, 'K'}, {"aes_algo", required_argument, 0, 'A'}, + {"replace", required_argument, 0, 'R'}, {"help", no_argument, 0, '?'}, {0, 0, 0, 0} }; -char *binlog_check_version = "2.1.0"; +char *binlog_check_version = "2.2.0"; int maxscale_uptime() @@ -81,14 +82,14 @@ int main(int argc, char **argv) { int option_index = 0; int debug_out = 0; - int fix_file = 0; int mariadb10_compat = 0; char *key_file = NULL; char *aes_algo = NULL; int report_header = 0; char c; + BINLOG_FILE_FIX binlog_file = {0, false, false}; - while ((c = getopt_long(argc, argv, "dVfMHK:A:?", long_options, &option_index)) >= 0) + while ((c = getopt_long(argc, argv, "dVfMHK:A:R:?", long_options, &option_index)) >= 0) { switch (c) { @@ -103,7 +104,7 @@ int main(int argc, char **argv) exit(EXIT_SUCCESS); break; case 'f': - fix_file = 1; + binlog_file.fix = true; break; case 'M': mariadb10_compat = 1; @@ -114,6 +115,9 @@ int main(int argc, char **argv) case 'A': aes_algo = optarg; break; + case 'R': + binlog_file.pos = atol(optarg); + break; case '?': printUsage(*argv); exit(optopt ? EXIT_FAILURE : EXIT_SUCCESS); @@ -162,7 +166,7 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } - int fd = open(path, fix_file ? O_RDWR : O_RDONLY, 0666); + int fd = open(path, binlog_file.fix ? O_RDWR : O_RDONLY, 0666); if (fd == -1) { printf("ERROR: Failed to open binlog file %s: %s.\n", @@ -203,7 +207,7 @@ int main(int argc, char **argv) MXS_NOTICE("Checking %s (%s), size %lu bytes", path, inst->binlog_name, filelen); /* read binary log */ - int ret = blr_read_events_all_events(inst, fix_file, debug_out | report_header); + int ret = blr_read_events_all_events(inst, &binlog_file, debug_out | report_header); mxs_log_flush_sync(); @@ -236,7 +240,7 @@ printUsage(const char *progname) printVersion(progname); printf("The MaxScale binlog check utility.\n\n"); - printf("Usage: %s [-f] [-d] [-v] []\n\n", progname); + printf("Usage: %s [-f] [-M] [-d] [-V] [-H] [-K file] [-A algo] [-R pos] []\n\n", progname); printf(" -f|--fix Fix binlog file, require write permissions (truncate)\n"); printf(" -d|--debug Print debug messages\n"); printf(" -M|--mariadb10 MariaDB 10 binlog compatibility\n"); @@ -244,6 +248,7 @@ printUsage(const char *progname) printf(" -K|--key_file AES Key file for MariaDB 10.1 binlog file decryption\n"); printf(" -A|--aes_algo AES Algorithm for MariaDB 10.1 binlog file decryption (default=AES_CBC, AES_CTR)\n"); printf(" -H|--header Print content of binlog event header\n"); + printf(" -R|--replace Replace the event at pos with an IGNORABLE EVENT\n"); printf(" -?|--help Print this help text\n"); }