OceanBase 存储层代码解读(二)微块存储格式

作者:

公祺,一个专注于 OBKV 的程序员

海芊,一个致力于当网红的 OceanBase 文档工程师。个人频道:Amber loves OB

1. 微块和宏块的关系

OceanBase 数据库的存储引擎采用了基于 LSM-Tree 的架构,把基线数据和增量数据分别保存在磁盘(SSTable)和内存(MemTable)中,其中 SSTable 以宏块(Macro Block)为单位组织数据,每个宏块大小为 2MB。宏块内部又划分出很多个大小为 16K(压缩前的大小)微块(Micro Block),每个微块内则包含多个行(Row)。

OceanBase 数据库内部 IO 的最小单元就是微块,微块数据可以进行压缩,下图是微块在宏块中的存储格式:

其中:

1.macro block header:宏块的元数据,包括:版本、宏块大小、微块的个数、列的类型、行的个数、压缩算法等信息。

2.micro block n:微块的具体数据,具体信息见下文微块的存储格式。

3.micro block index:微块的索引数据,用来索引每个微块,通常常驻内存。

每一个微块包含多个行数据,行数据中有多个列的数据,如下是当前微块的存储格式:

其中:

1.record header:包含微块数据大小、头部大小、version、checksum 等。

2.micro block header:包含微块的元数据,包括:列数、行索引的偏移量、行数等。

3.Row n:包含行数据,包括:row header、列数据、列索引。

(1)row header:行的元数据,包括:列索引占用的字节数、删除标记等。

(2)col n:列的值,包括:类型、长度、列的值。

(3)column index:列的索引数据,用来索引每一列,记录了每列值的偏移和长度。

4.Row Index:行的索引数据,用来索引每一行,记录了每行的偏移和长度。

接下来,让我们根据 OceanBase 的开源代码,介绍微块的具体代码实现,后续的代码解读都是基于此版本:v3.1.0_CE_BP1

2. 微块中行数据的编码

行数据写入的主要逻辑在 ObMacroBlockWriter 模块,见如下的代码:

// src/storage/blocksstable/ob_macro_block_writer.cpp
// 该函数主要逻辑为:
//   1. 将行数据写入到微块中,并更新 bloomfilter 和 checksum
//   2. 在当前微块写满的情况下:构建当前的微块,并切换微块写入器
int ObMacroBlockWriter::append_row(const ObStoreRow& row, const int64_t split_size, const bool ignore_lob)
{
  int ret = OB_SUCCESS;
  const ObStoreRow* row_to_append = &row;
  // ... 省略参数检查的相关代码if (OB_SUCC(ret)) {// 向当前的微块中写入一行数据if (OB_FAIL(micro_writer_->append_row(*row_to_append))) { if (OB_BUF_NOT_ENOUGH == ret) {
        if (0 == micro_writer_->get_row_count()) {
          // 不支持超过 16KB 的行
          ret = OB_NOT_SUPPORTED;
          STORAGE_LOG(ERROR, "The single row is too large, ", K(ret), K(row));
        } else if (OB_FAIL(build_micro_block(false))) { // 当前微块写满后,需要构建该微块:编码、压缩等// for compatibilitySTORAGE_LOG(WARN, "Fail to build micro block, ", K(ret));
        } else if (OB_FAIL(micro_writer_->append_row(*row_to_append))) { // 继续写当前行数据STORAGE_LOG(ERROR, "Fail to append row to micro block, ", K(ret), K(row));
        } else if (data_store_desc_->need_calc_column_checksum_ 
                   && OB_FAIL(add_row_checksum(row_to_append->row_val_))) { // 计算 checksumSTORAGE_LOG(WARN, "fail to add column checksum", K(ret));
        }
        if (OB_SUCC(ret) && data_store_desc_->need_prebuild_bloomfilter_) {
          // 根据 rowkey 构建 bloomfilter
          const ObStoreRowkey rowkey(row_to_append->row_val_.cells_, data_store_desc_->bloomfilter_rowkey_prefix_);
          if (OB_FAIL(micro_rowkey_hashs_.push_back(static_cast<uint32_t>(rowkey.murmurhash(0))))) {
            STORAGE_LOG(WARN, "Fail to put rowkey hash to array ", K(ret), K(rowkey));
            micro_rowkey_hashs_.reuse();
            ret = OB_SUCCESS;
          }
        
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值