Collection<VFileEvent> scan(long timeInQueue) {
    if (myWorkQueue.isEmpty()) return myEvents;
    var workQueue = myWorkQueue;
    myWorkQueue = List.of();
    var forceRefresh = !myIsRecursive && !myIsAsync;  // shallow sync refresh (e.g., project config files on open)

    var fs = LocalFileSystem.getInstance();
    if (!forceRefresh && fs instanceof LocalFileSystemImpl) {
      ((LocalFileSystemImpl)fs).markSuspiciousFilesDirty(workQueue);
    }

    if (LOG.isTraceEnabled()) LOG.trace("scanning " + workQueue);

    var t = System.nanoTime();
    PerformanceWatcher.Snapshot snapshot = null;
    Map<String, Integer> types = null;
    if (DURATION_REPORT_THRESHOLD_MS > 0) {
      snapshot = PerformanceWatcher.takeSnapshot();
      types = new HashMap<>();
    }

    var refreshRoots = new ArrayList<NewVirtualFile>(workQueue.size());
    for (var file : workQueue) {
      if (myCancelled) break;

      var nvf = (NewVirtualFile)file;
      if (forceRefresh) {
        nvf.markDirty();
      }
      if (!nvf.isDirty()) {
        continue;
      }
      refreshRoots.add(nvf);

      if (types != null) {
        var type = !file.isDirectory() ? "file" : file.getFileSystem() instanceof ArchiveFileSystem ? "arc" : "dir";
        types.put(type, types.getOrDefault(type, 0) + 1);
      }
    }

    var count = 0;
    var events = new ArrayList<VFileEvent>();
    do {
      if (myCancelled) break;
      if (LOG.isTraceEnabled()) LOG.trace("try=" + count);

      var worker = new RefreshWorker(refreshRoots, myIsRecursive);
      myWorker = worker;
      events.addAll(worker.scan());
      myWorker = null;

      count++;
      if (LOG.isTraceEnabled()) LOG.trace("events=" + events.size());
    }
    while (myIsRecursive && !myIsBackground && count < RETRY_LIMIT && ContainerUtil.exists(workQueue, f -> ((NewVirtualFile)f).isDirty()));

    t = NANOSECONDS.toMillis(System.nanoTime() - t);
    int localRoots = 0, archiveRoots = 0, otherRoots = 0;
    for (var file : refreshRoots) {
      if (file.getFileSystem() instanceof LocalFileSystem) localRoots++;
      else if (file.getFileSystem() instanceof ArchiveFileSystem) archiveRoots++;
      else otherRoots++;
    }
    VfsUsageCollector.logRefreshSession(myIsRecursive, localRoots, archiveRoots, otherRoots, myCancelled, timeInQueue, t, count);
    if (LOG.isTraceEnabled()) {
      LOG.trace((myCancelled ? "cancelled, " : "done, ") + t + " ms, tries " + count + ", events " + events);
    }
    else if (snapshot != null && t > DURATION_REPORT_THRESHOLD_MS) {
      snapshot.logResponsivenessSinceCreation(String.format(
        "Refresh session (queue size: %s, scanned: %s, result: %s, tries: %s, events: %d)",
        workQueue.size(), types, myCancelled ? "cancelled" : "done", count, events.size()));
    }

    var result = events.isEmpty() ? List.<VFileEvent>of() : new LinkedHashSet<>(events);
    myEventCount = result.size();
    return result;
  }
Collection<VFileEvent> scan(long timeInQueue)