Bug 1: registered-but-empty measurements are sealed as EMPTY chunks, making Java readers refuse the file
Environment: TsFileCpp 2.3.2.dev (cpp tree-model writer)
When a tree-model TsFileWriter registers a measurement but receives no data for it during a window (e.g. event-driven parameters that fire sporadically, or a wide schema where only a subset of columns receive values), flush_chunk_group() / flush_chunk_group_encoded() seal that column as an empty chunk:
[Chunk] of <device>.<measurement>, startTime: 9223372036854775807 endTime: -9223372036854775808 count: 0
[Chunk Header] marker=5, dataSize=0, size=78
Java readers treat this as a crashed file — TsFileSequenceReader self-check fails (self-check cannot proceed at position ... because: 0) and TsFileSketchTool throws IOException: ... because the file has crashed plus an NPE while printing the empty chunk. The whole file becomes unreadable by the Java toolchain, even though most chunks contain valid data.
Cause: the non-aligned branch of both flush functions only checks m_schema->chunk_writer_ != nullptr and lacks the hasData() guard that the aligned branch already has:
if (!chunk_group->is_aligned_ && m_schema->chunk_writer_ != nullptr) {
FLUSH_CHUNK(chunk_writer, ...); // seals count=0 chunk when empty
}
Expected behavior: an empty column should produce no chunk (mirroring the aligned branch and Java IoTDB behavior).
Bug 2: dangling reference capture in parallel aligned tablet write
In write_table() (aligned parallel path), the lambdas submitted to the thread pool capture the loop variables by reference:
for (auto& ctx : device_ctxs) {
futures.push_back(common::g_thread_pool_->submit(
[&write_time_segments, &ctx]() { ... })); // captures loop var by reference
for (auto& vt : ctx.value_tasks) {
futures.push_back(common::g_thread_pool_->submit(
[&write_value_segments, &vt, &ctx]() { ... }));
}
}
submit enqueues the task for asynchronous execution on pool threads. When the worker threads run the tasks, the loop has already advanced (or exited), so the references dangle / alias the same loop slot — reading out-of-scope or wrong ctx/vt state. This is a use-after-scope bug that can corrupt parallel tablet writes when parallel_write_enabled_ is on.
Expected behavior: capture the per-iteration addresses by value (ctx_ptr/vt_ptr) so each task reads its own DeviceWriteCtx/ValueTask.
Bug 1: registered-but-empty measurements are sealed as EMPTY chunks, making Java readers refuse the file
Environment: TsFileCpp 2.3.2.dev (cpp tree-model writer)
When a tree-model
TsFileWriterregisters a measurement but receives no data for it during a window (e.g. event-driven parameters that fire sporadically, or a wide schema where only a subset of columns receive values),flush_chunk_group()/flush_chunk_group_encoded()seal that column as an empty chunk:Java readers treat this as a crashed file —
TsFileSequenceReaderself-check fails (self-check cannot proceed at position ... because: 0) andTsFileSketchToolthrowsIOException: ... because the file has crashedplus an NPE while printing the empty chunk. The whole file becomes unreadable by the Java toolchain, even though most chunks contain valid data.Cause: the non-aligned branch of both flush functions only checks
m_schema->chunk_writer_ != nullptrand lacks thehasData()guard that the aligned branch already has:Expected behavior: an empty column should produce no chunk (mirroring the aligned branch and Java IoTDB behavior).
Bug 2: dangling reference capture in parallel aligned tablet write
In
write_table()(aligned parallel path), the lambdas submitted to the thread pool capture the loop variables by reference:submitenqueues the task for asynchronous execution on pool threads. When the worker threads run the tasks, the loop has already advanced (or exited), so the references dangle / alias the same loop slot — reading out-of-scope or wrongctx/vtstate. This is a use-after-scope bug that can corrupt parallel tablet writes whenparallel_write_enabled_is on.Expected behavior: capture the per-iteration addresses by value (
ctx_ptr/vt_ptr) so each task reads its ownDeviceWriteCtx/ValueTask.