Skip to content

Instantly share code, notes, and snippets.

@normanmaurer
Last active August 29, 2015 14:02
Show Gist options
  • Select an option

  • Save normanmaurer/de9f5d32a400de6a670f to your computer and use it in GitHub Desktop.

Select an option

Save normanmaurer/de9f5d32a400de6a670f to your computer and use it in GitHub Desktop.
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