精品人妻码一区二区三区_无码人妻久久一区二区三区免费丨_久久见久久久国产精品蜜桃_人嘼皇bestialitysex欧美





技術人生系列——MySQL:8.0中關于file_system的重大改進和8.0.23存在的問題

日期:2022-07-25


最近一(yi)(yi)個和file_system有關的(de)問題,因此將這部(bu)分(fen)數據結(jie)構和重要(yao)的(de)函數簡單看了一(yi)(yi)下(xia),好在數據結(jie)構不(bu)(bu)多,成員變(bian)量也不(bu)(bu)多。但是這部(bu)分(fen)的(de)知識和IO子(zi)系(xi)統(tong)(tong)聯系(xi)太(tai)緊(jin)密了,因為(wei)IO子(zi)系(xi)統(tong)(tong)不(bu)(bu)熟,所(suo)以難免有錯誤(wu)。但是也為(wei)學習IO子(zi)系(xi)統(tong)(tong)做了一(yi)(yi)層(ceng)鋪墊。并(bing)且不(bu)(bu)管(guan)錯誤(wu)與(yu)否必須要(yao)記錄一(yi)(yi)下(xia)否則很容易(yi)忘(wang)記,現記錄如下(xia)(包含代碼(ma),文章稍顯(xian)混(hun)亂),代碼(ma)來自8.0.23。

僅供參考。


一、前言

在我們(men)數據庫啟動(dong)的(de)(de)時候,實際(ji)上(shang)很多(duo)表都是(shi)沒有(you)打(da)開(kai)的(de)(de),當然除了(le)(le)一(yi)(yi)(yi)些redo/undo等系統空間會(hui)(hui)常駐打(da)開(kai),其(qi)他(ta)的(de)(de)用戶的(de)(de)innodb表示沒有(you)打(da)開(kai),當遇(yu)到真(zhen)正的(de)(de)IO操作后(hou)才(cai)會(hui)(hui)打(da)開(kai)文(wen)(wen)件(jian)(jian),這(zhe)些文(wen)(wen)件(jian)(jian)會(hui)(hui)存在于file_system中(zhong)(zhong),主要包含的(de)(de)就是(shi)fil_space_t結(jie)構(gou)(gou),一(yi)(yi)(yi)個(ge)(ge)fil_space_t對(dui)于單表或者(zhe)分(fen)(fen)(fen)區表的(de)(de)一(yi)(yi)(yi)個(ge)(ge)分(fen)(fen)(fen)區來講就對(dui)應(ying)一(yi)(yi)(yi)個(ge)(ge)fil_node_t,但是(shi)對(dui)于redo或者(zhe)undo這(zhe)些來講一(yi)(yi)(yi)個(ge)(ge)fil_space_t對(dui)應(ying)了(le)(le)多(duo)個(ge)(ge)file_node_t,因(yin)為有(you)多(duo)個(ge)(ge)相關文(wen)(wen)件(jian)(jian),真(zhen)正的(de)(de)io handler存儲在fil_node_t上(shang)。在5.7中(zhong)(zhong)打(da)開(kai)的(de)(de)文(wen)(wen)件(jian)(jian)都整(zheng)體(ti)存在于一(yi)(yi)(yi)個(ge)(ge)file_system下(xia),但是(shi)最近遇(yu)到了(le)(le)一(yi)(yi)(yi)個(ge)(ge)問題(ti),稍微看了(le)(le)下(xia)8.0發現做了(le)(le)拆分(fen)(fen)(fen),將一(yi)(yi)(yi)個(ge)(ge)file_system查分(fen)(fen)(fen)為 69個(ge)(ge)(8.0.19是(shi)65個(ge)(ge))這(zhe)個(ge)(ge)是(shi)個(ge)(ge)硬編碼。這(zhe)樣如果我們(men)需要打(da)開(kai)文(wen)(wen)件(jian)(jian)或者(zhe)關閉文(wen)(wen)件(jian)(jian)那么拆分(fen)(fen)(fen)后(hou)鎖的(de)(de)代(dai)價就更小了(le)(le),其(qi)中(zhong)(zhong)每(mei)一(yi)(yi)(yi)個(ge)(ge)拆分(fen)(fen)(fen)出來的(de)(de)結(jie)構(gou)(gou)叫(jiao)做shard(內部(bu)結(jie)構(gou)(gou)叫(jiao)做Fil_shard)。

