目标:让 experiment/read_perf/read_benchmark 能正确写入并读取 TsFile。
状态:全部修复完成,benchmark 正常运行。
运行 read_benchmark 时 ASAN 报 double-free,backtrace 指向 StringArrayDeviceID::~StringArrayDeviceID。
StringArrayDeviceID::deserialize(device_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:147:std::string* segment = nullptr;byte_stream.h read_var_char_ptr 入口:str = nullptr;(防御性初始化)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 判断是否需要跨页:
read_pos_=10x16 后 read_pos_=22 & 629 = 0(629 的 bit-1 未置位)→ 误触发跨页,read_page_ = next_ = nullptrE_OUT_OF_RANGE,read_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); // 实际数据量不变
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 有两个重载:
get_next_page(TsBlock*, Filter*, PageArena&) — 正确检查 multi_value_mode_,路由到 get_next_page_multiget_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:147 | segment 初始化为 nullptr |
src/common/allocator/byte_stream.h | wrap_from 取 2 的幂;read_var_char_ptr 入口 str=nullptr |
src/reader/aligned_chunk_reader.cc | 第 2 个 get_next_page 重载添加 multi_value_mode_ 检查 |
所有临时 [DEBUG] 调试输出已清理。