pjfanning opened a new pull request, #1226:
URL: https://github.com/apache/pekko-http/pull/1226
### Motivation
`LineParser` scanned its buffer one byte at a time:
```scala
bs(at) match {
case CR_BYTE if at < bs.length - 1 && bs(at + 1) == LF_BYTE => ...
```
The buffer is built as `buffer ++ grab(in)`, so it is a multi-fragment
`ByteString` whenever a line spans more than one chunk.
`ByteString$ByteStrings.apply` has no offset index or position cache - it walks
the fragment vector from the first fragment on every access - so scanning an
SSE line that arrives in N chunks costs O(bytes × N).
`ByteString.indexOf(byte, from)` is the opposite: it walks fragments once
and, inside a fragment, uses `SWARUtil` to test 8 bytes per step.
### Modification
Jump to the next CR or LF with `indexOf` instead of testing every byte. The
three identical line-emitting blocks are factored into a local `lineAt` helper.
Line termination semantics are unchanged - CR, LF, CRLF, a lone CR followed
by a non-LF byte, and a CRLF split across two chunks (the `lastCharWasCr` flag)
all behave exactly as before. The oversized-line handling (`maxLineSize` and
every `OversizedSseStrategy`) is untouched, just moved into the helper.
### Result
`LineParserBenchmark`, JDK 21, `-f 1 -wi 3 -i 3`:
| lineSize | chunkSize | before | after | |
|---|---|---|---|---|
| 1 KB | 512 | 0.265 ms/op | 0.189 ms/op | within noise |
| 1 KB | 8192 | 0.295 ms/op | 0.183 ms/op | within noise |
| 128 KB | 512 | 71.210 ms/op | 1.013 ms/op | ~70x |
| 128 KB | 8192 | 3.269 ms/op | 0.342 ms/op | ~10x |
| 1 MB | 512 | 9821.281 ms/op | 54.361 ms/op | ~180x |
Small lines are unaffected; the gain scales with how many chunks a line is
split across, which is exactly the shape of a real SSE stream over a network.
Note this is independent of the pending pekko-core change that gives
`ByteStrings.apply` a fragment hint. That hint helps monotonic forward scans,
but `indexOf` still avoids one virtual call per byte and tests 8 bytes at a
time, and this change also benefits the 1.x line, which is pinned to pekko
1.1.5.
### Tests
- `sbt "http-tests / Test / testOnly
org.apache.pekko.http.scaladsl.unmarshalling.sse.*"` - 48 passed (46 existing,
plus 2 new in `LineParserSpec`: a CRLF split across two chunks, and lines
parsed out of an explicitly multi-fragment `ByteString`, asserted non-compact
so the test really covers the rope path).
- `sbt "http-bench-jmh/Jmh/run …"` - numbers above, measured before and
after on the same machine.
- `scalafmt --mode diff-ref=upstream/main` - clean.
### References
None - found while auditing ByteString usage across the code base
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]