/* * 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); } }