Skip to content

Commit dbe24fd

Browse files
kikimoskyzh
andauthored
feat: pretty print B+ tree (#503)
* pretty print B+ tree * add back comment of `Draw()` * fix lint * fix clang-tidy * adapt to new interface Signed-off-by: Alex Chi <[email protected]> * fix Signed-off-by: Alex Chi <[email protected]> * fix Signed-off-by: Alex Chi <[email protected]> --------- Signed-off-by: Alex Chi <[email protected]> Co-authored-by: Alex Chi <[email protected]>
1 parent 826e81c commit dbe24fd

File tree

5 files changed

+159
-16
lines changed

5 files changed

+159
-16
lines changed

src/include/storage/index/b_plus_tree.h

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,3 @@
1-
//===----------------------------------------------------------------------===//
2-
//
3-
// CMU-DB Project (15-445/645)
4-
// ***DO NO SHARE PUBLICLY***
5-
//
6-
// Identification: src/include/index/b_plus_tree.h
7-
//
8-
// Copyright (c) 2018, Carnegie Mellon University Database Group
9-
//
10-
//===----------------------------------------------------------------------===//
111
/**
122
* b_plus_tree.h
133
*
@@ -22,9 +12,11 @@
2212

2313
#include <algorithm>
2414
#include <deque>
15+
#include <iostream>
2516
#include <optional>
2617
#include <queue>
2718
#include <shared_mutex>
19+
#include <string>
2820
#include <vector>
2921

3022
#include "common/config.h"
@@ -38,6 +30,8 @@
3830

3931
namespace bustub {
4032

33+
struct PrintableBPlusTree;
34+
4135
/**
4236
* @brief Definition of the Context class.
4337
*
@@ -63,6 +57,7 @@ class Context {
6357
};
6458

6559
#define BPLUSTREE_TYPE BPlusTree<KeyType, ValueType, KeyComparator>
60+
6661
// Main class providing the API for the Interactive B+ Tree.
6762
INDEX_TEMPLATE_ARGUMENTS
6863
class BPlusTree {
@@ -102,6 +97,19 @@ class BPlusTree {
10297
// Draw the B+ tree
10398
void Draw(BufferPoolManager *bpm, const std::string &outf);
10499

100+
/**
101+
* @brief draw a B+ tree, below is a printed
102+
* B+ tree(3 max leaf, 4 max internal) after inserting key:
103+
* {1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 18, 19, 20}
104+
*
105+
* (25)
106+
* (9,17,19) (33)
107+
* (1,5) (9,13) (17,18) (19,20,21) (25,29) (33,37)
108+
*
109+
* @return std::string
110+
*/
111+
auto DrawBPlusTree() -> std::string;
112+
105113
// read data from file and insert one by one
106114
void InsertFromFile(const std::string &file_name, Transaction *txn = nullptr);
107115

@@ -114,11 +122,13 @@ class BPlusTree {
114122

115123
void PrintTree(page_id_t page_id, const BPlusTreePage *page);
116124

117-
void Dump() {
118-
for (auto &f : log) {
119-
std::cout << f << std::endl;
120-
}
121-
}
125+
/**
126+
* @brief Convert A B+ tree into a Printable B+ tree
127+
*
128+
* @param root_id
129+
* @return PrintableNode
130+
*/
131+
auto ToPrintableBPlusTree(page_id_t root_id) -> PrintableBPlusTree;
122132

123133
// member variable
124134
std::string index_name_;
@@ -130,4 +140,40 @@ class BPlusTree {
130140
page_id_t header_page_id_;
131141
};
132142

143+
/**
144+
* @brief for test only. PrintableBPlusTree is a printalbe B+ tree.
145+
* We first convert B+ tree into a printable B+ tree and the print it.
146+
*/
147+
struct PrintableBPlusTree {
148+
int size_;
149+
std::string keys_;
150+
std::vector<PrintableBPlusTree> children_;
151+
152+
/**
153+
* @brief BFS traverse a printable B+ tree and print it into
154+
* into out_buf
155+
*
156+
* @param out_buf
157+
*/
158+
void Print(std::ostream &out_buf) {
159+
std::vector<PrintableBPlusTree *> que = {this};
160+
while (!que.empty()) {
161+
std::vector<PrintableBPlusTree *> new_que;
162+
163+
for (auto &t : que) {
164+
int padding = (t->size_ - t->keys_.size()) / 2;
165+
out_buf << std::string(padding, ' ');
166+
out_buf << t->keys_;
167+
out_buf << std::string(padding, ' ');
168+
169+
for (auto &c : t->children_) {
170+
new_que.push_back(&c);
171+
}
172+
}
173+
out_buf << "\n";
174+
que = new_que;
175+
}
176+
}
177+
};
178+
133179
} // namespace bustub

src/include/storage/page/b_plus_tree_internal_page.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#pragma once
1212

1313
#include <queue>
14+
#include <string>
1415

1516
#include "storage/page/b_plus_tree_page.h"
1617

@@ -72,6 +73,32 @@ class BPlusTreeInternalPage : public BPlusTreePage {
7273
*/
7374
auto ValueAt(int index) const -> ValueType;
7475

76+
/**
77+
* @brief For test only, return a string representing all keys in
78+
* this internal page, formatted as "(key1,key2,key3,...)"
79+
*
80+
* @return std::string
81+
*/
82+
auto ToString() const -> std::string {
83+
std::string kstr = "(";
84+
bool first = true;
85+
86+
// first key of internal page is always invalid
87+
for (int i = 1; i < GetSize(); i++) {
88+
KeyType key = KeyAt(i);
89+
if (first) {
90+
first = false;
91+
} else {
92+
kstr.append(",");
93+
}
94+
95+
kstr.append(std::to_string(key.ToString()));
96+
}
97+
kstr.append(")");
98+
99+
return kstr;
100+
}
101+
75102
private:
76103
// Flexible array member for page data.
77104
MappingType array_[0];

src/include/storage/page/b_plus_tree_leaf_page.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//===----------------------------------------------------------------------===//
1111
#pragma once
1212

13+
#include <string>
1314
#include <utility>
1415
#include <vector>
1516

@@ -58,6 +59,31 @@ class BPlusTreeLeafPage : public BPlusTreePage {
5859
void SetNextPageId(page_id_t next_page_id);
5960
auto KeyAt(int index) const -> KeyType;
6061

62+
/**
63+
* @brief for test only return a string representing all keys in
64+
* this leaf page formatted as "(key1,key2,key3,...)"
65+
*
66+
* @return std::string
67+
*/
68+
auto ToString() const -> std::string {
69+
std::string kstr = "(";
70+
bool first = true;
71+
72+
for (int i = 0; i < GetSize(); i++) {
73+
KeyType key = KeyAt(i);
74+
if (first) {
75+
first = false;
76+
} else {
77+
kstr.append(",");
78+
}
79+
80+
kstr.append(std::to_string(key.ToString()));
81+
}
82+
kstr.append(")");
83+
84+
return kstr;
85+
}
86+
6187
private:
6288
page_id_t next_page_id_;
6389
// Flexible array member for page data.

src/storage/index/b_plus_tree.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <sstream>
12
#include <string>
23

34
#include "common/exception.h"
@@ -292,6 +293,47 @@ void BPLUSTREE_TYPE::ToGraph(page_id_t page_id, const BPlusTreePage *page, std::
292293
}
293294
}
294295

296+
INDEX_TEMPLATE_ARGUMENTS
297+
auto BPLUSTREE_TYPE::DrawBPlusTree() -> std::string {
298+
if (IsEmpty()) {
299+
return "()";
300+
}
301+
302+
PrintableBPlusTree p_root = ToPrintableBPlusTree(GetRootPageId());
303+
std::ostringstream out_buf;
304+
p_root.Print(out_buf);
305+
306+
return out_buf.str();
307+
}
308+
309+
INDEX_TEMPLATE_ARGUMENTS
310+
auto BPLUSTREE_TYPE::ToPrintableBPlusTree(page_id_t root_id) -> PrintableBPlusTree {
311+
auto root_page_guard = bpm_->FetchPageBasic(root_id);
312+
auto root_page = root_page_guard.template As<BPlusTreePage>();
313+
PrintableBPlusTree proot;
314+
315+
if (root_page->IsLeafPage()) {
316+
auto leaf_page = root_page_guard.template As<LeafPage>();
317+
proot.keys_ = leaf_page->ToString();
318+
proot.size_ = proot.keys_.size() + 4; // 4 more spaces for indent
319+
320+
return proot;
321+
}
322+
323+
// draw internal page
324+
auto internal_page = root_page_guard.template As<InternalPage>();
325+
proot.keys_ = internal_page->ToString();
326+
proot.size_ = 0;
327+
for (int i = 0; i < internal_page->GetSize(); i++) {
328+
page_id_t child_id = internal_page->ValueAt(i);
329+
PrintableBPlusTree child_node = ToPrintableBPlusTree(child_id);
330+
proot.size_ += child_node.size_;
331+
proot.children_.push_back(child_node);
332+
}
333+
334+
return proot;
335+
}
336+
295337
template class BPlusTree<GenericKey<4>, RID, GenericComparator<4>>;
296338

297339
template class BPlusTree<GenericKey<8>, RID, GenericComparator<8>>;

tools/b_plus_tree_printer/b_plus_tree_printer.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ auto main(int argc, char **argv) -> int {
7777
page_id_t page_id;
7878
auto header_page = bpm->NewPage(&page_id);
7979
// create b+ tree
80-
BPlusTree<GenericKey<8>, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator, leaf_max_size, internal_max_size);
80+
BPlusTree<GenericKey<8>, RID, GenericComparator<8>> tree("foo_pk", page_id, bpm, comparator, leaf_max_size,
81+
internal_max_size);
8182
// create transaction
8283
auto *transaction = new Transaction(0);
8384
while (!quit) {
@@ -110,6 +111,7 @@ auto main(int argc, char **argv) -> int {
110111
quit = true;
111112
break;
112113
case 'p':
114+
std::cout << tree.DrawBPlusTree() << std::endl;
113115
tree.Print(bpm);
114116
break;
115117
case 'g':

0 commit comments

Comments
 (0)