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

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;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy