From 197a13611dd0f15fe165b3ea0c6738c932c74d17 Mon Sep 17 00:00:00 2001 From: Rick Parker Date: Tue, 22 Jan 2019 11:19:51 +0000 Subject: [PATCH] ENT-2967 Fix up use of various JDK performance contention points (#4608) * ENT-2967 Various JDK contention points * Move new private method to bottom of class. --- .../main/kotlin/net/corda/core/crypto/Crypto.kt | 12 ++++++++---- .../net/corda/core/crypto/SignatureScheme.kt | 14 +++++++++++++- .../net/corda/core/internal/ConstraintsUtils.kt | 2 +- .../serialization/internal/model/TypeIdentifier.kt | 8 +++++--- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt b/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt index 8f88762592..227f5c069b 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/Crypto.kt @@ -290,7 +290,7 @@ object Crypto { fun decodePrivateKey(encodedKey: ByteArray): PrivateKey { val keyInfo = PrivateKeyInfo.getInstance(encodedKey) val signatureScheme = findSignatureScheme(keyInfo.privateKeyAlgorithm) - val keyFactory = KeyFactory.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName]) + val keyFactory = keyFactory(signatureScheme) return keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey)) } @@ -323,7 +323,7 @@ object Crypto { "Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}" } try { - val keyFactory = KeyFactory.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName]) + val keyFactory = keyFactory(signatureScheme) return keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey)) } catch (ikse: InvalidKeySpecException) { throw InvalidKeySpecException("This private key cannot be decoded, please ensure it is PKCS8 encoded and that " + @@ -342,7 +342,7 @@ object Crypto { fun decodePublicKey(encodedKey: ByteArray): PublicKey { val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(encodedKey) val signatureScheme = findSignatureScheme(subjectPublicKeyInfo.algorithm) - val keyFactory = KeyFactory.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName]) + val keyFactory = keyFactory(signatureScheme) return keyFactory.generatePublic(X509EncodedKeySpec(encodedKey)) } @@ -377,7 +377,7 @@ object Crypto { "Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}" } try { - val keyFactory = KeyFactory.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName]) + val keyFactory = keyFactory(signatureScheme) return keyFactory.generatePublic(X509EncodedKeySpec(encodedKey)) } catch (ikse: InvalidKeySpecException) { throw throw InvalidKeySpecException("This public key cannot be decoded, please ensure it is X509 encoded and " + @@ -1063,4 +1063,8 @@ object Crypto { private fun setBouncyCastleRNG() { CryptoServicesRegistrar.setSecureRandom(newSecureRandom()) } + + private fun keyFactory(signatureScheme: SignatureScheme) = signatureScheme.getKeyFactory { + KeyFactory.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName]) + } } diff --git a/core/src/main/kotlin/net/corda/core/crypto/SignatureScheme.kt b/core/src/main/kotlin/net/corda/core/crypto/SignatureScheme.kt index c14568f9fa..4696e9b2db 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/SignatureScheme.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/SignatureScheme.kt @@ -2,6 +2,7 @@ package net.corda.core.crypto import net.corda.core.KeepForDJVM import org.bouncycastle.asn1.x509.AlgorithmIdentifier +import java.security.KeyFactory import java.security.Signature import java.security.spec.AlgorithmParameterSpec @@ -33,4 +34,15 @@ data class SignatureScheme( val algSpec: AlgorithmParameterSpec?, val keySize: Int?, val desc: String -) +) { + @Volatile + private var memoizedKeyFactory: KeyFactory? = null + + internal fun getKeyFactory(factoryFactory: () -> KeyFactory): KeyFactory { + return memoizedKeyFactory ?: run { + val newFactory = factoryFactory() + memoizedKeyFactory = newFactory + newFactory + } + } +} diff --git a/core/src/main/kotlin/net/corda/core/internal/ConstraintsUtils.kt b/core/src/main/kotlin/net/corda/core/internal/ConstraintsUtils.kt index f0f803bb22..4ab677c900 100644 --- a/core/src/main/kotlin/net/corda/core/internal/ConstraintsUtils.kt +++ b/core/src/main/kotlin/net/corda/core/internal/ConstraintsUtils.kt @@ -124,7 +124,7 @@ internal fun checkConstraintValidity(state: TransactionState<*>) { */ internal fun ContractClassName.contractHasAutomaticConstraintPropagation(classLoader: ClassLoader? = null): Boolean { return (classLoader ?: NoConstraintPropagation::class.java.classLoader) - .loadClass(this) + .run { Class.forName(this@contractHasAutomaticConstraintPropagation, false, this) } .getAnnotation(NoConstraintPropagation::class.java) == null } diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/model/TypeIdentifier.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/model/TypeIdentifier.kt index c40c75a0ad..43f0329ab9 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/model/TypeIdentifier.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/model/TypeIdentifier.kt @@ -24,7 +24,6 @@ class IncompatibleTypeIdentifierException(message: String) : NotSerializableExce * [TypeIdentifier] provides a family of type identifiers, together with a [prettyPrint] method for displaying them. */ sealed class TypeIdentifier { - /** * The name of the type. */ @@ -38,7 +37,7 @@ sealed class TypeIdentifier { * @throws IncompatibleTypeIdentifierException if the type identifier is incompatible with the locally-defined type * to which it refers. */ - abstract fun getLocalType(classLoader: ClassLoader = ClassLoader.getSystemClassLoader()): Type + abstract fun getLocalType(classLoader: ClassLoader = systemClassLoader): Type open val erased: TypeIdentifier get() = this @@ -61,6 +60,9 @@ sealed class TypeIdentifier { if (simplifyClassNames) split(".", "$").last() else this companion object { + // This method has locking. So we memo the value here. + private val systemClassLoader: ClassLoader = ClassLoader.getSystemClassLoader() + /** * Obtain the [TypeIdentifier] for an erased Java class. * @@ -204,7 +206,7 @@ sealed class TypeIdentifier { override fun toString() = "Parameterised(${prettyPrint()})" override fun getLocalType(classLoader: ClassLoader): Type { - val rawType = classLoader.loadClass(name) + val rawType = Class.forName(name, false, classLoader) if (rawType.typeParameters.size != parameters.size) { throw IncompatibleTypeIdentifierException( "Class $rawType expects ${rawType.typeParameters.size} type arguments, " +