/// <inheritdoc/> public virtual void PartialFree(int newCount, ref ChannelWriterBufferSlice <T> writeSlice) { if (newCount != 1) { throw new ArgumentOutOfRangeException( "newCount should be less or equal than current and greater than zero.", nameof(newCount)); } // Do nothing. }
/// <inheritdoc/> public virtual void CompleteWrite(int processedCount, ref ChannelWriterBufferSlice <T> writeSlice) { if ((processedCount < 0) || (processedCount > 1)) { throw new ArgumentOutOfRangeException( "processedCount should be greater or equal to zero and less than slice length.", nameof(processedCount)); } if (processedCount == 1) { WriteAsync(writeSlice.Span[0]).GetAwaiter().GetResult(); } }
/// <inheritdoc/> public void CompleteWrite(int processedCount, ref ChannelWriterBufferSlice <T> writeSlice) { if ((processedCount < 0) || (processedCount > writeSlice.Length)) { throw new ArgumentOutOfRangeException( nameof(processedCount), "processedCount should be non-negative and less than allocated count"); } using (var guard = new StateWriteGuard <TSyncObject>(_syncObject, _owner)) { if (!_owner._idToSliceEntries.TryGetValue(writeSlice.Id, out var sliceEntryNode)) { throw new ArgumentException("Wrong slice variable."); } if (!_writeInProgress) { throw new InvalidOperationException("CompleteWrite operation has not been started."); } var sliceEntry = sliceEntryNode.Value; if (writeSlice.Length != sliceEntry.Length) { throw new ArgumentException("The provided slice have an invalid state", nameof(writeSlice)); } guard.NotifyWritten(processedCount, sliceEntry.Length); sliceEntry.Status = SliceEntryStatus.Data; if (processedCount == 0) { _owner.RemoveNode(sliceEntryNode); } else { sliceEntry.Length = processedCount; } _writeInProgress = false; } }
/// <inheritdoc/> public void PartialFree(int newCount, ref ChannelWriterBufferSlice <T> writeSlice) { if ((newCount < 1) || (newCount > writeSlice.Length)) { throw new ArgumentOutOfRangeException( nameof(newCount), "New count should be greater than zero and less or equal to already allocated length."); } using (var guard = new StateWriteGuard <TSyncObject>(_syncObject, _owner)) { if (!_owner._idToSliceEntries.TryGetValue(writeSlice.Id, out var sliceEntryNode)) { throw new ArgumentException("Wrong slice variable."); } if (!_writeInProgress) { throw new InvalidOperationException("PartialFree operation has not been started."); } if (writeSlice.Length != sliceEntryNode.Value.Length) { throw new ArgumentException("The provided slice have an invalid state", nameof(writeSlice)); } int decreaseSize = sliceEntryNode.Value.Length - newCount; if (decreaseSize == 0) { // shit in shit out return; } writeSlice.DecreaseLength(decreaseSize); sliceEntryNode.Value.Length = newCount; guard.NotifyWritten(0, decreaseSize); } }
void IChannelWriter <T> .PartialFree(int newCount, ref ChannelWriterBufferSlice <T> writeSlice) => throw new NotSupportedException();
void IChannelWriter <T> .CompleteWrite(int processedCount, ref ChannelWriterBufferSlice <T> writeSlice) => throw new NotSupportedException();
/// <inheritdoc/> public void PartialFree(int newCount, ref ChannelWriterBufferSlice <T> writeSlice) => throw new NotImplementedException();
/// <inheritdoc/> public void CompleteWrite(int processedCount, ref ChannelWriterBufferSlice <T> writeSlice) => throw new NotImplementedException();
/// <inheritdoc/> public async ValueTask <ChannelWriterBufferSlice <T> > StartWriteAsync( int count, CancellationToken cancellationToken) { if (count <= 0) { throw new ArgumentOutOfRangeException(nameof(count), "Count should be non-zero positive value."); } bool isWriteStarted = false; while (true) { cancellationToken.ThrowIfCancellationRequested(); Task <VoidResult> taskToAwait; using (var guard = new StateWriteGuard <TSyncObject>(_syncObject, _owner)) { if (!isWriteStarted) { EnsureSequentialUsage(); _writeInProgress = true; isWriteStarted = true; } if (_owner._isCompleted) { _writeInProgress = false; throw new ChannelClosedException(); } int freeSpace = guard.GetFreeSpaceForWrite(); if (freeSpace != 0) { int amountToAllocate = Math.Min(Math.Min(count, freeSpace), _owner._maxSliceLength); guard.NotifyAllocated(amountToAllocate); var sliceEntry = _owner.AllocateNewEntry(); sliceEntry.Status = SliceEntryStatus.AllocatedForWrite; sliceEntry.Length = amountToAllocate; var slice = new ChannelWriterBufferSlice <T>( sliceEntry.Buffer, 0, amountToAllocate, sliceEntry.Id); return(slice); } Debug.Assert(_owner._writeSpaceAvailableCs != null, "_owner._writeSpaceAvailableCs != null"); taskToAwait = _owner._writeSpaceAvailableCs.Task; } await taskToAwait.WithCancellation(cancellationToken); // TODO: put this to avoid possible recursion. // await Task.Yield(); } }