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

Reply via email to