2012-12-05 22:11:48 +01:00
|
|
|
|
/*
|
|
|
|
|
* Copyright 2012 The Netty Project
|
|
|
|
|
*
|
|
|
|
|
* The Netty Project licenses this file to you 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 io.netty.buffer;
|
|
|
|
|
|
2013-01-11 06:03:27 +01:00
|
|
|
|
import io.netty.util.internal.PlatformDependent;
|
2012-12-05 22:11:48 +01:00
|
|
|
|
import io.netty.util.internal.StringUtil;
|
|
|
|
|
|
|
|
|
|
import java.nio.ByteBuffer;
|
2015-05-13 17:15:06 +02:00
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.List;
|
2016-03-14 17:25:43 +01:00
|
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
2019-01-22 13:53:28 +01:00
|
|
|
|
import java.util.concurrent.atomic.LongAdder;
|
2012-12-05 22:11:48 +01:00
|
|
|
|
|
2019-01-31 09:06:59 +01:00
|
|
|
|
import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
|
2016-04-08 11:56:32 +02:00
|
|
|
|
import static java.lang.Math.max;
|
|
|
|
|
|
2015-05-13 17:15:06 +02:00
|
|
|
|
abstract class PoolArena<T> implements PoolArenaMetric {
|
2015-10-09 21:03:03 +02:00
|
|
|
|
static final boolean HAS_UNSAFE = PlatformDependent.hasUnsafe();
|
2012-12-05 22:11:48 +01:00
|
|
|
|
|
2015-05-25 21:00:24 +02:00
|
|
|
|
enum SizeClass {
|
|
|
|
|
Tiny,
|
|
|
|
|
Small,
|
|
|
|
|
Normal
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-01 15:47:03 +01:00
|
|
|
|
static final int numTinySubpagePools = 512 >>> 4;
|
|
|
|
|
|
2012-12-05 22:11:48 +01:00
|
|
|
|
final PooledByteBufAllocator parent;
|
|
|
|
|
|
|
|
|
|
private final int maxOrder;
|
2014-03-01 15:47:03 +01:00
|
|
|
|
final int pageSize;
|
|
|
|
|
final int pageShifts;
|
|
|
|
|
final int chunkSize;
|
|
|
|
|
final int subpageOverflowMask;
|
|
|
|
|
final int numSmallSubpagePools;
|
2017-01-29 22:26:40 +01:00
|
|
|
|
final int directMemoryCacheAlignment;
|
|
|
|
|
final int directMemoryCacheAlignmentMask;
|
2013-03-05 15:55:41 +01:00
|
|
|
|
private final PoolSubpage<T>[] tinySubpagePools;
|
|
|
|
|
private final PoolSubpage<T>[] smallSubpagePools;
|
2012-12-05 22:11:48 +01:00
|
|
|
|
|
|
|
|
|
private final PoolChunkList<T> q050;
|
|
|
|
|
private final PoolChunkList<T> q025;
|
|
|
|
|
private final PoolChunkList<T> q000;
|
|
|
|
|
private final PoolChunkList<T> qInit;
|
|
|
|
|
private final PoolChunkList<T> q075;
|
|
|
|
|
private final PoolChunkList<T> q100;
|
|
|
|
|
|
2015-05-13 17:15:06 +02:00
|
|
|
|
private final List<PoolChunkListMetric> chunkListMetrics;
|
|
|
|
|
|
|
|
|
|
// Metrics for allocations and deallocations
|
|
|
|
|
private long allocationsNormal;
|
2019-01-22 13:53:28 +01:00
|
|
|
|
// We need to use the LongAdder here as this is not guarded via synchronized block.
|
|
|
|
|
private final LongAdder allocationsTiny = new LongAdder();
|
|
|
|
|
private final LongAdder allocationsSmall = new LongAdder();
|
|
|
|
|
private final LongAdder allocationsHuge = new LongAdder();
|
|
|
|
|
private final LongAdder activeBytesHuge = new LongAdder();
|
2015-05-13 17:15:06 +02:00
|
|
|
|
|
|
|
|
|
private long deallocationsTiny;
|
|
|
|
|
private long deallocationsSmall;
|
|
|
|
|
private long deallocationsNormal;
|
2016-03-14 09:00:50 +01:00
|
|
|
|
|
2019-01-22 13:53:28 +01:00
|
|
|
|
// We need to use the LongAdder here as this is not guarded via synchronized block.
|
|
|
|
|
private final LongAdder deallocationsHuge = new LongAdder();
|
2015-05-13 17:15:06 +02:00
|
|
|
|
|
2016-03-14 17:25:43 +01:00
|
|
|
|
// Number of thread caches backed by this arena.
|
|
|
|
|
final AtomicInteger numThreadCaches = new AtomicInteger();
|
|
|
|
|
|
2012-12-05 22:11:48 +01:00
|
|
|
|
// TODO: Test if adding padding helps under contention
|
|
|
|
|
//private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7;
|
|
|
|
|
|
2017-01-29 22:26:40 +01:00
|
|
|
|
protected PoolArena(PooledByteBufAllocator parent, int pageSize,
|
|
|
|
|
int maxOrder, int pageShifts, int chunkSize, int cacheAlignment) {
|
2012-12-05 22:11:48 +01:00
|
|
|
|
this.parent = parent;
|
|
|
|
|
this.pageSize = pageSize;
|
|
|
|
|
this.maxOrder = maxOrder;
|
|
|
|
|
this.pageShifts = pageShifts;
|
|
|
|
|
this.chunkSize = chunkSize;
|
2017-02-27 21:09:07 +01:00
|
|
|
|
directMemoryCacheAlignment = cacheAlignment;
|
|
|
|
|
directMemoryCacheAlignmentMask = cacheAlignment - 1;
|
2012-12-05 22:11:48 +01:00
|
|
|
|
subpageOverflowMask = ~(pageSize - 1);
|
2014-03-01 15:47:03 +01:00
|
|
|
|
tinySubpagePools = newSubpagePoolArray(numTinySubpagePools);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
for (int i = 0; i < tinySubpagePools.length; i ++) {
|
2013-03-05 15:55:41 +01:00
|
|
|
|
tinySubpagePools[i] = newSubpagePoolHead(pageSize);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-01 15:47:03 +01:00
|
|
|
|
numSmallSubpagePools = pageShifts - 9;
|
|
|
|
|
smallSubpagePools = newSubpagePoolArray(numSmallSubpagePools);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
for (int i = 0; i < smallSubpagePools.length; i ++) {
|
2013-03-05 15:55:41 +01:00
|
|
|
|
smallSubpagePools[i] = newSubpagePoolHead(pageSize);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-22 13:53:28 +01:00
|
|
|
|
q100 = new PoolChunkList<>(this, null, 100, Integer.MAX_VALUE, chunkSize);
|
|
|
|
|
q075 = new PoolChunkList<>(this, q100, 75, 100, chunkSize);
|
|
|
|
|
q050 = new PoolChunkList<>(this, q075, 50, 100, chunkSize);
|
|
|
|
|
q025 = new PoolChunkList<>(this, q050, 25, 75, chunkSize);
|
|
|
|
|
q000 = new PoolChunkList<>(this, q025, 1, 50, chunkSize);
|
|
|
|
|
qInit = new PoolChunkList<>(this, q000, Integer.MIN_VALUE, 25, chunkSize);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
|
2015-05-25 21:00:24 +02:00
|
|
|
|
q100.prevList(q075);
|
|
|
|
|
q075.prevList(q050);
|
|
|
|
|
q050.prevList(q025);
|
|
|
|
|
q025.prevList(q000);
|
|
|
|
|
q000.prevList(null);
|
|
|
|
|
qInit.prevList(qInit);
|
2015-05-13 17:15:06 +02:00
|
|
|
|
|
2019-01-22 13:53:28 +01:00
|
|
|
|
List<PoolChunkListMetric> metrics = new ArrayList<>(6);
|
2015-05-13 17:15:06 +02:00
|
|
|
|
metrics.add(qInit);
|
|
|
|
|
metrics.add(q000);
|
|
|
|
|
metrics.add(q025);
|
|
|
|
|
metrics.add(q050);
|
|
|
|
|
metrics.add(q075);
|
|
|
|
|
metrics.add(q100);
|
|
|
|
|
chunkListMetrics = Collections.unmodifiableList(metrics);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
2013-03-05 15:55:41 +01:00
|
|
|
|
private PoolSubpage<T> newSubpagePoolHead(int pageSize) {
|
2019-01-22 16:07:26 +01:00
|
|
|
|
PoolSubpage<T> head = new PoolSubpage<>(pageSize);
|
2013-03-05 15:55:41 +01:00
|
|
|
|
head.prev = head;
|
|
|
|
|
head.next = head;
|
|
|
|
|
return head;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-05 22:11:48 +01:00
|
|
|
|
@SuppressWarnings("unchecked")
|
2013-03-05 15:55:41 +01:00
|
|
|
|
private PoolSubpage<T>[] newSubpagePoolArray(int size) {
|
|
|
|
|
return new PoolSubpage[size];
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-01 15:47:03 +01:00
|
|
|
|
abstract boolean isDirect();
|
|
|
|
|
|
2012-12-19 08:48:53 +01:00
|
|
|
|
PooledByteBuf<T> allocate(PoolThreadCache cache, int reqCapacity, int maxCapacity) {
|
2012-12-05 22:11:48 +01:00
|
|
|
|
PooledByteBuf<T> buf = newByteBuf(maxCapacity);
|
2012-12-19 08:48:53 +01:00
|
|
|
|
allocate(cache, buf, reqCapacity);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-01 15:47:03 +01:00
|
|
|
|
static int tinyIdx(int normCapacity) {
|
|
|
|
|
return normCapacity >>> 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int smallIdx(int normCapacity) {
|
|
|
|
|
int tableIdx = 0;
|
|
|
|
|
int i = normCapacity >>> 10;
|
|
|
|
|
while (i != 0) {
|
|
|
|
|
i >>>= 1;
|
|
|
|
|
tableIdx ++;
|
|
|
|
|
}
|
|
|
|
|
return tableIdx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// capacity < pageSize
|
|
|
|
|
boolean isTinyOrSmall(int normCapacity) {
|
|
|
|
|
return (normCapacity & subpageOverflowMask) == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// normCapacity < 512
|
|
|
|
|
static boolean isTiny(int normCapacity) {
|
|
|
|
|
return (normCapacity & 0xFFFFFE00) == 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-19 08:48:53 +01:00
|
|
|
|
private void allocate(PoolThreadCache cache, PooledByteBuf<T> buf, final int reqCapacity) {
|
|
|
|
|
final int normCapacity = normalizeCapacity(reqCapacity);
|
2014-03-01 15:47:03 +01:00
|
|
|
|
if (isTinyOrSmall(normCapacity)) { // capacity < pageSize
|
2012-12-05 22:11:48 +01:00
|
|
|
|
int tableIdx;
|
2013-03-05 15:55:41 +01:00
|
|
|
|
PoolSubpage<T>[] table;
|
2015-05-13 17:15:06 +02:00
|
|
|
|
boolean tiny = isTiny(normCapacity);
|
|
|
|
|
if (tiny) { // < 512
|
2014-03-01 15:47:03 +01:00
|
|
|
|
if (cache.allocateTiny(this, buf, reqCapacity, normCapacity)) {
|
|
|
|
|
// was able to allocate out of the cache so move on
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
tableIdx = tinyIdx(normCapacity);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
table = tinySubpagePools;
|
|
|
|
|
} else {
|
2014-03-01 15:47:03 +01:00
|
|
|
|
if (cache.allocateSmall(this, buf, reqCapacity, normCapacity)) {
|
|
|
|
|
// was able to allocate out of the cache so move on
|
|
|
|
|
return;
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
2014-03-01 15:47:03 +01:00
|
|
|
|
tableIdx = smallIdx(normCapacity);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
table = smallSubpagePools;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-13 13:50:22 +02:00
|
|
|
|
final PoolSubpage<T> head = table[tableIdx];
|
2015-05-20 07:27:55 +02:00
|
|
|
|
|
|
|
|
|
/**
|
2015-10-22 22:09:41 +02:00
|
|
|
|
* Synchronize on the head. This is needed as {@link PoolChunk#allocateSubpage(int)} and
|
|
|
|
|
* {@link PoolChunk#free(long)} may modify the doubly linked list as well.
|
2015-05-20 07:27:55 +02:00
|
|
|
|
*/
|
|
|
|
|
synchronized (head) {
|
2013-03-05 15:55:41 +01:00
|
|
|
|
final PoolSubpage<T> s = head.next;
|
|
|
|
|
if (s != head) {
|
|
|
|
|
assert s.doNotDestroy && s.elemSize == normCapacity;
|
2012-12-05 22:11:48 +01:00
|
|
|
|
long handle = s.allocate();
|
2013-03-05 15:55:41 +01:00
|
|
|
|
assert handle >= 0;
|
2018-12-04 15:26:05 +01:00
|
|
|
|
s.chunk.initBufWithSubpage(buf, null, handle, reqCapacity);
|
2017-01-27 09:28:19 +01:00
|
|
|
|
incTinySmallAllocation(tiny);
|
2013-03-05 15:55:41 +01:00
|
|
|
|
return;
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-01-27 09:28:19 +01:00
|
|
|
|
synchronized (this) {
|
|
|
|
|
allocateNormal(buf, reqCapacity, normCapacity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
incTinySmallAllocation(tiny);
|
2015-05-20 07:27:55 +02:00
|
|
|
|
return;
|
2015-05-13 13:50:22 +02:00
|
|
|
|
}
|
|
|
|
|
if (normCapacity <= chunkSize) {
|
2014-03-01 15:47:03 +01:00
|
|
|
|
if (cache.allocateNormal(this, buf, reqCapacity, normCapacity)) {
|
|
|
|
|
// was able to allocate out of the cache so move on
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-01-27 09:28:19 +01:00
|
|
|
|
synchronized (this) {
|
|
|
|
|
allocateNormal(buf, reqCapacity, normCapacity);
|
|
|
|
|
++allocationsNormal;
|
|
|
|
|
}
|
2014-03-01 15:47:03 +01:00
|
|
|
|
} else {
|
|
|
|
|
// Huge allocations are never served via the cache so just call allocateHuge
|
2012-12-19 09:35:32 +01:00
|
|
|
|
allocateHuge(buf, reqCapacity);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-19 22:37:03 +02:00
|
|
|
|
// Method must be called inside synchronized(this) { ... }Â block
|
2017-01-27 09:28:19 +01:00
|
|
|
|
private void allocateNormal(PooledByteBuf<T> buf, int reqCapacity, int normCapacity) {
|
2012-12-19 08:48:53 +01:00
|
|
|
|
if (q050.allocate(buf, reqCapacity, normCapacity) || q025.allocate(buf, reqCapacity, normCapacity) ||
|
|
|
|
|
q000.allocate(buf, reqCapacity, normCapacity) || qInit.allocate(buf, reqCapacity, normCapacity) ||
|
2016-04-06 11:05:59 +02:00
|
|
|
|
q075.allocate(buf, reqCapacity, normCapacity)) {
|
2012-12-05 22:11:48 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add a new chunk.
|
|
|
|
|
PoolChunk<T> c = newChunk(pageSize, maxOrder, pageShifts, chunkSize);
|
2018-12-04 15:26:05 +01:00
|
|
|
|
boolean success = c.allocate(buf, reqCapacity, normCapacity);
|
|
|
|
|
assert success;
|
2012-12-05 22:11:48 +01:00
|
|
|
|
qInit.add(c);
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-27 09:28:19 +01:00
|
|
|
|
private void incTinySmallAllocation(boolean tiny) {
|
|
|
|
|
if (tiny) {
|
|
|
|
|
allocationsTiny.increment();
|
|
|
|
|
} else {
|
|
|
|
|
allocationsSmall.increment();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-19 09:35:32 +01:00
|
|
|
|
private void allocateHuge(PooledByteBuf<T> buf, int reqCapacity) {
|
2016-04-06 15:12:37 +02:00
|
|
|
|
PoolChunk<T> chunk = newUnpooledChunk(reqCapacity);
|
|
|
|
|
activeBytesHuge.add(chunk.chunkSize());
|
|
|
|
|
buf.initUnpooled(chunk, reqCapacity);
|
2016-04-05 11:46:25 +02:00
|
|
|
|
allocationsHuge.increment();
|
2012-12-19 09:35:32 +01:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-04 15:26:05 +01:00
|
|
|
|
void free(PoolChunk<T> chunk, ByteBuffer nioBuffer, long handle, int normCapacity, PoolThreadCache cache) {
|
2012-12-19 09:35:32 +01:00
|
|
|
|
if (chunk.unpooled) {
|
2016-04-06 15:12:37 +02:00
|
|
|
|
int size = chunk.chunkSize();
|
2012-12-19 09:35:32 +01:00
|
|
|
|
destroyChunk(chunk);
|
2016-04-06 15:12:37 +02:00
|
|
|
|
activeBytesHuge.add(-size);
|
2016-05-05 20:54:08 +02:00
|
|
|
|
deallocationsHuge.increment();
|
2012-12-19 09:35:32 +01:00
|
|
|
|
} else {
|
2015-05-25 21:00:24 +02:00
|
|
|
|
SizeClass sizeClass = sizeClass(normCapacity);
|
2018-12-04 15:26:05 +01:00
|
|
|
|
if (cache != null && cache.add(this, chunk, nioBuffer, handle, normCapacity, sizeClass)) {
|
2015-05-19 15:03:29 +02:00
|
|
|
|
// cached so not free it.
|
|
|
|
|
return;
|
2014-03-01 15:47:03 +01:00
|
|
|
|
}
|
2015-05-19 15:03:29 +02:00
|
|
|
|
|
2018-12-04 15:26:05 +01:00
|
|
|
|
freeChunk(chunk, handle, sizeClass, nioBuffer);
|
2015-05-25 21:00:24 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-09-02 07:15:58 +02:00
|
|
|
|
|
2015-05-25 21:00:24 +02:00
|
|
|
|
private SizeClass sizeClass(int normCapacity) {
|
|
|
|
|
if (!isTinyOrSmall(normCapacity)) {
|
|
|
|
|
return SizeClass.Normal;
|
|
|
|
|
}
|
|
|
|
|
return isTiny(normCapacity) ? SizeClass.Tiny : SizeClass.Small;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-04 15:26:05 +01:00
|
|
|
|
void freeChunk(PoolChunk<T> chunk, long handle, SizeClass sizeClass, ByteBuffer nioBuffer) {
|
2015-05-25 21:00:24 +02:00
|
|
|
|
final boolean destroyChunk;
|
|
|
|
|
synchronized (this) {
|
|
|
|
|
switch (sizeClass) {
|
|
|
|
|
case Normal:
|
|
|
|
|
++deallocationsNormal;
|
|
|
|
|
break;
|
|
|
|
|
case Small:
|
|
|
|
|
++deallocationsSmall;
|
|
|
|
|
break;
|
|
|
|
|
case Tiny:
|
|
|
|
|
++deallocationsTiny;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
throw new Error();
|
2013-11-30 19:48:40 +01:00
|
|
|
|
}
|
2018-12-04 15:26:05 +01:00
|
|
|
|
destroyChunk = !chunk.parent.free(chunk, handle, nioBuffer);
|
2015-05-25 21:00:24 +02:00
|
|
|
|
}
|
|
|
|
|
if (destroyChunk) {
|
|
|
|
|
// destroyChunk not need to be called while holding the synchronized lock.
|
|
|
|
|
destroyChunk(chunk);
|
2012-12-19 09:35:32 +01:00
|
|
|
|
}
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
2013-03-05 15:55:41 +01:00
|
|
|
|
PoolSubpage<T> findSubpagePoolHead(int elemSize) {
|
2012-12-05 22:11:48 +01:00
|
|
|
|
int tableIdx;
|
2013-03-05 15:55:41 +01:00
|
|
|
|
PoolSubpage<T>[] table;
|
2014-03-01 15:47:03 +01:00
|
|
|
|
if (isTiny(elemSize)) { // < 512
|
2012-12-05 22:11:48 +01:00
|
|
|
|
tableIdx = elemSize >>> 4;
|
|
|
|
|
table = tinySubpagePools;
|
|
|
|
|
} else {
|
|
|
|
|
tableIdx = 0;
|
|
|
|
|
elemSize >>>= 10;
|
|
|
|
|
while (elemSize != 0) {
|
|
|
|
|
elemSize >>>= 1;
|
|
|
|
|
tableIdx ++;
|
|
|
|
|
}
|
|
|
|
|
table = smallSubpagePools;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-05 15:55:41 +01:00
|
|
|
|
return table[tableIdx];
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-01 15:47:03 +01:00
|
|
|
|
int normalizeCapacity(int reqCapacity) {
|
2019-01-31 09:06:59 +01:00
|
|
|
|
checkPositiveOrZero(reqCapacity, "reqCapacity");
|
2017-01-29 22:26:40 +01:00
|
|
|
|
|
2012-12-19 09:35:32 +01:00
|
|
|
|
if (reqCapacity >= chunkSize) {
|
2017-01-29 22:26:40 +01:00
|
|
|
|
return directMemoryCacheAlignment == 0 ? reqCapacity : alignCapacity(reqCapacity);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-01 15:47:03 +01:00
|
|
|
|
if (!isTiny(reqCapacity)) { // >= 512
|
2012-12-05 22:11:48 +01:00
|
|
|
|
// Doubled
|
2013-06-20 11:38:11 +02:00
|
|
|
|
|
|
|
|
|
int normalizedCapacity = reqCapacity;
|
2014-04-14 22:57:24 +02:00
|
|
|
|
normalizedCapacity --;
|
2013-06-20 11:38:11 +02:00
|
|
|
|
normalizedCapacity |= normalizedCapacity >>> 1;
|
|
|
|
|
normalizedCapacity |= normalizedCapacity >>> 2;
|
|
|
|
|
normalizedCapacity |= normalizedCapacity >>> 4;
|
|
|
|
|
normalizedCapacity |= normalizedCapacity >>> 8;
|
|
|
|
|
normalizedCapacity |= normalizedCapacity >>> 16;
|
|
|
|
|
normalizedCapacity ++;
|
|
|
|
|
|
|
|
|
|
if (normalizedCapacity < 0) {
|
|
|
|
|
normalizedCapacity >>>= 1;
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
2017-01-29 22:26:40 +01:00
|
|
|
|
assert directMemoryCacheAlignment == 0 || (normalizedCapacity & directMemoryCacheAlignmentMask) == 0;
|
2013-06-20 11:38:11 +02:00
|
|
|
|
|
2012-12-05 22:11:48 +01:00
|
|
|
|
return normalizedCapacity;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-29 22:26:40 +01:00
|
|
|
|
if (directMemoryCacheAlignment > 0) {
|
|
|
|
|
return alignCapacity(reqCapacity);
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-05 22:11:48 +01:00
|
|
|
|
// Quantum-spaced
|
2012-12-19 08:48:53 +01:00
|
|
|
|
if ((reqCapacity & 15) == 0) {
|
|
|
|
|
return reqCapacity;
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-19 08:48:53 +01:00
|
|
|
|
return (reqCapacity & ~15) + 16;
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-01-29 22:26:40 +01:00
|
|
|
|
int alignCapacity(int reqCapacity) {
|
|
|
|
|
int delta = reqCapacity & directMemoryCacheAlignmentMask;
|
|
|
|
|
return delta == 0 ? reqCapacity : reqCapacity + directMemoryCacheAlignment - delta;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-05 22:11:48 +01:00
|
|
|
|
void reallocate(PooledByteBuf<T> buf, int newCapacity, boolean freeOldMemory) {
|
|
|
|
|
if (newCapacity < 0 || newCapacity > buf.maxCapacity()) {
|
|
|
|
|
throw new IllegalArgumentException("newCapacity: " + newCapacity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int oldCapacity = buf.length;
|
|
|
|
|
if (oldCapacity == newCapacity) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PoolChunk<T> oldChunk = buf.chunk;
|
2018-12-04 15:26:05 +01:00
|
|
|
|
ByteBuffer oldNioBuffer = buf.tmpNioBuf;
|
2012-12-05 22:11:48 +01:00
|
|
|
|
long oldHandle = buf.handle;
|
|
|
|
|
T oldMemory = buf.memory;
|
|
|
|
|
int oldOffset = buf.offset;
|
2014-03-01 15:47:03 +01:00
|
|
|
|
int oldMaxLength = buf.maxLength;
|
2012-12-05 22:11:48 +01:00
|
|
|
|
int readerIndex = buf.readerIndex();
|
|
|
|
|
int writerIndex = buf.writerIndex();
|
|
|
|
|
|
2015-05-25 21:00:24 +02:00
|
|
|
|
allocate(parent.threadCache(), buf, newCapacity);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
if (newCapacity > oldCapacity) {
|
|
|
|
|
memoryCopy(
|
2013-11-04 15:18:21 +01:00
|
|
|
|
oldMemory, oldOffset,
|
|
|
|
|
buf.memory, buf.offset, oldCapacity);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
} else if (newCapacity < oldCapacity) {
|
|
|
|
|
if (readerIndex < newCapacity) {
|
|
|
|
|
if (writerIndex > newCapacity) {
|
|
|
|
|
writerIndex = newCapacity;
|
|
|
|
|
}
|
|
|
|
|
memoryCopy(
|
|
|
|
|
oldMemory, oldOffset + readerIndex,
|
|
|
|
|
buf.memory, buf.offset + readerIndex, writerIndex - readerIndex);
|
|
|
|
|
} else {
|
|
|
|
|
readerIndex = writerIndex = newCapacity;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buf.setIndex(readerIndex, writerIndex);
|
|
|
|
|
|
|
|
|
|
if (freeOldMemory) {
|
2018-12-04 15:26:05 +01:00
|
|
|
|
free(oldChunk, oldNioBuffer, oldHandle, oldMaxLength, buf.cache);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-14 17:25:43 +01:00
|
|
|
|
@Override
|
|
|
|
|
public int numThreadCaches() {
|
|
|
|
|
return numThreadCaches.get();
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-13 17:15:06 +02:00
|
|
|
|
@Override
|
|
|
|
|
public int numTinySubpages() {
|
|
|
|
|
return tinySubpagePools.length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int numSmallSubpages() {
|
|
|
|
|
return smallSubpagePools.length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int numChunkLists() {
|
|
|
|
|
return chunkListMetrics.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public List<PoolSubpageMetric> tinySubpages() {
|
|
|
|
|
return subPageMetricList(tinySubpagePools);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public List<PoolSubpageMetric> smallSubpages() {
|
|
|
|
|
return subPageMetricList(smallSubpagePools);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public List<PoolChunkListMetric> chunkLists() {
|
|
|
|
|
return chunkListMetrics;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static List<PoolSubpageMetric> subPageMetricList(PoolSubpage<?>[] pages) {
|
2019-01-22 13:53:28 +01:00
|
|
|
|
List<PoolSubpageMetric> metrics = new ArrayList<>();
|
2017-02-04 00:08:46 +01:00
|
|
|
|
for (PoolSubpage<?> head : pages) {
|
2015-05-13 17:15:06 +02:00
|
|
|
|
if (head.next == head) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
PoolSubpage<?> s = head.next;
|
2019-01-23 14:01:48 +01:00
|
|
|
|
do {
|
2015-05-13 17:15:06 +02:00
|
|
|
|
metrics.add(s);
|
|
|
|
|
s = s.next;
|
2019-01-23 14:01:48 +01:00
|
|
|
|
} while (s != head);
|
2015-05-13 17:15:06 +02:00
|
|
|
|
}
|
|
|
|
|
return metrics;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public long numAllocations() {
|
2016-03-14 09:09:24 +01:00
|
|
|
|
final long allocsNormal;
|
|
|
|
|
synchronized (this) {
|
|
|
|
|
allocsNormal = allocationsNormal;
|
|
|
|
|
}
|
2019-01-22 13:53:28 +01:00
|
|
|
|
return allocationsTiny.longValue() + allocationsSmall.longValue() + allocsNormal + allocationsHuge.longValue();
|
2015-05-13 17:15:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public long numTinyAllocations() {
|
2019-01-22 13:53:28 +01:00
|
|
|
|
return allocationsTiny.longValue();
|
2015-05-13 17:15:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public long numSmallAllocations() {
|
2019-01-22 13:53:28 +01:00
|
|
|
|
return allocationsSmall.longValue();
|
2015-05-13 17:15:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2016-03-14 09:09:24 +01:00
|
|
|
|
public synchronized long numNormalAllocations() {
|
2015-05-13 17:15:06 +02:00
|
|
|
|
return allocationsNormal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public long numDeallocations() {
|
2016-03-14 09:09:24 +01:00
|
|
|
|
final long deallocs;
|
|
|
|
|
synchronized (this) {
|
2016-03-17 10:06:37 +01:00
|
|
|
|
deallocs = deallocationsTiny + deallocationsSmall + deallocationsNormal;
|
2016-03-14 09:09:24 +01:00
|
|
|
|
}
|
2019-01-22 13:53:28 +01:00
|
|
|
|
return deallocs + deallocationsHuge.longValue();
|
2015-05-13 17:15:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2016-03-14 09:09:24 +01:00
|
|
|
|
public synchronized long numTinyDeallocations() {
|
2015-05-13 17:15:06 +02:00
|
|
|
|
return deallocationsTiny;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2016-03-14 09:09:24 +01:00
|
|
|
|
public synchronized long numSmallDeallocations() {
|
2015-05-13 17:15:06 +02:00
|
|
|
|
return deallocationsSmall;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2016-03-14 09:09:24 +01:00
|
|
|
|
public synchronized long numNormalDeallocations() {
|
2015-05-13 17:15:06 +02:00
|
|
|
|
return deallocationsNormal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public long numHugeAllocations() {
|
2019-01-22 13:53:28 +01:00
|
|
|
|
return allocationsHuge.longValue();
|
2015-05-13 17:15:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public long numHugeDeallocations() {
|
2019-01-22 13:53:28 +01:00
|
|
|
|
return deallocationsHuge.longValue();
|
2015-05-13 17:15:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2016-03-14 09:09:24 +01:00
|
|
|
|
public long numActiveAllocations() {
|
2019-01-22 13:53:28 +01:00
|
|
|
|
long val = allocationsTiny.longValue() + allocationsSmall.longValue() + allocationsHuge.longValue()
|
|
|
|
|
- deallocationsHuge.longValue();
|
2016-03-14 09:09:24 +01:00
|
|
|
|
synchronized (this) {
|
2016-03-17 10:06:37 +01:00
|
|
|
|
val += allocationsNormal - (deallocationsTiny + deallocationsSmall + deallocationsNormal);
|
2016-03-14 09:09:24 +01:00
|
|
|
|
}
|
2016-04-08 11:56:32 +02:00
|
|
|
|
return max(val, 0);
|
2015-05-13 17:15:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public long numActiveTinyAllocations() {
|
2016-04-08 11:56:32 +02:00
|
|
|
|
return max(numTinyAllocations() - numTinyDeallocations(), 0);
|
2015-05-13 17:15:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public long numActiveSmallAllocations() {
|
2016-04-08 11:56:32 +02:00
|
|
|
|
return max(numSmallAllocations() - numSmallDeallocations(), 0);
|
2015-05-13 17:15:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public long numActiveNormalAllocations() {
|
2016-03-14 09:09:24 +01:00
|
|
|
|
final long val;
|
|
|
|
|
synchronized (this) {
|
|
|
|
|
val = allocationsNormal - deallocationsNormal;
|
|
|
|
|
}
|
2016-04-08 11:56:32 +02:00
|
|
|
|
return max(val, 0);
|
2015-05-13 17:15:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public long numActiveHugeAllocations() {
|
2016-04-08 11:56:32 +02:00
|
|
|
|
return max(numHugeAllocations() - numHugeDeallocations(), 0);
|
2015-05-13 17:15:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-04-06 15:12:37 +02:00
|
|
|
|
@Override
|
|
|
|
|
public long numActiveBytes() {
|
2019-01-22 13:53:28 +01:00
|
|
|
|
long val = activeBytesHuge.longValue();
|
2016-04-06 15:12:37 +02:00
|
|
|
|
synchronized (this) {
|
|
|
|
|
for (int i = 0; i < chunkListMetrics.size(); i++) {
|
|
|
|
|
for (PoolChunkMetric m: chunkListMetrics.get(i)) {
|
|
|
|
|
val += m.chunkSize();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return max(0, val);
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-05 22:11:48 +01:00
|
|
|
|
protected abstract PoolChunk<T> newChunk(int pageSize, int maxOrder, int pageShifts, int chunkSize);
|
2012-12-19 09:35:32 +01:00
|
|
|
|
protected abstract PoolChunk<T> newUnpooledChunk(int capacity);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
protected abstract PooledByteBuf<T> newByteBuf(int maxCapacity);
|
|
|
|
|
protected abstract void memoryCopy(T src, int srcOffset, T dst, int dstOffset, int length);
|
|
|
|
|
protected abstract void destroyChunk(PoolChunk<T> chunk);
|
|
|
|
|
|
2015-05-13 17:15:06 +02:00
|
|
|
|
@Override
|
2012-12-05 22:11:48 +01:00
|
|
|
|
public synchronized String toString() {
|
2014-11-08 23:46:30 +01:00
|
|
|
|
StringBuilder buf = new StringBuilder()
|
|
|
|
|
.append("Chunk(s) at 0~25%:")
|
|
|
|
|
.append(StringUtil.NEWLINE)
|
|
|
|
|
.append(qInit)
|
|
|
|
|
.append(StringUtil.NEWLINE)
|
|
|
|
|
.append("Chunk(s) at 0~50%:")
|
|
|
|
|
.append(StringUtil.NEWLINE)
|
|
|
|
|
.append(q000)
|
|
|
|
|
.append(StringUtil.NEWLINE)
|
|
|
|
|
.append("Chunk(s) at 25~75%:")
|
|
|
|
|
.append(StringUtil.NEWLINE)
|
|
|
|
|
.append(q025)
|
|
|
|
|
.append(StringUtil.NEWLINE)
|
|
|
|
|
.append("Chunk(s) at 50~100%:")
|
|
|
|
|
.append(StringUtil.NEWLINE)
|
|
|
|
|
.append(q050)
|
|
|
|
|
.append(StringUtil.NEWLINE)
|
|
|
|
|
.append("Chunk(s) at 75~100%:")
|
|
|
|
|
.append(StringUtil.NEWLINE)
|
|
|
|
|
.append(q075)
|
|
|
|
|
.append(StringUtil.NEWLINE)
|
|
|
|
|
.append("Chunk(s) at 100%:")
|
|
|
|
|
.append(StringUtil.NEWLINE)
|
|
|
|
|
.append(q100)
|
|
|
|
|
.append(StringUtil.NEWLINE)
|
|
|
|
|
.append("tiny subpages:");
|
2016-07-10 12:54:30 +02:00
|
|
|
|
appendPoolSubPages(buf, tinySubpagePools);
|
2014-11-08 23:46:30 +01:00
|
|
|
|
buf.append(StringUtil.NEWLINE)
|
|
|
|
|
.append("small subpages:");
|
2016-07-10 12:54:30 +02:00
|
|
|
|
appendPoolSubPages(buf, smallSubpagePools);
|
|
|
|
|
buf.append(StringUtil.NEWLINE);
|
|
|
|
|
|
|
|
|
|
return buf.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void appendPoolSubPages(StringBuilder buf, PoolSubpage<?>[] subpages) {
|
|
|
|
|
for (int i = 0; i < subpages.length; i ++) {
|
|
|
|
|
PoolSubpage<?> head = subpages[i];
|
2013-03-05 15:55:41 +01:00
|
|
|
|
if (head.next == head) {
|
2012-12-05 22:11:48 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-08 23:46:30 +01:00
|
|
|
|
buf.append(StringUtil.NEWLINE)
|
2016-07-10 12:54:30 +02:00
|
|
|
|
.append(i)
|
|
|
|
|
.append(": ");
|
|
|
|
|
PoolSubpage<?> s = head.next;
|
2019-01-23 14:01:48 +01:00
|
|
|
|
do {
|
2013-03-05 15:55:41 +01:00
|
|
|
|
buf.append(s);
|
|
|
|
|
s = s.next;
|
2019-01-23 14:01:48 +01:00
|
|
|
|
} while (s != head);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-17 04:43:51 +02:00
|
|
|
|
@Override
|
|
|
|
|
protected final void finalize() throws Throwable {
|
|
|
|
|
try {
|
|
|
|
|
super.finalize();
|
|
|
|
|
} finally {
|
|
|
|
|
destroyPoolSubPages(smallSubpagePools);
|
|
|
|
|
destroyPoolSubPages(tinySubpagePools);
|
|
|
|
|
destroyPoolChunkLists(qInit, q000, q025, q050, q075, q100);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void destroyPoolSubPages(PoolSubpage<?>[] pages) {
|
|
|
|
|
for (PoolSubpage<?> page : pages) {
|
|
|
|
|
page.destroy();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void destroyPoolChunkLists(PoolChunkList<T>... chunkLists) {
|
|
|
|
|
for (PoolChunkList<T> chunkList: chunkLists) {
|
|
|
|
|
chunkList.destroy(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-05 22:11:48 +01:00
|
|
|
|
static final class HeapArena extends PoolArena<byte[]> {
|
|
|
|
|
|
2017-01-29 22:26:40 +01:00
|
|
|
|
HeapArena(PooledByteBufAllocator parent, int pageSize, int maxOrder,
|
|
|
|
|
int pageShifts, int chunkSize, int directMemoryCacheAlignment) {
|
|
|
|
|
super(parent, pageSize, maxOrder, pageShifts, chunkSize,
|
|
|
|
|
directMemoryCacheAlignment);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-03-26 04:06:31 +02:00
|
|
|
|
private static byte[] newByteArray(int size) {
|
|
|
|
|
return PlatformDependent.allocateUninitializedArray(size);
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-01 15:47:03 +01:00
|
|
|
|
@Override
|
|
|
|
|
boolean isDirect() {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-05 22:11:48 +01:00
|
|
|
|
@Override
|
|
|
|
|
protected PoolChunk<byte[]> newChunk(int pageSize, int maxOrder, int pageShifts, int chunkSize) {
|
2019-01-22 13:53:28 +01:00
|
|
|
|
return new PoolChunk<>(this, newByteArray(chunkSize), pageSize, maxOrder, pageShifts, chunkSize, 0);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-19 09:35:32 +01:00
|
|
|
|
@Override
|
|
|
|
|
protected PoolChunk<byte[]> newUnpooledChunk(int capacity) {
|
2019-01-22 13:53:28 +01:00
|
|
|
|
return new PoolChunk<>(this, newByteArray(capacity), capacity, 0);
|
2012-12-19 09:35:32 +01:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-05 22:11:48 +01:00
|
|
|
|
@Override
|
|
|
|
|
protected void destroyChunk(PoolChunk<byte[]> chunk) {
|
|
|
|
|
// Rely on GC.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected PooledByteBuf<byte[]> newByteBuf(int maxCapacity) {
|
2015-10-09 21:03:03 +02:00
|
|
|
|
return HAS_UNSAFE ? PooledUnsafeHeapByteBuf.newUnsafeInstance(maxCapacity)
|
|
|
|
|
: PooledHeapByteBuf.newInstance(maxCapacity);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected void memoryCopy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int length) {
|
|
|
|
|
if (length == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
System.arraycopy(src, srcOffset, dst, dstOffset, length);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static final class DirectArena extends PoolArena<ByteBuffer> {
|
|
|
|
|
|
2017-01-29 22:26:40 +01:00
|
|
|
|
DirectArena(PooledByteBufAllocator parent, int pageSize, int maxOrder,
|
|
|
|
|
int pageShifts, int chunkSize, int directMemoryCacheAlignment) {
|
|
|
|
|
super(parent, pageSize, maxOrder, pageShifts, chunkSize,
|
|
|
|
|
directMemoryCacheAlignment);
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-01 15:47:03 +01:00
|
|
|
|
@Override
|
|
|
|
|
boolean isDirect() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-27 11:47:34 +01:00
|
|
|
|
// mark as package-private, only for unit test
|
|
|
|
|
int offsetCacheLine(ByteBuffer memory) {
|
2017-02-13 07:42:22 +01:00
|
|
|
|
// We can only calculate the offset if Unsafe is present as otherwise directBufferAddress(...) will
|
|
|
|
|
// throw an NPE.
|
2018-11-27 11:47:34 +01:00
|
|
|
|
int remainder = HAS_UNSAFE
|
|
|
|
|
? (int) (PlatformDependent.directBufferAddress(memory) & directMemoryCacheAlignmentMask)
|
|
|
|
|
: 0;
|
|
|
|
|
|
|
|
|
|
// offset = alignment - address & (alignment - 1)
|
|
|
|
|
return directMemoryCacheAlignment - remainder;
|
2017-01-29 22:26:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-05 22:11:48 +01:00
|
|
|
|
@Override
|
2017-01-29 22:26:40 +01:00
|
|
|
|
protected PoolChunk<ByteBuffer> newChunk(int pageSize, int maxOrder,
|
|
|
|
|
int pageShifts, int chunkSize) {
|
|
|
|
|
if (directMemoryCacheAlignment == 0) {
|
2019-01-22 13:53:28 +01:00
|
|
|
|
return new PoolChunk<>(this,
|
2017-01-29 22:26:40 +01:00
|
|
|
|
allocateDirect(chunkSize), pageSize, maxOrder,
|
|
|
|
|
pageShifts, chunkSize, 0);
|
|
|
|
|
}
|
|
|
|
|
final ByteBuffer memory = allocateDirect(chunkSize
|
|
|
|
|
+ directMemoryCacheAlignment);
|
2019-01-22 13:53:28 +01:00
|
|
|
|
return new PoolChunk<>(this, memory, pageSize,
|
2017-01-29 22:26:40 +01:00
|
|
|
|
maxOrder, pageShifts, chunkSize,
|
|
|
|
|
offsetCacheLine(memory));
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-19 09:35:32 +01:00
|
|
|
|
@Override
|
|
|
|
|
protected PoolChunk<ByteBuffer> newUnpooledChunk(int capacity) {
|
2017-01-29 22:26:40 +01:00
|
|
|
|
if (directMemoryCacheAlignment == 0) {
|
2019-01-22 13:53:28 +01:00
|
|
|
|
return new PoolChunk<>(this,
|
2017-01-29 22:26:40 +01:00
|
|
|
|
allocateDirect(capacity), capacity, 0);
|
|
|
|
|
}
|
|
|
|
|
final ByteBuffer memory = allocateDirect(capacity
|
|
|
|
|
+ directMemoryCacheAlignment);
|
2019-01-22 13:53:28 +01:00
|
|
|
|
return new PoolChunk<>(this, memory, capacity,
|
2017-01-29 22:26:40 +01:00
|
|
|
|
offsetCacheLine(memory));
|
2016-05-23 11:59:55 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static ByteBuffer allocateDirect(int capacity) {
|
|
|
|
|
return PlatformDependent.useDirectBufferNoCleaner() ?
|
|
|
|
|
PlatformDependent.allocateDirectNoCleaner(capacity) : ByteBuffer.allocateDirect(capacity);
|
2012-12-19 09:35:32 +01:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-05 22:11:48 +01:00
|
|
|
|
@Override
|
|
|
|
|
protected void destroyChunk(PoolChunk<ByteBuffer> chunk) {
|
2016-05-23 11:59:55 +02:00
|
|
|
|
if (PlatformDependent.useDirectBufferNoCleaner()) {
|
|
|
|
|
PlatformDependent.freeDirectNoCleaner(chunk.memory);
|
|
|
|
|
} else {
|
|
|
|
|
PlatformDependent.freeDirectBuffer(chunk.memory);
|
|
|
|
|
}
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected PooledByteBuf<ByteBuffer> newByteBuf(int maxCapacity) {
|
2013-03-05 07:25:25 +01:00
|
|
|
|
if (HAS_UNSAFE) {
|
2013-06-10 12:52:56 +02:00
|
|
|
|
return PooledUnsafeDirectByteBuf.newInstance(maxCapacity);
|
2013-01-10 10:27:16 +01:00
|
|
|
|
} else {
|
2013-06-10 12:52:56 +02:00
|
|
|
|
return PooledDirectByteBuf.newInstance(maxCapacity);
|
2013-01-10 10:27:16 +01:00
|
|
|
|
}
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected void memoryCopy(ByteBuffer src, int srcOffset, ByteBuffer dst, int dstOffset, int length) {
|
|
|
|
|
if (length == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-05 07:25:25 +01:00
|
|
|
|
if (HAS_UNSAFE) {
|
2013-01-10 10:27:16 +01:00
|
|
|
|
PlatformDependent.copyMemory(
|
|
|
|
|
PlatformDependent.directBufferAddress(src) + srcOffset,
|
|
|
|
|
PlatformDependent.directBufferAddress(dst) + dstOffset, length);
|
|
|
|
|
} else {
|
|
|
|
|
// We must duplicate the NIO buffers because they may be accessed by other Netty buffers.
|
|
|
|
|
src = src.duplicate();
|
|
|
|
|
dst = dst.duplicate();
|
|
|
|
|
src.position(srcOffset).limit(srcOffset + length);
|
|
|
|
|
dst.position(dstOffset);
|
|
|
|
|
dst.put(src);
|
|
|
|
|
}
|
2012-12-05 22:11:48 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|