Skip to content

Commit c34bd70

Browse files
committed
preallocate
1 parent f16e912 commit c34bd70

File tree

3 files changed

+32
-4
lines changed

3 files changed

+32
-4
lines changed

sdk/src/Services/S3/Custom/Transfer/Internal/BufferedPartDataHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ private async Task<IPartDataSource> BufferPartFromResponseAsync(
280280
_logger.DebugFormat("BufferedPartDataHandler: [Part {0}] Buffering {1} bytes using chunked buffer stream",
281281
partNumber, expectedBytes);
282282

283-
chunkedStream = new ChunkedBufferStream();
283+
chunkedStream = new ChunkedBufferStream(expectedBytes);
284284

285285
_logger.DebugFormat("BufferedPartDataHandler: [Part {0}] Reading response stream into chunked buffers",
286286
partNumber);

sdk/src/Services/S3/Custom/Transfer/Internal/ChunkedBufferStream.cs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,40 @@ internal class ChunkedBufferStream : Stream
7878
/// </summary>
7979
private const long MAX_STREAM_SIZE = (long)int.MaxValue * CHUNK_SIZE;
8080

81-
private readonly List<byte[]> _chunks = new List<byte[]>();
81+
private readonly List<byte[]> _chunks;
8282
private long _length = 0;
8383
private long _position = 0;
8484
private bool _isReadMode = false;
8585
private bool _disposed = false;
8686

87+
/// <summary>
88+
/// Creates a new ChunkedBufferStream with default initial capacity.
89+
/// </summary>
90+
public ChunkedBufferStream()
91+
{
92+
_chunks = new List<byte[]>();
93+
}
94+
95+
/// <summary>
96+
/// Creates a new ChunkedBufferStream with pre-allocated capacity for the expected size.
97+
/// This avoids List resizing during writes, improving performance for known sizes.
98+
/// </summary>
99+
/// <param name="estimatedSize">The estimated total size in bytes. Used to pre-allocate the chunk list capacity.</param>
100+
public ChunkedBufferStream(long estimatedSize)
101+
{
102+
if (estimatedSize > 0)
103+
{
104+
// Calculate number of chunks needed and cap at int.MaxValue for List capacity
105+
long estimatedChunks = (estimatedSize + CHUNK_SIZE - 1) / CHUNK_SIZE;
106+
int capacity = (int)Math.Min(estimatedChunks, int.MaxValue);
107+
_chunks = new List<byte[]>(capacity);
108+
}
109+
else
110+
{
111+
_chunks = new List<byte[]>();
112+
}
113+
}
114+
87115
/// <summary>
88116
/// Throws <see cref="ObjectDisposedException"/> if the stream has been disposed.
89117
/// </summary>

sdk/src/Services/S3/Custom/Transfer/Internal/ChunkedPartDataSource.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,12 @@ public ChunkedPartDataSource(int partNumber, ChunkedBufferStream stream)
102102
/// are not currently available, or zero if the end of the stream is reached.
103103
/// </returns>
104104
/// <exception cref="ObjectDisposedException">Thrown if the object has been disposed.</exception>
105-
public async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
105+
public Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
106106
{
107107
if (_disposed)
108108
throw new ObjectDisposedException(nameof(ChunkedPartDataSource));
109109

110-
return await _stream.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false);
110+
return _stream.ReadAsync(buffer, offset, count, cancellationToken);
111111
}
112112

113113
/// <summary>

0 commit comments

Comments
 (0)