Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Split-ordered linked list: lock free hash table

4,655 views

Published on

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.100.7132&rep=rep1&type=pdf

Published in: Sports, Technology
  • Login to see the comments

Split-ordered linked list: lock free hash table

  1. 1. Split-ordered lists: lock-free extensible hash tables O.Shalev and N.Shavit. In Journal of the ACM, 53(3):379-405,NY,USA,2006, ACM Press
  2. 2. 概要 複数のスレッドから並列にアクセスしても構造が破壊されないハッシュテーブル ロックを用いず高いスケーラビリティを実現 テーブルの拡張にもロックを用いない
  3. 3. 既存研究 細粒度ロックハッシュテーブル DougLea 氏によるバケット単位でのロックによる並列ハッシュテーブル <ul><ul><li>Java6 では get を楽観的ロック ( 成功時非ロック ) にて行う改良版を java.util.ConcurrentHashMap としてサポート </li></ul></ul>広く実用されている並列ハッシュとして比較対象 リニアハッシュテーブル ハッシュサイズを変更した際の影響範囲を最小限に抑えるハッシュテーブル ハッシュテーブルアルゴリズムとしては比較的古いけれどこれから紹介するものの先祖
  4. 4. 細粒度ロックハッシュテーブル バケット単位でロックを行うハッシュマップ ロック対象バケットをハッシュで決定 リサイズは再帰的 (?) にロックを獲得しながら行う 0 1 2 3 4 5 6 7 鍵 鍵 鍵
  5. 5. 細粒度ロックハッシュテーブル バケット単位でロックを行うハッシュマップ ロック対象バケットをハッシュで決定 リサイズは再帰的 (?) にロックを獲得しながら行う 赤い鍵をロックした場合 0, 3, 6 番のバケットがロック 黄色い鍵をロックした場合 1, 4, 7 番のバケットがロック 青い鍵をロックした場合 2, 5 番のバケットがロック 0 1 2 3 4 5 6 7 鍵 鍵 鍵
  6. 6. 細粒度ロックハッシュテーブル 同一のロックを持つスレッドは一度に一つしか存在しない スレッドは同時に一つのロックしか持たないのでデッドロックもしない データ保持量に対してロック数を増やす実装もありうる 赤い鍵をロックした場合 0, 3, 6 番のバケットがロック 黄色い鍵をロックした場合 1, 4, 7 番のバケットがロック 青い鍵をロックした場合 2, 5 番のバケットがロック 0 1 2 3 4 5 6 7 鍵 鍵 鍵
  7. 7. リニアハッシュテーブル ハッシュのリサイズ時に移動するアイテムを最少に抑えるハッシュテーブル これ自身は特に並列性への配慮は無し 0 1 2 3 Hash(x) mod 4 == 0 Hash(x) mod 4 == 1 Hash(x) mod 4 == 2 Hash(x) mod 4 == 3
  8. 8. リニアハッシュテーブル 例 ) ハッシュをリサイズして 1 だけ拡大する Mod の係数を倍々で増やしていく 計算後の値が存在しないバケットを指すなら Mod を 1 減らして計算した値を採用する 0 1 2 3 Hash(x) mod 8 == 0 Hash(x) mod 4 == 1 Hash(x) mod 4 == 2 Hash(x) mod 4 == 3 4 追加
  9. 9. リニアハッシュテーブル 下の例では、新しく追加されたバケットに既存のバケットからアイテムを移動させた 0 1 2 3 Hash(x) mod 8 == 0 Hash(x) mod 8 == 1 or 5 Hash(x) mod 8 == 2 or 6 Hash(x) mod 8 == 3 or 7 4 Hash(x) mod 8 == 4
  10. 10. リニアハッシュテーブル 下の例では、新しく追加されたバケットに既存のバケットからアイテムを移動させた Mod 8 に変わる事によって移動する必要が生じたのは Mod 4 == 0 だったバケットのみ 0 1 2 3 Hash(x) mod 8 == 0 Hash(x) mod 8 == 1 or 5 Hash(x) mod 8 == 2 or 6 Hash(x) mod 8 == 3 or 7 4 Hash(x) mod 8 == 4 移動不要
  11. 11. Split-ordered Hashtable リニアハッシュの概念から拡張し、ハッシュサイズが変わっても一切のノード移動が無いよう工夫 「バケットの間をアイテムが移動するのではなく、アイテムの間をバケットが移動する」という文章が印象的
  12. 12. Split-ordered list すべてのアイテムを一つの線形リストに投入 線形リスト内は hash 値で昇順に並んでいる バケットの先頭を表す Sentinel ノードも同一の線形リストに投入 Sentinel ノードへのショートカットをテーブルとして保持 List は LockfreeList を使うため並列に操作しても壊れない 更に操作失敗時に iterator が先頭に飛ぶ欠点を最寄りの Sentinel ノードへ飛ぶように改善
  13. 13. 概念図 一本の線形リストにデータと Sentinel ノードが両方入る 水色がデータ、緑色がハッシュ値 リストの中身はハッシュに沿って昇順 Sentinel ノードはバケットの値をビット逆転した物を使う 説明のため hash 最大値は 1byte にします 0 1 2 3 00 80 40 c0 02 48 6d 7f 8a 74 00000010 ↓ 01000000 00000001 ↓ 10000000 00000011 ↓ 11000000
  14. 14. データの挿入 <ul><li>対象となるデータのハッシュ値を算出
  15. 15. ハッシュ値に対応するテーブルにアクセス
  16. 16. 図左の縦長のテーブル
  17. 17. テーブルにSentinelノードへのポインタが書いてあるため対応するノードへジャンプ
  18. 18. 図中の赤い線
  19. 19. Sentinelノードの指すポインタを手繰っていけばハッシュの昇順にデータが並んでいるため、対応する場所に挿入 </li></ul>0 1 2 3 00 80 40 c0 02 48 6d 7f 8a 74 69
  20. 20. データの挿入 <ul><li>対象となるデータのハッシュ値を算出
  21. 21. ハッシュ値に対応するテーブルにアクセス
  22. 22. 図左の縦長のテーブル
  23. 23. テーブルにSentinelノードへのポインタが書いてあるため対応するノードへジャンプ
  24. 24. 図中の赤い線
  25. 25. Sentinelノードの指すポインタを手繰っていけばハッシュの昇順にデータが並んでいるため、対応する場所に挿入 </li></ul>0 1 2 3 00 80 40 c0 02 48 6d 7f 8a 74 69
  26. 26. テーブルの拡張 Sentinel ノードの間に挟まるアイテムの数が一定数を超えた場合にテーブルを拡張する リニアハッシュと違い必ず倍々オーダー あらかじめテーブルはそれなりの広さが用意してあり、コピー無しで拡張可能 , そのためロック不要 それ以上の拡大は後述します 0 1 2 3 00 80 40 c0 02 48 6d 69 7f 8a 74 4 5 6 7
  27. 27. テーブルの拡張 0 1 2 3 00 80 40 c0 02 48 6d 69 7f 8a 74 4 5 6 7 <ul><li>テーブル拡張後は新規探索は新しいテーブル上で行う
  28. 28. テーブル上に無かったらその一個左の Sentinel ノードを探索 </li></ul><ul><ul><li>もしそこにも無かったら更にもう一個左 </li></ul><li>Sentinel ノードが挿入されているべき個所を見つけ次第、 Sentinel ノードを挿入する
  29. 29. 目的の場所を見つけたら挿入 </li></ul>
  30. 30. テーブルの拡張 0 1 2 3 00 80 40 c0 02 48 6d 69 7f 8a 74 4 5 6 7 62 無い! <ul><li>テーブル拡張後は新規探索は新しいテーブル上で行う
  31. 31. テーブル上に無かったらその一個左の Sentinel ノードを探索 </li></ul><ul><ul><li>もしそこにも無かったら更にもう一個左 </li></ul><li>Sentinel ノードが挿入されているべき個所を見つけ次第、 Sentinel ノードを挿入する
  32. 32. 目的の場所を見つけたら挿入 </li></ul>
  33. 33. テーブルの拡張 0 1 2 3 00 80 40 c0 02 48 6d 69 7f 8a 74 4 5 6 7 62 <ul><li>テーブル拡張後は新規探索は新しいテーブル上で行う
  34. 34. テーブル上に無かったらその一個左の Sentinel ノードを探索 </li></ul><ul><ul><li>もしそこにも無かったら更にもう一個左 </li></ul><li>Sentinel ノードが挿入されているべき個所を見つけ次第、 Sentinel ノードを挿入する
  35. 35. 目的の場所を見つけたら挿入 </li></ul>
  36. 36. テーブルの拡張 0 1 2 3 00 80 40 c0 02 48 6d 69 7f 8a 74 4 5 6 7 62 <ul><li>テーブル拡張後は新規探索は新しいテーブル上で行う
  37. 37. テーブル上に無かったらその一個左の Sentinel ノードを探索 </li></ul><ul><ul><li>もしそこにも無かったら更にもう一個左 </li></ul><li>Sentinel ノードが挿入されているべき個所を見つけ次第、 Sentinel ノードを挿入する
  38. 38. 目的の場所を見つけたら挿入 </li></ul>
  39. 39. テーブルの拡張 0 1 2 3 00 80 40 c0 02 48 6d 69 7f 8a 74 4 5 6 7 62 60 <ul><li>テーブル拡張後は新規探索は新しいテーブル上で行う
  40. 40. テーブル上に無かったらその一個左の Sentinel ノードを探索 </li></ul><ul><ul><li>もしそこにも無かったら更にもう一個左 </li></ul><li>Sentinel ノードが挿入されているべき個所を見つけ次第、 Sentinel ノードを挿入する
  41. 41. 目的の場所を見つけたら挿入 </li></ul>
  42. 42. テーブルの拡張 0 1 2 3 00 80 40 c0 02 48 6d 69 7f 8a 74 4 5 6 7 62 60 <ul><li>テーブル拡張後は新規探索は新しいテーブル上で行う
  43. 43. テーブル上に無かったらその一個左の Sentinel ノードを探索 </li></ul><ul><ul><li>もしそこにも無かったら更にもう一個左 </li></ul><li>Sentinel ノードが挿入されているべき個所を見つけ次第、 Sentinel ノードを挿入する
  44. 44. 目的の場所を見つけたら挿入 </li></ul>
  45. 45. なぜリサイズが Lockfree なのか 検索中のスレッドが他のスレッドに追い抜かれても処理が続行可能 新しいアイテムが挿入されようと Sentinel ノードが挟まろうと ハッシュテーブルが拡張されようと ハッシュ値が一つの線形リスト上で昇順に並んでいる事に変わりは無い 0 1 2 3 00 80 40 c0 02 48 6d 7f 8a 74
  46. 46. テーブルのリサイズの実装 もし確保しておいたテーブルサイズで足りなくなったら 必要なだけ新しい固定長配列を動的に確保してアサイン <ul><ul><li>左の静的配列は充分大きい </li></ul></ul>2 段階間接参照を行い Sentinel ノードを発見する 0 1 2 3 4 5 6 7 静的配列 動的配列 動的配列 動的配列 00 80 40 c0 02 48 6d 7f 8a 74 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 16 33 34 35 36 21 22 23 24 25 26 27 28 29 30 31 32 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 16
  47. 47. 性能評価 Java 実装の DougLea 式の並列 Hashmap を C++ に移植して比較 ロックは 64 固定(それ以上増やした場合でもパフォーマンスが改善しなかったため Split-ordered list も C++ で実装 計算機 30-processor Sun Enterprise 6000, a cache-coherent NUMA machine formed from 15 boards of two 300 MHz UltraSPARC® II processors and 2 GB of RAM on each. コンパイラ a Sun cc compiler 5.3, -xO5 and -xarch=v8plusa
  48. 48. DougLea 式ハッシュテーブル ロックを 64 以上増やしても性能が伸びなかったというグラフ
  49. 49. 二つのハッシュテーブルの比較
  50. 50. 二つのハッシュテーブルの比較 マスタ テキストの書式設定 第 2 レベル <ul><ul><li>第 3 レベル </li><ul><li>第 4 レベル </li><ul><li>第 5 レベル </li></ul></ul></ul></ul><ul><li>DougLea 式は 24 スレッドでピーク
  51. 51. 新アルゴリズムは 44 スレッドでピーク
  52. 52. 8 スレッド以下の環境では DougLea 式のほうが高速
  53. 53. 新アルゴリズムはスケーラビリティに優れる </li></ul>
  54. 54. 利用パターンによる性能差
  55. 55. 利用パターンによる性能差 左から右にかけて、検索の割合が減っていき削除の割合が増えていくテストケース スレッド数が少ない場合を除く全ての場面で新アルゴリズムが倍以上高速
  56. 56. まとめ Split-ordered な LockfreeList による並列ハッシュマップを提案 一般に使われている物よりスケーラビリティに優れる 8 コアまでなら DougLea 式の方が高速

×