proposed boost b_tree_library(ja)

50
Proposed Boost B-tree Library ディスクに保存する 順序付き連想コンテナ Disk-resident ordered associative containers for Boost Beman Dawes May 17, 2011 (translated by id:eldesh Thu 26, 2011)

Upload: takayuki-goto

Post on 29-Jun-2015

1.700 views

Category:

Technology


0 download

DESCRIPTION

This is presentation material about proposal of Boost B-tree library translated to japanese.The original material have presented in BoostCon2011 by Beman Dawes.This is published under Beman's permission.

TRANSCRIPT

Page 1: Proposed boost b_tree_library(ja)

Proposed Boost B-tree Libraryディスクに保存する 順序付き連想コンテナ

Disk-resident ordered associative containersfor Boost

Beman DawesMay 17, 2011

(translated by id:eldesh Thu 26, 2011)

Page 2: Proposed boost b_tree_library(ja)

今日の目的

● B-tree導入(高度36,000フィートから俯瞰)● B-treeライブラリの使い方● ライブラリレビュー状況● ライブラリへのフィードバック

Page 3: Proposed boost b_tree_library(ja)

B-tree の基本 (1/2)

● B-treeは平衡多分木● 全てのリーフノードはルートから同じ距離にある● ノード1は固定数の要素を持ち、そのうちいくつかは空かも知れ

ない(it is not unusual for nodes to have hundreds of elements.)

1. 訳注)ノードページ

Page 4: Proposed boost b_tree_library(ja)

B-tree の基本(2/2)

● 要素はノードページ内で順序づけられて並んでおり、ノードページも順序付いて並んでいる。つまりツリー内の全ての要素が順序付いて並んでいる。

● 挿入、削除、検索操作の計算量は比較のため O(log2n) となる

● 挿入、削除、検索操作は O(h) 個のノードに触れる。 h はツリーの高さである;m をノードページ毎の平均エントリ数とすると、およそ logm(h) である。h は典型的には一桁の数字である。

Page 5: Proposed boost b_tree_library(ja)

figure.1

Page 6: Proposed boost b_tree_library(ja)

figure.2

Page 7: Proposed boost b_tree_library(ja)

結論

● B-treeの特徴は 一般には、 ディスクに保存された インデックスに、とりわけ、順序づけられたコンテナ にとって理想的である。

● 一般的な、ディスクに保存したデータの検索について、他に重要な候補は無い。

● B-treeは実質的に、全てのファイルシステム、リレーショナルデータベース検索機構、NoSQL構造化データシステム、ディスクに保存するインデックスにインデックスデータ構造を提供する。

Page 8: Proposed boost b_tree_library(ja)

結論

● B-treeの特徴は 一般には、 ディスクに保存された インデックスに、とりわけ、順序づけられたコンテナ にとって理想的である。

● 一般的な、ディスクに保存したデータの検索について、他に重要な候補は無い。

● B-treeは実質的に、全てのファイルシステム、リレーショナルデータベース検索機構、NoSQL構造化データシステム、ディスクに保存するインデックスにインデックスデータ構造を提供する。

B-treeはディスク固有の順序付き連想コンテナテクニックの選択肢である。

Page 9: Proposed boost b_tree_library(ja)

B-tree の背景

● B-treeは Rudolf Bayerにより発明された。彼が*B*が何を意味するのかを言うことは無かった。B-treeは彼を称えてBayer treeと呼ばれるべきだという人もいる。

● Bayerはまた、メモリ内検索のためのRed-Black treeと、ディスク固有の多次元(例えば空間)検索のためのUniversal B-treeも発明している。

● Organization and Maintenance of Large Ordered Indexes, Bayer and McCreight, 1972 がオリジナルの論文である。

● The Ubiquitous B-Tree, Douglas Comer, 1979, は素晴らしい読み物だ。

Page 10: Proposed boost b_tree_library(ja)
Page 11: Proposed boost b_tree_library(ja)

Proposed Boost B-tree Library

Page 12: Proposed boost b_tree_library(ja)

Proposed Boost B-tree library

● 標準ライブラリの順序付き連想コンテナと似た、ディスク固有順序付き連想コンテナをよりリーズナブルに提供する

● 重要なヘッダは <boost/btree/set.hpp>と<boost/btree/map.hpp>

