streamDecrypt buffers quadratically: recopies the whole accumulated buffer on every network read #21
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
streamDecryptinsrc/download/index.tsaccumulates incoming network data into a singleUint8Arrayand reallocates plus recopies the entire accumulated buffer on every read:For a chunk of
STREAM_CHUNK_SIZE(4 MiB) delivered as N network reads, that is O(chunk² / read)bytes copied, repeated for every chunk in the file.
buffer.slice(ENC_CHUNK_SIZE)after each pullcopies the remainder again.
Measured while working on #1: decrypting a single 4 MiB secretstream chunk from an in-memory
Responsebody takes on the order of a second, against roughly 20 ms of actual libsodium work.Essentially all of it is the buffering loop. On real multi-hundred-megabyte videos this is the
dominant cost of a backup run, and it is pure memory churn.
Suggested direction
Keep the incoming reads in an array of
Uint8Arraywith a running byte count, and onlymaterialise a contiguous buffer when a full
ENC_CHUNK_SIZEboundary has been reached (copyingeach source piece exactly once). Nothing about the wire format, the chunk framing, or the public
signatures needs to change.
Definition of done
streamDecryptcopies each received byte a bounded number of times, independent of file size.truncation cases added in #1 — the chunk boundary behaviour must be identical.
ReadableStreamwhich deliberately yields manysmall pieces, verifying the plaintext is still byte-identical.
make checkgreen, and the suite is not slower than before.Out of scope
Streaming the plaintext to disk instead of buffering the whole file in memory. That is a larger
change to the
DownloadResultcontract and belongs in its own issue.