Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit dbdba94

Browse files
[Backport][Pipelines] Noop Writes when Reader completed (#42982)
* [Backport][Pipelines] Noop Writes when Reader completed * move DisposeTrackingBufferPool to its own file * assembly version * fb * Fb * packageIndex
1 parent 2b5ec6d commit dbdba94

File tree

8 files changed

+125
-69
lines changed

8 files changed

+125
-69
lines changed

pkg/Microsoft.Private.PackageBaseline/packageIndex.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -2232,7 +2232,8 @@
22322232
"InboxOn": {},
22332233
"AssemblyVersionInPackageVersion": {
22342234
"4.0.0.0": "4.5.1",
2235-
"4.0.0.1": "4.5.2"
2235+
"4.0.0.1": "4.5.2",
2236+
"4.0.0.2": "4.5.3"
22362237
}
22372238
},
22382239
"System.IO.Pipes": {

src/System.IO.Pipelines/dir.props

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<Import Project="..\dir.props" />
44
<PropertyGroup>
5-
<AssemblyVersion>4.0.0.1</AssemblyVersion>
6-
<PackageVersion>4.5.3</PackageVersion>
5+
<AssemblyVersion>4.0.0.2</AssemblyVersion>
6+
<PackageVersion>4.5.4</PackageVersion>
77
<AssemblyKey>Open</AssemblyKey>
88
</PropertyGroup>
99
</Project>

src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs

+6
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,12 @@ internal void Advance(int bytesWritten)
269269
ThrowHelper.ThrowInvalidOperationException_NotWritingNoAlloc();
270270
}
271271

