mirror of
https://github.com/corda/corda.git
synced 2025-06-21 16:49:45 +00:00
Avoid constructing a lookup/builder if the type is already cached (#4294)
This commit is contained in:
@ -54,11 +54,12 @@ sealed class LocalTypeInformation {
|
|||||||
* types beginning the with provided [Type] and construct a complete set of [LocalTypeInformation] for that type.
|
* types beginning the with provided [Type] and construct a complete set of [LocalTypeInformation] for that type.
|
||||||
*
|
*
|
||||||
* @param type The [Type] to obtain [LocalTypeInformation] for.
|
* @param type The [Type] to obtain [LocalTypeInformation] for.
|
||||||
|
* @param typeIdentifier The [TypeIdentifier] for the [Type] to obtain [LocalTypeInformation] for.
|
||||||
* @param lookup The [LocalTypeLookup] to use to find previously-constructed [LocalTypeInformation].
|
* @param lookup The [LocalTypeLookup] to use to find previously-constructed [LocalTypeInformation].
|
||||||
*/
|
*/
|
||||||
fun forType(type: Type, lookup: LocalTypeLookup): LocalTypeInformation {
|
fun forType(type: Type, typeIdentifier: TypeIdentifier, lookup: LocalTypeLookup): LocalTypeInformation {
|
||||||
val builder = LocalTypeInformationBuilder(lookup)
|
val builder = LocalTypeInformationBuilder(lookup)
|
||||||
val result = builder.build(type, TypeIdentifier.forGenericType(type))
|
val result = builder.build(type, typeIdentifier)
|
||||||
|
|
||||||
// Patch every cyclic reference with a `follow` property pointing to the type information it refers to.
|
// Patch every cyclic reference with a `follow` property pointing to the type information it refers to.
|
||||||
builder.cycles.forEach { cycle ->
|
builder.cycles.forEach { cycle ->
|
||||||
|
@ -41,12 +41,6 @@ interface LocalTypeModel {
|
|||||||
* @param type The [Type] to get [LocalTypeInformation] for.
|
* @param type The [Type] to get [LocalTypeInformation] for.
|
||||||
*/
|
*/
|
||||||
fun inspect(type: Type): LocalTypeInformation
|
fun inspect(type: Type): LocalTypeInformation
|
||||||
|
|
||||||
/**
|
|
||||||
* Get [LocalTypeInformation] directly from the registry by [TypeIdentifier], returning null if no type information
|
|
||||||
* is registered for that identifier.
|
|
||||||
*/
|
|
||||||
operator fun get(typeIdentifier: TypeIdentifier): LocalTypeInformation?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,20 +49,51 @@ interface LocalTypeModel {
|
|||||||
*
|
*
|
||||||
* @param typeModelConfiguration Configuration controlling the behaviour of the [LocalTypeModel]'s type inspection.
|
* @param typeModelConfiguration Configuration controlling the behaviour of the [LocalTypeModel]'s type inspection.
|
||||||
*/
|
*/
|
||||||
class ConfigurableLocalTypeModel(private val typeModelConfiguration: LocalTypeModelConfiguration): LocalTypeModel, LocalTypeLookup {
|
class ConfigurableLocalTypeModel(private val typeModelConfiguration: LocalTypeModelConfiguration): LocalTypeModel {
|
||||||
|
|
||||||
private val typeInformationCache = DefaultCacheProvider.createCache<TypeIdentifier, LocalTypeInformation>()
|
private val typeInformationCache = DefaultCacheProvider.createCache<TypeIdentifier, LocalTypeInformation>()
|
||||||
|
|
||||||
override fun isExcluded(type: Type): Boolean = typeModelConfiguration.isExcluded(type)
|
/**
|
||||||
|
* We need to provide the [TypeInformationBuilder] with a temporary local cache, so that it doesn't leak
|
||||||
|
* [LocalTypeInformation] with unpatched cycles into the global cache where other threads can access them
|
||||||
|
* before we've patched the cycles up.
|
||||||
|
*/
|
||||||
|
private class BuilderLookup(
|
||||||
|
private val globalCache: MutableMap<TypeIdentifier, LocalTypeInformation>,
|
||||||
|
private val typeModelConfiguration: LocalTypeModelConfiguration) : LocalTypeLookup {
|
||||||
|
|
||||||
override fun inspect(type: Type): LocalTypeInformation = LocalTypeInformation.forType(type, this)
|
private val localCache: MutableMap<TypeIdentifier, LocalTypeInformation> = mutableMapOf()
|
||||||
|
|
||||||
override fun findOrBuild(type: Type, typeIdentifier: TypeIdentifier, builder: (Boolean) -> LocalTypeInformation): LocalTypeInformation =
|
/**
|
||||||
this[typeIdentifier] ?: builder(typeModelConfiguration.isOpaque(type)).apply {
|
* Read from the global cache (which contains only cycle-resolved type information), falling through
|
||||||
typeInformationCache.putIfAbsent(typeIdentifier, this)
|
* to the local cache if the type isn't there yet.
|
||||||
|
*/
|
||||||
|
override fun findOrBuild(type: Type, typeIdentifier: TypeIdentifier, builder: (Boolean) -> LocalTypeInformation): LocalTypeInformation =
|
||||||
|
globalCache[typeIdentifier] ?:
|
||||||
|
localCache.getOrPut(typeIdentifier) { builder(typeModelConfiguration.isOpaque(type)) }
|
||||||
|
|
||||||
|
override fun isExcluded(type: Type): Boolean = typeModelConfiguration.isExcluded(type)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge the local cache back into the global cache, once we've finished traversal (and patched all cycles).
|
||||||
|
*/
|
||||||
|
fun merge() {
|
||||||
|
localCache.forEach { (identifier, information) ->
|
||||||
|
globalCache.putIfAbsent(identifier, information)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override operator fun get(typeIdentifier: TypeIdentifier): LocalTypeInformation? = typeInformationCache[typeIdentifier]
|
override fun inspect(type: Type): LocalTypeInformation {
|
||||||
|
val typeIdentifier = TypeIdentifier.forGenericType(type)
|
||||||
|
|
||||||
|
return typeInformationCache.getOrPut(typeIdentifier) {
|
||||||
|
val lookup = BuilderLookup(typeInformationCache, typeModelConfiguration)
|
||||||
|
val result = LocalTypeInformation.forType(type, typeIdentifier, lookup)
|
||||||
|
lookup.merge()
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user