This is an automated email from the ASF dual-hosted git repository. toulmean pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/incubator-tuweni.git
The following commit(s) were added to refs/heads/main by this push: new b7e5e7c Add caching to app new 761b3e8 Merge pull request #330 from atoulme/add_caching_to_app b7e5e7c is described below commit b7e5e7c636b647ba9a71cbe8a5d948e3d3b05956 Author: Antoine Toulme <anto...@lunar-ocean.com> AuthorDate: Fri Jul 30 22:17:12 2021 -0700 Add caching to app --- jsonrpc-app/build.gradle | 3 ++ .../org/apache/tuweni/jsonrpc/app/JSONRPCApp.kt | 52 +++++++++++++++++++++- .../org/apache/tuweni/jsonrpc/app/JSONRPCConfig.kt | 8 ++++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/jsonrpc-app/build.gradle b/jsonrpc-app/build.gradle index 9c1037f..61441fd 100644 --- a/jsonrpc-app/build.gradle +++ b/jsonrpc-app/build.gradle @@ -21,6 +21,7 @@ dependencies { implementation project(':concurrent') implementation project(':eth') implementation project(':jsonrpc') + implementation project(':kv') implementation project(':metrics') implementation project(':net') implementation project(':units') @@ -40,6 +41,8 @@ dependencies { implementation 'io.opentelemetry:opentelemetry-sdk-metrics' implementation 'javax.servlet:javax.servlet-api' implementation 'org.bouncycastle:bcprov-jdk15on' + implementation 'org.infinispan:infinispan-core' + implementation 'org.infinispan:infinispan-cachestore-rocksdb' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core' implementation 'org.slf4j:slf4j-api' implementation 'org.jetbrains.kotlin:kotlin-stdlib' diff --git a/jsonrpc-app/src/main/kotlin/org/apache/tuweni/jsonrpc/app/JSONRPCApp.kt b/jsonrpc-app/src/main/kotlin/org/apache/tuweni/jsonrpc/app/JSONRPCApp.kt index 2cc0453..3d10d92 100644 --- a/jsonrpc-app/src/main/kotlin/org/apache/tuweni/jsonrpc/app/JSONRPCApp.kt +++ b/jsonrpc-app/src/main/kotlin/org/apache/tuweni/jsonrpc/app/JSONRPCApp.kt @@ -16,20 +16,36 @@ */ package org.apache.tuweni.jsonrpc.app +import com.fasterxml.jackson.databind.ObjectMapper import io.vertx.core.Vertx import io.vertx.core.VertxOptions import io.vertx.tracing.opentelemetry.OpenTelemetryOptions import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.runBlocking import org.apache.tuweni.eth.internalError +import org.apache.tuweni.bytes.Bytes +import org.apache.tuweni.eth.JSONRPCResponse import org.apache.tuweni.jsonrpc.JSONRPCClient import org.apache.tuweni.jsonrpc.JSONRPCServer +import org.apache.tuweni.jsonrpc.methods.CachingHandler import org.apache.tuweni.jsonrpc.methods.MeteredHandler import org.apache.tuweni.jsonrpc.methods.MethodAllowListHandler +import org.apache.tuweni.jsonrpc.methods.ThrottlingHandler +import org.apache.tuweni.kv.InfinispanKeyValueStore import org.apache.tuweni.metrics.MetricsService import org.apache.tuweni.net.ip.IPRangeChecker import org.apache.tuweni.net.tls.VertxTrustOptions import org.bouncycastle.jce.provider.BouncyCastleProvider +import org.infinispan.Cache +import org.infinispan.commons.dataconversion.MediaType +import org.infinispan.commons.io.ByteBuffer +import org.infinispan.commons.io.ByteBufferImpl +import org.infinispan.commons.marshall.AbstractMarshaller +import org.infinispan.configuration.cache.ConfigurationBuilder +import org.infinispan.configuration.global.GlobalConfigurationBuilder +import org.infinispan.manager.DefaultCacheManager +import org.infinispan.marshall.persistence.PersistenceMarshaller +import org.infinispan.persistence.rocksdb.configuration.RocksDBStoreConfigurationBuilder import org.slf4j.LoggerFactory import java.nio.file.Paths import java.security.Security @@ -93,7 +109,26 @@ class JSONRPCApplication( val successCounter = meter.longCounterBuilder("success").build() val failureCounter = meter.longCounterBuilder("failure").build() - val handler = MeteredHandler(successCounter, failureCounter, allowListHandler::handleRequest) + val nextHandler = if (config.cacheEnabled()) { + + val builder = GlobalConfigurationBuilder().serialization().marshaller(PersistenceMarshaller()) + val manager = DefaultCacheManager(builder.build()) + val cache: Cache<String, JSONRPCResponse> = manager.createCache( + "responses", + ConfigurationBuilder().persistence().addStore(RocksDBStoreConfigurationBuilder::class.java) + .location(config.cacheStoragePath()).build() + ) + + val cachingHandler = + CachingHandler(config.cachedMethods(), InfinispanKeyValueStore(cache), allowListHandler::handleRequest) + cachingHandler::handleRequest + } else { + allowListHandler::handleRequest + } + + val throttlingHandler = ThrottlingHandler(config.maxConcurrentRequests(), nextHandler) + + val handler = MeteredHandler(successCounter, failureCounter, throttlingHandler::handleRequest) val server = JSONRPCServer( vertx, config.port(), config.networkInterface(), config.ssl(), @@ -126,3 +161,18 @@ class JSONRPCApplication( } } } + +class PersistenceMarshaller : AbstractMarshaller() { + + companion object { + val mapper = ObjectMapper() + } + + override fun objectFromByteBuffer(buf: ByteArray?, offset: Int, length: Int) = mapper.readValue(Bytes.wrap(buf!!, offset, length).toArrayUnsafe(), JSONRPCResponse::class.java) + + override fun objectToBuffer(o: Any?, estimatedSize: Int): ByteBuffer = ByteBufferImpl.create(mapper.writeValueAsBytes(o)) + + override fun isMarshallable(o: Any?): Boolean = o is JSONRPCResponse + + override fun mediaType(): MediaType = MediaType.APPLICATION_OCTET_STREAM +} diff --git a/jsonrpc-app/src/main/kotlin/org/apache/tuweni/jsonrpc/app/JSONRPCConfig.kt b/jsonrpc-app/src/main/kotlin/org/apache/tuweni/jsonrpc/app/JSONRPCConfig.kt index 8cd38d8..49c1705 100644 --- a/jsonrpc-app/src/main/kotlin/org/apache/tuweni/jsonrpc/app/JSONRPCConfig.kt +++ b/jsonrpc-app/src/main/kotlin/org/apache/tuweni/jsonrpc/app/JSONRPCConfig.kt @@ -52,6 +52,10 @@ class JSONRPCConfig(val filePath: Path) { .addBoolean("endpointBasicAuthEnabled", false, "Enable basic authentication for the endpoint", null) .addString("endpointBasicAuthUsername", "", "Basic authentication username for the endpoint", null) .addString("endpointBasicAuthPassword", "", "Basic authentication password for the endpoint", null) + .addListOfString("cachedMethods", Collections.emptyList(), "Cached JSON-RPC methods", null) + .addBoolean("cacheEnabled", false, "Enable caching", null) + .addString("cacheStoragePath", "", "Location of cache storage", null) + .addInteger("maxConcurrentRequests", 30, "Maximum concurrent requests", null) .toSchema() } @@ -81,4 +85,8 @@ class JSONRPCConfig(val filePath: Path) { fun endpointBasicAuthEnabled() = config.getBoolean("endpointBasicAuthEnabled") fun endpointBasicAuthUsername() = config.getString("endpointBasicAuthUsername") fun endpointBasicAuthPassword() = config.getString("endpointBasicAuthPassword") + fun cachedMethods() = config.getListOfString("cachedMethods") + fun cacheEnabled() = config.getBoolean("cacheEnabled") + fun cacheStoragePath() = config.getString("cacheStoragePath") + fun maxConcurrentRequests() = config.getInteger("maxConcurrentRequests") } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@tuweni.apache.org For additional commands, e-mail: commits-h...@tuweni.apache.org