实现一个简单的Database9(译文)

浅析开源内存数据库Fastdb FastDB支持具有类似SQL语法的查询语言。FastDB使用的符号在面向对象编程中比在关系数据库中更受欢迎。表行被视为对象实例,表是这些对象的类。与SQL不同,FastDB面向的是使用对象,而不是SQL元组。因此,每次查询执行的结果都是一个类的一组对象。FastDB查询语言与标准SQL的主要区别在于:1、 没有几个表和嵌套子查询的联接。查询总是从一个表中返回一组对象。2、 标准C类型用于原子表列。3、 除了空引用之外,没有空值。我完全同意C.J.Date对三值逻辑的批评,以及他使用默认值的建议。 阅读详情
  • GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。
  • GreatSQL是MySQL的国产分支版本,使用上与MySQL一致。
  • 作者: 花家舍
  • 文章来源:GreatSQL社区原创

前文回顾


译注:cstack在github维护了一个简单的、类似sqlite的数据库实现,通过这个简单的项目,可以很好的理解数据库是如何运行的。本文是第九篇,主要是实现B-tree的二叉搜索并解决主键重复问题

Part 9 二叉搜索与主键重复

上次注意到我们的 B 树存储 key 时仍然是非排序的。现在我们来解决这个问题,并检测和拒绝主键的重复(插入)。

现在我们的 execute_insert() 函数在插入时,选择的位置是在表的结尾处。作为替换,我们需要搜索表(树)中正确的插入位置,然后把 key 插入到这个位置上。如果 key 在这个位置上已经存在,那么就返回(键重复)报错。

ExecuteResult execute_insert(Statement* statement, Table* table) {
   void* node = get_page(table->pager, table->root_page_num);
-  if ((*leaf_node_num_cells(node) >= LEAF_NODE_MAX_CELLS)) {
+  uint32_t num_cells = (*leaf_node_num_cells(node));
+  if (num_cells >= LEAF_NODE_MAX_CELLS) {
     return EXECUTE_TABLE_FULL;
   }

   Row* row_to_insert = &(statement->row_to_insert);
-  Cursor* cursor = table_end(table);
+  uint32_t key_to_insert = row_to_insert->id;
+  Cursor* cursor = table_find(table, key_to_insert);
+
+  if (cursor->cell_num < num_cells) {
+    uint32_t key_at_index = *leaf_node_key(node, cursor->cell_num);
+    if (key_at_index == key_to_insert) {
+      return EXECUTE_DUPLICATE_KEY;
+    }
+  }

   leaf_node_insert(cursor, row_to_insert->id, row_to_insert);

这样的话,我们就不再需要 table_end() 函数了。

-Cursor* table_end(Table* table) {
-  Cursor* cursor = malloc(sizeof(Cursor));
-  cursor->table = table;
-  cursor->page_num = table->root_page_num;
-
-  void* root_node = get_page(table->pager, table->root_page_num);
-  uint32_t num_cells = *leaf_node_num_cells(root_node);
-  cursor->cell_num = num_cells;
-  cursor->end_of_table = true;
-
-  return cursor;
-}

我们用一个方法替换 table_end() 函数,方法实现使用给定的 key 来搜索 Btree。

+/*
+Return the position of the given key.
+If the key is not present, return the position
+where it should be inserted
+*/
+Cursor* table_find(Table* table, uint32_t key) {
+  uint32_t root_page_num = table->root_page_num;
+  void* root_node = get_page(table->pager, root_page_num);
+
+  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);
+  }
+}

我先把内部节点实现的分支存根,因为我还没有实现内部节点(internal node)。我们可以在叶子节点中使用二叉搜索法来进行搜索。

+Cursor* leaf_node_find(Table* table, uint32_t page_num, uint32_t key) {
+  void* node = get_page(table->pager, page_num);
+  uint32_t num_cells = *leaf_node_num_cells(node);
+
+  Cursor* cursor = malloc(sizeof(Cursor));
+  cursor->table = table;
+  cursor->page_num = page_num;
+
+  // Binary search
+  uint32_t min_index = 0;
+  uint32_t one_past_max_index = num_cells;
+  while (one_past_max_index != min_index) {
+    uint32_t index = (min_index + one_past_max_index) / 2;
+    uint32_t key_at_index = *leaf_node_key(node, index);
+    if (key == key_at_index) {
+      cursor->cell_num = index;
+      return cursor;
+    }
+    if (key < key_at_index) {
+      one_past_max_index = index;
+    } else {
+      min_index = index + 1;
+    }
+  }
+
+  cursor->cell_num = min_index;
+  return cursor;
+}

