blob: 27a4c36d7341e471d51ea060486cec406c3bab86 [file] [view]
# Read Benchmark Crash Debug Log
目标:让 `experiment/read_perf/read_benchmark` 能正确写入并读取 TsFile
**状态:全部修复完成,benchmark 正常运行。**
---
## Bug 1:double-free crash(exit 134 / SIGABRT)
### 现象
运行 `read_benchmark` ASAN double-freebacktrace 指向 `StringArrayDeviceID::~StringArrayDeviceID`
### 根因
`StringArrayDeviceID::deserialize``device_id.cc:147`)中:
```cpp
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;`(防御性初始化)
---
## 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`
- 读取长度前缀 `0x16` `read_pos_=2`
- `2 & 629 = 0`629 bit-1 未置位)→ **误触发跨页**,`read_page_ = next_ = nullptr`
- 返回 `E_OUT_OF_RANGE``read_var_str` 中止,`key=""` 只消耗了 1 字节
### 修复
**`byte_stream.h`** `wrap_from` 中将 `page_size_` 向上取整到最近的 2 的幂:
```cpp
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 行):
```cpp
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]` 调试输出已清理。