Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Commit 3261e47

Browse files
committed
Prevent blocking by cache thread. Fix issue #280.
1 parent e81f676 commit 3261e47

File tree

2 files changed

+25
-40
lines changed

2 files changed

+25
-40
lines changed

src/main/scala/intellij/haskell/external/component/FileModuleIdentifiers.scala

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ package intellij.haskell.external.component
1919
import java.util
2020
import java.util.concurrent.TimeoutException
2121

22-
import com.github.blemale.scaffeine.{LoadingCache, Scaffeine}
22+
import com.github.blemale.scaffeine.{AsyncLoadingCache, Scaffeine}
2323
import com.intellij.openapi.application.ApplicationManager
2424
import com.intellij.openapi.project.Project
2525
import com.intellij.psi.PsiFile
@@ -39,52 +39,51 @@ object FileModuleIdentifiers {
3939

4040
private type Result = Option[ModuleIdentifiers]
4141

42-
private final val Cache: LoadingCache[Key, Result] = Scaffeine().build((k: Key) => findModuleIdentifiers(k))
42+
private final val Cache: AsyncLoadingCache[Key, Result] = Scaffeine().buildAsync((k: Key) => findModuleIdentifiers(k))
4343

4444
import scala.concurrent.ExecutionContext.Implicits.global
4545

4646
def invalidate(psiFile: PsiFile): Unit = {
47-
Cache.invalidate(Key(psiFile))
47+
Cache.synchronous.invalidate(Key(psiFile))
4848
}
4949

5050
def refresh(psiFile: PsiFile): Unit = {
51-
Cache.refresh(Key(psiFile))
51+
Cache.synchronous.refresh(Key(psiFile))
5252
}
5353

5454
// Invalidate files which have imported this module
5555
def invalidate(moduleName: String): Unit = {
56-
val keys = Cache.asMap().filter { case (_, v) => v.exists(_.exists(_.exists(_.exists(_.moduleName == moduleName)))) }.keys
57-
Cache.invalidateAll(keys)
56+
val syncCache = Cache.synchronous
57+
val keys = syncCache.asMap().filter { case (_, v) => v.exists(_.exists(_.exists(_.exists(_.moduleName == moduleName)))) }.keys
58+
syncCache.invalidateAll(keys)
5859
}
5960

6061
def invalidateAll(project: Project): Unit = {
61-
Cache.asMap().filter(_._1.psiFile.getProject == project).keys.foreach(Cache.invalidate)
62+
val syncCache = Cache.synchronous
63+
syncCache.asMap().filter(_._1.psiFile.getProject == project).keys.foreach(syncCache.invalidate)
6264
}
6365

6466
def findAvailableModuleIdentifiers(psiFile: PsiFile): Iterable[ModuleIdentifier] = {
67+
val message = s"find available module identifiers for ${psiFile.getName}"
6568
if (ApplicationManager.getApplication.isReadAccessAllowed) {
66-
val moduleIdentifiers = Future(getModuleIdentifiers(psiFile))
67-
68-
ScalaFutureUtil.waitWithCheckCancelled(psiFile.getProject, moduleIdentifiers, s"in findAvailableModuleIdentifiers to get all module identifiers for ${psiFile.getName}") match {
69-
case Some(mids) => mids.getOrElse(Iterable())
70-
case _ => Iterable()
71-
}
69+
val moduleIdentifiers = getModuleIdentifiers(psiFile)
70+
ScalaFutureUtil.waitWithCheckCancelled(psiFile.getProject, moduleIdentifiers, message).getOrElse(Iterable())
7271
} else {
73-
getModuleIdentifiers(psiFile).getOrElse(Iterable())
72+
ScalaFutureUtil.waitForValue(psiFile.getProject, getModuleIdentifiers(psiFile), message).getOrElse(Iterable())
7473
}
7574
}
7675

77-
private def getModuleIdentifiers(psiFile: PsiFile): Option[Iterable[ModuleIdentifier]] = {
76+
private def getModuleIdentifiers(psiFile: PsiFile): Future[Iterable[ModuleIdentifier]] = {
7877
val key = Key(psiFile)
79-
Cache.get(key) match {
78+
Cache.get(key) map {
8079
case Some(mids) =>
8180
if (mids.toSeq.contains(None)) {
82-
Cache.invalidate(key)
81+
Cache.synchronous.invalidate(key)
8382
}
84-
Some(mids.flatten.flatten)
83+
mids.flatten.flatten
8584
case None =>
86-
Cache.invalidate(key)
87-
None
85+
Cache.synchronous.invalidate(key)
86+
Iterable()
8887
}
8988
}
9089

src/main/scala/intellij/haskell/external/component/HaskellComponentsManager.scala

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,12 @@
1616

1717
package intellij.haskell.external.component
1818

19-
import java.util.concurrent.{Executors, TimeUnit}
19+
import java.util.concurrent.Executors
2020

21-
import com.intellij.openapi.application.ApplicationManager
2221
import com.intellij.openapi.editor.SelectionModel
2322
import com.intellij.openapi.module.Module
24-
import com.intellij.openapi.progress.ProgressManager
2523
import com.intellij.openapi.project.Project
2624
import com.intellij.psi.{PsiElement, PsiFile}
27-
import com.intellij.util.WaitFor
2825
import intellij.haskell.HaskellNotificationGroup
2926
import intellij.haskell.cabal.CabalInfo
3027
import intellij.haskell.external.component.DefinitionLocationComponent.DefinitionLocationResult
@@ -35,7 +32,7 @@ import intellij.haskell.external.repl.StackRepl.StanzaType
3532
import intellij.haskell.external.repl.StackReplsManager
3633
import intellij.haskell.psi.{HaskellPsiUtil, HaskellQualifiedNameElement}
3734
import intellij.haskell.util.index.{HaskellFileIndex, HaskellModuleNameIndex}
38-
import intellij.haskell.util.{ApplicationUtil, GhcVersion, HaskellProjectUtil, ScalaUtil}
35+
import intellij.haskell.util.{ApplicationUtil, GhcVersion, HaskellProjectUtil, ScalaFutureUtil}
3936

4037
import scala.concurrent._
4138

@@ -44,21 +41,10 @@ object HaskellComponentsManager {
4441
case class StackComponentInfo(module: Module, modulePath: String, packageName: String, target: String, stanzaType: StanzaType, sourceDirs: Seq[String], mainIs: Option[String], isImplicitPreludeActive: Boolean, buildDepends: Seq[String], exposedModuleNames: Seq[String] = Seq.empty)
4542

4643
def findModuleIdentifiersInCache(project: Project)(implicit ec: ExecutionContext): Iterable[ModuleIdentifier] = {
47-
val f = ApplicationManager.getApplication.executeOnPooledThread(ScalaUtil.callable {
48-
BrowseModuleComponent.findModuleIdentifiersInCache(project)
49-
})
50-
51-
new WaitFor(1000, 1) {
52-
override def condition(): Boolean = {
53-
ProgressManager.checkCanceled()
54-
f.isDone
55-
}
56-
}
57-
58-
if (f.isDone) {
59-
f.get(1, TimeUnit.MILLISECONDS)
60-
} else {
61-
Iterable()
44+
val f = Future(BrowseModuleComponent.findModuleIdentifiersInCache(project))
45+
ScalaFutureUtil.waitWithCheckCancelled(project, f, "find module identifiers in cache") match {
46+
case Some(ids) => ids
47+
case None => Iterable()
6248
}
6349
}
6450

0 commit comments

Comments
 (0)