Repository navigation
Conversation
An integer time column declared with timestamp_format "%Y%m%d" was formatted as a string and parsed by chrono for every row. Eight-digit values that form a valid date now go straight to the date; everything else takes the existing text parse, so results are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change mapObserved failure: reading an integer Existing behavior: Smallest sufficient change: for the compiled Focused verification: a unit test compares against the text parse over valid and invalid dates and edge values; an exhaustive sweep of all eight-digit values found no mismatches; indexes ingested on main and on this branch return identical temporal results. Stopping condition: integer
|
|
Important Review skippedReview was skipped as selected files did not have any reviewable changes.
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Summary
An integer time column declared with
timestamp_format: "%Y%m%d"(values like20240301) is read inRowAccess::timestamp_inby formatting each integer as a string (a heap allocation) and parsing it with chrono, first as a date-time, which always fails for a date-only format, and then as a date. That costs roughly 300 ns per value on a per-row path. Ingestion runs it for every row of such a column, for example when the column is an edge's sort key time. Temporal queries will also run it for every candidate row once they read declared formats (#205).String columns with the same format already go through a byte-level fast parser (
TimestampFormatParser), but integer columns never reached it.The fix: before the text round-trip, an eight-digit integer under the
%Y%m%dparser is split into year, month and day arithmetically and checked with chrono'sNaiveDate::from_ymd_opt. Everything else takes the existing text path unchanged: other formats, values that are not eight digits, and invalid dates such as20231345or20230229. The existing string fast parserparse_compact_ymd_fastis not reused because it does not validate month or day (it accepts month 13).Change map
#223 (comment)
Measured
Synthetic
users -> eventsgraph with 10M events and an int64t_ymdcolumn declared%Y%m%d, on a 64-core box using release wheels. Each figure is a median of 5 runs.t_ymdas the edge sort key timeTemporal queries on main read this column as epoch seconds and never reach this path. With #205 merged locally underneath, the cases that read the column from row data speed up. The sort-key path doesn't parse it, so that case is unchanged. These temporal numbers come from a single round and may be off by a few percent.
query_temporal, time column not the sort keyquery_temporal_lengths, time column not the sort keyquery_temporal, time column is the sort keyquery_temporal_lengths, time column is the sort keyBack-compat
Results are identical. chrono's
%Y%m%dreads exactly four year digits, then two month digits and two day digits, and accepts the value exactly whenfrom_ymd_optdoes. So the new path returns a value exactly when the old one did, with the same seconds. A sweep over all 90,000,000 eight-digit values against chrono 0.4.45 found no mismatches. Shorter values that chrono also reads as dates (for example the seven-digit2024031, which it reads as 2024-03-01) still take the old path.Indexes ingested on main and on this branch return the same temporal results for every user at three cutoffs: the same lengths, row ids and times, through the sort-key path. Their files are not byte-comparable because ingest output differs from run to run on main too.
Testing Done
integer_yyyymmdd_matches_text_parsecompares the result against the text parse (falling back to the epoch reading when it fails) over valid and invalid months and days in six years, plus 7-, 9-digit, zero, negative andi64extreme values.cargo test -p diskgraph-rowpack(319 tests), the timestamp and date tests ofcargo test -p diskgraph-ingest, andcargo clippy -p diskgraph-rowpack --all-targets -- -D warningspass.Hotfix Context
Not a hotfix or backport.
Checklist
🤖 Generated with Claude Code