Improve performance of Lookup storage

Reduce size of lookup map after rebuild, reduce waiting time by replacing operations of read+write with append, also split remove garbage process into smaller operations in get

#KT-46804 Fixed
This commit is contained in:
Aleksei.Cherepanov
2021-06-28 14:56:10 +03:00
committed by TeamCityServer
parent 35f6337de3
commit d2881a7920
2 changed files with 38 additions and 34 deletions
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.incremental
import com.intellij.openapi.diagnostic.Logger
import com.intellij.util.containers.MultiMap
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.incremental.components.LookupTracker
@@ -28,11 +29,14 @@ import org.jetbrains.kotlin.utils.keysToMap
import java.io.File
import java.io.IOException
import java.util.*
import kotlin.system.measureTimeMillis
open class LookupStorage(
targetDataDir: File,
pathConverter: FileToPathConverter
) : BasicMapsOwner(targetDataDir) {
val LOG = Logger.getInstance("#org.jetbrains.kotlin.jps.build.KotlinBuilder")
companion object {
private val DELETED_TO_SIZE_TRESHOLD = 0.5
private val MINIMUM_GARBAGE_COLLECTIBLE_SIZE = 10000
@@ -59,18 +63,30 @@ open class LookupStorage(
} catch (e: Exception) {
throw IOException("Could not read $countersFile", e)
}
}
@Synchronized
fun get(lookupSymbol: LookupSymbol): Collection<String> {
val key = LookupSymbolKey(lookupSymbol.name, lookupSymbol.scope)
val fileIds = lookupMap[key] ?: return emptySet()
val paths = mutableSetOf<String>()
val filtered = mutableSetOf<Int>()
for (fileId in fileIds) {
val path = idToFile[fileId]?.path
if (path != null) {
paths.add(path)
filtered.add(fileId)
}
return fileIds.mapNotNull {
// null means it's outdated
idToFile[it]?.path
}
if (size > MINIMUM_GARBAGE_COLLECTIBLE_SIZE && filtered.size.toDouble() / fileIds.size.toDouble() < DELETED_TO_SIZE_TRESHOLD) {
lookupMap[key] = filtered
}
return paths
}
@Synchronized
@@ -81,8 +97,8 @@ open class LookupStorage(
val key = LookupSymbolKey(lookupSymbol.name, lookupSymbol.scope)
val paths = lookups[lookupSymbol]
val fileIds = paths.mapTo(TreeSet()) { pathToId[it]!! }
fileIds.addAll(lookupMap[key] ?: emptySet())
lookupMap[key] = fileIds
lookupMap.append(key, fileIds)
}
}
@@ -121,8 +137,7 @@ open class LookupStorage(
countersFile.writeText("$size\n$deletedCount")
}
}
finally {
} finally {
super.flush(memoryCachesOnly)
}
}
@@ -138,41 +153,26 @@ open class LookupStorage(
}
private fun removeGarbageIfNeeded(force: Boolean = false) {
if (force || (size > MINIMUM_GARBAGE_COLLECTIBLE_SIZE && deletedCount.toDouble() / size > DELETED_TO_SIZE_TRESHOLD)) {
if (force && (size > MINIMUM_GARBAGE_COLLECTIBLE_SIZE && deletedCount.toDouble() / size > DELETED_TO_SIZE_TRESHOLD)) {
doRemoveGarbage()
}
}
private fun doRemoveGarbage() {
for (hash in lookupMap.keys) {
lookupMap[hash] = lookupMap[hash]!!.filter { it in idToFile }.toSet()
}
val oldFileToId = fileToId.toMap()
val oldIdToNewId = HashMap<Int, Int>(oldFileToId.size)
idToFile.clean()
fileToId.clean()
size = 0
deletedCount = 0
for ((file, oldId) in oldFileToId.entries.sortedBy { it.key.path }) {
val newId = addFileIfNeeded(file)
oldIdToNewId[oldId] = newId
}
for (lookup in lookupMap.keys) {
val fileIds = lookupMap[lookup]!!.mapNotNull { oldIdToNewId[it] }.toSet()
if (fileIds.isEmpty()) {
lookupMap.remove(lookup)
}
else {
lookupMap[lookup] = fileIds
val timeInMillis = measureTimeMillis {
for (hash in lookupMap.keys) {
val dirtyFileIds = lookupMap[hash]!!
val filteredFileIds = dirtyFileIds.filter { it in idToFile }.toSet()
if (dirtyFileIds != filteredFileIds) lookupMap[hash] = filteredFileIds
}
deletedCount = 0
}
LOG.debug(">>Garbage removed in $timeInMillis ms")
}
@TestOnly fun forceGC() {
@TestOnly
fun forceGC() {
removeGarbageIfNeeded(force = true)
flush(false)
}
@@ -27,6 +27,10 @@ class LookupMap(storage: File) : BasicMap<LookupSymbolKey, Collection<Int>>(stor
storage.append(LookupSymbolKey(name, scope), listOf(fileId))
}
fun append(lookup: LookupSymbolKey, fileIds: Collection<Int>) {
storage.append(lookup, fileIds)
}
operator fun get(key: LookupSymbolKey): Collection<Int>? = storage[key]
operator fun set(key: LookupSymbolKey, fileIds: Set<Int>) {