package com.ctriposs.bigcache.storage;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
import sun.misc.Unsafe;
public class OffHeapStorage implements IStorage {
protected final AtomicBoolean disposed = new AtomicBoolean(false);
protected ByteBuffer byteBuffer;
private static final Unsafe UNSAFE = getUnsafe();
private static final long BYTE_ARRAY_OFFSET = (long) UNSAFE.arrayBaseOffset(byte[].class);
private final long address;
private static Unsafe getUnsafe() {
try {
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
return (sun.misc.Unsafe) unsafeField.get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public OffHeapStorage(int capacity) {
this.address = UNSAFE.allocateMemory(capacity);
}
public OffHeapStorage(int capacity, ByteBuffer buffer) {
this.byteBuffer = ByteBuffer.allocateDirect(capacity);
try {
Method method = byteBuffer.getClass().getDeclaredMethod("address");
method.setAccessible(true);
this.address = (Long) method.invoke(byteBuffer);
} catch (Exception e) {
throw new RuntimeException("Unable to allocate offheap memory using sun.misc.Unsafe on your platform", e);
}
}
@Override
public void close() throws IOException {
if (!disposed.compareAndSet(false, true))
return;
UNSAFE.freeMemory(address);
}
@Override
public void get(int position, byte[] dest) throws IOException {
assert !disposed.get() : "disposed";
assert position >= 0 : position;
this.get(address + position, dest, BYTE_ARRAY_OFFSET, dest.length);
}
/**
* Get bytes from the local buffer to a given byte array.
*
* @param baseAddress the absolute base address of the local buffer
* @param dest the dest byte array
* @param destOffset the offset of the dest byte array
* @param length the length of bytes to get
*/
private void get(long baseAddress, byte[] dest, long destOffset, long length) {
UNSAFE.copyMemory(null, baseAddress, dest, destOffset, length);
}
@Override
public void put(int position, byte[] source) throws IOException {
assert !disposed.get() : "disposed";
assert position >= 0 : position;
this.put(BYTE_ARRAY_OFFSET, source, address + position, source.length);
}
/**
* Put bytes from a given byte array to the local buffer.
*
* @param srcOffset the offset of the source byte array
* @param source the source byte array
* @param baseAddress the absolute base address of the local buffer
* @param length the length of bytes to put
*/
private void put(long srcOffset, byte[] source, long baseAddress, long length) {
UNSAFE.copyMemory(source, srcOffset, null, baseAddress, length);
}
@Override
public void free() {
//do nothing
}
}