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
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.serialization.withWhitelist
import net.corda.core.utilities.contextLogger import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.debug import net.corda.core.utilities.debug
import net.corda.core.utilities.loggerFor
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@ -470,7 +471,18 @@ interface AttachmentsClassLoaderCache {
@DeleteForDJVM @DeleteForDJVM
class AttachmentsClassLoaderCacheImpl(cacheFactory: NamedCacheFactory) : SingletonSerializeAsToken(), AttachmentsClassLoaderCache { 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 { 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") 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 org.slf4j.Logger
import rx.Scheduler import rx.Scheduler
import java.lang.reflect.InvocationTargetException import java.lang.reflect.InvocationTargetException
import java.net.URLConnection
import java.sql.Connection import java.sql.Connection
import java.sql.Savepoint import java.sql.Savepoint
import java.time.Clock import java.time.Clock
import java.time.Duration import java.time.Duration
import java.time.format.DateTimeParseException import java.time.format.DateTimeParseException
import java.util.* import java.util.Properties
import java.util.concurrent.ExecutorService import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors import java.util.concurrent.Executors
import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.LinkedBlockingQueue
@ -238,7 +237,6 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
} }
quasarExcludePackages(configuration) quasarExcludePackages(configuration)
disableURLConnectionCache()
if (allowHibernateToManageAppSchema && !configuration.devMode) { if (allowHibernateToManageAppSchema && !configuration.devMode) {
throw ConfigurationException("Hibernate can only be used to manage app schema in development while using dev mode. " + 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) { private fun quasarExcludePackages(nodeConfiguration: NodeConfiguration) {
val quasarInstrumentor = Retransform.getInstrumentor() 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 bindWithMetrics(metricRegistry: MetricRegistry): BindableNamedCacheFactory = DefaultNamedCacheFactory(metricRegistry, this.nodeConfiguration)
override fun bindWithConfig(nodeConfiguration: NodeConfiguration): BindableNamedCacheFactory = DefaultNamedCacheFactory(this.metricRegistry, 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!!) { return with(nodeConfiguration!!) {
when { when {
name.startsWith("RPCSecurityManagerShiroCache_") -> with(security?.authService?.options?.cache!!) { caffeine.maximumSize(maxEntries).expireAfterWrite(expireAfterSecs, TimeUnit.SECONDS) } 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) 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 val defaultAttachmentsClassLoaderCacheSize = defaultCacheSize / CACHE_SIZE_DENOMINATOR
} }
private const val CACHE_SIZE_DENOMINATOR = 4L private const val CACHE_SIZE_DENOMINATOR = 4L