Beispiel #1
0
        /// <summary>
        /// Non-blocking write of an message to an underlying ring-buffer.
        /// </summary>
        /// <param name="msgTypeId"> type of the message encoding. </param>
        /// <param name="srcBuffer"> containing the encoded binary message. </param>
        /// <param name="srcIndex"> at which the encoded message begins. </param>
        /// <param name="length"> of the encoded message in bytes. </param>
        /// <returns> true if written to the ring-buffer, or false if insufficient space exists. </returns>
        /// <exception cref="ArgumentException"> if the length is greater than <seealso cref="IRingBuffer.MaxMsgLength()"/> </exception>
        public bool Write(int msgTypeId, IDirectBuffer srcBuffer, int srcIndex, int length)
        {
            RecordDescriptor.CheckTypeId(msgTypeId);
            CheckMsgLength(length);

            var isSuccessful = false;

            var buffer           = _buffer;
            var recordLength     = length + RecordDescriptor.HeaderLength;
            var requiredCapacity = BitUtil.Align(recordLength, RecordDescriptor.Alignment);
            var recordIndex      = ClaimCapacity(buffer, requiredCapacity);

            if (InsufficientCapacity != recordIndex)
            {
                buffer.PutLongOrdered(recordIndex, RecordDescriptor.MakeHeader(-recordLength, msgTypeId));
                // TODO JPW original: UnsafeAccess.UNSAFE.storeFence();
                Thread.MemoryBarrier();
                buffer.PutBytes(RecordDescriptor.EncodedMsgOffset(recordIndex), srcBuffer, srcIndex, length);
                buffer.PutIntOrdered(RecordDescriptor.LengthOffset(recordIndex), recordLength);

                isSuccessful = true;
            }

            return(isSuccessful);
        }
Beispiel #2
0
        /// <summary>
        /// Read as many messages as are available from the ring buffer to up a supplied maximum.
        /// </summary>
        /// <param name="handler"> to be called for processing each message in turn. </param>
        /// <param name="messageCountLimit"> the number of messages will be read in a single invocation. </param>
        /// <returns> the number of messages that have been processed. </returns>
        public int Read(MessageHandler handler, int messageCountLimit)
        {
            var messagesRead = 0;
            var buffer       = _buffer;
            var head         = buffer.GetLong(_headPositionIndex);

            var bytesRead = 0;

            var capacity              = _capacity;
            var headIndex             = (int)head & (capacity - 1);
            var contiguousBlockLength = capacity - headIndex;

            try
            {
                while ((bytesRead < contiguousBlockLength) && (messagesRead < messageCountLimit))
                {
                    var recordIndex = headIndex + bytesRead;
                    var header      = buffer.GetLongVolatile(recordIndex);

                    var recordLength = RecordDescriptor.RecordLength(header);
                    if (recordLength <= 0)
                    {
                        break;
                    }

                    bytesRead += BitUtil.Align(recordLength, RecordDescriptor.Alignment);

                    var messageTypeId = RecordDescriptor.MessageTypeId(header);
                    if (PaddingMsgTypeId == messageTypeId)
                    {
                        continue;
                    }

                    ++messagesRead;
                    handler(messageTypeId, buffer, recordIndex + RecordDescriptor.HeaderLength, recordLength - RecordDescriptor.HeaderLength);
                }
            }
            finally
            {
                if (bytesRead != 0)
                {
                    buffer.SetMemory(headIndex, bytesRead, 0);
                    buffer.PutLongOrdered(_headPositionIndex, head + bytesRead);
                }
            }

            return(messagesRead);
        }
Beispiel #3
0
        /// <summary>
        /// Unblock a multi-producer ring buffer where a producer has died during the act of offering. The operation will scan from
        /// the consumer position up to the producer position.
        ///
        /// If no action is required at the position then none will be taken.
        /// </summary>
        /// <returns> true of an unblocking action was taken otherwise false. </returns>
        public bool Unblock()
        {
            var buffer        = _buffer;
            var mask          = _capacity - 1;
            var consumerIndex = (int)(buffer.GetLongVolatile(_headPositionIndex) & mask);
            var producerIndex = (int)(buffer.GetLongVolatile(_tailPositionIndex) & mask);

            if (producerIndex == consumerIndex)
            {
                return(false);
            }

            var unblocked = false;
            var length    = buffer.GetIntVolatile(consumerIndex);

            if (length < 0)
            {
                buffer.PutLongOrdered(consumerIndex, RecordDescriptor.MakeHeader(-length, PaddingMsgTypeId));
                unblocked = true;
            }
            else if (0 == length)
            {
                // go from (consumerIndex to producerIndex) or (consumerIndex to capacity)
                var limit = producerIndex > consumerIndex ? producerIndex : _capacity;
                var i     = consumerIndex + RecordDescriptor.Alignment;

                do
                {
                    // read the top int of every long (looking for length aligned to 8=ALIGNMENT)
                    length = buffer.GetIntVolatile(i);
                    if (0 != length)
                    {
                        if (ScanBackToConfirmStillZeroed(buffer, i, consumerIndex))
                        {
                            buffer.PutLongOrdered(consumerIndex, RecordDescriptor.MakeHeader(i - consumerIndex, PaddingMsgTypeId));
                            unblocked = true;
                        }

                        break;
                    }

                    i += RecordDescriptor.Alignment;
                } while (i < limit);
            }

            return(unblocked);
        }
Beispiel #4
0
        private int ClaimCapacity(IAtomicBuffer buffer, int requiredCapacity)
        {
            var capacity               = _capacity;
            var tailPositionIndex      = _tailPositionIndex;
            var headCachePositionIndex = _headCachePositionIndex;
            var mask = capacity - 1;

            var head = buffer.GetLongVolatile(headCachePositionIndex);

            long tail;
            int  tailIndex;
            int  padding;

            do
            {
                tail = buffer.GetLongVolatile(tailPositionIndex);
                var availableCapacity = capacity - (int)(tail - head);

                if (requiredCapacity > availableCapacity)
                {
                    head = buffer.GetLongVolatile(_headPositionIndex);

                    if (requiredCapacity > (capacity - (int)(tail - head)))
                    {
                        return(InsufficientCapacity);
                    }

                    buffer.PutLongOrdered(headCachePositionIndex, head);
                }

                padding   = 0;
                tailIndex = (int)tail & mask;
                var toBufferEndLength = capacity - tailIndex;

                if (requiredCapacity > toBufferEndLength)
                {
                    var headIndex = (int)head & mask;

                    if (requiredCapacity > headIndex)
                    {
                        head      = buffer.GetLongVolatile(_headPositionIndex);
                        headIndex = (int)head & mask;
                        if (requiredCapacity > headIndex)
                        {
                            return(InsufficientCapacity);
                        }

                        buffer.PutLongOrdered(headCachePositionIndex, head);
                    }

                    padding = toBufferEndLength;
                }
            } while (!buffer.CompareAndSetLong(tailPositionIndex, tail, tail + requiredCapacity + padding));

            if (0 != padding)
            {
                buffer.PutLongOrdered(tailIndex, RecordDescriptor.MakeHeader(padding, PaddingMsgTypeId));
                tailIndex = 0;
            }

            return(tailIndex);
        }