From 25b01bf1dbac8df01673af319af97ade9a70c638 Mon Sep 17 00:00:00 2001 From: "Nikita.Skvortsov" Date: Mon, 15 Jul 2024 17:50:14 +0200 Subject: [PATCH] [es] consume source folder change events in a thread-safe way IDEA-350259 Consumer invocations may result in new operations arriving in `operationStates`, so it has to be a queue, not a simple list. Also fix usage of coroutine scope. GitOrigin-RevId: b170d1f6cf7dc2f5f2c0617aba0f88a4a6dbed6d --- .../project/manage/SourceFolderManagerImpl.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerImpl.kt b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerImpl.kt index 6d607cfa5431..f4d857648704 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerImpl.kt +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/SourceFolderManagerImpl.kt @@ -42,6 +42,8 @@ import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes import org.jetbrains.jps.model.java.JavaResourceRootType import org.jetbrains.jps.model.java.JavaSourceRootType import org.jetbrains.jps.model.module.JpsModuleSourceRootType +import java.util.concurrent.ArrayBlockingQueue +import java.util.concurrent.BlockingQueue import java.util.concurrent.Future @ApiStatus.Internal @@ -57,7 +59,7 @@ class SourceFolderManagerImpl(private val project: Project, private var sourceFolders = CanonicalPathPrefixTreeFactory.createMap() private var sourceFoldersByModule = HashMap() - private val operationsStates = mutableListOf>() + private val operationsStates: BlockingQueue> = ArrayBlockingQueue(16) @OptIn(ExperimentalCoroutinesApi::class) private val refreshFilesDispatcher = Dispatchers.IO.limitedParallelism(3) @@ -173,7 +175,7 @@ class SourceFolderManagerImpl(private val project: Project, } val application = ApplicationManager.getApplication() - val future = (project as ComponentManagerEx).getCoroutineScope().async { + val future = cs.async { blockingContext { updateSourceFolders(sourceFoldersToChange) } @@ -181,8 +183,8 @@ class SourceFolderManagerImpl(private val project: Project, if (application.isUnitTestMode) { ThreadingAssertions.assertEventDispatchThread() - operationsStates.removeIf { it.isDone } operationsStates.add(future) + future.whenComplete { _, _ -> operationsStates.remove(future) } } } @@ -326,9 +328,10 @@ class SourceFolderManagerImpl(private val project: Project, fun consumeBulkOperationsState(stateConsumer: (Future<*>) -> Unit) { ThreadingAssertions.assertEventDispatchThread() assert(ApplicationManager.getApplication().isUnitTestMode) - for (operationsState in operationsStates) { - stateConsumer.invoke(operationsState) - } + do { + val operation = operationsStates.poll() ?: break + stateConsumer.invoke(operation) + } while (true) } companion object {