Skip to content

Commit 0e74c9c

Browse files
committed
Implemented array return through disposal for ring-buffer
1 parent 21baa1b commit 0e74c9c

2 files changed

Lines changed: 91 additions & 2 deletions

File tree

src/FirebirdSql.Data.FirebirdClient/Client/Managed/FirebirdNetworkHandlingWrapper.cs

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
namespace FirebirdSql.Data.Client.Managed;
2727

28-
sealed class FirebirdNetworkHandlingWrapper : IDataProvider, ITracksIOFailure
28+
sealed class FirebirdNetworkHandlingWrapper : IDataProvider, ITracksIOFailure, IDisposable
2929
{
3030
public const string CompressionName = "zlib";
3131
public const string EncryptionName = "Arc4";
@@ -46,19 +46,23 @@ sealed class FirebirdNetworkHandlingWrapper : IDataProvider, ITracksIOFailure
4646
Org.BouncyCastle.Crypto.Engines.RC4Engine _decryptor;
4747
Org.BouncyCastle.Crypto.Engines.RC4Engine _encryptor;
4848

49+
bool _disposed;
50+
4951
public FirebirdNetworkHandlingWrapper(IDataProvider dataProvider)
5052
{
5153
_dataProvider = dataProvider;
5254

5355
_outputBuffer = new ByteRingBuffer(PreferredBufferSize);
5456
_inputBuffer = new ByteRingBuffer(PreferredBufferSize);
5557
_readBuffer = new byte[PreferredBufferSize];
58+
_disposed = false;
5659
}
5760

5861
public bool IOFailed { get; set; }
5962

6063
public int Read(byte[] buffer, int offset, int count)
6164
{
65+
EnsureNotDisposed();
6266
if (count <= 0)
6367
return 0;
6468

@@ -92,6 +96,7 @@ public int Read(byte[] buffer, int offset, int count)
9296

9397
public int Read(Span<byte> buffer, int offset, int count)
9498
{
99+
EnsureNotDisposed();
95100
if (count <= 0)
96101
return 0;
97102

@@ -119,6 +124,7 @@ public int Read(Span<byte> buffer, int offset, int count)
119124

120125
public async ValueTask<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken = default)
121126
{
127+
EnsureNotDisposed();
122128
if (count <= 0)
123129
return 0;
124130

@@ -152,6 +158,7 @@ public async ValueTask<int> ReadAsync(byte[] buffer, int offset, int count, Canc
152158

153159
public async ValueTask<int> ReadAsync(Memory<byte> buffer, int offset, int count, CancellationToken cancellationToken = default)
154160
{
161+
EnsureNotDisposed();
155162
if (count <= 0)
156163
return 0;
157164

@@ -187,6 +194,7 @@ public async ValueTask<int> ReadAsync(Memory<byte> buffer, int offset, int count
187194

188195
public void Write(ReadOnlySpan<byte> buffer)
189196
{
197+
EnsureNotDisposed();
190198
if (buffer.IsEmpty)
191199
return;
192200

@@ -209,6 +217,7 @@ public void Write(ReadOnlySpan<byte> buffer)
209217

210218
public void Write(byte[] buffer, int offset, int count)
211219
{
220+
EnsureNotDisposed();
212221
if (buffer == null || count <= 0)
213222
return;
214223

@@ -230,6 +239,7 @@ public void Write(byte[] buffer, int offset, int count)
230239
}
231240
public ValueTask WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken = default)
232241
{
242+
EnsureNotDisposed();
233243
if (buffer == null || count <= 0)
234244
return ValueTask.CompletedTask;
235245

@@ -257,6 +267,7 @@ async ValueTask WriteDirectAsync(byte[] directBuffer, int directOffset, int dire
257267

258268
public ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, int offset, int count, CancellationToken cancellationToken = default)
259269
{
270+
EnsureNotDisposed();
260271
if (count <= 0)
261272
return ValueTask.CompletedTask;
262273

@@ -284,6 +295,7 @@ async ValueTask WriteDirectAsync(ReadOnlyMemory<byte> directBuffer, int directOf
284295

285296
public void Flush()
286297
{
298+
EnsureNotDisposed();
287299
try
288300
{
289301
if (_compressor != null)
@@ -305,6 +317,7 @@ public void Flush()
305317
}
306318
public async ValueTask FlushAsync(CancellationToken cancellationToken = default)
307319
{
320+
EnsureNotDisposed();
308321
try
309322
{
310323
if (_compressor != null)
@@ -327,19 +340,22 @@ public async ValueTask FlushAsync(CancellationToken cancellationToken = default)
327340

328341
public void StartCompression()
329342
{
343+
EnsureNotDisposed();
330344
_compressionBuffer = new byte[PreferredBufferSize];
331345
_compressor = new Ionic.Zlib.ZlibCodec(Ionic.Zlib.CompressionMode.Compress);
332346
_decompressor = new Ionic.Zlib.ZlibCodec(Ionic.Zlib.CompressionMode.Decompress);
333347
}
334348

335349
public void StartEncryption(byte[] key)
336350
{
351+
EnsureNotDisposed();
337352
_encryptor = CreateCipher(key);
338353
_decryptor = CreateCipher(key);
339354
}
340355

341356
void FillInputBuffer()
342357
{
358+
EnsureNotDisposed();
343359
try
344360
{
345361
if (_decompressor == null)
@@ -380,6 +396,7 @@ void FillInputBuffer()
380396

381397
async ValueTask FillInputBufferAsync(CancellationToken cancellationToken)
382398
{
399+
EnsureNotDisposed();
383400
try
384401
{
385402
if (_decompressor == null)
@@ -420,6 +437,7 @@ async ValueTask FillInputBufferAsync(CancellationToken cancellationToken)
420437

421438
int HandleDecompression(byte[] buffer, int count)
422439
{
440+
EnsureNotDisposed();
423441
_decompressor.InputBuffer = buffer;
424442
_decompressor.NextOut = 0;
425443
_decompressor.NextIn = 0;
@@ -448,6 +466,7 @@ static void ResizeBuffer(ref byte[] buffer)
448466

449467
void FlushPlain()
450468
{
469+
EnsureNotDisposed();
451470
_outputBuffer.GetReadSegments(out var off1, out var len1, out var off2, out var len2);
452471

453472
try
@@ -481,6 +500,7 @@ void FlushPlain()
481500

482501
async ValueTask FlushPlainAsync(CancellationToken cancellationToken)
483502
{
503+
EnsureNotDisposed();
484504
_outputBuffer.GetReadSegments(out var off1, out var len1, out var off2, out var len2);
485505

486506
try
@@ -514,6 +534,7 @@ async ValueTask FlushPlainAsync(CancellationToken cancellationToken)
514534

515535
void FlushCompressed()
516536
{
537+
EnsureNotDisposed();
517538
_outputBuffer.GetReadSegments(out var off1, out var len1, out var off2, out var len2);
518539
try
519540
{
@@ -535,6 +556,7 @@ void FlushCompressed()
535556

536557
async ValueTask FlushCompressedAsync(CancellationToken cancellationToken)
537558
{
559+
EnsureNotDisposed();
538560
_outputBuffer.GetReadSegments(out var off1, out var len1, out var off2, out var len2);
539561
try
540562
{
@@ -556,6 +578,7 @@ async ValueTask FlushCompressedAsync(CancellationToken cancellationToken)
556578

557579
void DeflateAndWrite(byte[] input, int offset, int count, Ionic.Zlib.FlushType flushType)
558580
{
581+
EnsureNotDisposed();
559582
_compressor.InputBuffer = input;
560583
_compressor.NextIn = offset;
561584
_compressor.AvailableBytesIn = count;
@@ -589,6 +612,7 @@ void DeflateAndWrite(byte[] input, int offset, int count, Ionic.Zlib.FlushType f
589612

590613
async ValueTask DeflateAndWriteAsync(byte[] input, int offset, int count, Ionic.Zlib.FlushType flushType, CancellationToken cancellationToken)
591614
{
615+
EnsureNotDisposed();
592616
_compressor.InputBuffer = input;
593617
_compressor.NextIn = offset;
594618
_compressor.AvailableBytesIn = count;
@@ -627,11 +651,34 @@ static Org.BouncyCastle.Crypto.Engines.RC4Engine CreateCipher(byte[] key)
627651
return cipher;
628652
}
629653

630-
sealed class ByteRingBuffer
654+
public void Dispose()
655+
{
656+
if (_disposed)
657+
return;
658+
_disposed = true;
659+
660+
_inputBuffer.Dispose();
661+
_outputBuffer.Dispose();
662+
663+
_compressionBuffer = null;
664+
_compressor = null;
665+
_decompressor = null;
666+
_decryptor = null;
667+
_encryptor = null;
668+
}
669+
670+
void EnsureNotDisposed()
671+
{
672+
if (_disposed)
673+
throw new ObjectDisposedException(nameof(FirebirdNetworkHandlingWrapper));
674+
}
675+
676+
sealed class ByteRingBuffer : IDisposable
631677
{
632678
byte[] _buffer;
633679
int _head;
634680
int _count;
681+
bool _disposed;
635682

636683
public byte[] Buffer => _buffer;
637684
public int Count => _count;
@@ -641,10 +688,35 @@ public ByteRingBuffer(int initialCapacity)
641688
_buffer = ArrayPool<byte>.Shared.Rent(initialCapacity);
642689
_head = 0;
643690
_count = 0;
691+
_disposed = false;
692+
}
693+
694+
public void Dispose()
695+
{
696+
if (_disposed)
697+
return;
698+
_disposed = true;
699+
700+
var buffer = _buffer;
701+
_buffer = Array.Empty<byte>();
702+
_head = 0;
703+
_count = 0;
704+
705+
if (buffer.Length > 0)
706+
{
707+
ArrayPool<byte>.Shared.Return(buffer);
708+
}
709+
}
710+
711+
void EnsureNotDisposed()
712+
{
713+
if (_disposed)
714+
throw new ObjectDisposedException(nameof(ByteRingBuffer));
644715
}
645716

646717
public void EnsureFree(int bytes)
647718
{
719+
EnsureNotDisposed();
648720
if (bytes <= 0)
649721
return;
650722

@@ -657,6 +729,7 @@ public void EnsureFree(int bytes)
657729

658730
void Grow(int requiredCapacity)
659731
{
732+
EnsureNotDisposed();
660733
var newCapacity = _buffer.Length;
661734
while (newCapacity < requiredCapacity)
662735
{
@@ -682,6 +755,7 @@ void Grow(int requiredCapacity)
682755

683756
public void Write(ReadOnlySpan<byte> src)
684757
{
758+
EnsureNotDisposed();
685759
if (src.IsEmpty)
686760
return;
687761

@@ -702,6 +776,7 @@ public void Write(ReadOnlySpan<byte> src)
702776

703777
public int CopyTo(Span<byte> dst)
704778
{
779+
EnsureNotDisposed();
705780
if (dst.IsEmpty || _count == 0)
706781
return 0;
707782

@@ -719,6 +794,7 @@ public int CopyTo(Span<byte> dst)
719794

720795
public void Consume(int bytes)
721796
{
797+
EnsureNotDisposed();
722798
if (bytes <= 0)
723799
return;
724800

@@ -735,6 +811,7 @@ public void Consume(int bytes)
735811

736812
public void GetReadSegments(out int offset1, out int length1, out int offset2, out int length2)
737813
{
814+
EnsureNotDisposed();
738815
if (_count == 0)
739816
{
740817
offset1 = offset2 = length1 = length2 = 0;
@@ -749,6 +826,7 @@ public void GetReadSegments(out int offset1, out int length1, out int offset2, o
749826

750827
public void GetWriteSegment(out int offset, out int length)
751828
{
829+
EnsureNotDisposed();
752830
if (_count == _buffer.Length)
753831
{
754832
offset = 0;
@@ -763,6 +841,7 @@ public void GetWriteSegment(out int offset, out int length)
763841

764842
public void AdvanceWrite(int bytes)
765843
{
844+
EnsureNotDisposed();
766845
if (bytes <= 0)
767846
return;
768847

src/FirebirdSql.Data.FirebirdClient/Client/Managed/GdsConnection.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,19 +359,29 @@ await Xdr.ReadBooleanAsync(cancellationToken).ConfigureAwait(false),
359359

360360
public void Disconnect()
361361
{
362+
_firebirdNetworkHandlingWrapper?.Dispose();
363+
_firebirdNetworkHandlingWrapper = null;
364+
362365
if (_networkStream != null)
363366
{
364367
_networkStream.Dispose();
365368
_networkStream = null;
366369
}
370+
371+
Xdr = null;
367372
}
368373
public async ValueTask DisconnectAsync(CancellationToken cancellationToken = default)
369374
{
375+
_firebirdNetworkHandlingWrapper?.Dispose();
376+
_firebirdNetworkHandlingWrapper = null;
377+
370378
if (_networkStream != null)
371379
{
372380
await _networkStream.DisposeAsync().ConfigureAwait(false);
373381
_networkStream = null;
374382
}
383+
384+
Xdr = null;
375385
}
376386

377387
internal IResponse ProcessOperation(int operation)

0 commit comments

Comments
 (0)