summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <knielsen@knielsen-hq.org>2012-12-14 15:38:07 +0100
committerunknown <knielsen@knielsen-hq.org>2012-12-14 15:38:07 +0100
commit40bbf697aad7d923fc1bd995bc5f547e45461cbe (patch)
tree1563a1c99589bb5853d35faee4ae49e22b3fdd0a /sql
parente97d6232f366c474f6eba4013bfbd6dacc01d544 (diff)
downloadmariadb-git-40bbf697aad7d923fc1bd995bc5f547e45461cbe.tar.gz
MDEV-532: Async InnoDB commit checkpoint.
Make the commit checkpoint inside InnoDB be asynchroneous. Implement a background thread in binlog to do the writing and flushing of binlog checkpoint events to disk.
Diffstat (limited to 'sql')
-rw-r--r--sql/debug_sync.cc1
-rw-r--r--sql/log.cc167
-rw-r--r--sql/log.h55
-rw-r--r--sql/mysqld.cc6
-rw-r--r--sql/mysqld.h3
-rw-r--r--sql/rpl_rli.cc3
-rw-r--r--sql/sql_class.h3
7 files changed, 203 insertions, 35 deletions
diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc
index 4097d7fe6e1..1c95869987d 100644
--- a/sql/debug_sync.cc
+++ b/sql/debug_sync.cc
@@ -984,6 +984,7 @@ static bool debug_sync_eval_action(THD *thd, char *action_str)
DBUG_ENTER("debug_sync_eval_action");
DBUG_ASSERT(thd);
DBUG_ASSERT(action_str);
+ DBUG_PRINT("debug_sync", ("action_str='%s'", action_str));
/*
Get debug sync point name. Or a special command.
diff --git a/sql/log.cc b/sql/log.cc
index e664540f0d6..da9d576d1da 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -54,6 +54,7 @@
#include "rpl_handler.h"
#include "debug_sync.h"
#include "sql_show.h"
+#include "my_pthread.h"
/* max size of the log message */
#define MAX_LOG_BUFFER_SIZE 1024
@@ -107,6 +108,17 @@ static SHOW_VAR binlog_status_vars_detail[]=
{NullS, NullS, SHOW_LONG}
};
+/*
+ Variables for the binlog background thread.
+ Protected by the MYSQL_BIN_LOG::LOCK_binlog_background_thread mutex.
+ */
+static bool binlog_background_thread_started= false;
+static bool binlog_background_thread_stop= false;
+static MYSQL_BIN_LOG::xid_count_per_binlog *
+ binlog_background_thread_queue= NULL;
+
+static bool start_binlog_background_thread();
+
/**
purge logs, master and slave sides both, related error code
@@ -2958,12 +2970,28 @@ void MYSQL_BIN_LOG::cleanup()
my_free(b);
}
+ /* Wait for the binlog background thread to stop. */
+ if (!is_relay_log && binlog_background_thread_started)
+ {
+ mysql_mutex_lock(&LOCK_binlog_background_thread);
+ binlog_background_thread_stop= true;
+ mysql_cond_signal(&COND_binlog_background_thread);
+ while (binlog_background_thread_stop)
+ mysql_cond_wait(&COND_binlog_background_thread_end,
+ &LOCK_binlog_background_thread);
+ mysql_mutex_unlock(&LOCK_binlog_background_thread);
+ binlog_background_thread_started= false;
+ }
+
mysql_mutex_destroy(&LOCK_log);
mysql_mutex_destroy(&LOCK_index);
mysql_mutex_destroy(&LOCK_xid_list);
+ mysql_mutex_destroy(&LOCK_binlog_background_thread);
mysql_cond_destroy(&update_cond);
mysql_cond_destroy(&COND_queue_busy);
mysql_cond_destroy(&COND_xid_list);
+ mysql_cond_destroy(&COND_binlog_background_thread);
+ mysql_cond_destroy(&COND_binlog_background_thread_end);
}
DBUG_VOID_RETURN;
}
@@ -2989,6 +3017,13 @@ void MYSQL_BIN_LOG::init_pthread_objects()
mysql_cond_init(m_key_update_cond, &update_cond, 0);
mysql_cond_init(m_key_COND_queue_busy, &COND_queue_busy, 0);
mysql_cond_init(key_BINLOG_COND_xid_list, &COND_xid_list, 0);
+
+ mysql_mutex_init(key_BINLOG_LOCK_binlog_background_thread,
+ &LOCK_binlog_background_thread, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_BINLOG_COND_binlog_background_thread,
+ &COND_binlog_background_thread, 0);
+ mysql_cond_init(key_BINLOG_COND_binlog_background_thread_end,
+ &COND_binlog_background_thread_end, 0);
}
@@ -3086,6 +3121,10 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
DBUG_ENTER("MYSQL_BIN_LOG::open");
DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
+ if (!is_relay_log && !binlog_background_thread_started &&
+ start_binlog_background_thread())
+ DBUG_RETURN(1);
+
if (init_and_set_log_file_name(log_name, new_name, log_type_arg,
io_cache_type_arg))
{
@@ -5541,11 +5580,7 @@ bool general_log_write(THD *thd, enum enum_server_command command,
}
-/*
- I would like to make this function static, but this causes compiler warnings
- when it is declared as friend function in log.h.
-*/
-void
+static void
binlog_checkpoint_callback(void *cookie)
{
MYSQL_BIN_LOG::xid_count_per_binlog *entry=
@@ -8135,9 +8170,129 @@ int TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
void
TC_LOG_BINLOG::commit_checkpoint_notify(void *cookie)
{
- mark_xid_done(((xid_count_per_binlog *)cookie)->binlog_id, true);
+ xid_count_per_binlog *entry= static_cast<xid_count_per_binlog *>(cookie);
+ mysql_mutex_lock(&LOCK_binlog_background_thread);
+ entry->next_in_queue= binlog_background_thread_queue;
+ binlog_background_thread_queue= entry;
+ mysql_cond_signal(&COND_binlog_background_thread);
+ mysql_mutex_unlock(&LOCK_binlog_background_thread);
}
+/*
+ Binlog background thread.
+
+ This thread is used to log binlog checkpoints in the background, rather than
+ in the context of random storage engine threads that happen to call
+ commit_checkpoint_notify_ha() and may not like the delays while syncing
+ binlog to disk or may not be setup with all my_thread_init() and other
+ necessary stuff.
+
+ In the future, this thread could also be used to do log rotation in the
+ background, which could elimiate all stalls around binlog rotations.
+*/
+pthread_handler_t
+binlog_background_thread(void *arg __attribute__((unused)))
+{
+ bool stop;
+ MYSQL_BIN_LOG::xid_count_per_binlog *queue, *next;
+ THD *thd;
+
+ my_thread_init();
+ thd= new THD;
+ thd->system_thread= SYSTEM_THREAD_BINLOG_BACKGROUND;
+ thd->thread_stack= (char*) &thd; /* Set approximate stack start */
+ mysql_mutex_lock(&LOCK_thread_count);
+ thd->thread_id= thread_id++;
+ mysql_mutex_unlock(&LOCK_thread_count);
+ thd->store_globals();
+
+ for (;;)
+ {
+ /*
+ Wait until there is something in the queue to process, or we are asked
+ to shut down.
+ */
+ thd_proc_info(thd, "Waiting for background binlog tasks");
+ mysql_mutex_lock(&mysql_bin_log.LOCK_binlog_background_thread);
+ for (;;)
+ {
+ stop= binlog_background_thread_stop;
+ queue= binlog_background_thread_queue;
+ if (stop || queue)
+ break;
+ mysql_cond_wait(&mysql_bin_log.COND_binlog_background_thread,
+ &mysql_bin_log.LOCK_binlog_background_thread);
+ }
+ /* Grab the queue, if any. */
+ binlog_background_thread_queue= NULL;
+ mysql_mutex_unlock(&mysql_bin_log.LOCK_binlog_background_thread);
+
+ /* Process any incoming commit_checkpoint_notify() calls. */
+ while (queue)
+ {
+ thd_proc_info(thd, "Processing binlog checkpoint notification");
+ /* Grab next pointer first, as mark_xid_done() may free the element. */
+ next= queue->next_in_queue;
+ mysql_bin_log.mark_xid_done(queue->binlog_id, true);
+ queue= next;
+
+ DBUG_EXECUTE_IF("binlog_background_checkpoint_processed",
+ DBUG_ASSERT(!debug_sync_set_action(
+ thd,
+ STRING_WITH_LEN("now SIGNAL binlog_background_checkpoint_processed")));
+ );
+ }
+
+ if (stop)
+ break;
+ }
+
+ thd_proc_info(thd, "Stopping binlog background thread");
+
+ mysql_mutex_lock(&LOCK_thread_count);
+ delete thd;
+ mysql_mutex_unlock(&LOCK_thread_count);
+
+ my_thread_end();
+
+ /* Signal that we are (almost) stopped. */
+ mysql_mutex_lock(&mysql_bin_log.LOCK_binlog_background_thread);
+ binlog_background_thread_stop= false;
+ mysql_cond_signal(&mysql_bin_log.COND_binlog_background_thread_end);
+ mysql_mutex_unlock(&mysql_bin_log.LOCK_binlog_background_thread);
+
+ return 0;
+}
+
+#ifdef HAVE_PSI_INTERFACE
+static PSI_thread_key key_thread_binlog;
+
+static PSI_thread_info all_binlog_threads[]=
+{
+ { &key_thread_binlog, "binlog_background", PSI_FLAG_GLOBAL},
+};
+#endif /* HAVE_PSI_INTERFACE */
+
+static bool
+start_binlog_background_thread()
+{
+ pthread_t th;
+
+#ifdef HAVE_PSI_INTERFACE
+ if (PSI_server)
+ PSI_server->register_thread("sql", all_binlog_threads,
+ array_elements(all_binlog_threads));
+#endif
+
+ if (mysql_thread_create(key_thread_binlog, &th, NULL,
+ binlog_background_thread, NULL))
+ return 1;
+
+ binlog_background_thread_started= true;
+ return 0;
+}
+
+
int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
IO_CACHE *first_log,
Format_description_log_event *fdle)
diff --git a/sql/log.h b/sql/log.h
index 3959411d83a..9facf309279 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -395,8 +395,6 @@ private:
#define BINLOG_COOKIE_IS_DUMMY(c) \
( ((ulong)(c)>>1) == BINLOG_COOKIE_DUMMY_ID )
-void binlog_checkpoint_callback(void *cookie);
-
class binlog_cache_mngr;
class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
{
@@ -451,27 +449,6 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
};
/*
- A list of struct xid_count_per_binlog is used to keep track of how many
- XIDs are in prepared, but not committed, state in each binlog. And how
- many commit_checkpoint_request()'s are pending.
-
- When count drops to zero in a binlog after rotation, it means that there
- are no more XIDs in prepared state, so that binlog is no longer needed
- for XA crash recovery, and we can log a new binlog checkpoint event.
-
- The list is protected against simultaneous access from multiple
- threads by LOCK_xid_list.
- */
- struct xid_count_per_binlog : public ilink {
- char *binlog_name;
- uint binlog_name_len;
- ulong binlog_id;
- /* Total prepared XIDs and pending checkpoint requests in this binlog. */
- long xid_count;
- xid_count_per_binlog(); /* Give link error if constructor used. */
- };
- I_List<xid_count_per_binlog> binlog_xid_count_list;
- /*
When this is set, a RESET MASTER is in progress.
Then we should not write any binlog checkpoints into the binlog (that
@@ -480,7 +457,6 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
checkpoint arrives - when all have arrived, RESET MASTER will complete.
*/
bool reset_master_pending;
- friend void binlog_checkpoint_callback(void *cookie);
/* LOCK_log and LOCK_index are inited by init_pthread_objects() */
mysql_mutex_t LOCK_index;
@@ -550,10 +526,35 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
int write_transaction_or_stmt(group_commit_entry *entry);
bool write_transaction_to_binlog_events(group_commit_entry *entry);
void trx_group_commit_leader(group_commit_entry *leader);
- void mark_xid_done(ulong cookie, bool write_checkpoint);
- void mark_xids_active(ulong cookie, uint xid_count);
public:
+ /*
+ A list of struct xid_count_per_binlog is used to keep track of how many
+ XIDs are in prepared, but not committed, state in each binlog. And how
+ many commit_checkpoint_request()'s are pending.
+
+ When count drops to zero in a binlog after rotation, it means that there
+ are no more XIDs in prepared state, so that binlog is no longer needed
+ for XA crash recovery, and we can log a new binlog checkpoint event.
+
+ The list is protected against simultaneous access from multiple
+ threads by LOCK_xid_list.
+ */
+ struct xid_count_per_binlog : public ilink {
+ char *binlog_name;
+ uint binlog_name_len;
+ ulong binlog_id;
+ /* Total prepared XIDs and pending checkpoint requests in this binlog. */
+ long xid_count;
+ /* For linking in requests to the binlog background thread. */
+ xid_count_per_binlog *next_in_queue;
+ xid_count_per_binlog(); /* Give link error if constructor used. */
+ };
+ I_List<xid_count_per_binlog> binlog_xid_count_list;
+ mysql_mutex_t LOCK_binlog_background_thread;
+ mysql_cond_t COND_binlog_background_thread;
+ mysql_cond_t COND_binlog_background_thread_end;
+
using MYSQL_LOG::generate_name;
using MYSQL_LOG::is_open;
@@ -709,6 +710,8 @@ public:
bool appendv(const char* buf,uint len,...);
bool append(Log_event* ev);
+ void mark_xids_active(ulong cookie, uint xid_count);
+ void mark_xid_done(ulong cookie, bool write_checkpoint);
void make_log_name(char* buf, const char* log_ident);
bool is_active(const char* log_file_name);
bool can_purge_log(const char *log_file_name);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 57f7ae49ecb..a3874bb49a6 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -726,6 +726,7 @@ PSI_mutex_key key_LOCK_des_key_file;
#endif /* HAVE_OPENSSL */
PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
+ key_BINLOG_LOCK_binlog_background_thread,
key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi,
key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create,
key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log,
@@ -768,6 +769,7 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_BINLOG_LOCK_index, "MYSQL_BIN_LOG::LOCK_index", 0},
{ &key_BINLOG_LOCK_xid_list, "MYSQL_BIN_LOG::LOCK_xid_list", 0},
+ { &key_BINLOG_LOCK_binlog_background_thread, "MYSQL_BIN_LOG::LOCK_binlog_background_thread", 0},
{ &key_RELAYLOG_LOCK_index, "MYSQL_RELAY_LOG::LOCK_index", 0},
{ &key_delayed_insert_mutex, "Delayed_insert::mutex", 0},
{ &key_hash_filo_lock, "hash_filo::lock", 0},
@@ -836,6 +838,8 @@ PSI_cond_key key_PAGE_cond, key_COND_active, key_COND_pool;
#endif /* HAVE_MMAP */
PSI_cond_key key_BINLOG_COND_xid_list, key_BINLOG_update_cond,
+ key_BINLOG_COND_binlog_background_thread,
+ key_BINLOG_COND_binlog_background_thread_end,
key_COND_cache_status_changed, key_COND_manager,
key_COND_rpl_status, key_COND_server_started,
key_delayed_insert_cond, key_delayed_insert_cond_client,
@@ -865,6 +869,8 @@ static PSI_cond_info all_server_conds[]=
#endif /* HAVE_MMAP */
{ &key_BINLOG_COND_xid_list, "MYSQL_BIN_LOG::COND_xid_list", 0},
{ &key_BINLOG_update_cond, "MYSQL_BIN_LOG::update_cond", 0},
+ { &key_BINLOG_COND_binlog_background_thread, "MYSQL_BIN_LOG::COND_binlog_background_thread", 0},
+ { &key_BINLOG_COND_binlog_background_thread_end, "MYSQL_BIN_LOG::COND_binlog_background_thread_end", 0},
{ &key_BINLOG_COND_queue_busy, "MYSQL_BIN_LOG::COND_queue_busy", 0},
{ &key_RELAYLOG_update_cond, "MYSQL_RELAY_LOG::update_cond", 0},
{ &key_RELAYLOG_COND_queue_busy, "MYSQL_RELAY_LOG::COND_queue_busy", 0},
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 430811a956c..d346defad8e 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -228,6 +228,7 @@ extern PSI_mutex_key key_LOCK_des_key_file;
#endif
extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
+ key_BINLOG_LOCK_binlog_background_thread,
key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi,
key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create,
key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log,
@@ -259,6 +260,8 @@ extern PSI_cond_key key_PAGE_cond, key_COND_active, key_COND_pool;
#endif /* HAVE_MMAP */
extern PSI_cond_key key_BINLOG_COND_xid_list, key_BINLOG_update_cond,
+ key_BINLOG_COND_binlog_background_thread,
+ key_BINLOG_COND_binlog_background_thread_end,
key_COND_cache_status_changed, key_COND_manager,
key_COND_rpl_status, key_COND_server_started,
key_delayed_insert_cond, key_delayed_insert_cond_client,
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index e74831464fa..17919d3c1f1 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -58,6 +58,7 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery)
{
DBUG_ENTER("Relay_log_info::Relay_log_info");
+ relay_log.is_relay_log= TRUE;
#ifdef HAVE_PSI_INTERFACE
relay_log.set_psi_keys(key_RELAYLOG_LOCK_index,
key_RELAYLOG_update_cond,
@@ -216,8 +217,6 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
&mi->connection_name);
}
- rli->relay_log.is_relay_log= TRUE;
-
/*
note, that if open() fails, we'll still have index file open
but a destructor will take care of that
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 34dcd0ff11d..7f941220140 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1255,7 +1255,8 @@ enum enum_thread_type
SYSTEM_THREAD_SLAVE_SQL= 4,
SYSTEM_THREAD_NDBCLUSTER_BINLOG= 8,
SYSTEM_THREAD_EVENT_SCHEDULER= 16,
- SYSTEM_THREAD_EVENT_WORKER= 32
+ SYSTEM_THREAD_EVENT_WORKER= 32,
+ SYSTEM_THREAD_BINLOG_BACKGROUND= 64
};
inline char const *