innodb源碼8.0.19閱讀:mtr篇1

1,mtr0log.h

這個頭文件裏面聲明瞭寫相關日誌和解析相關日誌的函數,還有打開和關閉mtr日誌buffer的函數。

2,mtr0log.ic

基本的幾種日誌類型格式

MLOG_XBYTE:type(1字節),space id(1-5字節,原本是4字節,由於壓縮的原因),page no,offset(頁內偏移),data(實際數據)

前面type,space id,page no是redo日誌通用的,後面就是redo日誌的body。

MLOG_STRING:type,space id,page no,offset,len(字符串實際長度),data(記錄的字符串)

3,mtr0log.cc

                                         關鍵相關函數

//打開日誌buffer
byte *mlog_open(mtr_t *mtr, ulint size) {
  mtr->set_modified();
  //日誌模式爲這兩種,不記錄日誌
  if (mtr_get_log_mode(mtr) == MTR_LOG_NONE ||
      mtr_get_log_mode(mtr) == MTR_LOG_NO_REDO) {
    return (NULL);
  }
  //open函數:當前該mtr的buffer的最後一個block是否能容納size大小空間,如果可以返回空閒區域的地址
  //,如果不行,再添加一個block到buffer鏈表的末端,返回block最後一個block地址。也就是說返回的地址
  //是需要繼續寫日誌的位置。
  return (mtr->get_log()->open(size));
}
//關閉該mtr的日誌buffer
void mlog_close(mtr_t *mtr, /*!< in: mtr */
                byte *ptr)  /*!< in: buffer space from ptr up was not used */
{
  ut_ad(mtr_get_log_mode(mtr) != MTR_LOG_NONE);
  ut_ad(mtr_get_log_mode(mtr) != MTR_LOG_NO_REDO);
  //該函數表示寫完了,記錄該mtr寫了多少字節的日誌
  mtr->get_log()->close(ptr);
}
//寫入redo日誌的通用部分
byte *mlog_write_initial_log_record_fast(
    const byte *ptr, /*!< in: pointer to (inside) a buffer
                     frame holding the file page where
                     modification is made */
    mlog_id_t type,  /*!< in: log item type: MLOG_1BYTE, ... */
    byte *log_ptr,   /*!< in: pointer to mtr log which has
                     been opened */
    mtr_t *mtr)      /*!< in/out: mtr */
{
  const byte *page;
  space_id_t space;
  page_no_t offset;

  ut_ad(log_ptr);
  ut_d(mtr->memo_modify_page(ptr));
  //ptr指向在內存buffer中,一個page中要修改的地方,向下對頁面大小取模,就能夠得到該page的首地址
  page = (const byte *)ut_align_down(ptr, UNIV_PAGE_SIZE);
  //讀取表空間號
  space = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
  //讀取頁面號
  offset = mach_read_from_4(page + FIL_PAGE_OFFSET);

  //...............

  return (mlog_write_initial_log_record_low(type, space, offset, log_ptr, mtr));
}


byte *mlog_write_initial_log_record_low(mlog_id_t type, space_id_t space_id,
                                        page_no_t page_no, byte *log_ptr,
                                        mtr_t *mtr) {
  ut_ad(type <= MLOG_BIGGEST_TYPE);
  //寫入一條日誌的類型
  mach_write_to_1(log_ptr, type);
  log_ptr++;
  //將表空間號和頁面號壓縮,並且寫入日誌指針後面
  log_ptr += mach_write_compressed(log_ptr, space_id);
  log_ptr += mach_write_compressed(log_ptr, page_no);
  //該mtr中記錄數加1
  mtr->added_rec();
  return (log_ptr);
}


//一個簡單的壓縮算法
//大概思想就是:最高位爲0的時候,只用1字節,也就是8位,最高位浪費掉,用來標識有多少位實際用來存
//儲原本需要4字節的數據,也就是隻用7位來存儲。存儲的範圍也應該小於7位所能存儲的最大值。
//次高位爲0的時候,說明有兩位浪費了,只用14位存儲。
//從左到右,第三位爲0的時候,說明浪費了3位,只用了21位存儲數據。
ulint mach_write_compressed(byte *b, ulint n) {
  ut_ad(b);

  if (n < 0x80) {
    /* 0nnnnnnn (7 bits) */
    mach_write_to_1(b, n);
    return (1);
  } else if (n < 0x4000) {
    /* 10nnnnnn nnnnnnnn (14 bits) */
    mach_write_to_2(b, n | 0x8000);
    return (2);
  } else if (n < 0x200000) {
    /* 110nnnnn nnnnnnnn nnnnnnnn (21 bits) */
    mach_write_to_3(b, n | 0xC00000);
    return (3);
  } else if (n < 0x10000000) {
    /* 1110nnnn nnnnnnnn nnnnnnnn nnnnnnnn (28 bits) */
    mach_write_to_4(b, n | 0xE0000000);
    return (4);
  } else {
    /* 11110000 nnnnnnnn nnnnnnnn nnnnnnnn nnnnnnnn (32 bits) */
    mach_write_to_1(b, 0xF0);
    mach_write_to_4(b + 1, n);
    return (5);
  }
}
//解析日誌通用部分,也就是解析出日誌類型,space id,頁面號,並且返回body部分
//該函數用於崩潰恢復,返回NULL說明日誌不完全
byte *mlog_parse_initial_log_record(
    const byte *ptr,     /*!< in: buffer */
    const byte *end_ptr, /*!< in: buffer end */
    mlog_id_t *type,     /*!< out: log record type: MLOG_1BYTE, ... */
    space_id_t *space,   /*!< out: space id */
    page_no_t *page_no)  /*!< out: page number */
{
  if (end_ptr < ptr + 1) {
    return (NULL);
  }
  //MLOG_SINGLE_REC_FLAG是mtr單日誌記錄的標誌,如果是多日誌記錄,那麼還需要額外記錄一條redo日誌
  //,說明該mtr結束了。因此,將最高位去掉,就是type
  *type = (mlog_id_t)((ulint)*ptr & ~MLOG_SINGLE_REC_FLAG);
  ut_ad(*type <= MLOG_BIGGEST_TYPE);
    
  ptr++;
  //還需要至少兩字節,不然是不完整的
  if (end_ptr < ptr + 2) {
    return (NULL);
  }
  //解壓,與壓縮原理一樣
  *space = mach_parse_compressed(&ptr, end_ptr);
  //page 號
  if (ptr != NULL) {
    *page_no = mach_parse_compressed(&ptr, end_ptr);
  }
  //返回body
  return (const_cast<byte *>(ptr));
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章