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 @@
-
-
+
+
+