OceanBase 存储层代码解读(三)宏块存储格式

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

1.宏块的概述

在上一篇微块的存储格式中已经介绍了微块和宏块的关系,宏块是处于 SSTable 和微块之间的数据结构,OceanBase 中的宏块为2MB的定长数据块。众所周知,OceanBase 中微块是读 IO 最小单元,这是因为微块读处在用户请求的关键路径上,为保证快速响应用户的请求,微块不能过大,所以微块的默认大小一般不超过16KB;而宏块作为写 IO 的最小单元,它的读写不在用户请求的关键路径上,所以就有了2MB的宏块,目的是为了最大限度的发挥磁盘的吞吐性能,能快速的做 compaction 、迁移复制、坏块检查等操作。宏块的简单结构可以参考下图,详细的宏块格式介绍见下一节:

注:本文所有的说明及代码都是基于v3.1.0_CE_BP1版本的 OceanBase 开源代码。

2. 宏块的格式

目前 OceanBase 支持的宏块有很多种,具体可以 enum MacroBlockType 的定义,总共有十几种吧,但是常用的数据宏块主要有三种,如下:

  • SSTableData:常规的存放数据的宏块;
  • LobData:Large Object Data,用来存放数据较大的行数据;
  • BloomFilterData:带有 bloomfilter 的宏块。

本文主要介绍第1种常规的数据宏块,关于 LobData、BloomFilterData,后面找时间再单独说明。

宏块的整体格式可以参考上图,它是一种比较经典的存储结构(header + payload + trailer + padding):

  • header 中记录元数据:对应 OceanBase 宏块的 header ;
  • payload 存放的是具体的数据:OceanBase 宏块的 payload 为微块列表;
  • trailer 中记录的是数据的 index:OceanBase 宏块的 trailer 为微块的 index 信息,即为微块在宏块中的偏移量;
  • padding 是为了做对齐的:OceanBase 宏块为2MB,不足部分需要做 padding。

后面我们针对不同的部分,一一介绍其结构的存储格式。

2.1 宏块的 header

宏块的头部记录的自然就是宏块的元数据,它由多个部分组成,如下图所示:

宏块头部的各个部分存储的是不同的元数据,具体含义如下:

  • common header:宏块的版本、类型、大小、checksum 等信息,见 ObMacroBlockCommonHeader ;
  • macro block header:记录了宏块数据大小、table_id、partition_id、微块的数量、列数、行数、checksum、加密信息、以及相关 offset 信息,具体可以参考 struct ObSSTableMacroBlockHeader;
  • column id list:列的 id 列表,OceanBase 数据库表每一列都一个唯一 id;
  • column type list:每列的类型信息,包括:类型、编码字符集等;
  • column order list:每列的顺序,可以是 ASC 或 DESC ,宏块中所有微块中的行数据都是按照这个顺序存储;
  • column checksum list:每列数据的 checksum 信息,用来做列的数据校验。

微块头部的存储格式可以参考下面的代码:

// src/storage/blocksstable/ob_macro_block.cpp
// 该函数主要给宏块header结构预先指向buffer的不同的offset,后续就不需要再进行序列化操作了,
// 该函数在初始化宏块的时候调用,header成员变量的具体值是在后续的数据写入后指定。
int ObMacroBlock::reserve_header(const ObDataStoreDesc& spec)
{
  int ret = OB_SUCCESS;
  common_header_.reset();
  common_header_.set_attr(ObMacroBlockCommonHeader::SSTableData);
  common_header_.set_data_version(spec.data_version_);
  common_header_.set_reserved(0);
  const int64_t common_header_size = common_header_.get_serialize_size();

  // data_的类型是ObSelfBufferWriter,它是一个支持自动扩展的内存buffer
// ObSelfBufferWriter的实现见:src/storage/blocksstable/ob_data_buffer.h
  MEMSET(data_.data(), 0, data_.capacity());

  // 1. data_的第一部分为ObMacroBlockCommonHeader
if (OB_FAIL(data_.advance(common_header_size))) {
    STORAGE_LOG(WARN, "data buffer is not enough for common header.", K(ret), K(common_header_size));
  }

  if (OB_SUCC(ret)) {
    int64_t column_count = spec.row_column_count_;
    int64_t rowkey_column_count = spec.rowkey_column_count_;
    int64_t column_checksum_size = sizeof(int64_t) * column_count;
    int64_t column_id_size = sizeof(uint16_t) * column_count;
    int64_t column_type_size = sizeof(ObObjMeta) * column_count;
    int64_t column_ord
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值