perf(cpp): cache per-device schema check for repeated tablet writes (#885) - #934
Open
kkzi wants to merge 2 commits into
Open
perf(cpp): cache per-device schema check for repeated tablet writes (#885)#934kkzi wants to merge 2 commits into
kkzi wants to merge 2 commits into
Conversation
added 2 commits
September 2, 2026 09:06
Repeated tablet/record writes with a fixed device schema re-resolve every measurement name against measurement_schema_map_ on each write, which is a CPU hotspot for wide schemas (apache#885). Cache the resolved chunk writers and data types per device in MeasurementSchemaGroup, keyed by the measurement NAME SEQUENCE (column count alone is not a safe key: entries are reused by position, so a same-count tablet with a different name order would write values into the wrong column with the wrong data type). A mismatch drops the stale cache and re-resolves. The plain and aligned paths keep separate caches. Only fully-resolved results are cached: a NULL chunk writer for a not-yet-registered measurement must not be pinned, or the column would stay masked even after it is registered.
Five cases pinning the behaviors the cache must preserve: - repeated same-schema writes round-trip every row (hit path, incl. after a flush seals and resets the chunk writers); - a same-column-count tablet with different names/order re-resolves and writes each value into the column its name says; - a column unregistered at first write is not masked by a cached NULL after it is registered (only fully-resolved results are cached); - the aligned path keeps its own cache with the same guarantees; - per-device caches never cross-wire two devices.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Title:
perf(cpp): cache per-device schema check for repeated tablet writes (#885)
Body:
Problem
Closes #885.
TsFileWriter::do_check_schema/do_check_schema_alignedre-resolve everymeasurement name against
measurement_schema_map_on everywrite_tablet/write_tablet_aligned/write_recordcall, even thoughthe device schema is registered once and does not change during the file
lifecycle. For wide tablets written repeatedly this per-column string lookup
is a top CPU hotspot (profiling in #885).
Change
Cache the resolved chunk writers and data types per device in
MeasurementSchemaGroup(cpp/src/common/schema.h), resolved once andreused while the tablet's measurement name sequence is unchanged:
are reused by position, so the same count with a different name order (or
one column swapped) would silently write values into the wrong column with
the wrong data type. A mismatch drops the stale cache and re-resolves, so
dynamic schemas keep the existing validation behavior.
whichever path runs first lock the other out permanently).
not-yet-registered measurement must not be pinned, or the column would
stay masked even after it is registered later.
returns:
chunk_writer_is only freed indestroy(), flush only resetsit, and
register_timeseriesreturnsE_ALREADY_EXISTfor an existingname instead of replacing the object, so a cached pointer cannot dangle.
do_check_schema_table(table model) is unchanged; this targets the treemodel paths named in #885.
Tests
New suite
SchemaCheckCacheTest(cpp/test/writer/tsfile_writer_schema_cache_test.cc):RepeatedSameSchemaRoundTrip— hit path, incl. after a flush seals andresets the chunk writers; asserts every row and column (no dropped rows).
SameCountDifferentNamesAndOrder— same column count with a swapped /reordered name set re-resolves; values land in the column their name says.
ColumnRegisteredAfterFirstWriteIsNotMasked— the fully-resolved-onlyguard: a column unregistered at first write is written once registered.
AlignedRepeatedAndReorder— aligned path: own cache, hit + reorder.MultiDeviceCachesIndependent— two devices with identical measurementnames, interleaved writes, no cross-wiring.
Full suite: 830 tests, 827 passed, 3 skipped (environment-only skips:
external-index and cross-language fixture generators), 0 failures.
Benchmark
A/B microbenchmark (not committed — happy to add it to the tree if wanted):
one device, 200 INT32/PLAIN columns, 2000 tablet writes × 1 row each (the
few-rows-wide-tablet shape from the issue), parallel write disabled, best of
5 rounds, MSVC 2019 x64:
The schema check was ~43% of the total
write_tablettime in this shape.With more rows per tablet the end-to-end percentage shrinks (the saving is
per write, the encode cost is per point), but the per-column lookup remains
the dominant fixed cost per call — which is what #885 profiles.
Notes
can follow the direction from the maintainer feedback in Optimize TsFileWriter::do_check_schema CPU overhead for repeated wide-tablet writes #885.