MyTopling 分布式 Compact(二):CompactionFilter

一、背景

MyTopling 是基于 ToplingDB 的 MySQL,分叉自 MyRocks,ToplingDB 则分叉自 RocksDB,兼容 RocksDB 接口,从而 MyTopling 可以复用 MyRocks 的大部分成果。

ToplingDB 和  MyTopling 目前都已经开源。

ToplingDB 的一个重要功能是 分布式 Compact(文档),去年我们实现了 托管Todis 的 分布式 Compact 支持。同样是基于 ToplingDB,分布式 Compact 自然也是 MyTopling 的重要功能。

系列文章上一篇:MyTopling 分布式 Compact(一):从多线程到多进程

二、CompactionFilter 介绍

在稍微复杂点的 RocksDB 应用中,都少不了使用 CompactionFilter,虽然可以直接在 Options 中设置 CompactionFilter 对象,但我们还是更多地使用 CompactionFilterFactory,因为 CompactionFilter 经常是有状态的,而不是一个纯函数,所以需要动态创建并且在单个 subcompact 中维护其状态。

在原版 RocksDB 中,应用代码需要设置 ColumnFamilyOptions.compaction_filter_factory 来实现自己的 CompactionFilter 业务逻辑。在 MyRocks 中,CompactionFilter 用来删除两种数据:

ttl 过期的数据需要在数据字典中找到 ttl 的保存位置(在 value 中偏移),才能读取 ttl
被删除的 index/table需要在数据字典中找到正在删除的 index/table

在 MyRocks 中,table 其实只是一种特殊的 index(primary index)。

三、分布式 Compact 怎么支持 CompactionFilter

原版 RocksDB 也有跟 ToplingDB 分布式 Compact 类似的东西,叫做 RemoteCompaction(Experimental),貌似还不支持自定义 CompactionFilter。

ToplingDB 则不同,从一开始,ToplingDB 就通过 SidePlugin 来管理所有的 DB 配置信息,包括 CompactionFilterFactory,所以,在应用代码中,我们只需要修改一点代码,将我们自定义的 CompactionFilterFactory 注册到 SidePlugin 体系即可。我们在 CompactionFilterFactory As SidePlugin 中对此进行了详细说明。

如果 CompactionFilter 是个纯函数,那问题就会非常简单,只需要向 Compact Worker 结点传输类名就可以了,然而现实的 CompactionFilter 几乎都会包含状态,所以,ToplingDB 的 SidePlugin 框架从一开始就考虑了这个问题:对象序列化。具体到这里就是 CompactionFilterFactory 的序列化:

四、SidePlugin 框架怎么支持序列化

在原版 MyRocks 中,CompactionFilter 需要访问数据字典,而数据字典是个全局对象,并且其中的信息总是最新的,直接访问就行,所以 Rdb_compact_filter 的实现非常简单。

在 MyTopling 中,使用 SidePlugin 提供的机制,将 CompactionFilter 用到的信息进行序列化/反序列化:

class Rdb_compact_filter_factory {
// ...
};
//ROCKSDB_REG_DEFAULT_CONS(Rdb_compact_filter_factory, CompactionFilterFactory);
struct Rdb_compact_filter_factory_SerDe : SerDeFunc<CompactionFilterFactory> {
  const CompactionParams* m_cp;
  Rdb_compact_filter_factory_SerDe(const json& js, const SidePluginRepo&) {
    m_cp = JS_CompactionParamsDecodePtr(js);
    // more init ...
  }
  void Serialize(FILE* output, const CompactionFilterFactory& base)
  const override {
    if (IsCompactionWorker()) {
      // write compaction result info about compaction filter
    } else {
      // write required data dictionary info for compaction filter
    }
  }
  void DeSerialize(FILE* input, CompactionFilterFactory* base)
  const override {
    if (IsCompactionWorker()) {
      // read required data dictionary info for compaction filter
    } else {
      // read compaction result info about compaction filter
    }
  }
};
ROCKSDB_REG_PluginSerDe(Rdb_compact_filter_factory);

SerDe 是 Serialization/Deserialization 的缩写,其含义不言自明,可以看到,给 ROCKSDB_REG_PluginSerDe 传递的参数就是 Rdb_compact_filter_factory,在 ROCKSDB_REG_PluginSerDe 的定义中,自动给该参数加了个 _SerDe 后缀。

在具体细节上,本来就像上面代码中写的,使用

ROCKSDB_REG_DEFAULT_CONS(Rdb_compact_filter_factory, CompactionFilterFactory);

就可以注册 Rdb_compact_filter_factory,但是在 MyTopling 中,相关对象的初始化是通过全局对象的构造来实现的,所以对象构造的顺序非常重要,所以,我们将 Rdb_compact_filter_factory 的注册放在 http://ha_rocksdb.cc 中:

// New_Rdb_compact_filter_factory was forward declared
ROCKSDB_FACTORY_REG_0("Rdb_compact_filter_factory", New_Rdb_compact_filter_factory);

ROCKSDB_FACTORY_REG_0 是更下层,更明确的注册指令。

五、代码阅读指引

  1. class Rdb_compact_filter
    1. 是否是已删除的索引
    2. 是否 ttl 超时
  2. class Rdb_compact_filter_factory
    1. 从数据字典获取需要序列化的信息
    2. 更新全局信息
  3. 注册 Rdb_compact_filter_factory
  4. Rdb_compact_filter_factory_SerDe注册序列化

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值