MySQL Innodb Engine--DML操作时先生成Undo Log还是先生成Redo Log

时间:2021-07-13
本文章向大家介绍MySQL Innodb Engine--DML操作时先生成Undo Log还是先生成Redo Log,主要包括MySQL Innodb Engine--DML操作时先生成Undo Log还是先生成Redo Log使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

问题总结

问题:DML操作时先生成Undo Log是Redo Log?

答案:先生成Undo Log,再生成Redo Log。

在生成Undo Log并写入到Undo Space时,会产生Redo Log。

在故障恢复时,可以通过Redo Log来恢复Undo Log,再通过Undo Log来回滚事务。

代码瞎猜

函数btr_cur_optimistic_insert用来实现插入记录操作,其中代码为:

/** Tries to perform an insert to a page in an index tree, next to cursor.
 It is assumed that mtr holds an x-latch on the page. The operation does
 not succeed if there is too little space on the page. If there is just
 one record on the page, the insert will always succeed; this is to
 prevent trying to split a page with just one record.
 @return DB_SUCCESS, DB_WAIT_LOCK, DB_FAIL, or error number */
dberr_t btr_cur_optimistic_insert()
{
  /* Now, try the insert */
  {
    const rec_t *page_cursor_rec = page_cur_get_rec(page_cursor);
	
    /* 判断表是否为临时表(is_intrinsic) */
    if (index->table->is_intrinsic()) {
      /* 临时表不需要生产UNDO LOG */
      index->rec_cache.rec_size = rec_size;

      *rec = page_cur_tuple_direct_insert(page_cursor, entry, index, mtr);
    } else {
      /* Check locks and write to the undo log,if specified */
      err = btr_cur_ins_lock_and_undo(flags, cursor, entry, thr, mtr, &inherit);

      if (err != DB_SUCCESS) {
        goto fail_err;
      }
	  /* 向数据页中插入记录,插入过程会产生UNDO LOG */
      *rec = page_cur_tuple_insert(page_cursor, entry, index, offsets, heap, mtr);
    }

    reorg = page_cursor_rec != page_cur_get_rec(page_cursor);
  }
    
}

函数btr_cur_optimistic_update用于更新记录,其中代码为:

/** Tries to update a record on a page in an index tree. It is assumed that mtr
 holds an x-latch on the page. The operation does not succeed if there is too
 little space on the page or if the update would result in too empty a page,
 so that tree compression is recommended. We assume here that the ordering
 fields of the record do not change.
 @return error code, including
 @retval DB_SUCCESS on success
 @retval DB_OVERFLOW if the updated record does not fit
 @retval DB_UNDERFLOW if the page would become too empty
 @retval DB_ZIP_OVERFLOW if there is not enough space left
 on the compressed page (IBUF_BITMAP_FREE was reset outside mtr) */
dberr_t btr_cur_optimistic_update()
{
  /* Do lock checking and undo logging */
  err = btr_cur_upd_lock_and_undo(flags, cursor, *offsets, update, cmpl_info,
                                  thr, mtr, &roll_ptr);
  /* 更新adaptive hash index*/
  btr_search_update_hash_on_delete(cursor);
  
  /* 删除记录 */
  page_cur_delete_rec(page_cursor, index, *offsets, mtr);

  page_cur_move_to_prev(page_cursor);
  
  if (!(flags & BTR_KEEP_SYS_FLAG) && !index->table->is_intrinsic()) {
    row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR, roll_ptr);
    row_upd_index_entry_sys_field(new_entry, index, DATA_TRX_ID, trx_id);
  }

  /* There are no externally stored columns in new_entry */
  /* 插入记录 */
  rec = btr_cur_insert_if_possible(cursor, new_entry, offsets, heap, mtr);
  ut_a(rec); /* <- We calculated above the insert would fit */

  /* Restore the old explicit lock state on the record */
  if (!dict_table_is_locking_disabled(index->table)) {
    lock_rec_restore_from_page_infimum(block, rec, block);
  }

  page_cur_move_to_next(page_cursor);
  ut_ad(err == DB_SUCCESS);
}

Mini-transaction的日志类型

每条InnoDB存储引擎产生的Redo Log都包含下面信息:

  • type:Redo Log的类型,使用1字节来存放。
  • space:表空间ID
  • offset:数据页在表空间上的偏移量
  • body:存放Redo Log的日志数据

