void (@NotNull Project project, @NotNull List<FileSet> fileSets, @NotNull ProgressIndicator indicator) { if (ContainerUtil.and(fileSets, b -> b.files.isEmpty())) { return; } indicator.checkCanceled(); indicator.setIndeterminate(false); CachedFileContentLoader contentLoader = new CurrentProjectHintedCachedFileContentLoader(project); ProgressIndicator originalIndicator = unwrapAll(indicator); ProgressSuspender originalSuspender = ProgressSuspender.getSuspender(originalIndicator); IndexingJob indexingJob = new IndexingJob(project, indicator, contentLoader, fileSets, originalIndicator, originalSuspender); if (ApplicationManager.getApplication().isWriteAccessAllowed()) { // If the current thread has acquired the write lock, we can't grant it to worker threads, so we must do the work in the current thread. while (!indexingJob.areAllFilesProcessed()) { indexOneFileOfJob(indexingJob); } } else { ourIndexingJobs.add(indexingJob); try { AtomicInteger numberOfRunningWorkers = new AtomicInteger(); Runnable worker = () -> { try { indexJobsFairly(); } finally { numberOfRunningWorkers.decrementAndGet(); } }; for (int i = 0; i < myNumberOfIndexingThreads; i++) { myIndexingExecutor.execute(worker); numberOfRunningWorkers.incrementAndGet(); } while (!project.isDisposed() && !indexingJob.areAllFilesProcessed() && indexingJob.myError.get() == null) { // Internally checks for suspension of the indexing and blocks the current thread if necessary. indicator.checkCanceled(); // Add workers if the previous have stopped for whatever reason. int toAddWorkersNumber = myNumberOfIndexingThreads - numberOfRunningWorkers.get(); for (int i = 0; i < toAddWorkersNumber; i++) { myIndexingExecutor.execute(worker); numberOfRunningWorkers.incrementAndGet(); } try { if (indexingJob.myAllFilesAreProcessedLatch.await(100, TimeUnit.MILLISECONDS)) { break; } } catch (InterruptedException e) { throw new ProcessCanceledException(e); } } Throwable error = indexingJob.myError.get(); if (error instanceof ProcessCanceledException) { // The original error has happened in a different thread. Make stacktrace easier to understand by wrapping PCE into PCE ProcessCanceledException pce = new ProcessCanceledException(); pce.addSuppressed(error); throw pce; } if (error != null) { throw new RuntimeException("Indexing of " + project.getName() + " has failed", error); } } finally { ourIndexingJobs.remove(indexingJob); } } }