📄 log0log.c
字号:
log_flush_do_unlocks(unlock); mutex_exit(&(log_sys->mutex)); return; do_waits: mutex_exit(&(log_sys->mutex)); if (wait == LOG_WAIT_ONE_GROUP) { os_event_wait(log_sys->one_flushed_event); } else if (wait == LOG_WAIT_ALL_GROUPS) { os_event_wait(log_sys->no_flush_event); } else { ut_ad(wait == LOG_NO_WAIT); } }/********************************************************************Does a syncronous flush of the log buffer to disk. */voidlog_buffer_flush_to_disk(void)/*==========================*/{ dulint lsn; mutex_enter(&(log_sys->mutex)); lsn = log_sys->lsn; mutex_exit(&(log_sys->mutex)); log_write_up_to(lsn, LOG_WAIT_ALL_GROUPS, TRUE);}/********************************************************************Tries to establish a big enough margin of free space in the log buffer, suchthat a new log entry can be catenated without an immediate need for a flush. */staticvoidlog_flush_margin(void)/*==================*/{ ibool do_flush = FALSE; log_t* log = log_sys; dulint lsn; mutex_enter(&(log->mutex)); if (log->buf_free > log->max_buf_free) { if (log->n_pending_writes > 0) { /* A flush is running: hope that it will provide enough free space */ } else { do_flush = TRUE; lsn = log->lsn; } } mutex_exit(&(log->mutex)); if (do_flush) { log_write_up_to(lsn, LOG_NO_WAIT, FALSE); }}/********************************************************************Advances the smallest lsn for which there are unflushed dirty blocks in thebuffer pool. NOTE: this function may only be called if the calling thread ownsno synchronization objects! */iboollog_preflush_pool_modified_pages(/*=============================*/ /* out: FALSE if there was a flush batch of the same type running, which means that we could not start this flush batch */ dulint new_oldest, /* in: try to advance oldest_modified_lsn at least to this lsn */ ibool sync) /* in: TRUE if synchronous operation is desired */{ ulint n_pages; if (recv_recovery_on) { /* If the recovery is running, we must first apply all log records to their respective file pages to get the right modify lsn values to these pages: otherwise, there might be pages on disk which are not yet recovered to the current lsn, and even after calling this function, we could not know how up-to-date the disk version of the database is, and we could not make a new checkpoint on the basis of the info on the buffer pool only. */ recv_apply_hashed_log_recs(TRUE); } n_pages = buf_flush_batch(BUF_FLUSH_LIST, ULINT_MAX, new_oldest); if (sync) { buf_flush_wait_batch_end(BUF_FLUSH_LIST); } if (n_pages == ULINT_UNDEFINED) { return(FALSE); } return(TRUE);}/**********************************************************Completes a checkpoint. */staticvoidlog_complete_checkpoint(void)/*=========================*/{#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(log_sys->mutex)));#endif /* UNIV_SYNC_DEBUG */ ut_ad(log_sys->n_pending_checkpoint_writes == 0); log_sys->next_checkpoint_no = ut_dulint_add(log_sys->next_checkpoint_no, 1); log_sys->last_checkpoint_lsn = log_sys->next_checkpoint_lsn; rw_lock_x_unlock_gen(&(log_sys->checkpoint_lock), LOG_CHECKPOINT);}/**********************************************************Completes an asynchronous checkpoint info write i/o to a log file. */staticvoidlog_io_complete_checkpoint(void)/*============================*/{ mutex_enter(&(log_sys->mutex)); ut_ad(log_sys->n_pending_checkpoint_writes > 0); log_sys->n_pending_checkpoint_writes--; if (log_sys->n_pending_checkpoint_writes == 0) { log_complete_checkpoint(); } mutex_exit(&(log_sys->mutex));}/***********************************************************************Writes info to a checkpoint about a log group. */staticvoidlog_checkpoint_set_nth_group_info(/*==============================*/ byte* buf, /* in: buffer for checkpoint info */ ulint n, /* in: nth slot */ ulint file_no,/* in: archived file number */ ulint offset) /* in: archived file offset */{ ut_ad(n < LOG_MAX_N_GROUPS); mach_write_to_4(buf + LOG_CHECKPOINT_GROUP_ARRAY + 8 * n + LOG_CHECKPOINT_ARCHIVED_FILE_NO, file_no); mach_write_to_4(buf + LOG_CHECKPOINT_GROUP_ARRAY + 8 * n + LOG_CHECKPOINT_ARCHIVED_OFFSET, offset);}/***********************************************************************Gets info from a checkpoint about a log group. */voidlog_checkpoint_get_nth_group_info(/*==============================*/ byte* buf, /* in: buffer containing checkpoint info */ ulint n, /* in: nth slot */ ulint* file_no,/* out: archived file number */ ulint* offset) /* out: archived file offset */{ ut_ad(n < LOG_MAX_N_GROUPS); *file_no = mach_read_from_4(buf + LOG_CHECKPOINT_GROUP_ARRAY + 8 * n + LOG_CHECKPOINT_ARCHIVED_FILE_NO); *offset = mach_read_from_4(buf + LOG_CHECKPOINT_GROUP_ARRAY + 8 * n + LOG_CHECKPOINT_ARCHIVED_OFFSET);}/**********************************************************Writes the checkpoint info to a log group header. */staticvoidlog_group_checkpoint(/*=================*/ log_group_t* group) /* in: log group */{ log_group_t* group2;#ifdef UNIV_LOG_ARCHIVE dulint archived_lsn; dulint next_archived_lsn;#endif /* UNIV_LOG_ARCHIVE */ ulint write_offset; ulint fold; byte* buf; ulint i;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(log_sys->mutex)));#endif /* UNIV_SYNC_DEBUG */ ut_a(LOG_CHECKPOINT_SIZE <= OS_FILE_LOG_BLOCK_SIZE); buf = group->checkpoint_buf; mach_write_to_8(buf + LOG_CHECKPOINT_NO, log_sys->next_checkpoint_no); mach_write_to_8(buf + LOG_CHECKPOINT_LSN, log_sys->next_checkpoint_lsn); mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET, log_group_calc_lsn_offset( log_sys->next_checkpoint_lsn, group)); mach_write_to_4(buf + LOG_CHECKPOINT_LOG_BUF_SIZE, log_sys->buf_size);#ifdef UNIV_LOG_ARCHIVE if (log_sys->archiving_state == LOG_ARCH_OFF) { archived_lsn = ut_dulint_max; } else { archived_lsn = log_sys->archived_lsn; if (0 != ut_dulint_cmp(archived_lsn, log_sys->next_archived_lsn)) { next_archived_lsn = log_sys->next_archived_lsn; /* For debugging only */ } } mach_write_to_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN, archived_lsn);#else /* UNIV_LOG_ARCHIVE */ mach_write_to_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN, ut_dulint_max);#endif /* UNIV_LOG_ARCHIVE */ for (i = 0; i < LOG_MAX_N_GROUPS; i++) { log_checkpoint_set_nth_group_info(buf, i, 0, 0); } group2 = UT_LIST_GET_FIRST(log_sys->log_groups); while (group2) { log_checkpoint_set_nth_group_info(buf, group2->id,#ifdef UNIV_LOG_ARCHIVE group2->archived_file_no, group2->archived_offset#else /* UNIV_LOG_ARCHIVE */ 0, 0#endif /* UNIV_LOG_ARCHIVE */ ); group2 = UT_LIST_GET_NEXT(log_groups, group2); } fold = ut_fold_binary(buf, LOG_CHECKPOINT_CHECKSUM_1); mach_write_to_4(buf + LOG_CHECKPOINT_CHECKSUM_1, fold); fold = ut_fold_binary(buf + LOG_CHECKPOINT_LSN, LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN); mach_write_to_4(buf + LOG_CHECKPOINT_CHECKSUM_2, fold); /* Starting from InnoDB-3.23.50, we also write info on allocated size in the tablespace */ mach_write_to_4(buf + LOG_CHECKPOINT_FSP_FREE_LIMIT, log_fsp_current_free_limit); mach_write_to_4(buf + LOG_CHECKPOINT_FSP_MAGIC_N, LOG_CHECKPOINT_FSP_MAGIC_N_VAL); /* We alternate the physical place of the checkpoint info in the first log file */ if (ut_dulint_get_low(log_sys->next_checkpoint_no) % 2 == 0) { write_offset = LOG_CHECKPOINT_1; } else { write_offset = LOG_CHECKPOINT_2; } if (log_do_write) { if (log_sys->n_pending_checkpoint_writes == 0) { rw_lock_x_lock_gen(&(log_sys->checkpoint_lock), LOG_CHECKPOINT); } log_sys->n_pending_checkpoint_writes++; log_sys->n_log_ios++; /* We send as the last parameter the group machine address added with 1, as we want to distinguish between a normal log file write and a checkpoint field write */ fil_io(OS_FILE_WRITE | OS_FILE_LOG, FALSE, group->space_id, write_offset / UNIV_PAGE_SIZE, write_offset % UNIV_PAGE_SIZE, OS_FILE_LOG_BLOCK_SIZE, buf, ((byte*)group + 1)); ut_ad(((ulint)group & 0x1UL) == 0); }}/**********************************************************Writes info to a buffer of a log group when log files are created inbackup restoration. */voidlog_reset_first_header_and_checkpoint(/*==================================*/ byte* hdr_buf,/* in: buffer which will be written to the start of the first log file */ dulint start) /* in: lsn of the start of the first log file; we pretend that there is a checkpoint at start + LOG_BLOCK_HDR_SIZE */{ ulint fold; byte* buf; dulint lsn; mach_write_to_4(hdr_buf + LOG_GROUP_ID, 0); mach_write_to_8(hdr_buf + LOG_FILE_START_LSN, start); lsn = ut_dulint_add(start, LOG_BLOCK_HDR_SIZE); /* Write the label of ibbackup --restore */ strcpy((char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, "ibbackup "); ut_sprintf_timestamp( (char*) hdr_buf + (LOG_FILE_WAS_CREATED_BY_HOT_BACKUP + (sizeof "ibbackup ") - 1)); buf = hdr_buf + LOG_CHECKPOINT_1; mach_write_to_8(buf + LOG_CHECKPOINT_NO, ut_dulint_zero); mach_write_to_8(buf + LOG_CHECKPOINT_LSN, lsn); mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET, LOG_FILE_HDR_SIZE + LOG_BLOCK_HDR_SIZE); mach_write_to_4(buf + LOG_CHECKPOINT_LOG_BUF_SIZE, 2 * 1024 * 1024); mach_write_to_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN, ut_dulint_max); fold = ut_fold_binary(buf, LOG_CHECKPOINT_CHECKSUM_1); mach_write_to_4(buf + LOG_CHECKPOINT_CHECKSUM_1, fold); fold = ut_fold_binary(buf + LOG_CHECKPOINT_LSN, LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN); mach_write_to_4(buf + LOG_CHECKPOINT_CHECKSUM_2, fold); /* Starting from InnoDB-3.23.50, we should also write info on allocated size in the tablespace, but unfortunately we do not know it here */}/**********************************************************Reads a checkpoint info from a log group header to log_sys->checkpoint_buf. */voidlog_group_read_checkpoint_info(/*===========================*/ log_group_t* group, /* in: log group */ ulint field) /* in: LOG_CHECKPOINT_1 or LOG_CHECKPOINT_2 */{#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(log_sys->mutex)));#endif /* UNIV_SYNC_DEBUG */ log_sys->n_log_ios++; fil_io(OS_FILE_READ | OS_FILE_LOG, TRUE, group->space_id, field / UNIV_PAGE_SIZE, field % UNIV_PAGE_SIZE, OS_FILE_LOG_BLOCK_SIZE, log_sys->checkpoint_buf, NULL);}/**********************************************************Writes checkpoint info to groups. */voidlog_groups_write_checkpoint_info(void)/*==================================*/{ log_group_t* group;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(log_sys->mutex)));#endif /* UNIV_SYNC_DEBUG */ group = UT_LIST_GET_FIRST(log_sys->log_groups); while (group) { log_group_checkpoint(group); group = UT_LIST_GET_NEXT(log_groups, group); }}/**********************************************************Makes a checkpoint. Note that this function does not flush dirtyblocks from the buffer pool: it only checks what is lsn of the oldestmodification in the pool, and writes information about the lsn inlog files. Use log_make_checkpoint_at to flush also the pool. */iboollog_checkpoint(/*===========*/ /* out: TRUE if success, FALSE if a checkpoint write was already running */ ibool sync, /* in: TRUE if synchronous operation is desired */ ibool write_always) /* in: the function normally checks if the the new checkpoint would have a greater lsn than the previous one: if not, then no physical write is done; by setting this parameter TRUE, a physical write will always be made to log files */{ dulint oldest_lsn; if (recv_recovery_is_on()) { recv_apply_hashed_log_recs(TRUE); } if (srv_unix_file_flush_method != SRV_UNIX_NOSYNC) { fil_flush_file_spaces(FIL_TABLESPACE); } mutex_enter(&(log_sys->mutex)); oldest_lsn = log_buf_pool_get_oldest_modification(); mutex_exit(&(log_sys->mutex)); /* Because log also contains headers and dummy log records, if the buffer pool contains no dirty buffers, oldest_lsn gets the value log_sys->lsn from the previous function, and we must make sure that the log is flushed up to that lsn. If there are dirty buffers in the buffer pool, then our write-ahead-logging algorithm ensures that the log has been flushed up to oldest_lsn. */ log_write_up_to(oldest_lsn, LOG_WAIT_ALL_GROUPS, TRUE); mutex_enter(&(log_sys->mutex)); if (!write_always && ut_dulint_cmp( log_sys->last_checkpoint_lsn, oldest_lsn) >= 0) { mutex_exit(&(log_sys->mutex)); return(TRUE); } ut_ad(ut_dulint_cmp(log_sys->written_to_all_lsn, oldest_lsn) >= 0); if (log_sys->n_pending_checkpoint_writes > 0) { /* A checkpoint write is running */ mutex_exit(&(log_sys->mutex)); if (sync) { /* Wait for the checkpoint write to complete */ rw_lock_s_lock(&(log_sys->checkpoint_lock)); rw_lock_s_unlock(&(log_sys->checkpoint_lock)); } return(FALSE); } log_sys->next_checkpoint_lsn = oldest_lsn;#ifdef UNIV_DEBUG if (log_debug_writes) { fprintf(stderr, "Making checkpoint no %lu at lsn %lu %lu\n", (ulong) ut_dulint_get_low(log_sys->next_checkpoint_no), (ulong) ut_dulint_get_high(oldest_lsn), (ulong) ut_dulint_get_low(oldest_lsn)); }#endif /* UNIV_DEBUG */ log_groups_write_checkpoint_info(); mutex_exit(&(log_sys->mutex)); if (sync) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -