Read Benchmark Crash Debug Log

目标:让 experiment/read_perf/read_benchmark 能正确写入并读取 TsFile。

状态:全部修复完成,benchmark 正常运行。


Bug 1:double-free crash(exit 134 / SIGABRT)

现象

运行 read_benchmark 时 ASAN 报 double-free,backtrace 指向 StringArrayDeviceID::~StringArrayDeviceID

根因

StringArrayDeviceID::deserializedevice_id.cc:147)中:

for (uint32_t i = 0; i < num_segments; ++i) {
    std::string* segment;   // ← 未初始化!
    if (RET_FAIL(read_var_char_ptr(segment, read_stream))) {
        delete segment;     // ← 若失败,segment 持有上一次迭代残留的栈值
        return ret;
    }
    segments_.push_back(segment);
}

循环第二次迭代时,若 read_var_char_ptr 失败,segment 因栈帧复用持有上一次成功分配的 指针(已进入 segments_),delete segment 提前释放,析构函数再释放一次,触发 double-free。

修复

  • device_id.cc:147std::string* segment = nullptr;
  • byte_stream.h read_var_char_ptr 入口:str = nullptr;(防御性初始化)

Bug 2:unordered_map::at: key not found(元数据反序列化失败)

现象

double-free 修复后,TsFileMeta::deserialize_from 读到 table_schemas_size=0, 后续 table_schemas_.at("bench_table") 抛异常。

根因

wrap_from(tsfile_meta_buf, 630) 设置:

page_size_ = 630
page_mask_ = 629   // 0b1001110101,非 2 的幂

check_space()(read_pos_ & page_mask_) == 0 判断是否需要跨页:

  • 读取 1 字节(map_size)后 read_pos_=1
  • 读取长度前缀 0x16read_pos_=2
  • 2 & 629 = 0(629 的 bit-1 未置位)→ 误触发跨页read_page_ = next_ = nullptr
  • 返回 E_OUT_OF_RANGEread_var_str 中止,key="" 只消耗了 1 字节

修复

byte_stream.h wrap_from 中将 page_size_ 向上取整到最近的 2 的幂:

uint32_t ps = 1;
while (ps < (uint32_t)buf_len) ps <<= 1;
page_size_ = ps;
page_mask_ = ps - 1;
total_size_.store(buf_len);  // 实际数据量不变

Bug 3:ASSERT(false) in decode_tv_buf_into_tsblock_by_datatype

现象

[DEBUG] unexpected data_type_=255
Assertion failed: ((false)), function decode_tv_buf_into_tsblock_by_datatype,
    file aligned_chunk_reader.cc, line 1233.

根因

AlignedChunkReader::get_next_page 有两个重载:

  1. get_next_page(TsBlock*, Filter*, PageArena&) — 正确检查 multi_value_mode_,路由到 get_next_page_multi
  2. get_next_page(TsBlock*, Filter*, PageArena&, int64_t, int&, int&)缺少 multi_value_mode_ 检查

TsFileSeriesScanIterator::get_next 调用第 2 个重载(带 min_time_hint/row_offset/row_limit 参数)。即使 multi_value_mode_=true,也会进入单值解码路径,此时 value_chunk_header_ 从未被 load_by_aligned_meta 初始化,data_type_=255=INVALID_DATATYPE,触发 ASSERT。

修复

在第 2 个重载顶部添加 multi_value_mode_ 检查:

src/reader/aligned_chunk_reader.cc(第 1320 行):

int AlignedChunkReader::get_next_page(..., int64_t min_time_hint, int& row_offset, int& row_limit) {
    if (multi_value_mode_) {
        return get_next_page_multi(ret_tsblock, oneshoot_filter, pa);
    }
    ...

已修改文件(最终)

文件改动
src/common/device_id.cc:147segment 初始化为 nullptr
src/common/allocator/byte_stream.hwrap_from 取 2 的幂;read_var_char_ptr 入口 str=nullptr
src/reader/aligned_chunk_reader.cc第 2 个 get_next_page 重载添加 multi_value_mode_ 检查

所有临时 [DEBUG] 调试输出已清理。