针对DML中增删改产生的Redo Log有如下类型:

  /** Record insert */
  MLOG_REC_INSERT = 9,

  /*!< Delete a record from a page */
  MLOG_REC_DELETE = 14,

  /** update of a record, preserves record field sizes */
  MLOG_REC_UPDATE_IN_PLACE = 13,

  /** update of a compact record, preserves record field sizes */
  MLOG_COMP_REC_UPDATE_IN_PLACE = 41,

  /** delete a compact record from a page */
  MLOG_COMP_REC_DELETE = 42,

  /** compact record insert */
  MLOG_COMP_REC_INSERT = 38,

  /** delete a compact record from a page */
  MLOG_COMP_REC_DELETE = 42,

针对Undo Log产生的Redo Log有如下类型:

  /** Insert entry in an undo log */
  MLOG_UNDO_INSERT = 20,

  /** erase an undo log page end */
  MLOG_UNDO_ERASE_END = 21,

  /** initialize a page in an undo log */
  MLOG_UNDO_INIT = 22,

  /** reuse an insert undo log header */
  MLOG_UNDO_HDR_REUSE = 24,

  /** create an undo log header */
  MLOG_UNDO_HDR_CREATE = 25,

Mini-transaction的日志类型:

/** Logging modes for a mini-transaction */
enum mtr_log_t {
  /** Default mode: log all operations modifying disk-based data */
  MTR_LOG_ALL = 0,

  /** Log no operations and dirty pages are not added to the flush list */
  MTR_LOG_NONE = 1,

  /** Don't generate REDO log but add dirty pages to flush list */
  MTR_LOG_NO_REDO = 2,

  /** Inserts are logged in a shorter form */
  MTR_LOG_SHORT_INSERTS = 3,

  /** Last element */
  MTR_LOG_MODE_MAX = 4
};

/** @name Log item types
The log items are declared 'byte' so that the compiler can warn if val
and type parameters are switched in a call to mlog_write_ulint. NOTE!
For 1 - 8 bytes, the flag value must give the length also! @{ */
enum mlog_id_t {
  /** if the mtr contains only one log record for one page,
  i.e., write_initial_log_record has been called only once,
  this flag is ORed to the type of that first log record */
  MLOG_SINGLE_REC_FLAG = 128,

  /** one byte is written */
  MLOG_1BYTE = 1,

  /** 2 bytes ... */
  MLOG_2BYTES = 2,

  /** 4 bytes ... */
  MLOG_4BYTES = 4,

  /** 8 bytes ... */
  MLOG_8BYTES = 8,

  /** Record insert */
  MLOG_REC_INSERT = 9,

  /** Mark clustered index record deleted */
  MLOG_REC_CLUST_DELETE_MARK = 10,

  /** Mark secondary index record deleted */
  MLOG_REC_SEC_DELETE_MARK = 11,

  /** update of a record, preserves record field sizes */
  MLOG_REC_UPDATE_IN_PLACE = 13,

  /*!< Delete a record from a page */
  MLOG_REC_DELETE = 14,

  /** Delete record list end on index page */
  MLOG_LIST_END_DELETE = 15,

  /** Delete record list start on index page */
  MLOG_LIST_START_DELETE = 16,

  /** Copy record list end to a new created index page */
  MLOG_LIST_END_COPY_CREATED = 17,

  /** Reorganize an index page in ROW_FORMAT=REDUNDANT */
  MLOG_PAGE_REORGANIZE = 18,

  /** Create an index page */
  MLOG_PAGE_CREATE = 19,

  /** Insert entry in an undo log */
  MLOG_UNDO_INSERT = 20,

  /** erase an undo log page end */
  MLOG_UNDO_ERASE_END = 21,

  /** initialize a page in an undo log */
  MLOG_UNDO_INIT = 22,

  /** reuse an insert undo log header */
  MLOG_UNDO_HDR_REUSE = 24,

  /** create an undo log header */
  MLOG_UNDO_HDR_CREATE = 25,

  /** mark an index record as the predefined minimum record */
  MLOG_REC_MIN_MARK = 26,

  /** initialize an ibuf bitmap page */
  MLOG_IBUF_BITMAP_INIT = 27,

#ifdef UNIV_LOG_LSN_DEBUG
  /** Current LSN */
  MLOG_LSN = 28,
#endif /* UNIV_LOG_LSN_DEBUG */

