package org.glassfish.grizzly.nio;
import java.lang.ref.SoftReference;
import java.nio.ByteBuffer;
import java.util.Arrays;
import org.glassfish.grizzly.ThreadCache;
import org.glassfish.grizzly.memory.Buffers;
public final class DirectByteBufferRecord {
private static final ThreadCache.CachedTypeIndex<DirectByteBufferRecord> CACHE_IDX = ThreadCache.obtainIndex("direct-buffer-cache",
DirectByteBufferRecord.class, 1);
public static DirectByteBufferRecord get() {
final DirectByteBufferRecord record = ThreadCache.getFromCache(CACHE_IDX);
if (record != null) {
return record;
}
final DirectByteBufferRecord recordLocal = new DirectByteBufferRecord();
ThreadCache.putToCache(CACHE_IDX, recordLocal);
return recordLocal;
}
private ByteBuffer directBuffer;
private int sliceOffset;
private ByteBuffer directBufferSlice;
private SoftReference<ByteBuffer> softRef;
private ByteBuffer array[];
private int arraySize;
DirectByteBufferRecord() {
array = new ByteBuffer[8];
}
public ByteBuffer getDirectBuffer() {
return directBuffer;
}
public ByteBuffer getDirectBufferSlice() {
return directBufferSlice;
}
public ByteBuffer allocate(final int size) {
ByteBuffer byteBuffer;
if ((byteBuffer = switchToStrong()) != null && byteBuffer.remaining() >= size) {
return byteBuffer;
} else {
byteBuffer = ByteBuffer.allocateDirect(size);
reset(byteBuffer);
return byteBuffer;
}
}
public ByteBuffer sliceBuffer() {
int oldLim = directBuffer.limit();
Buffers.setPositionLimit(directBuffer, sliceOffset, directBuffer.capacity());
directBufferSlice = directBuffer.slice();
Buffers.setPositionLimit(directBuffer, 0, oldLim);
return directBufferSlice;
}
public void finishBufferSlice() {
if (directBufferSlice != null) {
directBufferSlice.flip();
final int sliceSz = directBufferSlice.remaining();
sliceOffset += sliceSz;
if (sliceSz > 0) {
putToArray(directBufferSlice);
}
directBufferSlice = null;
}
}
public ByteBuffer[] getArray() {
return array;
}
public int getArraySize() {
return arraySize;
}
public void putToArray(ByteBuffer byteBuffer) {
ensureArraySize();
array[arraySize++] = byteBuffer;
}
public void release() {
if (directBuffer != null) {
directBuffer.clear();
switchToSoft();
}
Arrays.fill(array, 0, arraySize, null);
arraySize = 0;
directBufferSlice = null;
sliceOffset = 0;
}
private ByteBuffer switchToStrong() {
if (directBuffer == null && softRef != null) {
directBuffer = directBufferSlice = softRef.get();
}
return directBuffer;
}
private void switchToSoft() {
if (directBuffer != null && softRef == null) {
softRef = new SoftReference<>(directBuffer);
}
directBuffer = null;
}
private void reset(ByteBuffer byteBuffer) {
directBuffer = directBufferSlice = byteBuffer;
softRef = null;
}
private void ensureArraySize() {
if (arraySize == array.length) {
array = Arrays.copyOf(array, arraySize * 3 / 2 + 1);
}
}
}