From 34f11b06e6aa5e8d4e648c04b5a4049179b66cfd Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Sun, 14 Oct 2018 20:41:49 +0200 Subject: Move deletion of old GTID rows to slave background thread This patch changes how old rows in mysql.gtid_slave_pos* tables are deleted. Instead of doing it as part of every replicated transaction in record_gtid(), it is done periodically (every @@gtid_cleanup_batch_size transaction) in the slave background thread. This removes the deletion step from the replication process in SQL or worker threads, which could speed up replication with many small transactions. It also decreases contention on the global mutex LOCK_slave_state. And it simplifies the logic, eg. when a replicated transaction fails after having deleted old rows. With this patch, the deletion of old GTID rows happens asynchroneously and slightly non-deterministic. Thus the number of old rows in mysql.gtid_slave_pos can temporarily exceed @@gtid_cleanup_batch_size. But all old rows will be deleted eventually after sufficiently many new GTIDs have been replicated. --- sql/slave.cc | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'sql/slave.cc') diff --git a/sql/slave.cc b/sql/slave.cc index 2a8c977451d..03b730b2b00 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -465,6 +465,8 @@ static struct slave_background_gtid_pos_create_t { void *hton; } *slave_background_gtid_pos_create_list; +static volatile bool slave_background_gtid_pending_delete_flag; + pthread_handler_t handle_slave_background(void *arg __attribute__((unused))) @@ -499,6 +501,7 @@ handle_slave_background(void *arg __attribute__((unused))) { slave_background_kill_t *kill_list; slave_background_gtid_pos_create_t *create_list; + bool pending_deletes; thd->ENTER_COND(&COND_slave_background, &LOCK_slave_background, &stage_slave_background_wait_request, @@ -508,13 +511,15 @@ handle_slave_background(void *arg __attribute__((unused))) stop= abort_loop || thd->killed || slave_background_thread_stop; kill_list= slave_background_kill_list; create_list= slave_background_gtid_pos_create_list; - if (stop || kill_list || create_list) + pending_deletes= slave_background_gtid_pending_delete_flag; + if (stop || kill_list || create_list || pending_deletes) break; mysql_cond_wait(&COND_slave_background, &LOCK_slave_background); } slave_background_kill_list= NULL; slave_background_gtid_pos_create_list= NULL; + slave_background_gtid_pending_delete_flag= false; thd->EXIT_COND(&old_stage); while (kill_list) @@ -541,6 +546,17 @@ handle_slave_background(void *arg __attribute__((unused))) create_list= next; } + if (pending_deletes) + { + rpl_slave_state::list_element *list; + + slave_background_gtid_pending_delete_flag= false; + list= rpl_global_gtid_slave_state->gtid_grab_pending_delete_list(); + rpl_global_gtid_slave_state->gtid_delete_pending(thd, &list); + if (list) + rpl_global_gtid_slave_state->put_back_list(list); + } + mysql_mutex_lock(&LOCK_slave_background); } while (!stop); @@ -614,6 +630,23 @@ slave_background_gtid_pos_create_request( } +/* + Request the slave background thread to delete no longer used rows from the + mysql.gtid_slave_pos* tables. + + This is called from time-critical rpl_slave_state::update(), so we avoid + taking any locks here. This means we may race with the background thread + to occasionally lose a signal. This is not a problem; any pending rows to + be deleted will just be deleted a bit later as part of the next batch. +*/ +void +slave_background_gtid_pending_delete_request(void) +{ + slave_background_gtid_pending_delete_flag= true; + mysql_cond_signal(&COND_slave_background); +} + + /* Start the slave background thread. -- cgit v1.2.1