예제 #1
0
        /// <summary>
        /// Allocate a new counter with a given label and type.
        /// </summary>
        /// <param name="label">  to describe the counter. </param>
        /// <param name="typeId"> for the type of counter. </param>
        /// <returns> the id allocated for the counter. </returns>
        public int Allocate(string label, int typeId = DEFAULT_TYPE_ID)
        {
            int counterId = NextCounterId();

            CheckCountersCapacity(counterId);

            int recordOffset = MetaDataOffset(counterId);

            CheckMetaDataCapacity(recordOffset);

            try
            {
                MetaDataBuffer.PutInt(recordOffset + TYPE_ID_OFFSET, typeId);
                MetaDataBuffer.PutLong(recordOffset + FREE_FOR_REUSE_DEADLINE_OFFSET, NOT_FREE_TO_REUSE);
                PutLabel(recordOffset, label);
                MetaDataBuffer.PutIntOrdered(recordOffset, RECORD_ALLOCATED);
            }
            catch (Exception)
            {
                _freeList.Add(counterId);
                throw;
            }

            return(counterId);
        }
예제 #2
0
        /// <summary>
        /// Allocate a new counter with a given label.
        ///
        /// The key function will be called with a buffer with the exact length of available key space
        /// in the record for the user to store what they want for the key. No offset is required.
        /// </summary>
        /// <param name="label">   to describe the counter. </param>
        /// <param name="typeId">  for the type of counter. </param>
        /// <param name="keyFunc"> for setting the key value for the counter. </param>
        /// <returns> the id allocated for the counter. </returns>
        public int Allocate(string label, int typeId, Action <IMutableDirectBuffer> keyFunc)
        {
            var counterId = NextCounterId();

            CheckCountersCapacity(counterId);

            var recordOffset = MetaDataOffset(counterId);

            CheckMetaDataCapacity(recordOffset);

            try
            {
                MetaDataBuffer.PutInt(recordOffset + TYPE_ID_OFFSET, typeId);
                keyFunc(new UnsafeBuffer(MetaDataBuffer, recordOffset + KEY_OFFSET, MAX_KEY_LENGTH));
                MetaDataBuffer.PutLong(recordOffset + FREE_FOR_REUSE_DEADLINE_OFFSET, NOT_FREE_TO_REUSE);
                PutLabel(recordOffset, label);

                MetaDataBuffer.PutIntOrdered(recordOffset, RECORD_ALLOCATED);
            }
            catch (Exception)
            {
                _freeList.Add(counterId);
                throw;
            }

            return(counterId);
        }
예제 #3
0
        /// <summary>
        /// Allocate a new counter with a given label.
        ///
        /// The key function will be called with a buffer with the exact length of available key space
        /// in the record for the user to store what they want for the key. No offset is required.
        /// </summary>
        /// <param name="label">   to describe the counter. </param>
        /// <param name="typeId">  for the type of counter. </param>
        /// <param name="keyFunc"> for setting the key value for the counter. </param>
        /// <returns> the id allocated for the counter. </returns>
        public int Allocate(string label, int typeId, Action <IMutableDirectBuffer> keyFunc)
        {
            var counterId = NextCounterId();

            if (CounterOffset(counterId) + COUNTER_LENGTH > ValuesBuffer.Capacity)
            {
                throw new InvalidOperationException("Unable to allocated counter, values buffer is full");
            }

            var recordOffset = MetaDataOffset(counterId);

            if (recordOffset + METADATA_LENGTH > MetaDataBuffer.Capacity)
            {
                throw new InvalidOperationException("Unable to allocate counter, labels buffer is full");
            }


            try
            {
                MetaDataBuffer.PutInt(recordOffset + TYPE_ID_OFFSET, typeId);
                keyFunc(new UnsafeBuffer(MetaDataBuffer, recordOffset + KEY_OFFSET, MAX_KEY_LENGTH));
                PutLabel(recordOffset, label);

                MetaDataBuffer.PutIntOrdered(recordOffset, RECORD_ALLOCATED);
            }
            catch (Exception)
            {
                _freeList.Enqueue(counterId);
                throw;
            }

            return(counterId);
        }
