Ejemplo n.º 1
0
        private void AllocateWriteHeadUnsynchronized(int sizeHint)
        {
            _operationState.BeginWrite();
            if (_writingHead == null)
            {
                // We need to allocate memory to write since nobody has written before
                BufferSegment newSegment = CreateSegmentUnsynchronized();
                newSegment.SetMemory(_pool.Rent(GetSegmentSize(sizeHint)));

                // Set all the pointers
                _writingHead = _readHead = _readTail = newSegment;
            }
            else
            {
                int bytesLeftInBuffer = _writingHead.WritableBytes;

                if (bytesLeftInBuffer == 0 || bytesLeftInBuffer < sizeHint)
                {
                    BufferSegment newSegment = CreateSegmentUnsynchronized();
                    newSegment.SetMemory(_pool.Rent(GetSegmentSize(sizeHint)));

                    _writingHead.SetNext(newSegment);
                    _writingHead = newSegment;
                }
            }
        }
Ejemplo n.º 2
0
        internal Memory <byte> GetMemory(int minimumSize)
        {
            if (_writerCompletion.IsCompleted)
            {
                ThrowHelper.ThrowInvalidOperationException_NoWritingAllowed();
            }

            if (minimumSize < 0)
            {
                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.minimumSize);
            }

            lock (_sync)
            {
                BufferSegment segment = _writingHead ?? AllocateWriteHeadUnsynchronized(minimumSize);

                int bytesLeftInBuffer = segment.WritableBytes;

                // If inadequate bytes left or if the segment is readonly
                if (bytesLeftInBuffer == 0 || bytesLeftInBuffer < minimumSize || segment.ReadOnly)
                {
                    BufferSegment nextSegment = CreateSegmentUnsynchronized();

                    nextSegment.SetMemory(_pool.Rent(Math.Max(_minimumSegmentSize, minimumSize)));

                    segment.SetNext(nextSegment);

                    _writingHead = nextSegment;
                }
            }

            return(_writingHead.AvailableMemory.Slice(_writingHead.End, _writingHead.WritableBytes));
        }
Ejemplo n.º 3
0
        public static BufferSegment Clone(ReadCursor beginBuffer, ReadCursor endBuffer, out BufferSegment lastSegment)
        {
            var beginOrig = beginBuffer.Segment;
            var endOrig   = endBuffer.Segment;

            if (beginOrig == endOrig)
            {
                lastSegment = new BufferSegment();
                lastSegment.SetMemory(beginOrig._owned, beginBuffer.Index, endBuffer.Index);
                return(lastSegment);
            }

            var beginClone = new BufferSegment();

            beginClone.SetMemory(beginOrig._owned, beginBuffer.Index, beginOrig.End);
            var endClone = beginClone;

            beginOrig = beginOrig.Next;

            while (beginOrig != endOrig)
            {
                var next = new BufferSegment();
                next.SetMemory(beginOrig._owned, beginOrig.Start, beginOrig.End);
                endClone.SetNext(next);

                endClone  = endClone.Next;
                beginOrig = beginOrig.Next;
            }

            lastSegment = new BufferSegment();
            lastSegment.SetMemory(endOrig._owned, endOrig.Start, endBuffer.Index);
            endClone.SetNext(lastSegment);

            return(beginClone);
        }
Ejemplo n.º 4
0
        public static BufferSegment Clone(BufferSegment start, int startIndex, BufferSegment end, int endIndex, out BufferSegment lastSegment)
        {
            var beginOrig = start;
            var endOrig   = end;

            if (beginOrig == endOrig)
            {
                lastSegment = new BufferSegment();
                lastSegment.SetMemory(beginOrig._ownedMemory, startIndex, endIndex);
                return(lastSegment);
            }

            var beginClone = new BufferSegment();

            beginClone.SetMemory(beginOrig._ownedMemory, startIndex, beginOrig.End);
            var endClone = beginClone;

            beginOrig = beginOrig.Next;

            while (beginOrig != endOrig)
            {
                var next = new BufferSegment();
                next.SetMemory(beginOrig._ownedMemory, beginOrig.Start, beginOrig.End);
                endClone.SetNext(next);

                endClone  = endClone.Next;
                beginOrig = beginOrig.Next;
            }

            lastSegment = new BufferSegment();
            lastSegment.SetMemory(endOrig._ownedMemory, endOrig.Start, endIndex);
            endClone.SetNext(lastSegment);

            return(beginClone);
        }