  /** this means that a file page is taken into use and the prior
  contents of the page should be ignored: in recovery we must not
  trust the lsn values stored to the file page.
  Note: it's deprecated because it causes crash recovery problem
  in bulk create index, and actually we don't need to reset page
  lsn in recv_recover_page_func() now. */
  MLOG_INIT_FILE_PAGE = 29,

  /** write a string to a page */
  MLOG_WRITE_STRING = 30,

  /** If a single mtr writes several log records, this log
  record ends the sequence of these records */
  MLOG_MULTI_REC_END = 31,

  /** dummy log record used to pad a log block full */
  MLOG_DUMMY_RECORD = 32,

  /** log record about creating an .ibd file, with format */
  MLOG_FILE_CREATE = 33,

  /** rename a tablespace file that starts with (space_id,page_no) */
  MLOG_FILE_RENAME = 34,

  /** delete a tablespace file that starts with (space_id,page_no) */
  MLOG_FILE_DELETE = 35,

  /** mark a compact index record as the predefined minimum record */
  MLOG_COMP_REC_MIN_MARK = 36,

  /** create a compact index page */
  MLOG_COMP_PAGE_CREATE = 37,

  /** compact record insert */
  MLOG_COMP_REC_INSERT = 38,

  /** mark compact clustered index record deleted */
  MLOG_COMP_REC_CLUST_DELETE_MARK = 39,

  /** mark compact secondary index record deleted; this log
  record type is redundant, as MLOG_REC_SEC_DELETE_MARK is
  independent of the record format. */
  MLOG_COMP_REC_SEC_DELETE_MARK = 40,

  /** update of a compact record, preserves record field sizes */
  MLOG_COMP_REC_UPDATE_IN_PLACE = 41,

  /** delete a compact record from a page */
  MLOG_COMP_REC_DELETE = 42,

  /** delete compact record list end on index page */
  MLOG_COMP_LIST_END_DELETE = 43,

  /*** delete compact record list start on index page */
  MLOG_COMP_LIST_START_DELETE = 44,

  /** copy compact record list end to a new created index page */
  MLOG_COMP_LIST_END_COPY_CREATED = 45,

  /** reorganize an index page */
  MLOG_COMP_PAGE_REORGANIZE = 46,

  /** write the node pointer of a record on a compressed
  non-leaf B-tree page */
  MLOG_ZIP_WRITE_NODE_PTR = 48,

  /** write the BLOB pointer of an externally stored column
  on a compressed page */
  MLOG_ZIP_WRITE_BLOB_PTR = 49,

  /** write to compressed page header */
  MLOG_ZIP_WRITE_HEADER = 50,

  /** compress an index page */
  MLOG_ZIP_PAGE_COMPRESS = 51,

  /** compress an index page without logging it's image */
  MLOG_ZIP_PAGE_COMPRESS_NO_DATA = 52,

  /** reorganize a compressed page */
  MLOG_ZIP_PAGE_REORGANIZE = 53,

  /** Create a R-Tree index page */
  MLOG_PAGE_CREATE_RTREE = 57,

  /** create a R-tree compact page */
  MLOG_COMP_PAGE_CREATE_RTREE = 58,

  /** this means that a file page is taken into use.
  We use it to replace MLOG_INIT_FILE_PAGE. */
  MLOG_INIT_FILE_PAGE2 = 59,

  /** Table is being truncated. (Marked only for file-per-table) */
  /* MLOG_TRUNCATE = 60,  Disabled for WL6378 */

  /** notify that an index tree is being loaded without writing
  redo log about individual pages */
  MLOG_INDEX_LOAD = 61,

  /** log for some persistent dynamic metadata change */
  MLOG_TABLE_DYNAMIC_META = 62,

  /** create a SDI index page */
  MLOG_PAGE_CREATE_SDI = 63,

  /** create a SDI compact page */
  MLOG_COMP_PAGE_CREATE_SDI = 64,

  /** Extend the space */
  MLOG_FILE_EXTEND = 65,

  /** Used in tests of redo log. It must never be used outside unit tests. */
  MLOG_TEST = 66,

  /** biggest value (used in assertions) */
  MLOG_BIGGEST_TYPE = MLOG_TEST
};

原文地址:https://www.cnblogs.com/gaogao67/p/15008294.html