public async Task StreamFlushAsyncThrowingDoesReturnMemoryToPool() { using (var pool = new DisposeTrackingBufferPool()) { var stream = new CancelledWritesStream(); var options = new StreamPipeWriterOptions(pool); PipeWriter writer = PipeWriter.Create(stream, options); writer.WriteEmpty(10); Assert.Equal(1, pool.CurrentlyRentedBlocks); Assert.Equal(0, pool.DisposedBlocks); ValueTask <FlushResult> task = writer.FlushAsync(); stream.WaitForWriteTask.TrySetResult(null); stream.WaitForFlushTask.TrySetException(new Exception()); await Assert.ThrowsAsync <Exception>(async() => await task); Assert.Equal(0, pool.CurrentlyRentedBlocks); Assert.Equal(1, pool.DisposedBlocks); writer.Complete(); Assert.Equal(0, pool.CurrentlyRentedBlocks); Assert.Equal(1, pool.DisposedBlocks); } }
public async Task CompletingReturnsUnconsumedMemoryToPool() { using (var pool = new DisposeTrackingBufferPool()) { var options = new StreamPipeReaderOptions(pool: pool, bufferSize: 4096, minimumReadSize: 1024); // 2 full segments var stream = new MemoryStream(new byte[options.BufferSize * 3]); PipeReader reader = PipeReader.Create(stream, options); while (true) { ReadResult readResult = await reader.ReadAsync(); reader.AdvanceTo(readResult.Buffer.Start, readResult.Buffer.End); if (readResult.IsCompleted) { break; } } Assert.Equal(4, pool.CurrentlyRentedBlocks); reader.Complete(); Assert.Equal(0, pool.CurrentlyRentedBlocks); Assert.Equal(4, pool.DisposedBlocks); } }
public async Task CanWriteAfterReturningMultipleBlocks() { var pool = new DisposeTrackingBufferPool(); var writeSize = 512; var pipe = new Pipe(new PipeOptions(pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false)); // Write two blocks Memory <byte> buffer = pipe.Writer.GetMemory(writeSize); pipe.Writer.Advance(buffer.Length); pipe.Writer.GetMemory(buffer.Length); pipe.Writer.Advance(writeSize); await pipe.Writer.FlushAsync(); Assert.Equal(2, pool.CurrentlyRentedBlocks); // Read everything ReadResult readResult = await pipe.Reader.ReadAsync(); pipe.Reader.AdvanceTo(readResult.Buffer.End); // Try writing more await pipe.Writer.WriteAsync(new byte[writeSize]); Assert.Equal(1, pool.CurrentlyRentedBlocks); Assert.Equal(0, pool.DisposedBlocks); Assert.Equal(2, pool.ReturnedBlocks); }
public async Task WriteAsyncThrowsDuringMultiSegmentWriteCompleteReturnsAllMemory() { using (var pool = new DisposeTrackingBufferPool()) { var stream = new ThrowAfterNWritesStream(1); var options = new StreamPipeWriterOptions(pool); PipeWriter writer = PipeWriter.Create(stream, options); writer.WriteEmpty(pool.MaxBufferSize); writer.WriteEmpty(pool.MaxBufferSize); writer.WriteEmpty(pool.MaxBufferSize); Assert.Equal(3, pool.CurrentlyRentedBlocks); Assert.Equal(0, pool.DisposedBlocks); await Assert.ThrowsAsync <InvalidOperationException>(async() => await writer.FlushAsync()); Assert.Equal(2, pool.CurrentlyRentedBlocks); Assert.Equal(1, pool.DisposedBlocks); writer.Complete(); Assert.Equal(0, writer.UnflushedBytes); Assert.Equal(0, pool.CurrentlyRentedBlocks); Assert.Equal(3, pool.DisposedBlocks); } }
public async Task CanWriteAfterReturningMultipleBlocks() { var pool = new DisposeTrackingBufferPool(); var writeSize = 512; using (var factory = new PipeFactory(pool)) { var pipe = factory.Create(); // Write two blocks var buffer = pipe.Writer.Alloc(writeSize); buffer.Advance(buffer.Buffer.Length); buffer.Ensure(buffer.Buffer.Length); buffer.Advance(writeSize); await buffer.FlushAsync(); Assert.Equal(2, pool.CurrentlyRentedBlocks); // Read everything var readResult = await pipe.Reader.ReadAsync(); pipe.Reader.Advance(readResult.Buffer.End); // Try writing more await pipe.Writer.WriteAsync(new byte[writeSize]); } }
public async Task CanWriteAfterReturningMultipleBlocks() { var pool = new DisposeTrackingBufferPool(); var writeSize = 512; var pipe = new ResetablePipe(new PipeOptions(pool)); // Write two blocks var buffer = pipe.Writer.GetMemory(writeSize); pipe.Writer.Advance(buffer.Length); pipe.Writer.GetMemory(buffer.Length); pipe.Writer.Advance(writeSize); await pipe.Writer.FlushAsync(); Assert.Equal(2, pool.CurrentlyRentedBlocks); // Read everything var readResult = await pipe.Reader.ReadAsync(); pipe.Reader.Advance(readResult.Buffer.End); // Try writing more await pipe.Writer.WriteAsync(new byte[writeSize]); }
public void ReturnsWriteHeadOnComplete() { var pool = new DisposeTrackingBufferPool(); var pipe = new Pipe(new PipeOptions(pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false)); var memory = pipe.Writer.GetMemory(512); pipe.Reader.Complete(); pipe.Writer.Complete(); Assert.Equal(0, pool.CurrentlyRentedBlocks); }
public void ReturnsWriteHeadOnComplete() { var pool = new DisposeTrackingBufferPool(); var pipe = new Pipe(new PipeOptions(pool)); var memory = pipe.Writer.GetMemory(512); pipe.Reader.Complete(); pipe.Writer.Complete(); Assert.Equal(0, pool.CurrentlyRentedBlocks); }
public async Task GetMemoryFlushWithACompletedReaderNoops() { var pool = new DisposeTrackingBufferPool(); var pipe = new Pipe(new PipeOptions(pool)); pipe.Reader.Complete(); for (var i = 0; i < 10000; i++) { var mem = pipe.Writer.GetMemory(); pipe.Writer.Advance(mem.Length); await pipe.Writer.FlushAsync(default);
public void ReturnsWriteHeadOnComplete() { var pool = new DisposeTrackingBufferPool(); var pipe = new Pipe(CreatePipeWithInlineSchedulers(pool)); pipe.Writer.GetMemory(512); pipe.Reader.Complete(); pipe.Writer.Complete(); Assert.Equal(0, pool.CurrentlyRentedBlocks); Assert.Equal(1, pool.DisposedBlocks); }
public void ReturnsWriteHeadWhenRequestingLargerBlock() { var pool = new DisposeTrackingBufferPool(); var pipe = new Pipe(new PipeOptions(pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline)); var memory = pipe.Writer.GetMemory(512); pipe.Writer.GetMemory(4096); pipe.Reader.Complete(); pipe.Writer.Complete(); Assert.Equal(0, pool.CurrentlyRentedBlocks); }
public async Task OnReaderCompletedCalledAfterBlocksReturned() { var pool = new DisposeTrackingBufferPool(); var pipe = new Pipe(CreatePipeWithInlineSchedulers(pool)); await pipe.Writer.WriteAsync(new byte[1]); Assert.Equal(1, pool.CurrentlyRentedBlocks); pipe.Writer.OnReaderCompleted((exception, o) => Assert.Equal(0, pool.CurrentlyRentedBlocks), null); pipe.Writer.Complete(); pipe.Reader.Complete(); }
public async Task ConsumingSegmentsReturnsMemoryToPool() { using (var pool = new DisposeTrackingBufferPool()) { var options = new StreamPipeReaderOptions(pool: pool, bufferSize: 4096, minimumReadSize: 1024); // 2 full segments var stream = new MemoryStream(new byte[options.BufferSize * 2]); PipeReader reader = PipeReader.Create(stream, options); ReadResult readResult = await reader.ReadAsync(); ReadOnlySequence <byte> buffer = readResult.Buffer; Assert.Equal(1, pool.CurrentlyRentedBlocks); Assert.Equal(options.BufferSize, buffer.Length); reader.AdvanceTo(buffer.Start, buffer.End); readResult = await reader.ReadAsync(); buffer = readResult.Buffer; Assert.Equal(options.BufferSize * 2, buffer.Length); Assert.Equal(2, pool.CurrentlyRentedBlocks); reader.AdvanceTo(buffer.Start, buffer.End); readResult = await reader.ReadAsync(); buffer = readResult.Buffer; Assert.Equal(options.BufferSize * 2, buffer.Length); // We end up allocating a 3rd block here since we don't know ahead of time that // it's the last one Assert.Equal(3, pool.CurrentlyRentedBlocks); reader.AdvanceTo(buffer.Slice(buffer.Start, 4096).End, buffer.End); Assert.Equal(2, pool.CurrentlyRentedBlocks); Assert.Equal(1, pool.DisposedBlocks); readResult = await reader.ReadAsync(); buffer = readResult.Buffer; Assert.Equal(options.BufferSize, buffer.Length); reader.AdvanceTo(buffer.Slice(buffer.Start, 4096).End, buffer.End); // All of the blocks get returned here since we hit the first case of emptying the entire list Assert.Equal(0, pool.CurrentlyRentedBlocks); Assert.Equal(3, pool.DisposedBlocks); reader.Complete(); } }
public async Task WriteAsyncWithACompletedReaderNoops() { var pool = new DisposeTrackingBufferPool(); var pipe = new Pipe(new PipeOptions(pool)); pipe.Reader.Complete(); byte[] writeBuffer = new byte[100]; for (var i = 0; i < 10000; i++) { await pipe.Writer.WriteAsync(writeBuffer); } Assert.Equal(0, pool.CurrentlyRentedBlocks); }
public async Task MultipleCompleteReaderWriterCauseDisposeOnlyOnce() { var pool = new DisposeTrackingBufferPool(); var readerWriter = new Pipe(new PipeOptions(pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false)); await readerWriter.Writer.WriteAsync(new byte[] { 1 }); readerWriter.Writer.Complete(); readerWriter.Reader.Complete(); Assert.Equal(1, pool.ReturnedBlocks); readerWriter.Writer.Complete(); readerWriter.Reader.Complete(); Assert.Equal(1, pool.ReturnedBlocks); }
public async Task MultipleCompleteReaderWriterCauseDisposeOnlyOnce() { var pool = new DisposeTrackingBufferPool(); var readerWriter = new Pipe(CreatePipeWithInlineSchedulers(pool)); await readerWriter.Writer.WriteAsync(new byte[] { 1 }); readerWriter.Writer.Complete(); readerWriter.Reader.Complete(); Assert.Equal(1, pool.DisposedBlocks); readerWriter.Writer.Complete(); readerWriter.Reader.Complete(); Assert.Equal(1, pool.DisposedBlocks); }
public async Task MultipleCompleteReaderWriterCauseDisposeOnlyOnce() { var pool = new DisposeTrackingBufferPool(); var readerWriter = new ResetablePipe(new PipeOptions(pool)); await readerWriter.Writer.WriteAsync(new byte[] { 1 }); readerWriter.Writer.Complete(); readerWriter.Reader.Complete(); Assert.Equal(1, pool.ReturnedBlocks); readerWriter.Writer.Complete(); readerWriter.Reader.Complete(); Assert.Equal(1, pool.ReturnedBlocks); }
public async Task OnWriterCompletedCalledAfterBlocksReturned() { var pool = new DisposeTrackingBufferPool(); var pipe = new Pipe(CreatePipeWithInlineSchedulers(pool)); await pipe.Writer.WriteAsync(new byte[1]); Assert.Equal(1, pool.CurrentlyRentedBlocks); #pragma warning disable CS0618 // Type or member is obsolete pipe.Reader.OnWriterCompleted((exception, o) => Assert.Equal(0, pool.CurrentlyRentedBlocks), null); #pragma warning restore CS0618 // Type or member is obsolete pipe.Reader.Complete(); pipe.Writer.Complete(); }
public async Task WriteDuringReadIsNotReturned() { var pool = new DisposeTrackingBufferPool(); var writeSize = 512; var pipe = new Pipe(CreatePipeWithInlineSchedulers(pool)); await pipe.Writer.WriteAsync(new byte[writeSize]); pipe.Writer.GetMemory(writeSize); ReadResult readResult = await pipe.Reader.ReadAsync(); pipe.Reader.AdvanceTo(readResult.Buffer.End); pipe.Writer.Write(new byte[writeSize]); await pipe.Writer.FlushAsync(); Assert.Equal(1, pool.CurrentlyRentedBlocks); }
public async Task WriteDuringReadIsNotReturned() { var pool = new DisposeTrackingBufferPool(); var writeSize = 512; var pipe = new Pipe(new PipeOptions(pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false)); await pipe.Writer.WriteAsync(new byte[writeSize]); pipe.Writer.GetMemory(writeSize); ReadResult readResult = await pipe.Reader.ReadAsync(); pipe.Reader.AdvanceTo(readResult.Buffer.End); pipe.Writer.Write(new byte[writeSize]); await pipe.Writer.FlushAsync(); Assert.Equal(1, pool.CurrentlyRentedBlocks); }
public async Task MultipleCompleteReaderWriterCauseDisposeOnlyOnce() { var pool = new DisposeTrackingBufferPool(); using (var factory = new PipeFactory(pool)) { var readerWriter = factory.Create(); await readerWriter.Writer.WriteAsync(new byte[] { 1 }); readerWriter.Writer.Complete(); readerWriter.Reader.Complete(); Assert.Equal(1, pool.Disposed); readerWriter.Writer.Complete(); readerWriter.Reader.Complete(); Assert.Equal(1, pool.Disposed); } }
public void GetMemoryBiggerThanPoolSizeAllocatesArrayPoolArray() { using (var pool = new DisposeTrackingBufferPool()) { var stream = new MemoryStream(); var options = new StreamPipeWriterOptions(pool); PipeWriter writer = PipeWriter.Create(stream, options); Memory <byte> memory = writer.GetMemory(pool.MaxBufferSize + 1); Assert.True(memory.Length > pool.MaxBufferSize + 1); Assert.Equal(0, pool.CurrentlyRentedBlocks); Assert.Equal(0, pool.DisposedBlocks); writer.Complete(); Assert.Equal(0, pool.CurrentlyRentedBlocks); Assert.Equal(0, pool.DisposedBlocks); } }
public async Task WriteDuringReadIsNotReturned() { var pool = new DisposeTrackingBufferPool(); var writeSize = 512; var pipe = new ResetablePipe(new PipeOptions(pool)); await pipe.Writer.WriteAsync(new byte[writeSize]); pipe.Writer.GetMemory(writeSize); var readResult = await pipe.Reader.ReadAsync(); pipe.Reader.Advance(readResult.Buffer.End); pipe.Writer.Write(new byte[writeSize]); pipe.Writer.Commit(); Assert.Equal(1, pool.CurrentlyRentedBlocks); }
public void GetMemorySameAsTheMaxPoolSizeUsesThePool() { using (var pool = new DisposeTrackingBufferPool()) { byte[] bytes = Encoding.ASCII.GetBytes("Hello World"); var stream = new MemoryStream(); var options = new StreamPipeWriterOptions(pool); PipeWriter writer = PipeWriter.Create(stream, options); Memory <byte> memory = writer.GetMemory(pool.MaxBufferSize); Assert.Equal(pool.MaxBufferSize, memory.Length); Assert.Equal(1, pool.CurrentlyRentedBlocks); Assert.Equal(0, pool.DisposedBlocks); writer.Complete(); Assert.Equal(0, pool.CurrentlyRentedBlocks); Assert.Equal(1, pool.DisposedBlocks); } }
public async Task AdvanceToEndReturnsAllBlocks() { var pool = new DisposeTrackingBufferPool(); var writeSize = 512; var pipe = new Pipe(new PipeOptions(pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false)); while (pool.CurrentlyRentedBlocks != 3) { PipeWriter writableBuffer = pipe.Writer.WriteEmpty(writeSize); await writableBuffer.FlushAsync(); } ReadResult readResult = await pipe.Reader.ReadAsync(); pipe.Reader.AdvanceTo(readResult.Buffer.End); Assert.Equal(0, pool.CurrentlyRentedBlocks); }
public async Task AdvanceToEndReturnsAllBlocks() { var pool = new DisposeTrackingBufferPool(); var writeSize = 512; var pipe = new ResetablePipe(new PipeOptions(pool)); while (pool.CurrentlyRentedBlocks != 3) { var writableBuffer = pipe.Writer.WriteEmpty(writeSize); await writableBuffer.FlushAsync(); } var readResult = await pipe.Reader.ReadAsync(); pipe.Reader.Advance(readResult.Buffer.End); Assert.Equal(0, pool.CurrentlyRentedBlocks); }
public void CompletingWithBufferedBytesStillReturnsMemoryToPool() { using (var pool = new DisposeTrackingBufferPool()) { byte[] bytes = Encoding.ASCII.GetBytes("Hello World"); var stream = new MemoryStream(); var options = new StreamPipeWriterOptions(pool); PipeWriter writer = PipeWriter.Create(stream, options); bytes.AsSpan().CopyTo(writer.GetSpan(bytes.Length)); writer.Advance(bytes.Length); Assert.Equal(1, pool.CurrentlyRentedBlocks); Assert.Equal(0, pool.DisposedBlocks); Assert.Equal(0, stream.Length); writer.Complete(); Assert.Equal(0, pool.CurrentlyRentedBlocks); Assert.Equal(1, pool.DisposedBlocks); } }
public async Task AdvanceToEndReturnsAllBlocks() { var pool = new DisposeTrackingBufferPool(); var writeSize = 512; var pipe = new Pipe(CreatePipeWithInlineSchedulers(pool)); while (pool.CurrentlyRentedBlocks != 3) { PipeWriter writableBuffer = pipe.Writer.WriteEmpty(writeSize); await writableBuffer.FlushAsync(); } ReadResult readResult = await pipe.Reader.ReadAsync(); pipe.Reader.AdvanceTo(readResult.Buffer.End); Assert.Equal(0, pool.CurrentlyRentedBlocks); Assert.Equal(3, pool.DisposedBlocks); }
public async Task RentsMinimumSegmentSize() { var pool = new DisposeTrackingBufferPool(); var writeSize = 512; var pipe = new Pipe(new PipeOptions(pool, minimumSegmentSize: 2020, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false)); Memory <byte> buffer = pipe.Writer.GetMemory(writeSize); int allocatedSize = buffer.Length; pipe.Writer.Advance(buffer.Length); buffer = pipe.Writer.GetMemory(1); int ensuredSize = buffer.Length; await pipe.Writer.FlushAsync(); pipe.Reader.Complete(); pipe.Writer.Complete(); Assert.Equal(2020, ensuredSize); Assert.Equal(2020, allocatedSize); }
public async Task RentsMinimumSegmentSize() { var pool = new DisposeTrackingBufferPool(); var writeSize = 512; var pipe = new ResetablePipe(new PipeOptions(pool, minimumSegmentSize: 2020)); var buffer = pipe.Writer.GetMemory(writeSize); var allocatedSize = buffer.Length; pipe.Writer.Advance(buffer.Length); buffer = pipe.Writer.GetMemory(1); var ensuredSize = buffer.Length; await pipe.Writer.FlushAsync(); pipe.Reader.Complete(); pipe.Writer.Complete(); Assert.Equal(2020, ensuredSize); Assert.Equal(2020, allocatedSize); }