Ejemplo n.º 5
0
        private void AllocateWriteHeadUnsynchronized(int sizeHint)
        {
            BufferSegment segment = null;

            if (_writingHead != null)
            {
                segment = _writingHead;

                int bytesLeftInBuffer = segment.WritableBytes;

                // If inadequate bytes left or if the segment is readonly
                if (bytesLeftInBuffer == 0 || bytesLeftInBuffer < sizeHint || segment.ReadOnly)
                {
                    BufferSegment nextSegment = CreateSegmentUnsynchronized();
                    nextSegment.SetMemory(_pool.Rent(GetSegmentSize(sizeHint)));

                    segment.SetNext(nextSegment);

                    _writingHead = nextSegment;
                }
            }
            else
            {
                if (_commitHead != null && !_commitHead.ReadOnly)
                {
                    // Try to return the tail so the calling code can append to it
                    int remaining = _commitHead.WritableBytes;

                    if (sizeHint <= remaining && remaining > 0)
                    {
                        // Free tail space of the right amount, use that
                        segment = _commitHead;

                        // Set write head to assigned segment
                        _writingHead = segment;
                        return;
                    }
                }

                // No free tail space, allocate a new segment
                segment = CreateSegmentUnsynchronized();
                segment.SetMemory(_pool.Rent(GetSegmentSize(sizeHint)));

                if (_commitHead == null)
                {
                    // No previous writes have occurred
                    _commitHead = segment;
                }
                else if (segment != _commitHead && _commitHead.Next == null)
                {
                    // Append the segment to the commit head if writes have been committed
                    // and it isn't the same segment (unused tail space)
                    _commitHead.SetNext(segment);
                }

                // Set write head to assigned segment
                _writingHead = segment;
            }
        }
Ejemplo n.º 6
0
        private void AdvanceTo(BufferSegment consumedSegment, int consumedIndex, BufferSegment examinedSegment, int examinedIndex)
        {
            if (consumedSegment == null)
            {
                return;
            }

            var returnStart = _readHead;
            var returnEnd   = consumedSegment;

            var consumedBytes = new ReadOnlySequence <byte>(returnStart, _readIndex, consumedSegment, consumedIndex).Length;

            _bufferedBytes -= consumedBytes;

            Debug.Assert(_bufferedBytes >= 0);

            _examinedEverything = false;

            if (examinedSegment == _readTail)
            {
                // If we examined everything, we force ReadAsync to actually read from the underlying stream
                // instead of returning a ReadResult from TryRead.
                _examinedEverything = examinedIndex == _readTail.End;
            }

            // Three cases here:
            // 1. All data is consumed. If so, we reset _readHead and _readTail to _readTail's original memory owner
            //  SetMemory on a IMemoryOwner will reset the internal Memory<byte> to be an empty segment
            // 2. A segment is entirely consumed but there is still more data in nextSegments
            //  We are allowed to remove an extra segment. by setting returnEnd to be the next block.
            // 3. We are in the middle of a segment.
            //  Move _readHead and _readIndex to consumedSegment and index
            if (_bufferedBytes == 0)
            {
                _readTail.SetMemory(_readTail.MemoryOwner);
                _readHead  = _readTail;
                returnEnd  = _readTail;
                _readIndex = 0;
            }
            else if (consumedIndex == returnEnd.Length)
            {
                var nextBlock = returnEnd.NextSegment;
                _readHead  = nextBlock;
                _readIndex = 0;
                returnEnd  = nextBlock;
            }
            else
            {
                _readHead  = consumedSegment;
                _readIndex = consumedIndex;
            }

            // Remove all blocks that are freed (except the last one)
            while (returnStart != returnEnd)
            {
                returnStart.ResetMemory();
                returnStart = returnStart.NextSegment;
            }
        }