二、總體示意圖

注意這(zhe)里我(wo)們只(zhi)討論一(yi)個(ge)fil_space_t對(dui)應一(yi)個(ge)fil_node_t的(de)(de)情況,也(ye)就是普(pu)通表(分(fen)區(qu)表的(de)(de)分(fen)區(qu)),這(zhe)往往也(ye)是和用戶關(guan)系較大的(de)(de)。

三、file_system(Fil_system)的重點變量

圖中包(bao)含另一些重點的(de)數(shu)據結構,其中 file_system中包(bao)含:

  • m_shards:這是一個vecoter數組,包含了69個shard。

  • m_max_n_open:這個是我們的參數Innodb_open_files設置的值。

  • m_max_assigned_id:是我們當前分配的最大的space_id。

四、shard的重點變量

  • m_id:當前shard的序號,從0開始

  • m_spaces:一個std map結構,在數據庫初始化的時候就建立好了,其主要是space_id和fil_space_t做的一個map結構

  • m_names:一個std map結構,在數據庫初始化的時候就建立好了,其主要是space_name和fil_space_t做的一個map結構

m_spaces和m_names變(bian)量的初始(shi)化可以查看函數Fil_shard::space_add,如下:

void Fil_shard::space_add(fil_space_t *space) {  ut_ad(mutex_owned());  {    auto it = m_spaces.insert(Spaces::value_type(space->id, space));    ut_a(it.second);  }  {    auto name = space->name;    auto it = m_names.insert(Names::value_type(name, space));    ut_a(it.second);  }}

我們通(tong)常在進行物理IO的時候(hou)需要打開(kai)文件,這個時候(hou)拿到的一般(ban)為page的space_id,這樣(yang)通(tong)過Fil_shard::get_space_by_id就快速(su)拿了(le)fil_space_t的結構,而不(bu)用去遍歷鏈表。

