ClickHouse 源代码零散笔记:mark 与 final mark
根据
ClickHouse 的 MergeTree 基本概念和基本原理 https://www.cnblogs.com/jthmath/p/16809828.html
所述,ClickHouse 用 mark 记录每个颗粒在列存文件的位置。本文叙述 ClickHouse 代码中对 mark 的处理。
行数与行号的计算
ClickHouse 中有个比较重要的类
class MergeTreeIndexGranularity
{
private:
std::vector<size_t> marks_rows_partial_sums;
// 其他
}
marks_rows_partial_sums 指的是,每个 mark 以及之前的 mark 对应的行数之和。它的长度就是 mark 的数量。
将 marks_rows_partial_sums 简记为 s,则根据它的含义,有:
- 0 号 mark 的行数是 \(s_0\),
- \(i\) 号 mark 的行数是 \(s_i−s_{i−1}\)。
- 0 号 mark 的起始行号自然是 0,
- \(i\) 号 mark 的起始行号是 \(0+s_{i−1}=s_{i−1}\)。
这里的 \(i > 0\)。
final mark 指的是结尾处额外一个 mark,它的值和上一个相等。也就是说,mark 号加了 1,但总行数没增加,是一个傀儡 mark。从我的日志调试结果来看,final mark 总是存在的。或许是旧版本的实现中没有,
目前来看,作用是快速判断是否终止,快速获取行数。
上面的计算式对应代码:
// 计算行数
size_t MergeTreeIndexGranularity::getMarkRows(size_t mark_index) const
{
if (mark_index >= getMarksCount())
{
throw Exception(ErrorCodes::LOGICAL_ERROR, "Trying to get non existing mark {}, while size is {}", mark_index, getMarksCount());
}
if (mark_index == 0)
{
return marks_rows_partial_sums[0];
}
else
{
return marks_rows_partial_sums[mark_index] - marks_rows_partial_sums[mark_index - 1];
}
}
// 计算起始行号
size_t MergeTreeIndexGranularity::getMarkStartingRow(size_t mark_index) const
{
return mark_index == 0 ? 0 : marks_rows_partial_sums[mark_index - 1];
}
final mark 的处理
class MergeTreeIndexGranularity
{
public:
// 获取最后一个 mark(无论是否 final)的行数
size_t getLastMarkRows() const
{
size_t last = marks_rows_partial_sums.size() - 1;
return getMarkRows(last);
}
size_t getLastNonFinalMarkRows() const
{
size_t last_mark_rows = getLastMarkRows();
if (last_mark_rows != 0)
{
return last_mark_rows;
}
return getMarkRows(marks_rows_partial_sums.size() - 2);
}
bool hasFinalMark() const
{
return getLastMarkRows() == 0;
}
// 其他
}
例
设索引颗粒度 g = 20(这里是为了计算简便,实际没有这么干的)。而当前的 data part 中有 r = 62 行,且每个颗粒中的行数相同,则需要 ceil(r/g) = ceil(62 / 20) = 4 个 mark,还需要一个 final mark。其值分别为 20,40,60,62,62。
参考日志
2022.06.14 09:07:31.711734 total_mark = 60
2022.06.14 09:07:31.711782 num_rows_total = 481808
2022.06.14 09:07:31.715601 mark = 55, start_row = 450560, mark_rows = 8192
2022.06.14 09:07:31.715669 mark = 56, start_row = 458752, mark_rows = 8192
2022.06.14 09:07:31.715737 mark = 57, start_row = 466944, mark_rows = 8192
2022.06.14 09:07:31.715784 mark = 58, start_row = 475136, mark_rows = 6672
2022.06.14 09:07:31.715854 mark = 59, start_row = 481808, mark_rows = 0
可以看到,final mark 的起始行和总行数一样,它的行数为 0。

浙公网安备 33010602011771号