272+
// If the reader is completed we no-op Advance but leave GetMemory and FlushAsync alone
273+
if (_readerCompletion.IsCompleted)
274+
{
275+
return;
276+
}
277+
272278
if (bytesWritten > 0)
273279
{
274280
Debug.Assert(!_writingHead.ReadOnly);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Buffers;
6+
using System.Threading.Tasks;
7+
using Xunit;
8+
9+
namespace System.IO.Pipelines.Tests
10+
{
11+
public class DisposeTrackingBufferPool : TestMemoryPool
12+
{
13+
public int DisposedBlocks { get; set; }
14+
public int CurrentlyRentedBlocks { get; set; }
15+
16+
public override IMemoryOwner<byte> Rent(int size)
17+
{
18+
return new DisposeTrackingMemoryManager(new byte[size], this);
19+
}
20+
21+
protected override void Dispose(bool disposing)
22+
{
23+
}
24+
25+
private class DisposeTrackingMemoryManager : MemoryManager<byte>
26+
{
27+
private byte[] _array;
28+
29+
private readonly DisposeTrackingBufferPool _bufferPool;
30+
31+
public DisposeTrackingMemoryManager(byte[] array, DisposeTrackingBufferPool bufferPool)
32+
{
33+
_array = array;
34+
_bufferPool = bufferPool;
35+
_bufferPool.CurrentlyRentedBlocks++;
36+
}
37+
38+
public override Memory<byte> Memory => CreateMemory(_array.Length);
39+
40+
public bool IsDisposed => _array == null;
41+
42+
public override MemoryHandle Pin(int elementIndex = 0)
43+
{
44+
throw new NotImplementedException();
45+
}
46+
47+
public override void Unpin()
48+
{
49+
throw new NotImplementedException();
50+
}
51+
52+
protected override bool TryGetArray(out ArraySegment<byte> segment)
53+
{
54+
if (IsDisposed)
55+
throw new ObjectDisposedException(nameof(DisposeTrackingBufferPool));
56+
segment = new ArraySegment<byte>(_array);
57+
return true;
58+
}
59+
60+
protected override void Dispose(bool disposing)
61+
{
62+
_bufferPool.DisposedBlocks++;
63+
_bufferPool.CurrentlyRentedBlocks--;
64+
65+
_array = null;
66+
}
67+
68+
public override Span<byte> GetSpan()
69+
{
70+
if (IsDisposed)
71+
throw new ObjectDisposedException(nameof(DisposeTrackingBufferPool));
72+
return _array;
73+
}
74+
}
75+
}
76+
}

src/System.IO.Pipelines/tests/PipePoolTests.cs

-66
Original file line numberDiff line numberDiff line change
@@ -10,72 +10,6 @@ namespace System.IO.Pipelines.Tests
1010
{
1111
public class PipePoolTests
1212
{
13-
private class DisposeTrackingBufferPool : TestMemoryPool
14-
{
15-
public int DisposedBlocks { get; set; }
16-
public int CurrentlyRentedBlocks { get; set; }
17-
18-
public override IMemoryOwner<byte> Rent(int size)
19-
{
20-
return new DisposeTrackingMemoryManager(new byte[size], this);
21-
}
22-
23-
protected override void Dispose(bool disposing)
24-
{
25-
}
26-
27-
private class DisposeTrackingMemoryManager : MemoryManager<byte>
28-
{
29-
private byte[] _array;
30-
31-
private readonly DisposeTrackingBufferPool _bufferPool;
32-
33-
public DisposeTrackingMemoryManager(byte[] array, DisposeTrackingBufferPool bufferPool)
34-
{
35-
_array = array;
36-
_bufferPool = bufferPool;
37-
_bufferPool.CurrentlyRentedBlocks++;
38-
}
39-
40-
public override Memory<byte> Memory => CreateMemory(_array.Length);
41-
42-
public bool IsDisposed => _array == null;
43-
44-
public override MemoryHandle Pin(int elementIndex = 0)
45-
{
46-
throw new NotImplementedException();
47-
}
48-
49-
public override void Unpin()
50-
{
51-
throw new NotImplementedException();
52-
}
53-
54-
protected override bool TryGetArray(out ArraySegment<byte> segment)
55-
{
56-
if (IsDisposed)
57-
throw new ObjectDisposedException(nameof(DisposeTrackingBufferPool));
58-
segment = new ArraySegment<byte>(_array);
59-
return true;
60-
}
61-
62-
protected override void Dispose(bool disposing)
63-
{
64-
_bufferPool.DisposedBlocks++;
65-
_bufferPool.CurrentlyRentedBlocks--;
66-
67-
_array = null;
68-
}
69-
70-
public override Span<byte> GetSpan()
71-
{
72-
if (IsDisposed)
73-
throw new ObjectDisposedException(nameof(DisposeTrackingBufferPool));
74-
return _array;
75-
}
76-
}
77-
}
78-
7913
[Fact]
8014
public async Task AdvanceToEndReturnsAllBlocks()
8115
{

src/System.IO.Pipelines/tests/PipeWriterTests.cs

+35
Original file line numberDiff line numberDiff line change
@@ -195,5 +195,40 @@ public void GetMemory_AdjustsToPoolMaxBufferSize()
195195
var memory = buffer.GetMemory(int.MaxValue);
196196
Assert.True(memory.Length >= 4096);
197197
}
198+
199+
[Fact]
200+
public async Task WriteAsyncWithACompletedReaderNoops()
201+
{
202+
var pool = new DisposeTrackingBufferPool();
203+
var pipe = new Pipe(new PipeOptions(pool));
204+
pipe.Reader.Complete();
205+
206+
byte[] writeBuffer = new byte[100];
207+
for (var i = 0; i < 10000; i++)
208+
{
209+
await pipe.Writer.WriteAsync(writeBuffer);
210+
}
211+
212+
Assert.Equal(0, pool.CurrentlyRentedBlocks);
213+
}
214+
215+
[Fact]
216+
public async Task GetMemoryFlushWithACompletedReaderNoops()
217+
{
218+
var pool = new DisposeTrackingBufferPool();
219+
var pipe = new Pipe(new PipeOptions(pool));
220+
pipe.Reader.Complete();
221+
222+
for (var i = 0; i < 10000; i++)
223+
{
224+
var mem = pipe.Writer.GetMemory();
225+
pipe.Writer.Advance(mem.Length);
226+
await pipe.Writer.FlushAsync(default);
227+
}
228+
229+
Assert.Equal(1, pool.CurrentlyRentedBlocks);
230+
pipe.Writer.Complete();
231+
Assert.Equal(0, pool.CurrentlyRentedBlocks);
232+
}
198233
}
199234
}

src/System.IO.Pipelines/tests/System.IO.Pipelines.Tests.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
1313
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
1414
<ItemGroup>
15+
<Compile Include="Infrastructure\DisposeTrackingBufferPool.cs" />
1516
<Compile Include="BackpressureTests.cs" />
1617
<Compile Include="FlushAsyncCancellationTests.cs" />
1718
<Compile Include="FlushAsyncCompletionTests.cs" />

src/packages.builds

+3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
<AdditionalProperties>$(AdditionalProperties)</AdditionalProperties>
2525
</Project>
2626
<!-- add specific builds / pkgproj's here to include in servicing builds -->
27+
<Project Include="$(MSBuildThisFileDirectory)System.IO.Pipelines\pkg\System.IO.Pipelines.pkgproj">
28+
<AdditionalProperties>$(AdditionalProperties)</AdditionalProperties>
29+
</Project>
2730
</ItemGroup>
2831

2932
<!-- Need the PackageIndexFile file property from baseline.props -->

0 commit comments

Comments
 (0)