예제 #4
0
        /// <summary>
        /// Allocate a new counter with a given label and type.
        /// </summary>
        /// <param name="label">  to describe the counter. </param>
        /// <param name="typeId"> for the type of counter. </param>
        /// <returns> the id allocated for the counter. </returns>
        public int Allocate(string label, int typeId = DEFAULT_TYPE_ID)
        {
            int counterId = NextCounterId();

            if ((CounterOffset(counterId) + COUNTER_LENGTH) > ValuesBuffer.Capacity)
            {
                throw new InvalidOperationException("Unable to allocated counter, values buffer is full");
            }

            int recordOffset = MetaDataOffset(counterId);

            if ((recordOffset + METADATA_LENGTH) > MetaDataBuffer.Capacity)
            {
                throw new InvalidOperationException("Unable to allocate counter, labels buffer is full");
            }

            try
            {
                MetaDataBuffer.PutInt(recordOffset + TYPE_ID_OFFSET, typeId);
                PutLabel(recordOffset, label);
                MetaDataBuffer.PutIntOrdered(recordOffset, RECORD_ALLOCATED);
            }
            catch (Exception)
            {
                _freeList.Enqueue(counterId);
                throw;
            }

            return(counterId);
        }
예제 #5
0
        /// <summary>
        /// Free the counter identified by counterId.
        /// </summary>
        /// <param name="counterId"> the counter to freed </param>
        public void Free(int counterId)
        {
            int recordOffset = MetaDataOffset(counterId);

            MetaDataBuffer.PutLong(recordOffset + FREE_FOR_REUSE_DEADLINE_OFFSET, _epochClock.Time() + _freeToReuseTimeoutMs);
            MetaDataBuffer.PutIntOrdered(recordOffset, RECORD_RECLAIMED);
            _freeList.Add(counterId);
        }
예제 #6
0
        private string LabelValue(int recordOffset)
        {
            int labelLength = MetaDataBuffer.GetInt(recordOffset + LABEL_OFFSET);

            byte[] stringInBytes = new byte[labelLength];
            MetaDataBuffer.GetBytes(recordOffset + LABEL_OFFSET + BitUtil.SIZE_OF_INT, stringInBytes);

            return(LabelCharset.GetString(stringInBytes));
        }
예제 #7
0
        private void PutLabel(int recordOffset, string label)
        {
            if (Encoding.ASCII.Equals(LabelCharset))
            {
                int length = MetaDataBuffer.PutStringWithoutLengthAscii(recordOffset + LABEL_OFFSET + BitUtil.SIZE_OF_INT, label, 0, MAX_LABEL_LENGTH);
                MetaDataBuffer.PutInt(recordOffset + LABEL_OFFSET, length);
            }
            else
            {
                byte[] bytes  = LabelCharset.GetBytes(label);
                int    length = Math.Min(bytes.Length, MAX_LABEL_LENGTH);

                MetaDataBuffer.PutInt(recordOffset + LABEL_OFFSET, length);
                MetaDataBuffer.PutBytes(recordOffset + LABEL_OFFSET + BitUtil.SIZE_OF_INT, bytes, 0, length);
            }
        }
