Avoid constructing a lookup/builder if the type is already cached (#4294)

This commit is contained in:
Dominic Fox 2018-11-26 13:48:32 +00:00 committed by GitHub
parent a4fd7d2356
commit 766681c0e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 15 deletions

View File

@ -54,11 +54,12 @@ sealed class LocalTypeInformation {
* 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 typeIdentifier The [TypeIdentifier] for the [Type] to obtain [LocalTypeInformation] for.
* @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 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.
builder.cycles.forEach { cycle ->

View File

@ -41,12 +41,6 @@ interface LocalTypeModel {
* @param type The [Type] to get [LocalTypeInformation] for.
*/
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.
*/
class ConfigurableLocalTypeModel(private val typeModelConfiguration: LocalTypeModelConfiguration): LocalTypeModel, LocalTypeLookup {
class ConfigurableLocalTypeModel(private val typeModelConfiguration: LocalTypeModelConfiguration): LocalTypeModel {
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 {
typeInformationCache.putIfAbsent(typeIdentifier, this)
/**
* Read from the global cache (which contains only cycle-resolved type information), falling through
* 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
}
}
}
/**