Uh oh!
There was an error while loading. Please reload this page.
Decompress: reuse the caller-supplied buffer for unknown-size frames - #168
Conversation
c4263b9 to
06c5aaaComparedf06769 to
7406064CompareUh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
| } | ||
| contentSize := decompressSizeHint(src) | ||
| contentSize, _ := decompressSizeHint(src) |
There was a problem hiding this comment.
we should make it the same logic here to be consistent ?
There was a problem hiding this comment.
Added a comment about why this diverges
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
7406064 to
539664dCompareDecompress sized its destination from decompressSizeHint(src), which reads the frame's content-size field. Frames that do not carry that field make the hint fall back to a pessimistic upper bound (>= decompressSizeBufferLimit, i.e. 1 MB): this is the case for legacy zstd v0.5 frames and for streaming frames compressed without a pledged source size. When the caller passed a smaller-but-adequate buffer, Decompress discarded it and allocated that bound, so every such decode allocated at least 1 MB regardless of the real payload size. decompressSizeHint now also reports whether the size was read from the frame (foundHint). When it was not, Decompress and ctx.Decompress try the caller-supplied buffer first via DecompressInto -- which reports a too-small buffer without writing past it -- before falling back to the hint-sized allocation and then the stream API. When the size is known (the common case where the same zstd version compressed and decompressed) the original path is unchanged, so callers passing a too-small buffer do not pay for a failed attempt. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
539664d to
ddc2cccCompare
Viq111
left a comment
There was a problem hiding this comment.
✅
(I've disabled circleCI for future runs / PR since we moved to github actions)
PR Shepherd is now watching this PR: fixing basic CI failures, rebasing when it falls behind, and re-queueing after transient merge-queue failures. To disable it, add the If you have any questions, reach the team in #ai-devx-flow. |
Uh oh!
There was an error while loading. Please reload this page.
Problem
Decompresssizes its destination buffer fromdecompressSizeHint(src), which reads the frame's content-size field. Frames that don't carry that field make the hint fall back to a pessimistic upper bound (max(50×len(src), decompressSizeBufferLimit)— at least 1 MB). This happens for:ZSTD_getFrameContentSizereports unknown), andWhen a caller passes a smaller-but-adequate buffer,
Decompressdiscards it (cap(dst) < bound) and allocates the full bound. So every decode of such a frame allocates at least 1 MB regardless of the real payload size — a significant per-call heap/GC cost for callers decoding many small unknown-size payloads with a pooled/hinted buffer.Fix
decompressSizeHintnow also returnsfoundHint— whether the decompressed size was actually read from the frame header.Decompressandctx.Decompressselect the destination buffer with a single switch, make oneDecompressInto, and fall back to the streaming reader only if that buffer is too small:cap(dst) >= hint— reuse the caller buffer (unchanged from before).!foundHint && cap(dst) > 0— size unknown, so reuse the caller buffer as-is rather than allocating the pessimistic bound.hint(the exact size when known; the bound when unknown and no caller buffer was supplied).Consequences:
DecompressInto.The same change is applied to
ctx.Decompress;BulkProcessor.Decompressis adapted to the new signature with its behavior preserved.Regression tests cover caller-buffer reuse (unknown- and known-size), the too-small fallback,
nildst, and thefoundHintsignal — run as subtests against bothDecompressandctx.Decompress.🤖 Generated with Claude Code