fix(storage): fail the download instead of committing bad chunk data - #71
Open
define-null wants to merge 3 commits into
Open
fix(storage): fail the download instead of committing bad chunk data#71define-null wants to merge 3 commits into
define-null wants to merge 3 commits into
Conversation
Drives the real ChunkDownloader against exact raw responses. Four of these fail today: a redirect, a non-parquet body, a truncated table and an empty one are all committed as chunk data, because the commit gate is the HTTP status alone (INV-13, GAP-5). The redirect case carries a valid table as its body, so only the status can tell it apart from the file it points at. The rest guard what already holds: a well-formed table commits, and an interruption is caught whenever the response framing makes it visible. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The commit gate was the HTTP status alone, so whatever bytes arrived became the chunk. Two checks close what a worker can decide on its own. A 3xx passes `error_for_status`, and the client follows no redirects, so the redirect response was being written as the table. Reject any non-2xx. Parse the parquet footer of each downloaded table — the same read the query engine does when it opens a chunk, so a committed file is one the read path can open. That covers an empty or substituted file, and a truncation the response framing left invisible to hyper. Page data is not decoded and the assignment carries no size or digest, so GAP-5's remainder stays open. `parquet` was already in the normal dependency graph through sqd-query and sqd-query-engine; declaring it directly costs no extra compilation. A rejected file fails its whole chunk: the staging directory is swept and the existing retry and give-up path applies unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…n handle Open the file read+write and hand the same handle to the footer parse once the copy is done, instead of re-opening it on the blocking pool. The parse is two small reads of a file just written, so it runs inline like the other fs ops in this module. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Problem
A chunk committed when every file's HTTP status was not 4xx/5xx and the body copied without an I/O error. Nothing looked at the bytes. Two ways bad data was being committed and served until an assignment stopped naming it:
error_for_statuspasses 3xx, so the redirect response's body was written as the table.reading parquet metadata …(server_error), permanently: recovery adopts chunks by directory name and reconciliation only queues absent chunks, so a bad chunk is never re-fetched.Fix
In
download_one:.parquetfooter withParquetMetaDataReader— the same read the query engine does when it opens a chunk. Footer only, page data isn't decoded.parquetwas already in the graph viasqd-queryandsqd-query-engine;Cargo.lockis unchanged.A rejected file fails its chunk: the staging directory is swept and the existing retry/give-up path applies unchanged.
Tests
tests/download_integrity.rsdrives the realChunkDownloaderagainst exact raw responses. The first commit adds the tests — 4 of 7 fail onmaster— and the second makes them pass. The redirect case carries a valid parquet body, so only the status check can reject it; each check was confirmed load-bearing by disabling it in turn.Not covered here
DatasetsIndex::new.🤖 Generated with Claude Code