[LL FIR] KT-58257 Implement active session invalidation

- This commit replaces session modification trackers with event-based
  session invalidation. The removal of modification trackers should
  improve overall performance, because session invalidation events
  happen less frequently than sessions are accessed. Getting rid of
  modification trackers also allows sessions to refer to other sessions
  lazily, which is essential when cyclic dependencies occur.
- The new `LLFirSession` validity tracker has constant complexity and
  will not cause the same kind of performance issues as dependency
  modification trackers. It is a bridge to support modification trackers
  in certain parts of the code (e.g. for `CachedValue`s), while being
  backed by event-based invalidation.
- `LLFirSessionInvalidationService` is the bridge between modification
  events and `LLFirSessionCache`. It finds out which modules should be
  invalidated and instructs the session cache to remove the associated
  sessions.
- Session invalidation must always happen in a write action to preserve
  consistency between sessions. Otherwise, while a session A is already
  removed from the cache, it might still be referenced by a dependent
  session B which is in the process of being invalidated. Such a session
  must never be returned from `getSession`.

^KT-57515 fixed
This commit is contained in:
Marco Pennekamp
2023-05-24 14:09:51 +02:00
committed by Space Team
parent 1f556589a2
commit e76692ef8d
20 changed files with 225 additions and 212 deletions
@@ -1,43 +0,0 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.utils.trackers
import com.intellij.openapi.util.ModificationTracker
import java.util.*
public class CompositeModificationTracker private constructor(private val trackers: List<ModificationTracker>) : ModificationTracker {
override fun getModificationCount(): Long = trackers.sumOf { it.modificationCount }
public companion object {
public fun create(trackers: List<ModificationTracker>): ModificationTracker {
return when (trackers.size) {
0 -> ModificationTracker.NEVER_CHANGED
1 -> trackers.single()
else -> CompositeModificationTracker(trackers)
}
}
public fun createFlattened(trackers: List<ModificationTracker>): ModificationTracker {
val set = Collections.newSetFromMap(IdentityHashMap<ModificationTracker, Boolean>())
val flattened = ArrayList<ModificationTracker>()
fun flatten(tracker: ModificationTracker) {
when (tracker) {
is CompositeModificationTracker -> tracker.trackers.forEach(::flatten)
ModificationTracker.NEVER_CHANGED -> {}
else -> {
if (set.add(tracker)) {
flattened += tracker
}
}
}
}
trackers.forEach(::flatten)
return create(flattened)
}
}
}