compiler.shared.event.group
authorVladimir Krivosheev <vladimir.krivosheev@jetbrains.com>
Thu, 16 Jun 2016 11:07:23 +0000 (13:07 +0200)
committerVladimir Krivosheev <vladimir.krivosheev@jetbrains.com>
Thu, 16 Jun 2016 11:07:23 +0000 (13:07 +0200)
java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java
platform/built-in-server/src/org/jetbrains/io/SubServer.java
platform/platform-impl/src/org/jetbrains/io/BuiltInServer.java
platform/platform-impl/src/org/jetbrains/io/ChannelRegistrar.java
platform/testFramework/src/com/intellij/testFramework/ThreadTracker.java
platform/util/resources/misc/registry.properties

index 67f9a73663a0123dff848007825eb04d6e52ec01..de76d32e054f71bb4572f1de4f11bbe87d60e055 100644 (file)
@@ -36,6 +36,7 @@ import com.intellij.execution.process.ProcessHandler;
 import com.intellij.ide.DataManager;
 import com.intellij.ide.PowerSaveMode;
 import com.intellij.ide.file.BatchFileChangeListener;
+import com.intellij.idea.StartupUtil;
 import com.intellij.openapi.Disposable;
 import com.intellij.openapi.actionSystem.CommonDataKeys;
 import com.intellij.openapi.application.Application;
@@ -90,7 +91,9 @@ import gnu.trove.THashSet;
 import io.netty.bootstrap.ServerBootstrap;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelInitializer;
+import io.netty.channel.EventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.oio.OioEventLoopGroup;
 import io.netty.handler.codec.protobuf.ProtobufDecoder;
 import io.netty.handler.codec.protobuf.ProtobufEncoder;
 import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
@@ -98,6 +101,7 @@ import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
 import io.netty.util.internal.ThreadLocalRandom;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.jetbrains.io.BuiltInServer;
 import org.jetbrains.io.ChannelRegistrar;
 import org.jetbrains.io.NettyKt;
 import org.jetbrains.jps.api.*;
