Repository navigation
Conversation
A block's TAG (id) column repeats the same value on every row, but ColAppender::fill() appended it row by row: one add_row() plus one append() per row. On a 3.2M-row table scan reading the TAG column this showed up as ~10% of read time in a sampled profile. Add Vector::fill_repeated() (defaulting to a per-row loop) with overrides for the fixed-length and variable-length vectors. Both build the value pattern once and then double the filled region, so the per-row work becomes a single memcpy copy step instead of a full append. 3.2M-row full scan: 0.298s -> 0.269s (~10%) with unchanged output.
Exercise the fixed-length and variable-length overrides directly: value and length correctness after multiple fills, row counters, capacity overflow rejection, and the zero-count no-op.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #1088 +/- ##
===========================================
- Coverage 66.51% 66.50% -0.01%
===========================================
Files 778 782 +4
Lines 56577 56761 +184
Branches 9105 9141 +36
===========================================
+ Hits 37633 37751 +118
- Misses 17291 17344 +53
- Partials 1653 1666 +13 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Review follow-ups on the new fill path: * Both ByteBuffer fill helpers wrote the first element before looking at count, so a count == 0 call wrote into the slack after the data — or past the end of an exactly-full buffer. Return early instead. * FixedLengthVector::fill_repeated used the caller's len as the element stride while every read path advances by type_len_. Use type_len_ and assert the caller agrees. * ColAppender::fill reported every failure (including E_OOM from a failed growth) as E_INVALID_ARG; propagate the actual code. Tests: zero-count at the ByteBuffer level (fails without the guard) and a variable-length fill larger than the per-row reservation, which exercises the grow-and-copy path.
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
3 open issues
What changed in this PR
This PR optimizes filling repeated TAG/id column values by adding bulk “fill repeated” APIs at the Vector/ByteBuffer layers and updating ColAppender to use them, reducing per-row append overhead.
Changes:
- Added
Vector::fill_repeated()with specialized overrides in fixed/variable-length vectors. - Added
ByteBuffer::fill_repeated_variable()/fill_repeated_fixed()using a doublingmemcpystrategy. - Updated
ColAppender::fill()to use bulk fill and added targeted regression tests.
| File | Description |
|---|---|
| cpp/test/common/tsblock/tslock_test.cc | Adds tests covering repeated fill for fixed/variable vectors, overflow handling, grow path, and zero-count no-op. |
| cpp/src/common/tsblock/vector/vector.h | Introduces Vector::fill_repeated() default implementation. |
| cpp/src/common/tsblock/vector/variable_length_vector.h | Overrides fill_repeated() to use ByteBuffer::fill_repeated_variable(). |
| cpp/src/common/tsblock/vector/fixed_length_vector.h | Overrides fill_repeated() to use ByteBuffer::fill_repeated_fixed(). |
| cpp/src/common/tsblock/tsblock.h | Switches ColAppender::fill() to call vec_->fill_repeated() and handles row count/capacity checks. |
| cpp/src/common/container/byte_buffer.h | Adds bulk repeated-fill helpers implementing doubling-copy strategy. |
Review effort: Lite
Return E_INVALID_ARG when the caller's len differs from type_len_ instead of relying on ASSERT, which is compiled out in release and would make the fill read past a shorter value buffer. Also include <cstring> for std::memcpy and copy test values into aligned locals instead of reinterpret_cast'ing the row buffer.
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
5 open issues
std::memcpy(dst, &len, variable_type_len_)assumesvariable_type_len_ <= sizeof(len); otherwise… · Newstd::memcpy(dst, &len, variable_type_len_)assumesvariable_type_len_ <= sizeof(len); otherwise… · Newreinterpret_cast<int32_t*>(read)can be undefined behavior on platforms that require alignment… · New The newly added<cstring>include does not appear to be used in the shown changes. If it’s not… · New This initializes only the first 3 bytes and copies all 16 bytes into the buffer. While not… · New
3 resolved since last review
Review effort: Lite
Return E_INVALID_ARG if variable_type_len_ ever exceeds sizeof(uint32_t) before the length prefix is copied from a uint32_t (it is fixed to sizeof(uint32_t) today, but make the invariant explicit). Also copy the int32_t test value out with memcpy instead of reinterpret_cast'ing the row buffer, which is what <cstring> was added for.
Same isolation fix as the writer tests: parallel CTest processes can seed the name generator in the same clock tick, and one then removes the file another is opening (E_ALREADY_EXIST at the fixture's open, observed on the macOS 3.11 and py-msvc 3.11 jobs). Append pid and a per-process counter.



Problem
A block's TAG (id) column repeats the same value on every row, but
ColAppender::fill()appended it row by row — oneadd_row()plus oneappend()per row. On a table scan that reads the TAG column this showed up as ~10% of read time in a sampled profile (fill_ids -> ColAppender::fill -> append).Change
Vector::fill_repeated(value, len, count), defaulting to the existing per-row loop, overridden byFixedLengthVectorandVariableLengthVector.ByteBuffer::fill_repeated_variable()/fill_repeated_fixed()helpers: write the value pattern once, then double the filled region, so the per-row work becomes one memcpy step instead of a full append.ColAppender::fill()now callsfill_repeated()and keeps the same capacity/error checks.Benchmark
3.2M-row full scan, single thread:
~10% faster with identical output.
Testing
Full C++ suite: 1454 tests passed.