Merge pull request #7172 from corda/chrisr3-urlconnection-caches

ENT-6532: Close AttachmentsClassLoader on eviction to avoid leaking file descriptors.
This commit is contained in:
Adel El-Beik 2022-05-23 10:10:44 +01:00 committed by GitHub
commit 91ef44dc12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 18 additions and 14 deletions

View File

@ -32,6 +32,7 @@ import net.corda.core.serialization.internal.AttachmentURLStreamHandlerFactory.t
import net.corda.core.serialization.withWhitelist
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.debug
import net.corda.core.utilities.loggerFor
import java.io.IOException
import java.io.InputStream
import java.lang.ref.WeakReference
@ -470,7 +471,18 @@ interface AttachmentsClassLoaderCache {
@DeleteForDJVM
class AttachmentsClassLoaderCacheImpl(cacheFactory: NamedCacheFactory) : SingletonSerializeAsToken(), AttachmentsClassLoaderCache {
private val cache: Cache<AttachmentsClassLoaderKey, SerializationContext> = cacheFactory.buildNamed(Caffeine.newBuilder(), "AttachmentsClassLoader_cache")
private val cache: Cache<AttachmentsClassLoaderKey, SerializationContext> = cacheFactory.buildNamed(
// Close deserialization classloaders when we evict them
// to release any resources they may be holding.
@Suppress("TooGenericExceptionCaught")
Caffeine.newBuilder().removalListener { key, context, _ ->
try {
(context?.deserializationClassLoader as? AutoCloseable)?.close()
} catch (e: Exception) {
loggerFor<AttachmentsClassLoaderCacheImpl>().warn("Error destroying serialization context for $key", e)
}
}, "AttachmentsClassLoader_cache"
)
override fun computeIfAbsent(key: AttachmentsClassLoaderKey, mappingFunction: Function<in AttachmentsClassLoaderKey, out SerializationContext>): SerializationContext {
return cache.get(key, mappingFunction) ?: throw NullPointerException("null returned from cache mapping function")

View File

@ -173,13 +173,12 @@ import org.jolokia.jvmagent.JolokiaServerConfig
import org.slf4j.Logger
import rx.Scheduler
import java.lang.reflect.InvocationTargetException
import java.net.URLConnection
import java.sql.Connection
import java.sql.Savepoint
import java.time.Clock
import java.time.Duration
import java.time.format.DateTimeParseException
import java.util.*
import java.util.Properties
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.LinkedBlockingQueue
@ -238,7 +237,6 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
}
quasarExcludePackages(configuration)
disableURLConnectionCache()
if (allowHibernateToManageAppSchema && !configuration.devMode) {
throw ConfigurationException("Hibernate can only be used to manage app schema in development while using dev mode. " +
@ -427,13 +425,6 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
}
}
private fun disableURLConnectionCache() {
object : URLConnection(null) {
override fun connect() {
}
}.defaultUseCaches = false
}
private fun quasarExcludePackages(nodeConfiguration: NodeConfiguration) {
val quasarInstrumentor = Retransform.getInstrumentor()

View File

@ -33,7 +33,8 @@ open class DefaultNamedCacheFactory protected constructor(private val metricRegi
override fun bindWithMetrics(metricRegistry: MetricRegistry): BindableNamedCacheFactory = DefaultNamedCacheFactory(metricRegistry, this.nodeConfiguration)
override fun bindWithConfig(nodeConfiguration: NodeConfiguration): BindableNamedCacheFactory = DefaultNamedCacheFactory(this.metricRegistry, nodeConfiguration)
open protected fun <K, V> configuredForNamed(caffeine: Caffeine<K, V>, name: String): Caffeine<K, V> {
@Suppress("ComplexMethod")
protected open fun <K, V> configuredForNamed(caffeine: Caffeine<K, V>, name: String): Caffeine<K, V> {
return with(nodeConfiguration!!) {
when {
name.startsWith("RPCSecurityManagerShiroCache_") -> with(security?.authService?.options?.cache!!) { caffeine.maximumSize(maxEntries).expireAfterWrite(expireAfterSecs, TimeUnit.SECONDS) }
@ -84,7 +85,7 @@ open class DefaultNamedCacheFactory protected constructor(private val metricRegi
return configuredForNamed(caffeine, name).build<K, V>(loader)
}
open protected val defaultCacheSize = 1024L
protected open val defaultCacheSize = 1024L
private val defaultAttachmentsClassLoaderCacheSize = defaultCacheSize / CACHE_SIZE_DENOMINATOR
}
private const val CACHE_SIZE_DENOMINATOR = 4L
private const val CACHE_SIZE_DENOMINATOR = 4L