Contenu connexe Similaire à Proposed boost b_tree_library(ja) (20) Proposed boost b_tree_library(ja)1. Proposed Boost B-tree Library
ディスクに保存する 順序付き連想コンテナ
Disk-resident ordered associative containers
for Boost
Beman Dawes
May 17, 2011
(translated by id:eldesh Thu 26, 2011)
3. B-tree の基本 (1/2)
● B-treeは平衡多分木
● 全てのリーフノードはルートから同じ距離にある
● ノード1は固定数の要素を持ち、そのうちいくつかは空かも知れ
ない
(it is not unusual for nodes to have hundreds of elements.)
1. 訳注)ノードページ
7. 結論
● B-treeの特徴は 一般には、 ディスクに保存された インデックス
に、とりわけ、順序づけられたコンテナ にとって理想的である。
● 一般的な、ディスクに保存したデータの検索について、
他に重要な候補は無い。
● B-treeは実質的に、全てのファイルシステム、リレーショナル
データベース検索機構、NoSQL構造化データシステム、ディスク
に保存するインデックスにインデックスデータ構造を提供する。
8. 結論
● B-treeの特徴は 一般には、 ディスクに保存された インデックス
B-treeはディスク固有の順序付き連
に、とりわけ、順序づけられたコンテナ にとって理想的である。
想コンテナテクニックの選択肢であ
● 一般的な、ディスクに保存したデータの検索について、
る。
他に重要な候補は無い。
● B-treeは実質的に、全てのファイルシステム、リレーショナル
データベース検索機構、NoSQL構造化データシステム、ディスク
に保存するインデックスにインデックスデータ構造を提供する。
9. 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, は素晴らしい
読み物だ。
12. Proposed Boost B-tree library
● 標準ライブラリの順序付き連想コンテナと似た、ディスク固有順
序付き連想コンテナをよりリーズナブルに提供する
● 重要なヘッダは <boost/btree/set.hpp>と<boost/btree/map.
hpp>
● これらはbtree_set, btree_multiset, btree_map,
btree_multimapと足場を提供する。
● 可変長(例: 文字列)キー とマップされた値がサポートされる。
13. Proposed Boost B-tree library (続き)
● このライブラリは<boost/btree/support>で追加の機能を提供
する。それは便利になるかも知れないが無視することも出来る。
● データファイルはデフォルトでポータブル である。キーとTがポー
タブルデータオブジェクトであることを仮定している。
● パフォーマンスを高度に調整可能である
● 私が書いて30年(!)保守してきたCライブラリの経験に基づい
ている。
14. 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
15. 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
16. Boost B-tree は何に 向かない ?
● シリアライゼーション;B-treeはBoost.Serializationの代替ではな
い
● シーケンシャルデータ; B-treeは連想コンテナである。通常の
ファイルにはディスク用シーケンスコンテナがより良い選択だ。
● インメモリデータ; Red-Black treeまたはハッシュテーブル(例:
標準ライブラリの連想コンテナ)が通常インメモリでの使用にとっ
てはより良い選択だ。
17. 標準連想コンテナとの違い
● テンプレートパラメータ
● Key とTへのより厳しい制約
● イテレータの無効化規則は、通常の古い連想コンテナより順序
無し連想コンテナにより近い
● [multi]map value_type は std::pair<> ではなく、
map_value<> である
● iterator と const_iterator は同じ型であり、それは不
変なイテレータである
● いくつかのメンバ関数が削除され、いくつかが追加された
18. // 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;
19. Key, Tの制約
● Key, T型はバイナリ入力/出力出来なければならない
○ それらは trivially copyable types (3.9, ¶9) で無ければならな
い。従ってそのオブジェクトはmemcopy出来る :)
○ 言い替えると、
std::is_trivially_copyable<>がtrueにならなければなら
ない
○ その型のオブジェクトは自分を含み、
且つ、位置とプロセスから独立していなければならない。
20. Key, Tの制約
● Key, T型はバイナリ入力/出力出来なければならない
○ それらは trivially copyable types (3.9, ¶9) で無ければならな
std::stringは使えないーそれは
い。従ってそのオブジェクトはmemcopy出来る :)
○ 言い替えると、 copyableでは無いから。
trivially
std::is_trivially_copyable<>がtrueにならなければなら
ない
○ その型のオブジェクトは自分を含み、
且つ、位置とプロセスから独立していなければならない。
22. 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
23. 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"
24. 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{};
25. bt_map.btr hex dump
00000000 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 btre
00000040 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..s
00000090 6572 2066 656c 697a 00 05 6472 696e 6b00 er feliz..drink.
000000a0 0562 6562 6572 0003 6561 7400 0563 6f6d .beber..eat..com
000000b0 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 ................
26. btree_map/multimap value_typeの
設計判断
● map_type デザインオプション
○ map_type<Key, T>
○ pair<const Key*, const T*>
● KeyとTがどちらも可変長でなければ、map_typeをvalue_typeとす
る
28. 欠落した関数
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);
29. 追加した関数(の一部)
void open(const path& p,
flags::bitmask flgs = flags::read_only,
size_t node_sz = default_node_size)
// node_sz ignored if existing file
void 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);
30. ユースケース
1. 順序付き連想配列ストレージコンテナとして使う場合;
実際のアプリケーションデータはキーそのもの(setの場合)、あるいは
マップされた値(mapの場合)
2. 他のファイルへの連想インデックスとして使う場合;
実際のアプリケーションデータは他のファイルにある。典型的にはB-
treeはmap/multimapであり、マップする値は他のファイルのレコードID
またはファイルオフセットである。
もし、B-treeアプリケーションのデザインが見かけ上のB-treeによる制限に
反しているように見えるなら、
(1)よりむしろ(2)について考えてみてください
31. 文字列データベースクラス
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;
}
34. キャッシュサイズ: btree_map vs std::map
(5,000,000 calls - 3,160,338 size)
cache Insert find iterate erase
size
32 33.55 sec 23.18 sec 0.07 sec 37.49 sec
8.6 rasio 6.50 ratio 0.37 ratio 8.48 ratio
2100 3.55 sec 21.74 sec sec 34.44 sec
6.10 ratio 6.02 ratio 0.41 ratio 7.97 ratio
4200 13.79 sec 16.34 sec 0.08 sec 25.90 sec
3.53 rasio 4.56 ratio 0.40 ratio 5.81 ratio
8400 4.35 sec .62 sec 0.04 sec 4.13 sec
1.12 ratio 1.00 ratio 0.23 ratio 0.93 ratio
35. ノードサイズ
● btree_* コンストラクタは第3引数にノードサイズを指定するオプ
ション引数を取る。
● 4096がデフォルトだが、これは明快で、WindowsのNTFSの ス
イートスポットであり、Linuxでもよさそうだ。しかし他のオペレー
ティングシステム(OS)やファイルシステムには他の値の方がよ
り良いかも知れない。512はフロッピーや古いファイル、OSに
とって最適だった。
● libs/tools/bt_time.cpp は実験に使える。
36. ノードサイズ: btree_map vs std::map
(5,000,000 calls - 3,160,338 size)
Node insert find iterate erase
size
512 5.54 sec 6.08 sec 0.07 sec 6.25 sec
1.39 ratio 1.65 ratio 0.38 ratio 1.41 ratio
1024 4.83 sec 5.25 sec 0.6 sec 5.33 sec
1.20 ratio 1.43 ratio 0.29 ratio 1.23 ratio
2048 4.30 sec 0.3 sec 0.05 sec 4.29
1.08 ratio 1.12 ratio 0.26 ratio 0.97 ratio
4096 .45 sec 3.67 sec 0.04 sec 4.16 sec
1.13 ratio 1.03 ratio 0.22 ratio 0.92 ratio
8192 5.20 sec 3.42 sec 0.04 sec 4.45 sec
1.34 ratio 0.93 ratio 0.22 ratio 1.01 ratio
16380 5.84 sec 2.70 sec 0.4 sec 4.59 sec
1.50 ratio 0.75 ratio 0.22 ratio 1.06 ratio
37. プリロード オプション
● flags::preload は btree_* コンストラクタで、または
open関数の第2引数で設定し、既存のB-treeファイルのプリロー
ドを引き起こす。これで指定したアプリケーションの高速化が出
来ます。
どのくらいかは人それぞれですが :)
38. Pack 最適化
● insertでノードがいっぱいになったとき、それより前の全ての
insertが全て順序通りであった場合、挿入操作は新しいノード上
で完了する。 これはノードがいっぱいになった場合の通常の振
る舞いがノードを二つに分割するのと対照的である。
● 結果は100%のノード使用率になり、通常の75%ではない。
● 3,160,338要素のタイミングテストファイルでは、サイズが
34,299,904から25,440,256(約74%)に減少した。
● 現在のところ、リーフノードにのみ実装してある
39. 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;
};
41. B-tree variations
● B-treeは非常に多くの派生がある
● B+-tree(びーぷらすつりー)は、例によってリーフノードにキーと
マップした値のペアを保存するが、ブランチノードにはキーのみ
を保存する。
Boostライブラリや他のほとんどの実用的なB-tree実装は B+-
treeを使っているが、包括的なB-treeという名称に自身を含めて
いる。
● 空になったら消去し、半分の使用でマージする
● B-tree派生についてのWikipediaの記事には、他のウェブベース
のポストのように、かなりの数の間違いが含まれているので注
意。
43. ライブラリの現状
● 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の機能はまだ使っていない
45. サポートヘッダ、ミニライブラリ、そして
万全のライブラリ
● 提案されているエンディアンライブラリ
● シンプルな固定サイズC文字列ホルダ - fixstr.hpp
● シンプルな可変長C文字列ホルダ - strbuf.hpp
● random_string.hpp
50. cd wherever
git clone ^
git://github.com/Beman/Boost-Btree.git xbtree
svn export -force ^
http://svn.boost.org/svn/boost/trunk xbtree
Windows:
cd xbtree
bootstrap
cd libsbtreetest
......bjam
POSIX-like:
cd xbtree
./bootstrap.sh
cd libs/btree/test
../../../bjam