예제 #8
0
        /// <summary>
        /// Allocate a counter with the minimum of allocation by allowing the label an key to be provided and copied.
        /// <para>
        /// If the keyBuffer is null then a copy of the key is not attempted.
        ///
        /// </para>
        /// </summary>
        /// <param name="typeId">      for the counter. </param>
        /// <param name="keyBuffer">   containing the optional key for the counter. </param>
        /// <param name="keyOffset">   within the keyBuffer at which the key begins. </param>
        /// <param name="keyLength">   of the key in the keyBuffer. </param>
        /// <param name="labelBuffer"> containing the mandatory label for the counter. </param>
        /// <param name="labelOffset"> within the labelBuffer at which the label begins. </param>
        /// <param name="labelLength"> of the label in the labelBuffer. </param>
        /// <returns> the id allocated for the counter. </returns>
        public int Allocate(int typeId, IDirectBuffer keyBuffer, int keyOffset, int keyLength, IDirectBuffer labelBuffer, int labelOffset, int labelLength)
        {
            int counterId = NextCounterId();

            if ((CounterOffset(counterId) + COUNTER_LENGTH) > ValuesBuffer.Capacity)
            {
                throw new InvalidOperationException("Unable to allocated counter, values buffer is full");
            }

            int recordOffset = MetaDataOffset(counterId);

            if ((recordOffset + METADATA_LENGTH) > MetaDataBuffer.Capacity)
            {
                throw new InvalidOperationException("Unable to allocate counter, labels buffer is full");
            }

            try
            {
                MetaDataBuffer.PutInt(recordOffset + TYPE_ID_OFFSET, typeId);

                int length;

                if (null != keyBuffer)
                {
                    length = Math.Min(keyLength, MAX_KEY_LENGTH);
                    MetaDataBuffer.PutBytes(recordOffset + KEY_OFFSET, keyBuffer, keyOffset, length);
                }

                length = Math.Min(labelLength, MAX_LABEL_LENGTH);
                MetaDataBuffer.PutInt(recordOffset + LABEL_OFFSET, length);
                MetaDataBuffer.PutBytes(recordOffset + LABEL_OFFSET + BitUtil.SIZE_OF_INT, labelBuffer, labelOffset, length);

                MetaDataBuffer.PutIntOrdered(recordOffset, RECORD_ALLOCATED);
            }
            catch (Exception)
            {
                _freeList.Enqueue(counterId);
                throw;
            }

            return(counterId);
        }
예제 #9
0
        /// <summary>
        /// Iterate over all labels in the label buffer.
        /// </summary>
        /// <param name="consumer"> function to be called for each label. </param>
        public void ForEach(IntObjConsumer <string> consumer)
        {
            var counterId = 0;

            for (int i = 0, capacity = MetaDataBuffer.Capacity; i < capacity; i += METADATA_LENGTH)
            {
                var recordStatus = MetaDataBuffer.GetIntVolatile(i);
                if (RECORD_UNUSED == recordStatus)
                {
                    break;
                }
                else if (RECORD_ALLOCATED == recordStatus)
                {
                    var label = MetaDataBuffer.GetStringUtf8(i + LABEL_OFFSET);
                    consumer(counterId, label);
                }

                counterId++;
            }
        }
예제 #10
0
        /// <summary>
        /// Iterate over the counters and provide the value and basic metadata.
        /// </summary>
        /// <param name="consumer"> for each allocated counter. </param>
        public void ForEach(CounterConsumer consumer)
        {
            int counterId = 0;

            for (int i = 0, capacity = MetaDataBuffer.Capacity; i < capacity; i += METADATA_LENGTH)
            {
                int recordStatus = MetaDataBuffer.GetIntVolatile(i);

                if (RECORD_ALLOCATED == recordStatus)
                {
                    consumer(ValuesBuffer.GetLongVolatile(CounterOffset(counterId)), counterId, LabelValue(i));
                }
                else if (RECORD_UNUSED == recordStatus)
                {
                    break;
                }

                counterId++;
            }
        }
예제 #11
0
        private int NextCounterId()
        {
            long nowMs = _epochClock.Time();

            for (int i = 0, size = _freeList.Count; i < size; i++)
            {
                int counterId = _freeList[i];

                long deadlineMs = MetaDataBuffer.GetLongVolatile(MetaDataOffset(counterId) + FREE_FOR_REUSE_DEADLINE_OFFSET);

                if (nowMs >= deadlineMs)
                {
                    _freeList.Remove(i);
                    ValuesBuffer.PutLongOrdered(CounterOffset(counterId), 0L);

                    return(counterId);
                }
            }

            return(++_idHighWaterMark);
        }
예제 #12
0
        private void PutLabel(int recordOffset, string label)
        {
            if (Encoding.ASCII.Equals(LabelCharset))
            {
                MetaDataBuffer.PutStringAscii(recordOffset + LABEL_OFFSET, label.Length > MAX_LABEL_LENGTH ? label.Substring(0, MAX_LABEL_LENGTH) : label);
            }
            else
            {
                byte[] bytes = LabelCharset.GetBytes(label);

                if (bytes.Length > MAX_LABEL_LENGTH)
                {
                    MetaDataBuffer.PutInt(recordOffset + LABEL_OFFSET, MAX_LABEL_LENGTH);
                    MetaDataBuffer.PutBytes(recordOffset + LABEL_OFFSET + BitUtil.SIZE_OF_INT, bytes, 0, MAX_LABEL_LENGTH);
                }
                else
                {
                    MetaDataBuffer.PutInt(recordOffset + LABEL_OFFSET, bytes.Length);
                    MetaDataBuffer.PutBytes(recordOffset + LABEL_OFFSET + BitUtil.SIZE_OF_INT, bytes);
                }
            }
        }
