Skip to content

Commit 1bf025a

Browse files
Rent byte buffers in SqlSequentialTextReader (#2356)
1 parent 9811c65 commit 1bf025a

File tree

1 file changed

+27
-18
lines changed

1 file changed

+27
-18
lines changed

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlSequentialTextReader.cs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6+
using System.Buffers;
67
using System.Buffers.Binary;
78
using System.Diagnostics;
89
using System.Text;
@@ -18,7 +19,8 @@ sealed internal class SqlSequentialTextReader : System.IO.TextReader
1819
private readonly int _columnIndex; // The index of out column in the table
1920
private readonly Encoding _encoding; // Encoding for this character stream
2021
private readonly Decoder _decoder; // Decoder based on the encoding (NOTE: Decoders are stateful as they are designed to process streams of data)
21-
private byte[] _leftOverBytes; // Bytes leftover from the last Read() operation - this can be null if there were no bytes leftover (Possible optimization: re-use the same array?)
22+
private byte[] _leftOverBytes; // Bytes leftover from the last Read() operation - this can be null if there were no bytes leftover
23+
private int _leftOverByteBufferUsed; //Number of bytes used from _leftOverBytes buffer - will be zero in case of null buffer
2224
private int _peekedChar; // The last character that we peeked at (or -1 if we haven't peeked at anything)
2325
private Task _currentTask; // The current async task
2426
private readonly CancellationTokenSource _disposalTokenSource; // Used to indicate that a cancellation is requested due to disposal
@@ -357,23 +359,18 @@ private byte[] PrepareByteBuffer(int numberOfChars, out int byteBufferUsed)
357359

358360
if (_leftOverBytes != null)
359361
{
360-
// If we have more leftover bytes than we need for this conversion, then just re-use the leftover buffer
361-
if (_leftOverBytes.Length > byteBufferSize)
362-
{
363-
byteBuffer = _leftOverBytes;
364-
byteBufferUsed = byteBuffer.Length;
365-
}
366-
else
367-
{
368-
// Otherwise, copy over the leftover buffer
369-
byteBuffer = new byte[byteBufferSize];
370-
Buffer.BlockCopy(_leftOverBytes, 0, byteBuffer, 0, _leftOverBytes.Length);
371-
byteBufferUsed = _leftOverBytes.Length;
372-
}
362+
// Copy over the leftover buffer
363+
byteBuffer = ArrayPool<byte>.Shared.Rent(byteBufferSize);
364+
Buffer.BlockCopy(_leftOverBytes, 0, byteBuffer, 0, _leftOverByteBufferUsed);
365+
byteBufferUsed = _leftOverByteBufferUsed;
366+
//return _leftOverBytes and clean _leftOverBytes reference
367+
ArrayPool<byte>.Shared.Return(_leftOverBytes);
368+
_leftOverBytes = null;
369+
_leftOverByteBufferUsed = 0;
373370
}
374371
else
375372
{
376-
byteBuffer = new byte[byteBufferSize];
373+
byteBuffer = ArrayPool<byte>.Shared.Rent(byteBufferSize);
377374
byteBufferUsed = 0;
378375
}
379376
}
@@ -402,14 +399,26 @@ private int DecodeBytesToChars(byte[] inBuffer, int inBufferCount, char[] outBuf
402399
// completed may be false and there is no spare bytes if the Decoder has stored bytes to use later
403400
if ((!completed) && (bytesUsed < inBufferCount))
404401
{
405-
_leftOverBytes = new byte[inBufferCount - bytesUsed];
406-
Buffer.BlockCopy(inBuffer, bytesUsed, _leftOverBytes, 0, _leftOverBytes.Length);
402+
_leftOverByteBufferUsed = inBufferCount - bytesUsed;
403+
_leftOverBytes = ArrayPool<byte>.Shared.Rent(_leftOverByteBufferUsed);
404+
405+
Buffer.BlockCopy(inBuffer, bytesUsed, _leftOverBytes, 0, _leftOverByteBufferUsed);
407406
}
408407
else
409408
{
410409
// If Convert() sets completed to true, then it must have used all of the bytes we gave it
411410
Debug.Assert(bytesUsed >= inBufferCount, "Converted completed, but not all bytes were used");
412-
_leftOverBytes = null;
411+
if (_leftOverBytes != null)
412+
{
413+
ArrayPool<byte>.Shared.Return(_leftOverBytes);
414+
_leftOverBytes = null;
415+
_leftOverByteBufferUsed = 0;
416+
}
417+
}
418+
419+
if (inBuffer.Length > 0)
420+
{
421+
ArrayPool<byte>.Shared.Return(inBuffer);
413422
}
414423

415424
Debug.Assert(((_reader == null) || (_reader.ColumnDataBytesRemaining() > 0) || (!completed) || (_leftOverBytes == null)), "Stream has run out of data and the decoder finished, but there are leftover bytes");

0 commit comments

Comments
 (0)