mirror of
https://github.com/corda/corda.git
synced 2025-06-17 14:48:16 +00:00
[CORDA-1411]: Prevent MappedSchema caching from leaking memory. (#3042)
This commit is contained in:
committed by
GitHub
parent
eb0fbb03e3
commit
5565b3e80d
@ -42,6 +42,26 @@ open class MappedSchema(schemaFamily: Class<*>,
|
|||||||
val mappedTypes: Iterable<Class<*>>) {
|
val mappedTypes: Iterable<Class<*>>) {
|
||||||
val name: String = schemaFamily.name
|
val name: String = schemaFamily.name
|
||||||
override fun toString(): String = "${this.javaClass.simpleName}(name=$name, version=$version)"
|
override fun toString(): String = "${this.javaClass.simpleName}(name=$name, version=$version)"
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as MappedSchema
|
||||||
|
|
||||||
|
if (version != other.version) return false
|
||||||
|
if (mappedTypes != other.mappedTypes) return false
|
||||||
|
if (name != other.name) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = version
|
||||||
|
result = 31 * result + mappedTypes.hashCode()
|
||||||
|
result = 31 * result + name.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//DOCEND MappedSchema
|
//DOCEND MappedSchema
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ release, see :doc:`upgrade-notes`.
|
|||||||
|
|
||||||
Unreleased
|
Unreleased
|
||||||
==========
|
==========
|
||||||
|
* Avoided a memory leak deriving from incorrect MappedSchema caching strategy.
|
||||||
|
|
||||||
* Added program line argument ``on-unknown-config-keys`` to allow specifying behaviour on unknown node configuration property keys.
|
* Added program line argument ``on-unknown-config-keys`` to allow specifying behaviour on unknown node configuration property keys.
|
||||||
Values are: [FAIL, WARN, IGNORE], default to FAIL if unspecified.
|
Values are: [FAIL, WARN, IGNORE], default to FAIL if unspecified.
|
||||||
|
@ -25,7 +25,8 @@ data class DatabaseConfig(
|
|||||||
val initialiseSchema: Boolean = true,
|
val initialiseSchema: Boolean = true,
|
||||||
val serverNameTablePrefix: String = "",
|
val serverNameTablePrefix: String = "",
|
||||||
val transactionIsolationLevel: TransactionIsolationLevel = TransactionIsolationLevel.REPEATABLE_READ,
|
val transactionIsolationLevel: TransactionIsolationLevel = TransactionIsolationLevel.REPEATABLE_READ,
|
||||||
val exportHibernateJMXStatistics: Boolean = false
|
val exportHibernateJMXStatistics: Boolean = false,
|
||||||
|
val mappedSchemaCacheSize: Long = 100
|
||||||
)
|
)
|
||||||
|
|
||||||
// This class forms part of the node config and so any changes to it must be handled with care
|
// This class forms part of the node config and so any changes to it must be handled with care
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.corda.nodeapi.internal.persistence
|
package net.corda.nodeapi.internal.persistence
|
||||||
|
|
||||||
|
import com.github.benmanes.caffeine.cache.Caffeine
|
||||||
import net.corda.core.internal.castIfPossible
|
import net.corda.core.internal.castIfPossible
|
||||||
import net.corda.core.schemas.MappedSchema
|
import net.corda.core.schemas.MappedSchema
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
@ -21,7 +22,6 @@ import org.hibernate.type.descriptor.sql.BlobTypeDescriptor
|
|||||||
import org.hibernate.type.descriptor.sql.VarbinaryTypeDescriptor
|
import org.hibernate.type.descriptor.sql.VarbinaryTypeDescriptor
|
||||||
import java.lang.management.ManagementFactory
|
import java.lang.management.ManagementFactory
|
||||||
import java.sql.Connection
|
import java.sql.Connection
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
import javax.management.ObjectName
|
import javax.management.ObjectName
|
||||||
import javax.persistence.AttributeConverter
|
import javax.persistence.AttributeConverter
|
||||||
|
|
||||||
@ -35,8 +35,7 @@ class HibernateConfiguration(
|
|||||||
private val logger = contextLogger()
|
private val logger = contextLogger()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make this a guava cache or similar to limit ability for this to grow forever.
|
private val sessionFactories = Caffeine.newBuilder().maximumSize(databaseConfig.mappedSchemaCacheSize).build<Set<MappedSchema>, SessionFactory>()
|
||||||
private val sessionFactories = ConcurrentHashMap<Set<MappedSchema>, SessionFactory>()
|
|
||||||
|
|
||||||
val sessionFactoryForRegisteredSchemas = schemas.let {
|
val sessionFactoryForRegisteredSchemas = schemas.let {
|
||||||
logger.info("Init HibernateConfiguration for schemas: $it")
|
logger.info("Init HibernateConfiguration for schemas: $it")
|
||||||
@ -44,7 +43,7 @@ class HibernateConfiguration(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @param key must be immutable, not just read-only. */
|
/** @param key must be immutable, not just read-only. */
|
||||||
fun sessionFactoryForSchemas(key: Set<MappedSchema>) = sessionFactories.computeIfAbsent(key, { makeSessionFactoryForSchemas(key) })
|
fun sessionFactoryForSchemas(key: Set<MappedSchema>): SessionFactory = sessionFactories.get(key, ::makeSessionFactoryForSchemas)!!
|
||||||
|
|
||||||
private fun makeSessionFactoryForSchemas(schemas: Set<MappedSchema>): SessionFactory {
|
private fun makeSessionFactoryForSchemas(schemas: Set<MappedSchema>): SessionFactory {
|
||||||
logger.info("Creating session factory for schemas: $schemas")
|
logger.info("Creating session factory for schemas: $schemas")
|
||||||
|
Reference in New Issue
Block a user