BuiltInServerManager.createClientBootstrap() to reuse event loop group

This commit is contained in:
Vladimir Krivosheev
2019-03-13 17:25:22 +01:00
parent 9a598497bf
commit cc8a85cd64
8 changed files with 57 additions and 58 deletions

View File

@@ -1,23 +1,10 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.ide
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.util.Url
import io.netty.bootstrap.Bootstrap
import java.net.URLConnection
@@ -31,6 +18,8 @@ abstract class BuiltInServerManager {
abstract val serverDisposable: Disposable?
abstract fun createClientBootstrap(): Bootstrap
abstract fun waitForStart(): BuiltInServerManager
abstract fun isOnBuiltInWebServer(url: Url?): Boolean

View File

@@ -12,7 +12,7 @@ import org.jetbrains.concurrency.AsyncPromise
import org.jetbrains.concurrency.Promise
import org.jetbrains.concurrency.catchError
import org.jetbrains.concurrency.resolvedPromise
import org.jetbrains.io.NettyUtil.nioClientBootstrap
import org.jetbrains.ide.BuiltInServerManager
import java.util.concurrent.atomic.AtomicReference
abstract class SingleConnectionNetService(project: Project) : NetService(project) {
@@ -26,7 +26,7 @@ abstract class SingleConnectionNetService(project: Project) : NetService(project
protected abstract fun configureBootstrap(bootstrap: Bootstrap, errorOutputConsumer: Consumer<String>)
final override fun connectToProcess(promise: AsyncPromise<OSProcessHandler>, port: Int, processHandler: OSProcessHandler, errorOutputConsumer: Consumer<String>) {
val bootstrap = nioClientBootstrap()
val bootstrap = BuiltInServerManager.getInstance().createClientBootstrap()
configureBootstrap(bootstrap, errorOutputConsumer)
this.bootstrap = bootstrap

View File

@@ -20,6 +20,8 @@ import com.intellij.util.concurrency.AppExecutorUtil
import com.intellij.util.net.NetUtils
import org.jetbrains.builtInWebServer.*
import org.jetbrains.io.BuiltInServer
import org.jetbrains.io.BuiltInServer.Companion.recommendedWorkerCount
import org.jetbrains.io.NettyUtil
import org.jetbrains.io.SubServer
import java.io.IOException
import java.net.InetAddress
@@ -49,6 +51,8 @@ class BuiltInServerManagerImpl : BuiltInServerManager() {
}
}
override fun createClientBootstrap() = NettyUtil.nioClientBootstrap(server!!.eventLoopGroup)
companion object {
private val LOG = logger<BuiltInServerManager>()
@@ -116,7 +120,7 @@ class BuiltInServerManagerImpl : BuiltInServerManager() {
val mainServer = StartupUtil.getServer()
@Suppress("DEPRECATION")
server = when {
mainServer == null || mainServer.eventLoopGroup is io.netty.channel.oio.OioEventLoopGroup -> BuiltInServer.start(2, defaultPort, PORTS_COUNT)
mainServer == null || mainServer.eventLoopGroup is io.netty.channel.oio.OioEventLoopGroup -> BuiltInServer.start(recommendedWorkerCount, defaultPort, PORTS_COUNT)
else -> BuiltInServer.start(mainServer.eventLoopGroup, false, defaultPort, PORTS_COUNT, true, null)
}
bindCustomPorts(server!!)

View File

@@ -6,6 +6,6 @@
<depends>com.intellij.modules.xml</depends>
<extensions defaultExtensionNs="org.jetbrains">
<binaryRequestHandler implementation="org.jetbrains.ide.BinaryRequestHandlerTest$MyBinaryRequestHandler"/>
<binaryRequestHandler implementation="org.jetbrains.ide.MyBinaryRequestHandler"/>
</extensions>
</idea-plugin>

View File

@@ -1,7 +1,7 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.ide
import com.intellij.testFramework.ProjectRule
import com.intellij.testFramework.ApplicationRule
import com.intellij.util.concurrency.Semaphore
import com.intellij.util.io.handler
import com.intellij.util.net.loopbackSocketAddress
@@ -15,7 +15,6 @@ import org.jetbrains.concurrency.Promise
import org.jetbrains.io.ChannelExceptionHandler
import org.jetbrains.io.Decoder
import org.jetbrains.io.MessageDecoder
import org.jetbrains.io.NettyUtil.nioClientBootstrap
import org.junit.ClassRule
import org.junit.Test
import java.util.*
@@ -25,14 +24,17 @@ import java.util.concurrent.TimeUnit
internal class BinaryRequestHandlerTest {
companion object {
@JvmField
@ClassRule val projectRule = ProjectRule()
@ClassRule
val appRule = ApplicationRule()
}
@Test fun test() {
@Test
fun test() {
val text = "Hello!"
val result = AsyncPromise<String>()
val bootstrap = nioClientBootstrap().handler {
val builtInServerManager = BuiltInServerManager.getInstance().waitForStart()
val bootstrap = builtInServerManager.createClientBootstrap().handler {
it.pipeline().addLast(object : Decoder() {
override fun messageReceived(context: ChannelHandlerContext, input: ByteBuf) {
val requiredLength = 4 + text.length
@@ -44,7 +46,7 @@ internal class BinaryRequestHandlerTest {
}, ChannelExceptionHandler.getInstance())
}
val port = BuiltInServerManager.getInstance().waitForStart().port
val port = builtInServerManager.port
val channel = bootstrap.connect(loopbackSocketAddress(port)).syncUninterruptibly().channel()
val buffer = channel.alloc().buffer()
buffer.writeByte('C'.toInt())
@@ -76,43 +78,39 @@ internal class BinaryRequestHandlerTest {
channel.close()
}
}
}
class MyBinaryRequestHandler : BinaryRequestHandler() {
companion object {
val ID: UUID = UUID.fromString("E5068DD6-1DB7-437C-A3FC-3CA53B6E1AC9")
private class MyBinaryRequestHandler : BinaryRequestHandler() {
companion object {
val ID: UUID = UUID.fromString("E5068DD6-1DB7-437C-A3FC-3CA53B6E1AC9")
}
override fun getId(): UUID = ID
override fun getInboundHandler(context: ChannelHandlerContext): ChannelHandler = MyDecoder()
private class MyDecoder : MessageDecoder() {
private var state = State.HEADER
private enum class State {
HEADER,
CONTENT
}
override fun getId(): UUID {
return ID
}
override fun messageReceived(context: ChannelHandlerContext, input: ByteBuf) {
while (true) {
when (state) {
State.HEADER -> {
val buffer = getBufferIfSufficient(input, 2, context) ?: return
contentLength = buffer.readUnsignedShort()
state = State.CONTENT
}
override fun getInboundHandler(context: ChannelHandlerContext): ChannelHandler {
return MyDecoder()
}
State.CONTENT -> {
val messageText = readChars(input) ?: return
private class MyDecoder : MessageDecoder() {
private var state = State.HEADER
private enum class State {
HEADER,
CONTENT
}
override fun messageReceived(context: ChannelHandlerContext, input: ByteBuf) {
while (true) {
when (state) {
State.HEADER -> {
val buffer = getBufferIfSufficient(input, 2, context) ?: return
contentLength = buffer.readUnsignedShort()
state = State.CONTENT
}
State.CONTENT -> {
val messageText = readChars(input) ?: return
state = State.HEADER
context.writeAndFlush(Unpooled.copiedBuffer("got-$messageText", Charsets.UTF_8))
}
state = State.HEADER
context.writeAndFlush(Unpooled.copiedBuffer("got-$messageText", Charsets.UTF_8))
}
}
}

View File

@@ -133,7 +133,7 @@ public final class SocketLock {
myToken = UUID.randomUUID().toString();
// should be not inlined because handler created for each connected channel
String[] lockedPaths = {myConfigPath, mySystemPath};
myServer = BuiltInServer.startNioOrOio(2, 6942, 50, false, () -> {
myServer = BuiltInServer.startNioOrOio(BuiltInServer.getRecommendedWorkerCount(), 6942, 50, false, () -> {
//noinspection CodeBlock2Expr
return new MyChannelInboundHandler(lockedPaths, myActivateListener, myToken);
});

View File

@@ -39,6 +39,10 @@ class BuiltInServer private constructor(val eventLoopGroup: EventLoopGroup, val
}
}
@JvmStatic
val recommendedWorkerCount: Int
get() = if (PlatformUtils.isIdeaCommunity()) 2 else 3
@Throws(Exception::class)
fun start(workerCount: Int, firstPort: Int, portsCount: Int, tryAnyPort: Boolean = false, handler: (() -> ChannelHandler)? = null): BuiltInServer {
return start(MultiThreadEventLoopGroup(workerCount, BuiltInServerThreadFactory()), true, firstPort, portsCount, tryAnyPort, handler)

View File

@@ -77,7 +77,11 @@ public final class NettyUtil {
return (throwable instanceof ChannelException && message.startsWith("Failed to bind to: "));
}
/**
* @deprecated Use BuiltInServerManager.getInstance().createClientBootstrap()
*/
@NotNull
@Deprecated
public static Bootstrap nioClientBootstrap() {
return nioClientBootstrap(NettyKt.MultiThreadEventLoopGroup(2));
}