● これらはbtree_set, btree_multiset, btree_map, btree_multimapと足場を提供する。

● 可変長(例: 文字列)キー とマップされた値がサポートされる。 

Page 13: Proposed boost b_tree_library(ja)

Proposed Boost B-tree library (続き)

● このライブラリは<boost/btree/support>で追加の機能を提供する。それは便利になるかも知れないが無視することも出来る。

● データファイルはデフォルトでポータブル である。キーとTがポータブルデータオブジェクトであることを仮定している。

● パフォーマンスを高度に調整可能である● 私が書いて30年(!)保守してきたCライブラリの経験に基づい

ている。

Page 14: Proposed boost b_tree_library(ja)

typedef set<int> set_type;set_type s;s.insert(5);s.insert(3);s.insert(1);for (set_type::iterator it=s.begin(); it!=s.end(); ++it){ cout << *it << '\n';}// Output: 1// 3// 5

Page 15: Proposed boost b_tree_library(ja)

typedef btree_set<int> set_type;set_type s("set.btr", flags::truncate);s.insert(5);s.insert(3);s.insert(1);for (set_type::iterator it=s.begin(); it!=s.end(); ++it){ cout << *it << '\n';}// Output: 1// 3// 5

Page 16: Proposed boost b_tree_library(ja)

Boost B-tree は何に 向かない ?

● シリアライゼーション;B-treeはBoost.Serializationの代替ではない

● シーケンシャルデータ; B-treeは連想コンテナである。通常のファイルにはディスク用シーケンスコンテナがより良い選択だ。

● インメモリデータ; Red-Black treeまたはハッシュテーブル(例:標準ライブラリの連想コンテナ)が通常インメモリでの使用にとってはより良い選択だ。

Page 17: Proposed boost b_tree_library(ja)

標準連想コンテナとの違い

● テンプレートパラメータ● Key とTへのより厳しい制約● イテレータの無効化規則は、通常の古い連想コンテナより順序

無し連想コンテナにより近い● [multi]map value_type は std::pair<> ではなく、map_value<> である

● iterator と const_iterator は同じ型であり、それは不変なイテレータである

● いくつかのメンバ関数が削除され、いくつかが追加された

Page 18: Proposed boost b_tree_library(ja)

// std::template <class Key, class T, class Compare = less<Key>, class Allocator = allocator<pair<const Key, T> > >class map;// boost::btree::template <class Key, class T, class Traits = default_endian_traits, class Compare = btree::less<Key> >class btree_map;

Page 19: Proposed boost b_tree_library(ja)

Key, Tの制約

● Key, T型はバイナリ入力/出力出来なければならない ○ それらは trivially copyable types (3.9, ¶9) で無ければならな

い。従ってそのオブジェクトはmemcopy出来る :) ○ 言い替えると、

std::is_trivially_copyable<>がtrueにならなければならない

○ その型のオブジェクトは自分を含み、且つ、位置とプロセスから独立していなければならない。

Page 20: Proposed boost b_tree_library(ja)

Key, Tの制約

● Key, T型はバイナリ入力/出力出来なければならない ○ それらは trivially copyable types (3.9, ¶9) で無ければならな

い。従ってそのオブジェクトはmemcopy出来る :) ○ 言い替えると、

std::is_trivially_copyable<>がtrueにならなければならない

○ その型のオブジェクトは自分を含み、且つ、位置とプロセスから独立していなければならない。

std::stringは使えないーそれはtrivially copyableでは無いから。

Page 21: Proposed boost b_tree_library(ja)

可変長キー / マップバリュー

