一、磁盘引擎框架回顾
在前面一段时间的学习中,我初步了解了open gauss存储引擎的access文件夹下内容,对存储引擎部分技术做了简单学习。接下来将会做一个小结,便于接下来的学习能够做到有序、成体系的开展。
从整个数据库服务的组成构架来看,存储引擎向上对接SQL引擎,向下对接存储介质,按照特定的数据组织方式,以页面、列存储单元(CU,compression unit)或其他形式为单位,通过存储介质提供的特定接口,对存储介质中的数据完成读、写操作。如下图所示:
二、access模块小结
access文件涵盖了:
- 各种行存储格式,元组格式;
- 元组与页面之间的转换和访存管理;
- 元组扫描、插入、删除和更新功能的接口实现;
- 几类索引,包括B-Tree、hash、GIN(generalized inverted index,通用倒排索引)、GiST(generalized search tree,通用搜索树)、psort(列存储局部排序索引)的访存管理和接口实现;
- 各类数据库操作对应的日志实现和恢复机制;
- 以及事务模块实现。 其主要工作范围如下图所示(节选自上图):
Storage目的是为了持久化存储数据。其中元组是其运用最为广泛和复杂的数据结构。以元组(其数据结构定义如下)的访存为例
typedef struct HeapTupleData {
uint32 t_len; //元组总大小
ItemPointerData t_self; // 行号
Oid t_tableOid; // 元组所属表的OID
TransactionId t_xid_base;
TransactionId t_multi_base;
HeapTupleHeader t_data; //指向元组头部
} HeapTupleData
HeapTupleData 是元组在内存中的拷贝,它是磁盘格式的元组读入内存后的存在方式 他的插入过程可以抽象为如下图所示过程:
其主调函数为heap_insert,位于src\gausskernel\storage\access\heap\heapam.cpp 以下是插入新元组的流程:
步骤 | 描述 |
---|---|
1 | 为新插入的元组(tup)调用 newoid 函数为其分配一个 OID。 |
2 | 初始化 tup,包括设置 t_xmin 和 t_cmin 为当前事务 ID 和当前命令 ID、将 t_xmax 置为无效、设置 tableOid(包含此元组的表的 OID)。 |
3 | 找到属于该表且空闲空间(freespace)大于 newtup 的文件块,将其载入缓冲区以用来插入 tup。 |
4 | 调用 RelationPutHeapTuple 函数将新元组插入至选中的缓冲区。 |
5 | 向事务日志(XLog)写入一条 XLog。 |
6 | 完成上述过程后,将缓冲区解锁并释放,并返回插入元组的 OID。 |
以上就是插入新元组的流程。 |
他的删除可以抽象为如下图所示过程:
其主调函数为heap_delete,位于src\gausskernel\storage\access\heap\heapam.cpp
步骤 | 描述 |
---|---|
1 | 获取元组 tid 相关的缓冲区并加锁。 |
2 | 检查元组对当前事务的可见性。如果不可见,解锁缓冲区并返回错误。 |
3 | 如果元组正在被本事务修改或已修改,更新元组的 ctid 字段,并解锁缓冲区。 |
4 | 如果元组正在被其他事务修改,等待该事务结束后再检测。如果可以修改,继续执行。 |
5 | 设置 t_max 为当前事务 ID,标记元组已删除。 |
6 | 记录 XLog。 |
7 | 如果元组有线外数据,删除 TOAST 表中对应数据。 |
8 | 如果是系统表元组,发送无效消息。 |
9 | 设置 FSM 表中该元组所在文件块的空闲空间值。 |
以上就是删除元组 tid 的流程。 |
在archive文件夹下nas_am.cpp学习了NAS(网络附加存储)的概念,NAS是指的以数据为中心,将存储设备与服务器彻底分离,集中管理数据,从而释放带宽、提高性能、降低总拥有成本、保护投资。其成本远远低于使用服务器存储,而效率却远远高于后者。对NAS写入函数,文件排序函数做了简单分析注解。 学习足迹1
在heapam.cpp文件学习了实现openGauss堆访问方法的heap_例程,这些方法被所有的POSTGRES关系所使用。
- Block Change Map(BCM)是数据库系统中用于跟踪哪些数据块已经被修改过的数据结构。
- WAL,全称为Write-Ahead Logging,是数据库系统中常见的一种手段,用于保证数据操作的原子性和持久性。过程中,BCM可以帮助系统确定哪些数据块需要被检查和恢复
在rewriteheap.cpp文件下学习了,如何提供了一种方式,可以完全重写一个堆,同时保留可见性信息和更新链。 详细了解了HOT技术的主要思想:是在更新时通过修改指针指向定位新元组,而不需要插入相应的索引元组。这样在频繁更新的系统中不仅数据会膨胀而且索引也会膨胀,同时维护索引的开销太大。 学习足迹1 学习足迹2
在cbtree.cpp文件学习了多路平衡查找树(B-Tree),他实现了多级树结构。索引的第一个段文件的起始位置存储了一个单独的元页面。所有其他页面要么是叶子页面,要么是内部页面。叶子页面是树的最低级别的页面。所有其他级别都由内部页面组成。每个叶子页面包含指向表行的元组。每个内部页面包含指向树下一级的元。 学习足迹1
三、总结
由衷感概这段时间的学习,帮助我很好地理解了数据库存储引擎的访存方式的底层代码构建。刚一开始,我诚惶诚恐无从下手,索性选择了一个文件夹就一头扎了进去,在注解过程中,我逐渐理解了其构建框架,实现流程。接下来将会依托以及理解的框架,展开更加系统的学习注解,以求完成我最开的期望——理解SQL引擎到存储引擎的完成构成。
access的学习内容远不止于此,对此,我将继续对其学习。但是会将重心放到MVCC技术的实现上面,也就是第一篇博客里提到的存储引擎关键技术之一。其上博客讲解不当之处,烦请斧正。靡不有初,鲜克有终,与诸君共勉。