[LL FIR] FileStructure: avoid synchronizations on cache access

From `ConcurrentMap#compute`
>The entire method invocation is performed atomically.
>Some attempted update operations on this map by other threads may
>be blocked while computation is in progress, so the computation
>should be short and simple

And we can call resolution (`reanalyze()`) under this synchronized
block that can take unpredictable time.

This fix drops all heavy operations from synchronization
This commit is contained in:
Dmitrii Gridin
2023-07-20 12:44:02 +02:00
committed by Space Team
parent 5c5367d377
commit dc56c5cf9e
@@ -87,26 +87,32 @@ internal class FileStructure private constructor(
}
private fun getStructureElementForDeclaration(declaration: KtElement): FileStructureElement {
val structureElement = structureElements.compute(declaration) { _, structureElement ->
when {
structureElement == null -> createStructureElement(declaration)
structureElement is ReanalyzableStructureElement<*, *> && !structureElement.isUpToDate() -> {
structureElement.reanalyze()
}
else -> structureElement
}
val elementFromCache = structureElements[declaration]
if (elementFromCache == null) {
val newElement = createStructureElement(declaration)
return structureElements.putIfAbsent(declaration, newElement) ?: newElement
}
return structureElement ?: errorWithFirSpecificEntries(
"FileStructureElement for was not defined for ${declaration::class.simpleName}",
if (elementFromCache !is ReanalyzableStructureElement<*, *> || elementFromCache.isUpToDate()) {
return elementFromCache
}
val reanalyzedElement = elementFromCache.reanalyze()
return structureElements.merge(declaration, reanalyzedElement) { _, oldElement ->
if (oldElement === elementFromCache) {
reanalyzedElement
} else {
// Another thread already reanalyzed the declaration
oldElement
}
} ?: errorWithFirSpecificEntries(
"${reanalyzedElement::class.simpleName} for ${declaration::class.simpleName} is gone",
psi = declaration,
)
}
fun getAllDiagnosticsForFile(diagnosticCheckerFilter: DiagnosticCheckerFilter): Collection<KtPsiDiagnostic> {
val structureElements = getAllStructureElements()
return buildList {
collectDiagnosticsFromStructureElements(structureElements, diagnosticCheckerFilter)
}