mirror of
https://github.com/MariaDB/server.git
synced 2025-01-15 19:42:28 +01:00
MDEV-34705: Binlog-in-engine: Implement RESET MASTER
Signed-off-by: Kristian Nielsen <knielsen@knielsen-hq.org>
This commit is contained in:
parent
85cb7e1ba7
commit
6c91b099b8
14 changed files with 163 additions and 32 deletions
|
@ -1,6 +1,8 @@
|
|||
--source include/have_binlog_format_row.inc
|
||||
--source include/have_innodb_binlog.inc
|
||||
|
||||
RESET MASTER;
|
||||
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
CREATE TABLE t2 (a INT PRIMARY KEY, b VARCHAR(2048)) ENGINE=InnoDB;
|
||||
INSERT INTO t1 VALUES (1);
|
||||
|
@ -18,4 +20,16 @@ SHOW BINARY LOGS;
|
|||
FLUSH BINARY LOGS;
|
||||
SHOW BINARY LOGS;
|
||||
|
||||
RESET MASTER;
|
||||
# ToDo: This will be racy, the second binlog file binlog-000001.ibb is
|
||||
# pre-allocated in the background, so will be visible or not depending on exact
|
||||
# timing. So just omit this SHOW BINARY LOGS or wait for both to be created
|
||||
# or something.
|
||||
SHOW BINARY LOGS;
|
||||
|
||||
INSERT INTO t1 VALUES (100);
|
||||
INSERT INTO t2 VALUES (100, 'xyzzy');
|
||||
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
--exec $MYSQL_BINLOG --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 --start-position=0-1-1 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog.txt
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
# files and only need to include the one.
|
||||
--source include/have_innodb_binlog.inc
|
||||
|
||||
RESET MASTER;
|
||||
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
--let $gtid_pos= `SELECT @@last_gtid`
|
||||
INSERT INTO t1 VALUES (1);
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
--source include/have_binlog_format_mixed.inc
|
||||
--source include/have_innodb_binlog.inc
|
||||
|
||||
# RESET MASTER deliberately omitted here for now; the test should be able to
|
||||
# work on top of any existing binlog.
|
||||
|
||||
CREATE TABLE sbtest1(
|
||||
id INTEGER NOT NULL AUTO_INCREMENT,
|
||||
k INTEGER DEFAULT '0' NOT NULL,
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
# Note: This test also tests the --binlog-directory option by putting it
|
||||
# in binlog_in_engine_restart.opt .
|
||||
|
||||
RESET MASTER;
|
||||
|
||||
CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||
INSERT INTO t1 VALUES (1, 0);
|
||||
let $i= 0;
|
||||
|
|
|
@ -1570,6 +1570,8 @@ struct handlerton
|
|||
Used to implement FLUSH BINARY LOGS.
|
||||
*/
|
||||
bool (*binlog_flush)();
|
||||
/* Engine implementation of RESET MASTER. */
|
||||
bool (*reset_binlogs)();
|
||||
|
||||
/*
|
||||
Optional clauses in the CREATE/ALTER TABLE
|
||||
|
|
34
sql/log.cc
34
sql/log.cc
|
@ -4466,6 +4466,17 @@ bool MYSQL_BIN_LOG::reset_logs(THD *thd, bool create_new_log,
|
|||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
if (opt_binlog_engine_hton)
|
||||
{
|
||||
if (next_log_number)
|
||||
{
|
||||
my_error(ER_ENGINE_BINLOG_NO_RESET_FILE_NUMBER, MYF(0));
|
||||
DBUG_RETURN(true);
|
||||
}
|
||||
DBUG_ASSERT(create_new_log);
|
||||
DBUG_RETURN(reset_engine_binlogs(thd, init_state, init_state_len));
|
||||
}
|
||||
|
||||
/*
|
||||
Mark that a RESET MASTER is in progress.
|
||||
This ensures that a binlog checkpoint will not try to write binlog
|
||||
|
@ -4728,6 +4739,29 @@ err:
|
|||
}
|
||||
|
||||
|
||||
bool
|
||||
MYSQL_BIN_LOG::reset_engine_binlogs(THD *thd, rpl_gtid *init_state,
|
||||
uint32 init_state_len)
|
||||
{
|
||||
bool err;
|
||||
DBUG_ASSERT(!is_relay_log);
|
||||
|
||||
mysql_mutex_lock(&LOCK_log);
|
||||
mysql_mutex_lock(&LOCK_index);
|
||||
|
||||
err= (*opt_binlog_engine_hton->reset_binlogs)();
|
||||
if (init_state)
|
||||
rpl_global_gtid_binlog_state.load(init_state, init_state_len);
|
||||
else
|
||||
rpl_global_gtid_binlog_state.reset();
|
||||
|
||||
mysql_mutex_unlock(&LOCK_index);
|
||||
mysql_mutex_unlock(&LOCK_log);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void MYSQL_BIN_LOG::wait_for_last_checkpoint_event()
|
||||
{
|
||||
mysql_mutex_lock(&LOCK_xid_list);
|
||||
|
|
|
@ -1100,6 +1100,8 @@ public:
|
|||
bool reset_logs(THD* thd, bool create_new_log,
|
||||
rpl_gtid *init_state, uint32 init_state_len,
|
||||
ulong next_log_number);
|
||||
bool reset_engine_binlogs(THD *thd, rpl_gtid *init_state,
|
||||
uint32 init_state_len);
|
||||
void wait_for_last_checkpoint_event();
|
||||
void close(uint exiting);
|
||||
void clear_inuse_flag_when_closing(File file);
|
||||
|
|
|
@ -12276,3 +12276,5 @@ ER_CANNOT_INIT_ENGINE_BINLOG_READER
|
|||
eng "Cannot initialize binlog reader from storage engine %s"
|
||||
ER_ENGINE_BINLOG_REQUIRES_GTID
|
||||
eng "GTID starting position is required on master with --binlog-storage-engine enabled"
|
||||
ER_ENGINE_BINLOG_NO_RESET_FILE_NUMBER
|
||||
eng "RESET MASTER TO is not available when --binlog-storage-engine is enabled"
|
||||
|
|
|
@ -104,6 +104,14 @@ fsp_binlog_init()
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
fsp_binlog_shutdown()
|
||||
{
|
||||
pthread_cond_destroy(&active_binlog_cond);
|
||||
mysql_mutex_destroy(&active_binlog_mutex);
|
||||
}
|
||||
|
||||
|
||||
/** Write out all pages, flush, and close/detach a binlog tablespace.
|
||||
@param[in] file_no Index of the binlog tablespace
|
||||
@return DB_SUCCESS or error code */
|
||||
|
@ -739,6 +747,7 @@ binlog_chunk_reader::fetch_current_page()
|
|||
actually maintaining that, to save unnecessary buffer pool
|
||||
lookup.
|
||||
*/
|
||||
goto_next_file:
|
||||
if (cur_file_handle >= (File)0)
|
||||
{
|
||||
my_close(cur_file_handle, MYF(0));
|
||||
|
@ -754,6 +763,8 @@ binlog_chunk_reader::fetch_current_page()
|
|||
s.page_no << srv_page_size_shift, MYF(MY_WME));
|
||||
if (res == (size_t)-1)
|
||||
return CHUNK_READER_ERROR;
|
||||
if (res == 0 && my_errno == HA_ERR_FILE_TOO_SHORT)
|
||||
goto goto_next_file;
|
||||
page_ptr= page_buffer;
|
||||
return CHUNK_READER_FOUND;
|
||||
}
|
||||
|
|
|
@ -4137,6 +4137,7 @@ static int innodb_init(void* p)
|
|||
innobase_hton->get_binlog_reader= innodb_get_binlog_reader;
|
||||
innobase_hton->get_binlog_file_list= innodb_get_binlog_file_list;
|
||||
innobase_hton->binlog_flush= innodb_binlog_flush;
|
||||
innobase_hton->reset_binlogs= innodb_reset_binlogs;
|
||||
|
||||
innodb_remember_check_sysvar_funcs();
|
||||
|
||||
|
|
|
@ -430,6 +430,37 @@ innodb_binlog_startup_init()
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
innodb_binlog_init_state()
|
||||
{
|
||||
first_open_binlog_file_no= ~(uint64_t)0;
|
||||
binlog_cur_end_offset[0].store(~(uint64_t)0, std::memory_order_relaxed);
|
||||
binlog_cur_end_offset[1].store(~(uint64_t)0, std::memory_order_relaxed);
|
||||
last_created_binlog_file_no= ~(uint64_t)0;
|
||||
active_binlog_file_no.store(~(uint64_t)0, std::memory_order_release);
|
||||
active_binlog_space= nullptr;
|
||||
binlog_cur_page_no= 0;
|
||||
binlog_cur_page_offset= FIL_PAGE_DATA;
|
||||
current_binlog_state_interval= innodb_binlog_state_interval;
|
||||
}
|
||||
|
||||
|
||||
/* Start the thread that pre-allocates new binlog files. */
|
||||
static void
|
||||
start_binlog_prealloc_thread()
|
||||
{
|
||||
prealloc_thread_end= false;
|
||||
binlog_prealloc_thr_obj= std::thread{innodb_binlog_prealloc_thread};
|
||||
|
||||
mysql_mutex_lock(&active_binlog_mutex);
|
||||
while (last_created_binlog_file_no == ~(uint64_t)0) {
|
||||
/* Wait for the first binlog file to be available. */
|
||||
my_cond_wait(&active_binlog_cond, &active_binlog_mutex.m_mutex);
|
||||
}
|
||||
mysql_mutex_unlock(&active_binlog_mutex);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Open the InnoDB binlog implementation.
|
||||
This is called from server binlog layer if the user configured the binlog to
|
||||
|
@ -462,15 +493,8 @@ innodb_binlog_init(size_t binlog_size, const char *directory)
|
|||
}
|
||||
innodb_binlog_directory= directory;
|
||||
|
||||
first_open_binlog_file_no= ~(uint64_t)0;
|
||||
binlog_cur_end_offset[0].store(~(uint64_t)0, std::memory_order_relaxed);
|
||||
binlog_cur_end_offset[1].store(~(uint64_t)0, std::memory_order_relaxed);
|
||||
last_created_binlog_file_no= ~(uint64_t)0;
|
||||
active_binlog_file_no.store(~(uint64_t)0, std::memory_order_release);
|
||||
active_binlog_space= nullptr;
|
||||
binlog_cur_page_no= 0;
|
||||
binlog_cur_page_offset= FIL_PAGE_DATA;
|
||||
current_binlog_state_interval= innodb_binlog_state_interval;
|
||||
innodb_binlog_init_state();
|
||||
|
||||
/* Find any existing binlog files and continue writing in them. */
|
||||
int res= innodb_binlog_discover();
|
||||
if (res < 0)
|
||||
|
@ -485,15 +509,7 @@ innodb_binlog_init(size_t binlog_size, const char *directory)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Start pre-allocating new binlog files. */
|
||||
binlog_prealloc_thr_obj= std::thread{innodb_binlog_prealloc_thread};
|
||||
|
||||
mysql_mutex_lock(&active_binlog_mutex);
|
||||
while (last_created_binlog_file_no == ~(uint64_t)0) {
|
||||
/* Wait for the first binlog file to be available. */
|
||||
my_cond_wait(&active_binlog_cond, &active_binlog_mutex.m_mutex);
|
||||
}
|
||||
mysql_mutex_unlock(&active_binlog_mutex);
|
||||
start_binlog_prealloc_thread();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -763,7 +779,7 @@ innodb_binlog_discover()
|
|||
}
|
||||
|
||||
|
||||
void innodb_binlog_close()
|
||||
void innodb_binlog_close(bool shutdown)
|
||||
{
|
||||
if (binlog_prealloc_thr_obj.joinable()) {
|
||||
mysql_mutex_lock(&active_binlog_mutex);
|
||||
|
@ -782,17 +798,11 @@ void innodb_binlog_close()
|
|||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
ToDo: This doesn't seem to free all memory. I'm still getting leaks in eg. --valgrind. Find out why and fix. Example:
|
||||
==3464576== at 0x48407B4: malloc (vg_replace_malloc.c:381)
|
||||
==3464576== by 0x15318CD: mem_strdup(char const*) (mem0mem.inl:452)
|
||||
==3464576== by 0x15321DF: fil_space_t::add(char const*, pfs_os_file_t, unsigned int, bool, bool, unsigned int) (fil0fil.cc:306)
|
||||
==3464576== by 0x1558445: fsp_binlog_tablespace_create(unsigned long) (fsp0fsp.cc:3900)
|
||||
==3464576== by 0x1558C70: fsp_binlog_write_cache(st_io_cache*, unsigned long, mtr_t*) (fsp0fsp.cc:4013)
|
||||
*/
|
||||
binlog_diff_state.free();
|
||||
pthread_cond_destroy(&active_binlog_cond);
|
||||
mysql_mutex_destroy(&active_binlog_mutex);
|
||||
if (shutdown)
|
||||
{
|
||||
binlog_diff_state.free();
|
||||
fsp_binlog_shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -2176,3 +2186,49 @@ innodb_find_binlogs(uint64_t *out_first, uint64_t *out_last)
|
|||
*out_last= last_file_no;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
innodb_reset_binlogs()
|
||||
{
|
||||
bool err= false;
|
||||
|
||||
/* Close existing binlog tablespaces and stop the pre-alloc thread. */
|
||||
innodb_binlog_close(false);
|
||||
|
||||
/* Delete all binlog files in the directory. */
|
||||
MY_DIR *dir= my_dir(innodb_binlog_directory, MYF(MY_WME));
|
||||
if (!dir)
|
||||
{
|
||||
ib::error() << "Could not read the binlog directory '" <<
|
||||
innodb_binlog_directory << "', error code " << my_errno << ".";
|
||||
err= true;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t num_entries= dir->number_of_files;
|
||||
fileinfo *entries= dir->dir_entry;
|
||||
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;
|
||||
char full_path[OS_FILE_MAX_PATH];
|
||||
binlog_name_make(full_path, file_no);
|
||||
if (my_delete(full_path, MYF(MY_WME)))
|
||||
err= true;
|
||||
}
|
||||
my_dirend(dir);
|
||||
}
|
||||
/*
|
||||
If we get an error deleting any of the existing files, we report the error
|
||||
back up. But we still try to initialize an empty binlog state, better than
|
||||
leaving a non-functional binlog with corrupt internal state.
|
||||
*/
|
||||
|
||||
/* Re-initialize empty binlog state and start the pre-alloc thread. */
|
||||
innodb_binlog_init_state();
|
||||
start_binlog_prealloc_thread();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -202,6 +202,7 @@ extern std::atomic<uint64_t> binlog_cur_written_offset[2];
|
|||
extern std::atomic<uint64_t> binlog_cur_end_offset[2];
|
||||
|
||||
extern void fsp_binlog_init();
|
||||
extern void fsp_binlog_shutdown();
|
||||
extern dberr_t fsp_binlog_tablespace_close(uint64_t file_no);
|
||||
extern fil_space_t *fsp_binlog_open(const char *file_name, pfs_os_file_t fh,
|
||||
uint64_t file_no, size_t file_size,
|
||||
|
|
|
@ -85,7 +85,7 @@ binlog_name_make(char name_buf[OS_FILE_MAX_PATH], uint64_t file_no)
|
|||
|
||||
extern void innodb_binlog_startup_init();
|
||||
extern bool innodb_binlog_init(size_t binlog_size, const char *directory);
|
||||
extern void innodb_binlog_close();
|
||||
extern void innodb_binlog_close(bool shutdown);
|
||||
extern bool binlog_gtid_state(rpl_binlog_state_base *state, mtr_t *mtr,
|
||||
buf_block_t * &block, uint32_t &page_no,
|
||||
uint32_t &page_offset, fil_space_t *space);
|
||||
|
@ -98,5 +98,6 @@ 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);
|
||||
extern bool innodb_reset_binlogs();
|
||||
|
||||
#endif /* innodb_binlog_h */
|
||||
|
|
|
@ -2066,7 +2066,7 @@ void innodb_shutdown()
|
|||
logs_empty_and_mark_files_at_shutdown();
|
||||
}
|
||||
|
||||
innodb_binlog_close();
|
||||
innodb_binlog_close(true);
|
||||
os_aio_free();
|
||||
fil_space_t::close_all();
|
||||
/* Exit any remaining threads. */
|
||||
|
|
Loading…
Reference in a new issue