예제 #13
0
        /// <summary>
        /// Allocate a new counter with a given label.
        /// </summary>
        /// <param name="label"> to describe the counter. </param>
        /// <returns> the id allocated for the counter. </returns>
        public int Allocate(string label)
        {
            int counterId = NextCounterId();

            if ((CounterOffset(counterId) + COUNTER_LENGTH) > ValuesBuffer.Capacity)
            {
                throw new ArgumentException("Unable to allocated counter, values buffer is full");
            }

            int recordOffset = MetaDataOffset(counterId);

            if ((recordOffset + METADATA_LENGTH) > MetaDataBuffer.Capacity)
            {
                throw new ArgumentException("Unable to allocate counter, labels buffer is full");
            }

            MetaDataBuffer.PutInt(recordOffset + TYPE_ID_OFFSET, DEFAULT_TYPE_ID);
            MetaDataBuffer.PutStringUtf8(recordOffset + LABEL_OFFSET, label, MAX_LABEL_LENGTH);

            MetaDataBuffer.PutIntOrdered(recordOffset, RECORD_ALLOCATED);

            return(counterId);
        }
예제 #14
0
        /// <summary>
        /// Iterate over all the metadata in the buffer.
        /// </summary>
        /// <param name="metaData"> function to be called for each metadata record. </param>
        public void ForEach(MetaData metaData)
        {
            var counterId = 0;

            for (int i = 0, capacity = MetaDataBuffer.Capacity; i < capacity; i += METADATA_LENGTH)
            {
                var recordStatus = MetaDataBuffer.GetIntVolatile(i);
                if (RECORD_UNUSED == recordStatus)
                {
                    break;
                }
                if (RECORD_ALLOCATED == recordStatus)
                {
                    var           typeId    = MetaDataBuffer.GetInt(i + TYPE_ID_OFFSET);
                    var           label     = MetaDataBuffer.GetStringUtf8(i + LABEL_OFFSET);
                    IDirectBuffer keyBuffer = new UnsafeBuffer(MetaDataBuffer, i + KEY_OFFSET, MAX_KEY_LENGTH);

                    metaData(counterId, typeId, keyBuffer, label);
                }

                counterId++;
            }
        }
예제 #15
0
        /// <summary>
        /// Allocate a counter with the minimum of allocation by allowing the label an key to be provided and copied.
        /// <para>
        /// If the keyBuffer is null then a copy of the key is not attempted.
        ///
        /// </para>
        /// </summary>
        /// <param name="typeId">      for the counter. </param>
        /// <param name="keyBuffer">   containing the optional key for the counter. </param>
        /// <param name="keyOffset">   within the keyBuffer at which the key begins. </param>
        /// <param name="keyLength">   of the key in the keyBuffer. </param>
        /// <param name="labelBuffer"> containing the mandatory label for the counter. </param>
        /// <param name="labelOffset"> within the labelBuffer at which the label begins. </param>
        /// <param name="labelLength"> of the label in the labelBuffer. </param>
        /// <returns> the id allocated for the counter. </returns>
        public int Allocate(int typeId, IDirectBuffer keyBuffer, int keyOffset, int keyLength, IDirectBuffer labelBuffer, int labelOffset, int labelLength)
        {
            int counterId = NextCounterId();

            CheckCountersCapacity(counterId);

            int recordOffset = MetaDataOffset(counterId);

            CheckMetaDataCapacity(recordOffset);

            try
            {
                MetaDataBuffer.PutInt(recordOffset + TYPE_ID_OFFSET, typeId);
                MetaDataBuffer.PutLong(recordOffset + FREE_FOR_REUSE_DEADLINE_OFFSET, NOT_FREE_TO_REUSE);

                int length;

                if (null != keyBuffer)
                {
                    length = Math.Min(keyLength, MAX_KEY_LENGTH);
                    MetaDataBuffer.PutBytes(recordOffset + KEY_OFFSET, keyBuffer, keyOffset, length);
                }

                length = Math.Min(labelLength, MAX_LABEL_LENGTH);
                MetaDataBuffer.PutInt(recordOffset + LABEL_OFFSET, length);
                MetaDataBuffer.PutBytes(recordOffset + LABEL_OFFSET + BitUtil.SIZE_OF_INT, labelBuffer, labelOffset, length);

                MetaDataBuffer.PutIntOrdered(recordOffset, RECORD_ALLOCATED);
            }
            catch (Exception)
            {
                _freeList.Add(counterId);
                throw;
            }

            return(counterId);
        }
