Skip to content

Commit

Permalink
Use shaded dependency on JCTools instead of copy and paste
Browse files Browse the repository at this point in the history
Motivation:
JCTools supports both non-unsafe, unsafe versions of queues and JDK6 which allows us to shade the library in netty-common allowing it to stay "zero dependency".

Modifications:
- Remove copy paste JCTools code and shade the library (dependencies that are shaded should be removed from the <dependencies> section of the generated POM).
- Remove usage of OneTimeTask and remove it all together.

Result:
Less code to maintain and easier to update JCTools and less GC pressure as the queue implementation nt creates so much garbage
  • Loading branch information
Guido Medina authored and normanmaurer committed Jun 10, 2016
1 parent 398efb1 commit c3abb91
Show file tree
Hide file tree
Showing 64 changed files with 228 additions and 2,498 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@
# JVM crash logs
hs_err_pid*.log

dependency-reduced-pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.internal.EmptyArrays;
import io.netty.util.internal.OneTimeTask;
import io.netty.util.internal.StringUtil;

import java.net.URI;
Expand Down Expand Up @@ -273,7 +272,7 @@ public final void finishHandshake(Channel channel, FullHttpResponse response) {
// Delay the removal of the decoder so the user can setup the pipeline if needed to handle
// WebSocketFrame messages.
// See https://github.com/netty/netty/issues/4533
channel.eventLoop().execute(new OneTimeTask() {
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
p.remove(codec);
Expand All @@ -290,7 +289,7 @@ public void run() {
// Delay the removal of the decoder so the user can setup the pipeline if needed to handle
// WebSocketFrame messages.
// See https://github.com/netty/netty/issues/4533
channel.eventLoop().execute(new OneTimeTask() {
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
p.remove(context.handler());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.internal.EmptyArrays;
import io.netty.util.internal.OneTimeTask;

import java.net.SocketAddress;
import java.nio.channels.ClosedChannelException;
Expand Down Expand Up @@ -201,7 +200,7 @@ protected final void doWrite(ChannelOutboundBuffer in) throws Exception {
in.remove();
}

preferredExecutor.execute(new OneTimeTask() {
preferredExecutor.execute(new Runnable() {
@Override
public void run() {
for (Object msg : msgsCopy) {
Expand Down Expand Up @@ -248,7 +247,7 @@ protected void fireChildRead(final Object msg) {
if (eventLoop().inEventLoop()) {
fireChildRead0(msg);
} else {
eventLoop().execute(new OneTimeTask() {
eventLoop().execute(new Runnable() {
@Override
public void run() {
fireChildRead0(msg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import io.netty.handler.codec.http2.Http2Exception.CompositeStreamException;
import io.netty.handler.codec.http2.Http2Exception.StreamException;
import io.netty.util.concurrent.ScheduledFuture;
import io.netty.util.internal.OneTimeTask;
import io.netty.util.internal.UnstableApi;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
Expand Down Expand Up @@ -766,7 +765,7 @@ private static final class ClosingChannelFutureListener implements ChannelFuture
long timeout, TimeUnit unit) {
this.ctx = ctx;
this.promise = promise;
timeoutTask = ctx.executor().schedule(new OneTimeTask() {
timeoutTask = ctx.executor().schedule(new Runnable() {
@Override
public void run() {
ctx.close(promise);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import io.netty.handler.codec.http.HttpServerUpgradeHandler.UpgradeEvent;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.internal.OneTimeTask;
import io.netty.util.internal.UnstableApi;

import java.util.ArrayList;
Expand Down Expand Up @@ -212,7 +211,7 @@ void writeFromStreamChannel(final Object msg, final boolean flush) {
writeFromStreamChannel0(msg, flush, promise);
} else {
try {
executor.execute(new OneTimeTask() {
executor.execute(new Runnable() {
@Override
public void run() {
writeFromStreamChannel0(msg, flush, promise);
Expand Down Expand Up @@ -344,7 +343,7 @@ public void onStreamClosed(Http2Stream stream) {
if (eventLoop.inEventLoop()) {
onStreamClosed0(streamInfo);
} else {
eventLoop.execute(new OneTimeTask() {
eventLoop.execute(new Runnable() {
@Override
public void run() {
onStreamClosed0(streamInfo);
Expand Down Expand Up @@ -381,7 +380,7 @@ public boolean visit(Http2Stream stream) {
if (executor.inEventLoop()) {
exceptionCaught(ctx, t);
} else {
executor.execute(new OneTimeTask() {
executor.execute(new Runnable() {
@Override
public void run() {
exceptionCaught(ctx, t);
Expand Down Expand Up @@ -518,7 +517,7 @@ protected void bytesConsumed(final int bytes) {
if (executor.inEventLoop()) {
bytesConsumed0(bytes);
} else {
executor.execute(new OneTimeTask() {
executor.execute(new Runnable() {
@Override
public void run() {
bytesConsumed0(bytes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import io.netty.channel.ChannelPromiseNotifier;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.internal.EmptyArrays;
import io.netty.util.internal.OneTimeTask;

import java.util.concurrent.TimeUnit;

Expand Down Expand Up @@ -253,7 +252,7 @@ public ChannelFuture close(final ChannelPromise promise) {
return finishEncode(ctx, promise);
} else {
final ChannelPromise p = ctx.newPromise();
executor.execute(new OneTimeTask() {
executor.execute(new Runnable() {
@Override
public void run() {
ChannelFuture f = finishEncode(ctx(), p);
Expand Down Expand Up @@ -352,7 +351,7 @@ public void operationComplete(ChannelFuture f) throws Exception {

if (!f.isDone()) {
// Ensure the channel is closed even if the write operation completes in time.
ctx.executor().schedule(new OneTimeTask() {
ctx.executor().schedule(new Runnable() {
@Override
public void run() {
ctx.close(promise);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import io.netty.channel.ChannelPromise;
import io.netty.channel.ChannelPromiseNotifier;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.internal.OneTimeTask;

import java.util.concurrent.TimeUnit;
import java.util.zip.CRC32;
Expand Down Expand Up @@ -164,7 +163,7 @@ public ChannelFuture close(final ChannelPromise promise) {
return finishEncode(ctx, promise);
} else {
final ChannelPromise p = ctx.newPromise();
executor.execute(new OneTimeTask() {
executor.execute(new Runnable() {
@Override
public void run() {
ChannelFuture f = finishEncode(ctx(), p);
Expand Down Expand Up @@ -260,7 +259,7 @@ public void operationComplete(ChannelFuture f) throws Exception {

if (!f.isDone()) {
// Ensure the channel is closed even if the write operation completes in time.
ctx.executor().schedule(new OneTimeTask() {
ctx.executor().schedule(new Runnable() {
@Override
public void run() {
ctx.close(promise);
Expand Down
32 changes: 32 additions & 0 deletions common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@
<scope>compile</scope> <!-- override the 'test' scope defined at parent pom.xml -->
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jctools</groupId>
<artifactId>jctools-core</artifactId>
<!-- Mark as optional as otherwise the bundle plugin will add strict import statements and so fail in OSGI containers-->
<optional>true</optional>
</dependency>

<!-- Logging frameworks - completely optional -->
<dependency>
Expand Down Expand Up @@ -75,6 +81,31 @@

<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>org.jctools</include>
</includes>
</artifactSet>
<relocations>
<relocation>
<pattern>org.jctools.</pattern>
<shadedPattern>io.netty.util.internal.shaded.org.jctools.</shadedPattern>
</relocation>
</relocations>
<minimizeJar>true</minimizeJar>
</configuration>
</execution>
</executions>
</plugin>
<!-- Add generated collection sources. -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
Expand Down Expand Up @@ -151,6 +182,7 @@
</goals>
<configuration>
<instructions>
<!-- Exclude org.jctools.* as we shade it -->
<!-- NativeLibraryLoader can be used to manually load native libraries from other bundles that this bundle does not depend on,
hence use DynamicImport-Package instruction to ensure the loading is successful -->
<DynamicImport-Package>*</DynamicImport-Package>
Expand Down
44 changes: 16 additions & 28 deletions common/src/main/java/io/netty/util/HashedWheelTimer.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package io.netty.util;

import io.netty.util.internal.MpscLinkedQueueNode;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.StringUtil;
import io.netty.util.internal.logging.InternalLogger;
Expand Down Expand Up @@ -106,7 +105,7 @@ public class HashedWheelTimer implements Timer {
private final int mask;
private final CountDownLatch startTimeInitialized = new CountDownLatch(1);
private final Queue<HashedWheelTimeout> timeouts = PlatformDependent.newMpscQueue();
private final Queue<Runnable> cancelledTimeouts = PlatformDependent.newMpscQueue();
private final Queue<HashedWheelTimeout> cancelledTimeouts = PlatformDependent.newMpscQueue();

private volatile long startTime;

Expand Down Expand Up @@ -412,13 +411,13 @@ private void transferTimeoutsToBuckets() {

private void processCancelledTasks() {
for (;;) {
Runnable task = cancelledTimeouts.poll();
if (task == null) {
HashedWheelTimeout timeout = cancelledTimeouts.poll();
if (timeout == null) {
// all processed
break;
}
try {
task.run();
timeout.remove();
} catch (Throwable t) {
if (logger.isWarnEnabled()) {
logger.warn("An exception was thrown while process a cancellation task", t);
Expand Down Expand Up @@ -472,8 +471,7 @@ public Set<Timeout> unprocessedTimeouts() {
}
}

private static final class HashedWheelTimeout extends MpscLinkedQueueNode<Timeout>
implements Timeout {
private static final class HashedWheelTimeout implements Timeout {

private static final int ST_INIT = 0;
private static final int ST_CANCELLED = 1;
Expand Down Expand Up @@ -530,25 +528,20 @@ public boolean cancel() {
if (!compareAndSetState(ST_INIT, ST_CANCELLED)) {
return false;
}
// If a task should be canceled we create a new Runnable for this to another queue which will
// be processed on each tick. So this means that we will have a GC latency of max. 1 tick duration
// which is good enough. This way we can make again use of our MpscLinkedQueue and so minimize the
// locking / overhead as much as possible.
//
// It is important that we not just add the HashedWheelTimeout itself again as it extends
// MpscLinkedQueueNode and so may still be used as tombstone.
timer.cancelledTimeouts.add(new Runnable() {
@Override
public void run() {
HashedWheelBucket bucket = HashedWheelTimeout.this.bucket;
if (bucket != null) {
bucket.remove(HashedWheelTimeout.this);
}
}
});
// If a task should be canceled we put this to another queue which will be processed on each tick.
// So this means that we will have a GC latency of max. 1 tick duration which is good enough. This way
// we can make again use of our MpscLinkedQueue and so minimize the locking / overhead as much as possible.
timer.cancelledTimeouts.add(this);
return true;
}

void remove() {
HashedWheelBucket bucket = this.bucket;
if (bucket != null) {
bucket.remove(this);
}
}

public boolean compareAndSetState(int expected, int state) {
return STATE_UPDATER.compareAndSet(this, expected, state);
}
Expand All @@ -567,11 +560,6 @@ public boolean isExpired() {
return state() == ST_EXPIRED;
}

@Override
public HashedWheelTimeout value() {
return this;
}

public void expire() {
if (!compareAndSetState(ST_INIT, ST_EXPIRED)) {
return;
Expand Down
8 changes: 1 addition & 7 deletions common/src/main/java/io/netty/util/ThreadDeathWatcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package io.netty.util;

import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.internal.MpscLinkedQueueNode;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.StringUtil;
import io.netty.util.internal.SystemPropertyUtil;
Expand Down Expand Up @@ -213,7 +212,7 @@ private void notifyWatchees() {
}
}

private static final class Entry extends MpscLinkedQueueNode<Entry> {
private static final class Entry {
final Thread thread;
final Runnable task;
final boolean isWatch;
Expand All @@ -224,11 +223,6 @@ private static final class Entry extends MpscLinkedQueueNode<Entry> {
this.isWatch = isWatch;
}

@Override
public Entry value() {
return this;
}

@Override
public int hashCode() {
return thread.hashCode() ^ task.hashCode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package io.netty.util.concurrent;

import io.netty.util.internal.ObjectUtil;
import io.netty.util.internal.OneTimeTask;

import java.util.PriorityQueue;
import java.util.Queue;
Expand Down Expand Up @@ -195,7 +194,7 @@ <V> ScheduledFuture<V> schedule(final ScheduledFutureTask<V> task) {
if (inEventLoop()) {
scheduledTaskQueue().add(task);
} else {
execute(new OneTimeTask() {
execute(new Runnable() {
@Override
public void run() {
scheduledTaskQueue().add(task);
Expand All @@ -210,7 +209,7 @@ final void removeScheduled(final ScheduledFutureTask<?> task) {
if (inEventLoop()) {
scheduledTaskQueue().remove(task);
} else {
execute(new OneTimeTask() {
execute(new Runnable() {
@Override
public void run() {
removeScheduled(task);
Expand Down
Loading

0 comments on commit c3abb91

Please sign in to comment.