这将返回:

  • key 的位置
  • 如果我们需要插入一个新的 key,需要移动 key 的话,返回这个 key 的位置
  • 超出最后一个 key 的位置

因为我们现在会检查节点的类型,所以需要一个函数在节点中获取和设置节点的类型值。

+NodeType get_node_type(void* node) {
+  uint8_t value = *((uint8_t*)(node + NODE_TYPE_OFFSET));
+  return (NodeType)value;
+}
+
+void set_node_type(void* node, NodeType type) {
+  uint8_t value = type;
+  *((uint8_t*)(node + NODE_TYPE_OFFSET)) = value;
+}

需要先把值转为 uint8_t 类型来确保它作为一个序列化的单字节。 还需要初始化节点的类型。

-void initialize_leaf_node(void* node) { *leaf_node_num_cells(node) = 0; }
+void initialize_leaf_node(void* node) {
+  set_node_type(node, NODE_LEAF);
+  *leaf_node_num_cells(node) = 0;
+}

最后,我们需要创建并处理一个新的错误码。

-enum ExecuteResult_t { EXECUTE_SUCCESS, EXECUTE_TABLE_FULL };
+enum ExecuteResult_t {
+  EXECUTE_SUCCESS,
+  EXECUTE_DUPLICATE_KEY,
+  EXECUTE_TABLE_FULL
+};
case (EXECUTE_SUCCESS):
  printf("Executed.\n");
  break;
+      case (EXECUTE_DUPLICATE_KEY):
+        printf("Error: Duplicate key.\n");
+        break;
case (EXECUTE_TABLE_FULL):
  printf("Error: Table full.\n");
  break;

有了这些修改,我们的测试可以更改为检查排序顺序:

"db > Executed.",
"db > Tree:",
"leaf (size 3)",
-      "  - 0 : 3",
-      "  - 1 : 1",
-      "  - 2 : 2",
+      "  - 0 : 1",
+      "  - 1 : 2",
+      "  - 2 : 3",
"db > "
])
end

并且我们能够为重复键增加一个新的测试:

+  it 'prints an error message if there is a duplicate id' do
+    script = [
+      "insert 1 user1 person1@example.com",
+      "insert 1 user1 person1@example.com",
+      "select",
+      ".exit",
+    ]
+    result = run_script(script)
+    expect(result).to match_array([
+      "db > Executed.",
+      "db > Error: Duplicate key.",
+      "db > (1, user1, person1@example.com)",
+      "Executed.",
+      "db > ",
+    ])
+  end

就是这样!接下来:实现拆分叶节点和创建内部节点。****

Enjoy GreatSQL 😃

关于 GreatSQL

GreatSQL是由万里数据库维护的MySQL分支,专注于提升MGR可靠性及性能,支持InnoDB并行查询特性,是适用于金融级应用的MySQL分支版本。

相关链接: GreatSQL社区 Gitee GitHub Bilibili

GreatSQL社区:

image

社区有奖建议反馈: https://greatsql.cn/thread-54-1-1.html

社区博客有奖征稿详情: https://greatsql.cn/thread-100-1-1.html

社区2022年度勋章获奖名单: https://greatsql.cn/thread-184-1-1.html

(对文章有疑问或者有独到见解都可以去社区官网提出或分享哦~)

译文 | A poor man‘s API 本文将展示如何在不编写任何代码的情况下,简单实现一个 API 实践。 阅读详情

相关推荐

程序设计二(面向对象)_实训10_复杂类的实现_ArrayList类的实现

第1关:构造函数与析构函数的实现

2401_83406306的博客 822

实现一个简单的Database1(译文)

cstsck在github维护了一个简单的、类似sqlite的数据库实现,通过这个简单的项目,可以很好的理解数据库是如何运行的。本文是第四篇,主要是使用rspec对目前实现的功能进行测试并解决测试出现BUG_

GreatSQL2021的博客 243

图像调整亮度饱和度 c语言,【C#/WPF】调节图像的HSL(色相、饱和度、明亮度)...