예제 #16
0
        /// <summary>
        /// Allocate a new counter with a given label.
        ///
        /// The key function will be called with a buffer with the exact length of available key space
        /// in the record for the user to store what they want for the key. No offset is required.
        /// </summary>
        /// <param name="label">   to describe the counter. </param>
        /// <param name="typeId">  for the type of counter. </param>
        /// <param name="keyFunc"> for setting the key value for the counter. </param>
        /// <returns> the id allocated for the counter. </returns>
        public int Allocate(string label, int typeId, Action <IMutableDirectBuffer> keyFunc)
        {
            var counterId = NextCounterId();

            if (CounterOffset(counterId) + COUNTER_LENGTH > ValuesBuffer.Capacity)
            {
                throw new ArgumentException("Unable to allocated counter, values buffer is full");
            }

            var recordOffset = MetaDataOffset(counterId);

            if (recordOffset + METADATA_LENGTH > MetaDataBuffer.Capacity)
            {
                throw new ArgumentException("Unable to allocate counter, labels buffer is full");
            }

            MetaDataBuffer.PutInt(recordOffset + TYPE_ID_OFFSET, typeId);
            keyFunc(new UnsafeBuffer(MetaDataBuffer, recordOffset + KEY_OFFSET, MAX_KEY_LENGTH));
            MetaDataBuffer.PutStringUtf8(recordOffset + LABEL_OFFSET, label, MAX_LABEL_LENGTH);

            MetaDataBuffer.PutIntOrdered(recordOffset, RECORD_ALLOCATED);

            return(counterId);
        }
예제 #17
0
        /// <summary>
        /// Get the deadline (in milliseconds) for when a given counter id may be reused.
        /// </summary>
        /// <param name="counterId"> to be read. </param>
        /// <returns> deadline (in milliseconds) for when a given counter id may be reused or <seealso cref="NOT_FREE_TO_REUSE"/> if
        /// currently in use. </returns>
        public long GetFreeForReuseDeadline(int counterId)
        {
            ValidateCounterId(counterId);

            return(MetaDataBuffer.GetLongVolatile(MetaDataOffset(counterId) + FREE_FOR_REUSE_DEADLINE_OFFSET));
        }
예제 #18
0
 /// <summary>
 /// Free the counter identified by counterId.
 /// </summary>
 /// <param name="counterId"> the counter to freed </param>
 public void Free(int counterId)
 {
     MetaDataBuffer.PutIntOrdered(MetaDataOffset(counterId), RECORD_RECLAIMED);
     _freeList.Enqueue(counterId);
 }
예제 #19
0
        /// <summary>
        /// Get the type id for a given counter id.
        /// </summary>
        /// <param name="counterId"> to be read. </param>
        /// <returns> the type id for a given counter id. </returns>
        public int GetCounterTypeId(int counterId)
        {
            ValidateCounterId(counterId);

            return(MetaDataBuffer.GetInt(MetaDataOffset(counterId) + TYPE_ID_OFFSET));
        }
예제 #20
0
        /// <summary>
        /// Get the state for a given counter id as a volatile read.
        /// </summary>
        /// <param name="counterId"> to be read. </param>
        /// <returns> the current state of the counter. </returns>
        /// <seealso cref="RECORD_UNUSED"></seealso>
        /// <seealso cref="RECORD_ALLOCATED"></seealso>
        /// <seealso cref="RECORD_RECLAIMED"></seealso>
        public int GetCounterState(int counterId)
        {
            ValidateCounterId(counterId);

            return(MetaDataBuffer.GetIntVolatile(MetaDataOffset(counterId)));
        }