com.bazaarvoice.emodb.event.db.astyanax.ChannelAllocationState Maven / Gradle / Ivy
package com.bazaarvoice.emodb.event.db.astyanax;
import com.google.common.collect.PeekingIterator;
import org.apache.commons.lang3.tuple.Pair;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
public class ChannelAllocationState {
private final Object _slabCreationLock = new Object();
private SlabRef _slab;
private int _slabConsumed;
private long _slabExpiresAt;
private int _slabBytesConsumed;
/** Per-channel lock on creating new shared slabs. */
public Object getSlabCreationLock() {
return _slabCreationLock;
}
public synchronized void rotateIfNecessary() {
if (isAttached() && _slabExpiresAt <= System.currentTimeMillis()) {
detach().release();
}
}
private synchronized boolean isAttached() {
return _slab != null;
}
/** Attaches a slab and allocates from it in a single atomic operation. */
public synchronized SlabAllocation attachAndAllocate(SlabRef slab, PeekingIterator eventSizes) {
attach(slab);
return allocate(eventSizes);
}
/** Attaches a new slab to the channel with the specified capacity. */
public synchronized void attach(SlabRef slab) {
// Assume ownership of the caller's ref. No need to call slab.addRef().
checkState(!isAttached());
_slab = slab;
_slabConsumed = 0;
_slabBytesConsumed = 0;
_slabExpiresAt = System.currentTimeMillis() + Constants.SLAB_ROTATE_TTL.toMillis();
}
/** Detaches a slab from the channel and returns it to the caller to dispose of. */
public synchronized SlabRef detach() {
if (!isAttached()) {
return null;
}
// Pass ownership of the slab ref to the caller. No need to call slab.release().
SlabRef slab = _slab;
_slab = null;
_slabExpiresAt = 0;
return slab;
}
public synchronized SlabAllocation allocate(PeekingIterator eventSizes) {
checkArgument(eventSizes.hasNext());
if (!isAttached()) {
return null;
}
int remaining = Constants.MAX_SLAB_SIZE - _slabConsumed;
Pair countAndBytesConsumed = DefaultSlabAllocator.defaultAllocationCount(_slabConsumed, _slabBytesConsumed, eventSizes);
int offsetForNewAllocation = _slabConsumed;
_slabConsumed += countAndBytesConsumed.getLeft();
_slabBytesConsumed += countAndBytesConsumed.getRight();
// Check for case where no more slots could be allocated because slab is full either because
// the max # of slots is consumed or the max # of bytes is consumed
if (countAndBytesConsumed.getLeft() == 0) {
detach().release();
return null;
}
if (countAndBytesConsumed.getLeft() < remaining) {
// All events fit in current slab, leave it attached
return new DefaultSlabAllocation(_slab.addRef(), offsetForNewAllocation, countAndBytesConsumed.getLeft());
} else {
// Whatever is left of this slab is consumed. Return the rest of the slab. Detach from it so we'll allocate a new one next time.
return new DefaultSlabAllocation(detach(), offsetForNewAllocation, countAndBytesConsumed.getLeft());
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy