diff --git a/buffer/src/main/java/io/netty/buffer/PoolArena.java b/buffer/src/main/java/io/netty/buffer/PoolArena.java index 33c0843924..39ce7706b0 100644 --- a/buffer/src/main/java/io/netty/buffer/PoolArena.java +++ b/buffer/src/main/java/io/netty/buffer/PoolArena.java @@ -89,8 +89,8 @@ abstract class PoolArena implements PoolArenaMetric { this.maxOrder = maxOrder; this.pageShifts = pageShifts; this.chunkSize = chunkSize; - this.directMemoryCacheAlignment = cacheAlignment; - this.directMemoryCacheAlignmentMask = cacheAlignment - 1; + directMemoryCacheAlignment = cacheAlignment; + directMemoryCacheAlignmentMask = cacheAlignment - 1; subpageOverflowMask = ~(pageSize - 1); tinySubpagePools = newSubpagePoolArray(numTinySubpagePools); for (int i = 0; i < tinySubpagePools.length; i ++) { @@ -103,12 +103,12 @@ abstract class PoolArena implements PoolArenaMetric { smallSubpagePools[i] = newSubpagePoolHead(pageSize); } - q100 = new PoolChunkList(null, 100, Integer.MAX_VALUE, chunkSize); - q075 = new PoolChunkList(q100, 75, 100, chunkSize); - q050 = new PoolChunkList(q075, 50, 100, chunkSize); - q025 = new PoolChunkList(q050, 25, 75, chunkSize); - q000 = new PoolChunkList(q025, 1, 50, chunkSize); - qInit = new PoolChunkList(q000, Integer.MIN_VALUE, 25, chunkSize); + 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); q100.prevList(q075); q075.prevList(q050); diff --git a/buffer/src/main/java/io/netty/buffer/PoolChunk.java b/buffer/src/main/java/io/netty/buffer/PoolChunk.java index f107fdf8ac..b3ca160223 100644 --- a/buffer/src/main/java/io/netty/buffer/PoolChunk.java +++ b/buffer/src/main/java/io/netty/buffer/PoolChunk.java @@ -192,7 +192,14 @@ final class PoolChunk implements PoolChunkMetric { @Override public int usage() { - final int freeBytes = this.freeBytes; + final int freeBytes; + synchronized (arena) { + freeBytes = this.freeBytes; + } + return usage(freeBytes); + } + + private int usage(int freeBytes) { if (freeBytes == 0) { return 100; } @@ -447,22 +454,29 @@ final class PoolChunk implements PoolChunkMetric { @Override public int freeBytes() { - return freeBytes; + synchronized (arena) { + return freeBytes; + } } @Override public String toString() { + final int freeBytes; + synchronized (arena) { + freeBytes = this.freeBytes; + } + return new StringBuilder() - .append("Chunk(") - .append(Integer.toHexString(System.identityHashCode(this))) - .append(": ") - .append(usage()) - .append("%, ") - .append(chunkSize - freeBytes) - .append('/') - .append(chunkSize) - .append(')') - .toString(); + .append("Chunk(") + .append(Integer.toHexString(System.identityHashCode(this))) + .append(": ") + .append(usage(freeBytes)) + .append("%, ") + .append(chunkSize - freeBytes) + .append('/') + .append(chunkSize) + .append(')') + .toString(); } void destroy() { diff --git a/buffer/src/main/java/io/netty/buffer/PoolChunkList.java b/buffer/src/main/java/io/netty/buffer/PoolChunkList.java index 287c50d4ab..f92834d85c 100644 --- a/buffer/src/main/java/io/netty/buffer/PoolChunkList.java +++ b/buffer/src/main/java/io/netty/buffer/PoolChunkList.java @@ -27,6 +27,7 @@ import static java.lang.Math.*; final class PoolChunkList implements PoolChunkListMetric { private static final Iterator EMPTY_METRICS = Collections.emptyList().iterator(); + private final PoolArena arena; private final PoolChunkList nextList; private final int minUsage; private final int maxUsage; @@ -39,8 +40,9 @@ final class PoolChunkList implements PoolChunkListMetric { // TODO: Test if adding padding helps under contention //private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7; - PoolChunkList(PoolChunkList nextList, int minUsage, int maxUsage, int chunkSize) { + PoolChunkList(PoolArena arena, PoolChunkList nextList, int minUsage, int maxUsage, int chunkSize) { assert minUsage <= maxUsage; + this.arena = arena; this.nextList = nextList; this.minUsage = minUsage; this.maxUsage = maxUsage; @@ -190,36 +192,39 @@ final class PoolChunkList implements PoolChunkListMetric { @Override public Iterator iterator() { - if (head == null) { - return EMPTY_METRICS; - } - List metrics = new ArrayList(); - for (PoolChunk cur = head;;) { - metrics.add(cur); - cur = cur.next; - if (cur == null) { - break; + synchronized (arena) { + if (head == null) { + return EMPTY_METRICS; } + List metrics = new ArrayList(); + for (PoolChunk cur = head;;) { + metrics.add(cur); + cur = cur.next; + if (cur == null) { + break; + } + } + return metrics.iterator(); } - return metrics.iterator(); } @Override public String toString() { - if (head == null) { - return "none"; - } - StringBuilder buf = new StringBuilder(); - for (PoolChunk cur = head;;) { - buf.append(cur); - cur = cur.next; - if (cur == null) { - break; + synchronized (arena) { + if (head == null) { + return "none"; } - buf.append(StringUtil.NEWLINE); - } + for (PoolChunk cur = head;;) { + buf.append(cur); + cur = cur.next; + if (cur == null) { + break; + } + buf.append(StringUtil.NEWLINE); + } + } return buf.toString(); } diff --git a/buffer/src/main/java/io/netty/buffer/PoolSubpage.java b/buffer/src/main/java/io/netty/buffer/PoolSubpage.java index e78ef31099..f897eeeb48 100644 --- a/buffer/src/main/java/io/netty/buffer/PoolSubpage.java +++ b/buffer/src/main/java/io/netty/buffer/PoolSubpage.java @@ -200,27 +200,50 @@ final class PoolSubpage implements PoolSubpageMetric { @Override public String toString() { + final boolean doNotDestroy; + final int maxNumElems; + final int numAvail; + final int elemSize; + synchronized (chunk.arena) { + if (!this.doNotDestroy) { + doNotDestroy = false; + // Not used for creating the String. + maxNumElems = numAvail = elemSize = -1; + } else { + doNotDestroy = true; + maxNumElems = this.maxNumElems; + numAvail = this.numAvail; + elemSize = this.elemSize; + } + } + if (!doNotDestroy) { return "(" + memoryMapIdx + ": not in use)"; } - return String.valueOf('(') + memoryMapIdx + ": " + (maxNumElems - numAvail) + '/' + maxNumElems + - ", offset: " + runOffset + ", length: " + pageSize + ", elemSize: " + elemSize + ')'; + return "(" + memoryMapIdx + ": " + (maxNumElems - numAvail) + '/' + maxNumElems + + ", offset: " + runOffset + ", length: " + pageSize + ", elemSize: " + elemSize + ')'; } @Override public int maxNumElements() { - return maxNumElems; + synchronized (chunk.arena) { + return maxNumElems; + } } @Override public int numAvailable() { - return numAvail; + synchronized (chunk.arena) { + return numAvail; + } } @Override public int elementSize() { - return elemSize; + synchronized (chunk.arena) { + return elemSize; + } } @Override