📄 log0log.c
字号:
log_group_t* group) /* in: log group */{#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(log_sys->mutex)));#endif /* UNIV_SYNC_DEBUG */ return(offset + LOG_FILE_HDR_SIZE * (1 + offset / (group->file_size - LOG_FILE_HDR_SIZE)));}/**********************************************************Calculates the offset of an lsn within a log group. */staticulintlog_group_calc_lsn_offset(/*======================*/ /* out: offset within the log group */ dulint lsn, /* in: lsn, must be within 4 GB of group->lsn */ log_group_t* group) /* in: log group */{ dulint gr_lsn; ib_longlong gr_lsn_size_offset; ib_longlong difference; ib_longlong group_size; ib_longlong offset; #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(log_sys->mutex)));#endif /* UNIV_SYNC_DEBUG */ /* If total log file size is > 2 GB we can easily get overflows with 32-bit integers. Use 64-bit integers instead. */ gr_lsn = group->lsn; gr_lsn_size_offset = (ib_longlong) log_group_calc_size_offset(group->lsn_offset, group); group_size = (ib_longlong) log_group_get_capacity(group); if (ut_dulint_cmp(lsn, gr_lsn) >= 0) { difference = (ib_longlong) ut_dulint_minus(lsn, gr_lsn); } else { difference = (ib_longlong) ut_dulint_minus(gr_lsn, lsn); difference = difference % group_size; difference = group_size - difference; } offset = (gr_lsn_size_offset + difference) % group_size; ut_a(offset < (((ib_longlong) 1) << 32)); /* offset must be < 4 GB */ /* fprintf(stderr, "Offset is %lu gr_lsn_offset is %lu difference is %lu\n", (ulint)offset,(ulint)gr_lsn_size_offset, (ulint)difference); */ return(log_group_calc_real_offset((ulint)offset, group));}/***********************************************************************Calculates where in log files we find a specified lsn. */ulintlog_calc_where_lsn_is(/*==================*/ /* out: log file number */ ib_longlong* log_file_offset, /* out: offset in that file (including the header) */ dulint first_header_lsn, /* in: first log file start lsn */ dulint lsn, /* in: lsn whose position to determine */ ulint n_log_files, /* in: total number of log files */ ib_longlong log_file_size) /* in: log file size (including the header) */{ ib_longlong ib_lsn; ib_longlong ib_first_header_lsn; ib_longlong capacity = log_file_size - LOG_FILE_HDR_SIZE; ulint file_no; ib_longlong add_this_many; ib_lsn = ut_conv_dulint_to_longlong(lsn); ib_first_header_lsn = ut_conv_dulint_to_longlong(first_header_lsn); if (ib_lsn < ib_first_header_lsn) { add_this_many = 1 + (ib_first_header_lsn - ib_lsn) / (capacity * (ib_longlong)n_log_files); ib_lsn += add_this_many * capacity * (ib_longlong)n_log_files; } ut_a(ib_lsn >= ib_first_header_lsn); file_no = ((ulint)((ib_lsn - ib_first_header_lsn) / capacity)) % n_log_files; *log_file_offset = (ib_lsn - ib_first_header_lsn) % capacity; *log_file_offset = *log_file_offset + LOG_FILE_HDR_SIZE; return(file_no);}/************************************************************Sets the field values in group to correspond to a given lsn. For this functionto work, the values must already be correctly initialized to correspond tosome lsn, for instance, a checkpoint lsn. */voidlog_group_set_fields(/*=================*/ log_group_t* group, /* in: group */ dulint lsn) /* in: lsn for which the values should be set */{ group->lsn_offset = log_group_calc_lsn_offset(lsn, group); group->lsn = lsn;}/*********************************************************************Calculates the recommended highest values for lsn - last_checkpoint_lsn,lsn - buf_get_oldest_modification(), and lsn - max_archive_lsn_age. */staticiboollog_calc_max_ages(void)/*===================*/ /* out: error value FALSE if the smallest log group is too small to accommodate the number of OS threads in the database server */{ log_group_t* group; ulint margin; ulint free; ibool success = TRUE; ulint smallest_capacity; ulint archive_margin; ulint smallest_archive_margin;#ifdef UNIV_SYNC_DEBUG ut_ad(!mutex_own(&(log_sys->mutex)));#endif /* UNIV_SYNC_DEBUG */ mutex_enter(&(log_sys->mutex)); group = UT_LIST_GET_FIRST(log_sys->log_groups); ut_ad(group); smallest_capacity = ULINT_MAX; smallest_archive_margin = ULINT_MAX; while (group) { if (log_group_get_capacity(group) < smallest_capacity) { smallest_capacity = log_group_get_capacity(group); } archive_margin = log_group_get_capacity(group) - (group->file_size - LOG_FILE_HDR_SIZE) - LOG_ARCHIVE_EXTRA_MARGIN; if (archive_margin < smallest_archive_margin) { smallest_archive_margin = archive_margin; } group = UT_LIST_GET_NEXT(log_groups, group); } /* Add extra safety */ smallest_capacity = smallest_capacity - smallest_capacity / 10; /* For each OS thread we must reserve so much free space in the smallest log group that it can accommodate the log entries produced by single query steps: running out of free log space is a serious system error which requires rebooting the database. */ free = LOG_CHECKPOINT_FREE_PER_THREAD * (10 + srv_thread_concurrency) + LOG_CHECKPOINT_EXTRA_FREE; if (free >= smallest_capacity / 2) { success = FALSE; goto failure; } else { margin = smallest_capacity - free; } margin = ut_min(margin, log_sys->adm_checkpoint_interval); margin = margin - margin / 10; /* Add still some extra safety */ log_sys->log_group_capacity = smallest_capacity; log_sys->max_modified_age_async = margin - margin / LOG_POOL_PREFLUSH_RATIO_ASYNC; log_sys->max_modified_age_sync = margin - margin / LOG_POOL_PREFLUSH_RATIO_SYNC; log_sys->max_checkpoint_age_async = margin - margin / LOG_POOL_CHECKPOINT_RATIO_ASYNC; log_sys->max_checkpoint_age = margin;#ifdef UNIV_LOG_ARCHIVE log_sys->max_archived_lsn_age = smallest_archive_margin; log_sys->max_archived_lsn_age_async = smallest_archive_margin - smallest_archive_margin / LOG_ARCHIVE_RATIO_ASYNC;#endif /* UNIV_LOG_ARCHIVE */failure: mutex_exit(&(log_sys->mutex)); if (!success) { fprintf(stderr,"InnoDB: Error: ib_logfiles are too small for innodb_thread_concurrency %lu.\n""InnoDB: The combined size of ib_logfiles should be bigger than\n""InnoDB: 200 kB * innodb_thread_concurrency.\n""InnoDB: To get mysqld to start up, set innodb_thread_concurrency in my.cnf\n""InnoDB: to a lower value, for example, to 8. After an ERROR-FREE shutdown\n""InnoDB: of mysqld you can adjust the size of ib_logfiles, as explained in\n""InnoDB: http://dev.mysql.com/doc/mysql/en/Adding_and_removing.html\n""InnoDB: Cannot continue operation. Calling exit(1).\n", (ulong)srv_thread_concurrency); exit(1); } return(success);}/**********************************************************Initializes the log. */voidlog_init(void)/*==========*/{ byte* buf; log_sys = mem_alloc(sizeof(log_t)); mutex_create(&(log_sys->mutex)); mutex_set_level(&(log_sys->mutex), SYNC_LOG); mutex_enter(&(log_sys->mutex)); /* Start the lsn from one log block from zero: this way every log record has a start lsn != zero, a fact which we will use */ log_sys->lsn = LOG_START_LSN; ut_a(LOG_BUFFER_SIZE >= 16 * OS_FILE_LOG_BLOCK_SIZE); ut_a(LOG_BUFFER_SIZE >= 4 * UNIV_PAGE_SIZE); buf = ut_malloc(LOG_BUFFER_SIZE + OS_FILE_LOG_BLOCK_SIZE); log_sys->buf = ut_align(buf, OS_FILE_LOG_BLOCK_SIZE); log_sys->buf_size = LOG_BUFFER_SIZE; memset(log_sys->buf, '\0', LOG_BUFFER_SIZE); log_sys->max_buf_free = log_sys->buf_size / LOG_BUF_FLUSH_RATIO - LOG_BUF_FLUSH_MARGIN; log_sys->check_flush_or_checkpoint = TRUE; UT_LIST_INIT(log_sys->log_groups); log_sys->n_log_ios = 0; log_sys->n_log_ios_old = log_sys->n_log_ios; log_sys->last_printout_time = time(NULL); /*----------------------------*/ log_sys->buf_next_to_write = 0; log_sys->write_lsn = ut_dulint_zero; log_sys->current_flush_lsn = ut_dulint_zero; log_sys->flushed_to_disk_lsn = ut_dulint_zero; log_sys->written_to_some_lsn = log_sys->lsn; log_sys->written_to_all_lsn = log_sys->lsn; log_sys->n_pending_writes = 0; log_sys->no_flush_event = os_event_create(NULL); os_event_set(log_sys->no_flush_event); log_sys->one_flushed_event = os_event_create(NULL); os_event_set(log_sys->one_flushed_event); /*----------------------------*/ log_sys->adm_checkpoint_interval = ULINT_MAX; log_sys->next_checkpoint_no = ut_dulint_zero; log_sys->last_checkpoint_lsn = log_sys->lsn; log_sys->n_pending_checkpoint_writes = 0; rw_lock_create(&(log_sys->checkpoint_lock)); rw_lock_set_level(&(log_sys->checkpoint_lock), SYNC_NO_ORDER_CHECK); log_sys->checkpoint_buf = ut_align( mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE), OS_FILE_LOG_BLOCK_SIZE); memset(log_sys->checkpoint_buf, '\0', OS_FILE_LOG_BLOCK_SIZE); /*----------------------------*/#ifdef UNIV_LOG_ARCHIVE /* Under MySQL, log archiving is always off */ log_sys->archiving_state = LOG_ARCH_OFF; log_sys->archived_lsn = log_sys->lsn; log_sys->next_archived_lsn = ut_dulint_zero; log_sys->n_pending_archive_ios = 0; rw_lock_create(&(log_sys->archive_lock)); rw_lock_set_level(&(log_sys->archive_lock), SYNC_NO_ORDER_CHECK); log_sys->archive_buf = NULL; /* ut_align( ut_malloc(LOG_ARCHIVE_BUF_SIZE + OS_FILE_LOG_BLOCK_SIZE), OS_FILE_LOG_BLOCK_SIZE); */ log_sys->archive_buf_size = 0; /* memset(log_sys->archive_buf, '\0', LOG_ARCHIVE_BUF_SIZE); */ log_sys->archiving_on = os_event_create(NULL);#endif /* UNIV_LOG_ARCHIVE */ /*----------------------------*/ log_block_init(log_sys->buf, log_sys->lsn); log_block_set_first_rec_group(log_sys->buf, LOG_BLOCK_HDR_SIZE); log_sys->buf_free = LOG_BLOCK_HDR_SIZE; log_sys->lsn = ut_dulint_add(LOG_START_LSN, LOG_BLOCK_HDR_SIZE); mutex_exit(&(log_sys->mutex));#ifdef UNIV_LOG_DEBUG recv_sys_create(); recv_sys_init(FALSE, buf_pool_get_curr_size()); recv_sys->parse_start_lsn = log_sys->lsn; recv_sys->scanned_lsn = log_sys->lsn; recv_sys->scanned_checkpoint_no = 0; recv_sys->recovered_lsn = log_sys->lsn; recv_sys->limit_lsn = ut_dulint_max;#endif}/**********************************************************************Inits a log group to the log system. */voidlog_group_init(/*===========*/ ulint id, /* in: group id */ ulint n_files, /* in: number of log files */ ulint file_size, /* in: log file size in bytes */ ulint space_id, /* in: space id of the file space which contains the log files of this group */ ulint archive_space_id __attribute__((unused))) /* in: space id of the file space which contains some archived log files for this group; currently, only for the first log group this is used */{ ulint i; log_group_t* group; group = mem_alloc(sizeof(log_group_t)); group->id = id; group->n_files = n_files; group->file_size = file_size; group->space_id = space_id; group->state = LOG_GROUP_OK; group->lsn = LOG_START_LSN; group->lsn_offset = LOG_FILE_HDR_SIZE; group->n_pending_writes = 0; group->file_header_bufs = mem_alloc(sizeof(byte*) * n_files);#ifdef UNIV_LOG_ARCHIVE group->archive_file_header_bufs = mem_alloc(sizeof(byte*) * n_files);#endif /* UNIV_LOG_ARCHIVE */ for (i = 0; i < n_files; i++) { *(group->file_header_bufs + i) = ut_align( mem_alloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE), OS_FILE_LOG_BLOCK_SIZE); memset(*(group->file_header_bufs + i), '\0', LOG_FILE_HDR_SIZE);#ifdef UNIV_LOG_ARCHIVE *(group->archive_file_header_bufs + i) = ut_align( mem_alloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE), OS_FILE_LOG_BLOCK_SIZE); memset(*(group->archive_file_header_bufs + i), '\0', LOG_FILE_HDR_SIZE);#endif /* UNIV_LOG_ARCHIVE */ } #ifdef UNIV_LOG_ARCHIVE group->archive_space_id = archive_space_id; group->archived_file_no = 0; group->archived_offset = 0;#endif /* UNIV_LOG_ARCHIVE */ group->checkpoint_buf = ut_align( mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE), OS_FILE_LOG_BLOCK_SIZE); memset(group->checkpoint_buf, '\0', OS_FILE_LOG_BLOCK_SIZE); UT_LIST_ADD_LAST(log_groups, log_sys->log_groups, group); ut_a(log_calc_max_ages());} /**********************************************************************Does the unlockings needed in flush i/o completion. */UNIV_INLINEvoidlog_flush_do_unlocks(/*=================*/ ulint code) /* in: any ORed combination of LOG_UNLOCK_FLUSH_LOCK and LOG_UNLOCK_NONE_FLUSHED_LOCK */{#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(log_sys->mutex)));#endif /* UNIV_SYNC_DEBUG */ /* NOTE that we must own the log mutex when doing the setting of the events: this is because transactions will wait for these events to be set, and at that moment the log flush they were waiting for must have ended. If the log mutex were not reserved here, the i/o-thread calling this function might be preempted for a while, and when it resumed execution, it might be that a new flush had been started, and this function would erroneously signal the NEW flush as completed. Thus, the changes in the state of these events are performed atomically in conjunction with the changes in the state of log_sys->n_pending_writes etc. */ if (code & LOG_UNLOCK_NONE_FLUSHED_LOCK) { os_event_set(log_sys->one_flushed_event); } if (code & LOG_UNLOCK_FLUSH_LOCK) { os_event_set(log_sys->no_flush_event); }}/**********************************************************************Checks if a flush is completed for a log group and does the completionroutine if yes. */UNIV_INLINEulintlog_group_check_flush_completion(/*=============================*/ /* out: LOG_UNLOCK_NONE_FLUSHED_LOCK or 0 */ log_group_t* group) /* in: log group */{#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(log_sys->mutex)));#endif /* UNIV_SYNC_DEBUG */ if (!log_sys->one_flushed && group->n_pending_writes == 0) {#ifdef UNIV_DEBUG if (log_debug_writes) { fprintf(stderr, "Log flushed first to group %lu\n", (ulong) group->id); }#endif /* UNIV_DEBUG */ log_sys->written_to_some_lsn = log_sys->write_lsn; log_sys->one_flushed = TRUE; return(LOG_UNLOCK_NONE_FLUSHED_LOCK); }#ifdef UNIV_DEBUG if (log_debug_writes && (group->n_pending_writes == 0)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -