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);
            }
        }
Beispiel #3
0
        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]);
            }
        }
Beispiel #6
0
        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]);
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        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);
        }
Beispiel #9
0
        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);
Beispiel #10
0
        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);
        }
Beispiel #11
0
        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);
        }
Beispiel #12
0
        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();
            }
        }
Beispiel #14
0
        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);
        }
Beispiel #15
0
        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);
        }
Beispiel #16
0
        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);
        }
Beispiel #17
0
        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);
        }
Beispiel #18
0
        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();
        }
Beispiel #19
0
        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);
        }
Beispiel #20
0
        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);
        }
Beispiel #21
0
        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);
            }
        }
Beispiel #22
0
        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);
            }
        }
Beispiel #23
0
        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);
            }
        }
Beispiel #25
0
        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);
        }
Beispiel #26
0
        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);
            }
        }
Beispiel #28
0
        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);
        }
Beispiel #29
0
        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);
        }
Beispiel #30
0
        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);
        }