Compare commits
1 Commits
native-tra
...
37f7b9c9ce
Author | SHA1 | Date | |
---|---|---|---|
37f7b9c9ce
|
@@ -5,12 +5,12 @@ WORKDIR /home/luser
|
|||||||
|
|
||||||
FROM base-release AS release
|
FROM base-release AS release
|
||||||
ADD gbcs-cli-envelope-*.jar gbcs.jar
|
ADD gbcs-cli-envelope-*.jar gbcs.jar
|
||||||
ENTRYPOINT ["java", "-XX:+UseZGC", "-XX:+ZGenerational", "-jar", "/home/luser/gbcs.jar", "server"]
|
ENTRYPOINT ["java", "-jar", "/home/luser/gbcs.jar", "server"]
|
||||||
|
|
||||||
FROM base-release AS release-memcache
|
FROM base-release AS release-memcache
|
||||||
ADD --chown=luser:luser gbcs-cli-envelope-*.jar gbcs.jar
|
ADD --chown=luser:luser gbcs-cli-envelope-*.jar gbcs.jar
|
||||||
RUN mkdir plugins
|
RUN mkdir plugins
|
||||||
WORKDIR /home/luser/plugins
|
WORKDIR /home/luser/plugins
|
||||||
RUN --mount=type=bind,source=.,target=/build/distributions tar -xf /build/distributions/gbcs-server-memcache*.tar
|
RUN --mount=type=bind,source=.,target=/build/distributions tar -xf /build/distributions/gbcs-server-memcached*.tar
|
||||||
WORKDIR /home/luser
|
WORKDIR /home/luser
|
||||||
ENTRYPOINT ["java", "-XX:+UseZGC", "-XX:+ZGenerational", "-jar", "/home/luser/gbcs.jar", "server"]
|
ENTRYPOINT ["java", "-jar", "/home/luser/gbcs.jar", "server"]
|
||||||
|
@@ -27,7 +27,6 @@ public class Configuration {
|
|||||||
Cache cache;
|
Cache cache;
|
||||||
Authentication authentication;
|
Authentication authentication;
|
||||||
Tls tls;
|
Tls tls;
|
||||||
boolean useNativeTransport;
|
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
public static class EventExecutor {
|
public static class EventExecutor {
|
||||||
@@ -152,8 +151,7 @@ public class Configuration {
|
|||||||
Map<String, Group> groups,
|
Map<String, Group> groups,
|
||||||
Cache cache,
|
Cache cache,
|
||||||
Authentication authentication,
|
Authentication authentication,
|
||||||
Tls tls,
|
Tls tls
|
||||||
boolean useNativeTransport
|
|
||||||
) {
|
) {
|
||||||
return new Configuration(
|
return new Configuration(
|
||||||
host,
|
host,
|
||||||
@@ -166,8 +164,7 @@ public class Configuration {
|
|||||||
groups,
|
groups,
|
||||||
cache,
|
cache,
|
||||||
authentication,
|
authentication,
|
||||||
tls,
|
tls
|
||||||
useNativeTransport
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -32,13 +32,6 @@ configurations {
|
|||||||
canBeResolved = true
|
canBeResolved = true
|
||||||
visible = true
|
visible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
nativeLibraries {
|
|
||||||
transitive = false
|
|
||||||
canBeConsumed = false
|
|
||||||
canBeResolved = true
|
|
||||||
visible = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
envelopeJar {
|
envelopeJar {
|
||||||
@@ -60,8 +53,6 @@ dependencies {
|
|||||||
// runtimeOnly catalog.slf4j.jdk14
|
// runtimeOnly catalog.slf4j.jdk14
|
||||||
runtimeOnly catalog.logback.classic
|
runtimeOnly catalog.logback.classic
|
||||||
// runtimeOnly catalog.slf4j.simple
|
// runtimeOnly catalog.slf4j.simple
|
||||||
|
|
||||||
nativeLibraries group: 'io.netty', name: 'netty-transport-native-epoll', version: catalog.versions.netty.get(), classifier: 'linux-x86_64'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Provider<EnvelopeJarTask> envelopeJarTaskProvider = tasks.named('envelopeJar', EnvelopeJarTask.class) {
|
Provider<EnvelopeJarTask> envelopeJarTaskProvider = tasks.named('envelopeJar', EnvelopeJarTask.class) {
|
||||||
@@ -76,9 +67,6 @@ Provider<EnvelopeJarTask> envelopeJarTaskProvider = tasks.named('envelopeJar', E
|
|||||||
// systemProperties['org.slf4j.simpleLogger.log.com.google.code.yanf4j'] = 'warn'
|
// systemProperties['org.slf4j.simpleLogger.log.com.google.code.yanf4j'] = 'warn'
|
||||||
// systemProperties['org.slf4j.simpleLogger.log.net.rubyeye.xmemcached'] = 'warn'
|
// systemProperties['org.slf4j.simpleLogger.log.net.rubyeye.xmemcached'] = 'warn'
|
||||||
// systemProperties['org.slf4j.simpleLogger.dateTimeFormat'] = 'yyyy-MM-dd\'T\'HH:mm:ss.SSSZ'
|
// systemProperties['org.slf4j.simpleLogger.dateTimeFormat'] = 'yyyy-MM-dd\'T\'HH:mm:ss.SSSZ'
|
||||||
from {
|
|
||||||
configurations.nativeLibraries.collect { it.isDirectory() ? it : zipTree(it) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.named(NativeImagePlugin.CONFIGURE_NATIVE_IMAGE_TASK_NAME, NativeImageConfigurationTask) {
|
tasks.named(NativeImagePlugin.CONFIGURE_NATIVE_IMAGE_TASK_NAME, NativeImageConfigurationTask) {
|
||||||
|
@@ -5,7 +5,6 @@ import net.woggioni.gbcs.cli.impl.GbcsCommand
|
|||||||
import net.woggioni.gbcs.cli.impl.commands.BenchmarkCommand
|
import net.woggioni.gbcs.cli.impl.commands.BenchmarkCommand
|
||||||
import net.woggioni.gbcs.cli.impl.commands.ClientCommand
|
import net.woggioni.gbcs.cli.impl.commands.ClientCommand
|
||||||
import net.woggioni.gbcs.cli.impl.commands.GetCommand
|
import net.woggioni.gbcs.cli.impl.commands.GetCommand
|
||||||
import net.woggioni.gbcs.cli.impl.commands.HealthCheckCommand
|
|
||||||
import net.woggioni.gbcs.cli.impl.commands.PasswordHashCommand
|
import net.woggioni.gbcs.cli.impl.commands.PasswordHashCommand
|
||||||
import net.woggioni.gbcs.cli.impl.commands.PutCommand
|
import net.woggioni.gbcs.cli.impl.commands.PutCommand
|
||||||
import net.woggioni.gbcs.cli.impl.commands.ServerCommand
|
import net.woggioni.gbcs.cli.impl.commands.ServerCommand
|
||||||
@@ -25,12 +24,8 @@ class GradleBuildCacheServerCli : GbcsCommand() {
|
|||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun main(vararg args: String) {
|
fun main(vararg args: String) {
|
||||||
val currentClassLoader = GradleBuildCacheServerCli::class.java.classLoader
|
Thread.currentThread().contextClassLoader = GradleBuildCacheServerCli::class.java.classLoader
|
||||||
Thread.currentThread().contextClassLoader = currentClassLoader
|
|
||||||
if(currentClassLoader.javaClass.name == "net.woggioni.envelope.loader.ModuleClassLoader") {
|
|
||||||
//We're running in an envelope jar and custom URL protocols won't work
|
|
||||||
GbcsUrlStreamHandlerFactory.install()
|
GbcsUrlStreamHandlerFactory.install()
|
||||||
}
|
|
||||||
val log = contextLogger()
|
val log = contextLogger()
|
||||||
val app = Application.builder("gbcs")
|
val app = Application.builder("gbcs")
|
||||||
.configurationDirectoryEnvVar("GBCS_CONFIGURATION_DIR")
|
.configurationDirectoryEnvVar("GBCS_CONFIGURATION_DIR")
|
||||||
@@ -49,7 +44,6 @@ class GradleBuildCacheServerCli : GbcsCommand() {
|
|||||||
addSubcommand(BenchmarkCommand())
|
addSubcommand(BenchmarkCommand())
|
||||||
addSubcommand(PutCommand())
|
addSubcommand(PutCommand())
|
||||||
addSubcommand(GetCommand())
|
addSubcommand(GetCommand())
|
||||||
addSubcommand(HealthCheckCommand())
|
|
||||||
})
|
})
|
||||||
System.exit(commandLine.execute(*args))
|
System.exit(commandLine.execute(*args))
|
||||||
}
|
}
|
||||||
|
@@ -46,7 +46,7 @@ class BenchmarkCommand : GbcsCommand() {
|
|||||||
clientCommand.configuration.profiles[profileName]
|
clientCommand.configuration.profiles[profileName]
|
||||||
?: throw IllegalArgumentException("Profile $profileName does not exist in configuration")
|
?: throw IllegalArgumentException("Profile $profileName does not exist in configuration")
|
||||||
}
|
}
|
||||||
GradleBuildCacheClient(profile).use { client ->
|
val client = GradleBuildCacheClient(profile)
|
||||||
|
|
||||||
val entryGenerator = sequence {
|
val entryGenerator = sequence {
|
||||||
val random = Random(SecureRandom.getInstance("NativePRNGNonBlocking").nextLong())
|
val random = Random(SecureRandom.getInstance("NativePRNGNonBlocking").nextLong())
|
||||||
@@ -81,8 +81,6 @@ class BenchmarkCommand : GbcsCommand() {
|
|||||||
semaphore.release()
|
semaphore.release()
|
||||||
completionCounter.incrementAndGet()
|
completionCounter.incrementAndGet()
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Thread.sleep(0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,10 +103,9 @@ class BenchmarkCommand : GbcsCommand() {
|
|||||||
val completionCounter = AtomicLong(0)
|
val completionCounter = AtomicLong(0)
|
||||||
val semaphore = Semaphore(profile.maxConnections * 3)
|
val semaphore = Semaphore(profile.maxConnections * 3)
|
||||||
val start = Instant.now()
|
val start = Instant.now()
|
||||||
val it = entries.iterator()
|
entries.forEach { entry ->
|
||||||
while (completionCounter.get() < entries.size) {
|
semaphore.acquire()
|
||||||
if (it.hasNext()) {
|
|
||||||
val entry = it.next()
|
|
||||||
val future = client.get(entry.first).thenApply {
|
val future = client.get(entry.first).thenApply {
|
||||||
if (it == null) {
|
if (it == null) {
|
||||||
log.error {
|
log.error {
|
||||||
@@ -124,9 +121,6 @@ class BenchmarkCommand : GbcsCommand() {
|
|||||||
completionCounter.incrementAndGet()
|
completionCounter.incrementAndGet()
|
||||||
semaphore.release()
|
semaphore.release()
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Thread.sleep(0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
val end = Instant.now()
|
val end = Instant.now()
|
||||||
log.info {
|
log.info {
|
||||||
@@ -139,4 +133,3 @@ class BenchmarkCommand : GbcsCommand() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
@@ -1,45 +0,0 @@
|
|||||||
package net.woggioni.gbcs.cli.impl.commands
|
|
||||||
|
|
||||||
import net.woggioni.gbcs.cli.impl.GbcsCommand
|
|
||||||
import net.woggioni.gbcs.client.GradleBuildCacheClient
|
|
||||||
import net.woggioni.gbcs.common.contextLogger
|
|
||||||
import picocli.CommandLine
|
|
||||||
import java.security.SecureRandom
|
|
||||||
import kotlin.random.Random
|
|
||||||
|
|
||||||
@CommandLine.Command(
|
|
||||||
name = "health",
|
|
||||||
description = ["Check server health"],
|
|
||||||
showDefaultValues = true
|
|
||||||
)
|
|
||||||
class HealthCheckCommand : GbcsCommand() {
|
|
||||||
private val log = contextLogger()
|
|
||||||
|
|
||||||
@CommandLine.Spec
|
|
||||||
private lateinit var spec: CommandLine.Model.CommandSpec
|
|
||||||
|
|
||||||
override fun run() {
|
|
||||||
val clientCommand = spec.parent().userObject() as ClientCommand
|
|
||||||
val profile = clientCommand.profileName.let { profileName ->
|
|
||||||
clientCommand.configuration.profiles[profileName]
|
|
||||||
?: throw IllegalArgumentException("Profile $profileName does not exist in configuration")
|
|
||||||
}
|
|
||||||
GradleBuildCacheClient(profile).use { client ->
|
|
||||||
val random = Random(SecureRandom.getInstance("NativePRNGNonBlocking").nextLong())
|
|
||||||
val nonce = ByteArray(0xa0)
|
|
||||||
random.nextBytes(nonce)
|
|
||||||
client.healthCheck(nonce).thenApply { value ->
|
|
||||||
if(value == null) {
|
|
||||||
throw IllegalStateException("Empty response from server")
|
|
||||||
}
|
|
||||||
for(i in 0 until nonce.size) {
|
|
||||||
for(j in value.size - nonce.size until nonce.size) {
|
|
||||||
if(nonce[i] != value[j]) {
|
|
||||||
throw IllegalStateException("Server nonce does not match")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.get()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -2,7 +2,6 @@ package net.woggioni.gbcs.cli.impl.commands
|
|||||||
|
|
||||||
import net.woggioni.gbcs.api.Configuration
|
import net.woggioni.gbcs.api.Configuration
|
||||||
import net.woggioni.gbcs.cli.impl.GbcsCommand
|
import net.woggioni.gbcs.cli.impl.GbcsCommand
|
||||||
import net.woggioni.gbcs.cli.impl.converters.DurationConverter
|
|
||||||
import net.woggioni.gbcs.common.contextLogger
|
import net.woggioni.gbcs.common.contextLogger
|
||||||
import net.woggioni.gbcs.common.debug
|
import net.woggioni.gbcs.common.debug
|
||||||
import net.woggioni.gbcs.common.info
|
import net.woggioni.gbcs.common.info
|
||||||
@@ -14,7 +13,6 @@ import picocli.CommandLine
|
|||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.time.Duration
|
|
||||||
|
|
||||||
@CommandLine.Command(
|
@CommandLine.Command(
|
||||||
name = "server",
|
name = "server",
|
||||||
@@ -37,14 +35,6 @@ class ServerCommand(app : Application) : GbcsCommand() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@CommandLine.Option(
|
|
||||||
names = ["-t", "--timeout"],
|
|
||||||
description = ["Exit after the specified time"],
|
|
||||||
paramLabel = "TIMEOUT",
|
|
||||||
converter = [DurationConverter::class]
|
|
||||||
)
|
|
||||||
private var timeout: Duration? = null
|
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["-c", "--config-file"],
|
names = ["-c", "--config-file"],
|
||||||
description = ["Read the application configuration from this file"],
|
description = ["Read the application configuration from this file"],
|
||||||
@@ -52,6 +42,10 @@ class ServerCommand(app : Application) : GbcsCommand() {
|
|||||||
)
|
)
|
||||||
private var configurationFile: Path = findConfigurationFile(app, "gbcs-server.xml")
|
private var configurationFile: Path = findConfigurationFile(app, "gbcs-server.xml")
|
||||||
|
|
||||||
|
val configuration : Configuration by lazy {
|
||||||
|
GradleBuildCacheServer.loadConfiguration(configurationFile)
|
||||||
|
}
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!Files.exists(configurationFile)) {
|
if (!Files.exists(configurationFile)) {
|
||||||
Files.createDirectories(configurationFile.parent)
|
Files.createDirectories(configurationFile.parent)
|
||||||
@@ -67,11 +61,7 @@ class ServerCommand(app : Application) : GbcsCommand() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val server = GradleBuildCacheServer(configuration)
|
val server = GradleBuildCacheServer(configuration)
|
||||||
server.run().use { server ->
|
server.run().use {
|
||||||
timeout?.let {
|
|
||||||
Thread.sleep(it)
|
|
||||||
server.shutdown()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,11 +0,0 @@
|
|||||||
package net.woggioni.gbcs.cli.impl.converters
|
|
||||||
|
|
||||||
import picocli.CommandLine
|
|
||||||
import java.time.Duration
|
|
||||||
|
|
||||||
|
|
||||||
class DurationConverter : CommandLine.ITypeConverter<Duration> {
|
|
||||||
override fun convert(value: String): Duration {
|
|
||||||
return Duration.parse(value)
|
|
||||||
}
|
|
||||||
}
|
|
@@ -15,4 +15,6 @@
|
|||||||
<root level="info">
|
<root level="info">
|
||||||
<appender-ref ref="console"/>
|
<appender-ref ref="console"/>
|
||||||
</root>
|
</root>
|
||||||
|
<logger name="com.google.code.yanf4j" level="warn"/>
|
||||||
|
<logger name="net.rubyeye.xmemcached" level="warn"/>
|
||||||
</configuration>
|
</configuration>
|
@@ -213,25 +213,6 @@ class GradleBuildCacheClient(private val profile: Configuration.Profile) : AutoC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun healthCheck(nonce: ByteArray): CompletableFuture<ByteArray?> {
|
|
||||||
return executeWithRetry {
|
|
||||||
sendRequest(profile.serverURI, HttpMethod.TRACE, nonce)
|
|
||||||
}.thenApply {
|
|
||||||
val status = it.status()
|
|
||||||
if (it.status() != HttpResponseStatus.OK) {
|
|
||||||
throw HttpException(status)
|
|
||||||
} else {
|
|
||||||
it.content()
|
|
||||||
}
|
|
||||||
}.thenApply { maybeByteBuf ->
|
|
||||||
maybeByteBuf?.let {
|
|
||||||
val result = ByteArray(it.readableBytes())
|
|
||||||
it.getBytes(0, result)
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun get(key: String): CompletableFuture<ByteArray?> {
|
fun get(key: String): CompletableFuture<ByteArray?> {
|
||||||
return executeWithRetry {
|
return executeWithRetry {
|
||||||
sendRequest(profile.serverURI.resolve(key), HttpMethod.GET, null)
|
sendRequest(profile.serverURI.resolve(key), HttpMethod.GET, null)
|
||||||
|
@@ -1,19 +0,0 @@
|
|||||||
package net.woggioni.gbcs.common
|
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.io.OutputStream
|
|
||||||
|
|
||||||
class ByteBufOutputStream(private val buf : ByteBuf) : OutputStream() {
|
|
||||||
override fun write(b: Int) {
|
|
||||||
buf.writeByte(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun write(b: ByteArray, off: Int, len: Int) {
|
|
||||||
buf.writeBytes(b, off, len)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun close() {
|
|
||||||
buf.release()
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,7 +0,0 @@
|
|||||||
package net.woggioni.gbcs.common
|
|
||||||
|
|
||||||
class ResourceNotFoundException(msg : String? = null, cause: Throwable? = null) : RuntimeException(msg, cause) {
|
|
||||||
}
|
|
||||||
|
|
||||||
class ModuleNotFoundException(msg : String? = null, cause: Throwable? = null) : RuntimeException(msg, cause) {
|
|
||||||
}
|
|
@@ -36,17 +36,13 @@ class GbcsUrlStreamHandlerFactory : URLStreamHandlerProvider() {
|
|||||||
private class JpmsHandler : URLStreamHandler() {
|
private class JpmsHandler : URLStreamHandler() {
|
||||||
|
|
||||||
override fun openConnection(u: URL): URLConnection {
|
override fun openConnection(u: URL): URLConnection {
|
||||||
val moduleName = u.host
|
|
||||||
val thisModule = javaClass.module
|
val thisModule = javaClass.module
|
||||||
val sourceModule =
|
val sourceModule = Optional.ofNullable(thisModule)
|
||||||
thisModule
|
.map { obj: Module -> obj.layer }
|
||||||
?.let(Module::getLayer)
|
.flatMap { layer: ModuleLayer ->
|
||||||
?.let { layer: ModuleLayer ->
|
val moduleName = u.host
|
||||||
layer.findModule(moduleName).orElse(null)
|
layer.findModule(moduleName)
|
||||||
} ?: if(thisModule.layer == null) {
|
}.orElse(thisModule)
|
||||||
thisModule
|
|
||||||
} else throw ModuleNotFoundException("Module '$moduleName' not found")
|
|
||||||
|
|
||||||
return JpmsResourceURLConnection(u, sourceModule)
|
return JpmsResourceURLConnection(u, sourceModule)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,9 +53,7 @@ class GbcsUrlStreamHandlerFactory : URLStreamHandlerProvider() {
|
|||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override fun getInputStream(): InputStream {
|
override fun getInputStream(): InputStream {
|
||||||
val resource = getURL().path
|
return module.getResourceAsStream(getURL().path)
|
||||||
return module.getResourceAsStream(resource)
|
|
||||||
?: throw ResourceNotFoundException("Resource '$resource' not found in module '${module.name}'")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -24,7 +24,6 @@ import io.netty.handler.codec.memcache.binary.FullBinaryMemcacheRequest
|
|||||||
import io.netty.handler.codec.memcache.binary.FullBinaryMemcacheResponse
|
import io.netty.handler.codec.memcache.binary.FullBinaryMemcacheResponse
|
||||||
import io.netty.util.concurrent.GenericFutureListener
|
import io.netty.util.concurrent.GenericFutureListener
|
||||||
import net.woggioni.gbcs.common.ByteBufInputStream
|
import net.woggioni.gbcs.common.ByteBufInputStream
|
||||||
import net.woggioni.gbcs.common.ByteBufOutputStream
|
|
||||||
import net.woggioni.gbcs.common.GBCS.digest
|
import net.woggioni.gbcs.common.GBCS.digest
|
||||||
import net.woggioni.gbcs.common.HostAndPort
|
import net.woggioni.gbcs.common.HostAndPort
|
||||||
import net.woggioni.gbcs.common.contextLogger
|
import net.woggioni.gbcs.common.contextLogger
|
||||||
@@ -115,14 +114,13 @@ class MemcacheClient(private val cfg: MemcacheCacheConfiguration) : AutoCloseabl
|
|||||||
val channel = channelFuture.now
|
val channel = channelFuture.now
|
||||||
val pipeline = channel.pipeline()
|
val pipeline = channel.pipeline()
|
||||||
channel.pipeline()
|
channel.pipeline()
|
||||||
.addLast("client-handler", object : SimpleChannelInboundHandler<FullBinaryMemcacheResponse>() {
|
.addLast("handler", object : SimpleChannelInboundHandler<FullBinaryMemcacheResponse>() {
|
||||||
override fun channelRead0(
|
override fun channelRead0(
|
||||||
ctx: ChannelHandlerContext,
|
ctx: ChannelHandlerContext,
|
||||||
msg: FullBinaryMemcacheResponse
|
msg: FullBinaryMemcacheResponse
|
||||||
) {
|
) {
|
||||||
pipeline.removeLast()
|
pipeline.removeLast()
|
||||||
pool.release(channel)
|
pool.release(channel)
|
||||||
msg.touch("The method's caller must remember to release this")
|
|
||||||
response.complete(msg.retain())
|
response.complete(msg.retain())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +135,6 @@ class MemcacheClient(private val cfg: MemcacheCacheConfiguration) : AutoCloseabl
|
|||||||
response.completeExceptionally(ex)
|
response.completeExceptionally(ex)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
request.touch()
|
|
||||||
channel.writeAndFlush(request)
|
channel.writeAndFlush(request)
|
||||||
} else {
|
} else {
|
||||||
response.completeExceptionally(channelFuture.cause())
|
response.completeExceptionally(channelFuture.cause())
|
||||||
@@ -164,12 +161,10 @@ class MemcacheClient(private val cfg: MemcacheCacheConfiguration) : AutoCloseabl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sendRequest(request).thenApply { response ->
|
return sendRequest(request).thenApply { response ->
|
||||||
try {
|
|
||||||
when (val status = response.status()) {
|
when (val status = response.status()) {
|
||||||
BinaryMemcacheResponseStatus.SUCCESS -> {
|
BinaryMemcacheResponseStatus.SUCCESS -> {
|
||||||
val compressionMode = cfg.compressionMode
|
val compressionMode = cfg.compressionMode
|
||||||
val content = response.content().retain()
|
val content = response.content()
|
||||||
content.touch()
|
|
||||||
if (compressionMode != null) {
|
if (compressionMode != null) {
|
||||||
when (compressionMode) {
|
when (compressionMode) {
|
||||||
MemcacheCacheConfiguration.CompressionMode.GZIP -> {
|
MemcacheCacheConfiguration.CompressionMode.GZIP -> {
|
||||||
@@ -184,16 +179,11 @@ class MemcacheClient(private val cfg: MemcacheCacheConfiguration) : AutoCloseabl
|
|||||||
ByteBufInputStream(content)
|
ByteBufInputStream(content)
|
||||||
}.let(Channels::newChannel)
|
}.let(Channels::newChannel)
|
||||||
}
|
}
|
||||||
|
|
||||||
BinaryMemcacheResponseStatus.KEY_ENOENT -> {
|
BinaryMemcacheResponseStatus.KEY_ENOENT -> {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> throw MemcacheException(status)
|
else -> throw MemcacheException(status)
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
response.release()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,18 +197,16 @@ class MemcacheClient(private val cfg: MemcacheCacheConfiguration) : AutoCloseabl
|
|||||||
extras.writeInt(0)
|
extras.writeInt(0)
|
||||||
extras.writeInt(encodeExpiry(expiry))
|
extras.writeInt(encodeExpiry(expiry))
|
||||||
val compressionMode = cfg.compressionMode
|
val compressionMode = cfg.compressionMode
|
||||||
content.retain()
|
|
||||||
val payload = if (compressionMode != null) {
|
val payload = if (compressionMode != null) {
|
||||||
val inputStream = ByteBufInputStream(content)
|
val inputStream = ByteBufInputStream(Unpooled.wrappedBuffer(content))
|
||||||
val buf = content.alloc().buffer()
|
val baos = ByteArrayOutputStream()
|
||||||
buf.retain()
|
|
||||||
val outputStream = when (compressionMode) {
|
val outputStream = when (compressionMode) {
|
||||||
MemcacheCacheConfiguration.CompressionMode.GZIP -> {
|
MemcacheCacheConfiguration.CompressionMode.GZIP -> {
|
||||||
GZIPOutputStream(ByteBufOutputStream(buf))
|
GZIPOutputStream(baos)
|
||||||
}
|
}
|
||||||
|
|
||||||
MemcacheCacheConfiguration.CompressionMode.DEFLATE -> {
|
MemcacheCacheConfiguration.CompressionMode.DEFLATE -> {
|
||||||
DeflaterOutputStream(ByteBufOutputStream(buf), Deflater(Deflater.DEFAULT_COMPRESSION, false))
|
DeflaterOutputStream(baos, Deflater(Deflater.DEFAULT_COMPRESSION, false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inputStream.use { i ->
|
inputStream.use { i ->
|
||||||
@@ -226,7 +214,7 @@ class MemcacheClient(private val cfg: MemcacheCacheConfiguration) : AutoCloseabl
|
|||||||
JWO.copy(i, o)
|
JWO.copy(i, o)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf
|
Unpooled.wrappedBuffer(baos.toByteArray())
|
||||||
} else {
|
} else {
|
||||||
content
|
content
|
||||||
}
|
}
|
||||||
@@ -236,14 +224,10 @@ class MemcacheClient(private val cfg: MemcacheCacheConfiguration) : AutoCloseabl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sendRequest(request).thenApply { response ->
|
return sendRequest(request).thenApply { response ->
|
||||||
try {
|
|
||||||
when(val status = response.status()) {
|
when(val status = response.status()) {
|
||||||
BinaryMemcacheResponseStatus.SUCCESS -> null
|
BinaryMemcacheResponseStatus.SUCCESS -> null
|
||||||
else -> throw MemcacheException(status)
|
else -> throw MemcacheException(status)
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
response.release()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,7 +18,6 @@ module net.woggioni.gbcs.server {
|
|||||||
requires net.woggioni.jwo;
|
requires net.woggioni.jwo;
|
||||||
requires net.woggioni.gbcs.common;
|
requires net.woggioni.gbcs.common;
|
||||||
requires net.woggioni.gbcs.api;
|
requires net.woggioni.gbcs.api;
|
||||||
requires io.netty.transport.classes.epoll;
|
|
||||||
|
|
||||||
exports net.woggioni.gbcs.server;
|
exports net.woggioni.gbcs.server;
|
||||||
|
|
||||||
|
@@ -10,9 +10,6 @@ import io.netty.channel.ChannelInboundHandlerAdapter
|
|||||||
import io.netty.channel.ChannelInitializer
|
import io.netty.channel.ChannelInitializer
|
||||||
import io.netty.channel.ChannelOption
|
import io.netty.channel.ChannelOption
|
||||||
import io.netty.channel.ChannelPromise
|
import io.netty.channel.ChannelPromise
|
||||||
import io.netty.channel.MultithreadEventLoopGroup
|
|
||||||
import io.netty.channel.epoll.EpollEventLoopGroup
|
|
||||||
import io.netty.channel.epoll.EpollServerSocketChannel
|
|
||||||
import io.netty.channel.nio.NioEventLoopGroup
|
import io.netty.channel.nio.NioEventLoopGroup
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel
|
import io.netty.channel.socket.nio.NioServerSocketChannel
|
||||||
import io.netty.handler.codec.compression.CompressionOptions
|
import io.netty.handler.codec.compression.CompressionOptions
|
||||||
@@ -52,7 +49,6 @@ import net.woggioni.gbcs.server.exception.ExceptionHandler
|
|||||||
import net.woggioni.gbcs.server.handler.ServerHandler
|
import net.woggioni.gbcs.server.handler.ServerHandler
|
||||||
import net.woggioni.gbcs.server.throttling.ThrottlingHandler
|
import net.woggioni.gbcs.server.throttling.ThrottlingHandler
|
||||||
import net.woggioni.jwo.JWO
|
import net.woggioni.jwo.JWO
|
||||||
import net.woggioni.jwo.OS
|
|
||||||
import net.woggioni.jwo.Tuple2
|
import net.woggioni.jwo.Tuple2
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
@@ -403,23 +399,10 @@ class GradleBuildCacheServer(private val cfg: Configuration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun run(): ServerHandle {
|
fun run(): ServerHandle {
|
||||||
val bossGroup : MultithreadEventLoopGroup
|
// Create the multithreaded event loops for the server
|
||||||
val workerGroup : MultithreadEventLoopGroup
|
val bossGroup = NioEventLoopGroup(1)
|
||||||
val serverSocketChannel : Class<*>
|
val serverSocketChannel = NioServerSocketChannel::class.java
|
||||||
if(cfg.isUseNativeTransport) {
|
val workerGroup = NioEventLoopGroup(0)
|
||||||
if(OS.isLinux) {
|
|
||||||
bossGroup = EpollEventLoopGroup(1)
|
|
||||||
serverSocketChannel = EpollServerSocketChannel::class.java
|
|
||||||
workerGroup = EpollEventLoopGroup(0)
|
|
||||||
} else {
|
|
||||||
throw java.lang.IllegalArgumentException("Native transport is not supported on ${OS.current.name}")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bossGroup = NioEventLoopGroup(1)
|
|
||||||
serverSocketChannel = NioServerSocketChannel::class.java
|
|
||||||
workerGroup = NioEventLoopGroup(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
val eventExecutorGroup = run {
|
val eventExecutorGroup = run {
|
||||||
val threadFactory = if (cfg.eventExecutor.isUseVirtualThreads) {
|
val threadFactory = if (cfg.eventExecutor.isUseVirtualThreads) {
|
||||||
Thread.ofVirtual().factory()
|
Thread.ofVirtual().factory()
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
package net.woggioni.gbcs.server.cache
|
package net.woggioni.gbcs.server.cache
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf
|
import io.netty.buffer.ByteBuf
|
||||||
|
import io.netty.buffer.Unpooled
|
||||||
import net.woggioni.gbcs.api.Cache
|
import net.woggioni.gbcs.api.Cache
|
||||||
import net.woggioni.gbcs.common.ByteBufInputStream
|
import net.woggioni.gbcs.common.ByteBufInputStream
|
||||||
import net.woggioni.gbcs.common.ByteBufOutputStream
|
|
||||||
import net.woggioni.gbcs.common.GBCS.digestString
|
import net.woggioni.gbcs.common.GBCS.digestString
|
||||||
import net.woggioni.gbcs.common.contextLogger
|
|
||||||
import net.woggioni.jwo.JWO
|
import net.woggioni.jwo.JWO
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
import java.nio.channels.Channels
|
import java.nio.channels.Channels
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
@@ -14,7 +14,6 @@ import java.time.Instant
|
|||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import java.util.concurrent.PriorityBlockingQueue
|
import java.util.concurrent.PriorityBlockingQueue
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
|
||||||
import java.util.zip.Deflater
|
import java.util.zip.Deflater
|
||||||
import java.util.zip.DeflaterOutputStream
|
import java.util.zip.DeflaterOutputStream
|
||||||
import java.util.zip.Inflater
|
import java.util.zip.Inflater
|
||||||
@@ -22,18 +21,11 @@ import java.util.zip.InflaterInputStream
|
|||||||
|
|
||||||
class InMemoryCache(
|
class InMemoryCache(
|
||||||
val maxAge: Duration,
|
val maxAge: Duration,
|
||||||
val maxSize: Long,
|
|
||||||
val digestAlgorithm: String?,
|
val digestAlgorithm: String?,
|
||||||
val compressionEnabled: Boolean,
|
val compressionEnabled: Boolean,
|
||||||
val compressionLevel: Int
|
val compressionLevel: Int
|
||||||
) : Cache {
|
) : Cache {
|
||||||
|
|
||||||
companion object {
|
|
||||||
@JvmStatic
|
|
||||||
private val log = contextLogger()
|
|
||||||
}
|
|
||||||
|
|
||||||
private val size = AtomicLong()
|
|
||||||
private val map = ConcurrentHashMap<String, ByteBuf>()
|
private val map = ConcurrentHashMap<String, ByteBuf>()
|
||||||
|
|
||||||
private class RemovalQueueElement(val key: String, val value : ByteBuf, val expiry : Instant) : Comparable<RemovalQueueElement> {
|
private class RemovalQueueElement(val key: String, val value : ByteBuf, val expiry : Instant) : Comparable<RemovalQueueElement> {
|
||||||
@@ -46,17 +38,9 @@ class InMemoryCache(
|
|||||||
private val garbageCollector = Thread {
|
private val garbageCollector = Thread {
|
||||||
while(true) {
|
while(true) {
|
||||||
val el = removalQueue.take()
|
val el = removalQueue.take()
|
||||||
val buf = el.value
|
|
||||||
val now = Instant.now()
|
val now = Instant.now()
|
||||||
if(now > el.expiry) {
|
if(now > el.expiry) {
|
||||||
val removed = map.remove(el.key, buf)
|
map.remove(el.key, el.value)
|
||||||
if(removed) {
|
|
||||||
updateSizeAfterRemoval(buf)
|
|
||||||
//Decrease the reference count for map
|
|
||||||
buf.release()
|
|
||||||
}
|
|
||||||
//Decrease the reference count for removalQueue
|
|
||||||
buf.release()
|
|
||||||
} else {
|
} else {
|
||||||
removalQueue.put(el)
|
removalQueue.put(el)
|
||||||
Thread.sleep(minOf(Duration.between(now, el.expiry), Duration.ofSeconds(1)))
|
Thread.sleep(minOf(Duration.between(now, el.expiry), Duration.ofSeconds(1)))
|
||||||
@@ -66,28 +50,6 @@ class InMemoryCache(
|
|||||||
start()
|
start()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeEldest() : Long {
|
|
||||||
while(true) {
|
|
||||||
val el = removalQueue.take()
|
|
||||||
val buf = el.value
|
|
||||||
val removed = map.remove(el.key, buf)
|
|
||||||
//Decrease the reference count for removalQueue
|
|
||||||
buf.release()
|
|
||||||
if(removed) {
|
|
||||||
val newSize = updateSizeAfterRemoval(buf)
|
|
||||||
//Decrease the reference count for map
|
|
||||||
buf.release()
|
|
||||||
return newSize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateSizeAfterRemoval(removed: ByteBuf) : Long {
|
|
||||||
return size.updateAndGet { currentSize : Long ->
|
|
||||||
currentSize - removed.readableBytes()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
running = false
|
running = false
|
||||||
garbageCollector.join()
|
garbageCollector.join()
|
||||||
@@ -102,13 +64,11 @@ class InMemoryCache(
|
|||||||
).let { digest ->
|
).let { digest ->
|
||||||
map[digest]
|
map[digest]
|
||||||
?.let { value ->
|
?.let { value ->
|
||||||
val copy = value.retainedDuplicate()
|
|
||||||
copy.touch("This has to be released by the caller of the cache")
|
|
||||||
if (compressionEnabled) {
|
if (compressionEnabled) {
|
||||||
val inflater = Inflater()
|
val inflater = Inflater()
|
||||||
Channels.newChannel(InflaterInputStream(ByteBufInputStream(copy), inflater))
|
Channels.newChannel(InflaterInputStream(ByteBufInputStream(value), inflater))
|
||||||
} else {
|
} else {
|
||||||
Channels.newChannel(ByteBufInputStream(copy))
|
Channels.newChannel(ByteBufInputStream(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.let {
|
}.let {
|
||||||
@@ -121,29 +81,18 @@ class InMemoryCache(
|
|||||||
?.let { md ->
|
?.let { md ->
|
||||||
digestString(key.toByteArray(), md)
|
digestString(key.toByteArray(), md)
|
||||||
} ?: key).let { digest ->
|
} ?: key).let { digest ->
|
||||||
content.retain()
|
|
||||||
val value = if (compressionEnabled) {
|
val value = if (compressionEnabled) {
|
||||||
val deflater = Deflater(compressionLevel)
|
val deflater = Deflater(compressionLevel)
|
||||||
val buf = content.alloc().buffer()
|
val baos = ByteArrayOutputStream()
|
||||||
buf.retain()
|
DeflaterOutputStream(baos, deflater).use { stream ->
|
||||||
DeflaterOutputStream(ByteBufOutputStream(buf), deflater).use { outputStream ->
|
JWO.copy(ByteBufInputStream(content), stream)
|
||||||
ByteBufInputStream(content).use { inputStream ->
|
|
||||||
JWO.copy(inputStream, outputStream)
|
|
||||||
}
|
}
|
||||||
}
|
Unpooled.wrappedBuffer(baos.toByteArray())
|
||||||
buf
|
|
||||||
} else {
|
} else {
|
||||||
content
|
content
|
||||||
}
|
}
|
||||||
val old = map.put(digest, value)
|
map[digest] = value
|
||||||
val delta = value.readableBytes() - (old?.readableBytes() ?: 0)
|
removalQueue.put(RemovalQueueElement(digest, value, Instant.now().plus(maxAge)))
|
||||||
var newSize = size.updateAndGet { currentSize : Long ->
|
|
||||||
currentSize + delta
|
|
||||||
}
|
|
||||||
removalQueue.put(RemovalQueueElement(digest, value.retain(), Instant.now().plus(maxAge)))
|
|
||||||
while(newSize > maxSize) {
|
|
||||||
newSize = removeEldest()
|
|
||||||
}
|
|
||||||
}.let {
|
}.let {
|
||||||
CompletableFuture.completedFuture<Void>(null)
|
CompletableFuture.completedFuture<Void>(null)
|
||||||
}
|
}
|
||||||
|
@@ -6,14 +6,12 @@ import java.time.Duration
|
|||||||
|
|
||||||
data class InMemoryCacheConfiguration(
|
data class InMemoryCacheConfiguration(
|
||||||
val maxAge: Duration,
|
val maxAge: Duration,
|
||||||
val maxSize: Long,
|
|
||||||
val digestAlgorithm : String?,
|
val digestAlgorithm : String?,
|
||||||
val compressionEnabled: Boolean,
|
val compressionEnabled: Boolean,
|
||||||
val compressionLevel: Int,
|
val compressionLevel: Int,
|
||||||
) : Configuration.Cache {
|
) : Configuration.Cache {
|
||||||
override fun materialize() = InMemoryCache(
|
override fun materialize() = InMemoryCache(
|
||||||
maxAge,
|
maxAge,
|
||||||
maxSize,
|
|
||||||
digestAlgorithm,
|
digestAlgorithm,
|
||||||
compressionEnabled,
|
compressionEnabled,
|
||||||
compressionLevel
|
compressionLevel
|
||||||
|
@@ -21,9 +21,6 @@ class InMemoryCacheProvider : CacheProvider<InMemoryCacheConfiguration> {
|
|||||||
val maxAge = el.renderAttribute("max-age")
|
val maxAge = el.renderAttribute("max-age")
|
||||||
?.let(Duration::parse)
|
?.let(Duration::parse)
|
||||||
?: Duration.ofDays(1)
|
?: Duration.ofDays(1)
|
||||||
val maxSize = el.renderAttribute("max-size")
|
|
||||||
?.let(java.lang.Long::decode)
|
|
||||||
?: 0x1000000
|
|
||||||
val enableCompression = el.renderAttribute("enable-compression")
|
val enableCompression = el.renderAttribute("enable-compression")
|
||||||
?.let(String::toBoolean)
|
?.let(String::toBoolean)
|
||||||
?: true
|
?: true
|
||||||
@@ -34,7 +31,6 @@ class InMemoryCacheProvider : CacheProvider<InMemoryCacheConfiguration> {
|
|||||||
|
|
||||||
return InMemoryCacheConfiguration(
|
return InMemoryCacheConfiguration(
|
||||||
maxAge,
|
maxAge,
|
||||||
maxSize,
|
|
||||||
digestAlgorithm,
|
digestAlgorithm,
|
||||||
enableCompression,
|
enableCompression,
|
||||||
compressionLevel
|
compressionLevel
|
||||||
@@ -47,7 +43,6 @@ class InMemoryCacheProvider : CacheProvider<InMemoryCacheConfiguration> {
|
|||||||
val prefix = doc.lookupPrefix(GBCS.GBCS_NAMESPACE_URI)
|
val prefix = doc.lookupPrefix(GBCS.GBCS_NAMESPACE_URI)
|
||||||
attr("xs:type", "${prefix}:inMemoryCacheType", GBCS.XML_SCHEMA_NAMESPACE_URI)
|
attr("xs:type", "${prefix}:inMemoryCacheType", GBCS.XML_SCHEMA_NAMESPACE_URI)
|
||||||
attr("max-age", maxAge.toString())
|
attr("max-age", maxAge.toString())
|
||||||
attr("max-size", maxSize.toString())
|
|
||||||
digestAlgorithm?.let { digestAlgorithm ->
|
digestAlgorithm?.let { digestAlgorithm ->
|
||||||
attr("digest", digestAlgorithm)
|
attr("digest", digestAlgorithm)
|
||||||
}
|
}
|
||||||
|
@@ -44,7 +44,6 @@ object Parser {
|
|||||||
val serverPath = root.renderAttribute("path")
|
val serverPath = root.renderAttribute("path")
|
||||||
var incomingConnectionsBacklogSize = 1024
|
var incomingConnectionsBacklogSize = 1024
|
||||||
var authentication: Authentication? = null
|
var authentication: Authentication? = null
|
||||||
var useNativeTransport = false
|
|
||||||
for (child in root.asIterable()) {
|
for (child in root.asIterable()) {
|
||||||
val tagName = child.localName
|
val tagName = child.localName
|
||||||
when (tagName) {
|
when (tagName) {
|
||||||
@@ -137,7 +136,7 @@ object Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
"event-executor" -> {
|
"event-executor" -> {
|
||||||
val useVirtualThread = child.renderAttribute("use-virtual-threads")
|
val useVirtualThread = root.renderAttribute("use-virtual-threads")
|
||||||
?.let(String::toBoolean) ?: true
|
?.let(String::toBoolean) ?: true
|
||||||
eventExecutor = Configuration.EventExecutor(useVirtualThread)
|
eventExecutor = Configuration.EventExecutor(useVirtualThread)
|
||||||
}
|
}
|
||||||
@@ -181,10 +180,6 @@ object Parser {
|
|||||||
}
|
}
|
||||||
tls = Tls(keyStore, trustStore)
|
tls = Tls(keyStore, trustStore)
|
||||||
}
|
}
|
||||||
"transport" -> {
|
|
||||||
useNativeTransport = child.renderAttribute("use-native-transport")
|
|
||||||
?.let(String::toBoolean) ?: false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Configuration.of(
|
return Configuration.of(
|
||||||
@@ -199,7 +194,6 @@ object Parser {
|
|||||||
cache!!,
|
cache!!,
|
||||||
authentication,
|
authentication,
|
||||||
tls,
|
tls,
|
||||||
useNativeTransport
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -44,12 +44,8 @@ object Serializer {
|
|||||||
attr("max-request-size", connection.maxRequestSize.toString())
|
attr("max-request-size", connection.maxRequestSize.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node("transport") {
|
|
||||||
attr("use-native-transport", conf.isUseNativeTransport.toString())
|
|
||||||
}
|
|
||||||
node("event-executor") {
|
node("event-executor") {
|
||||||
attr("use-virtual-threads", conf.eventExecutor.isUseVirtualThreads.toString())
|
attr("use-virtual-threads", conf.eventExecutor.isUseVirtualThreads.toString())
|
||||||
attr("use-virtual-threads", conf.eventExecutor.isUseVirtualThreads.toString())
|
|
||||||
}
|
}
|
||||||
val cache = conf.cache
|
val cache = conf.cache
|
||||||
val serializer : CacheProvider<Configuration.Cache> =
|
val serializer : CacheProvider<Configuration.Cache> =
|
||||||
|
@@ -57,9 +57,10 @@ class ServerHandler(private val cache: Cache, private val serverPrefix: Path) :
|
|||||||
response.headers().set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED)
|
response.headers().set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED)
|
||||||
}
|
}
|
||||||
ctx.write(response)
|
ctx.write(response)
|
||||||
when (channel) {
|
val content : Any = when (channel) {
|
||||||
is FileChannel -> {
|
is FileChannel -> DefaultFileRegion(channel, 0, channel.size())
|
||||||
val content = DefaultFileRegion(channel, 0, channel.size())
|
else -> ChunkedNioStream(channel)
|
||||||
|
}
|
||||||
if (keepAlive) {
|
if (keepAlive) {
|
||||||
ctx.write(content)
|
ctx.write(content)
|
||||||
ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT.retainedDuplicate())
|
ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT.retainedDuplicate())
|
||||||
@@ -67,20 +68,6 @@ class ServerHandler(private val cache: Cache, private val serverPrefix: Path) :
|
|||||||
ctx.writeAndFlush(content)
|
ctx.writeAndFlush(content)
|
||||||
.addListener(ChannelFutureListener.CLOSE)
|
.addListener(ChannelFutureListener.CLOSE)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
val content = ChunkedNioStream(channel)
|
|
||||||
if (keepAlive) {
|
|
||||||
ctx.write(content).addListener {
|
|
||||||
content.close()
|
|
||||||
}
|
|
||||||
ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT.retainedDuplicate())
|
|
||||||
} else {
|
|
||||||
ctx.writeAndFlush(content)
|
|
||||||
.addListener(ChannelFutureListener.CLOSE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
log.debug(ctx) {
|
log.debug(ctx) {
|
||||||
"Cache miss for key '$key'"
|
"Cache miss for key '$key'"
|
||||||
@@ -107,7 +94,7 @@ class ServerHandler(private val cache: Cache, private val serverPrefix: Path) :
|
|||||||
log.debug(ctx) {
|
log.debug(ctx) {
|
||||||
"Added value for key '$key' to build cache"
|
"Added value for key '$key' to build cache"
|
||||||
}
|
}
|
||||||
cache.put(key, msg.content()).thenRun {
|
cache.put(key, msg.content().retain()).thenRun {
|
||||||
val response = DefaultFullHttpResponse(
|
val response = DefaultFullHttpResponse(
|
||||||
msg.protocolVersion(), HttpResponseStatus.CREATED,
|
msg.protocolVersion(), HttpResponseStatus.CREATED,
|
||||||
Unpooled.copiedBuffer(key.toByteArray())
|
Unpooled.copiedBuffer(key.toByteArray())
|
||||||
|
@@ -9,7 +9,6 @@
|
|||||||
<xs:sequence minOccurs="0">
|
<xs:sequence minOccurs="0">
|
||||||
<xs:element name="bind" type="gbcs:bindType" maxOccurs="1"/>
|
<xs:element name="bind" type="gbcs:bindType" maxOccurs="1"/>
|
||||||
<xs:element name="connection" type="gbcs:connectionType" minOccurs="0" maxOccurs="1"/>
|
<xs:element name="connection" type="gbcs:connectionType" minOccurs="0" maxOccurs="1"/>
|
||||||
<xs:element name="transport" type="gbcs:transportType" minOccurs="0" maxOccurs="1"/>
|
|
||||||
<xs:element name="event-executor" type="gbcs:eventExecutorType" minOccurs="0" maxOccurs="1"/>
|
<xs:element name="event-executor" type="gbcs:eventExecutorType" minOccurs="0" maxOccurs="1"/>
|
||||||
<xs:element name="cache" type="gbcs:cacheType" maxOccurs="1"/>
|
<xs:element name="cache" type="gbcs:cacheType" maxOccurs="1"/>
|
||||||
<xs:element name="authorization" type="gbcs:authorizationType" minOccurs="0">
|
<xs:element name="authorization" type="gbcs:authorizationType" minOccurs="0">
|
||||||
@@ -43,10 +42,6 @@
|
|||||||
<xs:attribute name="max-request-size" type="xs:unsignedInt" use="optional" default="67108864"/>
|
<xs:attribute name="max-request-size" type="xs:unsignedInt" use="optional" default="67108864"/>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|
||||||
<xs:complexType name="transportType">
|
|
||||||
<xs:attribute name="use-native-transport" type="xs:boolean" use="optional" default="false"/>
|
|
||||||
</xs:complexType>
|
|
||||||
|
|
||||||
<xs:complexType name="eventExecutorType">
|
<xs:complexType name="eventExecutorType">
|
||||||
<xs:attribute name="use-virtual-threads" type="xs:boolean" use="optional" default="true"/>
|
<xs:attribute name="use-virtual-threads" type="xs:boolean" use="optional" default="true"/>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
@@ -57,7 +52,6 @@
|
|||||||
<xs:complexContent>
|
<xs:complexContent>
|
||||||
<xs:extension base="gbcs:cacheType">
|
<xs:extension base="gbcs:cacheType">
|
||||||
<xs:attribute name="max-age" type="xs:duration" default="P1D"/>
|
<xs:attribute name="max-age" type="xs:duration" default="P1D"/>
|
||||||
<xs:attribute name="max-size" type="xs:token" default="0x1000000"/>
|
|
||||||
<xs:attribute name="digest" type="xs:token" default="MD5"/>
|
<xs:attribute name="digest" type="xs:token" default="MD5"/>
|
||||||
<xs:attribute name="enable-compression" type="xs:boolean" default="true"/>
|
<xs:attribute name="enable-compression" type="xs:boolean" default="true"/>
|
||||||
<xs:attribute name="compression-level" type="xs:byte" default="-1"/>
|
<xs:attribute name="compression-level" type="xs:byte" default="-1"/>
|
||||||
|
@@ -55,7 +55,6 @@ abstract class AbstractBasicAuthServerTest : AbstractServerTest() {
|
|||||||
),
|
),
|
||||||
Configuration.BasicAuthentication(),
|
Configuration.BasicAuthentication(),
|
||||||
null,
|
null,
|
||||||
false,
|
|
||||||
)
|
)
|
||||||
Xml.write(Serializer.serialize(cfg), System.out)
|
Xml.write(Serializer.serialize(cfg), System.out)
|
||||||
}
|
}
|
||||||
|
@@ -171,8 +171,7 @@ abstract class AbstractTlsServerTest : AbstractServerTest() {
|
|||||||
Configuration.Tls(
|
Configuration.Tls(
|
||||||
Configuration.KeyStore(this.serverKeyStoreFile, null, SERVER_CERTIFICATE_ENTRY, PASSWORD),
|
Configuration.KeyStore(this.serverKeyStoreFile, null, SERVER_CERTIFICATE_ENTRY, PASSWORD),
|
||||||
Configuration.TrustStore(this.trustStoreFile, null, false, false),
|
Configuration.TrustStore(this.trustStoreFile, null, false, false),
|
||||||
),
|
)
|
||||||
false
|
|
||||||
)
|
)
|
||||||
Xml.write(Serializer.serialize(cfg), System.out)
|
Xml.write(Serializer.serialize(cfg), System.out)
|
||||||
}
|
}
|
||||||
|
@@ -51,12 +51,10 @@ class NoAuthServerTest : AbstractServerTest() {
|
|||||||
maxAge = Duration.ofSeconds(3600 * 24),
|
maxAge = Duration.ofSeconds(3600 * 24),
|
||||||
compressionEnabled = true,
|
compressionEnabled = true,
|
||||||
digestAlgorithm = "MD5",
|
digestAlgorithm = "MD5",
|
||||||
compressionLevel = Deflater.DEFAULT_COMPRESSION,
|
compressionLevel = Deflater.DEFAULT_COMPRESSION
|
||||||
maxSize = 0x1000000
|
|
||||||
),
|
),
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
false,
|
|
||||||
)
|
)
|
||||||
Xml.write(Serializer.serialize(cfg), System.out)
|
Xml.write(Serializer.serialize(cfg), System.out)
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,6 @@
|
|||||||
write-idle-timeout="PT11M"
|
write-idle-timeout="PT11M"
|
||||||
idle-timeout="PT30M"
|
idle-timeout="PT30M"
|
||||||
max-request-size="101325"/>
|
max-request-size="101325"/>
|
||||||
<transport use-native-transport="true"/>
|
|
||||||
<event-executor use-virtual-threads="false"/>
|
<event-executor use-virtual-threads="false"/>
|
||||||
<cache xs:type="gbcs:fileSystemCacheType" path="/tmp/gbcs" max-age="P7D"/>
|
<cache xs:type="gbcs:fileSystemCacheType" path="/tmp/gbcs" max-age="P7D"/>
|
||||||
<authentication>
|
<authentication>
|
||||||
|
Reference in New Issue
Block a user