com.anaptecs.jeaf.workload.proxy.ByteBufferPool Maven / Gradle / Ivy
The newest version!
/**
* Copyright 2004 - 2021 anaptecs GmbH, Burgstr. 96, 72764 Reutlingen, Germany
*
* All rights reserved.
*/
package com.anaptecs.jeaf.workload.proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import com.anaptecs.jeaf.tools.api.Tools;
import com.anaptecs.jeaf.xfun.api.XFun;
import stormpot.BlazePool;
import stormpot.Config;
import stormpot.Pool;
import stormpot.PoolException;
import stormpot.Timeout;
/**
* Class implements a pool for byte buffers. In order to avoid wasting memory the pool is able to provide byte buffers
* with different sizes.
*
* @author JEAF Development Team
*/
public class ByteBufferPool {
private static final String CLASS_PREFIX = ByteBufferPool.class.getName();
public static final String TOO_BIG_TO_POOL_COUNTER = CLASS_PREFIX + ".TooBigToPoolCounter";
public static final String POOL_ERROR_COUNTER = CLASS_PREFIX + ".PoolErrorCounter";
public static final String POOL_OVERLOADED_COUNTER = CLASS_PREFIX + ".PoolOverloadedCounter";
public static final String POOL_ACCESS_COUNTER = CLASS_PREFIX + ".PoolAccessCounter";
/**
* Timeout that is used when requesting buffers from the pool.
*/
private static final Timeout TIMEOUT = new Timeout(1, TimeUnit.NANOSECONDS);
/**
* Exponent offset is used to calculate the pool index.
*/
private final int exponentOffset;
/**
* List of all byte buffer pools.
*/
private final List> pools;
/**
* Size of each byte buffer pool.
*/
private final int poolSize;
/**
* Initialize object.
*
* @param pPoolSize Size of the pool.
* @param pSmallestBufferSize Size of the smallest byte buffers.
* @param pLargestBufferSize Size of the largest byte buffers.
*/
public ByteBufferPool( int pPoolSize, int pSmallestBufferSize, int pLargestBufferSize ) {
poolSize = pPoolSize;
exponentOffset = this.calculateExponent(pSmallestBufferSize);
int lPoolCount = Math.max(this.calculateExponent(pLargestBufferSize) - exponentOffset + 1, 1);
pools = new ArrayList<>(lPoolCount);
// Calculate size of pools with smallest byte buffers.
int lBufferSize = 1 << exponentOffset;
// Create buffer pools.
int lReservedMemory = 0;
for (int i = 0; i < lPoolCount; i++) {
// Create new pool for validating document builders
XFun.getTrace().info("Creating byte buffer pool with buffer size " + lBufferSize);
Config lConfig = new Config<>();
lConfig.setSize(poolSize);
lConfig.setAllocator(new PoolableByteBufferAllocator(lBufferSize));
BlazePool lNewPool = new BlazePool<>(lConfig);
pools.add(lNewPool);
// Adjust overall reserved memory
lReservedMemory = lReservedMemory + (poolSize * lBufferSize);
// For each pool we will double the pool size.
lBufferSize = lBufferSize * 2;
// Preload pool by claiming first object.
PoolableByteBuffer lBuffer = null;
try {
lBuffer = lNewPool.claim(new Timeout(10, TimeUnit.MILLISECONDS));
}
catch (PoolException e) {
XFun.getTrace().error(e.getMessage(), e);
}
catch (InterruptedException e) {
XFun.getTrace().error(e.getMessage(), e);
Thread.currentThread().interrupt();
}
finally {
if (lBuffer != null) {
lBuffer.release();
}
}
}
// Trace info about acquired memory.
XFun.getTrace().info("Reserved " + lReservedMemory / (1024)
+ "kB memory for byte buffer pools. Each pool has a capacity for " + poolSize + " objects.");
}
/**
* Method returns a pooled byte buffer that at least has the requested minimum size. If no more object are available
* the an unpooled object will be returned.
*
* @param pMinimumBufferSize Minimum size of the requested byte buffer.
* @return {@link PoolableByteBuffer} Byte buffer that has at least the requested minimum size. The method never
* returns null.
*/
public PoolableByteBuffer getPooledByteBuffer( int pMinimumBufferSize ) {
// Increment access counter.
Tools.getMonitoringTools().incrementCounter(POOL_ACCESS_COUNTER);
// Identify the right buffer pool according to the requested buffer size.
int lPoolIndex = this.calculatePoolIndex(pMinimumBufferSize);
// It might happen that for a certain buffer size there is no pool.
PoolableByteBuffer lBuffer;
if (lPoolIndex < pools.size()) {
// Lookup matching pool and request buffer.
try {
Pool lPool = pools.get(lPoolIndex);
lBuffer = lPool.claim(TIMEOUT);
// Pool seems to be overloaded.
if (lBuffer == null) {
Tools.getMonitoringTools().incrementCounter(POOL_OVERLOADED_COUNTER);
XFun.getTrace().warn(ProxyMessages.BYTE_BUFFER_POOL_OVERLOADED);
lBuffer = this.createUnpooledBuffer(pMinimumBufferSize);
}
}
// Unable to claim object from pool due to technical problems.
catch (InterruptedException | PoolException e) {
Tools.getMonitoringTools().incrementCounter(POOL_ERROR_COUNTER);
XFun.getTrace().error(ProxyMessages.BYTE_BUFFER_POOL_EXCEPTION, e);
lBuffer = this.createUnpooledBuffer(pMinimumBufferSize);
if (e instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
}
}
// Requested buffer is too big to be pooled.
else {
Tools.getMonitoringTools().incrementCounter(TOO_BIG_TO_POOL_COUNTER);
lBuffer = this.createUnpooledBuffer(pMinimumBufferSize);
}
return lBuffer;
}
/**
* Method creates a new unpooled byte buffer
*
* @param pMinimumBufferSize Minimum size of the requested byte buffer.
* @return {@link PoolableByteBuffer} Created byte buffer. The method never returns null.
*/
private PoolableByteBuffer createUnpooledBuffer( int pMinimumBufferSize ) {
return new PoolableByteBuffer(pMinimumBufferSize, null);
}
/**
* Method returns the size of the pools.
*
* @return int Pool size.
*/
public int getPoolCount( ) {
return pools.size();
}
/**
* Method calculates the pool index for the passed buffer size.
*
* @param pBufferSize Minimum size of the requested buffer.
* @return int Calculated index for the matching pool.
*/
public int calculatePoolIndex( int pBufferSize ) {
return Math.max(this.calculateExponent(pBufferSize) - exponentOffset, 0);
}
/**
* Method calculates the exponent based on power of 2 for the passed value.
*
* @param pValue Value for which the exponent should be calculated.
* @return int Calculated exponent.
*/
public int calculateExponent( int pValue ) {
// Shift by one and see if we reached 0.
pValue = Math.max(0, pValue - 1);
int i = 0;
while (pValue != 0) {
pValue = pValue >> 1;
i++;
}
return i;
}
}