Repository navigation
pxf: DatasetReader lexes a long token once, however many reads it spans (#168) - #172
Merged
Merged
Conversation
trendvidia
force-pushed
the
dataset-scan-linear-168
branch
from
November 7, 2026 04:23
2c84b66 to
3f3e817
Compare
…ns (#168) A token still open at the end of a read was lexed again from its start on every 4 KiB read, so an unclosed string, bytes literal, comment or number of n bytes cost about n*n/8192 byte visits: 136 MB for 1 MiB, 540 MB for 2 MiB. As protowire-go's reader does (mayEndToken), the scan now records the open token and lexes it again only when the bytes read since could end it: a closing quote not escaped by an odd run of backslashes, a newline, `"""`, `*/`, a byte that ends a run, a byte that cannot continue an identifier or number, or a bytes literal reaching max_bytes_literal_length. A token under 8 bytes is always lexed again. The header scan resumes too. It keeps its place in the header between reads, and an @proto body is matched by a resumable BraceMatch, which FindMatchingBrace now wraps. Tests DatasetReaderScan.IsLinear and HeaderIsLinear count the bytes lexed (through a test peer) for Go's shapes plus a long bytes literal, at 1 and 2 MiB, and for headers near the 64 KiB budget. They allow twice the input and see about 1.004x. With the waiting rule turned off, 18 of the 20 row cases and the long-string header case fail.
trendvidia
force-pushed
the
dataset-scan-linear-168
branch
from
November 7, 2026 06:49
3f3e817 to
38a9ca2
Compare
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.
Fixes #168. Built on #167 (#164), which brought in the lexer-based scan this changes. #167 has merged, and this PR is rebased onto
main(531c586).What was wrong
A token still open at the end of a 4 KiB read was lexed again from its start on every read. That covers an unclosed string, a bytes literal, a comment, or one long number or identifier. A token of n bytes cost about n²/8192 byte visits: 136 MB of lexing for 1 MiB, 540 MB for 2 MiB. The header scan lexed the whole buffer from the start on every read.
What changes
The reader now does what protowire-go's reader does (
mayEndToken). The scan records the open token, and lexes it again only when the bytes read since could end it:"""or*/;max_bytes_literal_length.A token under 8 bytes is always lexed again. The rule only decides when the lexer looks again, never what the token is. The header scan now keeps its place between reads too. An
@protobody is matched byBraceMatch, a resumable form ofFindMatchingBrace, which now wraps it.Evidence
Bytes lexed, counted through a test peer (
DatasetReaderTestPeer), for an unclosed row after the header, read 4 KiB at a time:The off figures fit n²/8192, which is 134 M for 1 MiB, and they grow 4× for 2× the input. All 10 shapes behave the same way: Go's 9, plus a long bytes literal. For a header near 64 KiB with one long string, 65,555 bytes are lexed against 552,853 with waiting off.
DatasetReaderScan.IsLinearandHeaderIsLinearallow twice the input. With the waiting rule turned off (a local patch, not committed), 18 of the 20 row cases fail and so does the long-string header case. The two that pass are the short-tokens control.ctest: 732/732 locally (macOS). clang-format 18 is clean. clang-tidy 23 on the changed sources and headers reports nothing new.Not in this PR
Go's third test in the same file,
CompleteRowIsNotHeldBack, needs a live stream, and cpp'sPullusesstd::istream::read, which waits for a full 4 KiB. That's #171. Go's one-byte-reader variants of these tests have no cpp equivalent until #171, since every read is 4 KiB or the rest of the input.