diff --git a/gbcs-cli/src/main/kotlin/net/woggioni/gbcs/cli/impl/commands/BenchmarkCommand.kt b/gbcs-cli/src/main/kotlin/net/woggioni/gbcs/cli/impl/commands/BenchmarkCommand.kt index e8263ad..be83f08 100644 --- a/gbcs-cli/src/main/kotlin/net/woggioni/gbcs/cli/impl/commands/BenchmarkCommand.kt +++ b/gbcs-cli/src/main/kotlin/net/woggioni/gbcs/cli/impl/commands/BenchmarkCommand.kt @@ -46,7 +46,8 @@ class BenchmarkCommand : GbcsCommand() { val random = Random(SecureRandom.getInstance("NativePRNGNonBlocking").nextLong()) while (true) { val key = Base64.getUrlEncoder().encode(random.nextBytes(16)).toString(Charsets.UTF_8) - val value = random.nextBytes(0x1000) + val content = random.nextInt().toByte() + val value = ByteArray(0x1000, { _ -> content }) yield(key to value) } } diff --git a/gbcs-client/src/main/kotlin/net/woggioni/gbcs/client/Client.kt b/gbcs-client/src/main/kotlin/net/woggioni/gbcs/client/Client.kt index 60fc387..85dab7e 100644 --- a/gbcs-client/src/main/kotlin/net/woggioni/gbcs/client/Client.kt +++ b/gbcs-client/src/main/kotlin/net/woggioni/gbcs/client/Client.kt @@ -30,16 +30,18 @@ import io.netty.handler.ssl.SslContextBuilder import io.netty.handler.stream.ChunkedWriteHandler import io.netty.util.concurrent.Future import io.netty.util.concurrent.GenericFutureListener +import net.woggioni.gbcs.client.impl.Parser import net.woggioni.gbcs.common.Xml import net.woggioni.gbcs.common.contextLogger import net.woggioni.gbcs.common.debug -import net.woggioni.gbcs.client.impl.Parser +import net.woggioni.gbcs.common.trace import java.net.InetSocketAddress import java.net.URI import java.nio.file.Files import java.nio.file.Path import java.security.PrivateKey import java.security.cert.X509Certificate +import java.time.Duration import java.util.Base64 import java.util.concurrent.CompletableFuture import java.util.concurrent.atomic.AtomicInteger @@ -67,6 +69,7 @@ class GbcsClient(private val profile: Configuration.Profile) : AutoCloseable { data class Profile( val serverURI: URI, val authentication: Authentication?, + val connectionTimeout : Duration?, val maxConnections : Int ) @@ -104,6 +107,9 @@ class GbcsClient(private val profile: Configuration.Profile) : AutoCloseable { option(ChannelOption.TCP_NODELAY, true) option(ChannelOption.SO_KEEPALIVE, true) remoteAddress(InetSocketAddress(host, port)) + profile.connectionTimeout?.let { + option(ChannelOption.CONNECT_TIMEOUT_MILLIS, it.toMillis().toInt()) + } } val channelPoolHandler = object : AbstractChannelPoolHandler() { @@ -114,20 +120,29 @@ class GbcsClient(private val profile: Configuration.Profile) : AutoCloseable { private var leaseCount = AtomicInteger() override fun channelReleased(ch: Channel) { - log.debug { - "Released lease ${leaseCount.decrementAndGet()}" + val activeLeases = leaseCount.decrementAndGet() + log.trace { + "Released channel ${ch.id().asShortText()}, number of active leases: $activeLeases" } } - override fun channelAcquired(ch: Channel?) { - log.debug { - "Acquired lease ${leaseCount.getAndIncrement()}" + override fun channelAcquired(ch: Channel) { + val activeLeases = leaseCount.getAndIncrement() + log.trace { + "Acquired channel ${ch.id().asShortText()}, number of active leases: $activeLeases" } } override fun channelCreated(ch: Channel) { + val connectionId = connectionCount.getAndIncrement() log.debug { - "Created connection ${connectionCount.getAndIncrement()}" + "Created connection $connectionId, total number of active connections: $connectionId" + } + ch.closeFuture().addListener { + val activeConnections = connectionCount.decrementAndGet() + log.debug { + "Closed connection $connectionId, total number of active connections: $activeConnections" + } } val pipeline: ChannelPipeline = ch.pipeline() @@ -202,6 +217,7 @@ class GbcsClient(private val profile: Configuration.Profile) : AutoCloseable { ctx.close() pipeline.removeLast() pool.release(channel) + super.exceptionCaught(ctx, cause) } }) // Prepare the HTTP request @@ -219,7 +235,7 @@ class GbcsClient(private val profile: Configuration.Profile) : AutoCloseable { set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes()) } set(HttpHeaderNames.HOST, profile.serverURI.host) - set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE) + set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE) set( HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP.toString() + "," + HttpHeaderValues.DEFLATE.toString() @@ -237,6 +253,8 @@ class GbcsClient(private val profile: Configuration.Profile) : AutoCloseable { // Set headers // Send the request channel.writeAndFlush(request) + } else { + responseFuture.completeExceptionally(channelFuture.cause()) } } }) diff --git a/gbcs-client/src/main/kotlin/net/woggioni/gbcs/client/impl/Parser.kt b/gbcs-client/src/main/kotlin/net/woggioni/gbcs/client/impl/Parser.kt index cc8a4a3..d775234 100644 --- a/gbcs-client/src/main/kotlin/net/woggioni/gbcs/client/impl/Parser.kt +++ b/gbcs-client/src/main/kotlin/net/woggioni/gbcs/client/impl/Parser.kt @@ -11,6 +11,7 @@ import java.nio.file.Path import java.security.KeyStore import java.security.PrivateKey import java.security.cert.X509Certificate +import java.time.Duration object Parser { @@ -60,7 +61,9 @@ object Parser { val maxConnections = child.renderAttribute("max-connections") ?.let(String::toInt) ?: 50 - profiles[name] = GbcsClient.Configuration.Profile(uri, authentication, maxConnections) + val connectionTimeout = child.renderAttribute("connection-timeout") + ?.let(Duration::parse) + profiles[name] = GbcsClient.Configuration.Profile(uri, authentication, connectionTimeout, maxConnections) } } } diff --git a/gbcs-client/src/main/resources/net/woggioni/gbcs/client/schema/gbcs-client.xsd b/gbcs-client/src/main/resources/net/woggioni/gbcs/client/schema/gbcs-client.xsd index 3663106..14cfa8f 100644 --- a/gbcs-client/src/main/resources/net/woggioni/gbcs/client/schema/gbcs-client.xsd +++ b/gbcs-client/src/main/resources/net/woggioni/gbcs/client/schema/gbcs-client.xsd @@ -21,6 +21,7 @@ + diff --git a/gbcs-server/src/main/kotlin/net/woggioni/gbcs/server/configuration/Parser.kt b/gbcs-server/src/main/kotlin/net/woggioni/gbcs/server/configuration/Parser.kt index d4b4081..c9282ef 100644 --- a/gbcs-server/src/main/kotlin/net/woggioni/gbcs/server/configuration/Parser.kt +++ b/gbcs-server/src/main/kotlin/net/woggioni/gbcs/server/configuration/Parser.kt @@ -21,14 +21,20 @@ import org.w3c.dom.TypeInfo import java.nio.file.Paths import java.time.Duration import java.time.temporal.ChronoUnit -import java.util.concurrent.TimeUnit object Parser { fun parse(document: Document): Configuration { val root = document.documentElement val anonymousUser = User("", null, emptySet()) - var connection: Configuration.Connection? = null - var eventExecutor: Configuration.EventExecutor? = null + var connection: Configuration.Connection = Configuration.Connection( + Duration.of(10, ChronoUnit.SECONDS), + Duration.of(10, ChronoUnit.SECONDS), + Duration.of(60, ChronoUnit.SECONDS), + Duration.of(30, ChronoUnit.SECONDS), + Duration.of(30, ChronoUnit.SECONDS), + 67108864 + ) + var eventExecutor: Configuration.EventExecutor = Configuration.EventExecutor(true) var cache: Cache? = null var host = "127.0.0.1" var port = 11080 diff --git a/gbcs-server/src/main/resources/net/woggioni/gbcs/server/gbcs-default.xml b/gbcs-server/src/main/resources/net/woggioni/gbcs/server/gbcs-default.xml index 97ca2b2..ca17e90 100644 --- a/gbcs-server/src/main/resources/net/woggioni/gbcs/server/gbcs-default.xml +++ b/gbcs-server/src/main/resources/net/woggioni/gbcs/server/gbcs-default.xml @@ -1,11 +1,17 @@ - - + + +