예제 #1
0
        /// <summary>
        /// Forms a slice out of the given <see cref="ReadableBuffer"/>, beginning at 'start', and is at most length bytes
        /// </summary>
        /// <param name="start">The index at which to begin this slice.</param>
        /// <param name="length">The length of the slice</param>
        public ReadableBuffer Slice(long start, long length)
        {
            var begin = ReadCursorOperations.Seek(BufferStart, BufferEnd, start, false);
            var end   = ReadCursorOperations.Seek(begin, BufferEnd, length, false);

            return(new ReadableBuffer(begin, end));
        }
예제 #2
0
        /// <summary>
        /// Forms a slice out of the given <see cref="ReadableBuffer"/>, beginning at 'start', ending at 'end' (inclusive).
        /// </summary>
        /// <param name="start">The starting (inclusive) <see cref="ReadCursor"/> at which to begin this slice.</param>
        /// <param name="end">The ending (inclusive) <see cref="ReadCursor"/> of the slice</param>
        public ReadableBuffer Slice(ReadCursor start, ReadCursor end)
        {
            ReadCursorOperations.BoundsCheck(BufferEnd, end);
            ReadCursorOperations.BoundsCheck(end, start);

            return(new ReadableBuffer(start, end));
        }
예제 #3
0
        /// <summary>
        /// Forms a slice out of the given <see cref="ReadableBuffer"/>, beginning at 'start', ending at 'end' (inclusive).
        /// </summary>
        /// <param name="start">The index at which to begin this slice.</param>
        /// <param name="end">The end (inclusive) of the slice</param>
        public ReadableBuffer Slice(long start, ReadCursor end)
        {
            ReadCursorOperations.BoundsCheck(BufferEnd, end);
            var begin = ReadCursorOperations.Seek(BufferStart, end, start);

            return(new ReadableBuffer(begin, end));
        }
예제 #4
0
 public ReadCursor Move(ReadCursor cursor, long count)
 {
     if (count < 0)
     {
         throw new ArgumentOutOfRangeException(nameof(count));
     }
     return(ReadCursorOperations.Seek(cursor, BufferEnd, count, false));
 }
예제 #5
0
        /// <summary>
        /// Forms a slice out of the given <see cref="ReadableBuffer"/>, beginning at 'start', and is at most length bytes
        /// </summary>
        /// <param name="start">The starting (inclusive) <see cref="ReadCursor"/> at which to begin this slice.</param>
        /// <param name="length">The length of the slice</param>
        public ReadableBuffer Slice(ReadCursor start, long length)
        {
            ReadCursorOperations.BoundsCheck(BufferEnd, start);

            var end = ReadCursorOperations.Seek(start, BufferEnd, length, false);

            return(new ReadableBuffer(start, end));
        }
예제 #6
0
        /// <summary>
        /// Forms a slice out of the given <see cref="ReadableBuffer"/>, beginning at 'start', ending at the existing <see cref="ReadableBuffer"/>'s end.
        /// </summary>
        /// <param name="start">The start index at which to begin this slice.</param>
        public ReadableBuffer Slice(long start)
        {
            if (start == 0)
            {
                return(this);
            }

            var begin = ReadCursorOperations.Seek(BufferStart, BufferEnd, start, false);

            return(new ReadableBuffer(begin, BufferEnd));
        }
예제 #7
0
        public bool TryGet(ref Position position, out ReadOnlyMemory <byte> item, bool advance = true)
        {
            if (position == default)
            {
                item = default;
                return(false);
            }

            var(segment, index) = position.Get <object>();
            var result = ReadCursorOperations.TryGetBuffer(new ReadCursor(segment, index), _buffer.End, out item, out var next);

            if (advance)
            {
                position = Position.Create(next.Segment, next.Index);
            }
            return(result);
        }
예제 #8
0
        // Reading

        void IPipeReader.Advance(ReadCursor consumed, ReadCursor examined)
        {
            BufferSegment returnStart = null;
            BufferSegment returnEnd   = null;

            // Reading commit head shared with writer
            Action continuation = null;

            lock (_sync)
            {
                bool examinedEverything = false;
                if (examined.Segment == _commitHead)
                {
                    examinedEverything = _commitHead != null ? examined.Index == _commitHeadIndex - _commitHead.Start : examined.Index == 0;
                }

                if (!consumed.IsDefault)
                {
                    if (_readHead == null)
                    {
                        PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.AdvanceToInvalidCursor);
                        return;
                    }

                    var consumedSegment = consumed.Get <BufferSegment>();

                    returnStart = _readHead;
                    returnEnd   = consumedSegment;

                    // Check if we crossed _maximumSizeLow and complete backpressure
                    var consumedBytes = ReadCursorOperations.GetLength(returnStart, _readHeadIndex, consumedSegment, consumed.Index);
                    var oldLength     = _length;
                    _length -= consumedBytes;

                    if (oldLength >= _maximumSizeLow &&
                        _length < _maximumSizeLow)
                    {
                        continuation = _writerAwaitable.Complete();
                    }

                    // Check if we consumed entire last segment
                    // if we are going to return commit head
                    // we need to check that there is no writing operation that
                    // might be using tailspace
                    if (consumed.Index == returnEnd.Length &&
                        !(_commitHead == returnEnd && _writingState.IsActive))
                    {
                        var nextBlock = returnEnd.NextSegment;
                        if (_commitHead == returnEnd)
                        {
                            _commitHead      = nextBlock;
                            _commitHeadIndex = 0;
                        }

                        _readHead      = nextBlock;
                        _readHeadIndex = 0;
                        returnEnd      = nextBlock;
                    }
                    else
                    {
                        _readHead      = consumedSegment;
                        _readHeadIndex = consumed.Index;
                    }
                }

                // We reset the awaitable to not completed if we've examined everything the producer produced so far
                // but only if writer is not completed yet
                if (examinedEverything && !_writerCompletion.IsCompleted)
                {
                    // Prevent deadlock where reader awaits new data and writer await backpressure
                    if (!_writerAwaitable.IsCompleted)
                    {
                        PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.BackpressureDeadlock);
                    }
                    _readerAwaitable.Reset();
                }

                _readingState.End(ExceptionResource.NoReadToComplete);

                while (returnStart != null && returnStart != returnEnd)
                {
                    returnStart.ResetMemory();
                    ReturnSegmentUnsynchronized(returnStart);
                    returnStart = returnStart.NextSegment;
                }
            }

            TrySchedule(_writerScheduler, continuation);
        }