/*
* Copyright 2012-2015 org.opencloudb.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.opencloudb.buffer;
import java.nio.ByteBuffer;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author mycat
*/
public final class BufferPool {
private final int chunkSize;
private final ByteBuffer[] items;
private final ReentrantLock lock;
private int putIndex;
private int takeIndex;
private int count;
private volatile int newCount;
public BufferPool(int bufferSize, int chunkSize) {
this.chunkSize = chunkSize;
int capacity = bufferSize / chunkSize;
capacity = (bufferSize % chunkSize == 0) ? capacity : capacity + 1;
this.items = new ByteBuffer[capacity];
this.lock = new ReentrantLock();
for (int i = 0; i < capacity; i++) {
insert(create(chunkSize));
}
}
public int capacity() {
return items.length;
}
public int size() {
return count;
}
public int getNewCount() {
return newCount;
}
public ByteBuffer allocate() {
ByteBuffer node = null;
final ReentrantLock lock = this.lock;
lock.lock();
try {
node = (count == 0) ? null : extract();
} finally {
lock.unlock();
}
if (node == null) {
++newCount;
return create(chunkSize);
} else {
return node;
}
}
public void recycle(ByteBuffer buffer) {
// 拒绝回收null和容量大于chunkSize的缓存
if (buffer == null || buffer.capacity() > chunkSize) {
return;
}
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count != items.length) {
buffer.clear();
insert(buffer);
}
} finally {
lock.unlock();
}
}
private void insert(ByteBuffer buffer) {
items[putIndex] = buffer;
putIndex = inc(putIndex);
++count;
}
private ByteBuffer extract() {
final ByteBuffer[] items = this.items;
ByteBuffer item = items[takeIndex];
items[takeIndex] = null;
takeIndex = inc(takeIndex);
--count;
return item;
}
private int inc(int i) {
return (++i == items.length) ? 0 : i;
}
private ByteBuffer create(int size) {
// for performance
return ByteBuffer.allocateDirect(size);
// return ByteBuffer.allocate(size);
}
}