11

一起做个简单的数据库(十一):B树的递归搜索

 4 years ago
source link: http://dockone.io/article/9941
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

用C语言从零开始实现SQLite clone系列:

  1. REPL的介绍和设置
  2. 世上最简单的SQL编译器和虚拟机
  3. 一个在内存中仅能做追加操作的单表数据库
  4. 第一次测试 (含bug处理)
  5. 持久化存储
  6. The Cursor Abstraction
  7. B树介绍
  8. B树叶子节点的格式
  9. 二进制查询和重复键
  10. 叶子节点的拆分

上一篇结束于在第15行插入时候的错误:

db > insert 15 user15 [email protected]

Need to implement searching an internal node

首先,用新的函数代替旧的

if (get_node_type(root_node) == NODE_LEAF) {

 return leaf_node_find(table, root_page_num, key);

} else {

-    printf("Need to implement searching an internal node\n");

-    exit(EXIT_FAILURE);

+    return internal_node_find(table, root_page_num, key);

}

}

此函数将执行二进制搜索以查找应包含给定键的子级。请记住每个子指针右边的键是该子指针包含的最大键。

qqM36nf.jpg!web

因此,我们的二进制搜索会比对和查找子指针右侧的键:

+Cursor* internal_node_find(Table* table, uint32_t page_num, uint32_t key) {

+  void* node = get_page(table->pager, page_num);

+  uint32_t num_keys = *internal_node_num_keys(node);

+

+  /* Binary search to find index of child to search */

+  uint32_t min_index = 0;

+  uint32_t max_index = num_keys; /* there is one more child than key */

+

+  while (min_index != max_index) {

+    uint32_t index = (min_index + max_index) / 2;

+    uint32_t key_to_right = *internal_node_key(node, index);

+    if (key_to_right >= key) {

+      max_index = index;

+    } else {

+      min_index = index + 1;

+    }

+  }

同时也请记住内部节点的子节点可以是叶子节点也可以是内部节点。当我们找到了正确的子节点,调用合适的函数:

+  uint32_t child_num = *internal_node_child(node, min_index);

+  void* child = get_page(table->pager, child_num);

+  switch (get_node_type(child)) {

+    case NODE_LEAF:

+      return leaf_node_find(table, child_num, key);

+    case NODE_INTERNAL:

+      return internal_node_find(table, child_num, key);

+  }

+}

测试

现在在多节点B树中插入键不会再有报错。我们可以升级一下我们的测试代码

"    - 12",

   "    - 13",

   "    - 14",

-      "db > Need to implement searching an internal node",

+      "db > Executed.",

+      "db > ",

 ])

end

我认为是时候我们再重新看一下另一个插入1400行的测试了,这个测试目前还有报错,但是是个新的错误。目前,当程序崩溃时我们的测试不能很好地处理它。如果发生这种情况,请仅使用到目前为止的输出来做判断(let’s just use the output we’ve gotten so far:):

raw_output = nil

 IO.popen("./db test.db", "r+") do |pipe|

   commands.each do |command|

-        pipe.puts command

+        begin

+          pipe.puts command

+        rescue Errno::EPIPE

+          break

+        end

   end



   pipe.close_write

这表明报错是我们的1400行测试产生的:

end

 script << ".exit"

 result = run_script(script)

-    expect(result[-2]).to eq('db > Error: Table full.')

+    expect(result.last(2)).to match_array([

+      "db > Executed.",

+      "db > Need to implement updating parent after split",

+    ])

end

我们下一篇来解决它!

原文链接: Part 11 - Recursively Searching the B-Tree (翻译:吴世曦)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK