package rocks.inspectit.server.cache.impl;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import rocks.inspectit.server.cache.IBufferElement;
import rocks.inspectit.server.cache.IBufferElement.BufferElementState;
import rocks.inspectit.server.util.Converter;
import rocks.inspectit.shared.all.communication.DefaultData;
import rocks.inspectit.shared.cs.indexing.impl.IndexingException;
/**
* Index processor. Performs indexing of the elements, update of indexing tree size and cleaning the
* indexing tree.
*
* @param <E>
* Type of data to process.
*
* @author Ivan Senic
*
*/
class IndexBufferElementProcessor<E extends DefaultData> extends AbstractBufferElementProcessor<E> {
/**
* Default constructor.
*
* @param atomicBuffer
* {@link AtomicBuffer} to work on.
*
* @param lastProcessed
* Reference to the last processed element.
* @param lock
* Lock to use during operation.
* @param condition
* Condition to wait on when there s nothing to process.
*/
public IndexBufferElementProcessor(AtomicBuffer<E> atomicBuffer, AtomicReference<IBufferElement<E>> lastProcessed, Lock lock, Condition condition) {
super(atomicBuffer, lastProcessed, lock, condition);
}
/**
* {@inheritDoc}
* <p>
* After element processing we check if tree cleaning is needed.
*/
@Override
public void process() throws InterruptedException {
super.process();
// if clean flag is set thread should try to perform indexing tree cleaning
// only thread that successfully executes the compare and set will do the cleaning
while (true) {
long dataRemoveInBytesCurrent = atomicBuffer.dataRemovedInBytes.get();
if (dataRemoveInBytesCurrent > atomicBuffer.flagsSetOnBytes) {
if (atomicBuffer.dataRemovedInBytes.compareAndSet(dataRemoveInBytesCurrent, 0)) {
long time = 0;
if (atomicBuffer.log.isDebugEnabled()) {
time = System.nanoTime();
}
atomicBuffer.indexingTree.cleanWithRunnable(atomicBuffer.indexingTreeCleaningExecutorService);
if (atomicBuffer.log.isDebugEnabled()) {
atomicBuffer.log.debug("Indexing tree cleaning duration: " + Converter.nanoToMilliseconds(System.nanoTime() - time));
}
break;
}
} else {
break;
}
}
}
/**
* {@inheritDoc}
* <p>
* We wait until element is analyzed to index it.
* <p>
* After successful indexing we check if update of indexing tree size is needed and if so update
* it.
*
*/
@Override
public boolean process(IBufferElement<E> elementToProcess, IBufferElement<E> lastProcessedElement) {
// we only index when the element has already been analyzed
if (!elementToProcess.isAnalyzed()) {
try {
Thread.sleep(atomicBuffer.bufferProperties.getIndexingWaitTime());
} catch (InterruptedException e) {
Thread.interrupted();
}
// we go back to the while loop, because we want to check if the nextForIndexing
// element has changed
return false;
}
// only thread that execute compare and set successfully can perform changes
if (lastProcessed.compareAndSet(lastProcessedElement, elementToProcess)) {
try {
// index element
atomicBuffer.indexingTree.put(elementToProcess.getObject());
elementToProcess.setBufferElementState(BufferElementState.INDEXED);
// increase number of indexed elements, and perform calculation of the
// indexing tree size if enough elements have been indexed
atomicBuffer.elementsIndexed.incrementAndGet();
long dataAddedInBytesCurrent = atomicBuffer.dataAddedInBytes.get();
if (dataAddedInBytesCurrent > atomicBuffer.flagsSetOnBytes) {
if (atomicBuffer.dataAddedInBytes.compareAndSet(dataAddedInBytesCurrent, 0)) {
long time = 0;
if (atomicBuffer.log.isDebugEnabled()) {
time = System.nanoTime();
}
while (true) {
// calculation of new size has to be repeated if old size
// compare and set fails
long newSize = atomicBuffer.indexingTree.getComponentSize(atomicBuffer.objectSizes);
newSize += newSize * atomicBuffer.objectSizes.getObjectSecurityExpansionRate();
long oldSize = atomicBuffer.indexingTreeSize.get();
if (atomicBuffer.indexingTreeSize.compareAndSet(oldSize, newSize)) {
atomicBuffer.addToCurrentSize(newSize - oldSize, false);
if (atomicBuffer.log.isDebugEnabled()) {
atomicBuffer.log.debug("Indexing tree size update duration: " + Converter.nanoToMilliseconds(System.nanoTime() - time));
atomicBuffer.log.debug("Indexing tree delta: " + (newSize - oldSize));
atomicBuffer.log.debug("Indexing tree new size: " + newSize);
}
break;
}
}
}
}
} catch (IndexingException e) {
// indexing exception should not happen
atomicBuffer.log.error(e.getMessage(), e);
}
return true;
}
return false;
}
}