中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

MYSQL INNODB中hash查找表的實現

發布時間:2020-08-11 09:25:42 來源:ITPUB博客 閱讀:226 作者:gaopengtttt 欄目:MySQL數據庫
原創有誤請指出:

版本:5.7.14
源碼位置為hash0hash.h hash0hash.cc
作為一種時間復雜度最優為O(1)的數據結構,但是最壞時間復雜對位O(n)的一種數據結構,但是在
良好的設計hash函數的情況下性能還是非常好的。關于hash表的圖在最后給出。在innodb中各種數據
結構都使用hash表查找比如LOCK_T結構,還有我們特別熟悉的自適應hash索引等等,下面我們進行一些
探討。
一、innodb hash函數
首先我們不得不研究一下innodb的hash函數,hash函數的設計至少有2個要求
1、計算簡單,否則如果計算花費了太多時間你的hash查找表也是不成功的
2、計算能夠盡可能的分散值
那么innodb是如何設計這個hash函數的呢?很簡單如下:

點擊(此處)折疊或打開

  1. ulint
  2. ut_hash_ulint(
  3. /*==========*/
  4. ulint    key,    /*!< in: value to be hashed */
  5. ulint    table_size)    /*!< in: hash table size */
  6. {
  7. ut_ad(table_size);
  8. key = key ^ UT_HASH_RANDOM_MASK2;
  9. return(key % table_size);
  10. }
上層調用為

點擊(此處)折疊或打開

  1. ulint
  2. hash_calc_hash(
  3. /*===========*/
  4. ulint    fold,    /*!< in: folded value */
  5. hash_table_t*    table)    /*!< in: hash table */
  6. {
  7. ut_ad(table);
  8. ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
  9. return(ut_hash_ulint(fold, table->n_cells));
  10. }
可以看到這里實際上和你的鍵值和你hash的cells(桶數量),我們看到這里做了一個異或操作然后和
cells(桶數量)進行取模操作,非常簡單實用。
二、處理沖突
hash表避免不了沖突,而數據庫中往往也利用這一點,將多個鏈表合并起來,innodb當然也就采用了
鏈表的方式來處理沖突。那么言外之意每一個數據結構中必須包含一個如普通鏈表中 data_struct* next
的指針,當然這里也可以用void*泛型指針,我們來看看lock_t結構體中:
hash_node_t hash; /*!< hash chain node for a record lock */
確實如此。這也是單項鏈表實現的基礎。
三、HASH表頭
一個hash表當然需要一個hash表頭這個表頭指向了具體的cell 數組(內存相似但在heap空間不再棧上),
innodb中如下,我去掉了一些用處不大的:

點擊(此處)折疊或打開

  1. struct hash_table_t {
  2. enum hash_table_sync_t    type;    /*<! type of hash_table. */
  3. ulint    n_cells;/* number of cells in the hash table */
  4. hash_cell_t*    array;    /*!< pointer to cell array */
  5. mem_heap_t*    heap;
  6. };
可以看到hash_cell_t* array;就是這樣一個元素,他實際上就是hash_cell_t就是
一個元素void*。

點擊(此處)折疊或打開

  1. typedef struct hash_cell_struct{
  2. void*    node;    /*!< hash chain node, NULL if none */
  3. } hash_cell_t;
那么通過這個元素他能夠指向具體的hash表了。那么user_str(用戶自己的結構體)->array->node就指向了一個
具體cell的地址了,后面的只是地址指針++就可以了。那么我們user_str也至少包含這樣一個
hash_table_t*的指針來指向整個hash表,確實如此在innodb lock_sys_t中包含了
hash_table_t* rec_hash
那么我們可以lock_sys_t和lock_t為列子畫一張展示圖如下:
MYSQL INNODB中hash查找表的實現
四、hash表的建立
這里主要涉及到cell的計算,計算函數為ut_find_prime,這里不用太多解釋

點擊(此處)折疊或打開

  1. hash_create(
  2. /*========*/
  3. ulint    n)    /*!< in: number of array cells */
  4. {
  5. hash_cell_t*    array;
  6. ulint    prime;
  7. hash_table_t*    table;


  8. prime = ut_find_prime(n);//計算cell桶的數量


  9. table = static_cast<hash_table_t*>(mem_alloc(sizeof(hash_table_t)));//為hash表頭分配內存


  10. array = static_cast<hash_cell_t*>(
  11. ut_malloc(sizeof(hash_cell_t) * prime));//為hash表分配內存


  12. /* The default type of hash_table is HASH_TABLE_SYNC_NONE i.e.:
  13. the caller is responsible for access control to the table. */
  14. table->type = HASH_TABLE_SYNC_NONE;
  15. table->array = array;//hash表頭指向hash表
  16. table->n_cells = prime;//設置
  17. table->heap = NULL;
  18. ut_d(table->magic_n = HASH_TABLE_MAGIC_N);

  19. /* Initialize the cell array */
  20. hash_table_clear(table); //memset 0x00整個hash表

  21. return(table);
  22. }

注意:下面都是通過LOCK部分hash表的實現來注釋的,其他其實也是一樣的。
五、插入一個元素
這部分是通過宏定義來做的如下,我寫了詳細的解釋

點擊(此處)折疊或打開

  1. /*******************************************************************//**
  2. Inserts a struct to a hash table. */
  3. /*
  4. HASH_INSERT(lock_t, hash, lock_sys->rec_hash,lock_rec_fold(space, page_no), lock);


  5. TYPE=lock_t:代表數據類型
  6. NAME=hash:代表lock_t下面有一個hash元素指針,其實這個指針和我們平時用的鏈表的struct* NEXT沒什么區別
  7.           唯一區別就是他是void*
  8.           (hash_node_t    hash;
  9.           typedef void* hash_node_t;)
  10. TABLE=lock_sys->rec_hash:代表hash表的地址指針,輸入參數
  11.        (hash_table_t*    rec_hash;)
  12. FOLD=lock_rec_fold(space, page_no):函數lock_rec_fold通過表空間和頁號得到一個unsigned long數字
  13. DATA=lock:這實際上就是你的數據的指針,當然這里就是lock_t* 輸入參數
  14. */


  15. #define HASH_INSERT(TYPE, NAME, TABLE, FOLD, DATA)\
  16. do {\
  17. hash_cell_t*    cell3333;\//實際上就是void*
  18. TYPE*    struct3333;\ //lock_t* struct3333;
  19. \
  20. HASH_ASSERT_OWN(TABLE, FOLD)\//斷言不考慮
  21. \
  22. (DATA)->NAME = NULL;\//lock->hash = NULL;
  23. \
  24. cell3333 = hash_get_nth_cell(TABLE, hash_calc_hash(FOLD, TABLE));\
  25. \
  26. if (cell3333->node == NULL) {\ //如果為NULL沒有元素掛載到這個cell下
  27. cell3333->node = DATA;\ //則我們掛載到這個cell下
  28. } else {\
  29. struct3333 = (TYPE*) cell3333->node;\ //否則說明有元素了取到這個元素的指針 lock_t* struct3333 = (lock_t*)cell3333->node;
  30. \
  31. while (struct3333->NAME != NULL) {\ //如果struct3333->hash 不等于NULL 說明他下面有元素了
  32. \
  33. struct3333 = (TYPE*) struct3333->NAME;\ //那么我們需要做的是指針像鏈表下一個元素移動
  34. }\
  35. \
  36. struct3333->NAME = DATA;\ //最后找到鏈表末尾 將數據節點掛載到下面 struct3333->hash = lock(lock是lock_t*)
  37. }\
  38. } while (0)
六、刪除一個元素
這部分也是通過宏定義來做的如下,我寫了詳細的解釋

點擊(此處)折疊或打開

  1. /*******************************************************************//**
  2. Deletes a struct from a hash table. */
  3. /*
  4. 有了上面基礎也就比較簡單了,這里直接在代碼進行注釋
  5. HASH_DELETE(lock_t, hash, lock_sys->rec_hash,lock_rec_fold(space, page_no), in_lock);
  6. */
  7. #define HASH_DELETE(TYPE, NAME, TABLE, FOLD, DATA)\
  8. do {\
  9. hash_cell_t*    cell3333;\//實際上就是void*
  10. TYPE*    struct3333;\ //lock_t* struct3333;
  11. \
  12. HASH_ASSERT_OWN(TABLE, FOLD)\//斷言不考慮
  13. \
  14. cell3333 = hash_get_nth_cell(TABLE, hash_calc_hash(FOLD, TABLE));\//通過函數hash_get_nth_cell計算這個值在哪個cell也就是hash 桶中
  15. \
  16. if (cell3333->node == DATA) {\ //地址比較,如果地址相同其地址必然相同
  17. HASH_ASSERT_VALID(DATA->NAME);\//斷言不考慮
  18. cell3333->node = DATA->NAME;\//如果找到 將指針移動到下一個元素 言外之意這里去掉了一個內存單元就是找到的那個
  19. } else {\
  20. struct3333 = (TYPE*) cell3333->node;\ //鏈表循環找
  21. \
  22. while (struct3333->NAME != DATA) {\
  23. \
  24. struct3333 = (TYPE*) struct3333->NAME;\
  25. ut_a(struct3333);\
  26. }\
  27. \
  28. struct3333->NAME = DATA->NAME;\ //最終找到 就做 鏈表去掉這個內存元素動作
  29. }\
  30. //最終這里涉及到一個問題就是釋放問題,但是注意雖然這個數據的指針在鏈表中去掉了,但是指針本身還在,可以拿到做free即可
  31. HASH_INVALIDATE(DATA, NAME);\ //debug版本使用不考慮
  32. } while (0)
七、其他
其他函數還包含:
HASH_SEARCH_ALL:宏實現在整個hash表中查找一個元素,相當于真個cell個鏈表查找
HASH_SEARCH:宏實現在有建值的情況下查找一個元素、言外之意cell(桶)確定了,相當于鏈表查找
hash_table_clear: 清空一個hash表
就不詳細解釋了,當然我只是對基本實現和常用的方法進行了描述,其他方面遇到再說吧。

作者微信:

MYSQL INNODB中hash查找表的實現
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

莎车县| 闽侯县| 宁阳县| 武汉市| 嘉峪关市| 昭苏县| 耿马| 荔波县| 安丘市| 静宁县| 英德市| 驻马店市| 长沙县| 辉南县| 房山区| 铜川市| 宁海县| 新闻| 平湖市| 共和县| 射阳县| 乐昌市| 安多县| 大同市| 望奎县| 遂平县| 台中县| 东丰县| 东台市| 鄢陵县| 漳浦县| 瑞金市| 贵溪市| 聊城市| 五河县| 霍山县| 塔河县| 乐亭县| 广东省| 肇东市| 专栏|