-
Notifications
You must be signed in to change notification settings - Fork 77
/
bpt.h
291 lines (240 loc) · 7.59 KB
/
bpt.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#ifndef BPT_H
#define BPT_H
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <iostream>
#ifndef UNIT_TEST
#include "predefined.h"
#else
#include "util/unit_test_predefined.h"
#endif
namespace bpt {
/* offsets */
#define OFFSET_META 0
#define OFFSET_BLOCK OFFSET_META + sizeof(meta_t)
#define SIZE_NO_CHILDREN sizeof(leaf_node_t) - BP_ORDER * sizeof(record_t)
/* meta information of B+ tree */
typedef struct {
size_t order; /* `order` of B+ tree */
size_t value_size; /* size of value */
size_t key_size; /* size of key */
size_t internal_node_num; /* how many internal nodes */
size_t leaf_node_num; /* how many leafs */
size_t height; /* height of tree (exclude leafs) */
off_t slot; /* where to store new block */
off_t root_offset; /* where is the root of internal nodes */
off_t leaf_offset; /* where is the first leaf */
} meta_t;
/* internal nodes' index segment */
struct index_t {
key_t key;
off_t child; /* child's offset */
};
/***
* internal node block
***/
struct internal_node_t {
typedef index_t * child_t;
off_t parent; /* parent node offset */
off_t next;
off_t prev;
size_t n; /* how many children */
index_t children[BP_ORDER];
};
/* the final record of value */
struct record_t {
key_t key;
value_t value;
};
/* leaf node block */
struct leaf_node_t {
typedef record_t *child_t;
off_t parent; /* parent node offset */
off_t next;
off_t prev;
size_t n;
record_t children[BP_ORDER];
};
/* the encapulated B+ tree */
class bplus_tree {
public:
bplus_tree(const char *path, bool force_empty = false);
/* abstract operations */
int search(const key_t& key, value_t *value) const;
int search_range(key_t *left, const key_t &right,
value_t *values, size_t max, bool *next = NULL) const;
int remove(const key_t& key);
int insert(const key_t& key, value_t value);
int update(const key_t& key, value_t value);
meta_t get_meta() const {
return meta;
};
#ifndef UNIT_TEST
public:
#else
public:
#endif
char path[512];
meta_t meta;
/* init empty tree */
void init_from_empty();
/* find index */
off_t search_index(const key_t &key) const;
/* find leaf */
off_t search_leaf(off_t index, const key_t &key) const;
off_t search_leaf(const key_t &key) const
{
return search_leaf(search_index(key), key);
}
/* remove internal node */
void remove_from_index(off_t offset, internal_node_t &node,
const key_t &key, bool remove_flag = false);
/* borrow one key from other internal node */
bool borrow_key(bool from_right, internal_node_t &borrower,
off_t offset);
/* borrow one record from other leaf */
bool borrow_key(bool from_right, leaf_node_t &borrower);
/* change one's parent key to another key */
void change_parent_child(off_t parent, const key_t &o, const key_t &n);
/* merge right leaf to left leaf */
void merge_leafs(leaf_node_t *left, leaf_node_t *right);
void merge_keys(index_t *where, internal_node_t &left,
internal_node_t &right, bool change_where_key = false);
/* insert into leaf without split */
void insert_record_no_split(leaf_node_t *leaf,
const key_t &key, const value_t &value);
/* add key to the internal node */
void insert_key_to_index(off_t offset, const key_t &key,
off_t value, off_t after);
void insert_key_to_index_no_split(internal_node_t &node, const key_t &key,
off_t value);
/* change children's parent */
void reset_index_children_parent(index_t *begin, index_t *end,
off_t parent);
template<class T>
void node_create(off_t offset, T *node, T *next);
template<class T>
void node_remove(T *prev, T *node);
/* multi-level file open/close */
mutable FILE *fp;
mutable int fp_level;
void open_file(const char *mode = "rb+") const
{
// `rb+` will make sure we can write everywhere without truncating file
if (fp_level == 0)
fp = fopen(path, mode);
++fp_level;
}
void close_file() const
{
if (fp_level == 1)
fclose(fp);
--fp_level;
}
/* alloc from disk */
off_t alloc(size_t size)
{
off_t slot = meta.slot;
meta.slot += size;
return slot;
}
off_t alloc(leaf_node_t *leaf)
{
leaf->n = 0;
meta.leaf_node_num++;
return alloc(sizeof(leaf_node_t));
}
off_t alloc(internal_node_t *node)
{
node->n = 1;
meta.internal_node_num++;
return alloc(sizeof(internal_node_t));
}
void unalloc(leaf_node_t *leaf, off_t offset)
{
--meta.leaf_node_num;
}
void unalloc(internal_node_t *node, off_t offset)
{
--meta.internal_node_num;
}
/* read block from disk */
int map(void *block, off_t offset, size_t size) const
{
open_file();
fseek(fp, offset, SEEK_SET);
size_t rd = fread(block, size, 1, fp);
close_file();
return rd - 1;
}
template<class T>
int map(T *block, off_t offset) const
{
return map(block, offset, sizeof(T));
}
/* write block to disk */
int unmap(void *block, off_t offset, size_t size) const
{
open_file();
fseek(fp, offset, SEEK_SET);
size_t wd = fwrite(block, size, 1, fp);
close_file();
return wd - 1;
}
template<class T>
int unmap(T *block, off_t offset) const
{
return unmap(block, offset, sizeof(T));
}
};
class TreeStructureDisplay {
public:
TreeStructureDisplay(const bplus_tree &tree) : tree(tree) {}
void Display() {
displayNode(tree.get_meta().root_offset, 0);
}
private:
const bplus_tree &tree;
void displayNode(off_t offset, int level) {
if (offset == 0) {
return;
}
if (level < tree.get_meta().height) {
// 内部节点
internal_node_t node;
tree.map(&node, offset);
std::cout << indent(level) << "Internal Node at offset " << offset << ": contains " << node.n
<< " keys\n";
for (size_t i = 0; i < node.n; ++i) {
std::cout << indent(level + 1) << "Key: " << node.children[i].key.k << ", Child: "
<< node.children[i].child << "\n";
}
// 递归遍历子节点
for (size_t i = 0; i < node.n; ++i) {
displayNode(node.children[i].child, level + 1);
}
} else {
// 叶节点
leaf_node_t leaf;
tree.map(&leaf, offset);
std::cout << indent(level) << "Leaf Node at offset " << offset << ": contains " << leaf.n
<< " records\n";
for (size_t i = 0; i < leaf.n; ++i) {
std::cout << indent(level + 1) << "Record: Key: " << leaf.children[i].key.k << ", Value: "
<< leaf.children[i].value << "\n";
}
}
}
//indent
std::string indent(int level) {
std::string res;
for (int i = 0; i < level; ++i) {
res += " ";
}
return res;
}
};
}
#endif /* end of BPT_H */