< 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: 2300_35243572715
Line coverage
98%
Covered lines: 66
Uncovered lines: 1
Coverable lines: 67
Total lines: 116
Line coverage: 98.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%22100%
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{
 174113    internal Task WriterTask { get; private init; }
 14
 15    private readonly IDuplexConnection _connection;
 79916    private readonly CancellationTokenSource _disposeCts = new();
 17    private Task? _disposeTask;
 18    private readonly Pipe _pipe;
 19
 8176920    public void Advance(int bytes) => _pipe.Writer.Advance(bytes);
 21
 22    /// <inheritdoc/>
 23    public ValueTask DisposeAsync()
 79824    {
 79825        _disposeTask ??= PerformDisposeAsync();
 79826        return new(_disposeTask);
 27
 28        async Task PerformDisposeAsync()
 79829        {
 79830            _disposeCts.Cancel();
 31
 79832            await WriterTask.ConfigureAwait(false);
 33
 79834            _pipe.Reader.Complete();
 79835            _pipe.Writer.Complete();
 36
 79837            _disposeCts.Dispose();
 79838        }
 79839    }
 40
 41    /// <inheritdoc/>
 042    public Memory<byte> GetMemory(int sizeHint = 0) => _pipe.Writer.GetMemory(sizeHint);
 43
 44    /// <inheritdoc/>
 8176945    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>
 79954    internal SlicDuplexConnectionWriter(
 79955        IDuplexConnection connection,
 79956        MemoryPool<byte> pool,
 79957        int minimumSegmentSize,
 79958        int pauseWriterThreshold)
 79959    {
 79960        _connection = connection;
 61
 79962        _pipe = new Pipe(new PipeOptions(
 79963            pool: pool,
 79964            minimumSegmentSize: minimumSegmentSize,
 79965            pauseWriterThreshold: pauseWriterThreshold,
 79966            // Match the algorithm PipeOptions uses for its defaults: resumeWriterThreshold = pauseWriterThreshold / 2.
 79967            // Without this override, the PipeOptions default of 32 KB would exceed pauseWriterThreshold for small
 79968            // thresholds and throw. When pauseWriterThreshold is 0, leave both at 0 to disable pausing.
 79969            resumeWriterThreshold: pauseWriterThreshold == 0 ? 0 : pauseWriterThreshold / 2,
 79970            useSynchronizationContext: false));
 71
 79972        WriterTask = Task.Run(
 79973            async () =>
 79974            {
 79975                try
 79976                {
 683677                    while (true)
 683678                    {
 683679                        ReadResult readResult = await _pipe.Reader.ReadAsync(_disposeCts.Token).ConfigureAwait(false);
 79980
 618881                        if (!readResult.Buffer.IsEmpty)
 608582                        {
 608583                            await _connection.WriteAsync(readResult.Buffer, _disposeCts.Token).ConfigureAwait(false);
 607884                            _pipe.Reader.AdvanceTo(readResult.Buffer.End);
 607885                        }
 79986
 618187                        if (readResult.IsCompleted)
 14488                        {
 14489                            await _connection.ShutdownWriteAsync(_disposeCts.Token).ConfigureAwait(false);
 14290                            break;
 79991                        }
 603792                    }
 14293                    _pipe.Reader.Complete();
 14294                }
 65395                catch (OperationCanceledException)
 65396                {
 79997                    // DisposeAsync was called.
 65398                }
 399                catch (Exception exception)
 3100                {
 3101                    _pipe.Reader.Complete(exception);
 3102                }
 1597103            });
 799104    }
 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) =>
 12356109        _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.
 144115        _pipe.Writer.Complete();
 116}