先说概念:HSL是一种描述颜色的方式(其他颜色描述方式还有大家熟悉的RGB值)。HSL三个字母分别表示图像的Hue色相、Saturation饱和度、Lightness明亮度。需求:制作一个面板,包含三个滑动条,拖动滑动条可以修改目标图片的HSL值。即模仿PS中类似的功能,如下图:方案一:遍历所有像素点,修改每个点的HSL值。前台界面:一个Image控件显示目标图片,一个Button按钮点击一下降低...

weixin_39935777的博客 1155

Zend Framework的DB处理

http://bbs.php.cn/thread-16360-1-1.html 除了MVC外,ZF中另外一个使用的比较充分的模块就是DB类库了。ZF的DB类库对数据库层进行了一个比较好的封装,将基本的数据库操作都转变为面向对象的操作。这里这些东西不再细讲,说另外一件事情。 当时看ZF的中文版手册,发现其中中英文混杂,并不是完整的中文版。正好赶上PHPChina总部负责《PHPer》杂志的刘昊同志...

翅膀同学的优快云 Blog 239

西门子S7-200 SMART PLC控制伺服电机

以下是使用西门子S7-200 SMART PLC控制伺服电机的详细程序框架和配置说明,涵盖硬件接线、PLC配置和基本运动控制逻辑。具体实现需根据伺服电机型号(如松下、三菱、台达等)调整参数。通过以上步骤,可实现伺服电机的基础位置控制。实际应用需根据设备机械参数和伺服驱动器手册调整细节。建议在调试时逐步测试脉冲输出和方向信号是否正常。

CHUXUEZHE8210的博客 6425

FOC时序及电流采样注意事项

摘要:本文介绍了无刷电机FOC(磁场定向控制)的实现方法,重点解析了电流采样时序与PWM同步的关键技术。在S32K144平台上,需使用两个独立的ADC组件实现双路电流同步采样,采样时刻必须严格对应低边MOS管开启时间并位于PWM波形中央。文章详细说明了硬件触发时序设计、采样电阻配置原则,并通过示波器实测波形验证了电流反馈电路的正确性,指出正弦电流波形应是理想输出形态。关键点包括ADC-PWM时序同步、低边MOS采样及正确的PWM映射配置。

qq_40916548的博客 2622

MySQL 创新版9.1.0有哪些功能?

MySQL 创新版9.1.0 于2024年10月15日正式发布。我们一起看看 9.1 版本都有哪些变化呢?

yang073402的专栏 5601

8.2-12.4GHz喇叭天线设计

使用后处理模板的优化算法,对a1、h_horn、b1进行优化,各参数的优化区间即为之前计算得到的参数范围。由于矩形喇叭的辐射特型基本上是E面和H面扇形喇叭的结合,当波导中只是单模传播(只有TE波)时,矩形喇叭的口径可以通过远场公式推理出来。表示矩形喇叭的口径效率,进行最佳增益设计时,一般取值为0.5。从表中可以看出,该结构在8.58GHz的增益误差为2.68%>2.5%,需要对结构进行优化。建模完成,之后就是在矩形波导尾部添加波导端口激励,以及对应频率的远场监视器。,在这里,将频率定为区间的中心频率。

qq_48897427的博客 6657

GraalVM Truffle 上下文退出机制全解析:自然退出、软退出与硬退出