但是(shi)(shi)(shi)(shi)需要(yao)(yao)注意(yi)的(de)(de)(de)(de)一點(dian)是(shi)(shi)(shi)(shi),我們(men)首先(xian)還需要(yao)(yao)判定(ding)是(shi)(shi)(shi)(shi)的(de)(de)(de)(de)這個(ge)(ge)space_id到底到哪個(ge)(ge)shard上(shang)建立(li)或者到哪個(ge)(ge)shard上(shang)查找,是(shi)(shi)(shi)(shi)需要(yao)(yao)定(ding)位(wei)到相關的(de)(de)(de)(de)shard上(shang)的(de)(de)(de)(de),這個(ge)(ge)是(shi)(shi)(shi)(shi)通過space_id取余來(lai)做到的(de)(de)(de)(de),函(han)數 Fil_system::shard_by_id(FIL_system 就(jiu)是(shi)(shi)(shi)(shi)我們(men)的(de)(de)(de)(de)file_system的(de)(de)(de)(de)數據結構)函(han)數完成這個(ge)(ge)功能,計算(suan)取余如(ru)下(xia):

  Fil_shard *shard_by_id(space_id_t space_id) const      MY_ATTRIBUTE((warn_unused_result)) {#ifndef UNIV_HOTBACKUP    if (space_id == dict_sys_t::s_log_space_first_id) {      return m_shards[REDO_SHARD];    } else if (fsp_is_undo_tablespace(space_id)) {      const size_t limit = space_id % UNDO_SHARDS;      return m_shards[UNDO_SHARDS_START + limit];    }    ut_ad(m_shards.size() == MAX_SHARDS);     return m_shards[space_id % UNDO_SHARDS_START]; //取余,將各個space分布到不同的shard上#else  /* !UNIV_HOTBACKUP */    ut_ad(m_shards.size() == 1);    return m_shards[0];#endif /* !UNIV_HOTBACKUP */  }

因(yin)為我(wo)們的(de)undo,redo會獨占末尾的(de)幾個(ge)shard,因(yin)此這(zhe)里用了(le)(le)宏來減(jian)去(qu)了(le)(le)這(zhe)部分然后取(qu)余(yu),相關宏定義如下(xia)。

/** Maximum number of shards supported. */static const size_t MAX_SHARDS = 69; //69個shard/** The redo log is in its own shard. */static const size_t REDO_SHARD = MAX_SHARDS - 1; //末尾第1個為redo的shard/** Number of undo shards to reserve. */static const size_t UNDO_SHARDS = 4;//倒數第2到第5為undo的shard/** The UNDO logs have their own shards (4). */static const size_t UNDO_SHARDS_START = REDO_SHARD - UNDO_SHARDS;#else  /* !UNIV_HOTBACKUP */
  • m_LRU:這個玩意是一個最重要的數據結構了,如果一個文件剛剛打開或者io complete讀操作就會將其以頭插法加入到這個鏈表,這就形成了一個LRU鏈表,如果超過參數Innodb_open_files的設置就會在這里面進行尾部淘汰。打開文件函數如下:

Fil_shard::prepare_file_for_io 調入為物理IO準備好文件:void Fil_shard::file_opened(fil_node_t *file) {   ut_ad(m_id == REDO_SHARD || mutex_owned());  if (Fil_system::space_belongs_in_LRU(file->space)) {    /* Put the file to the LRU list */    UT_LIST_ADD_FIRST(m_LRU, file); //頭插法  }  ++s_n_open;  file->is_open = true;  fil_n_file_opened = s_n_open;}

IO COMPLETE如下:

void Fil_shard::complete_io(fil_node_t *file, const IORequest &type) {  ut_ad(m_id == REDO_SHARD || mutex_owned());  ut_a(file->n_pending > 0);  --file->n_pending;  ut_ad(type.validate());  if (type.is_write()) { //如果是寫操作    ut_ad(!srv_read_only_mode || fsp_is_system_temporary(file->space->id));    write_completed(file); //需要加入flush  而不是 LRU 鏈表  }  if (file->n_pending == 0 && Fil_system::space_belongs_in_LRU(file->space)) { //是否為 tablespace    /* The file must be put back to the LRU list */    UT_LIST_ADD_FIRST(m_LRU, file); //如果是讀操作直接加入 LRU鏈表  }}

當調用Fil_shard::close_file關閉(bi)文件時候會從LRU的末尾去(qu)掉,見(jian)后文分(fen)析。這個(ge)結(jie)構(gou)就是我們最為熟悉(xi)的file system(下shard)的LRU鏈表,當然如果數據庫(ku)當時打開了(le)很多文件超過了(le)參數Innodb_open_files的設置(zhi) ,并且做了(le)大(da)量的IO操作,那(nei)么這個(ge)LRU鏈表可能(neng)找不到相應的能(neng)夠關閉(bi)的文件。

  • m_unflushed_spaces:如其名,主要是進行寫操作的IO可能涉及到需要進行flush data file,因此都放在這個鏈表里面。加入調用也是Fil_shard::write_completed ,但是需要判定是否文件打開用的SRV_UNIX_O_DIRECT_NO_FSYNC,當然一般都不是的,如下:

Fil_shard::write_completed     ->add_to_unflushed_list(file->space); //寫入完成,還沒有flush          UT_LIST_ADD_FIRST(m_unflushed_spaces, space);//頭插法

去掉時機:

Fil_shard::space_flush   ->remove_from_unflushed_list(space)      UT_LIST_REMOVE(m_unflushed_spaces, space);//尾部去除

看起來(lai)就(jiu)是space進行(xing)flush刷(shua)盤(pan)過后(hou)。那(nei)么需(xu)要(yao)注意(yi)的(de)打開的(de)文(wen)件(jian)并(bing)不一(yi)定在(zai)m_unflushed_spaces或者m_LRU,如果正(zheng)在(zai)進行(xing)讀IO可能兩個(ge)鏈表中都沒有這個(ge)打開的(de)文(wen)件(jian),但是問題不大,因為本來(lai)就(jiu)不能淘汰。

  • static原子變量s_n_open:顯然這個屬性不是某個shard特有的,是全部shard一起持有的,那么它代表的實際上就是當前打開的innodb文件總數,使用原子變量避免加鎖,這樣在比較是否超過最大打開數的時候就可以通過file_system的m_max_n_open(也就是參數Innodb_open_files)和其比較即可。

  • static原子變量s_open_slot:顯然這個屬性不是某個shard特有的,是全部shard一起持有的,它用處是保護(The number of open file descriptors is a shard resource),使用一個原子變量的比較/交換操作compare_exchange_weak并且附加while循環,來保證共享資源file descriptors ,這是無鎖化編程一種方式。

四、關于文件的關閉

如(ru)果(guo)文(wen)(wen)件(jian)沒有保存在file_system中,進行物(wu)理IO的(de)(de)(de)(de)時候需要(yao)打(da)開(kai)(kai)它(ta)(Fil_shard::do_io),也(ye)就(jiu)是Fil_shard::prepare_file_for_io調(diao)用準備打(da)開(kai)(kai)文(wen)(wen)件(jian)之前(qian),需要(yao)當前(qian)打(da)開(kai)(kai)的(de)(de)(de)(de)innodb文(wen)(wen)件(jian)數(shu)量(liang)是否(fou)大于(yu)了參數(shu)Innodb_open_files的(de)(de)(de)(de)設(she)置(zhi),如(ru)果(guo)大于(yu)了那(nei)么就(jiu)需要(yao)做淘汰文(wen)(wen)件(jian)出來,代碼在Fil_shard::mutex_acquire_and_get_space中,當然Fil_shard::mutex_acquire_and_get_space的(de)(de)(de)(de)調(diao)用在Fil_shard::prepare_file_for_io調(diao)用之前(qian),且都在Fil_shard::do_io下(xia)面。這里有一(yi)個(ge)重點,就(jiu)是參數(shu)Innodb_open_files設(she)置(zhi)是總(zong)的(de)(de)(de)(de)大小,因此不管從哪個(ge)shard中淘汰一(yi)個(ge),那(nei)么這個(ge)文(wen)(wen)件(jian)就(jiu)能打(da)開(kai)(kai),而不是一(yi)定要(yao)在本space所在的(de)(de)(de)(de)shard中關(guan)閉(bi),比如(ru)我(wo)們在shard 4中關(guan)閉(bi)了一(yi)個(ge)文(wen)(wen)件(jian),我(wo)需要(yao)打(da)開(kai)(kai)的(de)(de)(de)(de)文(wen)(wen)件(jian)映射到了shard 10,那(nei)么打(da)開(kai)(kai)文(wen)(wen)件(jian)總(zong)是還是相等的(de)(de)(de)(de),沒有問題。這也(ye)是我(wo)開(kai)(kai)始疑惑的(de)(de)(de)(de)地方。來看看主要(yao)流程,也(ye)是很(hen)簡單:

Fil_shard::mutex_acquire_and_get_space  ->Fil_system::close_file_in_all_LRU(循環每個shard)    ->Fil_shard::close_files_in_LRU(判斷LRU上是否有可以close文件)      ->Fil_shard::close_file(關閉文件)Fil_shard::mutex_acquire_and_get_space //mutex只是本shard的mutex本函數有1個嵌套循環for (size_t i = 0; i < 3; ++i){ //嘗試清理3次,每次都必須清理出一個文件(壓力過大剛清理又滿了?) while (fil_system->m_max_n_open <= s_n_open && //如果s_n_open static變量大于了fil_system設置m_max_n_open(也就是參數Innodb_open_files設置的大小)           !fil_system->close_file_in_all_LRU(i > 1)) {  //根據LRU 關閉 打開的文件如果清理嘗試來到第2次開始輸出note級別的日志,如果清理失敗可能繼續      if (ut_time_monotonic() - start_time >= PRINT_INTERVAL_SECS) { //如果本次清理時間大于了PRINT_INTERVAL_SECS 設置就報警        start_time = ut_time_monotonic();        ib::warn(ER_IB_MSG_279) << "Trying to close a file for "                                << start_time - begin_time << " seconds"                                << ". Configuration only allows for "                                << fil_system->m_max_n_open << " open files.";      }    }Fil_system::close_file_in_all_LRU函數bool Fil_system::close_file_in_all_LRU(bool print_info) {  for (auto shard : m_shards) {//m_shards 為一個 數組循環每個shard    shard->mutex_acquire();    if (print_info) {      ib::info(ER_IB_MSG_277, shard->id(),               ulonglong{UT_LIST_GET_LEN(shard->m_LRU)}); //如果是第2次嘗試會打印日志    }    bool success = shard->close_files_in_LRU(print_info);    shard->mutex_release();    if (success) { //如果成功關閉了一個文件success為true      return true; //返回成功    }  }  return false;//返回失敗}Fil_shard::close_files_in_LRU函數bool Fil_shard::close_files_in_LRU(bool print_info) {  for (auto file = UT_LIST_GET_LAST(m_LRU); file != nullptr;       file = UT_LIST_GET_PREV(LRU, file)) { //循環LRU鏈表,如果鏈表沒有元素即可返回    if (file->modification_counter == file->flush_counter &&        file->n_pending_flushes == 0 && file->in_use == 0) {//繼續額外的判斷,尚不清楚為什么。      close_file(file, true); //關閉1個文件,并且會從LRU中取下來      return true; //關閉一個則成功    }    if (!print_info) {//如果不需要打印日志,也就是是第1次嘗試清理,不需要打印日志      continue;    }...//關閉失敗的note日志省略  return false;//如果本shard沒有可以關閉的則返回flase

這(zhe)里(li)的(de)(de)(de)流程如果出(chu)現(xian)文件(jian)較多,并且同時(shi)打開進行IO文件(jian)較多(顯(xian)著的(de)(de)(de)就是包含大量(liang)分區的(de)(de)(de)分區表)的(de)(de)(de)情(qing)況超過了參數Innodb_open_files的(de)(de)(de)大小情(qing)況,可能出(chu)現(xian)日志(zhi):

圖片

也就是(shi)(shi)ER_IB_MSG_277的note日志輸出,第一個(ge)(ge)為shard的id,第二個(ge)(ge)0代表(biao)是(shi)(shi)LRU元素(su)的個(ge)(ge)數,但(dan)(dan)是(shi)(shi)從(cong)上(shang)面的邏輯來(lai)看(kan),雖(sui)然循(xun)環(huan)次數比較多,但(dan)(dan)是(shi)(shi)每次循(xun)環(huan)的元素(su)很少或者(zhe)(zhe)為0個(ge)(ge)元素(su),因此代價也就不(bu)那么高了。另外從(cong)這個(ge)(ge)算(suan)法(fa)來(lai)看(kan)因為是(shi)(shi)從(cong)頭(tou)遍歷shard 1-69 個(ge)(ge)shard,如(ru)果要(yao)淘汰打(da)(da)開的文件,理論上(shang)前(qian)面的shard相關的fil_space_t(可簡(jian)單理解為表(biao)或者(zhe)(zhe)分(fen)區)更(geng)容易(yi)淘汰和關閉掉(diao)。此處代碼來(lai)自8.0.23,不(bu)知道過后是(shi)(shi)否(fou)會改進(jin)(隨機算(suan)法(fa)取shard是(shi)(shi)不(bu)是(shi)(shi)更(geng)好?),測試情(qing)況下我設置參數Innodb_open_files為400,建立了2000個(ge)(ge)表(biao),全部打(da)(da)開后,發現前(qian)面很多shard的m_LRU為空如(ru)下:

(gdb) p ((Fil_shard*)(0x7fffe0044c90))->m_LRU$15 = {count = 0, start = 0x0, end = 0x0, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02e0f90))->m_LRU$16 = {count = 0, start = 0x0, end = 0x0, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02ea480))->m_LRU$17 = {count = 17, start = 0x7fffe3267240, end = 0x7fffe2a9f1f0, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02e19d0))->m_LRU$18 = {count = 0, start = 0x0, end = 0x0, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02e1f30))->m_LRU$19 = {count = 0, start = 0x0, end = 0x0, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02e49c0))->m_LRU$20 = {count = 0, start = 0x0, end = 0x0, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02e6ec0))->m_LRU$21 = {count = 0, start = 0x0, end = 0x0, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02e7170))->m_LRU$22 = {count = 0, start = 0x0, end = 0x0, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02e5480))->m_LRU$23 = {count = 0, start = 0x0, end = 0x0, node = &fil_node_t::LRU, init = 51966}//前面好多shard的m_LRU長度都是0//到這里才開m_LRU有值(gdb) p ((Fil_shard*)(0x7fffe02e7ee0))->m_LRU$24 = {count = 1, start = 0x7fffe3279530, end = 0x7fffe3279530, node = &fil_node_t::LRU, init = 51966}$25 = {count = 18, start = 0x7fffe327b290, end = 0x7fffe2a9c670, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02e8190))->m_LRU$26 = {count = 17, start = 0x7fffe3279ae0, end = 0x7fffe30974d0, node = &fil_node_t::LRU, init = 51966}

我大(da)概數了一下,就是后面20來個(ge)shard才有值,差不多一個(ge)有17 18個(ge)表,這(zhe)樣算起來差不多是參數Innodb_open_files設置的400大(da)小。這(zhe)樣分(fen)(fen)布不均勻直(zhi)接導致(zhi)的問題就是拆分(fen)(fen)效(xiao)果大(da)打折扣。

隨后查看8.0.28的(de)代碼似乎進行(xing)更改,具(ju)體(ti)的(de)提交就不去查了,看來(lai)官方是(shi)發現了這個問題:

bool Fil_system::close_file_in_all_LRU() {  const auto n_shards = m_shards.size();  const auto index = m_next_shard_to_close_from_LRU++;//原子變量  for (size_t i = 0; i < n_shards; ++i) {    auto shard = m_shards[(index + i) % n_shards]; //跳躍性查找,不在數循序的    if (shard->id() == REDO_SHARD) {      /* Redo shard don't ever have any spaces on LRU. It is not guarded by a      mutex so we can't continue the execution of the for block. */      continue;    }    shard->mutex_acquire();    bool success = shard->close_files_in_LRU();    shard->mutex_release();    if (success) {      return true;    }  }  return false;}

五、最后

最后我們來看看如(ru)果debug這(zhe)些(xie)元素其實很(hen)簡單,因為file_system是(shi)一個全(quan)局變量,直接(jie)就(jiu)能(neng)拿(na)到比如(ru),我想查(cha)看這(zhe)69個shard如(ru)下:

(gdb) p fil_system->m_shards$2 = std::vector of length 69, capacity 128 = {0x7fffe0044c90, 0x7fffe02e0f90, 0x7fffe02e1120, 0x7fffe02e13d0, 0x7fffe02e1680, 0x7fffe02e19d0, 0x7fffe02e1c80, 0x7fffe02e1f30,   0x7fffe02e21e0, 0x7fffe02e25b0, 0x7fffe02e2860, 0x7fffe02e2b10, 0x7fffe02e2dc0, 0x7fffe02e3070, 0x7fffe02e3320, 0x7fffe02e35d0, 0x7fffe02e3880, 0x7fffe02e3cd0, 0x7fffe02e3f00,   0x7fffe02e41b0, 0x7fffe02e4460, 0x7fffe02e4710, 0x7fffe02e49c0, 0x7fffe02e4c70, 0x7fffe02e4f20, 0x7fffe02e51d0, 0x7fffe02e5480, 0x7fffe02e5730, 0x7fffe02e59e0, 0x7fffe02e5c90,   0x7fffe02e5f40, 0x7fffe02e61f0, 0x7fffe02e64a0, 0x7fffe02e3b30, 0x7fffe02e6c10, 0x7fffe02e6ec0, 0x7fffe02e7170, 0x7fffe02e7420, 0x7fffe02e76d0, 0x7fffe02e7980, 0x7fffe02e7c30,   0x7fffe02e7ee0, 0x7fffe02e8190, 0x7fffe02e8440, 0x7fffe02e86f0, 0x7fffe02e89a0, 0x7fffe02e8c50, 0x7fffe02e8f00, 0x7fffe02e91b0, 0x7fffe02e9460, 0x7fffe02e9710, 0x7fffe02e99c0,   0x7fffe02e9c70, 0x7fffe02e9f20, 0x7fffe02ea1d0, 0x7fffe02ea480, 0x7fffe02ea730, 0x7fffe02ea9e0, 0x7fffe02eac90, 0x7fffe02eaf40, 0x7fffe02eb1f0, 0x7fffe02eb4a0, 0x7fffe02eb750,   0x7fffe02eba00, 0x7fffe02ebcb0, 0x7fffe02e6750, 0x7fffe02ec700, 0x7fffe02ec910, 0x7fffe02ecbc0}(gdb)

如果我(wo)想看每個shard里面(mian)包含哪些(xie)表的fil_space_t如下(xia)即可:

(gdb) p ((Fil_shard*)(0x7fffe0044c90))->m_names$6 = std::unordered_map with 18 elements = {[0x7fffe32513c0 "t10/t883"] = 0x7fffe32511e0, [0x7fffe323a2d0 "t10/t819"] = 0x7fffe323a0f0, [0x7fffe3223630 "t10/t755"] = 0x7fffe3223450,   [0x7fffe320cc60 "t10/t691"] = 0x7fffe320ca80, [0x7fffe31c51b0 "t10/t499"] = 0x7fffe31c4fd0, [0x7fffe309e2c0 "testpri/t1"] = 0x7fffe309e0e0, [0x7fffe31954b0 "t10/t371"] = 0x7fffe31952d0,   [0x7fffe308c620 "t10/ERPDB_TEST"] = 0x7fffe308c440, [0x7fffe31dcca0 "t10/t563"] = 0x7fffe31dcac0, [0x7fffe3104ee0 "t10/t115"] = 0x7fffe3121620,   [0x7fffe043eb40 "innodb_system"] = 0x7fffe0437280, [0x7fffe31511c0 "t10/t243"] = 0x7fffe3150fe0, [0x7fffe317e750 "t10/t307"] = 0x7fffe317e570,   [0x7fffe326a450 "t10/t947"] = 0x7fffe326a270, [0x7fffe31f4c10 "t10/t627"] = 0x7fffe31f4a30, [0x7fffe2b7bee0 "t10/t51"] = 0x7fffe310b9e0, [0x7fffe3139a90 "t10/t179"] = 0x7fffe31398b0,   [0x7fffe31adc40 "t10/t435"] = 0x7fffe31ada60}(這里就是names和fil_space_t的map映射,當然fil_space_t是指針類型)(gdb) p ((Fil_shard*)(0x7fffe0044c90))->m_id$7 = 0(這里是share id 我取的第1個元素 1 id就是0)

也可(ke)以查看shard的(de)其他元素,當然可(ke)以繼(ji)續debug各個fil_space_t,fil_node_t 數(shu)據結構的(de)數(shu)據。

另外除了8.0.28代碼看到的(de)問題修復,還有2個(ge)和(he)這部分相關的(de)BUG供參考(kao)如下,當然這幾個(ge)BUG沒仔細(xi)看,在新版(8.0.27)都(dou)修復了:

  • InnoDB: “Too many open files” errors were encountered when creating a large number of tables. (Bug #32634620)

  • InnoDB: An excessive number of notes were written to the error log when the innodb_open_files limit was temporarily exceeded. (Bug #33343690)

其實說了這么(me)多和(he)貌似(si)和(he)我們運維相關(guan)的只有1個variable和(he)1個status如下,略顯尷尬:

  • variable Innodb_open_files:innodb能夠打開的最大文件,自適應算法可參考官方文檔,體現在Fil_system::m_max_n_open上。

  • status Innodb_num_open_files:顯然這個就是Innodb當前打開的文件數量,和static原子變量shard::s_n_open是一個值( fil_n_file_opened = s_n_open;)。

 
 
 

   文章來源于MySQL學習,作者高(gao)鵬(八(ba)怪)

《深入理解(jie)MySQL主(zhu)從原理》作者

中(zhong)亦科(ke)技(ji)數(shu)據庫團(tuan)隊MySQL二線工程師 

十余年數據庫運維經驗\擅長故障(zhang)診(zhen)斷,性(xing)能(neng)調(diao)優


鍛造凝煉IT服務 助推用戶事業發展
地址:北京市西城區百萬莊大街11號糧科大廈3層
電話:(010)58523737
傳真:(010)58523739