diff --git a/buffer/src/main/java/io/netty/buffer/PoolChunk.java b/buffer/src/main/java/io/netty/buffer/PoolChunk.java index 9b6dd41f52..a22421a9f9 100644 --- a/buffer/src/main/java/io/netty/buffer/PoolChunk.java +++ b/buffer/src/main/java/io/netty/buffer/PoolChunk.java @@ -119,26 +119,62 @@ final class PoolChunk { } private long allocateRun(int normCapacity, int curIdx, int val) { - for (;;) { - if ((val & ST_ALLOCATED) != 0) { // state == ST_ALLOCATED || state == ST_ALLOCATED_SUBPAGE - return -1; - } - - if ((val & ST_BRANCH) != 0) { // state == ST_BRANCH - int nextIdx = curIdx << 1 ^ nextRandom(); - long res = allocateRun(normCapacity, nextIdx, memoryMap[nextIdx]); - if (res > 0) { - return res; + switch (val & 3) { + case ST_UNUSED: + return allocateRunSimple(normCapacity, curIdx, val); + case ST_BRANCH: + final int nextIdxLeft = curIdx << 1; + final int nextValLeft = memoryMap[nextIdxLeft]; + final boolean recurseLeft; + switch (nextValLeft & 3) { + case ST_UNUSED: + return allocateRunSimple(normCapacity, nextIdxLeft, nextValLeft); + case ST_BRANCH: + recurseLeft = true; + break; + default: + recurseLeft = false; } - curIdx = nextIdx ^ 1; - val = memoryMap[curIdx]; - continue; - } + final int nextIdxRight = nextIdxLeft ^ 1; + final int nextValRight = memoryMap[nextIdxRight]; + final boolean recurseRight; + switch (nextValRight & 3) { + case ST_UNUSED: + return allocateRunSimple(normCapacity, nextIdxRight, nextValRight); + case ST_BRANCH: + recurseRight = true; + break; + default: + recurseRight = false; + } - // state == ST_UNUSED - return allocateRunSimple(normCapacity, curIdx, val); + if (recurseLeft) { + long res = branchRun(normCapacity, nextIdxLeft); + if (res > 0) { + return res; + } + } + + if (recurseRight) { + return branchRun(normCapacity, nextIdxRight); + } } + + return -1; + } + + private long branchRun(int normCapacity, int nextIdx) { + int nextNextIdx = nextIdx << 1; + int nextNextVal = memoryMap[nextNextIdx]; + long res = allocateRun(normCapacity, nextNextIdx, nextNextVal); + if (res > 0) { + return res; + } + + nextNextIdx ^= 1; + nextNextVal = memoryMap[nextNextIdx]; + return allocateRun(normCapacity, nextNextIdx, nextNextVal); } private long allocateRunSimple(int normCapacity, int curIdx, int val) { diff --git a/buffer/src/main/java/io/netty/buffer/PoolSubpage.java b/buffer/src/main/java/io/netty/buffer/PoolSubpage.java index e915ab7f98..89cb680f6b 100644 --- a/buffer/src/main/java/io/netty/buffer/PoolSubpage.java +++ b/buffer/src/main/java/io/netty/buffer/PoolSubpage.java @@ -19,20 +19,20 @@ package io.netty.buffer; final class PoolSubpage { final PoolChunk chunk; - final int memoryMapIdx; - final int runOffset; - final int pageSize; - final long[] bitmap; + private final int memoryMapIdx; + private final int runOffset; + private final int pageSize; + private final long[] bitmap; PoolSubpage prev; PoolSubpage next; boolean doNotDestroy; int elemSize; - int maxNumElems; - int nextAvail; - int bitmapLength; - int numAvail; + private int maxNumElems; + private int bitmapLength; + private int nextAvail; + private int numAvail; // TODO: Test if adding padding helps under contention //private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7; @@ -87,7 +87,7 @@ final class PoolSubpage { return -1; } - final int bitmapIdx = nextAvail; + final int bitmapIdx = getNextAvail(); int q = bitmapIdx >>> 6; int r = bitmapIdx & 63; assert (bitmap[q] >>> r & 1) == 0; @@ -95,9 +95,6 @@ final class PoolSubpage { if (-- numAvail == 0) { removeFromPool(); - nextAvail = -1; - } else { - nextAvail = findNextAvailable(); } return toHandle(bitmapIdx); @@ -118,8 +115,9 @@ final class PoolSubpage { assert (bitmap[q] >>> r & 1) != 0; bitmap[q] ^= 1L << r; + setNextAvail(bitmapIdx); + if (numAvail ++ == 0) { - nextAvail = bitmapIdx; addToPool(); return true; } @@ -157,27 +155,47 @@ final class PoolSubpage { prev = null; } - private int findNextAvailable() { - int newNextAvail = -1; - loop: + private void setNextAvail(int bitmapIdx) { + nextAvail = bitmapIdx; + } + + private int getNextAvail() { + int nextAvail = this.nextAvail; + if (nextAvail >= 0) { + this.nextAvail = -1; + return nextAvail; + } + return findNextAvail(); + } + + private int findNextAvail() { + final long[] bitmap = this.bitmap; + final int bitmapLength = this.bitmapLength; for (int i = 0; i < bitmapLength; i ++) { long bits = bitmap[i]; if (~bits != 0) { - for (int j = 0; j < 64; j ++) { - if ((bits & 1) == 0) { - newNextAvail = i << 6 | j; - break loop; - } - bits >>>= 1; - } + return findNextAvail0(i, bits); } } + return -1; + } - if (newNextAvail < maxNumElems) { - return newNextAvail; - } else { - return -1; + private int findNextAvail0(int i, long bits) { + final int maxNumElems = this.maxNumElems; + final int baseVal = i << 6; + + for (int j = 0; j < 64; j ++) { + if ((bits & 1) == 0) { + int val = baseVal | j; + if (val < maxNumElems) { + return val; + } else { + break; + } + } + bits >>>= 1; } + return -1; } private long toHandle(int bitmapIdx) {