From 947de2bfaf24599a1df185f40498ef5a24b670cd Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Tue, 7 Jan 2025 09:41:32 +0100 Subject: [PATCH] MDEV-34705: Binlog-in-engine: Implement SHOW BINARY LOGS Signed-off-by: Kristian Nielsen --- .../binlog_in_engine_restart.test | 2 + sql/handler.h | 13 ++++++ sql/sql_repl.cc | 14 +++--- storage/innobase/handler/ha_innodb.cc | 29 ++++++++++++ storage/innobase/handler/innodb_binlog.cc | 46 ++++++++++++++++++- storage/innobase/include/innodb_binlog.h | 1 + 6 files changed, 97 insertions(+), 8 deletions(-) diff --git a/mysql-test/suite/binlog_in_engine/binlog_in_engine_restart.test b/mysql-test/suite/binlog_in_engine/binlog_in_engine_restart.test index de3f5ee2050..e69601409b8 100644 --- a/mysql-test/suite/binlog_in_engine/binlog_in_engine_restart.test +++ b/mysql-test/suite/binlog_in_engine/binlog_in_engine_restart.test @@ -40,6 +40,8 @@ while ($i < 10) { inc $i; } +SHOW BINARY LOGS; + --exec $MYSQL_BINLOG --start-position=$gtid_pos3 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog3.txt DROP TABLE t1; diff --git a/sql/handler.h b/sql/handler.h index 3b3f8608ae9..dad2ec612b7 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1230,6 +1230,17 @@ typedef struct st_ha_create_table_option { struct st_mysql_sys_var *var; } ha_create_table_option; + +/* Struct used to return binlog file list for SHOW BINARY LOGS from engine. */ +struct binlog_file_entry +{ + binlog_file_entry *next; + LEX_CSTRING name; + /* The size is filled in by server, engine need not return it. */ + my_off_t size; +}; + + class handler; class group_by_handler; class derived_handler; @@ -1552,6 +1563,8 @@ struct handlerton void (*binlog_oob_free)(THD *thd, void *engine_data); /* Obtain an object to allow reading from the binlog. */ handler_binlog_reader * (*get_binlog_reader)(); + /* Obtain list of binlog files (SHOw BINARY LOGS). */ + binlog_file_entry * (*get_binlog_file_list)(MEM_ROOT *mem_root); /* Optional clauses in the CREATE/ALTER TABLE diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 4920399edee..b82772a663a 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -990,13 +990,6 @@ static int send_heartbeat_event(binlog_send_info *info, } -struct binlog_file_entry -{ - binlog_file_entry *next; - LEX_CSTRING name; - my_off_t size; -}; - /** Read all binary logs and return as a list @@ -1021,6 +1014,13 @@ get_binlog_list(MEM_ROOT *memroot, bool reverse= true, binlog_file_entry *current_list= NULL, *current_link= NULL, *e; DBUG_ENTER("get_binlog_list"); + if (opt_binlog_engine_hton) + { + if (already_locked) + mysql_bin_log.unlock_index(); + DBUG_RETURN((*opt_binlog_engine_hton->get_binlog_file_list)(memroot)); + } + if (!mysql_bin_log.is_open()) { if (already_locked) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index e262a5cad2d..fd077057a9e 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4024,6 +4024,34 @@ static void innobase_update_optimizer_costs(OPTIMIZER_COSTS *costs) } +static binlog_file_entry *innodb_get_binlog_file_list(MEM_ROOT *mem_root) +{ + uint64_t first, last; + if (innodb_find_binlogs(&first, &last)) + return nullptr; + binlog_file_entry *list; + binlog_file_entry **next_ptr= &list; + for (uint64_t i= first; i <= last; ++i) + { + binlog_file_entry *e= (binlog_file_entry *)alloc_root(mem_root, sizeof(*e)); + if (!e) + return nullptr; + char name_buf[OS_FILE_MAX_PATH]; + binlog_name_make(name_buf, i); + e->name.length= strlen(name_buf); + char *str= (char *)alloc_root(mem_root, e->name.length + 1); + if (!str) + return nullptr; + strcpy(str, name_buf); + e->name.str= str; + *next_ptr= e; + next_ptr= &(e->next); + } + *next_ptr= nullptr; + return list; +} + + /** Initialize the InnoDB storage engine plugin. @param[in,out] p InnoDB handlerton @return error code @@ -4097,6 +4125,7 @@ static int innodb_init(void* p) innobase_hton->binlog_oob_data= innodb_binlog_oob; innobase_hton->binlog_oob_free= innodb_free_oob; innobase_hton->get_binlog_reader= innodb_get_binlog_reader; + innobase_hton->get_binlog_file_list= innodb_get_binlog_file_list; innodb_remember_check_sysvar_funcs(); diff --git a/storage/innobase/handler/innodb_binlog.cc b/storage/innobase/handler/innodb_binlog.cc index 4654e873eb8..8961d3a2ddf 100644 --- a/storage/innobase/handler/innodb_binlog.cc +++ b/storage/innobase/handler/innodb_binlog.cc @@ -667,7 +667,7 @@ innodb_binlog_discover() struct found_binlogs UNINIT_VAR(binlog_files); binlog_files.found_binlogs= 0; size_t num_entries= dir->number_of_files; - fileinfo *entries= dir-> dir_entry; + fileinfo *entries= dir->dir_entry; for (size_t i= 0; i < num_entries; ++i) { const char *name= entries[i].name; uint64_t idx; @@ -2131,3 +2131,47 @@ innobase_binlog_write_direct(IO_CACHE *cache, /* ToDo: Presumably innodb_binlog_write_cache() should be able to fail in some cases? Then return any such error to the caller. */ return false; } + + +bool +innodb_find_binlogs(uint64_t *out_first, uint64_t *out_last) +{ + MY_DIR *dir= my_dir(innodb_binlog_directory, MYF(0)); + if (!dir) + { + ib::error() << "Could not read the binlog directory '" << + innodb_binlog_directory << "', error code " << my_errno << "."; + return true; + } + + size_t num_entries= dir->number_of_files; + fileinfo *entries= dir->dir_entry; + uint64_t first_file_no, last_file_no; + uint64_t num_file_no= 0; + for (size_t i= 0; i < num_entries; ++i) { + const char *name= entries[i].name; + uint64_t file_no; + if (!is_binlog_name(name, &file_no)) + continue; + if (num_file_no == 0 || file_no < first_file_no) + first_file_no= file_no; + if (num_file_no == 0 || file_no > last_file_no) + last_file_no= file_no; + ++num_file_no; + } + my_dirend(dir); + + if (num_file_no == 0) + { + ib::error() << "No binlog files found (deleted externally?)"; + return true; + } + if (num_file_no != last_file_no - first_file_no + 1) + { + ib::error() << "Missing binlog files (deleted externally?)"; + return true; + } + *out_first= first_file_no; + *out_last= last_file_no; + return false; +} diff --git a/storage/innobase/include/innodb_binlog.h b/storage/innobase/include/innodb_binlog.h index bb492f11980..d0a787e7cad 100644 --- a/storage/innobase/include/innodb_binlog.h +++ b/storage/innobase/include/innodb_binlog.h @@ -97,5 +97,6 @@ extern void innodb_binlog_trx(trx_t *trx, mtr_t *mtr); extern bool innobase_binlog_write_direct (IO_CACHE *cache, handler_binlog_event_group_info *binlog_info, const rpl_gtid *gtid); +extern bool innodb_find_binlogs(uint64_t *out_first, uint64_t *out_last); #endif /* innodb_binlog_h */