From bc330bd9890d41904bbeea6e579f5fc4438872b6 Mon Sep 17 00:00:00 2001 From: Christian Sailer Date: Fri, 24 Aug 2018 17:17:22 +0100 Subject: [PATCH] ENT-2414 Named caches (#3848) * Add named caches and apply to NonInvalidingUnboundCache and all usages. * Add named caches and apply to NonInvalidingCache and all usages. * Add named caches and apply to NonInvalidingWeightBasedCache and all usages. * Move NamedCache to core/internal * Remove type `NamedCache` and `NamedLoadingCache` * Suppressed 'name not used' warning, added comment, and fixed generic parameters on the buildNamed functions. * Use `buildNamed` in all caffeine instances in production code. Not using it for caches that are created in test code. * Add checks for the cache name * Formatting * Minor code review revisions --- .idea/compiler.xml | 4 +- .../client/jfx/model/NetworkIdentityModel.kt | 3 +- .../rpc/internal/RPCClientProxyHandler.kt | 9 +--- core/build.gradle | 3 ++ .../net/corda/core/internal/NamedCache.kt | 41 +++++++++++++++++++ .../net/corda/core/internal/NamedCacheTest.kt | 24 +++++++++++ .../nodeapi/internal/DeduplicationChecker.kt | 5 ++- .../persistence/HibernateConfiguration.kt | 3 +- .../security/RPCSecurityManagerImpl.kt | 3 +- .../identity/PersistentIdentityService.kt | 2 + .../keys/PersistentKeyManagementService.kt | 1 + .../messaging/P2PMessageDeduplicator.kt | 1 + .../node/services/messaging/RPCServer.kt | 3 +- .../network/PersistentNetworkMapCache.kt | 8 +++- .../persistence/DBTransactionStorage.kt | 1 + .../persistence/NodeAttachmentService.kt | 5 ++- .../NodePropertiesPersistentStore.kt | 1 + .../BFTNonValidatingNotaryService.kt | 1 + .../PersistentUniquenessProvider.kt | 1 + .../transactions/RaftUniquenessProvider.kt | 1 + .../upgrade/ContractUpgradeServiceImpl.kt | 1 + .../node/utilities/AppendOnlyPersistentMap.kt | 4 ++ .../node/utilities/NonInvalidatingCache.kt | 17 ++++---- .../utilities/NonInvalidatingUnboundCache.kt | 9 ++-- .../net/corda/node/utilities/PersistentMap.kt | 2 + .../AppendOnlyPersistentMapTest.kt | 1 + .../node/utilities/PersistentMapTests.kt | 1 + .../internal/SerializationScheme.kt | 3 +- .../explorer/identicon/IdenticonRenderer.kt | 3 +- 29 files changed, 130 insertions(+), 31 deletions(-) create mode 100644 core/src/main/kotlin/net/corda/core/internal/NamedCache.kt create mode 100644 core/src/test/kotlin/net/corda/core/internal/NamedCacheTest.kt diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 7e061003e1..ef6407f0b3 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -24,6 +24,8 @@ + + @@ -233,4 +235,4 @@ - + \ No newline at end of file diff --git a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/NetworkIdentityModel.kt b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/NetworkIdentityModel.kt index 610e5129f8..0b09957678 100644 --- a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/NetworkIdentityModel.kt +++ b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/NetworkIdentityModel.kt @@ -6,6 +6,7 @@ import javafx.collections.FXCollections import javafx.collections.ObservableList import net.corda.client.jfx.utils.* import net.corda.core.identity.AnonymousParty +import net.corda.core.internal.buildNamed import net.corda.core.node.NodeInfo import net.corda.core.node.services.NetworkMapCache.MapChange import java.security.PublicKey @@ -30,7 +31,7 @@ class NetworkIdentityModel { private val rpcProxy by observableValue(NodeMonitorModel::proxyObservable) private val identityCache = Caffeine.newBuilder() - .build>({ publicKey -> + .buildNamed>("NetworkIdentityModel_identity", { publicKey -> publicKey.let { rpcProxy.map { it?.cordaRPCOps?.nodeInfoFromParty(AnonymousParty(publicKey)) } } }) val notaries = ChosenList(rpcProxy.map { FXCollections.observableList(it?.cordaRPCOps?.notaryIdentities() ?: emptyList()) }, "notaries") diff --git a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt index 8b45999554..f10607ad97 100644 --- a/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt +++ b/client/rpc/src/main/kotlin/net/corda/client/rpc/internal/RPCClientProxyHandler.kt @@ -14,10 +14,7 @@ import net.corda.client.rpc.internal.serialization.amqp.RpcClientObservableDeSer import net.corda.core.context.Actor import net.corda.core.context.Trace import net.corda.core.context.Trace.InvocationId -import net.corda.core.internal.LazyStickyPool -import net.corda.core.internal.LifeCycle -import net.corda.core.internal.ThreadBox -import net.corda.core.internal.times +import net.corda.core.internal.* import net.corda.core.messaging.RPCOps import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.serialize @@ -162,9 +159,7 @@ class RPCClientProxyHandler( observablesToReap.locked { observables.add(observableId) } } return Caffeine.newBuilder(). - weakValues(). - removalListener(onObservableRemove).executor(SameThreadExecutor.getExecutor()). - build() + weakValues().removalListener(onObservableRemove).executor(SameThreadExecutor.getExecutor()).buildNamed("RpcClientProxyHandler_rpcObservable") } private var sessionFactory: ClientSessionFactory? = null diff --git a/core/build.gradle b/core/build.gradle index 0039fa25af..671b7b616d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -84,6 +84,9 @@ dependencies { // Guava: Google utilities library. testCompile "com.google.guava:guava:$guava_version" + // For caches rather than guava + compile "com.github.ben-manes.caffeine:caffeine:$caffeine_version" + // Smoke tests do NOT have any Node code on the classpath! smokeTestCompile project(':smoke-test-utils') smokeTestCompile "org.assertj:assertj-core:${assertj_version}" diff --git a/core/src/main/kotlin/net/corda/core/internal/NamedCache.kt b/core/src/main/kotlin/net/corda/core/internal/NamedCache.kt new file mode 100644 index 0000000000..7b54b6ceb4 --- /dev/null +++ b/core/src/main/kotlin/net/corda/core/internal/NamedCache.kt @@ -0,0 +1,41 @@ +package net.corda.core.internal + +import com.github.benmanes.caffeine.cache.Cache +import com.github.benmanes.caffeine.cache.CacheLoader +import com.github.benmanes.caffeine.cache.Caffeine +import com.github.benmanes.caffeine.cache.LoadingCache + +/** + * Restrict the allowed characters of a cache name - this ensures that each cache has a name, and that + * the name can be used to create a file name or a metric name. + */ +internal fun checkCacheName(name: String) { + require(!name.isBlank()) + require(allowedChars.matches(name)) +} + +private val allowedChars = Regex("^[0-9A-Za-z_.]*\$") + +/* buildNamed is the central helper method to build caffeine caches in Corda. + * This allows to easily add tweaks to all caches built in Corda, and also forces + * cache users to give their cache a (meaningful) name that can be used e.g. for + * capturing cache traces etc. + * + * Currently it is not used in this version of CORDA, but there are plans to do so. + */ + +fun Caffeine.buildNamed(name: String): Cache { + checkCacheName(name) + return this.build() +} + +fun Caffeine.buildNamed(name: String, loadFunc: (K) -> V): LoadingCache { + checkCacheName(name) + return this.build(loadFunc) +} + + +fun Caffeine.buildNamed(name: String, loader: CacheLoader): LoadingCache { + checkCacheName(name) + return this.build(loader) +} diff --git a/core/src/test/kotlin/net/corda/core/internal/NamedCacheTest.kt b/core/src/test/kotlin/net/corda/core/internal/NamedCacheTest.kt new file mode 100644 index 0000000000..3358696bce --- /dev/null +++ b/core/src/test/kotlin/net/corda/core/internal/NamedCacheTest.kt @@ -0,0 +1,24 @@ +package net.corda.core.internal + +import org.junit.Test +import kotlin.test.assertEquals + +class NamedCacheTest { + fun checkNameHelper(name: String, throws: Boolean) { + var exceptionThrown = false + try { + checkCacheName(name) + } catch (e: Exception) { + exceptionThrown = true + } + assertEquals(throws, exceptionThrown) + } + + @Test + fun TestCheckCacheName() { + checkNameHelper("abc_123.234", false) + checkNameHelper("", true) + checkNameHelper("abc 123", true) + checkNameHelper("abc/323", true) + } +} \ No newline at end of file diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/DeduplicationChecker.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/DeduplicationChecker.kt index 86742c6325..71d99e0fec 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/DeduplicationChecker.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/DeduplicationChecker.kt @@ -2,6 +2,7 @@ package net.corda.nodeapi.internal import com.github.benmanes.caffeine.cache.CacheLoader import com.github.benmanes.caffeine.cache.Caffeine +import net.corda.core.internal.buildNamed import java.time.Duration import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicLong @@ -9,11 +10,11 @@ import java.util.concurrent.atomic.AtomicLong /** * A class allowing the deduplication of a strictly incrementing sequence number. */ -class DeduplicationChecker(cacheExpiry: Duration) { +class DeduplicationChecker(cacheExpiry: Duration, name: String = "DeduplicationChecker") { // dedupe identity -> watermark cache private val watermarkCache = Caffeine.newBuilder() .expireAfterAccess(cacheExpiry.toNanos(), TimeUnit.NANOSECONDS) - .build(WatermarkCacheLoader) + .buildNamed("${name}_watermark", WatermarkCacheLoader) private object WatermarkCacheLoader : CacheLoader { override fun load(key: Any) = AtomicLong(-1) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt index 2b809e1ce9..5afeb3fe8d 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/HibernateConfiguration.kt @@ -1,6 +1,7 @@ package net.corda.nodeapi.internal.persistence import com.github.benmanes.caffeine.cache.Caffeine +import net.corda.core.internal.buildNamed import net.corda.core.internal.castIfPossible import net.corda.core.schemas.MappedSchema import net.corda.core.utilities.contextLogger @@ -57,7 +58,7 @@ class HibernateConfiguration( } } - private val sessionFactories = Caffeine.newBuilder().maximumSize(databaseConfig.mappedSchemaCacheSize).build, SessionFactory>() + private val sessionFactories = Caffeine.newBuilder().maximumSize(databaseConfig.mappedSchemaCacheSize).buildNamed, SessionFactory>("HibernateConfiguration_sessionFactories") val sessionFactoryForRegisteredSchemas = schemas.let { logger.info("Init HibernateConfiguration for schemas: $it") diff --git a/node/src/main/kotlin/net/corda/node/internal/security/RPCSecurityManagerImpl.kt b/node/src/main/kotlin/net/corda/node/internal/security/RPCSecurityManagerImpl.kt index a3e788721a..bd7fcb9f72 100644 --- a/node/src/main/kotlin/net/corda/node/internal/security/RPCSecurityManagerImpl.kt +++ b/node/src/main/kotlin/net/corda/node/internal/security/RPCSecurityManagerImpl.kt @@ -5,6 +5,7 @@ import com.github.benmanes.caffeine.cache.Cache import com.github.benmanes.caffeine.cache.Caffeine import com.google.common.primitives.Ints import net.corda.core.context.AuthServiceId +import net.corda.core.internal.buildNamed import net.corda.core.internal.uncheckedCast import net.corda.core.utilities.loggerFor import net.corda.node.internal.DataSourceFactory @@ -308,7 +309,7 @@ private class CaffeineCacheManager(val maxSize: Long, return Caffeine.newBuilder() .expireAfterWrite(timeToLiveSeconds, TimeUnit.SECONDS) .maximumSize(maxSize) - .build() + .buildNamed("RPCSecurityManagerShiroCache_$name") .toShiroCache() } diff --git a/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt b/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt index 764a6be6cd..8ed683b8bf 100644 --- a/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt +++ b/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt @@ -35,6 +35,7 @@ class PersistentIdentityService : SingletonSerializeAsToken(), IdentityServiceIn fun createPKMap(): AppendOnlyPersistentMap { return AppendOnlyPersistentMap( + "PersistentIdentityService_partyByKey", toPersistentEntityKey = { it.toString() }, fromPersistentEntity = { Pair( @@ -51,6 +52,7 @@ class PersistentIdentityService : SingletonSerializeAsToken(), IdentityServiceIn fun createX500Map(): AppendOnlyPersistentMap { return AppendOnlyPersistentMap( + "PersistentIdentityService_partyByName", toPersistentEntityKey = { it.toString() }, fromPersistentEntity = { Pair(CordaX500Name.parse(it.name), SecureHash.parse(it.publicKeyHash)) }, toPersistentEntity = { key: CordaX500Name, value: SecureHash -> diff --git a/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt b/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt index 14c659f74f..fe9107a5b1 100644 --- a/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt +++ b/node/src/main/kotlin/net/corda/node/services/keys/PersistentKeyManagementService.kt @@ -49,6 +49,7 @@ class PersistentKeyManagementService(val identityService: PersistentIdentityServ private companion object { fun createKeyMap(): AppendOnlyPersistentMap { return AppendOnlyPersistentMap( + "PersistentKeyManagementService_keys", toPersistentEntityKey = { it.toStringShort() }, fromPersistentEntity = { Pair(Crypto.decodePublicKey(it.publicKey), Crypto.decodePrivateKey( it.privateKey)) }, diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessageDeduplicator.kt b/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessageDeduplicator.kt index ddcb02a80d..fcf89d2177 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessageDeduplicator.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/P2PMessageDeduplicator.kt @@ -25,6 +25,7 @@ class P2PMessageDeduplicator(private val database: CordaPersistence) { private fun createProcessedMessages(): AppendOnlyPersistentMap { return AppendOnlyPersistentMap( + "P2PMessageDeduplicator_processedMessages", toPersistentEntityKey = { it.toString }, fromPersistentEntity = { Pair(DeduplicationId(it.id), MessageMeta(it.insertionTime, it.hash, it.seqNo)) }, toPersistentEntity = { key: DeduplicationId, value: MessageMeta -> diff --git a/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt b/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt index 9fcb4a83f0..f47f97dc7b 100644 --- a/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt +++ b/node/src/main/kotlin/net/corda/node/services/messaging/RPCServer.kt @@ -13,6 +13,7 @@ import net.corda.core.context.Trace import net.corda.core.context.Trace.InvocationId import net.corda.core.identity.CordaX500Name import net.corda.core.internal.LifeCycle +import net.corda.core.internal.buildNamed import net.corda.core.messaging.RPCOps import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.SerializationDefaults @@ -153,7 +154,7 @@ class RPCServer( log.debug { "Unsubscribing from Observable with id $key because of $cause" } value!!.subscription.unsubscribe() } - return Caffeine.newBuilder().removalListener(onObservableRemove).executor(SameThreadExecutor.getExecutor()).build() + return Caffeine.newBuilder().removalListener(onObservableRemove).executor(SameThreadExecutor.getExecutor()).buildNamed("RPCServer_observableSubscription") } fun start(activeMqServerControl: ActiveMQServerControl) { diff --git a/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt b/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt index 8c77573259..c2fbf40dac 100644 --- a/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt +++ b/node/src/main/kotlin/net/corda/node/services/network/PersistentNetworkMapCache.kt @@ -122,7 +122,9 @@ open class PersistentNetworkMapCache(private val database: CordaPersistence, override fun getNodesByLegalIdentityKey(identityKey: PublicKey): List = nodesByKeyCache[identityKey]!! - private val nodesByKeyCache = NonInvalidatingCache>(1024) { key -> + private val nodesByKeyCache = NonInvalidatingCache>( + "PersistentNetworkMap_nodesByKey", + 1024) { key -> database.transaction { queryByIdentityKey(session, key) } } @@ -140,7 +142,9 @@ open class PersistentNetworkMapCache(private val database: CordaPersistence, return identityByLegalNameCache.get(name)!!.orElse(null) } - private val identityByLegalNameCache = NonInvalidatingCache>(1024) { name -> + private val identityByLegalNameCache = NonInvalidatingCache>( + "PersistentNetworkMap_idByLegalName", + 1024) { name -> Optional.ofNullable(database.transaction { queryIdentityByLegalName(session, name) }) } diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorage.kt b/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorage.kt index 9d958870c4..1fe72c50a9 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorage.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/DBTransactionStorage.kt @@ -52,6 +52,7 @@ class DBTransactionStorage(cacheSizeBytes: Long, private val database: CordaPers fun createTransactionsMap(maxSizeInBytes: Long) : AppendOnlyPersistentMapBase { return WeightBasedAppendOnlyPersistentMap( + name = "DBTransactionStorage_transactions", toPersistentEntityKey = { it.toString() }, fromPersistentEntity = { Pair(SecureHash.parse(it.txId), diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt b/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt index 93a8753616..78a62f2149 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt @@ -206,6 +206,7 @@ class NodeAttachmentService( // a problem somewhere else or this needs to be revisited. private val attachmentContentCache = NonInvalidatingWeightBasedCache( + name = "NodeAttachmentService_attachmentContent", maxWeight = attachmentContentCacheSize, weigher = Weigher>> { key, value -> key.size + if (value.isPresent) value.get().second.size else 0 }, loadFunction = { Optional.ofNullable(loadAttachmentContent(it)) } @@ -226,7 +227,9 @@ class NodeAttachmentService( } } - private val attachmentCache = NonInvalidatingCache>(attachmentCacheBound) { key -> + private val attachmentCache = NonInvalidatingCache>( + "NodeAttachmentService_attachemnt", + attachmentCacheBound) { key -> Optional.ofNullable(createAttachment(key)) } diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/NodePropertiesPersistentStore.kt b/node/src/main/kotlin/net/corda/node/services/persistence/NodePropertiesPersistentStore.kt index cc6720c0ed..ae10d94435 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/NodePropertiesPersistentStore.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/NodePropertiesPersistentStore.kt @@ -48,6 +48,7 @@ class FlowsDrainingModeOperationsImpl(readPhysicalNodeId: () -> String, private } internal val map = PersistentMap( + "FlowDrainingMode_nodeProperties", { key -> key }, { entity -> entity.key to entity.value!! }, NodePropertiesPersistentStore::DBNodeProperty, diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt b/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt index b2aaac22b1..d6963e7130 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/BFTNonValidatingNotaryService.kt @@ -102,6 +102,7 @@ class BFTNonValidatingNotaryService( private fun createMap(): AppendOnlyPersistentMap { return AppendOnlyPersistentMap( + "BFTNonValidatingNotaryService_transactions", toPersistentEntityKey = { PersistentStateRef(it.txhash.toString(), it.index) }, fromPersistentEntity = { //TODO null check will become obsolete after making DB/JPA columns not nullable diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/PersistentUniquenessProvider.kt b/node/src/main/kotlin/net/corda/node/services/transactions/PersistentUniquenessProvider.kt index a6d8eaa207..e0ab98b9e5 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/PersistentUniquenessProvider.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/PersistentUniquenessProvider.kt @@ -77,6 +77,7 @@ class PersistentUniquenessProvider(val clock: Clock) : UniquenessProvider, Singl private val log = contextLogger() fun createMap(): AppendOnlyPersistentMap = AppendOnlyPersistentMap( + "PersistentUniquenessProvider_transactions", toPersistentEntityKey = { PersistentStateRef(it.txhash.toString(), it.index) }, fromPersistentEntity = { //TODO null check will become obsolete after making DB/JPA columns not nullable diff --git a/node/src/main/kotlin/net/corda/node/services/transactions/RaftUniquenessProvider.kt b/node/src/main/kotlin/net/corda/node/services/transactions/RaftUniquenessProvider.kt index 0065ada6b9..1e5c46d28b 100644 --- a/node/src/main/kotlin/net/corda/node/services/transactions/RaftUniquenessProvider.kt +++ b/node/src/main/kotlin/net/corda/node/services/transactions/RaftUniquenessProvider.kt @@ -61,6 +61,7 @@ class RaftUniquenessProvider( private val log = contextLogger() fun createMap(): AppendOnlyPersistentMap, CommittedState, PersistentStateRef> = AppendOnlyPersistentMap( + "RaftUniquenessProvider_transactions", toPersistentEntityKey = { PersistentStateRef(it) }, fromPersistentEntity = { val txId = it.id.txId diff --git a/node/src/main/kotlin/net/corda/node/services/upgrade/ContractUpgradeServiceImpl.kt b/node/src/main/kotlin/net/corda/node/services/upgrade/ContractUpgradeServiceImpl.kt index 5d1e95f9d7..e6924dd3c7 100644 --- a/node/src/main/kotlin/net/corda/node/services/upgrade/ContractUpgradeServiceImpl.kt +++ b/node/src/main/kotlin/net/corda/node/services/upgrade/ContractUpgradeServiceImpl.kt @@ -28,6 +28,7 @@ class ContractUpgradeServiceImpl : ContractUpgradeService, SingletonSerializeAsT private companion object { fun createContractUpgradesMap(): PersistentMap { return PersistentMap( + "ContractUpgradeService_upgrades", toPersistentEntityKey = { it }, fromPersistentEntity = { Pair(it.stateRef, it.upgradedContractClassName ?: "") }, toPersistentEntity = { key: String, value: String -> diff --git a/node/src/main/kotlin/net/corda/node/utilities/AppendOnlyPersistentMap.kt b/node/src/main/kotlin/net/corda/node/utilities/AppendOnlyPersistentMap.kt index 549c2d2486..274ceb6c5a 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/AppendOnlyPersistentMap.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/AppendOnlyPersistentMap.kt @@ -309,6 +309,7 @@ abstract class AppendOnlyPersistentMapBase( // Open for tests to override open class AppendOnlyPersistentMap( + name: String, toPersistentEntityKey: (K) -> EK, fromPersistentEntity: (E) -> Pair, toPersistentEntity: (key: K, value: V) -> E, @@ -321,6 +322,7 @@ open class AppendOnlyPersistentMap( persistentEntityClass) { //TODO determine cacheBound based on entity class later or with node config allowing tuning, or using some heuristic based on heap size override val cache = NonInvalidatingCache( + name = name, bound = cacheBound, loadFunction = { key: K -> // This gets called if a value is read and the cache has no Transactional for this key yet. @@ -353,6 +355,7 @@ open class AppendOnlyPersistentMap( // Same as above, but with weighted values (e.g. memory footprint sensitive). class WeightBasedAppendOnlyPersistentMap( + name: String, toPersistentEntityKey: (K) -> EK, fromPersistentEntity: (E) -> Pair, toPersistentEntity: (key: K, value: V) -> E, @@ -365,6 +368,7 @@ class WeightBasedAppendOnlyPersistentMap( toPersistentEntity, persistentEntityClass) { override val cache = NonInvalidatingWeightBasedCache( + name, maxWeight = maxWeight, weigher = Weigher { key, value -> weighingFunc(key, value) }, loadFunction = { key: K -> diff --git a/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingCache.kt b/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingCache.kt index 5de030ddf8..814ef0102e 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingCache.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingCache.kt @@ -4,18 +4,19 @@ import com.github.benmanes.caffeine.cache.CacheLoader import com.github.benmanes.caffeine.cache.Caffeine import com.github.benmanes.caffeine.cache.LoadingCache import com.github.benmanes.caffeine.cache.Weigher +import net.corda.core.internal.buildNamed class NonInvalidatingCache private constructor( val cache: LoadingCache ) : LoadingCache by cache { - constructor(bound: Long, loadFunction: (K) -> V) : - this(buildCache(bound, loadFunction)) + constructor(name: String, bound: Long, loadFunction: (K) -> V) : + this(buildCache(name, bound, loadFunction)) private companion object { - private fun buildCache(bound: Long, loadFunction: (K) -> V): LoadingCache { + private fun buildCache(name: String, bound: Long, loadFunction: (K) -> V): LoadingCache { val builder = Caffeine.newBuilder().maximumSize(bound) - return builder.build(NonInvalidatingCacheLoader(loadFunction)) + return builder.buildNamed(name, NonInvalidatingCacheLoader(loadFunction)) } } @@ -32,13 +33,13 @@ class NonInvalidatingCache private constructor( class NonInvalidatingWeightBasedCache private constructor( val cache: LoadingCache ) : LoadingCache by cache { - constructor (maxWeight: Long, weigher: Weigher, loadFunction: (K) -> V) : - this(buildCache(maxWeight, weigher, loadFunction)) + constructor (name: String, maxWeight: Long, weigher: Weigher, loadFunction: (K) -> V) : + this(buildCache(name, maxWeight, weigher, loadFunction)) private companion object { - private fun buildCache(maxWeight: Long, weigher: Weigher, loadFunction: (K) -> V): LoadingCache { + private fun buildCache(name: String, maxWeight: Long, weigher: Weigher, loadFunction: (K) -> V): LoadingCache { val builder = Caffeine.newBuilder().maximumWeight(maxWeight).weigher(weigher) - return builder.build(NonInvalidatingCache.NonInvalidatingCacheLoader(loadFunction)) + return builder.buildNamed(name, NonInvalidatingCache.NonInvalidatingCacheLoader(loadFunction)) } } } \ No newline at end of file diff --git a/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingUnboundCache.kt b/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingUnboundCache.kt index 601825feaf..f16ec74f8f 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingUnboundCache.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/NonInvalidatingUnboundCache.kt @@ -5,20 +5,21 @@ import com.github.benmanes.caffeine.cache.CacheLoader import com.github.benmanes.caffeine.cache.Caffeine import com.github.benmanes.caffeine.cache.LoadingCache import com.github.benmanes.caffeine.cache.RemovalListener +import net.corda.core.internal.buildNamed class NonInvalidatingUnboundCache private constructor( val cache: LoadingCache ) : LoadingCache by cache { - constructor(loadFunction: (K) -> V, removalListener: RemovalListener = RemovalListener { _, _, _ -> }, + constructor(name: String, loadFunction: (K) -> V, removalListener: RemovalListener = RemovalListener { _, _, _ -> }, keysToPreload: () -> Iterable = { emptyList() }) : - this(buildCache(loadFunction, removalListener, keysToPreload)) + this(buildCache(name, loadFunction, removalListener, keysToPreload)) private companion object { - private fun buildCache(loadFunction: (K) -> V, removalListener: RemovalListener, + private fun buildCache(name: String, loadFunction: (K) -> V, removalListener: RemovalListener, keysToPreload: () -> Iterable): LoadingCache { val builder = Caffeine.newBuilder().removalListener(removalListener).executor(SameThreadExecutor.getExecutor()) - return builder.build(NonInvalidatingCacheLoader(loadFunction)).apply { + return builder.buildNamed(name, NonInvalidatingCacheLoader(loadFunction)).apply { getAll(keysToPreload()) } } diff --git a/node/src/main/kotlin/net/corda/node/utilities/PersistentMap.kt b/node/src/main/kotlin/net/corda/node/utilities/PersistentMap.kt index 8e60880eae..2f04ea7bbe 100644 --- a/node/src/main/kotlin/net/corda/node/utilities/PersistentMap.kt +++ b/node/src/main/kotlin/net/corda/node/utilities/PersistentMap.kt @@ -10,6 +10,7 @@ import java.util.* * Implements an unbound caching layer on top of a table accessed via Hibernate mapping. */ class PersistentMap( + name: String, val toPersistentEntityKey: (K) -> EK, val fromPersistentEntity: (E) -> Pair, val toPersistentEntity: (key: K, value: V) -> E, @@ -21,6 +22,7 @@ class PersistentMap( } private val cache = NonInvalidatingUnboundCache( + name, loadFunction = { key -> Optional.ofNullable(loadValue(key)) }, removalListener = ExplicitRemoval(toPersistentEntityKey, persistentEntityClass) ) diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/AppendOnlyPersistentMapTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/AppendOnlyPersistentMapTest.kt index b6ec99f77d..69646a6ccc 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/AppendOnlyPersistentMapTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/AppendOnlyPersistentMapTest.kt @@ -271,6 +271,7 @@ class AppendOnlyPersistentMapTest(var scenario: Scenario) { ) class TestMap : AppendOnlyPersistentMap( + "ApoendOnlyPersistentMap_test", toPersistentEntityKey = { it }, fromPersistentEntity = { Pair(it.key, it.value) }, toPersistentEntity = { key: Long, value: String -> diff --git a/node/src/test/kotlin/net/corda/node/utilities/PersistentMapTests.kt b/node/src/test/kotlin/net/corda/node/utilities/PersistentMapTests.kt index c8180e7e7e..baaf99a34f 100644 --- a/node/src/test/kotlin/net/corda/node/utilities/PersistentMapTests.kt +++ b/node/src/test/kotlin/net/corda/node/utilities/PersistentMapTests.kt @@ -16,6 +16,7 @@ class PersistentMapTests { //create a test map using an existing db table private fun createTestMap(): PersistentMap { return PersistentMap( + "Test_test", toPersistentEntityKey = { it }, fromPersistentEntity = { Pair(it.stateRef, it.upgradedContractClassName ?: "") }, toPersistentEntity = { key: String, value: String -> diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/SerializationScheme.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/SerializationScheme.kt index 9c78e01926..e94e2b95b4 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/SerializationScheme.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/SerializationScheme.kt @@ -6,6 +6,7 @@ import net.corda.core.DeleteForDJVM import net.corda.core.KeepForDJVM import net.corda.core.contracts.Attachment import net.corda.core.crypto.SecureHash +import net.corda.core.internal.buildNamed import net.corda.core.internal.copyBytes import net.corda.core.serialization.* import net.corda.core.utilities.ByteSequence @@ -76,7 +77,7 @@ data class SerializationContextImpl @JvmOverloads constructor(override val prefe */ @DeleteForDJVM internal class AttachmentsClassLoaderBuilder(private val properties: Map, private val deserializationClassLoader: ClassLoader) { - private val cache: Cache, AttachmentsClassLoader> = Caffeine.newBuilder().weakValues().maximumSize(1024).build() + private val cache: Cache, AttachmentsClassLoader> = Caffeine.newBuilder().weakValues().maximumSize(1024).buildNamed("SerializationScheme_attachmentClassloader") fun build(attachmentHashes: List): AttachmentsClassLoader? { val serializationContext = properties[serializationContextKey] as? SerializeAsTokenContext ?: return null // Some tests don't set one. diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/identicon/IdenticonRenderer.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/identicon/IdenticonRenderer.kt index 97a8549688..db17fc7749 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/identicon/IdenticonRenderer.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/identicon/IdenticonRenderer.kt @@ -14,6 +14,7 @@ import javafx.scene.image.WritableImage import javafx.scene.paint.Color import javafx.scene.text.TextAlignment import net.corda.core.crypto.SecureHash +import net.corda.core.internal.buildNamed /** * (The MIT License) @@ -75,7 +76,7 @@ object IdenticonRenderer { private const val renderingSize = 30.0 - private val cache = Caffeine.newBuilder().build(CacheLoader { key -> + private val cache = Caffeine.newBuilder().buildNamed("IdentIconRenderer_image", CacheLoader { key -> key.let { render(key.hashCode(), renderingSize) } })