Motivation - Recycler stack and delayed queue drop ratio can only be configured with the same value. The overall drop ratio is ratio^2. - #10251 shows that enable drop in `WeakOrderQueue` may introduce performance degradation. Though the final reason is not clear now, it would be better to add option to configure delayed queue drop ratio separately. Modification - "io.netty.recycler.delayedQueue.ratio" as the drop ratio of delayed queue - default "delayedQueue.ratio" is same as "ratio" Results Able to configure recycler delayed queue drop ratio separately
This commit is contained in:
parent
731d33070f
commit
909e7c9c29
@ -57,6 +57,7 @@ public abstract class Recycler<T> {
|
||||
private static final int MAX_DELAYED_QUEUES_PER_THREAD;
|
||||
private static final int LINK_CAPACITY;
|
||||
private static final int RATIO;
|
||||
private static final int DELAYED_QUEUE_RATIO;
|
||||
|
||||
static {
|
||||
// In the future, we might have different maxCapacity for different object types.
|
||||
@ -86,6 +87,7 @@ public abstract class Recycler<T> {
|
||||
// This should help to slowly increase the capacity of the recycler while not be too sensitive to allocation
|
||||
// bursts.
|
||||
RATIO = max(0, SystemPropertyUtil.getInt("io.netty.recycler.ratio", 8));
|
||||
DELAYED_QUEUE_RATIO = max(0, SystemPropertyUtil.getInt("io.netty.recycler.delayedQueue.ratio", RATIO));
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
if (DEFAULT_MAX_CAPACITY_PER_THREAD == 0) {
|
||||
@ -93,11 +95,13 @@ public abstract class Recycler<T> {
|
||||
logger.debug("-Dio.netty.recycler.maxSharedCapacityFactor: disabled");
|
||||
logger.debug("-Dio.netty.recycler.linkCapacity: disabled");
|
||||
logger.debug("-Dio.netty.recycler.ratio: disabled");
|
||||
logger.debug("-Dio.netty.recycler.delayedQueue.ratio: disabled");
|
||||
} else {
|
||||
logger.debug("-Dio.netty.recycler.maxCapacityPerThread: {}", DEFAULT_MAX_CAPACITY_PER_THREAD);
|
||||
logger.debug("-Dio.netty.recycler.maxSharedCapacityFactor: {}", MAX_SHARED_CAPACITY_FACTOR);
|
||||
logger.debug("-Dio.netty.recycler.linkCapacity: {}", LINK_CAPACITY);
|
||||
logger.debug("-Dio.netty.recycler.ratio: {}", RATIO);
|
||||
logger.debug("-Dio.netty.recycler.delayedQueue.ratio: {}", DELAYED_QUEUE_RATIO);
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,12 +112,13 @@ public abstract class Recycler<T> {
|
||||
private final int maxSharedCapacityFactor;
|
||||
private final int interval;
|
||||
private final int maxDelayedQueuesPerThread;
|
||||
private final int delayedQueueInterval;
|
||||
|
||||
private final FastThreadLocal<Stack<T>> threadLocal = new FastThreadLocal<Stack<T>>() {
|
||||
@Override
|
||||
protected Stack<T> initialValue() {
|
||||
return new Stack<T>(Recycler.this, Thread.currentThread(), maxCapacityPerThread, maxSharedCapacityFactor,
|
||||
interval, maxDelayedQueuesPerThread);
|
||||
interval, maxDelayedQueuesPerThread, delayedQueueInterval);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -141,7 +146,14 @@ public abstract class Recycler<T> {
|
||||
|
||||
protected Recycler(int maxCapacityPerThread, int maxSharedCapacityFactor,
|
||||
int ratio, int maxDelayedQueuesPerThread) {
|
||||
this(maxCapacityPerThread, maxSharedCapacityFactor, ratio, maxDelayedQueuesPerThread,
|
||||
DELAYED_QUEUE_RATIO);
|
||||
}
|
||||
|
||||
protected Recycler(int maxCapacityPerThread, int maxSharedCapacityFactor,
|
||||
int ratio, int maxDelayedQueuesPerThread, int delayedQueueRatio) {
|
||||
interval = max(0, ratio);
|
||||
delayedQueueInterval = max(0, delayedQueueRatio);
|
||||
if (maxCapacityPerThread <= 0) {
|
||||
this.maxCapacityPerThread = 0;
|
||||
this.maxSharedCapacityFactor = 1;
|
||||
@ -331,7 +343,7 @@ public abstract class Recycler<T> {
|
||||
// Stack itself GCed.
|
||||
head = new Head(stack.availableSharedCapacity);
|
||||
head.link = tail;
|
||||
interval = stack.interval;
|
||||
interval = stack.delayedQueueInterval;
|
||||
handleRecycleCount = interval; // Start at interval so the first one will be recycled.
|
||||
}
|
||||
|
||||
@ -489,6 +501,7 @@ public abstract class Recycler<T> {
|
||||
|
||||
private final int maxCapacity;
|
||||
private final int interval;
|
||||
private final int delayedQueueInterval;
|
||||
DefaultHandle<?>[] elements;
|
||||
int size;
|
||||
private int handleRecycleCount;
|
||||
@ -496,13 +509,14 @@ public abstract class Recycler<T> {
|
||||
private volatile WeakOrderQueue head;
|
||||
|
||||
Stack(Recycler<T> parent, Thread thread, int maxCapacity, int maxSharedCapacityFactor,
|
||||
int interval, int maxDelayedQueues) {
|
||||
int interval, int maxDelayedQueues, int delayedQueueInterval) {
|
||||
this.parent = parent;
|
||||
threadRef = new WeakReference<Thread>(thread);
|
||||
this.maxCapacity = maxCapacity;
|
||||
availableSharedCapacity = new AtomicInteger(max(maxCapacity / maxSharedCapacityFactor, LINK_CAPACITY));
|
||||
elements = new DefaultHandle[min(INITIAL_CAPACITY, maxCapacity)];
|
||||
this.interval = interval;
|
||||
this.delayedQueueInterval = delayedQueueInterval;
|
||||
handleRecycleCount = interval; // Start at interval so the first one will be recycled.
|
||||
this.maxDelayedQueues = maxDelayedQueues;
|
||||
}
|
||||
|
@ -27,13 +27,14 @@ import static org.junit.Assert.*;
|
||||
public class RecyclerTest {
|
||||
|
||||
private static Recycler<HandledObject> newRecycler(int maxCapacityPerThread) {
|
||||
return newRecycler(maxCapacityPerThread, 2, 8, 2);
|
||||
return newRecycler(maxCapacityPerThread, 2, 8, 2, 8);
|
||||
}
|
||||
|
||||
private static Recycler<HandledObject> newRecycler(int maxCapacityPerThread, int maxSharedCapacityFactor,
|
||||
int ratio, int maxDelayedQueuesPerThread) {
|
||||
int ratio, int maxDelayedQueuesPerThread,
|
||||
int delayedQueueRatio) {
|
||||
return new Recycler<HandledObject>(maxCapacityPerThread, maxSharedCapacityFactor, ratio,
|
||||
maxDelayedQueuesPerThread) {
|
||||
maxDelayedQueuesPerThread, delayedQueueRatio) {
|
||||
@Override
|
||||
protected HandledObject newObject(
|
||||
Recycler.Handle<HandledObject> handle) {
|
||||
@ -141,7 +142,7 @@ public class RecyclerTest {
|
||||
|
||||
@Test
|
||||
public void testRecycleDisableDrop() {
|
||||
Recycler<HandledObject> recycler = newRecycler(1024, 2, 0, 2);
|
||||
Recycler<HandledObject> recycler = newRecycler(1024, 2, 0, 2, 0);
|
||||
HandledObject object = recycler.get();
|
||||
object.recycle();
|
||||
HandledObject object2 = recycler.get();
|
||||
@ -152,6 +153,27 @@ public class RecyclerTest {
|
||||
object3.recycle();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecycleDisableDelayedQueueDrop() throws Exception {
|
||||
final Recycler<HandledObject> recycler = newRecycler(1024, 2, 1, 2, 0);
|
||||
final HandledObject o = recycler.get();
|
||||
final HandledObject o2 = recycler.get();
|
||||
final HandledObject o3 = recycler.get();
|
||||
final Thread thread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
o.recycle();
|
||||
o2.recycle();
|
||||
o3.recycle();
|
||||
}
|
||||
};
|
||||
thread.start();
|
||||
thread.join();
|
||||
// In reverse order
|
||||
assertSame(o3, recycler.get());
|
||||
assertSame(o, recycler.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to make sure bug #2848 never happens again
|
||||
* https://github.com/netty/netty/issues/2848
|
||||
@ -184,13 +206,7 @@ public class RecyclerTest {
|
||||
|
||||
@Test
|
||||
public void testRecycleAtDifferentThread() throws Exception {
|
||||
final Recycler<HandledObject> recycler = new Recycler<HandledObject>(256, 10, 2, 10) {
|
||||
@Override
|
||||
protected HandledObject newObject(Recycler.Handle<HandledObject> handle) {
|
||||
return new HandledObject(handle);
|
||||
}
|
||||
};
|
||||
|
||||
final Recycler<HandledObject> recycler = newRecycler(256, 10, 2, 10, 2);
|
||||
final HandledObject o = recycler.get();
|
||||
final HandledObject o2 = recycler.get();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user