mirror of
https://github.com/corda/corda.git
synced 2025-06-16 14:18:20 +00:00
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:
@ -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")
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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
|
Reference in New Issue
Block a user