1
# name : innodb_purge_thread.patch
2
# introduced : 11 or before
3
# maintainer : Yasufumi
6
# Any small change to this file in the main branch
7
# should be done or reviewed by the maintainer!
8
--- a/storage/innodb_plugin/handler/ha_innodb.cc
9
+++ b/storage/innodb_plugin/handler/ha_innodb.cc
10
@@ -11001,6 +11001,11 @@
11
"Output statistics of recovery process after it.",
14
+static MYSQL_SYSVAR_ULONG(use_purge_thread, srv_use_purge_thread,
15
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
16
+ "Number of purge devoted threads. #### over 1 is EXPERIMENTAL ####",
17
+ NULL, NULL, 0, 0, UNIV_MAX_PARALLELISM, 0);
19
static MYSQL_SYSVAR_BOOL(overwrite_relay_log_info, innobase_overwrite_relay_log_info,
20
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
21
"During InnoDB crash recovery on slave overwrite relay-log.info "
22
@@ -11495,6 +11500,7 @@
23
MYSQL_SYSVAR(random_read_ahead),
24
MYSQL_SYSVAR(read_ahead_threshold),
25
MYSQL_SYSVAR(io_capacity),
26
+ MYSQL_SYSVAR(use_purge_thread),
30
--- a/storage/innodb_plugin/handler/innodb_patch_info.h
31
+++ b/storage/innodb_plugin/handler/innodb_patch_info.h
33
{"innodb_dict_size_limit","Limit dictionary cache size","Variable innodb_dict_size_limit in bytes","http://www.percona.com/docs/wiki/percona-xtradb"},
34
{"innodb_split_buf_pool_mutex","More fix of buffer_pool mutex","Spliting buf_pool_mutex and optimizing based on innodb_opt_lru_count","http://www.percona.com/docs/wiki/percona-xtradb"},
35
{"innodb_recovery_patches","Bugfixes and adjustments about recovery process","","http://www.percona.com/docs/wiki/percona-xtradb"},
36
+{"innodb_purge_thread","Enable to use purge devoted thread","","http://www.percona.com/docs/wiki/percona-xtradb"},
37
{NULL, NULL, NULL, NULL}
39
--- a/storage/innodb_plugin/include/srv0srv.h
40
+++ b/storage/innodb_plugin/include/srv0srv.h
43
extern ibool srv_recovery_stats;
45
+extern ulint srv_use_purge_thread;
47
extern ibool srv_auto_extend_last_data_file;
48
extern ulint srv_last_file_size_max;
49
extern char** srv_log_group_home_dirs;
51
SRV_RECOVERY, /**< threads finishing a recovery */
52
SRV_INSERT, /**< thread flushing the insert buffer to disk */
54
+ SRV_PURGE, /* thread purging undo records */
55
+ SRV_PURGE_WORKER, /* thread purging undo records */
56
SRV_MASTER /**< the master thread, (whose type number must
61
void* arg); /*!< in: a dummy parameter required by
63
+/*************************************************************************
64
+The undo purge thread. */
69
+ void* arg); /* in: a dummy parameter required by
71
+/*************************************************************************
72
+The undo purge thread. */
75
+srv_purge_worker_thread(
76
+/*====================*/
78
/*******************************************************************//**
79
Tells the Innobase server that there has been activity in the database
80
and wakes up the master thread if it is suspended (not sleeping). Used
81
--- a/storage/innodb_plugin/include/trx0purge.h
82
+++ b/storage/innodb_plugin/include/trx0purge.h
87
+/**********************************************************************
88
+This function runs a purge worker batch */
94
+/**********************************************************************
95
+This function waits the event for worker batch */
98
+trx_purge_worker_wait(void);
99
+/*========================*/
100
+/**********************************************************************
101
+This function wakes the waiting worker batch */
104
+trx_purge_worker_wake(void);
105
+/*========================*/
106
/******************************************************************//**
107
Prints information of the purge system to stderr. */
110
of the trx system and it never ends */
111
que_t* query; /*!< The query graph which will do the
112
parallelized purge operation */
114
+ os_event_t worker_event;
118
rw_lock_t latch; /*!< The latch protecting the purge view.
119
A purge operation must acquire an
120
x-latch here for the instant at which
121
--- a/storage/innodb_plugin/log/log0log.c
122
+++ b/storage/innodb_plugin/log/log0log.c
123
@@ -3151,6 +3151,16 @@
127
+ /* Check that the purge threads ended */
128
+ if (srv_use_purge_thread
129
+ && (srv_n_threads_active[SRV_PURGE] != 0
130
+ || srv_n_threads_active[SRV_PURGE_WORKER] != 0)) {
132
+ mutex_exit(&kernel_mutex);
137
mutex_exit(&kernel_mutex);
139
mutex_enter(&(log_sys->mutex));
140
--- a/storage/innodb_plugin/srv/srv0srv.c
141
+++ b/storage/innodb_plugin/srv/srv0srv.c
144
UNIV_INTERN ibool srv_recovery_stats = FALSE;
146
+UNIV_INTERN ulint srv_use_purge_thread = 0;
148
/* if TRUE, then we auto-extend the last data file */
149
UNIV_INTERN ibool srv_auto_extend_last_data_file = FALSE;
150
/* if != 0, this tells the max size auto-extending may increase the
151
@@ -2640,10 +2642,10 @@
152
srv_main_thread_process_no = os_proc_get_number();
153
srv_main_thread_id = os_thread_pf(os_thread_get_curr_id());
155
- srv_table_reserve_slot(SRV_MASTER);
157
mutex_enter(&kernel_mutex);
159
+ srv_table_reserve_slot(SRV_MASTER);
160
srv_n_threads_active[SRV_MASTER]++;
162
mutex_exit(&kernel_mutex);
163
@@ -3101,6 +3103,7 @@
164
/* Flush logs if needed */
165
srv_sync_log_buffer_in_background();
167
+ if (!srv_use_purge_thread) {
168
/* We run a full purge every 10 seconds, even if the server
171
@@ -3117,6 +3120,7 @@
172
srv_sync_log_buffer_in_background();
174
} while (n_pages_purged);
177
srv_main_thread_op_info = "flushing buffer pool pages";
179
@@ -3185,6 +3189,7 @@
180
os_thread_sleep(100000);
183
+ if (!srv_use_purge_thread) {
184
srv_main_thread_op_info = "purging";
186
/* Run a full purge */
187
@@ -3201,6 +3206,7 @@
188
srv_sync_log_buffer_in_background();
190
} while (n_pages_purged);
193
srv_main_thread_op_info = "reserving kernel mutex";
195
@@ -3353,3 +3359,143 @@
197
OS_THREAD_DUMMY_RETURN; /* Not reached, avoid compiler warning */
200
+/*************************************************************************
201
+A thread which is devoted to purge, for take over the master thread's
207
+ void* arg __attribute__((unused)))
208
+ /* in: a dummy parameter required by os_thread_create */
210
+ ulint n_pages_purged;
211
+ ulint n_pages_purged_sum = 1; /* dummy */
213
+ ulint sleep_ms= 10000; /* initial: 10 sec. */
214
+ ibool can_be_last = FALSE;
216
+#ifdef UNIV_DEBUG_THREAD_CREATION
217
+ fprintf(stderr, "Purge thread starts, id %lu\n",
218
+ os_thread_pf(os_thread_get_curr_id()));
221
+ mutex_enter(&kernel_mutex);
222
+ srv_table_reserve_slot(SRV_PURGE);
223
+ srv_n_threads_active[SRV_PURGE]++;
224
+ mutex_exit(&kernel_mutex);
227
+ if (srv_shutdown_state > 0) {
228
+ if (srv_fast_shutdown) {
229
+ /* someone other should wait the end of the workers */
233
+ mutex_enter(&kernel_mutex);
234
+ if (srv_n_threads_active[SRV_PURGE_WORKER]) {
235
+ can_be_last = FALSE;
237
+ can_be_last = TRUE;
239
+ mutex_exit(&kernel_mutex);
244
+ os_thread_sleep( sleep_ms * 1000 );
246
+ history_len = trx_sys->rseg_history_len;
247
+ if (history_len > 1000)
252
+ n_pages_purged_sum = 0;
255
+ if (srv_fast_shutdown && srv_shutdown_state > 0) {
258
+ n_pages_purged = trx_purge();
259
+ n_pages_purged_sum += n_pages_purged;
260
+ } while (n_pages_purged);
262
+ if (srv_shutdown_state > 0 && can_be_last) {
263
+ /* the last trx_purge() is executed without workers */
267
+ if (n_pages_purged_sum) {
268
+ srv_active_wake_master_thread();
271
+ if (n_pages_purged_sum == 0)
273
+ if (sleep_ms > 10000)
279
+ trx_purge_worker_wake(); /* It may not make sense. for safety only */
281
+ /* wake master thread to flush the pages */
282
+ srv_wake_master_thread();
284
+ mutex_enter(&kernel_mutex);
285
+ srv_n_threads_active[SRV_PURGE]--;
286
+ mutex_exit(&kernel_mutex);
287
+ os_thread_exit(NULL);
289
+ OS_THREAD_DUMMY_RETURN;
292
+/*************************************************************************
293
+A thread which is devoted to purge, for take over the master thread's
297
+srv_purge_worker_thread(
298
+/*====================*/
301
+ ulint worker_id; /* index for array */
303
+ worker_id = *((ulint*)arg);
305
+#ifdef UNIV_DEBUG_THREAD_CREATION
306
+ fprintf(stderr, "Purge worker thread starts, id %lu\n",
307
+ os_thread_pf(os_thread_get_curr_id()));
309
+ mutex_enter(&kernel_mutex);
310
+ srv_table_reserve_slot(SRV_PURGE_WORKER);
311
+ srv_n_threads_active[SRV_PURGE_WORKER]++;
312
+ mutex_exit(&kernel_mutex);
315
+ /* purge worker threads only works when srv_shutdown_state==0 */
316
+ /* for safety and exactness. */
317
+ if (srv_shutdown_state > 0) {
321
+ trx_purge_worker_wait();
323
+ if (srv_shutdown_state > 0) {
327
+ trx_purge_worker(worker_id);
332
+ mutex_enter(&kernel_mutex);
333
+ srv_n_threads_active[SRV_PURGE_WORKER]--;
334
+ mutex_exit(&kernel_mutex);
335
+ os_thread_exit(NULL);
337
+ OS_THREAD_DUMMY_RETURN;
339
--- a/storage/innodb_plugin/srv/srv0start.c
340
+++ b/storage/innodb_plugin/srv/srv0start.c
344
/** io_handler_thread parameters for thread identification */
345
-static ulint n[SRV_MAX_N_IO_THREADS + 6];
346
+static ulint n[SRV_MAX_N_IO_THREADS + 6 + UNIV_MAX_PARALLELISM];
347
/** io_handler_thread identifiers */
348
-static os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 6];
349
+static os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 6 + UNIV_MAX_PARALLELISM];
351
/** We use this mutex to test the return value of pthread_mutex_trylock
352
on successful locking. HP-UX does NOT return 0, though Linux et al do. */
353
@@ -1725,6 +1725,20 @@
355
os_thread_create(&srv_master_thread, NULL, thread_ids
356
+ (1 + SRV_MAX_N_IO_THREADS));
358
+ if (srv_use_purge_thread) {
361
+ os_thread_create(&srv_purge_thread, NULL, thread_ids
362
+ + (5 + SRV_MAX_N_IO_THREADS));
364
+ for (i = 0; i < srv_use_purge_thread - 1; i++) {
365
+ n[6 + i + SRV_MAX_N_IO_THREADS] = i; /* using as index for arrays in purge_sys */
366
+ os_thread_create(&srv_purge_worker_thread,
367
+ n + (6 + i + SRV_MAX_N_IO_THREADS),
368
+ thread_ids + (6 + i + SRV_MAX_N_IO_THREADS));
372
/* buf_debug_prints = TRUE; */
373
#endif /* UNIV_DEBUG */
374
--- a/storage/innodb_plugin/trx/trx0purge.c
375
+++ b/storage/innodb_plugin/trx/trx0purge.c
377
@return own: the query graph */
380
-trx_purge_graph_build(void)
381
+trx_purge_graph_build(
382
/*=======================*/
389
heap = mem_heap_create(512);
390
fork = que_fork_create(NULL, NULL, QUE_FORK_PURGE, heap);
391
- fork->trx = purge_sys->trx;
394
thr = que_thr_create(fork, heap);
396
@@ -243,10 +244,35 @@
398
ut_a(trx_start_low(purge_sys->trx, ULINT_UNDEFINED));
400
- purge_sys->query = trx_purge_graph_build();
401
+ purge_sys->query = trx_purge_graph_build(purge_sys->trx);
403
purge_sys->view = read_view_oldest_copy_or_open_new(ut_dulint_zero,
406
+ purge_sys->n_worker = 0;
407
+ if (srv_use_purge_thread > 1) {
408
+ /* Use worker threads */
411
+ purge_sys->n_worker = srv_use_purge_thread - 1;
413
+ purge_sys->sess_arr = mem_alloc(sizeof(sess_t*) * purge_sys->n_worker);
414
+ purge_sys->trx_arr = mem_alloc(sizeof(trx_t*) * purge_sys->n_worker);
415
+ purge_sys->query_arr = mem_alloc(sizeof(que_t*) * purge_sys->n_worker);
417
+ purge_sys->worker_event = os_event_create(NULL);
418
+ os_event_reset(purge_sys->worker_event);
420
+ for (i = 0; i < purge_sys->n_worker; i++) {
421
+ purge_sys->sess_arr[i] = sess_open();
423
+ purge_sys->trx_arr[i] = purge_sys->sess_arr[i]->trx;
424
+ purge_sys->trx_arr[i]->is_purge = 1;
425
+ ut_a(trx_start_low(purge_sys->trx_arr[i], ULINT_UNDEFINED));
427
+ purge_sys->query_arr[i] = trx_purge_graph_build(purge_sys->trx_arr[i]);
432
/************************************************************************
433
@@ -1144,7 +1170,7 @@
435
/* Handle at most 20 undo log pages in one purge batch */
437
- purge_sys->handle_limit = purge_sys->n_pages_handled + 20;
438
+ purge_sys->handle_limit = purge_sys->n_pages_handled + 20 * (srv_use_purge_thread + 1);
440
old_pages_handled = purge_sys->n_pages_handled;
442
@@ -1163,6 +1189,9 @@
444
mutex_exit(&kernel_mutex);
446
+ if (purge_sys->n_worker)
447
+ os_event_set(purge_sys->worker_event);
449
/* srv_que_task_enqueue(thr2); */
451
if (srv_print_thread_releases) {
452
@@ -1172,6 +1201,9 @@
454
que_run_threads(thr);
456
+ if (purge_sys->n_worker)
457
+ os_event_reset(purge_sys->worker_event);
459
if (srv_print_thread_releases) {
462
@@ -1182,6 +1214,52 @@
463
return(purge_sys->n_pages_handled - old_pages_handled);
466
+/**********************************************************************
467
+This function runs a purge worker batch */
476
+ mutex_enter(&kernel_mutex);
478
+ thr = que_fork_start_command(purge_sys->query_arr[worker_id]);
482
+ mutex_exit(&kernel_mutex);
484
+ que_run_threads(thr);
486
+ if (purge_sys->state == TRX_STOP_PURGE) { /* optimistic */
487
+ os_event_reset(purge_sys->worker_event);
491
+/**********************************************************************
492
+This function waits the event for worker batch */
495
+trx_purge_worker_wait(void)
496
+/*=======================*/
498
+ os_event_wait(purge_sys->worker_event);
501
+/**********************************************************************
502
+This function wakes the waiting worker batch */
505
+trx_purge_worker_wake(void)
506
+/*=======================*/
508
+ if (purge_sys->n_worker)
509
+ os_event_set(purge_sys->worker_event);
512
/******************************************************************//**
513
Prints information of the purge system to stderr. */