Repository navigation
perf(load): make the csv overwrite's fragment write a streaming operator - #1178
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
eeb614b to
5c1ea03
Compare
|
Recommendation: revise. The published graph stays one overwrite and one publish. Revise the written memory contract so it matches that code. One blocking finding. Three optional findings. WhyA WhatEach parse partition now fills a fragment of up to 1,048,576 rows while the rows drain. A full fragment goes to a Lance writer. At most How the overwrite stays one publication
A producer error sets A crash before publication leaves the graph unchanged. A crash after the manifest commit keeps the publication. Parse partitions own contiguous source ranges, so ImpactThe working set of a streaming overwrite is the open chunks plus the writers in flight. The pool charges an open chunk through Blocking
The new sentences above say a streaming overwrite writes a fragment per parse partition as the rows drain, and that its working set is the open fragments plus the writers in flight. These two sentences still say a That pair is now false.
Please make these three pages describe one contract: when the first fragment file appears, what a Optional
This loop deletes CSV load rejects Blob and Vector (
This 1.2× figure is a local measurement. This review has no rerun of the SF30 load. The baseline in the pull request text is Tradeoff and liabilityThis removes the need to hold the whole typed delta before the first Lance call. It adds one owner for uncommitted overwrite files ( The new state is the chunk order, the in-flight bound, and the file list a refusal deletes. Each one earns its place. The liability that stays open is the written limit. An operator who sizes Alignment#1174 (open) sizes unique-holder tables with #1158 is the parent of this design. This change is the sink that #1158 left until after the verdict. #1156, #1171, #1168, #1177, and #818 need no change here. An overwrite still drops indexes. Fragment identity stays the identity of the fragment files. Cleanup already owns unreferenced objects under Lance 13.0.0 (the pinned crate, unmodified) matches this use. ValidationHead On the head, from
On the merge base, after
LimitationsSF30, S3, Azure, the full workspace test graph, clippy, and |
c976c59 to
4ca4c24
Compare
Since #1158 a
load csvoverwrite parses its source by partition and checks uniqueness as the rows drain, but its write is still a pipeline breaker: the sink materializes every validated batch and starts its Lance writers only after the validate operator's verdict on the whole delta, a serial tail of 45 s in SF30's 104 s load, with the delta held twice until then.The sink now writes as the rows drain: each parse partition fills fragments of up to 1 Mi rows, and a full fragment goes to one of
stage_write_concurrencyLance writers while the next rows arrive. The planner decides per statement whether the validate operator streams (every check swept as the rows pass and settled in the judgment after the drain) or stays a breaker (a retained-edge check, a judged endpoint check or a removal scan reads the whole delta), so a streaming load plans as one pipeline from the source through the write. The guard is the refusal path: nothing commits before the statement's one publish, and a refusal that arrives after fragments were written deletes them and reports the validate operator's verdict, so a refused load leaves no fragment behind and the table version never moves.LDBC SF30, release builds of
2af30259and this branch, two interleaved rounds, medians: load 104.5 → 87.2 s, the write phase after the last row 45.4 → 3.6 s, the writers' remaining work now inside the parse and validate walls. A sink test counts Lance'sdata/files across a refused run that had written fragments, and two corpus cases pin, at 10-row fragments, that a refusal past written fragments keeps the committed rows and reports the validate operator's text and value.For review: the decision to challenge is the validate operator's shape as a plan decision, streaming whenever no check reads the whole delta after the drain, with lowering refusing an operator whose emission disagrees with the plan. Least sure is refusal precedence in the streaming shape: the sink's keyed-write check can meet a key repeated inside one full fragment before the verdict, so the staging drains its input to that verdict before deleting; it is pinned at 10-row fragments and not run at the default 1 Mi. A delta parsed in several partitions now lands as one fragment per partition where it was one per 1 Mi rows; the store format and the overwrite transaction are unchanged. A crash between the first fragment write and the publish leaves unreferenced files under
data/for the cleanup that already reclaims that class, over a longer window than before.