All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.agrona.concurrent.status.CountersManager Maven / Gradle / Ivy

There is a newer version: 0.9.1
Show newest version
/*
 * Copyright 2014 - 2016 Real Logic Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.agrona.concurrent.status;

import org.agrona.MutableDirectBuffer;
import org.agrona.concurrent.AtomicBuffer;
import org.agrona.concurrent.UnsafeBuffer;

import java.util.Deque;
import java.util.LinkedList;
import java.util.function.Consumer;

/**
 * Manages the allocation and freeing of counters that are normally stored in a memory-mapped file.
 *
 * This class in not threadsafe. Counters should be centrally managed.
 *
 * Values Buffer
 * 
 *   0                   1                   2                   3
 *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *  |                        Counter Value                          |
 *  |                                                               |
 *  +---------------------------------------------------------------+
 *  |                     120 bytes of padding                     ...
 * ...                                                              |
 *  +---------------------------------------------------------------+
 *  |                   Repeats to end of buffer                   ...
 *  |                                                               |
 * ...                                                              |
 *  +---------------------------------------------------------------+
 * 
* * Meta Data Buffer *
 *   0                   1                   2                   3
 *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *  |                        Record State                           |
 *  +---------------------------------------------------------------+
 *  |                          Type Id                              |
 *  +---------------------------------------------------------------+
 *  |                      120 bytes for key                       ...
 * ...                                                              |
 *  +-+-------------------------------------------------------------+
 *  |R|                      Label Length                           |
 *  +-+-------------------------------------------------------------+
 *  |                  124 bytes of Label in UTF-8                 ...
 * ...                                                              |
 *  +---------------------------------------------------------------+
 *  |                   Repeats to end of buffer                   ...
 *  |                                                               |
 * ...                                                              |
 *  +---------------------------------------------------------------+
 * 
*/ public class CountersManager extends CountersReader { /** * Default type id of a counter when none is supplied. */ public static final int DEFAULT_TYPE_ID = 0; /** * Default function to set a key when none is supplied. */ public static final Consumer DEFAULT_KEY_FUNC = (ignore) -> { }; private int idHighWaterMark = -1; private final Deque freeList = new LinkedList<>(); /** * Create a new counter buffer manager over two buffers. * * @param metaDataBuffer containing the types, keys, and labels for the counters. * @param valuesBuffer containing the values of the counters themselves. */ public CountersManager(final AtomicBuffer metaDataBuffer, final AtomicBuffer valuesBuffer) { super(metaDataBuffer, valuesBuffer); valuesBuffer.verifyAlignment(); if (metaDataBuffer.capacity() < (valuesBuffer.capacity() * 2)) { throw new IllegalArgumentException("Meta data buffer not sufficiently large"); } } /** * Allocate a new counter with a given label. * * @param label to describe the counter. * @return the id allocated for the counter. */ public int allocate(final String label) { return allocate(label, DEFAULT_TYPE_ID, DEFAULT_KEY_FUNC); } /** * 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. * * @param label to describe the counter. * @param typeId for the type of counter. * @param keyFunc for setting the key value for the counter. * @return the id allocated for the counter. */ public int allocate(final String label, final int typeId, final Consumer keyFunc) { final int counterId = nextCounterId(); if ((counterOffset(counterId) + COUNTER_LENGTH) > valuesBuffer.capacity()) { throw new IllegalArgumentException("Unable to allocated counter, values buffer is full"); } final int recordOffset = metaDataOffset(counterId); if ((recordOffset + METADATA_LENGTH) > metaDataBuffer.capacity()) { throw new IllegalArgumentException("Unable to allocate counter, labels buffer is full"); } metaDataBuffer.putInt(recordOffset + TYPE_ID_OFFSET, typeId); keyFunc.accept(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; } /** * Allocate a counter record and wrap it with a new {@link AtomicCounter} for use. * * @param label to describe the counter. * @return a newly allocated {@link AtomicCounter} */ public AtomicCounter newCounter(final String label) { return new AtomicCounter(valuesBuffer, allocate(label), this); } /** * Allocate a counter record and wrap it with a new {@link AtomicCounter} for use. * * @param label to describe the counter. * @param typeId for the type of counter. * @param keyFunc for setting the key value for the counter. * * @return a newly allocated {@link AtomicCounter} */ public AtomicCounter newCounter(final String label, final int typeId, final Consumer keyFunc) { return new AtomicCounter(valuesBuffer, allocate(label, typeId, keyFunc), this); } /** * Free the counter identified by counterId. * * @param counterId the counter to freed */ public void free(final int counterId) { metaDataBuffer.putIntOrdered(metaDataOffset(counterId), RECORD_RECLAIMED); freeList.add(counterId); } /** * Set an {@link AtomicCounter} value based on counterId. * * @param counterId to be set. * @param value to set for the counter. */ public void setCounterValue(final int counterId, final long value) { valuesBuffer.putLongOrdered(counterOffset(counterId), value); } private int nextCounterId() { if (freeList.isEmpty()) { return ++idHighWaterMark; } final int counterId = freeList.remove(); valuesBuffer.putLongOrdered(counterOffset(counterId), 0L); return counterId; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy