Skip to content

Commit d843d6d

Browse files
authored
feat(tar): support for async streams (#746)
1 parent e589b5e commit d843d6d

File tree

15 files changed

+1239
-418
lines changed

15 files changed

+1239
-418
lines changed

benchmark/ICSharpCode.SharpZipLib.Benchmark/Program.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using System;
2-
using BenchmarkDotNet;
3-
using BenchmarkDotNet.Configs;
1+
using BenchmarkDotNet.Configs;
42
using BenchmarkDotNet.Jobs;
53
using BenchmarkDotNet.Running;
64
using BenchmarkDotNet.Toolchains.CsProj;
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using System;
2+
using System.IO;
3+
using System.Security.Cryptography;
4+
using System.Text;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
using BenchmarkDotNet.Attributes;
8+
using ICSharpCode.SharpZipLib.Tar;
9+
10+
namespace ICSharpCode.SharpZipLib.Benchmark.Tar
11+
{
12+
[MemoryDiagnoser]
13+
[Config(typeof(MultipleRuntimes))]
14+
public class TarInputStream
15+
{
16+
private readonly byte[] archivedData;
17+
private readonly byte[] readBuffer = new byte[1024];
18+
19+
public TarInputStream()
20+
{
21+
using (var outputMemoryStream = new MemoryStream())
22+
{
23+
using (var zipOutputStream =
24+
new ICSharpCode.SharpZipLib.Tar.TarOutputStream(outputMemoryStream, Encoding.UTF8))
25+
{
26+
var tarEntry = TarEntry.CreateTarEntry("some file");
27+
tarEntry.Size = 1024 * 1024;
28+
zipOutputStream.PutNextEntry(tarEntry);
29+
30+
var rng = RandomNumberGenerator.Create();
31+
var inputBuffer = new byte[1024];
32+
rng.GetBytes(inputBuffer);
33+
34+
for (int i = 0; i < 1024; i++)
35+
{
36+
zipOutputStream.Write(inputBuffer, 0, inputBuffer.Length);
37+
}
38+
}
39+
40+
archivedData = outputMemoryStream.ToArray();
41+
}
42+
}
43+
44+
[Benchmark]
45+
public long ReadTarInputStream()
46+
{
47+
using (var memoryStream = new MemoryStream(archivedData))
48+
using (var zipInputStream = new ICSharpCode.SharpZipLib.Tar.TarInputStream(memoryStream, Encoding.UTF8))
49+
{
50+
var entry = zipInputStream.GetNextEntry();
51+
52+
while (zipInputStream.Read(readBuffer, 0, readBuffer.Length) > 0)
53+
{
54+
}
55+
56+
return entry.Size;
57+
}
58+
}
59+
60+
[Benchmark]
61+
public async Task<long> ReadTarInputStreamAsync()
62+
{
63+
using (var memoryStream = new MemoryStream(archivedData))
64+
using (var zipInputStream = new ICSharpCode.SharpZipLib.Tar.TarInputStream(memoryStream, Encoding.UTF8))
65+
{
66+
var entry = await zipInputStream.GetNextEntryAsync(CancellationToken.None);
67+
68+
#if NETCOREAPP2_1_OR_GREATER
69+
while (await zipInputStream.ReadAsync(readBuffer.AsMemory()) > 0)
70+
{
71+
}
72+
#else
73+
while (await zipInputStream.ReadAsync(readBuffer, 0, readBuffer.Length) > 0)
74+
{
75+
}
76+
#endif
77+
78+
return entry.Size;
79+
}
80+
}
81+
}
82+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System.IO;
2+
using System.Security.Cryptography;
3+
using System.Text;
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
using BenchmarkDotNet.Attributes;
7+
using ICSharpCode.SharpZipLib.Tar;
8+
9+
namespace ICSharpCode.SharpZipLib.Benchmark.Tar
10+
{
11+
[MemoryDiagnoser]
12+
[Config(typeof(MultipleRuntimes))]
13+
public class TarOutputStream
14+
{
15+
private readonly byte[] backingArray = new byte[1024 * 1024 + (6 * 1024)];
16+
private readonly byte[] inputBuffer = new byte[1024];
17+
private static readonly RandomNumberGenerator _rng = RandomNumberGenerator.Create();
18+
19+
[Benchmark]
20+
public void WriteTarOutputStream()
21+
{
22+
using (var outputMemoryStream = new MemoryStream(backingArray))
23+
{
24+
using (var tarOutputStream =
25+
new ICSharpCode.SharpZipLib.Tar.TarOutputStream(outputMemoryStream, Encoding.UTF8))
26+
{
27+
var tarEntry = TarEntry.CreateTarEntry("some file");
28+
tarEntry.Size = 1024 * 1024;
29+
tarOutputStream.PutNextEntry(tarEntry);
30+
31+
_rng.GetBytes(inputBuffer);
32+
33+
for (int i = 0; i < 1024; i++)
34+
{
35+
tarOutputStream.Write(inputBuffer, 0, inputBuffer.Length);
36+
}
37+
}
38+
}
39+
}
40+
41+
[Benchmark]
42+
public async Task WriteTarOutputStreamAsync()
43+
{
44+
using (var outputMemoryStream = new MemoryStream(backingArray))
45+
{
46+
using (var tarOutputStream =
47+
new ICSharpCode.SharpZipLib.Tar.TarOutputStream(outputMemoryStream, Encoding.UTF8))
48+
{
49+
var tarEntry = TarEntry.CreateTarEntry("some file");
50+
tarEntry.Size = 1024 * 1024;
51+
52+
await tarOutputStream.PutNextEntryAsync(tarEntry, CancellationToken.None);
53+
54+
_rng.GetBytes(inputBuffer);
55+
56+
for (int i = 0; i < 1024; i++)
57+
{
58+
await tarOutputStream.WriteAsync(inputBuffer, 0, inputBuffer.Length);
59+
}
60+
}
61+
}
62+
}
63+
}
64+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System;
2+
using System.Buffers;
3+
4+
namespace ICSharpCode.SharpZipLib.Core
5+
{
6+
/// <summary>
7+
/// A MemoryPool that will return a Memory which is exactly the length asked for using the bufferSize parameter.
8+
/// This is in contrast to the default ArrayMemoryPool which will return a Memory of equal size to the underlying
9+
/// array which at least as long as the minBufferSize parameter.
10+
/// Note: The underlying array may be larger than the slice of Memory
11+
/// </summary>
12+
/// <typeparam name="T"></typeparam>
13+
internal sealed class ExactMemoryPool<T> : MemoryPool<T>
14+
{
15+
public new static readonly MemoryPool<T> Shared = new ExactMemoryPool<T>();
16+
17+
public override IMemoryOwner<T> Rent(int bufferSize = -1)
18+
{
19+
if ((uint)bufferSize > int.MaxValue || bufferSize < 0)
20+
{
21+
throw new ArgumentOutOfRangeException(nameof(bufferSize));
22+
}
23+
24+
return new ExactMemoryPoolBuffer(bufferSize);
25+
}
26+
27+
protected override void Dispose(bool disposing)
28+
{
29+
}
30+
31+
public override int MaxBufferSize => int.MaxValue;
32+
33+
private sealed class ExactMemoryPoolBuffer : IMemoryOwner<T>, IDisposable
34+
{
35+
private T[] array;
36+
private readonly int size;
37+
38+
public ExactMemoryPoolBuffer(int size)
39+
{
40+
this.size = size;
41+
this.array = ArrayPool<T>.Shared.Rent(size);
42+
}
43+
44+
public Memory<T> Memory
45+
{
46+
get
47+
{
48+
T[] array = this.array;
49+
if (array == null)
50+
{
51+
throw new ObjectDisposedException(nameof(ExactMemoryPoolBuffer));
52+
}
53+
54+
return new Memory<T>(array).Slice(0, size);
55+
}
56+
}
57+
58+
public void Dispose()
59+
{
60+
T[] array = this.array;
61+
if (array == null)
62+
{
63+
return;
64+
}
65+
66+
this.array = null;
67+
ArrayPool<T>.Shared.Return(array);
68+
}
69+
}
70+
}
71+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Collections.Concurrent;
2+
using System.Text;
3+
4+
namespace ICSharpCode.SharpZipLib.Core
5+
{
6+
internal class StringBuilderPool
7+
{
8+
public static StringBuilderPool Instance { get; } = new StringBuilderPool();
9+
private readonly ConcurrentQueue<StringBuilder> pool = new ConcurrentQueue<StringBuilder>();
10+
11+
public StringBuilder Rent()
12+
{
13+
return pool.TryDequeue(out var builder) ? builder : new StringBuilder();
14+
}
15+
16+
public void Return(StringBuilder builder)
17+
{
18+
builder.Clear();
19+
pool.Enqueue(builder);
20+
}
21+
}
22+
}

src/ICSharpCode.SharpZipLib/ICSharpCode.SharpZipLib.csproj

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,18 @@ Please see https://github.com/icsharpcode/SharpZipLib/wiki/Release-1.3.3 for mor
3333
<ItemGroup>
3434
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
3535
</ItemGroup>
36-
37-
<ItemGroup>
36+
37+
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
38+
<PackageReference Include="System.Memory" Version="4.5.4" />
39+
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.2" />
40+
</ItemGroup>
41+
42+
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
43+
<PackageReference Include="System.Memory" Version="4.5.4" />
44+
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.2" />
45+
</ItemGroup>
46+
47+
<ItemGroup>
3848
<None Include="../../assets/sharpziplib-nuget-256x256.png">
3949
<Pack>True</Pack>
4050
<PackagePath>images</PackagePath>

0 commit comments

Comments
 (0)