@@ -160,7 +164,7 @@ public class BuildManager implements Disposable {
   private final ExecutorService myRequestsProcessor = SequentialTaskExecutor.createSequentialApplicationPoolExecutor();
   private final Map<String, ProjectData> myProjectDataMap = Collections.synchronizedMap(new HashMap<String, ProjectData>());
 
-  private final BuildManagerPeriodicTask myAutoMakeTask = new BuildManagerPeriodicTask() {
+  private final BuildManagerPeriodicTask myAutoMakeTask = new BuildManagerPeriodicTask(this) {
     @Override
     protected int getDelay() {
       return Registry.intValue("compiler.automake.trigger.delay");
@@ -172,7 +176,7 @@ public class BuildManager implements Disposable {
     }
   };
 
-  private final BuildManagerPeriodicTask myDocumentSaveTask = new BuildManagerPeriodicTask() {
+  private final BuildManagerPeriodicTask myDocumentSaveTask = new BuildManagerPeriodicTask(this) {
     @Override
     protected int getDelay() {
       return Registry.intValue("compiler.document.save.trigger.delay");
@@ -1293,11 +1297,20 @@ public class BuildManager implements Disposable {
   @NotNull
   private Future<?> stopListening() {
     myListenPort = -1;
-    return myChannelRegistrar.close(true);
+    return myChannelRegistrar.close();
   }
 
   private int startListening() throws Exception {
-    final ServerBootstrap bootstrap = NettyKt.serverBootstrap(new NioEventLoopGroup(1, ConcurrencyUtil.newNamedThreadFactory("External compiler")));
+    EventLoopGroup group;
+    BuiltInServer mainServer = StartupUtil.getServer();
+    boolean isOwnEventLoopGroup = !Registry.is("compiler.shared.event.group", false) || mainServer == null || mainServer.getEventLoopGroup() instanceof OioEventLoopGroup;
+    if (isOwnEventLoopGroup) {
+      group = new NioEventLoopGroup(1, ConcurrencyUtil.newNamedThreadFactory("External compiler"));
+    }
+    else {
+      group = mainServer.getEventLoopGroup();
+    }
+    final ServerBootstrap bootstrap = NettyKt.serverBootstrap(group);
     bootstrap.childHandler(new ChannelInitializer() {
       @Override
       protected void initChannel(@NotNull Channel channel) throws Exception {
@@ -1310,7 +1323,7 @@ public class BuildManager implements Disposable {
       }
     });
     Channel serverChannel = bootstrap.bind(InetAddress.getLoopbackAddress(), 0).syncUninterruptibly().channel();
-    myChannelRegistrar.add(serverChannel);
+    myChannelRegistrar.add(serverChannel, isOwnEventLoopGroup);
     return ((InetSocketAddress)serverChannel.localAddress()).getPort();
   }
 
@@ -1337,7 +1350,7 @@ public class BuildManager implements Disposable {
   }
 
   private abstract static class BuildManagerPeriodicTask implements Runnable {
-    private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD);
+    private final Alarm myAlarm;
     private final AtomicBoolean myInProgress = new AtomicBoolean(false);
     private final Runnable myTaskRunnable = () -> {
       try {
@@ -1348,6 +1361,10 @@ public class BuildManager implements Disposable {
       }
     };
 
+    protected BuildManagerPeriodicTask(@NotNull Disposable disposable) {
+      myAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, disposable);
+    }
+
     public final void schedule() {
       cancelPendingExecution();
       final int delay = Math.max(100, getDelay());
index 67a52d832d21e1242ecbef37d5274e988d7c3b08..62aab4d2fec3e928730a7628beb4494f5008a6e2 100644 (file)
@@ -76,7 +76,7 @@ public final class SubServer implements CustomPortServerManager.CustomPortServic
 
     try {
       bootstrap.localAddress(user.isAvailableExternally() ? new InetSocketAddress(port) : NetKt.loopbackSocketAddress(port));
-      channelRegistrar.add(bootstrap.bind().syncUninterruptibly().channel());
+      channelRegistrar.add(bootstrap.bind().syncUninterruptibly().channel(), false);
       return true;
     }
     catch (Exception e) {
@@ -97,7 +97,7 @@ public final class SubServer implements CustomPortServerManager.CustomPortServic
 
   private void stop() {
     if (channelRegistrar != null) {
-      channelRegistrar.close(false);
+      channelRegistrar.close();
     }
   }
 
index 7f5bf8f055bc8486abff44f2fee9191905648e98..d432bcd9088e43507a8bba110246c58d418905d0 100644 (file)
@@ -41,7 +41,6 @@ public class BuiltInServer implements Disposable {
   private final EventLoopGroup eventLoopGroup;
   private final int port;
   private final ChannelRegistrar channelRegistrar;
-  private final boolean isOwnerOfEventLoopGroup;
 
   static {
     // IDEA-120811
@@ -54,12 +53,10 @@ public class BuiltInServer implements Disposable {
 
   private BuiltInServer(@NotNull EventLoopGroup eventLoopGroup,
                         int port,
-                        @NotNull ChannelRegistrar channelRegistrar,
-                        boolean isOwnerOfEventLoopGroup) {
+                        @NotNull ChannelRegistrar channelRegistrar) {
     this.eventLoopGroup = eventLoopGroup;
     this.port = port;
     this.channelRegistrar = channelRegistrar;
-    this.isOwnerOfEventLoopGroup = isOwnerOfEventLoopGroup;
   }
 
   @NotNull
@@ -77,7 +74,7 @@ public class BuiltInServer implements Disposable {
 
   @Override
   public void dispose() {
-    channelRegistrar.close(isOwnerOfEventLoopGroup);
+    channelRegistrar.close();
     Logger.getInstance(BuiltInServer.class).info("web server stopped");
   }
 
@@ -118,8 +115,8 @@ public class BuiltInServer implements Disposable {
     ChannelRegistrar channelRegistrar = new ChannelRegistrar();
     ServerBootstrap bootstrap = NettyKt.serverBootstrap(eventLoopGroup);
     configureChildHandler(bootstrap, channelRegistrar, handler);
-    int port = bind(firstPort, portsCount, tryAnyPort, bootstrap, channelRegistrar);
-    return new BuiltInServer(eventLoopGroup, port, channelRegistrar, isEventLoopGroupOwner);
+    int port = bind(firstPort, portsCount, tryAnyPort, bootstrap, channelRegistrar, isEventLoopGroupOwner);
+    return new BuiltInServer(eventLoopGroup, port, channelRegistrar);
   }
 
   static void configureChildHandler(@NotNull ServerBootstrap bootstrap,
@@ -138,7 +135,8 @@ public class BuiltInServer implements Disposable {
                           int portsCount,
                           boolean tryAnyPort,
                           @NotNull ServerBootstrap bootstrap,
-                          @NotNull ChannelRegistrar channelRegistrar) throws Exception {
+                          @NotNull ChannelRegistrar channelRegistrar,
+                          boolean isEventLoopGroupOwner) throws Exception {
     InetAddress address = InetAddress.getLoopbackAddress();
 
     for (int i = 0; i < portsCount; i++) {
@@ -150,7 +148,7 @@ public class BuiltInServer implements Disposable {
 
       ChannelFuture future = bootstrap.bind(address, port).awaitUninterruptibly();
       if (future.isSuccess()) {
-        channelRegistrar.add(future.channel());
+        channelRegistrar.add(future.channel(), isEventLoopGroupOwner);
         return port;
       }
       else if (!tryAnyPort && i == portsCount - 1) {
@@ -161,7 +159,7 @@ public class BuiltInServer implements Disposable {
     Logger.getInstance(BuiltInServer.class).info("We cannot bind to our default range, so, try to bind to any free port");
     ChannelFuture future = bootstrap.bind(address, 0).awaitUninterruptibly();
     if (future.isSuccess()) {
-      channelRegistrar.add(future.channel());
+      channelRegistrar.add(future.channel(), isEventLoopGroupOwner);
       return ((InetSocketAddress)future.channel().localAddress()).getPort();
     }
     ExceptionUtil.rethrowAll(future.cause());
index 7af34eed8df3f265694e133e8ab66b83f0971cf5..e0698341d4dcb25f6ec0fc8863fc9ca9e007885e 100644 (file)
@@ -32,12 +32,14 @@ public final class ChannelRegistrar extends ChannelInboundHandlerAdapter {
   private static final Logger LOG = Logger.getInstance(ChannelRegistrar.class);
 
   private final ChannelGroup openChannels = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE);
+  private boolean isEventLoopGroupOwner;
 
   public boolean isEmpty() {
     return openChannels.isEmpty();
   }
 
-  public void add(@NotNull Channel serverChannel) {
+  public void add(@NotNull Channel serverChannel, boolean isOwnEventLoopGroup) {
+    this.isEventLoopGroupOwner = isOwnEventLoopGroup;
     assert serverChannel instanceof ServerChannel;
     openChannels.add(serverChannel);
   }
@@ -50,12 +52,13 @@ public final class ChannelRegistrar extends ChannelInboundHandlerAdapter {
     super.channelActive(context);
   }
 
-  public void close() {
-    close(true);
+  @NotNull
+  public Future<?> close() {
+    return close(isEventLoopGroupOwner);
   }
 
   @NotNull
-  public Future<?> close(boolean shutdownEventLoopGroup) {
+  private Future<?> close(boolean shutdownEventLoopGroup) {
     EventLoopGroup eventLoopGroup = null;
     if (shutdownEventLoopGroup) {
       for (Channel channel : openChannels) {
index 5ed6d1a04b945908dda153aff2ec9cad941bd722..a22bab6b4e571c7f4e6c8203c8a144b530447fbb 100644 (file)
@@ -82,6 +82,7 @@ public class ThreadTracker {
     wellKnownOffenders.add("main");
     wellKnownOffenders.add("Monitor Ctrl-Break");
     wellKnownOffenders.add("Netty ");
+    wellKnownOffenders.add("External compiler");
     wellKnownOffenders.add("Reference Handler");
     wellKnownOffenders.add("RMI TCP Connection");
     wellKnownOffenders.add("Signal Dispatcher");
index 462bff4781d12bbfebdceaaf4d2993de5e414cb4..0c74a455cf0b286122eaab8250e542e845c36ee4 100644 (file)
@@ -255,6 +255,8 @@ compiler.document.save.trigger.delay.description=Delay in milliseconds before tr
 compiler.build.data.unused.threshold=30
 compiler.build.data.unused.threshold.description=If project is not opened for the specified number of days, its build data will be cleared to save disk space
 
+compiler.shared.event.group=false
+
 vcs.annotations.preload=false
 vcs.showConsole=true
 vcs.log.bek.sort.disabled=false