Ejemplo n.º 7
0
        private static ReadableBuffer CreateInternal(OwnedMemory <byte> data, int offset, int length)
        {
            var segment = new BufferSegment();

            segment.SetMemory(data, offset, offset + length);

            return(new ReadableBuffer(new ReadCursor(segment, offset), new ReadCursor(segment, offset + length)));
        }
Ejemplo n.º 8
0
        private BufferSegment AllocateSegment(int sizeHint)
        {
            BufferSegment newSegment = CreateSegmentUnsynchronized();

            if (_pool is null)
            {
                // Use the array pool
                newSegment.SetMemory(ArrayPool <byte> .Shared.Rent(GetSegmentSize(sizeHint)));
            }
            else if (sizeHint <= _pool.MaxBufferSize)
            {
                // Use the specified pool if it fits
                newSegment.SetMemory(_pool.Rent(GetSegmentSize(sizeHint, _pool.MaxBufferSize)));
            }
            else
            {
                // We can't use the pool so allocate an array
                newSegment.SetUnownedMemory(new byte[sizeHint]);
            }

            return(newSegment);
        }
Ejemplo n.º 9
0
 private void AllocateReadTail()
 {
     if (_readHead == null)
     {
         Debug.Assert(_readTail == null);
         _readHead = CreateBufferSegment();
         _readHead.SetMemory(_pool.Rent(GetSegmentSize()));
         _readTail = _readHead;
     }
     else if (_readTail.WritableBytes < _minimumReadThreshold)
     {
         CreateNewTailSegment();
     }
 }
Ejemplo n.º 10
0
        private BufferSegment AllocateWriteHeadUnsynchronized(int count)
        {
            BufferSegment segment = null;

            if (_commitHead != null && !_commitHead.ReadOnly)
            {
                // Try to return the tail so the calling code can append to it
                int remaining = _commitHead.WritableBytes;

                if (count <= remaining && remaining > 0)
                {
                    // Free tail space of the right amount, use that
                    segment = _commitHead;
                }
            }

            if (segment == null)
            {
                // No free tail space, allocate a new segment
                segment = CreateSegmentUnsynchronized();
                segment.SetMemory(_pool.Rent(Math.Max(_minimumSegmentSize, count)));
            }

            if (_commitHead == null)
            {
                // No previous writes have occurred
                _commitHead = segment;
            }
            else if (segment != _commitHead && _commitHead.Next == null)
            {
                // Append the segment to the commit head if writes have been committed
                // and it isn't the same segment (unused tail space)
                _commitHead.SetNext(segment);
            }

            // Set write head to assigned segment
            _writingHead = segment;

            return(segment);
        }
Ejemplo n.º 11
0
        internal Memory <byte> GetMemory(int sizeHint)
        {
            if (_writerCompletion.IsCompleted)
            {
                ThrowHelper.ThrowInvalidOperationException_NoWritingAllowed();
            }

            if (sizeHint < 0)
            {
                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.minimumSize);
            }

            lock (_sync)
            {
                BufferSegment segment = _writingHead ?? AllocateWriteHeadUnsynchronized(sizeHint);

                int bytesLeftInBuffer = segment.WritableBytes;

                // If inadequate bytes left or if the segment is readonly
                if (bytesLeftInBuffer == 0 || bytesLeftInBuffer < sizeHint || segment.ReadOnly)
                {
                    BufferSegment nextSegment = CreateSegmentUnsynchronized();
                    nextSegment.SetMemory(_pool.Rent(GetSegmentSize(sizeHint)));

                    segment.SetNext(nextSegment);

                    _writingHead = nextSegment;
                }
            }

            // Slice the AvailableMemory to the WritableBytes size
            int           end             = _writingHead.End;
            Memory <byte> availableMemory = _writingHead.AvailableMemory;

            availableMemory = availableMemory.Slice(end, availableMemory.Length - end);
            return(availableMemory);
        }