Last active
August 29, 2015 14:02
-
-
Save normanmaurer/de9f5d32a400de6a670f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| iff --git a/common/src/main/java/io/netty/util/Recycler.java b/common/src/main/java/io/netty/util/Recycler.java | |
| index 971740f..170a0e5 100644 | |
| --- a/common/src/main/java/io/netty/util/Recycler.java | |
| +++ b/common/src/main/java/io/netty/util/Recycler.java | |
| @@ -35,7 +35,8 @@ import java.util.concurrent.atomic.AtomicInteger; | |
| public abstract class Recycler<T> { | |
| private static final InternalLogger logger = InternalLoggerFactory.getInstance(Recycler.class); | |
| - | |
| + private static final AtomicInteger ID_GENERATOR = new AtomicInteger(Integer.MIN_VALUE); | |
| + private static final int OWN_THREAD_ID = ID_GENERATOR.getAndIncrement(); | |
| private static final int DEFAULT_MAX_CAPACITY; | |
| private static final int INITIAL_CAPACITY; | |
| @@ -101,12 +102,13 @@ public abstract class Recycler<T> { | |
| public interface Handle { } | |
| static final class DefaultHandle implements Handle { | |
| - private final int id; | |
| + private int lastRecycledId; | |
| + private int recycleId; | |
| + | |
| private Stack<?> stack; | |
| private Object value; | |
| - DefaultHandle(int id, Stack<?> stack) { | |
| - this.id = id; | |
| + DefaultHandle(Stack<?> stack) { | |
| this.stack = stack; | |
| } | |
| @@ -155,6 +157,7 @@ public abstract class Recycler<T> { | |
| // pointer to another queue of delayed items for the same stack | |
| private WeakOrderQueue next; | |
| private final WeakReference<Thread> owner; | |
| + private final int id = ID_GENERATOR.getAndIncrement(); | |
| public WeakOrderQueue(Stack<?> stack, Thread thread) { | |
| head = tail = new Link(); | |
| @@ -166,6 +169,8 @@ public abstract class Recycler<T> { | |
| } | |
| void add(DefaultHandle handle) { | |
| + handle.lastRecycledId = id; | |
| + | |
| Link tail = this.tail; | |
| int writeIndex; | |
| if ((writeIndex = tail.get()) == LINK_CAPACITY) { | |
| @@ -209,13 +214,14 @@ public abstract class Recycler<T> { | |
| to.elements = Arrays.copyOf(to.elements, (to.size + count) * 2); | |
| } | |
| - BitSet present = to.present; | |
| DefaultHandle[] src = head.elements; | |
| DefaultHandle[] trg = to.elements; | |
| int size = to.size; | |
| while (start < end) { | |
| DefaultHandle element = src[start]; | |
| - if (!present.set(element.id)) { | |
| + if (element.recycleId == 0) { | |
| + element.recycleId = element.lastRecycledId; | |
| + } else if (element.recycleId != element.lastRecycledId) { | |
| throw new IllegalStateException("recycled already"); | |
| } | |
| element.stack = to; | |
| @@ -241,11 +247,9 @@ public abstract class Recycler<T> { | |
| // to scavenge those that can be reused. this permits us to incur minimal thread synchronisation whilst | |
| // still recycling all items; more importantly it permits us to use a BitSet to track ids, as we can | |
| // be certain that, under correct usage, the id domain does not grow unbounded | |
| - private int maxId; | |
| final Recycler<T> parent; | |
| final Thread thread; | |
| private DefaultHandle[] elements; | |
| - private final BitSet present = new BitSet(256); | |
| private final int maxCapacity; | |
| private int size; | |
| @@ -271,7 +275,10 @@ public abstract class Recycler<T> { | |
| } | |
| size --; | |
| DefaultHandle ret = elements[size]; | |
| - present.clear(ret.id); | |
| + if (ret.lastRecycledId != ret.recycleId) { | |
| + throw new IllegalStateException("recycled multiple times"); | |
| + } | |
| + ret.recycleId = 0; | |
| this.size = size; | |
| return ret; | |
| } | |
| @@ -292,11 +299,6 @@ public abstract class Recycler<T> { | |
| } | |
| } | |
| - // maybe expand our id domain / pool size | |
| - if (maxId == present.size()) { | |
| - present.ensureCapacity(maxId * 2); | |
| - } | |
| - | |
| // reset our scavenge cursor | |
| prev = null; | |
| cursor = head; | |
| @@ -337,7 +339,9 @@ public abstract class Recycler<T> { | |
| } | |
| void push(DefaultHandle item) { | |
| - if (!present.set(item.id)) { | |
| + if (item.recycleId == 0) { | |
| + item.recycleId = item.lastRecycledId = OWN_THREAD_ID; | |
| + } else if (item.recycleId != item.lastRecycledId) { | |
| throw new IllegalStateException("recycled already"); | |
| } | |
| @@ -355,38 +359,7 @@ public abstract class Recycler<T> { | |
| } | |
| DefaultHandle newHandle() { | |
| - return new DefaultHandle(maxId++, this); | |
| - } | |
| - } | |
| - | |
| - // a simpler bitset than the java.util.BitSet, which performs unnecessary work | |
| - private static final class BitSet { | |
| - private long[] bits; | |
| - | |
| - BitSet(int initialCapacity) { | |
| - assert (initialCapacity & 63) == 0; | |
| - bits = new long[initialCapacity >>> 6]; | |
| - } | |
| - | |
| - boolean set(int index) { | |
| - int bucket = index >>> 6; | |
| - long bit = 1L << (index & 63); | |
| - long prev = bits[bucket]; | |
| - bits[bucket] = prev | bit; | |
| - return (prev & bit) == 0; | |
| - } | |
| - | |
| - void clear(int index) { | |
| - bits[index >>> 6] &= ~(1L << (index & 63)); | |
| - } | |
| - | |
| - int size() { | |
| - return bits.length << 6; | |
| - } | |
| - | |
| - void ensureCapacity(int newCapacity) { | |
| - assert (newCapacity & 63) == 0; | |
| - bits = Arrays.copyOf(bits, newCapacity); | |
| + return new DefaultHandle(this); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment