// Path: src/main/java/com/bah/lucene/blockcache_v2/cachevalue/ByteArrayCacheValue.java
// @SuppressWarnings("serial")
// public class ByteArrayCacheValue extends BaseCacheValue {
// 
//   private final byte[] _buffer;
// 
//   public ByteArrayCacheValue(int length) {
//     super(length);
//     _buffer = new byte[length];
//   }
// 
//   @Override
//   protected void writeInternal(int position, byte[] buf, int offset, int length) {
//     System.arraycopy(buf, offset, _buffer, position, length);
//   }
// 
//   @Override
//   protected void readInternal(int position, byte[] buf, int offset, int length) {
//     System.arraycopy(_buffer, position, buf, offset, length);
//   }
// 
//   @Override
//   protected byte readInternal(int position) {
//     return _buffer[position];
//   }
// 
//   @Override
//   public void release() {
//     _released = true;
//   }
// 
//   @Override
//   public int size() {
//     return length();
//   }
// 
//   @Override
//   public CacheValue trim(int length) {
//     if (_buffer.length == length) {
//       return this;
//     }
//     ByteArrayCacheValue cacheValue = new ByteArrayCacheValue(length);
//     System.arraycopy(_buffer, 0, cacheValue._buffer, 0, length);
//     return cacheValue;
//   }
// }
// 
// Path: src/main/java/com/bah/lucene/blockcache_v2/cachevalue/UnsafeCacheValue.java
// @SuppressWarnings("serial")
// public class UnsafeCacheValue extends BaseCacheValue {
// 
//   private static final String JAVA_NIO_BITS = "java.nio.Bits";
//   private static final Unsafe _unsafe;
//   private static final AtomicLong _offHeapMemorySize = new AtomicLong();
// 
//   static {
//     try {
//       Class<?> clazz = Class.forName(JAVA_NIO_BITS);
//       Field field = clazz.getDeclaredField("unsafe");
//       field.setAccessible(true);
//       _unsafe = (Unsafe) field.get(null);
//     } catch (Exception e) {
//       throw new RuntimeException(e);
//     }
//   }
// 
//   private static final int BYTE_ARRAY_BASE_OFFSET = _unsafe.arrayBaseOffset(byte[].class);
// 
//   private static void copyFromArray(byte[] src, int srcOffset, int length, long destAddress) {
//     long offset = BYTE_ARRAY_BASE_OFFSET + srcOffset;
//     _unsafe.copyMemory(src, offset, null, destAddress, length);
//   }
// 
//   private static void copyToArray(long srcAddress, byte[] dst, int dstOffset, int length) {
//     long offset = BYTE_ARRAY_BASE_OFFSET + dstOffset;
//     _unsafe.copyMemory(null, srcAddress, dst, offset, length);
//   }
// 
//   private final long _address;
//   private final int _capacity;
// 
//   public UnsafeCacheValue(int length) {
//     super(length);
//     _capacity = length;
//     _address = _unsafe.allocateMemory(_capacity);
//     _offHeapMemorySize.addAndGet(_capacity);
//   }
// 
//   @Override
//   protected void writeInternal(int position, byte[] buf, int offset, int length) {
//     copyFromArray(buf, offset, length, resolveAddress(position));
//   }
// 
//   @Override
//   protected void readInternal(int position, byte[] buf, int offset, int length) {
//     copyToArray(resolveAddress(position), buf, offset, length);
//   }
// 
//   @Override
//   protected byte readInternal(int position) {
//     return _unsafe.getByte(resolveAddress(position));
//   }
// 
//   private long resolveAddress(int position) {
//     return _address + position;
//   }
// 
//   @Override
//   public void release() {
//     if (!_released) {
//       _unsafe.freeMemory(_address);
//       _released = true;
//       _offHeapMemorySize.addAndGet(0 - _capacity);
//     } else {
//       new Throwable().printStackTrace();
//     }
//   }
// 
//   @Override
//   public int size() {
//     return _capacity;
//   }
// 
//   @Override
//   public CacheValue trim(int length) {
//     if (length == _capacity) {
//       return this;
//     }
//     UnsafeCacheValue unsafeCacheValue = new UnsafeCacheValue(length);
//     _unsafe.copyMemory(_address, unsafeCacheValue._address, length);
//     release();
//     return unsafeCacheValue;
//   }
// }


