Two pool-retention sites kept the runaway-RSS pattern in #6541 visible
even after #9420 and #9421:
* weed/util/buffer_pool: SyncPoolPutBuffer dropped a buffer back into
sync.Pool regardless of how big it had grown. After a 64 MiB chunk
upload through volume.PostHandler -> needle.ParseUpload, the pool
hoarded a 64 MiB byte array per cached entry for the rest of the
process's lifetime. Cap retention at 4 MiB; oversized buffers are
dropped so GC can reclaim the backing array.
* weed/s3api/...copy.go: uploadChunkData left UploadOption.BytesBuffer
unset, so operation.upload_content fell back to the package-global
valyala/bytebufferpool. That pool also retains high-water buffers
forever, and concurrent UploadPartCopy filled it with one chunk-sized
buffer per concurrent upload. Provide a fresh per-call bytes.Buffer
pre-sized to chunk + multipart framing; it's GC'd as soon as the
upload returns.
Tests:
- weed/util/buffer_pool/sync_pool_test.go: pin the cap (oversized
buffers don't round-trip), the inverse (right-sized buffers do), and
nil-safety.
- weed/s3api/...copy_chunk_upload_test.go: extract newChunkUploadOption
and pin that BytesBuffer is always non-nil and pre-sized, and that
each call gets a distinct buffer.