/** * Allocate a new counter with a given label with a default type of {@link #DEFAULT_TYPE_ID}. * * @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); }
/** * Create a new counter for the enumerated descriptor. * * @param countersManager for managing the underlying storage. * @return a new counter for the enumerated descriptor. */ public AtomicCounter newCounter(final CountersManager countersManager) { return countersManager.newCounter(label, SYSTEM_COUNTER_TYPE_ID, (buffer) -> buffer.putInt(0, id)); } }
@Test public void shouldFreeAndReuseCountersAfterCooldown() { final int abc = managerWithCooldown.allocate("abc"); final int def = managerWithCooldown.allocate("def"); final int ghi = managerWithCooldown.allocate("ghi"); managerWithCooldown.free(def); currentTimestamp += FREE_TO_REUSE_TIMEOUT; assertThat(managerWithCooldown.allocate("the next label"), is(def)); }
/** * Allocate a new counter with a given label and type. * * @param label to describe the counter. * @param typeId for the type of counter. * @return the id allocated for the counter. */ public int allocate(final String label, final int typeId) { final int counterId = nextCounterId(); checkCountersCapacity(counterId); final 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 (final Exception ex) { freeList.pushInt(counterId); LangUtil.rethrowUnchecked(ex); } return counterId; }
@Test public void shouldStoreAndLoadValue() { final int counterId = manager.allocate("Test Counter"); final long value = 7L; manager.setCounterValue(counterId, value); assertThat(manager.getCounterValue(counterId), is(value)); } }
final int labelLength) final int counterId = nextCounterId(); checkCountersCapacity(counterId); final int recordOffset = metaDataOffset(counterId); checkMetaDataCapacity(recordOffset); allocate(typeId, keyBuffer, keyOffset, keyLength, labelBuffer, labelOffset, labelLength), this);
(UnsafeBuffer)countersManager.valuesBuffer(), allocateCounterId(tempBuffer, name, typeId, countersManager, registrationId, sessionId, streamId, channel), countersManager); final int counterId = countersManager.allocate( typeId, tempBuffer, labelLength); return new UnsafeBufferPosition((UnsafeBuffer)countersManager.valuesBuffer(), counterId, countersManager);
@Test public void shouldCopeWithExceptionKeyFunc() { final RuntimeException ex = new RuntimeException(); try { manager.allocate( "label", CountersManager.DEFAULT_TYPE_ID, (buffer) -> { throw ex; }); } catch (final RuntimeException caught) { assertThat(caught, is(ex)); final AtomicCounter counter = manager.newCounter("new label"); assertThat(counter.id(), is(0)); return; } fail("Should have thrown exception"); }
public void close() { if (!isClosed) { isClosed = true; if (null != countersManager) { countersManager.free(counterId); } } } }
/** * Allocate a counter for tracking the last heartbeat of an entity. * * @param tempBuffer to be used for labels and key. * @param name of the counter for the label. * @param typeId of the counter for classification. * @param countersManager from which to allocated the underlying storage. * @param registrationId to be associated with the counter. * @return a new {@link AtomicCounter} for tracking the last heartbeat. */ public static AtomicCounter allocate( final MutableDirectBuffer tempBuffer, final String name, final int typeId, final CountersManager countersManager, final long registrationId) { return new AtomicCounter( countersManager.valuesBuffer(), allocateCounterId(tempBuffer, name, typeId, countersManager, registrationId), countersManager); }
@Test public void shouldStoreMetaData() { final int typeIdOne = 333; final long keyOne = 777L; final int typeIdTwo = 222; final long keyTwo = 444; final int counterIdOne = manager.allocate("Test Label One", typeIdOne, (buffer) -> buffer.putLong(0, keyOne)); final int counterIdTwo = manager.allocate("Test Label Two", typeIdTwo, (buffer) -> buffer.putLong(0, keyTwo)); manager.forEach(metaData); final ArgumentCaptor<DirectBuffer> argCaptorOne = ArgumentCaptor.forClass(DirectBuffer.class); final ArgumentCaptor<DirectBuffer> argCaptorTwo = ArgumentCaptor.forClass(DirectBuffer.class); final InOrder inOrder = Mockito.inOrder(metaData); inOrder.verify(metaData).accept(eq(counterIdOne), eq(typeIdOne), argCaptorOne.capture(), eq("Test Label One")); inOrder.verify(metaData).accept(eq(counterIdTwo), eq(typeIdTwo), argCaptorTwo.capture(), eq("Test Label Two")); inOrder.verifyNoMoreInteractions(); final DirectBuffer keyOneBuffer = argCaptorOne.getValue(); assertThat(keyOneBuffer.getLong(0), is(keyOne)); final DirectBuffer keyTwoBuffer = argCaptorTwo.getValue(); assertThat(keyTwoBuffer.getLong(0), is(keyTwo)); }
countersManager = new CountersManager( countersMetaDataBuffer(), countersValuesBuffer(), US_ASCII, clock, reuseTimeoutMs);
/** * 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); }
/** * 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<MutableDirectBuffer> 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; }
private int nextCounterId() { final long nowMs = epochClock.time(); for (int i = 0, size = freeList.size(); i < size; i++) { final int counterId = freeList.getInt(i); final 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; }
/** * Free the counter identified by counterId. * * @param counterId the counter to freed */ public void free(final int counterId) { final int recordOffset = metaDataOffset(counterId); metaDataBuffer.putLong( recordOffset + FREE_FOR_REUSE_DEADLINE_OFFSET, epochClock.time() + freeToReuseTimeoutMs); metaDataBuffer.putIntOrdered(recordOffset, RECORD_RECLAIMED); freeList.addInt(counterId); }
final int labelLength) final int counterId = nextCounterId(); checkCountersCapacity(counterId); final int recordOffset = metaDataOffset(counterId); checkMetaDataCapacity(recordOffset); allocate(typeId, keyBuffer, keyOffset, keyLength, labelBuffer, labelOffset, labelLength), this);
(UnsafeBuffer)countersManager.valuesBuffer(), allocateCounterId(tempBuffer, name, typeId, countersManager, registrationId, sessionId, streamId, channel), countersManager); final int counterId = countersManager.allocate( typeId, tempBuffer, labelLength); return new UnsafeBufferPosition((UnsafeBuffer)countersManager.valuesBuffer(), counterId, countersManager);
final int counterId = nextCounterId(); checkCountersCapacity(counterId); final int recordOffset = metaDataOffset(counterId); checkMetaDataCapacity(recordOffset); keyFunc.accept(new UnsafeBuffer(metaDataBuffer, recordOffset + KEY_OFFSET, MAX_KEY_LENGTH)); metaDataBuffer.putLong(recordOffset + FREE_FOR_REUSE_DEADLINE_OFFSET, NOT_FREE_TO_REUSE); putLabel(recordOffset, label);
/** * Free the counter slot for reuse. */ public void close() { if (!isClosed) { isClosed = true; if (null != countersManager) { countersManager.free(id); } } } }