Rocksdb提供一种方法,用于自定义逻辑在后台线程删除或者修改 key/value对。这在用于自定义垃圾回收的时候非常方便,比如根据TTL删除超时的key,或者在后台删除一个区间的key。同时这可以用于更新一个已经存在的key的值。
为了使用CompactionFilter,应用程序需要实现 CompactionFilter接口,然后在ColumnFamilyOptions里面设置。或者,应用程序可以实现CompactionFilterFactory接口,他提供一个更加灵活的方法,用于针对不同的(子)压缩任务,创建不同的CompactionFilter。CompactionFilter工厂还可以根据CompactionFilter::Context变量知道一些压缩上下文信息(这是一个全量压缩还是一个人工触发压缩)。工厂可以根据上下文返回不同的CompactionFilter。
options.compaction_filter = new CustomCompactionFilter();
// or
options.compaction_filter_factory.reset(new CustomCompactionFilterFactory());
这两种提供CompactionFilter的方式来自不同的线程安全需求。如果一个CompactionFilter提供给了RocksDB,他必须是线程安全的,因为多个子压缩可能并行运行,并且他们都是用同一个CompactionFilter实例。如果一个CompactionFilter工厂被提供,每个子压缩会调用工厂来构造一个CompactionFilter实例。因此可以保证每个CompactionFilter实例都只会被一个线程访问,并且CompactionFilter不需要保证线程安全。不过线程压缩器工厂可能被多个子压缩并行访问。
CompactionFilter在落盘的时候不会被调用,落盘也是一种压缩。
有两组API可以用于CompactionFilter的实现。Filter/FilterMergeOperand API提供一个简单的回调,用于告知压缩过程是否需要过滤一个key/value对。FilterV2 API通过允许修改value或者删除从当前的key开始的一个范围的key,来拓展基础API。
每当一个子压缩看到一个输入进来的新的key,并且他的value是普通value,他就调用CompactionFilter。根据CompactionFilter的结果:
如果压缩的输入里面有同一个key的多个版本,CompactionFilter只会对最新的版本调用一次。如果最新的版本是一个删除标记,CompactionFilter也不会调用。然而,CompactionFilter可能针对一个已经删除的key被调起,如果这次压缩的输入里面没有把这个key标记为删除。
当合并被使用,CompactionFilter会在每个合并操作的时候调起。CompactionFilter的结果会在合并操作符之前被应用到合并操作。
6.0以前 如果在key/value对之后创建了快照,这个key/value对不能被过滤,而且CompactionFilter也不会被调用。
6.0之后这个功能发现有bug不太好修干脆删了,这样key就不会被pin住,snapshot无法原样生成了。注意