< Summary

Information
Class: IceRpc.Transports.Slic.Internal.SlicDuplexConnectionWriter
Assembly: IceRpc
File(s): /home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc/Transports/Slic/Internal/SlicDuplexConnectionWriter.cs
Tag: 1856_27024993493
Line coverage
92%
Covered lines: 62
Uncovered lines: 5
Coverable lines: 67
Total lines: 116
Line coverage: 92.5%
Branch coverage
75%
Covered branches: 3
Total branches: 4
Branch coverage: 75%
Method coverage
88%
Covered methods: 8
Fully covered methods: 7
Total methods: 9
Method coverage: 88.8%
Full method coverage: 77.7%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_WriterTask()100%11100%
.ctor(...)100%2292%
Advance(...)100%11100%
DisposeAsync()50%22100%
PerformDisposeAsync()100%11100%
GetMemory(...)100%210%
GetSpan(...)100%11100%
FlushAsync(...)100%11100%
Shutdown()100%11100%

File(s)

/home/runner/work/icerpc-csharp/icerpc-csharp/src/IceRpc/Transports/Slic/Internal/SlicDuplexConnectionWriter.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3using System.Buffers;
 4using System.IO.Pipelines;
 5
 6namespace IceRpc.Transports.Slic.Internal;
 7
 8/// <summary>A helper class to write data to a duplex connection. Its methods shouldn't be called concurrently. The data
 9/// written to this writer is copied and buffered with an internal pipe. The data from the pipe is written on the duplex
 10/// connection with a background task.</summary>
 11internal class SlicDuplexConnectionWriter : IBufferWriter<byte>, IAsyncDisposable
 12{
 164813    internal Task WriterTask { get; private init; }
 14
 15    private readonly IDuplexConnection _connection;
 75316    private readonly CancellationTokenSource _disposeCts = new();
 17    private Task? _disposeTask;
 18    private readonly Pipe _pipe;
 19
 8035620    public void Advance(int bytes) => _pipe.Writer.Advance(bytes);
 21
 22    /// <inheritdoc/>
 23    public ValueTask DisposeAsync()
 75224    {
 75225        _disposeTask ??= PerformDisposeAsync();
 75226        return new(_disposeTask);
 27
 28        async Task PerformDisposeAsync()
 75229        {
 75230            _disposeCts.Cancel();
 31
 75232            await WriterTask.ConfigureAwait(false);
 33
 75234            _pipe.Reader.Complete();
 75235            _pipe.Writer.Complete();
 36
 75237            _disposeCts.Dispose();
 75238        }
 75239    }
 40
 41    /// <inheritdoc/>
 042    public Memory<byte> GetMemory(int sizeHint = 0) => _pipe.Writer.GetMemory(sizeHint);
 43
 44    /// <inheritdoc/>
 8035645    public Span<byte> GetSpan(int sizeHint = 0) => _pipe.Writer.GetSpan(sizeHint);
 46
 47    /// <summary>Constructs a duplex connection writer.</summary>
 48    /// <param name="connection">The duplex connection to write to.</param>
 49    /// <param name="pool">The memory pool to use.</param>
 50    /// <param name="minimumSegmentSize">The minimum segment size for buffers allocated from <paramref
 51    /// name="pool"/>.</param>
 52    /// <param name="pauseWriterThreshold">The pipe pause writer threshold. When buffered data exceeds this value, <see
 53    /// cref="FlushAsync" /> blocks until the background writer task drains enough data from the pipe.</param>
 75354    internal SlicDuplexConnectionWriter(
 75355        IDuplexConnection connection,
 75356        MemoryPool<byte> pool,
 75357        int minimumSegmentSize,
 75358        int pauseWriterThreshold)
 75359    {
 75360        _connection = connection;
 61
 75362        _pipe = new Pipe(new PipeOptions(
 75363            pool: pool,
 75364            minimumSegmentSize: minimumSegmentSize,
 75365            pauseWriterThreshold: pauseWriterThreshold,
 75366            // Match the algorithm PipeOptions uses for its defaults: resumeWriterThreshold = pauseWriterThreshold / 2.
 75367            // Without this override, the PipeOptions default of 32 KB would exceed pauseWriterThreshold for small
 75368            // thresholds and throw. When pauseWriterThreshold is 0, leave both at 0 to disable pausing.
 75369            resumeWriterThreshold: pauseWriterThreshold == 0 ? 0 : pauseWriterThreshold / 2,
 75370            useSynchronizationContext: false));
 71
 75372        WriterTask = Task.Run(
 75373            async () =>
 75374            {
 75375                try
 75376                {
 718477                    while (true)
 718478                    {
 718479                        ReadResult readResult = await _pipe.Reader.ReadAsync(_disposeCts.Token).ConfigureAwait(false);
 75380
 657781                        if (!readResult.Buffer.IsEmpty)
 648282                        {
 648283                            await _connection.WriteAsync(readResult.Buffer, _disposeCts.Token).ConfigureAwait(false);
 647984                            _pipe.Reader.AdvanceTo(readResult.Buffer.End);
 647985                        }
 75386
 657487                        if (readResult.IsCompleted)
 14388                        {
 14389                            await _connection.ShutdownWriteAsync(_disposeCts.Token).ConfigureAwait(false);
 14190                            break;
 75391                        }
 643192                    }
 14193                    _pipe.Reader.Complete();
 14194                }
 61195                catch (OperationCanceledException)
 61196                {
 75397                    // DisposeAsync was called.
 61198                }
 099                catch (Exception exception)
 0100                {
 0101                    _pipe.Reader.Complete(exception);
 0102                }
 1505103            });
 753104    }
 105
 106    /// <summary>Flushes the underlying pipe. May block when the buffered data exceeds the configured pause writer
 107    /// threshold.</summary>
 108    internal ValueTask<FlushResult> FlushAsync(CancellationToken cancellationToken) =>
 12239109        _pipe.Writer.FlushAsync(cancellationToken);
 110
 111    /// <summary>Requests the shut down of the duplex connection writes after the buffered data is written on the
 112    /// duplex connection.</summary>
 113    internal void Shutdown() =>
 114        // Completing the pipe writer makes the background write task complete successfully.
 143115        _pipe.Writer.Complete();
 116}