Fix overflow bug in MultithreadEventExecutorGroup (#10474)

Motivation:

We should pluck executors in round-robin, but at the 32-bit overflow boundary, the round-robin sequence was disrupted when the number of executors are not a power of 2.

Modifications:

Changed the index counter from a 32-bit to a 64-bit long. The overflow bug is still technically there, but it now takes so long to reach that it will never happen in practice. For example, 2^63 nanoseconds is almost 300 years.

Result:

 The round-robin behaviour is now preserved in practice. This is a backport of https://github.com/netty/netty/pull/10468
This commit is contained in:
Norman Maurer 2020-08-12 11:22:24 +02:00 committed by GitHub
parent 02676e369c
commit 41313130a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -25,6 +25,7 @@ import java.util.concurrent.Executor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
* {@link EventExecutorGroup} implementation that handles their tasks with multiple threads at
@ -166,7 +167,10 @@ public class MultithreadEventExecutorGroup extends AbstractEventExecutorGroup {
readonlyChildren = Collections.unmodifiableList(Arrays.asList(children));
}
private final AtomicInteger idx = new AtomicInteger();
// Use a 'long' counter to avoid non-round-robin behaviour at the 32-bit overflow boundary.
// The 64-bit long solves this by placing the overflow so far into the future, that no system
// will encounter this in practice.
private final AtomicLong idx = new AtomicLong();
/**
* The {@link EventExecutor}s that are used by this {@link MultithreadEventExecutorGroup}.
@ -182,9 +186,9 @@ public class MultithreadEventExecutorGroup extends AbstractEventExecutorGroup {
@Override
public EventExecutor next() {
if (powerOfTwo) {
return children[idx.getAndIncrement() & children.length - 1];
return children[(int) idx.getAndIncrement() & children.length - 1];
}
return children[Math.abs(idx.getAndIncrement() % children.length)];
return children[(int) Math.abs(idx.getAndIncrement() % children.length)];
}
private static boolean isPowerOfTwo(int val) {