写点什么

一文读懂 OceanBase 数据库的启动恢复代码解析

发布于: 4 小时前

作者简介:镜水,一个致力于无限进步的数据库学徒。

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


本文主要介绍 OceanBase 数据库启动时是如何将已持久化的日志和数据恢复到内存,重新形成各类信息(如租户信息、分区信息等)的内存映像,从而回到宕机前的状态。


在介绍具体的恢复流程之前,我们首先来了解一些与之相关的存储结构。

存储数据结构

MacroBlock

OceanBase 数据库将数据分为增量数据和基线数据,基线数据是几乎占满整个磁盘的一个超大文件,OceanBase 数据库以固定大小的宏块(MacroBlock,默认大小为 2 MB)为单位对磁盘上的基线数据进行管理,从而优化每日合并过程并高效利用磁盘空间,这类似于操作系统中内存的页式管理。宏块按照其在磁盘中的位置进行逻辑编号,起始编号为 0。


MacroBlockType 枚举类型标识了宏块有哪些种类:

enum MacroBlockType {    Free = 0,							// 空闲宏块    SSTableData = 1,					// 数据宏块,实际存放用户数据    PartitionMeta = 2,					// 分区元数据宏块,通常以宏块链表的方式进行存储    // SchemaData = 3,    // Compressor = 4,    MacroMeta = 5,						// 宏块元数据宏块,通常以宏块链表的方式进行存储    Reserved = 6,    MacroBlockSecondIndex = 7,  		// deprecated    SortTempData = 8,    LobData = 9,    LobIndex = 10,    TableMgrMeta = 11,					// 新版本已废弃    TenantConfigMeta = 12,				// 租户配置元数据宏块,通常以宏块链表的方式进行存储    BloomFilterData = 13,    MaxMacroType,  };
复制代码

除此之外,类似于文件系统,宏块还有一种称为 Super Block 的特殊种类。Super Block 存放了整个基线数据的关键信息,比如元数据入口点和日志回放点,固定为第 0 块宏块,通常还有若干个备份块。


除了 Super Block 以外每个宏块都有一个 ObMacroBlockCommonHeader

struct ObMacroBlockCommonHeader {  int32_t header_size_;  // struct size  int32_t version_;      // header version  int32_t magic_;        // magic number  						 // each bits of the lower 8 bits represents:  						 // is_free, sstable meta, tablet meta, compressor name, macro block meta, 0, 0, 0  int32_t attr_;         // MacroBlockType  union {    uint64_t data_version_;  // sstable macro block: major version(48 bits) + minor version(16 bits)    /**     * For meta block, it is organized as a link block. The next block has a index point to     * its previous block. The entry block index is store in upper layer meta (super block)     * 0 or -1 means no previous block     */    int64_t previous_block_index_;  };  union {    int64_t reserved_;    struct {      int32_t payload_size_;      // not include the size of common header      int32_t payload_checksum_;  // crc64 of payload    };  };};
复制代码

NOTEprevious_block_index_ 为前向指针,通常为链式结构的元数据宏块,它表明从新到旧的一个前向关系。例如,下表所示宏块链表的写入顺序为 12345,但由于前向链接,读取时的入口点为 5,从而导致读取顺序为 54321,因此实际使用数据时,通常需要一次正向(54321)读取获取 block id 的数组后,再进行一次反向(12345)读取,从而得到正确的数据写入顺序。



在了解了数据块的基本单元 Macro Block 后,我们接着来介绍 Super Block 以及 Meta Block


由于历史原因,目前对于super block以及meta block的组织方式有新旧两个版本之分,下面我们将这两个版本分开介绍。

旧版本:

旧版本的 Super Block 和所有的 Meta Block 都在同一个大文件(如果对 observer 的执行目录有所了解的话,这个大文件可以理解为 sstable 目录下的 block_file)上。

Super Block

Super Block 可以简单理解为所有持久化数据的普遍元数据,其中包含了各种 Meta Block 的入口块(即宏块链表第一块)以及 SLog 的回放入口点(SLog 文件中的日志经过 checkpoint 后成为 Meta Block,这里的回放入口点即 SLog 中尚未经过 checkpoint 形成 meta 的日志偏移位置,如果将 Meta Block看作 meta 的基线数据,那么 SLog 需要回放的日志可以理解为 meta 的增量数据),一般是前两个 macro block

struct ObSuperBlockHeader {  static const int64_t OB_MAX_SUPER_BLOCK_SIZE = 64 * 1024;  int32_t super_block_size_;  // not used any more  int32_t version_;  int32_t magic_;  // magic number  int32_t attr_;   // reserved, set 0};struct ObSuperBlockV2 {  struct MetaEntry {    static const int64_t META_ENTRY_VERSION = 1;    int64_t block_index_;  // first entry meta macro block id    int64_t log_seq_;      // replay log seq    int64_t file_id_;      // ofs file id    int64_t file_size_;    // ofs file size  };  struct SuperBlockContent {    static const int64_t SUPER_BLOCK_CONTENT_VERSION = 2;
int64_t create_timestamp_; // create timestamp int64_t modify_timestamp_; // last modified timestamp int64_t macro_block_size_; int64_t total_macro_block_count_; int64_t free_macro_block_count_; int64_t total_file_size_;
// entry of macro block meta blocks, common::ObLogCursor replay_start_point_; // SLog 回放入口点 MetaEntry macro_block_meta_; // macro block 元数据回放入口点 MetaEntry partition_meta_; // partition 元数据回放入口点 MetaEntry table_mgr_meta_; // table mgr 元数据回放入口点 MetaEntry tenant_config_meta_; // tenant config 元数据回放入口点 }; ObSuperBlockHeader header_; SuperBlockContent content_;}
复制代码

由于 Meta Block 是以前向链表的形式连接的,每个 Meta Block 除了 ObMacroBlockCommonHeader 以外还包含一个 link header

struct ObLinkedMacroBlockHeader {  int32_t header_size_;  int32_t version_;  int32_t magic_;  int32_t attr_;                  // MacroBlockType  int64_t meta_data_offset_;      // data offset base on current header  int64_t meta_data_count_;       // 当前 block 有多少个元数据 item  								  // 如果是 0,表示该 item 超出 2 M,那么多个 block 构成多个完整 item  								  // 否则,1 个 block 包含多个完整 item  int64_t previous_block_index_;  // last link block  int64_t total_previous_count_;  // 之前所有 block 所包含的元数据 item 总数  int64_t user_data1_;            // log_seq_num,not used  int64_t user_data2_;            // 如果多个 block 组成多个 item,该值表示这多个 block 所包含的多个 item 的总数据序列化长度}
复制代码

MacroBlockMeta

宏块元数据保存了数据宏块中数据列排布、微块索引等重要元数据,从磁盘加载后常驻内存并在内存中维护。


所有宏块元数据(macro block meta,也就是 item)由多个 macro block 组成,每个 block 可能有多个 item(完整的,由于一个 item 不会跨多个 block,可能存在 padding 空间),每个 item 代表了 block id 从 0 开始的每一个 macro block 的元数据,也就是说每个 macro block 都有一个 macro block meta


每个 item 是 ObMacroBlockMeta 结构,解析出来的每个 item 在内存里存放在一个类似于 hash table 的结构里,通过 block id 进行 hash,解析代码见 ObMacroMetaBlockReader::parse

TableMgrMeta

表管理元数据保存了 SSTable 的相关元信息。


TableMgrMeta 由多个macro block组成,可能每个 block 有多个 item(完整的,这种情况下 block 可能存在 padding 空间),也可能多个 block 组成多个 item(比如,3 个 block 组成 4 个 item,那么前两个 block 的 linked_header.meta_data_count_ 为 0,最后一个 block 的 linked_header.meta_data_count_ 为 4,第一个 block 的 linked_header.user_data2_ 代表了这 4 个 item 的总序列化大小,第二和第三个 bloc k 的 linked_header.user_data2_ 则为 0),而一次对多个 item 的读取(一个 block,或者多个 block)实际对应着一条 log 记录,是同一个 log_seq_num


每个 item 是 ObOldSSTable 结构,包含了一个 sstable 的信息,解析代码见 ObTableMgrMetaBlockReader::parse。解析一条 log 中的多个 item 用的是 ObTableMgr::load_sstable


每个 ObOldSSTable 有一个 table_key

struct TableKey {  ObITable::TableType table_type_;  common::ObPartitionKey pkey_;  uint64_t table_id_; // combine bits // include tenant_id (24 bits)  common::ObVersionRange trans_version_range_;  common::ObVersion version_;  // only used for major merge  common::ObLogTsRange log_ts_range_;}
复制代码

PartitionMeta

分区元数据由多个 macro block 组成,可能每个 block 有多个 item(完整的),也可能多个 block 组成多个 item(组成方式和 TableMgrMeta 相同),一次对多个 item 的读取同样对应着同一条 log 记录,解析一条 log 中的多个 item 用的是 ObPartitionMetaRedoModule::load_partition


每个 item 是 ObPartitionGroup 结构,包含了 partition 的全部基线信息,包括 sstable 信息。


解析代码见 ObPartitionMetaBlockReader::parse,解析后每个 partition 的 sstable 会存放在其自身的 ObPGStorage pg_storage_.sstable_mgr_.table_map_

NOTE:PartitionGroup(简称 PG)和 Partition 的概念可能会增加代码阅读复杂度,可以简单理解一个 PG 里面只有一个 Partition,只有特殊情况 PG 才会包含多个 Partition,看代码时可以简单把 PG 看作 Partition。

TenantConfigMeta

租户配置元数据由多个 macro block 组成,每个 block 可能有多个 item(完整的),每个 item 是一个容纳了所有租户配置项的数组(TenantUnits结构)。


每个 item 在ObTenantConfigMgr::load_tenant_units载入时,会reset原来的配置项数组,相当于覆盖更新。


解析代码见 ObTenantConfigMetaBlockReader::parse

新版本:

旧版本 Super Block 和所有的 meta block 都在同一个文件上,没有为不同的 tenant 做区分。而新版本则不一样,每个 tenant 有单独的 Super Block 和 meta block,其中每个 tenant 的 Super Block(第二级 Super Block)是一个 SuperBlockMeta(第一级 meta)item,和第一级 Super Block 在同一个文件,而每个 tenant 的 meta block在 其单独的文件中,文件 id 以及元数据的入口点保存在 tenant 自己的 Super Block 中。


简单来说,通过第一级 Super Block 能够找到第一级 meta(SuperBlockMeta)的入口点,而通过第一级 meta 能够找到每个 tenant 对应的单独文件以及对应的二级 Super Block,然后通过二级 Super Block上的入口点能够得到每个 tenant 的单独文件 id 以及文件上的二级 meta block

Super Block

这是第一级 Super Block,针对所有的 tenant

struct ObSuperBlockMetaEntry {  blocksstable::MacroBlockId macro_block_id_;  // first entry meta macro block id};struct ObSuperBlockHeaderV2 {  int32_t version_;  int32_t magic_;  // magic number};struct ObServerSuperBlock {  struct ServerSuperBlockContent {    static const int64_t SUPER_BLOCK_CONTENT_VERSION = 1;
int64_t create_timestamp_; // create timestamp int64_t modify_timestamp_; // last modified timestamp int64_t macro_block_size_; int64_t total_macro_block_count_; int64_t total_file_size_;
common::ObLogCursor replay_start_point_; // SLog 回放入口点 ObSuperBlockMetaEntry super_block_meta_; // tenant spuer block 元数据回放入口点 ObSuperBlockMetaEntry tenant_config_meta_; // tenant config 元数据回放入口点 }; ObSuperBlockHeaderV2 header_; ServerSuperBlockContent content_;};
复制代码

Meta Block 除了 ObMacroBlockCommonHeader 以外还包含一个 link header

struct ObLinkedMacroBlockHeaderV2 {  int32_t header_size_;  int32_t version_;  int32_t magic_;  int32_t attr_;  int32_t item_count_;			// 该 block 有多少个 item  						       	// 如果是 0,表示该 item 超出 2M,那么多个 block 构成多个完整 item  								// 否则,1 个block 包含多个完整 item  int32_t fragment_offset_;  // record previous macro block's MacroBlockId // 分别是 MacroBlockId 的四个部分  int64_t previous_block_first_id_;  int64_t previous_block_second_id_;  int64_t previous_block_third_id_;  int64_t previous_block_fourth_id_;}
复制代码

新版本的每个 meta item 都包含一个 meta header

struct ObPGMetaItemHeader {  int16_t type_;  int16_t reserved_;  int32_t size_;						// item 的数据长度,不带 ObPGMetaItemHeader 的长度};
复制代码

TenantConfigMeta

新版本租户配置元数据和旧版本含义一致,解析代码见ObTenantConfigMetaCheckpointReader::read_checkpoint


每个 item 是 TenantUnits 结构,每个 item 也是调用 ObTenantConfigMgr::load_tenant_units 载入。

SuperBlockMeta

这是第一级 meta,由多个 macro block 构成,可能每个 block 有多个 i tem(完整的),也可能多个 block 组成多个 item。


新版本和旧版本对 item 的拆分方式不太一样,旧版本的拆分方式可以见TableMgrMeta 的介绍,新版本则为拆分封装了更规范的函数(ObPGMetaItemReader::get_next_item 等),通过 item_count_ 来判断一个 block 是否包含完整的 item,不再通过 linked_header.user_data2_ 来判断多个 item 的总长度(该成员新版本已不存在),而是通过 item_header.size_ 来 判断每个 item 的长度,如果一个 item 跨多个 block,则根据 item 的长度和每个 block 的有效数据长度(common_header.payload_size_)来拼接得到整个 item 的有效数据。


解析代码见 ObTenantFileSuperBlockCheckpointReader::read_checkpoint,每个 item 由ObPGMetaItemReader::get_next_item依次获取,每个 item 是 ObTenantFileSuperBlockCheckpointEntry 结构,包含了一个 ObTenantFileInfoObTenantFileInfo 包含了一个 tenant 单独文件的 id 以及第二级 Super Block,由此可以得到每个tenant 对应的单独文件以及二级元数据的入口点。

struct ObTenantFileKey {  uint64_t tenant_id_;  int64_t file_id_;						// 每个 tenant 单独文件的文件 id, 二级 meta block 存储在该文件上};struct ObTenantFileSuperBlock {  blocksstable::ObSuperBlockMetaEntry macro_meta_entry_;	// 二级 meta, macro block meta  blocksstable::ObSuperBlockMetaEntry pg_meta_entry_;		// 二级 meta, pg meta  ObTenantFileStatus status_;  bool is_sys_table_file_;};struct ObTenantFileInfo {  ObTenantFileKey tenant_key_;  ObTenantFileSuperBlock tenant_file_super_block_;			// 一级 meta, 每个 tenant 单独的 super block  PG_MAP pg_map_;};
复制代码

MacroBlockMeta

宏块元数据是第二级 meta,针对的是某个 tenant,由多个 macro block 组成,每个 block 可能有多个 item(完整的),每个 item 是 ObPGMacroBlockMetaCheckpointEntry 结构,其中包含的 meta_ 不再是旧版本的 ObMacroBlockMeta 结构,而是 ObMacroBlockMetaV2


解析出来的所有 item 存放在一个 hashmap 里,key 是 ObMacroBlockKey 结构,解析代码见 ObPGMacroMetaCheckpointReader::read_checkpoint

struct ObPGMacroBlockMetaCheckpointEntry {  int64_t disk_no_;  blocksstable::MacroBlockId macro_block_id_;  ObITable::TableKey table_key_;  blocksstable::ObMacroBlockMetaV2& meta_;};struct ObMacroBlockKey {  // 引入 table key 可以在检查时判断该 sstable 是否还存在,不存在那么 macro block 自然也失效了  ObITable::TableKey table_key_;  // 这里的 block id 是每个 sstable 里宏块的逻辑 id,对于每一个 sstable 都是从头开始  blocksstable::MacroBlockId macro_block_id_;};
复制代码

PGMeta

分区组元数据是第二级 meta,针对的是某个 tenant,但和旧版本的 PartitionMeta 含义基本一致,依然由多个 macro block 组成,可能每个 block 有多个 item(完整的),也可能多个 block 组成多个 item,解析代码见 ObPGMetaCheckpointReader::read_checkpoint


每个 item 是 ObPartitionGroup 结构,包含了 partition 的全部基线信息,包括 sstable 信息。每个 item 载入内存的过程依然是调用 ObPartitionMetaRedoModule::load_partition

SLog

SLog 是 meta 的增量数据,相关介绍可以阅读 SLog 结构介绍 文档,这里我们简单介绍几种具体的 SLog 日志类型。


MacroBlockMeta SLog(main_type = OB_REDO_LOG_MACROBLOCK)


该日志对应于旧版本的MacroBlockMeta,新版本不再使用。

只有一种日志类型:CHANGE_MACRO_BLOCK_META


CHANGE_MACRO_BLOCK_META:某个 macro block 的元数据发生了变更。每个 log entry 是ObMacroBlockMetaLogEntry结构,包含 block_id 和ObMacroBlockMeta,意味着整个新Macro Block元数据都在 log 里。

struct ObMacroBlockMetaLogEntry {  int64_t data_file_id_;  int64_t disk_no_;  int64_t block_index_;  ObMacroBlockMeta& meta_ptr_;};
复制代码

TableMgr SLog(main_type = OB_REDO_LOG_TABLE_MGR)


该日志对应于旧版本的 TableMgrMeta,新版本不再使用。


包含三种日志:REDO_LOG_CREATE_SSTABLEREDO_LOG_COMPELTE_SSTABLE 和 REDO_LOG_DELETE_SSTABLE


REDO_LOG_CREATE_SSTABLE:不支持。


REDO_LOG_COMPELTE_SSTABLE:增加了一个 sstable。每个 log entry 是 ObCompleteSSTableLogEntry 结构,包含了 table_key 和 ObOldSSTable

struct ObCompleteSSTableLogEntry {  ObOldSSTable& sstable_;};
复制代码

REDO_LOG_DELETE_SSTABLE:删除了一个 sstable。每个 log entry 是 ObDeleteSSTableLogEntry 结构,包含了 table_key。

struct ObDeleteSSTableLogEntry {  ObITable::TableKey table_key_;};
复制代码

TenantConfigMeta Slog (main_type = OB_REDO_LOG_TENANT_CONFIG)


该日志新旧版本都使用。


只有一种日志类型:REDO_LOG_UPDATE_TENANT_CONFIG


REDO_LOG_UPDATE_TENANT_CONFIG:租户配置发生变更。每个 log entry 是 ObUpdateTenantConfigLogEntry结构,包含 TenantUnits,replay 时会将原有 tenant_units_ 重置并全部更新,意味着即使只有一个租户配置变化,log 里还是保存了所有租户的配置。

struct ObUpdateTenantConfigLogEntry {  share::TenantUnits& units_;};
复制代码

PartitionMeta SLog (main_type = OB_REDO_LOG_PARTITION)


该日志新旧版本都使用,并且旧版本的部分日志类型迁移到了该日志下。


由于日志种类比较多,这里只介绍部分日志类型,感兴趣的同学可以进一步阅读代码(ObPartitionMetaRedoModule::replay)。


REDO_LOG_ADD_PARTITION/REDO_LOG_ADD_PARTITION_GROUP/REDO_LOG_ADD_PARTITION_TO_PG:增加 partition 或者 pg。每个 log entry 是 ObChangePartitionLogEntry 结构,只包含了ObPartitionKey/ObPGKey 等标识信息。

struct ObChangePartitionLogEntry {  common::ObPartitionKey partition_key_;  common::ObReplicaType replica_type_;  common::ObPGKey pg_key_;  uint64_t log_id_;};
复制代码

REDO_LOG_ADD_SSTABLE:某 partition 增加了 sstable。每个 log entry 是 ObAddSSTableLogEntry 结构,包含 ObPGKey 和 ObSSTable。replay 时会将 ObSSTable 添加到 ObPGStorage::sstable_mgr_ 里的 table_map_

struct ObAddSSTableLogEntry {  common::ObPGKey pg_key_;  ObSSTable& sstable_;};
复制代码

REDO_LOG_CHANGE_MACRO_META:某个 macro block 的元数据发生了变更。该日志与旧版本的CHANGE_MACRO_BLOCK_META 类型日志一致。每个 log entry 是 ObPGMacroBlockMetaLogEntry 结构,包含 block id 和 ObMacroBlockMetaV2

struct ObPGMacroBlockMetaLogEntry {  ObPGKey pg_key_;  ObITable::TableKey table_key_;  int64_t data_file_id_;  int64_t disk_no_;  blocksstable::MacroBlockId macro_block_id_;  blocksstable::ObMacroBlockMetaV2& meta_;};
复制代码

恢复流程

启动恢复过程的调用栈如下:

ObStoreFile::open(bool)>> ObLocalFileSystem::start() // 开源上是ObLocalFileSystem,可能还有其他FileSystem>>> ObPartitionService::start()>>>> ObServer::start()>>>>> main(int, char **)
复制代码

主要分为三个流程:

1.加载元数据的快照点,即将分区和 sstable 的信息还原进内存

2.回放 slog,将分区和 sstable 的信息更新到最新状态

3.从分区的元信息中获取 clog 的回放位点,开始回放 clog 日志生成 memory table


其中前两步调用 ObStoreFile::read_checkpoint_and_replay_log 完成,这里只介绍这一过程,建议参照代码阅读。


ObStoreFile::read_checkpoint_and_replay_log

1.根据 super_block 的版本走不同的分支

2.v2 版本(旧版本),先读出 ObSuperBlockV2 super_block,然后调用 ObServerCheckpointLogReaderV1::read_checkpoint_and_replay_log

3.v3 版本(新版本),直接调用 ObServerCheckpointLogReader::read_checkpoint_and_replay_log


ObServerCheckpointLogReaderV1::read_checkpoint_and_replay_log

1.首先 ObServerCheckpointLogReaderV1::read_checkpoint 读取所有的 meta blockmacro_meta/table_mgr_meta/partition_meta/tenant_config_meta),并使用对应元数据的类解析函数 parse 出相应的信息恢复到内存(比如 partition_meta 能够解析出每个分区的基础信息以及包含的 sstable 信息,将以某种结构保存到内存),然后将所有 meta block 的 block id 存到同一个数组,进而在内存维护每个 meta block 的引用状态。

2.接着 ObServerCheckpointLogReaderV1::replay_slog 恢复 SLog,首先根据 super block 中的 replay_start_point_ 位置从 SLog 读取每一条 log,记录 begin 和 commit(ObStorageLogCommittedTransGetter::init),然后 ObStorageLogReplayer::replay 进行日志回放,同样从 replay_start_point_ 位置开始读 SLog,log 的 trans id 如果是已经 commited 的(上一步记录了),那么 redo 该日志,即调用该 log type 对应的 replay 函数。


ObServerCheckpointLogReader::read_checkpoint_and_replay_log

1.首先读出 ObServerSuperBlock super_block(第一级 Super Block

2.从 super_block 获取 SLog 回放入口点 replay_start_point_,从该位置读取每一条 log,记录 begin 和 commit(ObStorageLogCommittedTransGetter::init

3.ObServerCheckpointLogReader::read_tenant_file_super_block_checkpoint 读取所有 tenant 的 super block meta(这些 super block meta 相当于第一级 meta,第二级的 super block,和 super_block 在同一个文件上,入口点在 super_block上 ,也是多个 macro block 前向链接而成):首先ObPGMetaBlockReader::init 从 super block meta 入口点读取所有的super block metaObPGMetaBlockReader::get_meta_blocks),并反向预取出第一个 meta block 的数据保存在内存,接着将反向读取每一个 meta block;然后依次解析每个 meta item,将每个tenant和其对应的 file 以 map 的形式保存在内存(ObBaseFileMgr::replay_alloc_file

4.ObServerCheckpointLogReader::read_tenant_meta_checkpoint读取所有 tenant config meta block:首先 ObTenantConfigMetaCheckpointReader::init 从 super block meta 入口点读取所有的 super block metaObPGMetaBlockReader::get_meta_blocks),并反向预取出第一个 meta block 的数据保存在内存,接着将反向读取每一个 meta block;然后依次解析每个 meta item ,不断重新覆盖 tenant configObTenantConfigMgr::load_tenant_units)

5.ObServerCheckpointLogReader::replay_server_slog回放第一级 meta(tenant 的 super block metatenant config meta)的 SLog,调用 ObStorageLogReplayer::replay 进行日志回放,从replay_start_point位置开始读 SLog,log 的 trans id 如果是已经 commit 的(第 2 步记录了),那么 redo,调用相应的 replay 函数(只会对上述两种 meta 的 SLog 触发 replay)

6.ObServerCheckpointLogReader::read_pg_meta_checkpoint 根据第 3 步得到的 map 依次回放每个tenant 的二级元数据,每个 tenant 的回放调用ObTenantFilePGMetaCheckpointReader::read_checkpoint:首先从 tenent 的 file_info 能够得到 tenant_file_super_block_,从而获得 macro meta 和 pg meta 的 block 入口点,然后首先通过ObPGMacroMetaCheckpointReader::read_checkpoint 读取 macro meta 并保存在一个从 tenant_mgr 得到的 replay_map中,接着通过 ObPGMetaCheckpointReader::read_checkpoint读取 pg meta,每个 item 包含一个 pg 的信息,使用 ObPartitionMetaRedoModule::load_partition 将其解析并载入到内存

7.ObServerCheckpointLogReader::replay_other_slog 回放第二级 meta(每个 tenant 的 macro meta 以及 pg meta)的 SLog,调用 ObStorageLogReplayer::replay进行日志回放,从replay_start_point 位置开始读 SLog,log 的 trans id 如果是已经 commit 的(第 2 步记录了),那么 redo,调用相应的 replay 函数(只会对上述两种 meta 的 SLog 触发 replay)

8.最后 ObServerCheckpointLogReader::set_meta_block_list 将所有meta block 的 block id 存到同一个数组,进而在内存维护每个 meta block 的引用状态。

回顾

在了解了宏块、各种宏块类型、SLog 以及从 Meta 和 SLog 恢复内存数据的过程后,将会更容易理解整个 OBServer 的存储结构。整个存储结构从上到下大致可以分为这样几层:



如果您有任何疑问,可以通过以下方式与我们进行交流:

微信群:扫码添加小助手,将拉你进群哟~



钉钉群:33254054



厚脸皮地来求个 star

我们想让 Github 上优质的开源项目被更多人看到。

文档都是我们精心整理。如果有帮助的话求个 star(◕ᴗ◕),鼓励鼓励我们哟!

也欢迎大家给我们提 issue,请点击 这里。运营小姐姐在此跪谢️️ (^_-)

欢迎大家一起参与社区贡献,指南请参考看 这里

社区答疑:请点击 这里


发布于: 4 小时前阅读数: 6
用户头像

OceanBase 社区版 2020.05.06 加入

github:https://github.com/oceanbase/oceanbase 欢迎大家

评论

发布
暂无评论
一文读懂 OceanBase 数据库的启动恢复代码解析