* Improved the throughput of the server-side accept operation
* Added FastQueue.isEmpty()
This commit is contained in:
parent
4d17db6eb1
commit
dccc9f8665
@ -202,10 +202,6 @@ class NioServerSocketPipelineSink extends AbstractChannelSink {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
try {
|
try {
|
||||||
SocketChannel acceptedSocket = channel.socket.accept();
|
SocketChannel acceptedSocket = channel.socket.accept();
|
||||||
if (acceptedSocket == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ChannelPipeline pipeline =
|
ChannelPipeline pipeline =
|
||||||
channel.getConfig().getPipelineFactory().getPipeline();
|
channel.getConfig().getPipelineFactory().getPipeline();
|
||||||
|
@ -32,7 +32,6 @@ import java.nio.channels.ScatteringByteChannel;
|
|||||||
import java.nio.channels.SelectionKey;
|
import java.nio.channels.SelectionKey;
|
||||||
import java.nio.channels.Selector;
|
import java.nio.channels.Selector;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
@ -72,11 +71,15 @@ class NioWorker implements Runnable {
|
|||||||
private final int id;
|
private final int id;
|
||||||
private final Executor executor;
|
private final Executor executor;
|
||||||
private final AtomicBoolean started = new AtomicBoolean();
|
private final AtomicBoolean started = new AtomicBoolean();
|
||||||
volatile Thread thread;
|
private volatile Thread thread;
|
||||||
volatile Selector selector;
|
private volatile Selector selector;
|
||||||
final AtomicBoolean wakenUp = new AtomicBoolean();
|
private final AtomicBoolean wakenUp = new AtomicBoolean();
|
||||||
final ReadWriteLock selectorGuard = new ReentrantReadWriteLock();
|
private final ReadWriteLock selectorGuard = new ReentrantReadWriteLock();
|
||||||
final Queue<Runnable> taskQueue = new ConcurrentLinkedQueue<Runnable>();
|
private final ReadWriteLock shutdownLock = new ReentrantReadWriteLock();
|
||||||
|
//private final FastQueue<Runnable> taskQueue = new FastQueue<Runnable>();
|
||||||
|
//private final ConcurrentFastQueue<Runnable> taskQueue = new ConcurrentFastQueue<Runnable>();
|
||||||
|
private final FastQueue<Runnable> registerTaskQueue = new FastQueue<Runnable>();
|
||||||
|
private final ConcurrentLinkedQueue<Runnable> writeTaskQueue = new ConcurrentLinkedQueue<Runnable>();
|
||||||
|
|
||||||
NioWorker(int bossId, int id, Executor executor) {
|
NioWorker(int bossId, int id, Executor executor) {
|
||||||
this.bossId = bossId;
|
this.bossId = bossId;
|
||||||
@ -104,60 +107,24 @@ class NioWorker implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean server = !(channel instanceof NioClientSocketChannel);
|
||||||
|
Runnable registerTask = new RegisterTask(selector, channel, future, server);
|
||||||
if (firstChannel) {
|
if (firstChannel) {
|
||||||
try {
|
registerTask.run();
|
||||||
channel.socket.register(selector, SelectionKey.OP_READ, channel);
|
|
||||||
if (future != null) {
|
|
||||||
future.setSuccess();
|
|
||||||
}
|
|
||||||
} catch (ClosedChannelException e) {
|
|
||||||
future.setFailure(e);
|
|
||||||
throw new ChannelException(
|
|
||||||
"Failed to register a socket to the selector.", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean server = !(channel instanceof NioClientSocketChannel);
|
|
||||||
if (server) {
|
|
||||||
fireChannelOpen(channel);
|
|
||||||
fireChannelBound(channel, channel.getLocalAddress());
|
|
||||||
} else if (!((NioClientSocketChannel) channel).boundManually) {
|
|
||||||
fireChannelBound(channel, channel.getLocalAddress());
|
|
||||||
}
|
|
||||||
fireChannelConnected(channel, channel.getRemoteAddress());
|
|
||||||
|
|
||||||
String threadName =
|
String threadName =
|
||||||
(server ? "New I/O server worker #"
|
(server ? "New I/O server worker #"
|
||||||
: "New I/O client worker #") + bossId + '-' + id;
|
: "New I/O client worker #") + bossId + '-' + id;
|
||||||
|
|
||||||
executor.execute(new ThreadRenamingRunnable(this, threadName));
|
executor.execute(new ThreadRenamingRunnable(this, threadName));
|
||||||
} else {
|
} else {
|
||||||
selectorGuard.readLock().lock();
|
shutdownLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
if (wakenUp.compareAndSet(false, true)) {
|
registerTaskQueue.offer(registerTask);
|
||||||
selector.wakeup();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
channel.socket.register(selector, SelectionKey.OP_READ, channel);
|
|
||||||
if (future != null) {
|
|
||||||
future.setSuccess();
|
|
||||||
}
|
|
||||||
} catch (ClosedChannelException e) {
|
|
||||||
future.setFailure(e);
|
|
||||||
throw new ChannelException(
|
|
||||||
"Failed to register a socket to the selector.", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean server = !(channel instanceof NioClientSocketChannel);
|
|
||||||
if (server) {
|
|
||||||
fireChannelOpen(channel);
|
|
||||||
fireChannelBound(channel, channel.getLocalAddress());
|
|
||||||
} else if (!((NioClientSocketChannel) channel).boundManually) {
|
|
||||||
fireChannelBound(channel, channel.getLocalAddress());
|
|
||||||
}
|
|
||||||
fireChannelConnected(channel, channel.getRemoteAddress());
|
|
||||||
} finally {
|
} finally {
|
||||||
selectorGuard.readLock().unlock();
|
shutdownLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
if (wakenUp.compareAndSet(false, true)) {
|
||||||
|
selector.wakeup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -170,15 +137,18 @@ class NioWorker implements Runnable {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
wakenUp.set(false);
|
wakenUp.set(false);
|
||||||
|
|
||||||
selectorGuard.writeLock().lock();
|
if (CONSTRAINT_LEVEL != 0) {
|
||||||
// This empty synchronization block prevents the selector
|
selectorGuard.writeLock().lock();
|
||||||
// from acquiring its lock.
|
// This empty synchronization block prevents the selector
|
||||||
selectorGuard.writeLock().unlock();
|
// from acquiring its lock.
|
||||||
|
selectorGuard.writeLock().unlock();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int selectedKeyCount = selector.select(500);
|
int selectedKeyCount = selector.select(500);
|
||||||
|
|
||||||
processTaskQueue();
|
processRegisterTaskQueue();
|
||||||
|
processWriteTaskQueue();
|
||||||
|
|
||||||
if (selectedKeyCount > 0) {
|
if (selectedKeyCount > 0) {
|
||||||
processSelectedKeys(selector.selectedKeys());
|
processSelectedKeys(selector.selectedKeys());
|
||||||
@ -193,9 +163,9 @@ class NioWorker implements Runnable {
|
|||||||
if (shutdown ||
|
if (shutdown ||
|
||||||
executor instanceof ExecutorService && ((ExecutorService) executor).isShutdown()) {
|
executor instanceof ExecutorService && ((ExecutorService) executor).isShutdown()) {
|
||||||
|
|
||||||
selectorGuard.writeLock().lock();
|
shutdownLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
if (selector.keys().isEmpty()) {
|
if (registerTaskQueue.isEmpty() && selector.keys().isEmpty()) {
|
||||||
try {
|
try {
|
||||||
selector.close();
|
selector.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -210,7 +180,7 @@ class NioWorker implements Runnable {
|
|||||||
shutdown = false;
|
shutdown = false;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
selectorGuard.writeLock().unlock();
|
shutdownLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Give one more second.
|
// Give one more second.
|
||||||
@ -233,9 +203,20 @@ class NioWorker implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processTaskQueue() {
|
private void processRegisterTaskQueue() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
final Runnable task = taskQueue.poll();
|
final Runnable task = registerTaskQueue.poll();
|
||||||
|
if (task == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
task.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processWriteTaskQueue() {
|
||||||
|
for (;;) {
|
||||||
|
final Runnable task = writeTaskQueue.poll();
|
||||||
if (task == null) {
|
if (task == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -390,7 +371,7 @@ class NioWorker implements Runnable {
|
|||||||
Thread workerThread = worker.thread;
|
Thread workerThread = worker.thread;
|
||||||
if (workerThread != null && Thread.currentThread() != workerThread) {
|
if (workerThread != null && Thread.currentThread() != workerThread) {
|
||||||
if (channel.writeTaskInTaskQueue.compareAndSet(false, true)) {
|
if (channel.writeTaskInTaskQueue.compareAndSet(false, true)) {
|
||||||
worker.taskQueue.offer(channel.writeTask);
|
worker.writeTaskQueue.offer(channel.writeTask);
|
||||||
}
|
}
|
||||||
if (worker.wakenUp.compareAndSet(false, true)) {
|
if (worker.wakenUp.compareAndSet(false, true)) {
|
||||||
worker.selector.wakeup();
|
worker.selector.wakeup();
|
||||||
@ -434,11 +415,11 @@ class NioWorker implements Runnable {
|
|||||||
int bufIdx;
|
int bufIdx;
|
||||||
|
|
||||||
synchronized (channel.writeLock) {
|
synchronized (channel.writeLock) {
|
||||||
FastQueue<MessageEvent> internalWriteBuffer = channel.writeBuffer;
|
FastQueue<MessageEvent> writeBuffer = channel.writeBuffer;
|
||||||
evt = channel.currentWriteEvent;
|
evt = channel.currentWriteEvent;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (evt == null) {
|
if (evt == null) {
|
||||||
evt = internalWriteBuffer.poll();
|
evt = writeBuffer.poll();
|
||||||
if (evt == null) {
|
if (evt == null) {
|
||||||
channel.currentWriteEvent = null;
|
channel.currentWriteEvent = null;
|
||||||
removeOpWrite = true;
|
removeOpWrite = true;
|
||||||
@ -510,11 +491,11 @@ class NioWorker implements Runnable {
|
|||||||
int writtenBytes = 0;
|
int writtenBytes = 0;
|
||||||
|
|
||||||
synchronized (channel.writeLock) {
|
synchronized (channel.writeLock) {
|
||||||
FastQueue<MessageEvent> internalWriteBuffer = channel.writeBuffer;
|
FastQueue<MessageEvent> writeBuffer = channel.writeBuffer;
|
||||||
evt = channel.currentWriteEvent;
|
evt = channel.currentWriteEvent;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (evt == null) {
|
if (evt == null) {
|
||||||
evt = internalWriteBuffer.poll();
|
evt = writeBuffer.poll();
|
||||||
if (evt == null) {
|
if (evt == null) {
|
||||||
channel.currentWriteEvent = null;
|
channel.currentWriteEvent = null;
|
||||||
removeOpWrite = true;
|
removeOpWrite = true;
|
||||||
@ -758,9 +739,9 @@ class NioWorker implements Runnable {
|
|||||||
fireExceptionCaught(channel, cause);
|
fireExceptionCaught(channel, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
FastQueue<MessageEvent> internalWriteBuffer = channel.writeBuffer;
|
FastQueue<MessageEvent> writeBuffer = channel.writeBuffer;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
evt = internalWriteBuffer.poll();
|
evt = writeBuffer.poll();
|
||||||
if (evt == null) {
|
if (evt == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -837,4 +818,42 @@ class NioWorker implements Runnable {
|
|||||||
fireExceptionCaught(channel, t);
|
fireExceptionCaught(channel, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class RegisterTask implements Runnable {
|
||||||
|
private final Selector selector;
|
||||||
|
private final NioSocketChannel channel;
|
||||||
|
private final ChannelFuture future;
|
||||||
|
private final boolean server;
|
||||||
|
|
||||||
|
RegisterTask(
|
||||||
|
Selector selector,
|
||||||
|
NioSocketChannel channel, ChannelFuture future, boolean server) {
|
||||||
|
|
||||||
|
this.selector = selector;
|
||||||
|
this.channel = channel;
|
||||||
|
this.future = future;
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
channel.socket.register(selector, SelectionKey.OP_READ, channel);
|
||||||
|
if (future != null) {
|
||||||
|
future.setSuccess();
|
||||||
|
}
|
||||||
|
} catch (ClosedChannelException e) {
|
||||||
|
future.setFailure(e);
|
||||||
|
throw new ChannelException(
|
||||||
|
"Failed to register a socket to the selector.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (server) {
|
||||||
|
fireChannelOpen(channel);
|
||||||
|
fireChannelBound(channel, channel.getLocalAddress());
|
||||||
|
} else if (!((NioClientSocketChannel) channel).boundManually) {
|
||||||
|
fireChannelBound(channel, channel.getLocalAddress());
|
||||||
|
}
|
||||||
|
fireChannelConnected(channel, channel.getRemoteAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -71,6 +71,11 @@ public class FastQueue<E> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized boolean isEmpty() {
|
||||||
|
return offeredElements == null &&
|
||||||
|
(drainedElements == null || drainedElements.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private E cast(Object o) {
|
private E cast(Object o) {
|
||||||
return (E) o;
|
return (E) o;
|
||||||
|
Loading…
Reference in New Issue
Block a user