Iteration 13 从 5/7 开始到 5/20 结束,为期两周。这个周期成功合并了不少之前提交的 PR,感觉非常有成就感。
difftastic
difftastic 是一个使用 Rust 开发的能理解语义的 diff 工具。
在这个周期中,我合并了两个 PR:
fix: Bad padding of column numbers at the end of files 修复了文件末尾的 padding 不正确问题:
这里的 str2
应当需要跟上面的 Violets
悬空对齐,但是并没有。简单的调试后发现是计算 padding 的时候错误地忽略了一些情况,去掉之后就修复了:
feat: Improve binary content guess 则是改进了二进制内容的检测算法。
在过去,difftastic 使用一种比较简单粗暴的方法来检测二进制文件:
let num_replaced = String::from_utf8_lossy(bytes)
.to_string()
.chars()
.take(1000)
.filter(|c| *c == std::char::REPLACEMENT_CHARACTER || *c == '\0')
.count();
num_replaced > 20
在前一千个字节中寻找非法的 Unicode 字符以及 \0
,如果超过 20 个就认为是二进制文件。在 Issue Treat PDFs as binary files 中,作者希望能够检测 PDF 并将其作为二进制文件处理。给定一个文件头,要求我们判断是否为二进制文件,其实很容易可以想到根据 magic number 来判断。我在 PR 中引入了 tree_magic_mini
来检测这段内容的 MIME,并对常见的二进制类型做了统一的处理:
let mime = tree_magic_mini::from_u8(bytes);
match mime {
// Treat pdf as binary.
"application/pdf" => return true,
// Treat all image content as binary.
v if v.starts_with("image/") => return true,
// Treat all audio content as binary.
v if v.starts_with("audio/") => return true,
// Treat all video content as binary.
v if v.starts_with("video/") => return true,
// Treat all font content as binary.
v if v.starts_with("font/") => return true,
_ => {}
}
这样 difftastic 就能够正确地处理绝大多数二进制类型了。
databend
正如上个周报中提到的,这个周期我花了不少功夫来提升 Databend 配置的兼容性。在 RFC: Config Backward Compatibility 的推动下,我为 databend-query
和 databend-meta
都加上了配置的兼容层。同时在 PR refactor: Reuse StorageConfig in stage 中还为内部的 Storage 相关配置做了大范围重构,使得内部的逻辑都可以共享同一个配置文件,不需要再重复实现相似的逻辑。
处理 databend-meta
的配置兼容比较坎坷,因为内部的配置项特别多,又经历了不少重构,所以 meta 有不少配置项,其中不少配置项还都没有遵循统一的命名风格。所以在纠结了很久之后,我发现了 serfig
的全新用法:
pub fn load() -> MetaResult<Self> {
let arg_conf = Self::parse();
let mut builder: serfig::Builder<Self> = serfig::Builder::default();
// Load from the config file first.
{
let config_file = if !arg_conf.config_file.is_empty() {
arg_conf.config_file.clone()
} else if let Ok(path) = env::var("METASRV_CONFIG_FILE") {
path
} else {
"".to_string()
};
builder = builder.collect(from_file(Toml, &config_file));
}
// Then, load from env.
let cfg_via_env: ConfigViaEnv = serfig::Builder::default()
.collect(from_env())
.build()
.map_err(|e| MetaError::InvalidConfig(e.to_string()))?;
builder = builder.collect(from_self(cfg_via_env.into()));
// Finally, load from args.
builder = builder.collect(from_self(arg_conf));
builder
.build()
.map_err(|e| MetaError::InvalidConfig(e.to_string()))
}
用户可以维护一个独立的 cfg env wrapper,从 env loading 数据并转换成 cfg。不过这种用法对于少量的 env 不兼容来说还是比较麻烦。@DCjanus 在 Issue Add bind attribute support 中同样提到了类似的需求。
总结
下个周期后专注于 Databend 读取压缩文件的支持,后面 databend 将能够实现直接读取 gzip,zstd 等压缩文件~