import com.bah.lucene.blockcache_v2.cachevalue.ByteArrayCacheValue;
import com.bah.lucene.blockcache_v2.cachevalue.UnsafeCacheValue;
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import com.googlecode.concurrentlinkedhashmap.EvictionListener;
import com.googlecode.concurrentlinkedhashmap.Weigher;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.store.IOContext;
import java.io.Closeable;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

  private void addToReleaseQueue(CacheKey key, CacheValue value) {
    if (value != null) {
      if (value.refCount() == 0) {
        value.release();
        return;
      }
      long capacity = _cacheMap.capacity();
      _cacheMap.setCapacity(capacity - value.size());

      ReleaseEntry releaseEntry = new ReleaseEntry();
      releaseEntry._key = key;
      releaseEntry._value = value;

      LOG.debug(MessageFormat.format("CacheValue was not released [{0}]", releaseEntry));
      _releaseQueue.add(releaseEntry);
    }
  }

  @Override
  public boolean shouldBeQuiet(CacheDirectory directory, String fileName) {
    return _quiet.shouldBeQuiet(directory, fileName);
  }

  @Override
  public CacheValue newInstance(CacheDirectory directory, String fileName, int cacheBlockSize) {
    switch (_store) {
    case ON_HEAP:
      return new ByteArrayCacheValue(cacheBlockSize);
    case OFF_HEAP:
// Path: src/main/java/com/bah/lucene/blockcache_v2/cachevalue/ByteArrayCacheValue.java
// @SuppressWarnings("serial")
// public class ByteArrayCacheValue extends BaseCacheValue {
// 
//   private final byte[] _buffer;
// 
//   public ByteArrayCacheValue(int length) {
//     super(length);
//     _buffer = new byte[length];
//   }
// 
//   @Override
//   protected void writeInternal(int position, byte[] buf, int offset, int length) {
//     System.arraycopy(buf, offset, _buffer, position, length);
//   }
// 
//   @Override
//   protected void readInternal(int position, byte[] buf, int offset, int length) {
//     System.arraycopy(_buffer, position, buf, offset, length);
//   }
// 
//   @Override
//   protected byte readInternal(int position) {
//     return _buffer[position];
//   }
// 
//   @Override
//   public void release() {
//     _released = true;
//   }
// 
//   @Override
//   public int size() {
//     return length();
//   }
// 
//   @Override
//   public CacheValue trim(int length) {
//     if (_buffer.length == length) {
//       return this;
//     }
//     ByteArrayCacheValue cacheValue = new ByteArrayCacheValue(length);
//     System.arraycopy(_buffer, 0, cacheValue._buffer, 0, length);
//     return cacheValue;
//   }
// }
// 
// Path: src/main/java/com/bah/lucene/blockcache_v2/cachevalue/UnsafeCacheValue.java
// @SuppressWarnings("serial")
// public class UnsafeCacheValue extends BaseCacheValue {
// 
//   private static final String JAVA_NIO_BITS = "java.nio.Bits";
//   private static final Unsafe _unsafe;
//   private static final AtomicLong _offHeapMemorySize = new AtomicLong();
// 
//   static {
//     try {
//       Class<?> clazz = Class.forName(JAVA_NIO_BITS);
//       Field field = clazz.getDeclaredField("unsafe");
//       field.setAccessible(true);
//       _unsafe = (Unsafe) field.get(null);
//     } catch (Exception e) {
//       throw new RuntimeException(e);
//     }
//   }
// 
//   private static final int BYTE_ARRAY_BASE_OFFSET = _unsafe.arrayBaseOffset(byte[].class);
// 
//   private static void copyFromArray(byte[] src, int srcOffset, int length, long destAddress) {
//     long offset = BYTE_ARRAY_BASE_OFFSET + srcOffset;
//     _unsafe.copyMemory(src, offset, null, destAddress, length);
//   }
// 
//   private static void copyToArray(long srcAddress, byte[] dst, int dstOffset, int length) {
//     long offset = BYTE_ARRAY_BASE_OFFSET + dstOffset;
//     _unsafe.copyMemory(null, srcAddress, dst, offset, length);
//   }
// 
//   private final long _address;
//   private final int _capacity;
// 
//   public UnsafeCacheValue(int length) {
//     super(length);
//     _capacity = length;
//     _address = _unsafe.allocateMemory(_capacity);
//     _offHeapMemorySize.addAndGet(_capacity);
//   }
// 
//   @Override
//   protected void writeInternal(int position, byte[] buf, int offset, int length) {
//     copyFromArray(buf, offset, length, resolveAddress(position));
//   }
// 
//   @Override
//   protected void readInternal(int position, byte[] buf, int offset, int length) {
//     copyToArray(resolveAddress(position), buf, offset, length);
//   }
// 
//   @Override
//   protected byte readInternal(int position) {
//     return _unsafe.getByte(resolveAddress(position));
//   }
// 
//   private long resolveAddress(int position) {
//     return _address + position;
//   }
// 
//   @Override
//   public void release() {
//     if (!_released) {
//       _unsafe.freeMemory(_address);
//       _released = true;
//       _offHeapMemorySize.addAndGet(0 - _capacity);
//     } else {
//       new Throwable().printStackTrace();
//     }
//   }
// 
//   @Override
//   public int size() {
//     return _capacity;
//   }
// 
//   @Override
//   public CacheValue trim(int length) {
//     if (length == _capacity) {
//       return this;
//     }
//     UnsafeCacheValue unsafeCacheValue = new UnsafeCacheValue(length);
//     _unsafe.copyMemory(_address, unsafeCacheValue._address, length);
//     release();
//     return unsafeCacheValue;
//   }
// }


// Path: src/main/java/com/bah/lucene/blockcache_v2/BaseCache.java
import com.bah.lucene.blockcache_v2.cachevalue.ByteArrayCacheValue;
import com.bah.lucene.blockcache_v2.cachevalue.UnsafeCacheValue;
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import com.googlecode.concurrentlinkedhashmap.EvictionListener;
import com.googlecode.concurrentlinkedhashmap.Weigher;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.store.IOContext;
import java.io.Closeable;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;


  private void addToReleaseQueue(CacheKey key, CacheValue value) {
    if (value != null) {
      if (value.refCount() == 0) {
        value.release();
        return;
      }
      long capacity = _cacheMap.capacity();
      _cacheMap.setCapacity(capacity - value.size());

      ReleaseEntry releaseEntry = new ReleaseEntry();
      releaseEntry._key = key;
      releaseEntry._value = value;

      LOG.debug(MessageFormat.format("CacheValue was not released [{0}]", releaseEntry));
      _releaseQueue.add(releaseEntry);
    }
  }

  @Override
  public boolean shouldBeQuiet(CacheDirectory directory, String fileName) {
    return _quiet.shouldBeQuiet(directory, fileName);
  }

  @Override
  public CacheValue newInstance(CacheDirectory directory, String fileName, int cacheBlockSize) {
    switch (_store) {
    case ON_HEAP:
      return new ByteArrayCacheValue(cacheBlockSize);
    case OFF_HEAP:
      return new UnsafeCacheValue(cacheBlockSize);