Commit 743597ea authored by unknown's avatar unknown

Backport innodb_max_purge_lag from 4.1


innobase/include/srv0srv.h:
  Add configuration parameter srv_max_purge_lag.
  Add global variable srv_dml_needed_delay.
innobase/include/trx0sys.h:
  Add trx_sys->rseg_history_len
innobase/row/row0mysql.c:
  Add row_mysql_delay_if_needed() for delaying INSERTs, UPDATEs and
  DELETEs for srv_dml_needed_delay microseconds.
innobase/srv/srv0srv.c:
  Define global variable srv_dml_needed_delay.
  Define configuration parameter srv_max_purge_lag.
innobase/trx/trx0purge.c:
  Update trx_sys->rseg_history_len.
  trx_purge(): Compute srv_dml_needed_delay from srv_max_purge_lag
  and trx_sys->rseg_history_len.
innobase/trx/trx0rseg.c:
  Initialize trx_sys->rseg_history_len at InnoDB start-up.
sql/ha_innodb.h:
  Add configuration parameter srv_max_purge_lag.
sql/mysqld.cc:
  Add startup option innodb_max_purge_lag,
  with default value 0 (meaning infinite, disabling the feature).
sql/set_var.cc:
  Add global variable innodb_max_purge_lag.
parent 9abe7d27
...@@ -99,6 +99,7 @@ extern ibool srv_use_doublewrite_buf; ...@@ -99,6 +99,7 @@ extern ibool srv_use_doublewrite_buf;
extern ibool srv_set_thread_priorities; extern ibool srv_set_thread_priorities;
extern int srv_query_thread_priority; extern int srv_query_thread_priority;
extern ulint srv_max_purge_lag;
/*-------------------------------------------*/ /*-------------------------------------------*/
extern ulint srv_n_rows_inserted; extern ulint srv_n_rows_inserted;
...@@ -152,6 +153,7 @@ extern ulint srv_test_array_size; ...@@ -152,6 +153,7 @@ extern ulint srv_test_array_size;
extern ulint srv_activity_count; extern ulint srv_activity_count;
extern ulint srv_fatal_semaphore_wait_threshold; extern ulint srv_fatal_semaphore_wait_threshold;
extern ulint srv_dml_needed_delay;
extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs, extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs,
query threads, and lock table: we allocate query threads, and lock table: we allocate
......
...@@ -419,6 +419,10 @@ struct trx_sys_struct{ ...@@ -419,6 +419,10 @@ struct trx_sys_struct{
trx_rseg_t* rseg_array[TRX_SYS_N_RSEGS]; trx_rseg_t* rseg_array[TRX_SYS_N_RSEGS];
/* Pointer array to rollback segments; /* Pointer array to rollback segments;
NULL if slot not in use */ NULL if slot not in use */
ulint rseg_history_len;/* Length of the TRX_RSEG_HISTORY
list (update undo logs for committed
transactions), protected by
rseg->mutex */
UT_LIST_BASE_NODE_T(read_view_t) view_list; UT_LIST_BASE_NODE_T(read_view_t) view_list;
/* List of read views sorted on trx no, /* List of read views sorted on trx no,
biggest first */ biggest first */
......
...@@ -89,6 +89,19 @@ row_mysql_is_system_table( ...@@ -89,6 +89,19 @@ row_mysql_is_system_table(
|| 0 == strcmp(name + 6, "user") || 0 == strcmp(name + 6, "user")
|| 0 == strcmp(name + 6, "db")); || 0 == strcmp(name + 6, "db"));
} }
/***********************************************************************
Delays an INSERT, DELETE or UPDATE operation if the purge is lagging. */
static
void
row_mysql_delay_if_needed(void)
/*===========================*/
{
if (srv_dml_needed_delay) {
os_thread_sleep(srv_dml_needed_delay);
}
}
/*********************************************************************** /***********************************************************************
Reads a MySQL format variable-length field (like VARCHAR) length and Reads a MySQL format variable-length field (like VARCHAR) length and
returns pointer to the field data. */ returns pointer to the field data. */
...@@ -856,6 +869,8 @@ row_insert_for_mysql( ...@@ -856,6 +869,8 @@ row_insert_for_mysql(
trx->op_info = (char *) "inserting"; trx->op_info = (char *) "inserting";
row_mysql_delay_if_needed();
trx_start_if_not_started(trx); trx_start_if_not_started(trx);
if (node == NULL) { if (node == NULL) {
...@@ -1071,6 +1086,8 @@ row_update_for_mysql( ...@@ -1071,6 +1086,8 @@ row_update_for_mysql(
trx->op_info = (char *) "updating or deleting"; trx->op_info = (char *) "updating or deleting";
row_mysql_delay_if_needed();
trx_start_if_not_started(trx); trx_start_if_not_started(trx);
node = prebuilt->upd_node; node = prebuilt->upd_node;
......
...@@ -58,6 +58,10 @@ ulint srv_activity_count = 0; ...@@ -58,6 +58,10 @@ ulint srv_activity_count = 0;
/* The following is the maximum allowed duration of a lock wait. */ /* The following is the maximum allowed duration of a lock wait. */
ulint srv_fatal_semaphore_wait_threshold = 600; ulint srv_fatal_semaphore_wait_threshold = 600;
/* How much data manipulation language (DML) statements need to be delayed,
in microseconds, in order to reduce the lagging of the purge thread. */
ulint srv_dml_needed_delay = 0;
ibool srv_lock_timeout_and_monitor_active = FALSE; ibool srv_lock_timeout_and_monitor_active = FALSE;
ibool srv_error_monitor_active = FALSE; ibool srv_error_monitor_active = FALSE;
...@@ -841,6 +845,8 @@ srv_general_init(void) ...@@ -841,6 +845,8 @@ srv_general_init(void)
/*======================= InnoDB Server FIFO queue =======================*/ /*======================= InnoDB Server FIFO queue =======================*/
/* Maximum allowable purge history length. <=0 means 'infinite'. */
ulint srv_max_purge_lag = 0;
/************************************************************************* /*************************************************************************
Puts an OS thread to wait if there are too many concurrent threads Puts an OS thread to wait if there are too many concurrent threads
......
...@@ -295,6 +295,9 @@ trx_purge_add_update_undo_to_history( ...@@ -295,6 +295,9 @@ trx_purge_add_update_undo_to_history(
/* Add the log as the first in the history list */ /* Add the log as the first in the history list */
flst_add_first(rseg_header + TRX_RSEG_HISTORY, flst_add_first(rseg_header + TRX_RSEG_HISTORY,
undo_header + TRX_UNDO_HISTORY_NODE, mtr); undo_header + TRX_UNDO_HISTORY_NODE, mtr);
mutex_enter(&kernel_mutex);
trx_sys->rseg_history_len++;
mutex_exit(&kernel_mutex);
/* Write the trx number to the undo log header */ /* Write the trx number to the undo log header */
mlog_write_dulint(undo_header + TRX_UNDO_TRX_NO, trx->no, mtr); mlog_write_dulint(undo_header + TRX_UNDO_TRX_NO, trx->no, mtr);
...@@ -386,6 +389,12 @@ loop: ...@@ -386,6 +389,12 @@ loop:
flst_cut_end(rseg_hdr + TRX_RSEG_HISTORY, flst_cut_end(rseg_hdr + TRX_RSEG_HISTORY,
log_hdr + TRX_UNDO_HISTORY_NODE, n_removed_logs, &mtr); log_hdr + TRX_UNDO_HISTORY_NODE, n_removed_logs, &mtr);
mutex_enter(&kernel_mutex);
ut_ad(trx_sys->rseg_history_len >= n_removed_logs);
trx_sys->rseg_history_len -= n_removed_logs;
mutex_exit(&kernel_mutex);
freed = FALSE; freed = FALSE;
while (!freed) { while (!freed) {
...@@ -470,6 +479,11 @@ loop: ...@@ -470,6 +479,11 @@ loop:
} }
if (cmp >= 0) { if (cmp >= 0) {
mutex_enter(&kernel_mutex);
ut_a(trx_sys->rseg_history_len >= n_removed_logs);
trx_sys->rseg_history_len -= n_removed_logs;
mutex_exit(&kernel_mutex);
flst_truncate_end(rseg_hdr + TRX_RSEG_HISTORY, flst_truncate_end(rseg_hdr + TRX_RSEG_HISTORY,
log_hdr + TRX_UNDO_HISTORY_NODE, log_hdr + TRX_UNDO_HISTORY_NODE,
n_removed_logs, &mtr); n_removed_logs, &mtr);
...@@ -1031,6 +1045,30 @@ trx_purge(void) ...@@ -1031,6 +1045,30 @@ trx_purge(void)
purge_sys->view = NULL; purge_sys->view = NULL;
mem_heap_empty(purge_sys->heap); mem_heap_empty(purge_sys->heap);
/* Determine how much data manipulation language (DML) statements
need to be delayed in order to reduce the lagging of the purge
thread. */
srv_dml_needed_delay = 0; /* in microseconds; default: no delay */
/* If we cannot advance the 'purge view' because of an old
'consistent read view', then the DML statements cannot be delayed.
Also, srv_max_purge_lag <= 0 means 'infinity'. */
if (srv_max_purge_lag > 0
&& !UT_LIST_GET_LAST(trx_sys->view_list)) {
float ratio = (float) trx_sys->rseg_history_len
/ srv_max_purge_lag;
if (ratio > ULINT_MAX / 10000) {
/* Avoid overflow: maximum delay is 4295 seconds */
srv_dml_needed_delay = ULINT_MAX;
} else if (ratio > 1) {
/* If the history list length exceeds the
innodb_max_purge_lag, the
data manipulation statements are delayed
by at least 5000 microseconds. */
srv_dml_needed_delay = (ulint) ((ratio - .5) * 10000);
}
}
purge_sys->view = read_view_oldest_copy_or_open_new(NULL, purge_sys->view = read_view_oldest_copy_or_open_new(NULL,
purge_sys->heap); purge_sys->heap);
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
......
...@@ -135,6 +135,7 @@ trx_rseg_mem_create( ...@@ -135,6 +135,7 @@ trx_rseg_mem_create(
trx_ulogf_t* undo_log_hdr; trx_ulogf_t* undo_log_hdr;
fil_addr_t node_addr; fil_addr_t node_addr;
ulint sum_of_undo_sizes; ulint sum_of_undo_sizes;
ulint len;
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&kernel_mutex)); ut_ad(mutex_own(&kernel_mutex));
...@@ -166,7 +167,9 @@ trx_rseg_mem_create( ...@@ -166,7 +167,9 @@ trx_rseg_mem_create(
MLOG_4BYTES, mtr) MLOG_4BYTES, mtr)
+ 1 + sum_of_undo_sizes; + 1 + sum_of_undo_sizes;
if (flst_get_len(rseg_header + TRX_RSEG_HISTORY, mtr) > 0) { len = flst_get_len(rseg_header + TRX_RSEG_HISTORY, mtr);
if (len > 0) {
trx_sys->rseg_history_len += len;
node_addr = trx_purge_get_log_from_hist( node_addr = trx_purge_get_log_from_hist(
flst_get_last(rseg_header + TRX_RSEG_HISTORY, flst_get_last(rseg_header + TRX_RSEG_HISTORY,
...@@ -206,6 +209,8 @@ trx_rseg_list_and_array_init( ...@@ -206,6 +209,8 @@ trx_rseg_list_and_array_init(
UT_LIST_INIT(trx_sys->rseg_list); UT_LIST_INIT(trx_sys->rseg_list);
trx_sys->rseg_history_len = 0;
for (i = 0; i < TRX_SYS_N_RSEGS; i++) { for (i = 0; i < TRX_SYS_N_RSEGS; i++) {
page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr); page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr);
......
...@@ -207,6 +207,7 @@ extern my_bool innobase_log_archive, ...@@ -207,6 +207,7 @@ extern my_bool innobase_log_archive,
innobase_create_status_file; innobase_create_status_file;
extern "C" { extern "C" {
extern ulong srv_max_buf_pool_modified_pct; extern ulong srv_max_buf_pool_modified_pct;
extern ulong srv_max_purge_lag;
} }
extern TYPELIB innobase_lock_typelib; extern TYPELIB innobase_lock_typelib;
......
...@@ -3520,6 +3520,7 @@ enum options_mysqld { ...@@ -3520,6 +3520,7 @@ enum options_mysqld {
OPT_INNODB_LOG_BUFFER_SIZE, OPT_INNODB_LOG_BUFFER_SIZE,
OPT_INNODB_BUFFER_POOL_SIZE, OPT_INNODB_BUFFER_POOL_SIZE,
OPT_INNODB_ADDITIONAL_MEM_POOL_SIZE, OPT_INNODB_ADDITIONAL_MEM_POOL_SIZE,
OPT_INNODB_MAX_PURGE_LAG,
OPT_INNODB_FILE_IO_THREADS, OPT_INNODB_FILE_IO_THREADS,
OPT_INNODB_LOCK_WAIT_TIMEOUT, OPT_INNODB_LOCK_WAIT_TIMEOUT,
OPT_INNODB_THREAD_CONCURRENCY, OPT_INNODB_THREAD_CONCURRENCY,
...@@ -3700,6 +3701,11 @@ struct my_option my_long_options[] = ...@@ -3700,6 +3701,11 @@ struct my_option my_long_options[] =
{"innodb_max_dirty_pages_pct", OPT_INNODB_MAX_DIRTY_PAGES_PCT, {"innodb_max_dirty_pages_pct", OPT_INNODB_MAX_DIRTY_PAGES_PCT,
"Percentage of dirty pages allowed in bufferpool", (gptr*) &srv_max_buf_pool_modified_pct, "Percentage of dirty pages allowed in bufferpool", (gptr*) &srv_max_buf_pool_modified_pct,
(gptr*) &srv_max_buf_pool_modified_pct, 0, GET_ULONG, REQUIRED_ARG, 90, 0, 100, 0, 0, 0}, (gptr*) &srv_max_buf_pool_modified_pct, 0, GET_ULONG, REQUIRED_ARG, 90, 0, 100, 0, 0, 0},
{"innodb_max_purge_lag", OPT_INNODB_MAX_PURGE_LAG,
"",
(gptr*) &srv_max_purge_lag,
(gptr*) &srv_max_purge_lag, 0, GET_LONG, REQUIRED_ARG, 0, 0, ~0L,
0, 1L, 0},
{"innodb_table_locks", OPT_INNODB_TABLE_LOCKS, {"innodb_table_locks", OPT_INNODB_TABLE_LOCKS,
"If Innodb should enforce LOCK TABLE", "If Innodb should enforce LOCK TABLE",
(gptr*) &global_system_variables.innodb_table_locks, (gptr*) &global_system_variables.innodb_table_locks,
......
...@@ -263,6 +263,8 @@ sys_var_thd_ulong sys_net_wait_timeout("wait_timeout", ...@@ -263,6 +263,8 @@ sys_var_thd_ulong sys_net_wait_timeout("wait_timeout",
#ifdef HAVE_INNOBASE_DB #ifdef HAVE_INNOBASE_DB
sys_var_long_ptr sys_innodb_max_dirty_pages_pct("innodb_max_dirty_pages_pct", sys_var_long_ptr sys_innodb_max_dirty_pages_pct("innodb_max_dirty_pages_pct",
&srv_max_buf_pool_modified_pct); &srv_max_buf_pool_modified_pct);
sys_var_long_ptr sys_innodb_max_purge_lag("innodb_max_purge_lag",
&srv_max_purge_lag);
sys_var_thd_bool sys_innodb_table_locks("innodb_table_locks", sys_var_thd_bool sys_innodb_table_locks("innodb_table_locks",
&SV::innodb_table_locks); &SV::innodb_table_locks);
#endif #endif
...@@ -451,6 +453,7 @@ sys_var *sys_variables[]= ...@@ -451,6 +453,7 @@ sys_var *sys_variables[]=
&sys_os, &sys_os,
#ifdef HAVE_INNOBASE_DB #ifdef HAVE_INNOBASE_DB
&sys_innodb_max_dirty_pages_pct, &sys_innodb_max_dirty_pages_pct,
&sys_innodb_max_purge_lag,
&sys_innodb_table_locks, &sys_innodb_table_locks,
#endif #endif
&sys_unique_checks &sys_unique_checks
...@@ -523,6 +526,7 @@ struct show_var_st init_vars[]= { ...@@ -523,6 +526,7 @@ struct show_var_st init_vars[]= {
{"innodb_log_group_home_dir", (char*) &innobase_log_group_home_dir, SHOW_CHAR_PTR}, {"innodb_log_group_home_dir", (char*) &innobase_log_group_home_dir, SHOW_CHAR_PTR},
{"innodb_mirrored_log_groups", (char*) &innobase_mirrored_log_groups, SHOW_LONG}, {"innodb_mirrored_log_groups", (char*) &innobase_mirrored_log_groups, SHOW_LONG},
{sys_innodb_max_dirty_pages_pct.name, (char*) &sys_innodb_max_dirty_pages_pct, SHOW_SYS}, {sys_innodb_max_dirty_pages_pct.name, (char*) &sys_innodb_max_dirty_pages_pct, SHOW_SYS},
{sys_innodb_max_purge_lag.name, (char*) &sys_innodb_max_purge_lag, SHOW_SYS},
{sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS}, {sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS},
#endif #endif
{sys_interactive_timeout.name,(char*) &sys_interactive_timeout, SHOW_SYS}, {sys_interactive_timeout.name,(char*) &sys_interactive_timeout, SHOW_SYS},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment