/**
*Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)]
*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
*/
/**
*Copyright [2009-2010] [dennis zhuang(killme2008@gmail.com)]
*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 net.rubyeye.xmemcached.buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import net.rubyeye.xmemcached.utils.ByteUtils;
import com.google.code.yanf4j.util.CircularQueue;
/**
* Cached IoBuffer allocator,cached buffer in ThreadLocal.
*
* @author dennis
*
*/
@Deprecated
public class CachedBufferAllocator implements BufferAllocator {
private static final int DEFAULT_MAX_POOL_SIZE = 8;
private static final int DEFAULT_MAX_CACHED_BUFFER_SIZE = 1 << 18; // 256KB
private final int maxPoolSize;
private final int maxCachedBufferSize;
private final ThreadLocal<Map<Integer, Queue<CachedIoBuffer>>> heapBuffers;
private final IoBuffer EMPTY_IO_BUFFER = new CachedBufferAllocator.CachedIoBuffer(
ByteBuffer.allocate(0));
/**
* Creates a new instance with the default parameters ({@literal
* #DEFAULT_MAX_POOL_SIZE} and {@literal #DEFAULT_MAX_CACHED_BUFFER_SIZE}).
*/
public CachedBufferAllocator() {
this(DEFAULT_MAX_POOL_SIZE, DEFAULT_MAX_CACHED_BUFFER_SIZE);
}
/**
* Creates a new instance.
*
* @param maxPoolSize
* the maximum number of buffers with the same capacity per
* thread. <tt>0</tt> disables this limitation.
* @param maxCachedBufferSize
* the maximum capacity of a cached buffer. A buffer whose
* capacity is bigger than this value is not pooled. <tt>0</tt>
* disables this limitation.
*/
public CachedBufferAllocator(int maxPoolSize, int maxCachedBufferSize) {
if (maxPoolSize < 0) {
throw new IllegalArgumentException("maxPoolSize: " + maxPoolSize);
}
if (maxCachedBufferSize < 0) {
throw new IllegalArgumentException("maxCachedBufferSize: "
+ maxCachedBufferSize);
}
this.maxPoolSize = maxPoolSize;
this.maxCachedBufferSize = maxCachedBufferSize;
this.heapBuffers = new ThreadLocal<Map<Integer, Queue<CachedIoBuffer>>>() {
@Override
protected Map<Integer, Queue<CachedIoBuffer>> initialValue() {
return newPoolMap();
}
};
}
public int getMaxPoolSize() {
return this.maxPoolSize;
}
public int getMaxCachedBufferSize() {
return this.maxCachedBufferSize;
}
/**
* 初始化缓冲池
*
* @return
*/
private Map<Integer, Queue<CachedIoBuffer>> newPoolMap() {
Map<Integer, Queue<CachedIoBuffer>> poolMap = new HashMap<Integer, Queue<CachedIoBuffer>>();
int poolSize = this.maxPoolSize == 0 ? DEFAULT_MAX_POOL_SIZE
: this.maxPoolSize;
for (int i = 0; i < 31; i++) {
poolMap.put(1 << i, new CircularQueue<CachedIoBuffer>(poolSize));
}
poolMap.put(0, new CircularQueue<CachedIoBuffer>(poolSize));
poolMap.put(Integer.MAX_VALUE, new CircularQueue<CachedIoBuffer>(
poolSize));
return poolMap;
}
public final IoBuffer allocate(int requestedCapacity) {
if (requestedCapacity == 0) {
return this.EMPTY_IO_BUFFER;
}
// 圆整requestedCapacity到2的x次方
int actualCapacity = ByteUtils.normalizeCapacity(requestedCapacity);
IoBuffer buf;
if (this.maxCachedBufferSize != 0
&& actualCapacity > this.maxCachedBufferSize) {
buf = wrap(ByteBuffer.allocate(actualCapacity));
} else {
Queue<CachedIoBuffer> pool;
pool = this.heapBuffers.get().get(actualCapacity);
// 从池中取
buf = pool.poll();
if (buf != null) {
buf.clear();
} else {
buf = wrap(ByteBuffer.allocate(actualCapacity));
}
}
buf.limit(requestedCapacity);
return buf;
}
public final IoBuffer wrap(ByteBuffer nioBuffer) {
return new CachedIoBuffer(nioBuffer);
}
public void dispose() {
this.heapBuffers.remove();
}
public static BufferAllocator newInstance() {
return new CachedBufferAllocator();
}
public static BufferAllocator newInstance(int maxPoolSize,
int maxCachedBufferSize) {
return new CachedBufferAllocator(maxPoolSize, maxCachedBufferSize);
}
public class CachedIoBuffer implements IoBuffer {
Thread ownerThread; // 所分配的线程
ByteBuffer origBuffer;
public CachedIoBuffer(ByteBuffer origBuffer) {
super();
this.ownerThread = Thread.currentThread();
this.origBuffer = origBuffer;
}
public void putInt(int i) {
this.origBuffer.putInt(i);
}
public void putShort(short s) {
this.origBuffer.putShort(s);
}
public ByteOrder order() {
return this.origBuffer.order();
}
public boolean isDirect() {
return this.origBuffer.isDirect();
}
public void order(ByteOrder byteOrder) {
this.origBuffer.order(byteOrder);
}
public void putLong(long l) {
this.origBuffer.putLong(l);
}
public final void free() {
if (this.origBuffer == null
|| this.origBuffer.capacity() > CachedBufferAllocator.this.maxCachedBufferSize
|| Thread.currentThread() != this.ownerThread) {
return;
}
// Add to the cache.
Queue<CachedIoBuffer> pool;
pool = CachedBufferAllocator.this.heapBuffers.get().get(
this.origBuffer.capacity());
if (pool == null) {
return;
}
// 防止OOM
if (CachedBufferAllocator.this.maxPoolSize == 0
|| pool.size() < CachedBufferAllocator.this.maxPoolSize) {
pool.offer(new CachedIoBuffer(this.origBuffer));
}
this.origBuffer = null;
}
public final ByteBuffer[] getByteBuffers() {
return new ByteBuffer[] { this.origBuffer };
}
public final void put(byte[] bytes) {
this.origBuffer.put(bytes);
}
public final int capacity() {
return this.origBuffer.capacity();
}
public final void clear() {
this.origBuffer.clear();
}
public final void reset() {
this.origBuffer.reset();
}
public final int remaining() {
return this.origBuffer.remaining();
}
public final int position() {
return this.origBuffer.position();
}
public final void mark() {
this.origBuffer.mark();
}
public final int limit() {
return this.origBuffer.limit();
}
public final boolean hasRemaining() {
return this.origBuffer.hasRemaining();
}
public final void flip() {
this.origBuffer.flip();
}
public final void put(byte b) {
this.origBuffer.put(b);
}
public final void put(ByteBuffer buff) {
this.origBuffer.put(buff);
}
public final ByteBuffer getByteBuffer() {
return this.origBuffer;
}
public final void limit(int limit) {
this.origBuffer.limit(limit);
}
public final void position(int pos) {
this.origBuffer.position(pos);
}
}
}