📄 log0log.c
字号:
fprintf(stderr, "Log flushed to group %lu\n", (ulong) group->id); }#endif /* UNIV_DEBUG */ return(0);}/**********************************************************Checks if a flush is completed and does the completion routine if yes. */staticulintlog_sys_check_flush_completion(void)/*================================*/ /* out: LOG_UNLOCK_FLUSH_LOCK or 0 */{ ulint move_start; ulint move_end;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(log_sys->mutex)));#endif /* UNIV_SYNC_DEBUG */ if (log_sys->n_pending_writes == 0) { log_sys->written_to_all_lsn = log_sys->write_lsn; log_sys->buf_next_to_write = log_sys->write_end_offset; if (log_sys->write_end_offset > log_sys->max_buf_free / 2) { /* Move the log buffer content to the start of the buffer */ move_start = ut_calc_align_down( log_sys->write_end_offset, OS_FILE_LOG_BLOCK_SIZE); move_end = ut_calc_align(log_sys->buf_free, OS_FILE_LOG_BLOCK_SIZE); ut_memmove(log_sys->buf, log_sys->buf + move_start, move_end - move_start); log_sys->buf_free -= move_start; log_sys->buf_next_to_write -= move_start; } return(LOG_UNLOCK_FLUSH_LOCK); } return(0);}/**********************************************************Completes an i/o to a log file. */voidlog_io_complete(/*============*/ log_group_t* group) /* in: log group or a dummy pointer */{ ulint unlock;#ifdef UNIV_LOG_ARCHIVE if ((byte*)group == &log_archive_io) { /* It was an archive write */ log_io_complete_archive(); return; }#endif /* UNIV_LOG_ARCHIVE */ if ((ulint)group & 0x1UL) { /* It was a checkpoint write */ group = (log_group_t*)((ulint)group - 1); if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC && srv_unix_file_flush_method != SRV_UNIX_NOSYNC) { fil_flush(group->space_id); }#ifdef UNIV_DEBUG if (log_debug_writes) { fprintf(stderr, "Checkpoint info written to group %lu\n", group->id); }#endif /* UNIV_DEBUG */ log_io_complete_checkpoint(); return; } ut_error; /* We currently use synchronous writing of the logs and cannot end up here! */ if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC && srv_unix_file_flush_method != SRV_UNIX_NOSYNC && srv_flush_log_at_trx_commit != 2) { fil_flush(group->space_id); } mutex_enter(&(log_sys->mutex)); ut_a(group->n_pending_writes > 0); ut_a(log_sys->n_pending_writes > 0); group->n_pending_writes--; log_sys->n_pending_writes--; unlock = log_group_check_flush_completion(group); unlock = unlock | log_sys_check_flush_completion(); log_flush_do_unlocks(unlock); mutex_exit(&(log_sys->mutex));}/**********************************************************Writes a log file header to a log file space. */staticvoidlog_group_file_header_flush(/*========================*/ log_group_t* group, /* in: log group */ ulint nth_file, /* in: header to the nth file in the log file space */ dulint start_lsn) /* in: log file data starts at this lsn */{ byte* buf; ulint dest_offset;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(log_sys->mutex)));#endif /* UNIV_SYNC_DEBUG */ ut_a(nth_file < group->n_files); buf = *(group->file_header_bufs + nth_file); mach_write_to_4(buf + LOG_GROUP_ID, group->id); mach_write_to_8(buf + LOG_FILE_START_LSN, start_lsn); /* Wipe over possible label of ibbackup --restore */ memcpy(buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, " ", 4); dest_offset = nth_file * group->file_size;#ifdef UNIV_DEBUG if (log_debug_writes) { fprintf(stderr, "Writing log file header to group %lu file %lu\n", (ulong) group->id, (ulong) nth_file); }#endif /* UNIV_DEBUG */ if (log_do_write) { log_sys->n_log_ios++; srv_os_log_pending_writes++; fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->space_id, dest_offset / UNIV_PAGE_SIZE, dest_offset % UNIV_PAGE_SIZE, OS_FILE_LOG_BLOCK_SIZE, buf, group); srv_os_log_pending_writes--; }}/**********************************************************Stores a 4-byte checksum to the trailer checksum field of a log blockbefore writing it to a log file. This checksum is used in recovery tocheck the consistency of a log block. */staticvoidlog_block_store_checksum(/*=====================*/ byte* block) /* in/out: pointer to a log block */{ log_block_set_checksum(block, log_block_calc_checksum(block));} /**********************************************************Writes a buffer to a log file group. */voidlog_group_write_buf(/*================*/ log_group_t* group, /* in: log group */ byte* buf, /* in: buffer */ ulint len, /* in: buffer len; must be divisible by OS_FILE_LOG_BLOCK_SIZE */ dulint start_lsn, /* in: start lsn of the buffer; must be divisible by OS_FILE_LOG_BLOCK_SIZE */ ulint new_data_offset)/* in: start offset of new data in buf: this parameter is used to decide if we have to write a new log file header */{ ulint write_len; ibool write_header; ulint next_offset; ulint i; #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(log_sys->mutex)));#endif /* UNIV_SYNC_DEBUG */ ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0); ut_a(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); if (new_data_offset == 0) { write_header = TRUE; } else { write_header = FALSE; }loop: if (len == 0) { return; } next_offset = log_group_calc_lsn_offset(start_lsn, group); if ((next_offset % group->file_size == LOG_FILE_HDR_SIZE) && write_header) { /* We start to write a new log file instance in the group */ log_group_file_header_flush(group, next_offset / group->file_size, start_lsn); srv_os_log_written+= OS_FILE_LOG_BLOCK_SIZE; srv_log_writes++; } if ((next_offset % group->file_size) + len > group->file_size) { write_len = group->file_size - (next_offset % group->file_size); } else { write_len = len; }#ifdef UNIV_DEBUG if (log_debug_writes) { fprintf(stderr, "Writing log file segment to group %lu offset %lu len %lu\n" "start lsn %lu %lu\n" "First block n:o %lu last block n:o %lu\n", (ulong) group->id, (ulong) next_offset, (ulong) write_len, (ulong) ut_dulint_get_high(start_lsn), (ulong) ut_dulint_get_low(start_lsn), (ulong) log_block_get_hdr_no(buf), (ulong) log_block_get_hdr_no( buf + write_len - OS_FILE_LOG_BLOCK_SIZE)); ut_a(log_block_get_hdr_no(buf) == log_block_convert_lsn_to_no(start_lsn)); for (i = 0; i < write_len / OS_FILE_LOG_BLOCK_SIZE; i++) { ut_a(log_block_get_hdr_no(buf) + i == log_block_get_hdr_no(buf + i * OS_FILE_LOG_BLOCK_SIZE)); } }#endif /* UNIV_DEBUG */ /* Calculate the checksums for each log block and write them to the trailer fields of the log blocks */ for (i = 0; i < write_len / OS_FILE_LOG_BLOCK_SIZE; i++) { log_block_store_checksum(buf + i * OS_FILE_LOG_BLOCK_SIZE); } if (log_do_write) { log_sys->n_log_ios++; srv_os_log_pending_writes++; fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->space_id, next_offset / UNIV_PAGE_SIZE, next_offset % UNIV_PAGE_SIZE, write_len, buf, group); srv_os_log_pending_writes--; srv_os_log_written+= write_len; srv_log_writes++; } if (write_len < len) { start_lsn = ut_dulint_add(start_lsn, write_len); len -= write_len; buf += write_len; write_header = TRUE; goto loop; }}/**********************************************************This function is called, e.g., when a transaction wants to commit. It checksthat the log has been written to the log file up to the last log entry writtenby the transaction. If there is a flush running, it waits and checks if theflush flushed enough. If not, starts a new flush. */voidlog_write_up_to(/*============*/ dulint lsn, /* in: log sequence number up to which the log should be written, ut_dulint_max if not specified */ ulint wait, /* in: LOG_NO_WAIT, LOG_WAIT_ONE_GROUP, or LOG_WAIT_ALL_GROUPS */ ibool flush_to_disk) /* in: TRUE if we want the written log also to be flushed to disk */{ log_group_t* group; ulint start_offset; ulint end_offset; ulint area_start; ulint area_end; ulint loop_count; ulint unlock; if (recv_no_ibuf_operations) { /* Recovery is running and no operations on the log files are allowed yet (the variable name .._no_ibuf_.. is misleading) */ return; } loop_count = 0;loop: loop_count++; ut_ad(loop_count < 5); if (loop_count > 2) {/* fprintf(stderr, "Log loop count %lu\n", loop_count); */ } mutex_enter(&(log_sys->mutex)); if (flush_to_disk && ut_dulint_cmp(log_sys->flushed_to_disk_lsn, lsn) >= 0) { mutex_exit(&(log_sys->mutex)); return; } if (!flush_to_disk && (ut_dulint_cmp(log_sys->written_to_all_lsn, lsn) >= 0 || (ut_dulint_cmp(log_sys->written_to_some_lsn, lsn) >= 0 && wait != LOG_WAIT_ALL_GROUPS))) { mutex_exit(&(log_sys->mutex)); return; } if (log_sys->n_pending_writes > 0) { /* A write (+ possibly flush to disk) is running */ if (flush_to_disk && ut_dulint_cmp(log_sys->current_flush_lsn, lsn) >= 0) { /* The write + flush will write enough: wait for it to complete */ goto do_waits; } if (!flush_to_disk && ut_dulint_cmp(log_sys->write_lsn, lsn) >= 0) { /* The write will write enough: wait for it to complete */ goto do_waits; } mutex_exit(&(log_sys->mutex)); /* Wait for the write to complete and try to start a new write */ os_event_wait(log_sys->no_flush_event); goto loop; } if (!flush_to_disk && log_sys->buf_free == log_sys->buf_next_to_write) { /* Nothing to write and no flush to disk requested */ mutex_exit(&(log_sys->mutex)); return; }#ifdef UNIV_DEBUG if (log_debug_writes) { fprintf(stderr, "Writing log from %lu %lu up to lsn %lu %lu\n", (ulong) ut_dulint_get_high(log_sys->written_to_all_lsn), (ulong) ut_dulint_get_low(log_sys->written_to_all_lsn), (ulong) ut_dulint_get_high(log_sys->lsn), (ulong) ut_dulint_get_low(log_sys->lsn)); }#endif /* UNIV_DEBUG */ log_sys->n_pending_writes++; group = UT_LIST_GET_FIRST(log_sys->log_groups); group->n_pending_writes++; /* We assume here that we have only one log group! */ os_event_reset(log_sys->no_flush_event); os_event_reset(log_sys->one_flushed_event); start_offset = log_sys->buf_next_to_write; end_offset = log_sys->buf_free; area_start = ut_calc_align_down(start_offset, OS_FILE_LOG_BLOCK_SIZE); area_end = ut_calc_align(end_offset, OS_FILE_LOG_BLOCK_SIZE); ut_ad(area_end - area_start > 0); log_sys->write_lsn = log_sys->lsn; if (flush_to_disk) { log_sys->current_flush_lsn = log_sys->lsn; } log_sys->one_flushed = FALSE; log_block_set_flush_bit(log_sys->buf + area_start, TRUE); log_block_set_checkpoint_no( log_sys->buf + area_end - OS_FILE_LOG_BLOCK_SIZE, log_sys->next_checkpoint_no); /* Copy the last, incompletely written, log block a log block length up, so that when the flush operation writes from the log buffer, the segment to write will not be changed by writers to the log */ ut_memcpy(log_sys->buf + area_end, log_sys->buf + area_end - OS_FILE_LOG_BLOCK_SIZE, OS_FILE_LOG_BLOCK_SIZE); log_sys->buf_free += OS_FILE_LOG_BLOCK_SIZE; log_sys->write_end_offset = log_sys->buf_free; group = UT_LIST_GET_FIRST(log_sys->log_groups); /* Do the write to the log files */ while (group) { log_group_write_buf(group, log_sys->buf + area_start, area_end - area_start, ut_dulint_align_down(log_sys->written_to_all_lsn, OS_FILE_LOG_BLOCK_SIZE), start_offset - area_start); log_group_set_fields(group, log_sys->write_lsn); group = UT_LIST_GET_NEXT(log_groups, group); } mutex_exit(&(log_sys->mutex)); if (srv_unix_file_flush_method == SRV_UNIX_O_DSYNC) { /* O_DSYNC means the OS did not buffer the log file at all: so we have also flushed to disk what we have written */ log_sys->flushed_to_disk_lsn = log_sys->write_lsn; } else if (flush_to_disk) { group = UT_LIST_GET_FIRST(log_sys->log_groups); fil_flush(group->space_id); log_sys->flushed_to_disk_lsn = log_sys->write_lsn; } mutex_enter(&(log_sys->mutex)); group = UT_LIST_GET_FIRST(log_sys->log_groups); ut_a(group->n_pending_writes == 1); ut_a(log_sys->n_pending_writes == 1); group->n_pending_writes--; log_sys->n_pending_writes--; unlock = log_group_check_flush_completion(group); unlock = unlock | log_sys_check_flush_completion();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -