├── README.md ├── bplustree.c ├── bplustree.h ├── bplustree_demo.c └── makefile /README.md: -------------------------------------------------------------------------------- 1 | # 基于B+树的磁盘索引 2 | 3 | 支持查找、插入、删除、可视化,支持范围操作 4 | 5 | 6 | 7 | 两个存储文件:index存储数据,boot存储B+树的信息 8 | 9 | 10 | 11 | 设置.index位置和命名,用于存放数据 12 | 13 | ``` 14 | Set data index file name (e.g. /tmp/data.index): 15 | ``` 16 | 17 | 设置_block_size,用于存放B+树节点在内存中的缓存 18 | 19 | ``` 20 | Set index file block size (bytes, power of 2, e.g. 4096): 21 | ``` 22 | 23 | 输入命令 24 | 25 | ``` 26 | Please input command (Type 'h' for help): 27 | ``` 28 | 29 | 帮助文档,插入、删除、查找、可视化、退出 30 | 31 | ``` 32 | i: Insert key. e.g. i 1 4-7 9 33 | r: Remove key. e.g. r 1-100 34 | s: Search by key. e.g. s 41-60 35 | d: Dump the tree structure. 36 | q: quit. 37 | ``` 38 | 39 | 编译 40 | 41 | ``` 42 | make 43 | make clean 44 | ``` 45 | 46 | 运行 47 | 48 | ``` 49 | ./bplustree_demo.out 50 | ``` 51 | 52 | 库文件 53 | 54 | ``` 55 | lib 56 | |----bplustree.h 57 | |----bplustree.c 58 | ``` 59 | 60 | demo 61 | 62 | ``` 63 | bplustree_demo.c 64 | ``` 65 | 66 | -------------------------------------------------------------------------------- /bplustree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include"bplustree.h" 12 | 13 | /* 14 | 偏移量的枚举 15 | INVALID_OFFSET非法偏移量 16 | */ 17 | enum { 18 | INVALID_OFFSET = 0xdeadbeef, 19 | }; 20 | 21 | /* 22 | 是否为叶子节点的枚举 23 | 叶子节点 24 | 非叶子节点 25 | */ 26 | enum { 27 | BPLUS_TREE_LEAF, 28 | BPLUS_TREE_NON_LEAF = 1, 29 | }; 30 | 31 | /* 32 | 兄弟节点的枚举 33 | 左兄弟 34 | 右兄弟 35 | */ 36 | enum { 37 | LEFT_SIBLING, 38 | RIGHT_SIBLING = 1, 39 | }; 40 | 41 | /* 42 | 内存结构 43 | --------------------------------------------------------------------------------------------------- 44 | | | | | | | | | | | | | | 45 | |叶子节点 | node | key | key | key | key | key | data | data | data | data | data | 46 | | | | | | | | | | | | | | 47 | |--------------------------------------------------------------------------------------------------- 48 | | | | | | | | | | | | | | 49 | |非叶子节点 | node | key | key | key | key | ptr | ptr | ptr | ptr | ptr | ptr | 50 | | | | | | | | | | | | | | 51 | --------------------------------------------------------------------------------------------------- 52 | key和data的个数由_max_entries决定:_max_entries = (_block_size - sizeof(node)) / (sizeof(key_t) + sizeof(long)); 53 | 一个节点的大小由_block_size决定,容量要包含1个node结构体和3个及以上的key,data 54 | */ 55 | 56 | /*16位数据宽度*/ 57 | #define ADDR_STR_WIDTH 16 58 | 59 | /*B+树节点node末尾的偏移地址,即key的首地址*/ 60 | #define offset_ptr(node) ((char *) (node) + sizeof(*node)) 61 | 62 | /*返回B+树节点末尾地址,强制转换为key_t*,即key的指针*/ 63 | #define key(node) ((key_t *)offset_ptr(node)) 64 | 65 | /*返回B+树节点和key末尾地址,强制转换为long*,即data指针*/ 66 | #define data(node) ((long *)(offset_ptr(node) + _max_entries * sizeof(key_t))) 67 | 68 | /*返回最后一个key的指针,用于非叶子节点的指向,即第一个ptr*/ 69 | #define sub(node) ((off_t *)(offset_ptr(node) + (_max_order - 1) * sizeof(key_t))) 70 | 71 | /* 72 | 全局静态变量 73 | _block_size--------------------每个节点的大小(容量要包含1个node和3个及以上的key,data) 74 | _max_entries-------------------叶子节点内包含个数最大值 75 | _max_order---------------------非叶子节点内最大关键字个数 76 | */ 77 | static int _block_size; 78 | static int _max_entries; 79 | static int _max_order; 80 | 81 | /* 82 | 判断是否为叶子节点 83 | */ 84 | static inline int is_leaf(struct bplus_node *node) 85 | { 86 | return node->type == BPLUS_TREE_LEAF; 87 | } 88 | 89 | /* 90 | 键值二分查找 91 | */ 92 | static int key_binary_search(struct bplus_node *node, key_t target) 93 | { 94 | key_t *arr = key(node); 95 | /*叶子节点:len;非叶子节点:len-1;非叶子节点的key少一个,用于放ptr*/ 96 | int len = is_leaf(node) ? node->children : node->children - 1; 97 | int low = -1; 98 | int high = len; 99 | 100 | while (low + 1 < high) { 101 | int mid = low + (high - low) / 2; 102 | if (target > arr[mid]) { 103 | low = mid; 104 | } else { 105 | high = mid; 106 | } 107 | } 108 | 109 | if (high >= len || arr[high] != target) { 110 | return -high - 1; 111 | } else { 112 | return high; 113 | } 114 | } 115 | 116 | /* 117 | 查找键值在父节点的第几位 118 | */ 119 | static inline int parent_key_index(struct bplus_node *parent, key_t key) 120 | { 121 | int index = key_binary_search(parent, key); 122 | return index >= 0 ? index : -index - 2; 123 | } 124 | 125 | /* 126 | 占用缓存区,与cache_defer对应 127 | 占用内存,以供使用 128 | 缓存不足,assert(0)直接终止程序 129 | */ 130 | static inline struct bplus_node *cache_refer(struct bplus_tree *tree) 131 | { 132 | int i; 133 | for (i = 0; i < MIN_CACHE_NUM; i++) { 134 | if (!tree->used[i]) { 135 | tree->used[i] = 1; 136 | char *buf = tree->caches + _block_size * i; 137 | return (struct bplus_node *) buf; 138 | } 139 | } 140 | assert(0); 141 | } 142 | 143 | /* 144 | 释放缓冲区,与cache_refer对应 145 | 将used重置,能够存放接下来的数据 146 | */ 147 | static inline void cache_defer(struct bplus_tree *tree, struct bplus_node *node) 148 | { 149 | char *buf = (char *) node; 150 | int i = (buf - tree->caches) / _block_size; 151 | tree->used[i] = 0; 152 | } 153 | 154 | /* 155 | 创建新的节点 156 | */ 157 | static struct bplus_node *node_new(struct bplus_tree *tree) 158 | { 159 | struct bplus_node *node = cache_refer(tree); 160 | node->self = INVALID_OFFSET; 161 | node->parent = INVALID_OFFSET; 162 | node->prev = INVALID_OFFSET; 163 | node->next = INVALID_OFFSET; 164 | node->children = 0; 165 | return node; 166 | } 167 | 168 | /* 169 | 创建新的非叶子节点 170 | */ 171 | static inline struct bplus_node *non_leaf_new(struct bplus_tree *tree) 172 | { 173 | struct bplus_node *node = node_new(tree); 174 | node->type = BPLUS_TREE_NON_LEAF; 175 | return node; 176 | } 177 | 178 | /* 179 | 创建新的叶子节点 180 | */ 181 | static inline struct bplus_node *leaf_new(struct bplus_tree *tree) 182 | { 183 | struct bplus_node *node = node_new(tree); 184 | node->type = BPLUS_TREE_LEAF; 185 | return node; 186 | } 187 | 188 | /* 189 | 根据偏移量从.index获取节点的全部信息,加载到缓冲区 190 | 偏移量非法则返回NULL 191 | */ 192 | static struct bplus_node *node_fetch(struct bplus_tree *tree, off_t offset) 193 | { 194 | if (offset == INVALID_OFFSET) { 195 | return NULL; 196 | } 197 | 198 | struct bplus_node *node = cache_refer(tree); 199 | int len = pread(tree->fd, node, _block_size, offset); 200 | assert(len == _block_size); 201 | return node; 202 | } 203 | 204 | /* 205 | 通过节点的偏移量从.index中获取节点的全部信息 206 | */ 207 | static struct bplus_node *node_seek(struct bplus_tree *tree, off_t offset) 208 | { 209 | /*偏移量不合法*/ 210 | if (offset == INVALID_OFFSET) { 211 | return NULL; 212 | } 213 | 214 | /*偏移量合法*/ 215 | int i; 216 | for (i = 0; i < MIN_CACHE_NUM; i++) { 217 | if (!tree->used[i]) { 218 | char *buf = tree->caches + _block_size * i; 219 | int len = pread(tree->fd, buf, _block_size, offset); 220 | assert(len == _block_size); 221 | return (struct bplus_node *) buf; 222 | } 223 | } 224 | assert(0); 225 | } 226 | 227 | /* 228 | B+树节点保存 229 | 将其保存到index 230 | 并将内存内的缓冲区释放 231 | 往tree->fd的文件描述符写入 232 | node指向的节点信息和其后面跟随的节点内容 233 | 长度为_block_size 234 | 偏移量为node->self 235 | */ 236 | static inline void node_flush(struct bplus_tree *tree, struct bplus_node *node) 237 | { 238 | if (node != NULL) { 239 | int len = pwrite(tree->fd, node, _block_size, node->self); 240 | assert(len == _block_size); 241 | cache_defer(tree, node); 242 | } 243 | } 244 | 245 | /* 246 | 节点加入到树,为新节点分配新的偏移量,即文件大小 247 | 判断链表是否为空,判断是否有空闲区块 248 | 空闲区块首地址保存在.boot 249 | */ 250 | static off_t new_node_append(struct bplus_tree *tree, struct bplus_node *node) 251 | { 252 | /*.index无空闲区块*/ 253 | if (list_empty(&tree->free_blocks)) { 254 | node->self = tree->file_size; 255 | tree->file_size += _block_size; 256 | /*.inedx有空闲区块*/ 257 | } else { 258 | struct free_block *block; 259 | block = list_first_entry(&tree->free_blocks, struct free_block, link); 260 | list_del(&block->link); 261 | node->self = block->offset; 262 | free(block); 263 | } 264 | return node->self; 265 | } 266 | 267 | /* 268 | 从.index删除整个节点,多出一块空闲区块,添加到B+树信息结构体 269 | struct bplus_tree *tree-------------------B+树信息结构体 270 | struct bplus_node *node-------------------要被删除的节点 271 | struct bplus_node *left-------------------左孩子 272 | struct bplus_node *right------------------右孩子 273 | */ 274 | static void node_delete(struct bplus_tree *tree, struct bplus_node *node, struct bplus_node *left, struct bplus_node *right) 275 | { 276 | if (left != NULL) { 277 | /*左右孩子均存在*/ 278 | if (right != NULL) { 279 | left->next = right->self; 280 | right->prev = left->self; 281 | node_flush(tree, right); 282 | /*左孩子存在,右孩子不存在*/ 283 | } else { 284 | left->next = INVALID_OFFSET; 285 | } 286 | node_flush(tree, left); 287 | } else { 288 | /*没有孩子节点*/ 289 | if (right != NULL) { 290 | right->prev = INVALID_OFFSET; 291 | node_flush(tree, right); 292 | } 293 | } 294 | 295 | assert(node->self != INVALID_OFFSET); 296 | struct free_block *block = malloc(sizeof(*block)); 297 | assert(block != NULL); 298 | /*空闲区块指向被删除节点在.index中的偏移量*/ 299 | block->offset = node->self; 300 | /*添加空闲区块*/ 301 | list_add_tail(&block->link, &tree->free_blocks); 302 | /*释放缓冲区*/ 303 | cache_defer(tree, node); 304 | } 305 | 306 | /* 307 | 更新非叶子节点的指向 308 | struct bplus_tree *tree----------------B+树信息结构体 309 | struct bplus_node *parent--------------父节点 310 | int index------------------------------插入位置 311 | struct bplus_node *sub_node------------要插入的分支 312 | */ 313 | static inline void sub_node_update(struct bplus_tree *tree, struct bplus_node *parent, 314 | int index, struct bplus_node *sub_node) 315 | { 316 | assert(sub_node->self != INVALID_OFFSET); 317 | sub(parent)[index] = sub_node->self; 318 | sub_node->parent = parent->self; 319 | node_flush(tree, sub_node); 320 | } 321 | 322 | /* 323 | 将分裂的非叶子节点的孩子重定向,并写入.index 324 | struct bplus_tree *tree----------------B+树信息结构体 325 | struct bplus_node *parent--------------分裂的新的非叶子节点 326 | off_t sub_offset-----------------------偏移量,即指向子节点的指针 327 | */ 328 | static inline void sub_node_flush(struct bplus_tree *tree, struct bplus_node *parent, off_t sub_offset) 329 | { 330 | struct bplus_node *sub_node = node_fetch(tree, sub_offset); 331 | assert(sub_node != NULL); 332 | sub_node->parent = parent->self; 333 | node_flush(tree, sub_node); 334 | } 335 | 336 | /* 337 | B+树查找 338 | */ 339 | static long bplus_tree_search(struct bplus_tree *tree, key_t key) 340 | { 341 | int ret = -1; 342 | /*返回根节点的结构体*/ 343 | struct bplus_node *node = node_seek(tree, tree->root); 344 | while (node != NULL) { 345 | int i = key_binary_search(node, key); 346 | /*到达叶子节点*/ 347 | if (is_leaf(node)) { 348 | ret = i >= 0 ? data(node)[i] : -1; 349 | break; 350 | /*未到达叶子节点,循环递归*/ 351 | } else { 352 | if (i >= 0) { 353 | node = node_seek(tree, sub(node)[i + 1]); 354 | } else { 355 | i = -i - 1; 356 | node = node_seek(tree, sub(node)[i]); 357 | } 358 | } 359 | } 360 | 361 | return ret; 362 | } 363 | 364 | /* 365 | 左节点添加 366 | 设置左右兄弟叶子节点的指向,不存在就设置为非法 367 | struct bplus_tree *tree------------B+树信息结构体 368 | struct bplus_node *node------------B+树要分裂的节点 369 | struct bplus_node *left------------B+树左边的新节点 370 | */ 371 | static void left_node_add(struct bplus_tree *tree, struct bplus_node *node, struct bplus_node *left) 372 | { 373 | new_node_append(tree, left); 374 | 375 | struct bplus_node *prev = node_fetch(tree, node->prev); 376 | if (prev != NULL) { 377 | prev->next = left->self; 378 | left->prev = prev->self; 379 | node_flush(tree, prev); 380 | } else { 381 | left->prev = INVALID_OFFSET; 382 | } 383 | left->next = node->self; 384 | node->prev = left->self; 385 | } 386 | 387 | /* 388 | 右节点添加 389 | 设置左右兄弟叶子节点的指向,不存在就设置为非法 390 | struct bplus_tree *tree------------B+树信息结构体 391 | struct bplus_node *node------------B+树要分裂的节点 392 | struct bplus_node *right-----------B+树右边的新节点 393 | */ 394 | static void right_node_add(struct bplus_tree *tree, struct bplus_node *node, struct bplus_node *right) 395 | { 396 | new_node_append(tree, right); 397 | 398 | struct bplus_node *next = node_fetch(tree, node->next); 399 | if (next != NULL) { 400 | next->prev = right->self; 401 | right->next = next->self; 402 | node_flush(tree, next); 403 | } else { 404 | right->next = INVALID_OFFSET; 405 | } 406 | right->prev = node->self; 407 | node->next = right->self; 408 | } 409 | 410 | /*非叶子节点插入,声明*/ 411 | static key_t non_leaf_insert(struct bplus_tree *tree, struct bplus_node *node, struct bplus_node *l_ch, struct bplus_node *r_ch, key_t key); 412 | 413 | /* 414 | 下一层节点满后分裂,建立新的父节点,添加键值 415 | struct bplus_tree *tree-------------B+树信息结构体 416 | struct bplus_node *l_ch-------------B+树左孩子节点 417 | struct bplus_node *r_ch-------------B+树右孩子节点 418 | key_t key---------------------------后继节点的键值 419 | */ 420 | static int parent_node_build(struct bplus_tree *tree, struct bplus_node *l_ch, struct bplus_node *r_ch, key_t key) 421 | { 422 | /*左右节点均没有父节点*/ 423 | if (l_ch->parent == INVALID_OFFSET && r_ch->parent == INVALID_OFFSET) { 424 | /*左右节点均没有父节点,建立新的父节点*/ 425 | struct bplus_node *parent = non_leaf_new(tree); 426 | key(parent)[0] = key; 427 | sub(parent)[0] = l_ch->self; 428 | sub(parent)[1] = r_ch->self; 429 | parent->children = 2; 430 | 431 | /*写入新的父节点,升级B+树信息结构体内的root根节点*/ 432 | tree->root = new_node_append(tree, parent); 433 | l_ch->parent = parent->self; 434 | r_ch->parent = parent->self; 435 | tree->level++; 436 | 437 | /*操作完成,将父节点和子节点记入index*/ 438 | node_flush(tree, l_ch); 439 | node_flush(tree, r_ch); 440 | node_flush(tree, parent); 441 | return 0; 442 | /*右节点没有父节点*/ 443 | } else if (r_ch->parent == INVALID_OFFSET) { 444 | /*node_fetch(tree, l_ch->parent):从.index文件获取*/ 445 | return non_leaf_insert(tree, node_fetch(tree, l_ch->parent), l_ch, r_ch, key); 446 | /*左节点没有父节点*/ 447 | } else { 448 | /*node_fetch(tree, r_ch->parent):从.index文件获取*/ 449 | return non_leaf_insert(tree, node_fetch(tree, r_ch->parent), l_ch, r_ch, key); 450 | } 451 | } 452 | 453 | /* 454 | 非叶子节点的分裂插入 455 | insert在spilit左边,insertchildren = split; 478 | node->children = _max_order - split + 1; 479 | 480 | /*将原来的insert~spilit的key和data复制到分裂的左兄弟*/ 481 | memmove(&key(left)[0], &key(node)[0], pivot * sizeof(key_t)); 482 | memmove(&sub(left)[0], &sub(node)[0], pivot * sizeof(off_t)); 483 | 484 | /*将原来的insert+1~end的key和data后移1位,方便插入*/ 485 | memmove(&key(left)[pivot + 1], &key(node)[pivot], (split - pivot - 1) * sizeof(key_t)); 486 | memmove(&sub(left)[pivot + 1], &sub(node)[pivot], (split - pivot - 1) * sizeof(off_t)); 487 | 488 | /*将分裂的左节点的孩子重定向,写入.index*/ 489 | for (i = 0; i < left->children; i++) { 490 | if (i != pivot && i != pivot + 1) { 491 | sub_node_flush(tree, left, sub(left)[i]); 492 | } 493 | } 494 | 495 | /*插入新键和子节点,并找到拆分键*/ 496 | key(left)[pivot] = key; 497 | /* 498 | 插入的非叶子节点有左右两孩子 499 | 判断他们在分裂边界的那一边 500 | pivot == split - 1:孩子节点在分裂边界的两边 501 | else:孩子节点均在分裂节点左边 502 | */ 503 | if (pivot == split - 1) { 504 | /* 505 | 孩子节点在分裂边界的两边 506 | 更新索引,l_ch放到新分裂的非叶子节点 507 | r_ch放到原非叶子节点 508 | */ 509 | sub_node_update(tree, left, pivot, l_ch); 510 | sub_node_update(tree, node, 0, r_ch); 511 | split_key = key; 512 | } else { 513 | /* 514 | 两个新的子节点在分裂左节点 515 | 更新索引,l_ch和r_ch均放到新分裂的非叶子节点 516 | */ 517 | sub_node_update(tree, left, pivot, l_ch); 518 | sub_node_update(tree, left, pivot + 1, r_ch); 519 | sub(node)[0] = sub(node)[split - 1]; 520 | split_key = key(node)[split - 2]; 521 | } 522 | 523 | /*将原节点分裂边界右边的key和ptr左移*/ 524 | memmove(&key(node)[0], &key(node)[split - 1], (node->children - 1) * sizeof(key_t)); 525 | memmove(&sub(node)[1], &sub(node)[split], (node->children - 1) * sizeof(off_t)); 526 | 527 | /*返回前继节点,作为上一层键值*/ 528 | return split_key; 529 | } 530 | 531 | /* 532 | 非叶子节点的分裂插入 533 | insert与spilit重叠,insert==spilit 534 | 直接分裂,移动操作减少 535 | struct bplus_tree *tree------------------B+树信息结构体 536 | struct bplus_node *node------------------原节点 537 | struct bplus_node *right-----------------新分裂的节点 538 | struct bplus_node *l_ch------------------左孩子 539 | struct bplus_node *r_ch------------------右孩子 540 | key_t key--------------------------------键值 541 | int insert-------------------------------插入位置 542 | */ 543 | static key_t non_leaf_split_right1(struct bplus_tree *tree, struct bplus_node *node, struct bplus_node *right, struct bplus_node *l_ch, struct bplus_node *r_ch, key_t key, int insert) 544 | { 545 | int i; 546 | 547 | /*分裂边界spilit=(len+1)/2*/ 548 | int split = (_max_order + 1) / 2; 549 | 550 | /*新分裂的节点添加到树*/ 551 | right_node_add(tree, node, right); 552 | 553 | /*上一层的键值*/ 554 | key_t split_key = key(node)[split - 1]; 555 | 556 | /*重新计算孩子个数*/ 557 | int pivot = 0; 558 | node->children = split; 559 | right->children = _max_order - split + 1; 560 | 561 | /*插入key和ptr*/ 562 | key(right)[0] = key; 563 | sub_node_update(tree, right, pivot, l_ch); 564 | sub_node_update(tree, right, pivot + 1, r_ch); 565 | 566 | /*复制数据到新的分裂节点*/ 567 | memmove(&key(right)[pivot + 1], &key(node)[split], (right->children - 2) * sizeof(key_t)); 568 | memmove(&sub(right)[pivot + 2], &sub(node)[split + 1], (right->children - 2) * sizeof(off_t)); 569 | 570 | /*重定向父子结点,写入.index*/ 571 | for (i = pivot + 2; i < right->children; i++) { 572 | sub_node_flush(tree, right, sub(right)[i]); 573 | } 574 | 575 | /*返回上一层键值*/ 576 | return split_key; 577 | } 578 | 579 | /* 580 | 非叶子节点的分裂插入 581 | insert在spilit右边,insert>spilit 582 | struct bplus_tree *tree------------------B+树信息结构体 583 | struct bplus_node *node------------------原节点 584 | struct bplus_node *right-----------------新分裂的节点 585 | struct bplus_node *l_ch------------------左孩子 586 | struct bplus_node *r_ch------------------右孩子 587 | key_t key--------------------------------键值 588 | int insert-------------------------------插入位置 589 | */ 590 | static key_t non_leaf_split_right2(struct bplus_tree *tree, struct bplus_node *node, struct bplus_node *right, struct bplus_node *l_ch, struct bplus_node *r_ch, key_t key, int insert) 591 | { 592 | int i; 593 | 594 | /*分裂边界spilit=(len+1)/2*/ 595 | int split = (_max_order + 1) / 2; 596 | 597 | /*右节点添加到树*/ 598 | right_node_add(tree, node, right); 599 | 600 | /*上一层的键值*/ 601 | key_t split_key = key(node)[split]; 602 | 603 | /*重新计算孩子个数*/ 604 | int pivot = insert - split - 1; 605 | node->children = split + 1; 606 | right->children = _max_order - split; 607 | 608 | /*复制数据到新的分裂节点*/ 609 | memmove(&key(right)[0], &key(node)[split + 1], pivot * sizeof(key_t)); 610 | memmove(&sub(right)[0], &sub(node)[split + 1], pivot * sizeof(off_t)); 611 | 612 | /*插入key和ptr,更新索引*/ 613 | key(right)[pivot] = key; 614 | sub_node_update(tree, right, pivot, l_ch); 615 | sub_node_update(tree, right, pivot + 1, r_ch); 616 | 617 | /*将原节点insert+1~end的数据移动到新分裂的非叶子节点*/ 618 | memmove(&key(right)[pivot + 1], &key(node)[insert], (_max_order - insert - 1) * sizeof(key_t)); 619 | memmove(&sub(right)[pivot + 2], &sub(node)[insert + 1], (_max_order - insert - 1) * sizeof(off_t)); 620 | 621 | /*重定向父子结点,写入.index*/ 622 | for (i = 0; i < right->children; i++) { 623 | if (i != pivot && i != pivot + 1) { 624 | sub_node_flush(tree, right, sub(right)[i]); 625 | } 626 | } 627 | 628 | /*返回上一层键值*/ 629 | return split_key; 630 | } 631 | 632 | /* 633 | 父节点未满时,非叶子节点的简单插入 634 | struct bplus_tree *tree----------------B+树信息结构体 635 | struct bplus_node *node----------------父节点 636 | struct bplus_node *l_ch----------------左孩子 637 | struct bplus_node *r_ch----------------右孩子 638 | key_t key------------------------------键值 639 | int insert-----------------------------插入位置 640 | */ 641 | static void non_leaf_simple_insert(struct bplus_tree *tree, struct bplus_node *node, struct bplus_node *l_ch, struct bplus_node *r_ch, key_t key, int insert) 642 | { 643 | /*将insert处原来的值后移*/ 644 | memmove(&key(node)[insert + 1], &key(node)[insert], (node->children - 1 - insert) * sizeof(key_t)); 645 | memmove(&sub(node)[insert + 2], &sub(node)[insert + 1], (node->children - 1 - insert) * sizeof(off_t)); 646 | 647 | /*在insert处插入键值,并更新索引*/ 648 | key(node)[insert] = key; 649 | sub_node_update(tree, node, insert, l_ch); 650 | sub_node_update(tree, node, insert + 1, r_ch); 651 | node->children++; 652 | } 653 | 654 | /* 655 | 非叶子节点插入,定义 656 | 即生成新的父节点 657 | struct bplus_tree *tree-------------B+树信息结构体 658 | struct bplus_node *node-------------要接入的新的B+树兄弟叶子节点 659 | struct bplus_node *l_ch-------------B+树左孩子节点 660 | struct bplus_node *r_ch-------------B+树右孩子节点 661 | key_t key 662 | */ 663 | static int non_leaf_insert(struct bplus_tree *tree, struct bplus_node *node, struct bplus_node *l_ch, struct bplus_node *r_ch, key_t key) 664 | { 665 | /*键值二分查找*/ 666 | int insert = key_binary_search(node, key); 667 | assert(insert < 0); 668 | insert = -insert - 1; 669 | 670 | /*父节点满,进行分裂*/ 671 | if (node->children == _max_order) { 672 | key_t split_key; 673 | /*分裂边界spilit=(len+1)/2*/ 674 | int split = (node->children + 1) / 2; 675 | /*生成一个新的分裂的非叶子节点*/ 676 | struct bplus_node *sibling = non_leaf_new(tree); 677 | if (insert < split) { 678 | split_key = non_leaf_split_left(tree, node, sibling, l_ch, r_ch, key, insert); 679 | } else if (insert == split) { 680 | split_key = non_leaf_split_right1(tree, node, sibling, l_ch, r_ch, key, insert); 681 | } else { 682 | split_key = non_leaf_split_right2(tree, node, sibling, l_ch, r_ch, key, insert); 683 | } 684 | 685 | /*再次建立新的父节点*/ 686 | if (insert < split) { 687 | return parent_node_build(tree, sibling, node, split_key); 688 | } else { 689 | return parent_node_build(tree, node, sibling, split_key); 690 | } 691 | /*父节点未满,进行简单的非叶子节点插入,并保存*/ 692 | } else { 693 | non_leaf_simple_insert(tree, node, l_ch, r_ch, key, insert); 694 | node_flush(tree, node); 695 | } 696 | return 0; 697 | } 698 | 699 | /* 700 | 节点分裂插入,插入位置在分裂位置的左边 701 | 与leaf_split_right类似 702 | struct bplus_tree *tree-----------B+树信息结构体 703 | struct bplus_node *leaf-----------B+树叶子节点 704 | struct bplus_node *left-----------新的叶子节点 705 | key_t key-------------------------键值 706 | long data-------------------------数据 707 | int insert------------------------插入位置 708 | */ 709 | static key_t leaf_split_left(struct bplus_tree *tree, struct bplus_node *leaf, struct bplus_node *left, key_t key, long data, int insert) 710 | { 711 | /*分裂边界split=(len+1)/2*/ 712 | int split = (leaf->children + 1) / 2; 713 | 714 | /*节点分裂,设置左右兄弟叶子节点的指向*/ 715 | left_node_add(tree, leaf, left); 716 | 717 | /*重新设置children的数值*/ 718 | int pivot = insert; 719 | left->children = split; 720 | leaf->children = _max_entries - split + 1; 721 | 722 | /* 723 | 将原叶子节点key[0]-key[insert]的数值复制到左边分裂出的新的叶子节点 724 | 将原叶子节点data[0]-data[insert]的数值复制到左边分裂出的新的叶子节点 725 | */ 726 | memmove(&key(left)[0], &key(leaf)[0], pivot * sizeof(key_t)); 727 | memmove(&data(left)[0], &data(leaf)[0], pivot * sizeof(long)); 728 | 729 | /*在insert处插入新的key和data*/ 730 | key(left)[pivot] = key; 731 | data(left)[pivot] = data; 732 | 733 | /*从原叶子节点将insert到split的值放到新的叶子节点insert+1处*/ 734 | memmove(&key(left)[pivot + 1], &key(leaf)[pivot], (split - pivot - 1) * sizeof(key_t)); 735 | memmove(&data(left)[pivot + 1], &data(leaf)[pivot], (split - pivot - 1) * sizeof(long)); 736 | 737 | /*将原叶子节点insert+1~end的key和data复制到原叶子节点key[0]*/ 738 | memmove(&key(leaf)[0], &key(leaf)[split - 1], leaf->children * sizeof(key_t)); 739 | memmove(&data(leaf)[0], &data(leaf)[split - 1], leaf->children * sizeof(long)); 740 | 741 | /*返回后继节点的key,即原叶子节点现在的key[0]*/ 742 | return key(leaf)[0]; 743 | } 744 | 745 | /* 746 | 节点分裂插入,插入位置在分裂位置的右边 747 | 与leaf_split_left类似 748 | struct bplus_tree *tree-----------B+树信息结构体 749 | struct bplus_node *leaf-----------B+树叶子节点 750 | struct bplus_node *right----------新的叶子节点 751 | key_t key-------------------------键值 752 | long data-------------------------数据 753 | int insert------------------------插入位置 754 | */ 755 | static key_t leaf_split_right(struct bplus_tree *tree, struct bplus_node *leaf, struct bplus_node *right, key_t key, long data, int insert) 756 | { 757 | /*分裂边界split=(len+1)/2*/ 758 | int split = (leaf->children + 1) / 2; 759 | 760 | /*节点分裂,设置左右兄弟叶子节点的指向*/ 761 | right_node_add(tree, leaf, right); 762 | 763 | /*重新设置children的数值*/ 764 | int pivot = insert - split; 765 | leaf->children = split; 766 | right->children = _max_entries - split + 1; 767 | 768 | /*将原叶子节点spilt~insert的key和data复制到右边分裂出的新的叶子节点*/ 769 | memmove(&key(right)[0], &key(leaf)[split], pivot * sizeof(key_t)); 770 | memmove(&data(right)[0], &data(leaf)[split], pivot * sizeof(long)); 771 | 772 | /*在insert处插入新的key和data*/ 773 | key(right)[pivot] = key; 774 | data(right)[pivot] = data; 775 | 776 | /*移动剩余的数据*/ 777 | memmove(&key(right)[pivot + 1], &key(leaf)[insert], (_max_entries - insert) * sizeof(key_t)); 778 | memmove(&data(right)[pivot + 1], &data(leaf)[insert], (_max_entries - insert) * sizeof(long)); 779 | 780 | /*返回后继节点的key,即分裂的叶子节点的key[0]*/ 781 | return key(right)[0]; 782 | } 783 | 784 | /* 785 | 叶子节点在未满时的简单插入 786 | struct bplus_tree *tree--------------------B+树信息结构体 787 | struct bplus_node *leaf--------------------B+树节点结构体,要插入的位置的上一个节点 788 | key_t key----------------------------------键值 789 | long data----------------------------------数据 790 | int intsert--------------------------------要插入的节点位序 791 | 两个memmove是将在insert之前的数据往后存放,使得数据能够插入 792 | */ 793 | static void leaf_simple_insert(struct bplus_tree *tree, struct bplus_node *leaf, key_t key, long data, int insert) 794 | { 795 | memmove(&key(leaf)[insert + 1], &key(leaf)[insert], (leaf->children - insert) * sizeof(key_t)); 796 | memmove(&data(leaf)[insert + 1], &data(leaf)[insert], (leaf->children - insert) * sizeof(long)); 797 | key(leaf)[insert] = key; 798 | data(leaf)[insert] = data; 799 | leaf->children++; 800 | } 801 | 802 | /* 803 | 插入叶子节点 804 | struct bplus_tree *tree--------------------B+树信息结构体 805 | struct bplus_node *leaf--------------------B+树节点结构体,要插入的位置的上一个节点 806 | key_t key----------------------------------键值 807 | long data----------------------------------数据 808 | */ 809 | static int leaf_insert(struct bplus_tree *tree, struct bplus_node *leaf, key_t key, long data) 810 | { 811 | /*键值二分查找*/ 812 | int insert = key_binary_search(leaf, key); 813 | /*已存在键值*/ 814 | if (insert >= 0) { 815 | return -1; 816 | } 817 | insert = -insert - 1; 818 | 819 | /*从空闲节点缓存中获取*/ 820 | int i = ((char *) leaf - tree->caches) / _block_size; 821 | tree->used[i] = 1; 822 | 823 | /*叶子节点满*/ 824 | if (leaf->children == _max_entries) { 825 | key_t split_key; 826 | 827 | /*节点分裂边界split=(len+1)/2*/ 828 | int split = (_max_entries + 1) / 2; 829 | struct bplus_node *sibling = leaf_new(tree); 830 | 831 | /* 832 | 由插入位置决定的兄弟叶复制 833 | insert < split:插入位置在分裂位置的左边 834 | insert >= split:插入位置在分裂位置的右边 835 | 返回后继节点,以放入父节点作为键值 836 | */ 837 | if (insert < split) { 838 | split_key = leaf_split_left(tree, leaf, sibling, key, data, insert); 839 | } else { 840 | split_key = leaf_split_right(tree, leaf, sibling, key, data, insert); 841 | } 842 | 843 | /*建立新的父节点*/ 844 | if (insert < split) { 845 | return parent_node_build(tree, sibling, leaf, split_key); 846 | } else { 847 | return parent_node_build(tree, leaf, sibling, split_key); 848 | } 849 | /*叶子节点未满*/ 850 | } else { 851 | leaf_simple_insert(tree, leaf, key, data, insert); 852 | node_flush(tree, leaf); 853 | } 854 | 855 | return 0; 856 | } 857 | 858 | /* 859 | 插入节点 860 | */ 861 | static int bplus_tree_insert(struct bplus_tree *tree, key_t key, long data) 862 | { 863 | struct bplus_node *node = node_seek(tree, tree->root); 864 | while (node != NULL) { 865 | /*到达叶子节点*/ 866 | if (is_leaf(node)) { 867 | return leaf_insert(tree, node, key, data); 868 | /*还未到达叶子节点,继续循环递归查找*/ 869 | } else { 870 | int i = key_binary_search(node, key); 871 | if (i >= 0) { 872 | node = node_seek(tree, sub(node)[i + 1]); 873 | } else { 874 | i = -i - 1; 875 | node = node_seek(tree, sub(node)[i]); 876 | } 877 | } 878 | } 879 | 880 | /* 881 | 创建新的叶子节点 882 | 在B+树后面跟随赋值key和data 883 | 添加key:key(root)[0] = key; 884 | 添加data:data(root)[0] = data; 885 | 插入树:tree->root = new_node_append(tree, root); 886 | 刷新缓冲区:node_flush(tree, root); 887 | */ 888 | struct bplus_node *root = leaf_new(tree); 889 | key(root)[0] = key; 890 | data(root)[0] = data; 891 | root->children = 1; 892 | tree->root = new_node_append(tree, root); 893 | tree->level = 1; 894 | node_flush(tree, root); 895 | return 0; 896 | } 897 | 898 | /* 899 | struct bplus_node *l_sib------------------左兄弟 900 | struct bplus_node *r_sib------------------右兄弟 901 | struct bplus_node *parent-----------------父节点 902 | int i-------------------------------------键值在父节点中的位置 903 | */ 904 | static inline int sibling_select(struct bplus_node *l_sib, struct bplus_node *r_sib, struct bplus_node *parent, int i) 905 | { 906 | if (i == -1) { 907 | /*没有左兄弟,选择右兄弟合并*/ 908 | return RIGHT_SIBLING; 909 | } else if (i == parent->children - 2) { 910 | /*没有右兄弟,选择左兄弟*/ 911 | return LEFT_SIBLING; 912 | } else { 913 | /*有左右兄弟,选择孩子更多的节点*/ 914 | return l_sib->children >= r_sib->children ? LEFT_SIBLING : RIGHT_SIBLING; 915 | } 916 | } 917 | 918 | /* 919 | 非叶子节点从左兄弟拿一个值 920 | */ 921 | static void non_leaf_shift_from_left(struct bplus_tree *tree, struct bplus_node *node, struct bplus_node *left, struct bplus_node *parent, int parent_key_index, int remove) 922 | { 923 | memmove(&key(node)[1], &key(node)[0], remove * sizeof(key_t)); 924 | memmove(&sub(node)[1], &sub(node)[0], (remove + 1) * sizeof(off_t)); 925 | 926 | key(node)[0] = key(parent)[parent_key_index]; 927 | key(parent)[parent_key_index] = key(left)[left->children - 2]; 928 | 929 | sub(node)[0] = sub(left)[left->children - 1]; 930 | sub_node_flush(tree, node, sub(node)[0]); 931 | 932 | left->children--; 933 | } 934 | 935 | /* 936 | 非叶子节点合并到左兄弟 937 | */ 938 | static void non_leaf_merge_into_left(struct bplus_tree *tree, struct bplus_node *node, struct bplus_node *left, struct bplus_node *parent, int parent_key_index, int remove) 939 | { 940 | /*键值下移*/ 941 | key(left)[left->children - 1] = key(parent)[parent_key_index]; 942 | 943 | memmove(&key(left)[left->children], &key(node)[0], remove * sizeof(key_t)); 944 | memmove(&sub(left)[left->children], &sub(node)[0], (remove + 1) * sizeof(off_t)); 945 | 946 | memmove(&key(left)[left->children + remove], &key(node)[remove + 1], (node->children - remove - 2) * sizeof(key_t)); 947 | memmove(&sub(left)[left->children + remove + 1], &sub(node)[remove + 2], (node->children - remove - 2) * sizeof(off_t)); 948 | 949 | int i, j; 950 | for (i = left->children, j = 0; j < node->children - 1; i++, j++) { 951 | sub_node_flush(tree, left, sub(left)[i]); 952 | } 953 | 954 | left->children += node->children - 1; 955 | } 956 | 957 | /* 958 | 非叶子节点从右兄弟拿一个值 959 | */ 960 | static void non_leaf_shift_from_right(struct bplus_tree *tree, struct bplus_node *node, struct bplus_node *right, struct bplus_node *parent, int parent_key_index) 961 | { 962 | key(node)[node->children - 1] = key(parent)[parent_key_index]; 963 | key(parent)[parent_key_index] = key(right)[0]; 964 | 965 | sub(node)[node->children] = sub(right)[0]; 966 | sub_node_flush(tree, node, sub(node)[node->children]); 967 | node->children++; 968 | 969 | memmove(&key(right)[0], &key(right)[1], (right->children - 2) * sizeof(key_t)); 970 | memmove(&sub(right)[0], &sub(right)[1], (right->children - 1) * sizeof(off_t)); 971 | 972 | right->children--; 973 | } 974 | 975 | /* 976 | 非叶子节点合并到右兄弟 977 | */ 978 | static void non_leaf_merge_from_right(struct bplus_tree *tree, struct bplus_node *node, struct bplus_node *right, struct bplus_node *parent, int parent_key_index) 979 | { 980 | key(node)[node->children - 1] = key(parent)[parent_key_index]; 981 | node->children++; 982 | 983 | memmove(&key(node)[node->children - 1], &key(right)[0], (right->children - 1) * sizeof(key_t)); 984 | memmove(&sub(node)[node->children - 1], &sub(right)[0], right->children * sizeof(off_t)); 985 | 986 | int i, j; 987 | for (i = node->children - 1, j = 0; j < right->children; i++, j++) { 988 | sub_node_flush(tree, node, sub(node)[i]); 989 | } 990 | 991 | node->children += right->children - 1; 992 | } 993 | 994 | /* 995 | 非叶子节点的简单删除 996 | */ 997 | static inline void non_leaf_simple_remove(struct bplus_tree *tree, struct bplus_node *node, int remove) 998 | { 999 | assert(node->children >= 2); 1000 | memmove(&key(node)[remove], &key(node)[remove + 1], (node->children - remove - 2) * sizeof(key_t)); 1001 | memmove(&sub(node)[remove + 1], &sub(node)[remove + 2], (node->children - remove - 2) * sizeof(off_t)); 1002 | node->children--; 1003 | } 1004 | 1005 | /* 1006 | 非叶子节点的删除操作 1007 | 叶子节点删除操作后,更新非叶子节点,非叶子节点的键值也可能被删除,非叶子节点也可能合并 1008 | struct bplus_tree *tree---------------------B+树信息结构体 1009 | struct bplus_node *node---------------------要执行删除操作的节点 1010 | int remove----------------------------------要删除的键值位置 1011 | */ 1012 | static void non_leaf_remove(struct bplus_tree *tree, struct bplus_node *node, int remove) 1013 | { 1014 | /*不存在父节点,要执行删除操作的节点是根节点*/ 1015 | if (node->parent == INVALID_OFFSET) { 1016 | /*只有两个键值*/ 1017 | if (node->children == 2) { 1018 | /*用第一个子节点替换旧根节点*/ 1019 | struct bplus_node *root = node_fetch(tree, sub(node)[0]); 1020 | root->parent = INVALID_OFFSET; 1021 | tree->root = root->self; 1022 | tree->level--; 1023 | node_delete(tree, node, NULL, NULL); 1024 | node_flush(tree, root); 1025 | /*键值大于2,将remove后的数据前移*/ 1026 | } else { 1027 | non_leaf_simple_remove(tree, node, remove); 1028 | node_flush(tree, node); 1029 | } 1030 | /*存在父节点,且非叶子节点内含数据小于一半,也要进行合并操作*/ 1031 | } else if (node->children <= (_max_order + 1) / 2) { 1032 | struct bplus_node *l_sib = node_fetch(tree, node->prev); 1033 | struct bplus_node *r_sib = node_fetch(tree, node->next); 1034 | struct bplus_node *parent = node_fetch(tree, node->parent); 1035 | 1036 | int i = parent_key_index(parent, key(node)[0]); 1037 | 1038 | /*选择左兄弟合并*/ 1039 | if (sibling_select(l_sib, r_sib, parent, i) == LEFT_SIBLING) { 1040 | /*左兄弟节点内数据过半,无法合并,就拿一个数据过来*/ 1041 | if (l_sib->children > (_max_order + 1) / 2) { 1042 | /*左兄弟数据未过半,两两合并*/ 1043 | non_leaf_shift_from_left(tree, node, l_sib, parent, i, remove); 1044 | node_flush(tree, node); 1045 | node_flush(tree, l_sib); 1046 | node_flush(tree, r_sib); 1047 | node_flush(tree, parent); 1048 | /*左兄弟数据未过半,两两合并*/ 1049 | } else { 1050 | non_leaf_merge_into_left(tree, node, l_sib, parent, i, remove); 1051 | node_delete(tree, node, l_sib, r_sib); 1052 | non_leaf_remove(tree, parent, i); 1053 | } 1054 | /*选择右兄弟合并*/ 1055 | } else { 1056 | /*在与兄弟节点合并时首先删除,以防溢出*/ 1057 | non_leaf_simple_remove(tree, node, remove); 1058 | 1059 | /*右兄弟节点内数据过半,无法合并,就拿一个数据过来*/ 1060 | if (r_sib->children > (_max_order + 1) / 2) { 1061 | non_leaf_shift_from_right(tree, node, r_sib, parent, i + 1); 1062 | node_flush(tree, node); 1063 | node_flush(tree, l_sib); 1064 | node_flush(tree, r_sib); 1065 | node_flush(tree, parent); 1066 | /*右兄弟数据未过半,两两合并*/ 1067 | } else { 1068 | non_leaf_merge_from_right(tree, node, r_sib, parent, i + 1); 1069 | struct bplus_node *rr_sib = node_fetch(tree, r_sib->next); 1070 | node_delete(tree, r_sib, node, rr_sib); 1071 | node_flush(tree, l_sib); 1072 | non_leaf_remove(tree, parent, i + 1); 1073 | } 1074 | } 1075 | /*存在父节点,且非叶子节点内含数据大于一半,不需要进行合并操作*/ 1076 | } else { 1077 | non_leaf_simple_remove(tree, node, remove); 1078 | node_flush(tree, node); 1079 | } 1080 | } 1081 | 1082 | /* 1083 | 从左兄弟拿一个数据,来保持平衡 1084 | struct bplus_tree *tree------------------B+树信息结构体 1085 | struct bplus_node *leaf------------------要执行删除操作和合并操作的叶子节点 1086 | struct bplus_node *left------------------左兄弟 1087 | struct bplus_node *parent----------------父节点 1088 | int parent_key_index---------------------leaf在父节点的位置 1089 | int remove-------------------------------删除的数据在leaf的位置 1090 | */ 1091 | static void leaf_shift_from_left(struct bplus_tree *tree, struct bplus_node *leaf, struct bplus_node *left, struct bplus_node *parent, int parent_key_index, int remove) 1092 | { 1093 | /*腾出第一个位置*/ 1094 | memmove(&key(leaf)[1], &key(leaf)[0], remove * sizeof(key_t)); 1095 | memmove(&data(leaf)[1], &data(leaf)[0], remove * sizeof(off_t)); 1096 | 1097 | /*从左兄弟拿一个数据*/ 1098 | key(leaf)[0] = key(left)[left->children - 1]; 1099 | data(leaf)[0] = data(left)[left->children - 1]; 1100 | left->children--; 1101 | 1102 | /*更新父节点的键值*/ 1103 | key(parent)[parent_key_index] = key(leaf)[0]; 1104 | } 1105 | 1106 | /* 1107 | 左兄弟数据未过半,两两合并 1108 | */ 1109 | static void leaf_merge_into_left(struct bplus_tree *tree, struct bplus_node *leaf, struct bplus_node *left, int parent_key_index, int remove) 1110 | { 1111 | /*将key和data从leaf复制到left,不包括被删除的数据*/ 1112 | memmove(&key(left)[left->children], &key(leaf)[0], remove * sizeof(key_t)); 1113 | memmove(&data(left)[left->children], &data(leaf)[0], remove * sizeof(off_t)); 1114 | memmove(&key(left)[left->children + remove], &key(leaf)[remove + 1], (leaf->children - remove - 1) * sizeof(key_t)); 1115 | memmove(&data(left)[left->children + remove], &data(leaf)[remove + 1], (leaf->children - remove - 1) * sizeof(off_t)); 1116 | left->children += leaf->children - 1; 1117 | } 1118 | 1119 | /* 1120 | 从左兄弟拿一个数据,来保持平衡 1121 | struct bplus_tree *tree------------------B+树信息结构体 1122 | struct bplus_node *leaf------------------要执行删除操作和合并操作的叶子节点 1123 | struct bplus_node *right-----------------右兄弟 1124 | struct bplus_node *parent----------------父节点 1125 | int parent_key_index---------------------leaf在父节点的位置 1126 | int remove-------------------------------删除的数据在leaf的位置 1127 | */ 1128 | static void leaf_shift_from_right(struct bplus_tree *tree, struct bplus_node *leaf, struct bplus_node *right, struct bplus_node *parent, int parent_key_index) 1129 | { 1130 | /*leaf最后一个位置放right第一个数据*/ 1131 | key(leaf)[leaf->children] = key(right)[0]; 1132 | data(leaf)[leaf->children] = data(right)[0]; 1133 | leaf->children++; 1134 | 1135 | /*right左移*/ 1136 | memmove(&key(right)[0], &key(right)[1], (right->children - 1) * sizeof(key_t)); 1137 | memmove(&data(right)[0], &data(right)[1], (right->children - 1) * sizeof(off_t)); 1138 | right->children--; 1139 | 1140 | /*更新父节点的键值*/ 1141 | key(parent)[parent_key_index] = key(right)[0]; 1142 | } 1143 | 1144 | /* 1145 | 左兄弟数据未过半,两两合并 1146 | */ 1147 | static inline void leaf_merge_from_right(struct bplus_tree *tree, struct bplus_node *leaf, struct bplus_node *right) 1148 | { 1149 | memmove(&key(leaf)[leaf->children], &key(right)[0], right->children * sizeof(key_t)); 1150 | memmove(&data(leaf)[leaf->children], &data(right)[0], right->children * sizeof(off_t)); 1151 | leaf->children += right->children; 1152 | } 1153 | 1154 | /* 1155 | 叶子节点的简单删除操作 1156 | */ 1157 | static inline void leaf_simple_remove(struct bplus_tree *tree, struct bplus_node *leaf, int remove) 1158 | { 1159 | /*key和data左移覆盖被删除的key和data*/ 1160 | memmove(&key(leaf)[remove], &key(leaf)[remove + 1], (leaf->children - remove - 1) * sizeof(key_t)); 1161 | memmove(&data(leaf)[remove], &data(leaf)[remove + 1], (leaf->children - remove - 1) * sizeof(off_t)); 1162 | leaf->children--; 1163 | } 1164 | 1165 | /* 1166 | 叶子节点的删除操作 1167 | struct bplus_tree *tree-----------------B+树信息结构体 1168 | struct bplus_node *leaf-----------------要执行删除操作的叶子节点 1169 | key_t key-------------------------------要删除的键值 1170 | */ 1171 | static int leaf_remove(struct bplus_tree *tree, struct bplus_node *leaf, key_t key) 1172 | { 1173 | int remove = key_binary_search(leaf, key); 1174 | /*要删除的键值不存在*/ 1175 | if (remove < 0) { 1176 | return -1; 1177 | } 1178 | 1179 | /*节点所在的缓存位置*/ 1180 | int i = ((char *) leaf - tree->caches) / _block_size; 1181 | tree->used[i] = 1; 1182 | 1183 | /*父节点非法,即不存在父节点,要进行删除操作的叶子节点是根节点*/ 1184 | if (leaf->parent == INVALID_OFFSET) { 1185 | /*节点内只有1个数据*/ 1186 | if (leaf->children == 1) { 1187 | /* delete the only last node */ 1188 | assert(key == key(leaf)[0]); 1189 | tree->root = INVALID_OFFSET; 1190 | tree->level = 0; 1191 | /*删除节点*/ 1192 | node_delete(tree, leaf, NULL, NULL); 1193 | /*节点内有多个数据*/ 1194 | } else { 1195 | leaf_simple_remove(tree, leaf, remove); 1196 | node_flush(tree, leaf); 1197 | } 1198 | /*有父节点,删除后节点内数据过少,要进行合并操作*/ 1199 | } else if (leaf->children <= (_max_entries + 1) / 2) { 1200 | struct bplus_node *l_sib = node_fetch(tree, leaf->prev); 1201 | struct bplus_node *r_sib = node_fetch(tree, leaf->next); 1202 | struct bplus_node *parent = node_fetch(tree, leaf->parent); 1203 | 1204 | i = parent_key_index(parent, key(leaf)[0]); 1205 | 1206 | /*选择左兄弟合并*/ 1207 | if (sibling_select(l_sib, r_sib, parent, i) == LEFT_SIBLING) { 1208 | /*左兄弟节点内数据过半,无法合并,就拿一个数据过来*/ 1209 | if (l_sib->children > (_max_entries + 1) / 2) { 1210 | leaf_shift_from_left(tree, leaf, l_sib, parent, i, remove); 1211 | node_flush(tree, leaf); 1212 | node_flush(tree, l_sib); 1213 | node_flush(tree, r_sib); 1214 | node_flush(tree, parent); 1215 | /*左兄弟数据未过半,合并*/ 1216 | } else { 1217 | leaf_merge_into_left(tree, leaf, l_sib, i, remove); 1218 | /*删除无意义的leaf*/ 1219 | node_delete(tree, leaf, l_sib, r_sib); 1220 | /*更新父节点*/ 1221 | non_leaf_remove(tree, parent, i); 1222 | } 1223 | /*选择右兄弟合并*/ 1224 | } else { 1225 | leaf_simple_remove(tree, leaf, remove); 1226 | 1227 | /*右兄弟节点内数据过半,无法合并,就拿一个数据过来*/ 1228 | if (r_sib->children > (_max_entries + 1) / 2) { 1229 | leaf_shift_from_right(tree, leaf, r_sib, parent, i + 1); 1230 | /* flush leaves */ 1231 | node_flush(tree, leaf); 1232 | node_flush(tree, l_sib); 1233 | node_flush(tree, r_sib); 1234 | node_flush(tree, parent); 1235 | /*右兄弟数据未过半,合并*/ 1236 | } else { 1237 | leaf_merge_from_right(tree, leaf, r_sib); 1238 | /*删除无意义的leaf*/ 1239 | struct bplus_node *rr_sib = node_fetch(tree, r_sib->next); 1240 | node_delete(tree, r_sib, leaf, rr_sib); 1241 | node_flush(tree, l_sib); 1242 | /*更新父节点*/ 1243 | non_leaf_remove(tree, parent, i + 1); 1244 | } 1245 | } 1246 | /*有父节点,但删除后,节点内数据大于一半,不进行合并*/ 1247 | } else { 1248 | leaf_simple_remove(tree, leaf, remove); 1249 | node_flush(tree, leaf); 1250 | } 1251 | 1252 | return 0; 1253 | } 1254 | 1255 | /* 1256 | 删除节点 1257 | */ 1258 | static int bplus_tree_delete(struct bplus_tree *tree, key_t key) 1259 | { 1260 | struct bplus_node *node = node_seek(tree, tree->root); 1261 | while (node != NULL) { 1262 | /*叶子节点,直接进行删除操作*/ 1263 | if (is_leaf(node)) { 1264 | return leaf_remove(tree, node, key); 1265 | /*非叶子节点,继续循环递归查找*/ 1266 | } else { 1267 | int i = key_binary_search(node, key); 1268 | if (i >= 0) { 1269 | node = node_seek(tree, sub(node)[i + 1]); 1270 | } else { 1271 | i = -i - 1; 1272 | node = node_seek(tree, sub(node)[i]); 1273 | } 1274 | } 1275 | } 1276 | return -1; 1277 | } 1278 | 1279 | /* 1280 | 查找结点的入口 1281 | */ 1282 | long bplus_tree_get(struct bplus_tree *tree, key_t key) 1283 | { 1284 | return bplus_tree_search(tree, key); 1285 | } 1286 | 1287 | /* 1288 | 处理节点入口 1289 | 插入节点 1290 | 删除节点 1291 | */ 1292 | int bplus_tree_put(struct bplus_tree *tree, key_t key, long data) 1293 | { 1294 | if (data) { 1295 | return bplus_tree_insert(tree, key, data); 1296 | } else { 1297 | return bplus_tree_delete(tree, key); 1298 | } 1299 | } 1300 | 1301 | /* 1302 | 获取范围 1303 | */ 1304 | long bplus_tree_get_range(struct bplus_tree *tree, key_t key1, key_t key2) 1305 | { 1306 | long start = -1; 1307 | key_t min = key1 <= key2 ? key1 : key2; 1308 | key_t max = min == key1 ? key2 : key1; 1309 | 1310 | struct bplus_node *node = node_seek(tree, tree->root); 1311 | while (node != NULL) { 1312 | int i = key_binary_search(node, min); 1313 | if (is_leaf(node)) { 1314 | if (i < 0) { 1315 | i = -i - 1; 1316 | if (i >= node->children) { 1317 | node = node_seek(tree, node->next); 1318 | } 1319 | } 1320 | while (node != NULL && key(node)[i] <= max) { 1321 | start = data(node)[i]; 1322 | if (++i >= node->children) { 1323 | node = node_seek(tree, node->next); 1324 | i = 0; 1325 | } 1326 | } 1327 | break; 1328 | } else { 1329 | if (i >= 0) { 1330 | node = node_seek(tree, sub(node)[i + 1]); 1331 | } else { 1332 | i = -i - 1; 1333 | node = node_seek(tree, sub(node)[i]); 1334 | } 1335 | } 1336 | } 1337 | 1338 | return start; 1339 | } 1340 | 1341 | /* 1342 | 打开B+树 1343 | 返回fd 1344 | */ 1345 | int bplus_open(char *filename) 1346 | { 1347 | return open(filename, O_CREAT | O_RDWR, 0644); 1348 | } 1349 | 1350 | /* 1351 | 关闭B+树 1352 | */ 1353 | void bplus_close(int fd) 1354 | { 1355 | close(fd); 1356 | } 1357 | 1358 | /* 1359 | 字符串转16进制 1360 | */ 1361 | static off_t str_to_hex(char *c, int len) 1362 | { 1363 | off_t offset = 0; 1364 | while (len-- > 0) { 1365 | if (isdigit(*c)) { 1366 | offset = offset * 16 + *c - '0'; 1367 | } else if (isxdigit(*c)) { 1368 | if (islower(*c)) { 1369 | offset = offset * 16 + *c - 'a' + 10; 1370 | } else { 1371 | offset = offset * 16 + *c - 'A' + 10; 1372 | } 1373 | } 1374 | c++; 1375 | } 1376 | return offset; 1377 | } 1378 | 1379 | /* 1380 | 16进制转字符串 1381 | */ 1382 | static inline void hex_to_str(off_t offset, char *buf, int len) 1383 | { 1384 | const static char *hex = "0123456789ABCDEF"; 1385 | while (len-- > 0) { 1386 | buf[len] = hex[offset & 0xf]; 1387 | offset >>= 4; 1388 | } 1389 | } 1390 | 1391 | /* 1392 | 加载文件数据,每16位记录一个信息 1393 | 如果读取到数据,即len>0,返回数据 1394 | 如果没有读到数据,即len<=0,返回INVALID_OFFSET 1395 | */ 1396 | static inline off_t offset_load(int fd) 1397 | { 1398 | char buf[ADDR_STR_WIDTH]; 1399 | ssize_t len = read(fd, buf, sizeof(buf)); 1400 | return len > 0 ? str_to_hex(buf, sizeof(buf)) : INVALID_OFFSET; 1401 | } 1402 | 1403 | /* 1404 | 存储B+相关数据 1405 | */ 1406 | static inline ssize_t offset_store(int fd, off_t offset) 1407 | { 1408 | char buf[ADDR_STR_WIDTH]; 1409 | hex_to_str(offset, buf, sizeof(buf)); 1410 | return write(fd, buf, sizeof(buf)); 1411 | } 1412 | 1413 | /* 1414 | B+树初始化 1415 | char *filename----------文件名 1416 | int block_size----------文件大小 1417 | 返回--------------------B+树头节点结构体指针 1418 | */ 1419 | struct bplus_tree *bplus_tree_init(char *filename, int block_size) 1420 | { 1421 | int i; 1422 | struct bplus_node node; 1423 | 1424 | /*文件名过长*/ 1425 | if (strlen(filename) >= 1024) { 1426 | fprintf(stderr, "Index file name too long!\n"); 1427 | return NULL; 1428 | } 1429 | 1430 | /*文件大小不是2的平方*/ 1431 | if ((block_size & (block_size - 1)) != 0) { 1432 | fprintf(stderr, "Block size must be pow of 2!\n"); 1433 | return NULL; 1434 | } 1435 | 1436 | /*文件容量太小*/ 1437 | if (block_size < (int) sizeof(node)) { 1438 | fprintf(stderr, "block size is too small for one node!\n"); 1439 | return NULL; 1440 | } 1441 | 1442 | _block_size = block_size; 1443 | _max_order = (block_size - sizeof(node)) / (sizeof(key_t) + sizeof(off_t)); 1444 | _max_entries = (block_size - sizeof(node)) / (sizeof(key_t) + sizeof(long)); 1445 | 1446 | /*文件容量太小*/ 1447 | if (_max_order <= 2) { 1448 | fprintf(stderr, "block size is too small for one node!\n"); 1449 | return NULL; 1450 | } 1451 | 1452 | /*为B+树信息节点分配内存*/ 1453 | struct bplus_tree *tree = calloc(1, sizeof(*tree)); 1454 | assert(tree != NULL); 1455 | list_init(&tree->free_blocks); 1456 | strcpy(tree->filename, filename); 1457 | 1458 | /* 1459 | 加载boot文件,可读可写 1460 | tree->filename变为.boot 1461 | 首次运行不存在 1462 | 得到信息节点的信息,每16位记录一个信息 1463 | root----------------B+树根节点在.index中的偏移量 1464 | block_size----------分配的空间大小 1465 | file_size-----------实际空间大小 1466 | */ 1467 | int fd = open(strcat(tree->filename, ".boot"), O_RDWR, 0644); 1468 | if (fd >= 0) { 1469 | tree->root = offset_load(fd); 1470 | _block_size = offset_load(fd); 1471 | tree->file_size = offset_load(fd); 1472 | 1473 | /*加载freeblocks空闲数据块*/ 1474 | while ((i = offset_load(fd)) != INVALID_OFFSET) { 1475 | struct free_block *block = malloc(sizeof(*block)); 1476 | assert(block != NULL); 1477 | block->offset = i; 1478 | list_add(&block->link, &tree->free_blocks); 1479 | } 1480 | close(fd); 1481 | } else { 1482 | tree->root = INVALID_OFFSET; 1483 | _block_size = block_size; 1484 | tree->file_size = 0; 1485 | } 1486 | 1487 | /*设置节点内关键字和数据最大个数*/ 1488 | _max_order = (_block_size - sizeof(node)) / (sizeof(key_t) + sizeof(off_t)); 1489 | _max_entries = (_block_size - sizeof(node)) / (sizeof(key_t) + sizeof(long)); 1490 | printf("config node order:%d and leaf entries:%d and _block_size:%d\n", _max_order, _max_entries,_block_size); 1491 | 1492 | /*申请和初始化节点缓存*/ 1493 | tree->caches = malloc(_block_size * MIN_CACHE_NUM); 1494 | 1495 | /*打开index文件,首次运行不存在,创建index文件=*/ 1496 | tree->fd = bplus_open(filename); 1497 | assert(tree->fd >= 0); 1498 | return tree; 1499 | } 1500 | 1501 | /* 1502 | B+树的关闭操作 1503 | 打开.boot文件 1504 | */ 1505 | void bplus_tree_deinit(struct bplus_tree *tree) 1506 | { 1507 | /*向.boot写入B+树的3个配置数据*/ 1508 | int fd = open(tree->filename, O_CREAT | O_RDWR, 0644); 1509 | assert(fd >= 0); 1510 | assert(offset_store(fd, tree->root) == ADDR_STR_WIDTH); 1511 | assert(offset_store(fd, _block_size) == ADDR_STR_WIDTH); 1512 | assert(offset_store(fd, tree->file_size) == ADDR_STR_WIDTH); 1513 | 1514 | /*将空闲块存储在文件中以备将来重用*/ 1515 | struct list_head *pos, *n; 1516 | list_for_each_safe(pos, n, &tree->free_blocks) { 1517 | list_del(pos); 1518 | struct free_block *block = list_entry(pos, struct free_block, link); 1519 | assert(offset_store(fd, block->offset) == ADDR_STR_WIDTH); 1520 | free(block); 1521 | } 1522 | 1523 | bplus_close(tree->fd); 1524 | free(tree->caches); 1525 | free(tree); 1526 | } 1527 | 1528 | 1529 | /**以下部分是绘图操作**/ 1530 | 1531 | /*B+树的最大层数*/ 1532 | #define MAX_LEVEL 10 1533 | 1534 | /* 1535 | 积压节点 1536 | off_t offset-------------------偏移量 1537 | int next_sub_idx---------------下一个数据在节点内的位置 1538 | */ 1539 | struct node_backlog { 1540 | off_t offset; 1541 | int next_sub_idx; 1542 | }; 1543 | 1544 | /* 1545 | 返回节点的children个数 1546 | */ 1547 | static inline int children(struct bplus_node *node) 1548 | { 1549 | assert(!is_leaf(node)); 1550 | return node->children; 1551 | } 1552 | 1553 | /* 1554 | 绘制键值 1555 | */ 1556 | static void node_key_dump(struct bplus_node *node) 1557 | { 1558 | int i; 1559 | /*叶子节点的键值比非叶子节点的键值多一个*/ 1560 | if (is_leaf(node)) { 1561 | printf("leaf:"); 1562 | for (i = 0; i < node->children; i++) { 1563 | printf(" %d", key(node)[i]); 1564 | } 1565 | } else { 1566 | printf("node:"); 1567 | for (i = 0; i < node->children - 1; i++) { 1568 | printf(" %d", key(node)[i]); 1569 | } 1570 | } 1571 | printf("\n"); 1572 | } 1573 | 1574 | /* 1575 | 绘图 1576 | struct bplus_tree *tree-------------------------B+树信息结构体 1577 | struct bplus_node *node-------------------------B+树当前节点 1578 | struct node_backlog *stack----------------------存放节点的栈 1579 | int level---------------------------------------节点所在层数 1580 | */ 1581 | static void draw(struct bplus_tree *tree, struct bplus_node *node, struct node_backlog *stack, int level) 1582 | { 1583 | int i; 1584 | for (i = 1; i < level; i++) { 1585 | if (i == level - 1) { 1586 | printf("%-8s", "+-------"); 1587 | } else { 1588 | if (stack[i - 1].offset != INVALID_OFFSET) { 1589 | printf("%-8s", "|"); 1590 | } else { 1591 | printf("%-8s", " "); 1592 | } 1593 | } 1594 | } 1595 | node_key_dump(node); 1596 | } 1597 | 1598 | /* 1599 | 绘图入口,用栈实现遍历 1600 | */ 1601 | void bplus_tree_dump(struct bplus_tree *tree) 1602 | { 1603 | /* 1604 | p_nbl------------------层节点 1605 | nbl_stack--------------栈 1606 | top--------------------栈顶 1607 | */ 1608 | int level = 0; 1609 | struct bplus_node *node = node_seek(tree, tree->root); 1610 | struct node_backlog *p_nbl = NULL; 1611 | struct node_backlog nbl_stack[MAX_LEVEL]; 1612 | struct node_backlog *top = nbl_stack; 1613 | 1614 | for (; ;) { 1615 | if (node != NULL) { 1616 | /*sub_idx用于定位非叶子节点中的指针*/ 1617 | int sub_idx = p_nbl != NULL ? p_nbl->next_sub_idx : 0; 1618 | /*重置每个循环*/ 1619 | p_nbl = NULL; 1620 | 1621 | /*积压节点,每一层一个节点*/ 1622 | if (is_leaf(node) || sub_idx + 1 >= children(node)) { 1623 | top->offset = INVALID_OFFSET; 1624 | top->next_sub_idx = 0; 1625 | } else { 1626 | top->offset = node->self; 1627 | top->next_sub_idx = sub_idx + 1; 1628 | } 1629 | 1630 | /*指向nbl_stack的下一个元素*/ 1631 | top++; 1632 | /*查找下一层数据*/ 1633 | level++; 1634 | 1635 | /*绘制第一次通过时的节点*/ 1636 | if (sub_idx == 0) { 1637 | draw(tree, node, nbl_stack, level); 1638 | } 1639 | 1640 | /*向下移动*/ 1641 | node = is_leaf(node) ? NULL : node_seek(tree, sub(node)[sub_idx]); 1642 | } else { 1643 | p_nbl = top == nbl_stack ? NULL : --top; 1644 | if (p_nbl == NULL) { 1645 | /*遍历结束*/ 1646 | break; 1647 | } 1648 | node = node_seek(tree, p_nbl->offset); 1649 | level--; 1650 | } 1651 | } 1652 | } 1653 | -------------------------------------------------------------------------------- /bplustree.h: -------------------------------------------------------------------------------- 1 | #ifndef _BPLUS_TREE_H 2 | #define _BPLUS_TREE_H 3 | 4 | /* 5 | 最少缓冲数目,缓冲最少需要5个 6 | 节点自身,左兄弟节点,右兄弟节点,兄弟的兄弟节点,父节点 7 | */ 8 | #define MIN_CACHE_NUM 5 9 | 10 | /*得到struct bplus_tree内free_blocks的偏移量*/ 11 | #define list_entry(ptr, type, member) \ 12 | ((type *)((char *)(ptr) - (size_t)(&((type *)0)->member))) 13 | 14 | /*得到struct bplus_tree内free_blocks->next的偏移量*/ 15 | #define list_first_entry(ptr, type, member) \ 16 | list_entry((ptr)->next, type, member) 17 | 18 | /*得到struct bplus_tree内free_blocks->prev的偏移量*/ 19 | #define list_last_entry(ptr, type, member) \ 20 | list_entry((ptr)->prev, type, member) 21 | 22 | #define list_for_each(pos, head) \ 23 | for (pos = (head)->next; pos != (head); pos = pos->next) 24 | 25 | #define list_for_each_safe(pos, n, head) \ 26 | for (pos = (head)->next, n = pos->next; pos != (head); \ 27 | pos = n, n = pos->next) 28 | 29 | typedef int key_t; 30 | 31 | /* 32 | 链表头部 33 | 记录前一个节点和后一个节点 34 | */ 35 | struct list_head { 36 | struct list_head *prev, *next; 37 | }; 38 | 39 | /* 40 | 链表头部初始化 41 | 前一个节点和后一个节点均指向自己 42 | */ 43 | static inline void list_init(struct list_head *link) 44 | { 45 | link->prev = link; 46 | link->next = link; 47 | } 48 | 49 | /* 50 | 添加一个节点 51 | */ 52 | static inline void __list_add(struct list_head *link, struct list_head *prev, struct list_head *next) 53 | { 54 | link->next = next; 55 | link->prev = prev; 56 | next->prev = link; 57 | prev->next = link; 58 | } 59 | 60 | 61 | /* 62 | 删除一个节点 63 | */ 64 | static inline void __list_del(struct list_head *prev, struct list_head *next) 65 | { 66 | prev->next = next; 67 | next->prev = prev; 68 | } 69 | 70 | /* 71 | 添加一个节点 72 | */ 73 | static inline void list_add(struct list_head *link, struct list_head *prev) 74 | { 75 | __list_add(link, prev, prev->next); 76 | } 77 | 78 | /* 79 | 添加头节点 80 | */ 81 | static inline void list_add_tail(struct list_head *link, struct list_head *head) 82 | { 83 | __list_add(link, head->prev, head); 84 | } 85 | 86 | /* 87 | 从链表中删除一个节点 88 | 并初始化被删除的节点 89 | */ 90 | static inline void list_del(struct list_head *link) 91 | { 92 | __list_del(link->prev, link->next); 93 | list_init(link); 94 | } 95 | 96 | /* 97 | 判断是否为空列表 98 | */ 99 | static inline int list_empty(const struct list_head *head) 100 | { 101 | return head->next == head; 102 | } 103 | 104 | /* 105 | B+树节点结构体 106 | 偏移量指在.index文件中的偏移量,用文件的大小来设置 107 | B+树叶子节点后面会跟随key和data 108 | B+树非叶子节点后面会更随key和ptr 109 | off_t-----------------------------------32位long int类型 110 | off_t self------------------------------记录自身节点偏移量 111 | off_t parent----------------------------记录父亲节点偏移量 112 | off_t prev------------------------------记录上一个节点偏移量 113 | off_t next------------------------------记录下一个节点偏移量 114 | int type--------------------------------记录节点类型:叶子节点或者非叶子节点 115 | int children----------------------------如果是叶子节点记录节点内键值个数,不是就记录分支数量(即指针ptr的数量) 116 | */ 117 | typedef struct bplus_node { 118 | off_t self; 119 | off_t parent; 120 | off_t prev; 121 | off_t next; 122 | int type; 123 | /* If leaf node, it specifies count of entries, 124 | * if non-leaf node, it specifies count of children(branches) */ 125 | int children; 126 | } bplus_node; 127 | 128 | /*B+树非叶子节点*/ 129 | /* 130 | struct bplus_non_leaf { 131 | off_t self; 132 | off_t parent; 133 | off_t prev; 134 | off_t next; 135 | int type; 136 | int children; 137 | key_t key[BPLUS_MAX_ORDER - 1]; 138 | off_t sub_ptr[BPLUS_MAX_ORDER]; 139 | }; 140 | */ 141 | 142 | /*B+树叶子节点*/ 143 | /* 144 | struct bplus_leaf { 145 | off_t self; 146 | off_t parent; 147 | off_t prev; 148 | off_t next; 149 | int type; 150 | int entries; 151 | key_t key[BPLUS_MAX_ENTRIES]; 152 | long data[BPLUS_MAX_ENTRIES]; 153 | }; 154 | */ 155 | 156 | /* 157 | struct list_head link---------链表头部,指向上一个节点和下一个节点 158 | off_t offset------------------记录偏移地址 159 | */ 160 | typedef struct free_block { 161 | struct list_head link; 162 | off_t offset; 163 | } free_block; 164 | 165 | /* 166 | 定义B+树信息结构体 167 | char *caches------------------------节点缓存,存放B+树节点的内存缓冲,最少5个,包括:自身节点,父节点,左兄弟节点,右兄弟节点,兄弟的兄弟节点 168 | int used[MIN_CACHE_NUM]-------------可用缓存个数 169 | char filename[1024];----------------文件名字 170 | int fd------------------------------文件描述符指向index 171 | int level---------------------------文件等级 172 | off_t root--------------------------B+树根节点 173 | off_t file_size---------------------文件大小 174 | struct list_head free_blocks--------链表指针 175 | */ 176 | struct bplus_tree { 177 | char *caches; 178 | int used[MIN_CACHE_NUM]; 179 | char filename[1024]; 180 | int fd; 181 | int level; 182 | off_t root; 183 | off_t file_size; 184 | struct list_head free_blocks; 185 | }; 186 | 187 | /* 188 | 以下是B+树库所提供的外部接口,static函数无法在其他文件使用,需通过以下函数调用 189 | bplus_tree_dump-----------------------绘图 190 | bplus_tree_get------------------------查找 191 | bplus_tree_put------------------------插入和删除 192 | bplus_tree_get_range------------------范围查找 193 | bplus_tree_init-----------------------B+树初始化 194 | bplus_tree_deinit---------------------B+树关闭操作 195 | bplus_open----------------------------B+树开启操作 196 | bplus_close---------------------------B+树关闭操作 197 | */ 198 | void bplus_tree_dump(struct bplus_tree *tree); 199 | long bplus_tree_get(struct bplus_tree *tree, key_t key); 200 | int bplus_tree_put(struct bplus_tree *tree, key_t key, long data); 201 | long bplus_tree_get_range(struct bplus_tree *tree, key_t key1, key_t key2); 202 | struct bplus_tree *bplus_tree_init(char *filename, int block_size); 203 | void bplus_tree_deinit(struct bplus_tree *tree); 204 | int bplus_open(char *filename); 205 | void bplus_close(int fd); 206 | 207 | /*_BPLUS_TREE_H*/ 208 | #endif 209 | -------------------------------------------------------------------------------- /bplustree_demo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include"bplustree.h" 8 | 9 | /* 10 | B+树设置结构体 11 | char filename[1024]----文件名字 12 | int block_size---------文件大小 13 | */ 14 | struct bplus_tree_config { 15 | char filename[1024]; 16 | int block_size; 17 | }; 18 | 19 | /*计时器结构体,定义在*/ 20 | struct timespec t1,t2; 21 | 22 | /* 23 | 刷新stdin缓冲区 24 | */ 25 | static void stdin_flush(void) 26 | { 27 | int c; 28 | while ((c = getchar()) != '\n' && c != EOF) { 29 | continue; 30 | } 31 | } 32 | 33 | /* 34 | B+树设置 35 | 设置索引文件的地址和名字 36 | 设置索引文件大小 37 | struct bplus_tree_config *config------设置结构体 38 | 返回----------------------------------正确返回0,错误返回-1 39 | */ 40 | static int bplus_tree_setting(struct bplus_tree_config *config) 41 | { 42 | int i, size, ret = 0, again = 1; 43 | 44 | printf("\n-- B+tree setting...\n"); 45 | /*设置.index文件名和路径*/ 46 | while (again) { 47 | printf("Set data index file name (e.g. /tmp/data.index): "); 48 | /*获取一个字符,从stdin流中删除*/ 49 | switch (i = getchar()) { 50 | /*获取失败*/ 51 | case EOF: 52 | printf("\n"); 53 | /*'q'退出*/ 54 | case 'q': 55 | return -1; 56 | /*换行符,文件名默认*/ 57 | case '\n': 58 | strcpy(config->filename, "/tmp/data.index"); 59 | again = 0; 60 | break; 61 | /*默认:用户输入文件名*/ 62 | default: 63 | /*将getchar拿走的字符放回去*/ 64 | ungetc(i, stdin); 65 | /*输入文件名和路径*/ 66 | ret = fscanf(stdin, "%s", config->filename); 67 | /*出错,再来一遍循环*/ 68 | if (!ret || getchar() != '\n') { 69 | /*刷新缓冲区*/ 70 | stdin_flush(); 71 | again = 1; 72 | } else { 73 | again = 0; 74 | } 75 | break; 76 | } 77 | } 78 | 79 | again = 1; 80 | /*设置区块大小,区块存放node、key、data、ptr*/ 81 | while (again) { 82 | printf("Set index file block size (bytes, power of 2, e.g. 256): "); 83 | switch (i = getchar()) { 84 | case EOF: 85 | printf("\n"); 86 | case 'q': 87 | return -1; 88 | /*换行符,默认区块大小256*/ 89 | case '\n': 90 | config->block_size = 256; 91 | again = 0; 92 | break; 93 | /*输入区块大小*/ 94 | default: 95 | ungetc(i, stdin); 96 | ret = fscanf(stdin, "%d", &size); 97 | /*出错,刷新缓冲区,再来一遍循环*/ 98 | if (!ret || getchar() != '\n') { 99 | stdin_flush(); 100 | again = 1; 101 | /*等于小小于0,或大小不是2的倍数*/ 102 | } else if (size <= 0 || (size & (size - 1)) != 0) { 103 | fprintf(stderr, "Block size must be positive and pow of 2!\n"); 104 | again = 1; 105 | } else if (size <= 0 || (size & (size - 1)) != 0) { 106 | again = 1; 107 | /*最小容量包括:B+树节点,3个及以上键值和偏移量*/ 108 | } else { 109 | int order = (size - sizeof(struct bplus_node)) / (sizeof(key_t) + sizeof(off_t)); 110 | if (size < (int) sizeof(struct bplus_node) || order <= 2) { 111 | fprintf(stderr, "block size is too small for one node!\n"); 112 | again = 1; 113 | } else { 114 | config->block_size = size; 115 | again = 0; 116 | } 117 | } 118 | break; 119 | } 120 | } 121 | 122 | return ret; 123 | } 124 | 125 | /* 126 | 执行选定的操作 127 | 插入 128 | 删除 129 | 查找 130 | */ 131 | static void _proc(struct bplus_tree *tree, char op, int n) 132 | { 133 | switch (op) { 134 | case 'i': 135 | bplus_tree_put(tree, n, n); 136 | break; 137 | case 'r': 138 | bplus_tree_put(tree, n, 0); 139 | break; 140 | case 's': 141 | printf("key:%d data_index:%ld\n", n, bplus_tree_get(tree, n)); 142 | break; 143 | default: 144 | break; 145 | } 146 | } 147 | 148 | /* 149 | 读取输入的数字,判断要执行的操作 150 | */ 151 | static int number_process(struct bplus_tree *tree, char op) 152 | { 153 | int c, n = 0; 154 | int start = 0, end = 0; 155 | 156 | while ((c = getchar()) != EOF) { 157 | /*空格||tab||换行*/ 158 | if (c == ' ' || c == '\t' || c == '\n') { 159 | if (start != 0) { 160 | if (n >= 0) { 161 | end = n; 162 | } else { 163 | n = 0; 164 | } 165 | } 166 | 167 | /*范围操作*/ 168 | if (start != 0 && end != 0) { 169 | /*从小到大*/ 170 | if (start <= end) { 171 | for (n = start; n <= end; n++) { 172 | _proc(tree, op, n); 173 | } 174 | /*从大到小*/ 175 | } else { 176 | for (n = start; n >= end; n--) { 177 | _proc(tree, op, n); 178 | } 179 | } 180 | /*单个数据操作*/ 181 | } else { 182 | if (n != 0) { 183 | _proc(tree, op, n); 184 | } 185 | } 186 | 187 | n = 0; 188 | start = 0; 189 | end = 0; 190 | 191 | if (c == '\n') { 192 | return 0; 193 | } else { 194 | continue; 195 | } 196 | } 197 | 198 | /*得到单个数字*/ 199 | if (c >= '0' && c <= '9') { 200 | n = n * 10 + c - '0'; 201 | /*得到范围*/ 202 | } else if (c == '-' && n != 0) { 203 | start = n; 204 | n = 0; 205 | /*删除字母*/ 206 | } else { 207 | n = 0; 208 | start = 0; 209 | end = 0; 210 | while ((c = getchar()) != ' ' && c != '\t' && c != '\n') { 211 | continue; 212 | } 213 | ungetc(c, stdin); 214 | } 215 | } 216 | 217 | printf("\n"); 218 | return -1; 219 | } 220 | 221 | /* 222 | 显示帮助文档 223 | */ 224 | static void command_tips(void) 225 | { 226 | printf("i: Insert key. e.g. i 1 4-7 9\n"); 227 | printf("r: Remove key. e.g. r 1-100\n"); 228 | printf("s: Search by key. e.g. s 41-60\n"); 229 | printf("d: Dump the tree structure.\n"); 230 | printf("q: quit.\n"); 231 | } 232 | 233 | /* 234 | 命令进程 235 | q---------------------退出 236 | h---------------------显示帮助文档 237 | d---------------------绘图 238 | i---------------------插入节点 239 | r---------------------删除节点 240 | s---------------------查找节点 241 | \n--------------------提示输入下一次命令 242 | */ 243 | static void command_process(struct bplus_tree *tree) 244 | { 245 | int c; 246 | printf("Please input command (Type 'h' for help): "); 247 | for (; ;) { 248 | switch (c = getchar()) { 249 | case EOF: 250 | printf("\n"); 251 | case 'q': 252 | return; 253 | case 'h': 254 | command_tips(); 255 | break; 256 | case 'd': 257 | /*计时器启动*/ 258 | clock_gettime(CLOCK_MONOTONIC,&t1); 259 | bplus_tree_dump(tree); 260 | /*计时器结束*/ 261 | clock_gettime(CLOCK_MONOTONIC,&t2); 262 | /*输出耗时*/ 263 | printf("This operation takes time:%lf second\n",((t2.tv_sec-t1.tv_sec)*pow(10,9)+t2.tv_nsec-t1.tv_nsec)/pow(10,9)); 264 | break; 265 | case 'i': 266 | case 'r': 267 | case 's': 268 | /*计时器启动*/ 269 | clock_gettime(CLOCK_MONOTONIC,&t1); 270 | if (number_process(tree, c) < 0) { 271 | return; 272 | } 273 | /*计时器结束*/ 274 | clock_gettime(CLOCK_MONOTONIC,&t2); 275 | /*输出耗时*/ 276 | printf("This operation takes time:%lf second\n",((t2.tv_sec-t1.tv_sec)*pow(10,9)+t2.tv_nsec-t1.tv_nsec)/pow(10,9)); 277 | case '\n': 278 | printf("Please input command (Type 'h' for help): "); 279 | default: 280 | break; 281 | } 282 | } 283 | } 284 | 285 | int main(void) 286 | { 287 | /*声明B+树设置*/ 288 | struct bplus_tree_config config; 289 | /*定义一个B+树信息结构体*/ 290 | struct bplus_tree *tree = NULL; 291 | while (tree == NULL) { 292 | /*设置B+树*/ 293 | if (bplus_tree_setting(&config) < 0) { 294 | return 0; 295 | } 296 | /* 297 | 初始化索引,将config的值赋值给tree 298 | 首次运行创建.index文件 299 | 再次运行会将.boot内保存的free_blocks赋值给tree 300 | */ 301 | tree = bplus_tree_init(config.filename, config.block_size); 302 | } 303 | command_process(tree); 304 | bplus_tree_deinit(tree); 305 | 306 | return 0; 307 | } 308 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | bplustree_demo.out:bplustree.o bplustree_demo.o 2 | gcc *.o -o bplustree_demo.out 3 | 4 | bplustree.o:bplustree.c 5 | gcc -c bplustree.c -o bplustree.o 6 | 7 | bplustree_demo.o:bplustree_demo.c 8 | gcc -c bplustree_demo.c -o bplustree_demo.o 9 | 10 | .PHONY:clean 11 | clean: 12 | rm -rf *.o --------------------------------------------------------------------------------