もしKeyのサイズが可変であるならば、map/multimapのvalue_typeとしてstd::pair<Key, T> は動作しない。替わりに、value_typeはclass map_valueになる template<class Key, class T>class map_value{public: const Key& key() const; const T& mapped_value() const; std::sisze_t size() const; // dynamic size in bytes};

Page 22: Proposed boost b_tree_library(ja)

typedef btree_map<int, long> map_type; map_type bt_map("bt_map.btr", flags::truncate);bt_map.emplace(2, -2);bt_map.emplace(3, -3);bt_map.emplace(1, -1);for (map_type::iterator it=bt_map.begin(); it != bt_map.end(); ++it){ cout << " " << it->key() << " --> " << it->mapped_value() << '\n ';} // Output: 1 --> -1// 2 --> -2// 3 --> -3

Page 23: Proposed boost b_tree_library(ja)

typedef btree_map<strbuf, strbuf> map_type;map_type bt_map("bt_map.btr", flags::truncate);bt_map.emplace("eat", "comer");bt_map.emplace("drink", "beber");bt_map.emplace("be merry", "ser feliz");for (map_type::iterator it=bt_map.begin(); it != bt_map.end(); ++it){ cout << " \"" << it->key() << "\" --> \"" << it->mapped_value() << "\"\n";}

// Output : "be merry" --> "ser feliz"// "drink" --> "beber"// "eat" --> "comer"

Page 24: Proposed boost b_tree_library(ja)

class strbuf {public: strbuf(); strbuf(const char* s); strbuf(const strbuf& s); strbuf& operator=(const char* s); strbuf& operator=(const strbuf& s); std::size_t size() const; const char* c_str() const; bool operator==(const strbuf& rhs) const; // other relationals...private: boost::uint8_t m_size;// strlen(m_buf) for speed char m_buf[max_size+1]; // '\0' terminated};std::ostream& operator<<(std::ostream& os, const strbuf& x);inline std::size_t dynamic_size(const strbuf& x){return x.size();}template<> struct has_dynamic_size<strbuf> : public true_type{};

Page 25: Proposed boost b_tree_library(ja)

bt_map.btr hex dump00000000 bbbb bbbb 0100 0100 0000 0000 0000 0003 ;;;;............00000010 0000 0080 0000 0004 0000 0001 0000 0001 ................00000020 0000 0001 0000 0002 0000 0000 0000 ffff ................00000030 ffff 6264 6f73 742e 6f72 6720 6274 7265 ..boost.org btre00000040 6500 0000 0100 0100 0000 0000 0000 0000 e...............00000050 0000 0000 0100 0100 0000 0000 0000 0000 ................00000060 0000 0000 0100 0100 0000 0000 0000 0000 ................00000070 0000 0000 0100 0100 0000 0000 0000 0000 ................

00000080 0000 002f 0862 6520 6d65 7272 7900 0973 .../.be merry..s00000090 6572 2066 656c 697a 00 05 6472 696e 6b00 er feliz..drink.000000a0 0562 6562 6572 0003 6561 7400 0563 6f6d .beber..eat..com000000b0 6572 0000 0000 0000 0000 0000 0000 0000 er..............000000c0 0000 0000 0000 0000 0000 0000 0000 0000 ................000000d0 0000 0000 0000 0000 0000 0000 0000 0000 ................000000e0 0000 0000 0000 0000 0000 0000 0000 0000 ................000000f0 0000 0000 0000 0000 0000 0000 0000 0000 ................

Page 26: Proposed boost b_tree_library(ja)

btree_map/multimap value_typeの設計判断

● map_type デザインオプション○ map_type<Key, T>○ pair<const Key*, const T*>

● KeyとTがどちらも可変長でなければ、map_typeをvalue_typeとする

Page 27: Proposed boost b_tree_library(ja)

マップされた値の更新

btree_map/multimapの実装は、ノードが更新されたときにそれを知る必要がある、そうすればノードは更新されたときのみディスクに書かれる。変更可能イテレータとマップされた値型は以下を許していない。 itr->mapped_value() = new_value; // error 解決策は用意してあり、 iterator update(iterator itr, const mapped_type & x);

そしてこのように書く bt.update(itr, new_value);

Page 28: Proposed boost b_tree_library(ja)

欠落した関数

size_type max_size() const;T& operator[](const key_type& k);const T& at(const key_type& k) const;T& at(const key_type& k);

Page 29: Proposed boost b_tree_library(ja)

追加した関数(の一部)

void open(const path& p, flags::bitmask flgs = flags::read_only, size_t node_sz = default_node_size) // node_sz ignored if existing filevoid flush();void close();bool is_open() const;size_t node_size() const;size_t max_cache_size() const;void max_cache_size(size_t m);

Page 30: Proposed boost b_tree_library(ja)

ユースケース

1. 順序付き連想配列ストレージコンテナとして使う場合;実際のアプリケーションデータはキーそのもの(setの場合)、あるいはマップされた値(mapの場合)

2. 他のファイルへの連想インデックスとして使う場合;実際のアプリケーションデータは他のファイルにある。典型的にはB-treeはmap/multimapであり、マップする値は他のファイルのレコードIDまたはファイルオフセットである。

もし、B-treeアプリケーションのデザインが見かけ上のB-treeによる制限に反しているように見えるなら、(1)よりむしろ(2)について考えてみてください

Page 31: Proposed boost b_tree_library(ja)

文字列データベースクラス

template <class String, class ID>class string_db{public: typedef String string_type; typedef ID id_type; // 0 indicates none string_db(const path& p, flags f); id_type insert(const string_type& s); id_type erase(const string_type& s); bool erase(id_type id); id_type find(const string_type& s) const; const string_type& find(id_type id) const;}

Page 32: Proposed boost b_tree_library(ja)

パフォーマンスチューニング

● 最大キャッシュサイズ● ノードサイズ● プリロードオプション● pack最適化● traits

Page 33: Proposed boost b_tree_library(ja)

最大キャッシュサイズ

この実装は使用中で無くなったノードをキャッシュする。このキャッシュの最大サイズはユーザがコントロールできる。 void max_cache_size(std::size_t m);

Page 34: Proposed boost b_tree_library(ja)

cachesize

Insert find iterate erase

32 33.55 sec8.6 rasio

23.18 sec6.50 ratio

0.07 sec0.37 ratio

37.49 sec8.48 ratio

2100 3.55 sec6.10 ratio

21.74 sec6.02 ratio

sec0.41 ratio

34.44 sec7.97 ratio

4200 13.79 sec3.53 rasio

16.34 sec4.56 ratio

0.08 sec0.40 ratio

25.90 sec5.81 ratio

8400 4.35 sec1.12 ratio

.62 sec1.00 ratio

0.04 sec0.23 ratio

4.13 sec0.93 ratio

キャッシュサイズ: btree_map vs std::map(5,000,000 calls - 3,160,338 size)

Page 35: Proposed boost b_tree_library(ja)

ノードサイズ

● btree_* コンストラクタは第3引数にノードサイズを指定するオプション引数を取る。

● 4096がデフォルトだが、これは明快で、WindowsのNTFSの スイートスポットであり、Linuxでもよさそうだ。しかし他のオペレーティングシステム(OS)やファイルシステムには他の値の方がより良いかも知れない。512はフロッピーや古いファイル、OSにとって最適だった。

● libs/tools/bt_time.cpp は実験に使える。

Page 36: Proposed boost b_tree_library(ja)

ノードサイズ: btree_map vs std::map(5,000,000 calls - 3,160,338 size)

Node size

insert find iterate erase

512 5.54 sec1.39 ratio

6.08 sec1.65 ratio

0.07 sec0.38 ratio

6.25 sec1.41 ratio

1024 4.83 sec1.20 ratio

5.25 sec1.43 ratio

0.6 sec0.29 ratio

5.33 sec1.23 ratio

2048 4.30 sec1.08 ratio

0.3 sec1.12 ratio

0.05 sec0.26 ratio

4.290.97 ratio

4096 .45 sec1.13 ratio

3.67 sec1.03 ratio

0.04 sec0.22 ratio

4.16 sec0.92 ratio

8192 5.20 sec1.34 ratio

3.42 sec0.93 ratio

0.04 sec0.22 ratio

4.45 sec1.01 ratio

16380 5.84 sec1.50 ratio

2.70 sec0.75 ratio

0.4 sec0.22 ratio

4.59 sec1.06 ratio

Page 37: Proposed boost b_tree_library(ja)

プリロード オプション

● flags::preload は btree_* コンストラクタで、または open関数の第2引数で設定し、既存のB-treeファイルのプリロードを引き起こす。これで指定したアプリケーションの高速化が出来ます。どのくらいかは人それぞれですが :)

Page 38: Proposed boost b_tree_library(ja)

Pack 最適化

● insertでノードがいっぱいになったとき、それより前の全てのinsertが全て順序通りであった場合、挿入操作は新しいノード上で完了する。 これはノードがいっぱいになった場合の通常の振る舞いがノードを二つに分割するのと対照的である。

● 結果は100%のノード使用率になり、通常の75%ではない。● 3,160,338要素のタイミングテストファイルでは、サイズが

34,299,904から25,440,256(約74%)に減少した。● 現在のところ、リーフノードにのみ実装してある

Page 39: Proposed boost b_tree_library(ja)

Traits

struct default_endian_traits{ typedef integer::ubig32_t node_id_type; typedef integer::ubig16_t node_size_type; typedef integer::ubig16_t node_level_type; static const BOOST_SCOPED_ENUM(integer::endianness) header_endianness = ineger::endianness::big; };

Page 40: Proposed boost b_tree_library(ja)

ファイルヘッダ

Boost.btreeのファイルはヘッダレコードから始まる。 内容:

● ツリー基盤データ(ノードサイズ、ルートノードid、フラグ、 など)● ユーザの利便性のためのデータ(c-str、ユーザint、など)● 頑健性のためのデータ(レコード型、クラスUUID、など)

Page 41: Proposed boost b_tree_library(ja)

B-tree variations

● B-treeは非常に多くの派生がある● B+-tree(びーぷらすつりー)は、例によってリーフノードにキーと

マップした値のペアを保存するが、ブランチノードにはキーのみを保存する。Boostライブラリや他のほとんどの実用的なB-tree実装は B+-treeを使っているが、包括的なB-treeという名称に自身を含めている。

● 空になったら消去し、半分の使用でマージする● B-tree派生についてのWikipediaの記事には、他のウェブベース

のポストのように、かなりの数の間違いが含まれているので注意。

Page 42: Proposed boost b_tree_library(ja)

派生には適用されないこと

● シーケンスリンク:挿入、削除が遅いこと(実際のテストによる)、挿入、削除に於いて父系の確立が難しいこと、特にユニークでないコンテナでは。

● 分岐キー接頭辞圧縮;KISS● 分岐キー接尾辞圧縮;KISS● insertによる満杯のノードの要素再分配;KISS

KISS: keep it short and simple?

Page 43: Proposed boost b_tree_library(ja)

ライブラリの現状

● Githubで利用可能。https://github.com/Beman/Boost-Btree/raw/master/README を見て下さい

● ドキュメントがいくらかあるが全く足りていない● JamfilesとVC++10によるビルドとテストを設定した● WindowsのVC++8/9/10とGCC/MinGW 4.4/4.5とUbuntu11.4

with GCC4.4でテスト済み● C++0xの機能はまだ使っていない

Page 44: Proposed boost b_tree_library(ja)

stl_test.cppによるテスト

● std::map<int32_t, int32_t>とbtree_map<int32_t, int32_t>で操作を実行し、結果が同一かを検証する。

● テスト条件を設定するための多数のプログラムオプション ● 50億回もの操作を破綻無く実行する。

Page 45: Proposed boost b_tree_library(ja)

サポートヘッダ、ミニライブラリ、そして万全のライブラリ

● 提案されているエンディアンライブラリ● シンプルな固定サイズC文字列ホルダ - fixstr.hpp● シンプルな可変長C文字列ホルダ - strbuf.hpp● random_string.hpp

Page 46: Proposed boost b_tree_library(ja)

開発目標

● フォーマルレビュー(Version 0.9)● Boost初リリース(Version 1.0)● B-treeのB-tree(Version 1.1)● 他のスレッドまたはプロセスによる共有更新(?)(Version ?)

Page 47: Proposed boost b_tree_library(ja)

手伝い募集!

● プレビューコメント● アーリーアダプターによるフィードバック● 独自に開発されたテストプログラム

Page 48: Proposed boost b_tree_library(ja)

議論

● コメント?● 抜けてる機能?● 懸念事項とか問題とか?

Page 49: Proposed boost b_tree_library(ja)

Thank You!

Page 50: Proposed boost b_tree_library(ja)

cd wherevergit clone ^ git://github.com/Beman/Boost-Btree.git xbtreesvn export -force ^ http://svn.boost.org/svn/boost/trunk xbtreeWindows: cd xbtree bootstrap cd libs\btree\test ..\..\..\bjamPOSIX-like: cd xbtree ./bootstrap.sh cd libs/btree/test ../../../bjam