本文以 GraalVM Truffle 框架的 [Exit.md](https://link.gitcode.com/i/acccd62d17b97b4b4f60cd6b163a3a30) 文档为骨架,结合本仓库 `truffle/src` 下 Truffle API 源码与 SimpleLanguage(SL)参考语言实现,系统讲解 polyglot 上下文(context)的三种退出类型——自

gitblog_00452的博客 392

Alist/Openlist 的 WebDAV 老是连不上?别再乱试了,这才是标准答案!(1Panel如何使用Alist/Openlist作为备份账号)

😫服务器硬盘告急,想用 Alist/Openlist 的 WebDAV 备份却屡屡失败?别慌!本文带你揭秘正确的连接地址和权限配置,手把手教你搞定 1Panel 备份设置,让你的网盘秒变备份仓库!

XiaoqiangClub的博客 5589

2025.06.06【Ribo-seq】|riboWaltz:P-site定位与三碱基周期性分析流程

同学们,大家好!今天我们要学习的是riboWaltz——一款专为Ribo-seq(核糖体足迹测序)数据设计的R包,主要用于P-site定位优化和三碱基周期性分析。P-site的准确定位是Ribo-seq下游所有翻译组学分析的基础,riboWaltz为我们提供了系统、可视化、易用的解决方案。P-site定位优化:自动识别不同长度RPF的最佳P-site偏移量。三碱基周期性分析:可视化RPF在CDS、UTR等区域的分布,评估数据质量。多样本/多条件支持:可同时处理多个样本,便于批量分析和对比。

1793

从 CSV 到查询结果:DB Browser for SQLite 十分钟上手指南

DB Browser for SQLite(DB4S)是一款免费开源的 SQLite 数据库管理工具,建库、设计表、CSV 导入、查询、导出,全程点选完成,适合拿到 .db 文件想快速摸清数据的人。 ## 装好它 ### 安装:三个系统各一条命令 Windows 用 winget,macOS 用 Homebrew,Ubuntu/Debian 系 Linux 用 apt,装完从应用列表启动。

gitblog_00465的博客 151

使用Zed 实现测距

此代码基于官方代码基础上进行改写,主要是获取zed相机深度画面的深度值,为yolo测距打基础。Zed相机是由Stereolabs公司开发的一种先进的立体视觉相机。这种相机专为计算机视觉和机器学习应用而设计,能够提供高质量的3D捕捉和分析功能。: Zed相机配备有一对垂直排列的传感器,能够捕捉两个略有偏移的图像,从而模拟人的双眼视觉,实现深度感知。: 利用立体成像技术,Zed相机能够实时生成环境的3D模型,这对于机器人导航、增强现实(AR)和虚拟现实(VR)等应用至关重要。

weixin_45303602的博客 912

十分钟上手 DB Browser for SQLite:免费 SQLite 数据库管理工具跑通传感器数据全流程

DB Browser for SQLite(DB4S)是一款免费开源的 SQLite 数据库管理工具:打开 .db 文件看表、导入 CSV、执行 SQL 查询看结果、维护数据库,全程点选完成,不写 SQL 也能干完大部分活。 [![DB Browser for SQLite 图形化 SQLite 数据库管理工具主界面](https://raw.gitcode.com/gh_mirrors/sq/

gitblog_00479的博客 227

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

ES2018(ES9)译文指南

ES2018 原文链接 异步迭代 在async/await的某些时刻,你可能尝试在同步循环中调用异步函数。例如: async function process(array) { for (let i of array) { await doSomething(i); } } 这段代码是不会正常执行的,循环本身依旧保持同步,并在在内部异步函数之前全部调用完成。 ES20...

Chad97的博客 357

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

ApacheCN Python 译文集 20211108 更新

Think Python 中文第二版 第一章 编程之路 第二章 变量,表达式,语句 第三章 函数 第四章 案例学习:交互设计 第五章 条件循环 第六章 有返回值的函数 第七章 迭代 第八章 字符串 第九章 案例学习:单词游戏 第十章 列表 第十一章 字典 第十二章 元组 第十三章 案例学习:数据结构的选择 第十四章 文件 第十五章 类和对象 第十六章 类和函数 第十七章 类和方法 第十八章 继承 第十九章 更多功能 笨办法学 Python · 续 中文版 引言 第一部分:预备知识 练习 0:起步 .

龙哥盟 1242

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

IOS9关于搜索的认识和实现

原文链接 : iOS 9 App Search Tutorial: Introduction to App Search原文作者 : Chris Wagner译文出自 : 开发技术前线 www.devtf.cn译者 : kmyhy Ray 注:本文作为《iOS 9 Feast》中的一部分,节略自 《iOS 9 Tutorials》其中一章——通过本文,您可对全书内容窥见一斑。祝您阅读愉快!

hbblzjy的博客 1279

python名词解释数据仓库_python数据仓库

广告关闭腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元!python拥有一个强大的标准库,python语言的核心只包含数字、字符串、列表、字典、文件等常见类型和函数,而由python标准库提供了系统管理、网络通信、文本处理、数据库接口、图形系统、xml处理等额外的功能。 python社区提供了大量的第三方模块,使用方式与标准库类似。 它们...

weixin_39569753的博客 285

FaRM译文

具有强一致性和高可用性的事务简化了分布式系统的构建和推理。然而,之前的实现表现不 佳。这迫使系统设计人员要么完全避免使用事务,要么削弱一致性保证,或者提供需要程序 员自己划分数据的单机事务。在本文中,我们展示了在现代数据中心中无需妥协。我们展示 了一种称为FaRM的主存分布式计算平台能够提供具有严格可串行化、高性能、持久性和高 可用性的分布式事务。FaRM在90台机器上使用4.9 TB数据库实现了每秒1.4亿次TATP 事务的峰值吞吐量,并能在不到50毫秒内从故障中恢复。

John_Snowww的博客 558

5.9 亿国内用户简历遭殃,数据库持续“裸奔”!

在过去的三个月中,590,497,000份简历被曝从中国公司泄露,这个数字十分惊人!而报告显示,大多数简历泄漏的原因都是由于MongoDB数据库的安全性较差和ElasticSearch服务器没有受到密码保护,或意外的防火墙错误导致服务器暴露——这些都表明,中国人力资源公司和中国求职网站们根本无视用户隐私,而且也说明这些公司的安全措施不够完善。 作者 |CatalinCi...

优快云资讯 2042

一个老程序员的30年生涯回顾(译文)

前几天,我读到一篇文章[1],一个60多岁老程序员回顾自己的人生。 读完以后,我很受触动,觉得对于软件行业的很多看法,我也有同感。下面就是这篇文章的翻译。 一个老程序员的30年生涯回顾(译文) 原文网址:hackernoon.com[2] 作者:Chris Fox 1、 1967年,我13岁时开始学习编程。 1988年,我正式进入了软件行业,通过编程养活自己。那一年,我34...

勇往直前的专栏 674

天工开物 #9 Why Async Rust(译文)

昨天的文章里,我介绍了 Async Rust 当前的实现以及一个实现 Async Runtime 需要了解的概念和现有的一些实践。文章发出后,有评论称 Async Rust 创造性工作,没有可借鉴的经验。诚然,Rust 系统编程语言的定位就决定了它与其他有运行时的语言在设计时存在巨大的不同,同类语言 C 和 C++ 在异步编程方面,受限于语言的历史包袱,相关的支持往往以三方库而不是语言级的支持出现...

Miracle 944

tcl把文本产生html,TCL脚本数据文件格式(译文)

TCL脚本数据文件格式简介一个典型的tcl脚本把它的内部数据保存在列表和数组(tcl中两种主要的数据结构)中.比如,假定你想写一个能将数据先保存在磁盘上,然后再读取的tcl应用程序, 这将使你的用户可以先把一个项目保存下来,以后再重新装入.你需要一个办法,把数据从其内部存储处(列表与数组)写入到一个文件中,同样,也要有一个办法把数据从文件中读出装入到正在运行的脚本中去.你可以选择把数据保存为二进制...

weixin_33093437的博客 553

DateFormatter性能深度优化(译文)

此文章为本人翻译的译文,版权为原作者所有。 英文原文:Parsing Dates: When Performance Matters 简书同步地址 www.jianshu.com/p/6fdb4631b… 不久前,我在App开发中遇到了一些性能问题。 这个App需要处理数千个JSON对象,并将它们存储在Core Data数据库中 - 这不是一项微不足道的任务,能都理解会有性能问题。 但是多...

weixin_34008805的博客 565

我看过的数据库方面的好文章

本文不定期更新,最后更新于2019-5-18 GitHub上实时更新,地址:good-articles-by-sort/数据库.md 数据库 数据库事务隔离级别与并发事务控制(悲观锁与乐观锁) 浅谈数据库事务 记住,永远不要在MySQL中使用“utf8” B树和B+树的插入、删除图文详解 一文说尽MySQL优化原理,值得你看! 数据库设计入门指南与学习笔记 数据库管理提速:SQL解析的探索与应...

个人博客 606

[渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:建立一个EF数据模型

英文渣水平,大伙凑合着看吧…… 这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第一篇:建立一个EF数据模型 原文:Creating an Entity Framework Data Model 译文版权所有,谢绝全文转载——但你可以在你的网站上添加到该教程的链接。 Contos...

weixin_34392435的博客 265
上一篇: 实现一个简单Database8(译文)
下一篇: 实现一个简单的Database10(译文)
GreatSQL社区
博客等级 码龄5年 1210粉丝 390原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值