srv0src.cc
srv_master_thread(void* arg __attribute__((unused)))
{
## 省略各种变量声明、赋值
[color=blue]loop:[/color]
/*****************************************************************/
/* ---- When there is database activity by users, we cycle in this
loop */
srv_main_thread_op_info = "reserving kernel mutex";
## 获取bp的统计信息
buf_get_total_stat(&buf_stat);
n_ios_very_old = log_sys->n_log_ios + buf_stat.n_pages_read
+ buf_stat.n_pages_written;
mutex_enter(&kernel_mutex);
/* Store the user activity counter at the start of this loop */
old_activity_count = srv_activity_count;
mutex_exit(&kernel_mutex);
if (srv_force_recovery >= SRV_FORCE_NO_BACKGROUND) {
goto suspend_thread;
}
/* ---- We run the following loop approximately once per second
when there is database activity */
srv_last_log_flush_time = time(NULL);
/* Sleep for 1 second on entrying the for loop below the first time. */
next_itr_time = ut_time_ms() + 1000;
[color=blue] 每1秒进行的工作 [/color]
for (i = 0; i < 10; i++) {
ulint cur_time = ut_time_ms();
/* ALTER TABLE in MySQL requires on Unix that the table handler
can drop tables lazily after there no longer are SELECT
queries to them. */
srv_main_thread_op_info = "doing background drop tables";
## [color=red] ALTER TABLE产生的drop tables lazily信息 [/color]
row_drop_tables_for_mysql_in_background();
srv_main_thread_op_info = "";
if (srv_fast_shutdown && srv_shutdown_state > 0) {
goto background_loop;
}
## [color=red] 获取bp的统计信息 [/color]
buf_get_total_stat(&buf_stat);
n_ios_old = log_sys->n_log_ios + buf_stat.n_pages_read
+ buf_stat.n_pages_written;
srv_main_thread_op_info = "sleeping";
srv_main_1_second_loops++;
## [color=red] 可能sleep 1秒[/color]
if (next_itr_time > cur_time
&& srv_shutdown_state == SRV_SHUTDOWN_NONE) {
/* Get sleep interval in micro seconds. We use
ut_min() to avoid long sleep in case of
wrap around. */
os_thread_sleep(ut_min(1000000,
(next_itr_time - cur_time)
* 1000));
srv_main_sleeps++;
}
/* Each iteration should happen at 1 second interval. */
next_itr_time = ut_time_ms() + 1000;
## [color=red] flush log buffer [/color]
srv_sync_log_buffer_in_background();
## 检查是否要进行flush log buffer 或者产生一个新的checkpoint
srv_main_thread_op_info = "making checkpoint";
log_free_check();
/* If i/os during one second sleep were less than 5% of
capacity, we assume that there is free disk i/o capacity
available, and it makes sense to do an insert buffer merge. */
## [color=red] 获取bp的统计信息 [/color]
buf_get_total_stat(&buf_stat);
## [color=red] 可能merge最多5个insert buffer[/color]
n_pend_ios = buf_get_n_pending_ios() + log_sys->n_pending_writes;
n_ios = log_sys->n_log_ios + buf_stat.n_pages_read
+ buf_stat.n_pages_written;
if (n_pend_ios < SRV_PEND_IO_THRESHOLD
&& (n_ios - n_ios_old < SRV_RECENT_IO_ACTIVITY)) {
ibuf_contract_for_n_pages(FALSE, PCT_IO(5));
/* Flush logs if needed */
srv_sync_log_buffer_in_background();
}
## [color=red] 根据BP的脏页比例, 可能则flush最多100个脏页[/color]
if (UNIV_UNLIKELY(buf_get_modified_ratio_pct()
> srv_max_buf_pool_modified_pct)) {
n_pages_flushed = buf_flush_list(
PCT_IO(100), IB_ULONGLONG_MAX);
} else if (srv_adaptive_flushing) {
ulint n_flush = buf_flush_get_desired_flush_rate();
if (n_flush) {
n_flush = ut_min(PCT_IO(100), n_flush);
n_pages_flushed =
buf_flush_list(n_flush,IB_ULONGLONG_MAX);
}
}
## [color=red] 检查是否存在活动用户 [/color]
if (srv_activity_count == old_activity_count) {
goto background_loop;
}
}
[color=blue] 每1秒的工作结束 [/color]
[color=blue] 每10秒的工作开始 [/color]
/* ---- We perform the following code approximately once per
10 seconds when there is database activity */
## [color=red]获取bp的统计信息 [/color]
buf_get_total_stat(&buf_stat);
n_pend_ios = buf_get_n_pending_ios() + log_sys->n_pending_writes;
n_ios = log_sys->n_log_ios + buf_stat.n_pages_read
+ buf_stat.n_pages_written;
srv_main_10_second_loops++;
## [color=red] io使用情况, 可能则flush最多100个脏页[/color]
if (n_pend_ios < SRV_PEND_IO_THRESHOLD
&& (n_ios - n_ios_very_old < SRV_PAST_IO_ACTIVITY)) {
buf_flush_list(PCT_IO(100), IB_ULONGLONG_MAX);
## flush log buffer
srv_sync_log_buffer_in_background();
}
## [color=red]merge 5个insert buffer [/color]
srv_main_thread_op_info = "doing insert buffer merge";
ibuf_contract_for_n_pages(FALSE, PCT_IO(5));
## [color=red] flush log buffer [/color]
srv_sync_log_buffer_in_background();
## [color=red]未启用purge thread,则full purge。即删除BP中无用的undo页[/color]
if (srv_n_purge_threads == 0) {
srv_main_thread_op_info = "master purging";
srv_master_do_purge();
}
## [color=red]检查BP的脏页比例是否大于70%,flush 100或10个脏页 [/color]
srv_main_thread_op_info = "flushing buffer pool pages";
if (buf_get_modified_ratio_pct() > 70) {
## flush BP中 100 个脏页
n_pages_flushed = buf_flush_list(PCT_IO(100), IB_ULONGLONG_MAX);
} else {
## flush BP中 10 个脏页
n_pages_flushed = buf_flush_list(PCT_IO(10), IB_ULONGLONG_MAX);
}
## [color=red]产生一个checkpoint [/color]
srv_main_thread_op_info = "making checkpoint";
log_checkpoint(TRUE, FALSE);
srv_main_thread_op_info = "reserving kernel mutex";
[color=blue] 每10秒的工作结束 [/color]
## [color=red]检查是跳回loop还是进入background_loop [/color]
mutex_enter(&kernel_mutex);
if (srv_activity_count != old_activity_count) {
mutex_exit(&kernel_mutex);
goto loop;
}
mutex_exit(&kernel_mutex);
[color=blue]background_loop:[/color]
srv_main_background_loops++;
srv_main_thread_op_info = "doing background drop tables";
## [color=red] ALTER TABLE产生的drop tables lazily信息 [/color]
n_tables_to_drop = row_drop_tables_for_mysql_in_background();
if (n_tables_to_drop > 0) {
/* Do not monopolize the CPU even if there are tables waiting
in the background drop queue. (It is essentially a bug if
MySQL tries to drop a table while there are still open handles
to it and we had to put it to the background drop queue.) */
if (srv_shutdown_state == SRV_SHUTDOWN_NONE) {
os_thread_sleep(100000);
}
}
## [color=red]未启用purge thread,则full purge。即删除BP中无用的undo页[/color]
if (srv_n_purge_threads == 0) {
srv_main_thread_op_info = "master purging";
srv_master_do_purge();
}
## [color=red]检查是跳回loop还是继续 [/color]
srv_main_thread_op_info = "reserving kernel mutex";
mutex_enter(&kernel_mutex);
if (srv_activity_count != old_activity_count) {
mutex_exit(&kernel_mutex);
goto loop;
}
mutex_exit(&kernel_mutex);
## [color=red] 根据srv_fast_shutdown配置
是否merge最多100个insert buffer [/color]
srv_main_thread_op_info = "doing insert buffer merge";
if (srv_fast_shutdown && srv_shutdown_state > 0) {
n_bytes_merged = 0;
} else {
n_bytes_merged = ibuf_contract_for_n_pages(FALSE,
PCT_IO(100));
}
## [color=red]检查是跳回loop还是进入 flush loop [/color]
mutex_enter(&kernel_mutex);
if (srv_activity_count != old_activity_count) {
mutex_exit(&kernel_mutex);
goto loop;
}
mutex_exit(&kernel_mutex);
[color=blue]flush_loop:[/color]
srv_main_thread_op_info = "flushing buffer pool pages";
srv_main_flush_loops++;
## [color=red] srv_fast_shutdown<2,从LFU中flush最多100个 dirty page [/color]
if (srv_fast_shutdown < 2) {
n_pages_flushed = buf_flush_list(
PCT_IO(100), IB_ULONGLONG_MAX);
} else {
/* In the fastest shutdown we do not flush the buffer pool
to data files: we set n_pages_flushed to 0 artificially. */
n_pages_flushed = 0;
}
## [color=red]检查是跳回loop还是继续 [/color]
srv_main_thread_op_info = "reserving kernel mutex";
mutex_enter(&kernel_mutex);
if (srv_activity_count != old_activity_count) {
mutex_exit(&kernel_mutex);
goto loop;
}
mutex_exit(&kernel_mutex);
## [color=red] 将LFU所有脏页进行flush,直到有flush结束信号 [/color]
srv_main_thread_op_info = "waiting for buffer pool flush to end";
buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST);
## [color=red] merge insert buffer[/color]
srv_sync_log_buffer_in_background();
## [color=red]产生 checkpoint [/color]
srv_main_thread_op_info = "making checkpoint";
log_checkpoint(TRUE, FALSE);
## [color=red]根据脏页比较是否继续flush_loop [/color]
if (buf_get_modified_ratio_pct() > srv_max_buf_pool_modified_pct) {
goto flush_loop;
}
## [color=red]检查是跳回loop还是继续 [/color]
srv_main_thread_op_info = "reserving kernel mutex";
mutex_enter(&kernel_mutex);
if (srv_activity_count != old_activity_count) {
mutex_exit(&kernel_mutex);
goto loop;
}
mutex_exit(&kernel_mutex);
## [color=red]log归档检查 [/color]
/*
srv_main_thread_op_info = "archiving log (if log archive is on)";
log_archive_do(FALSE, &n_bytes_archived);
*/
n_bytes_archived = 0;
/* Print progress message every 60 seconds during shutdown */
if (srv_shutdown_state > 0 && srv_print_verbose_log) {
srv_shutdown_print_master_pending(&last_print_time,
n_tables_to_drop,
n_bytes_merged,
n_pages_flushed);
}
## [color=red]
是否有ALTER TABLE产生的drop tables lazily信息
是否有新的脏页需要flush
是否有log需要archive
重新跳回background_loop
[/color]
if (srv_fast_shutdown && srv_shutdown_state > 0) {
if (n_tables_to_drop + n_pages_flushed
+ n_bytes_archived != 0) {
goto background_loop;
}
} else if (n_tables_to_drop
+ n_pages_purged + n_bytes_merged + n_pages_flushed
+ n_bytes_archived != 0) {
goto background_loop;
}
/* There is no work for background operations either: suspend
master thread to wait for more server activity */
## [color=red] mysql挂起,等待事件发生 [/color]
[color=blue]suspend_thread:[/color]
srv_main_thread_op_info = "suspending";
mutex_enter(&kernel_mutex);
if (row_get_background_drop_list_len_low() > 0) {
mutex_exit(&kernel_mutex);
goto loop;
}
srv_suspend_thread(slot);
mutex_exit(&kernel_mutex);
/* DO NOT CHANGE THIS STRING. innobase_start_or_create_for_mysql()
waits for database activity to die down when converting < 4.1.x
databases, and relies on this string being exactly as it is. InnoDB
manual also mentions this string in several places. */
srv_main_thread_op_info = "waiting for server activity";
os_event_wait(slot->event);
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
os_thread_exit(NULL);
}
/* When there is user activity, InnoDB will set the event and the
main thread goes back to loop. */
goto loop;
}