private void markDirtyRelative(@NotNull String path, int startIndex) {
    if (myPaths.size() > DIRTY_SCOPE_SIZE_THRESHOLD) {
      // Avoid performance issues for specific 'poorly mergeable' dirty path configurations.
      // This should not happen in practice.
      markEverythingDirty();
      return;
    }

    int index = startIndex;
    int previousPrefixHash = 0;

    IntList prefixHashes = new IntArrayList();
    prefixHashes.add(0);

    int prevCounter = myPathHashCounters.get(0);
    boolean needCutOff = false;

    while (index < path.length()) {
      int nextIndex = path.indexOf('/', index + 1);
      if (nextIndex == -1) nextIndex = path.length();

      int prefixHash = FilePathHashUtil.pathHashCode(myCaseSensitive, path, index, nextIndex, previousPrefixHash);

      if (myPathHashSet.contains(prefixHash)) {
        String prefix = path.substring(startIndex, nextIndex);
        if (myPaths.contains(prefix)) return;
      }

      int counter = myPathHashCounters.get(prefixHash);

      boolean addParentFolder = needCutOff && counter < prevCounter ||
                                prevCounter - counter > FOLDER_SIZE_THRESHOLD;

      if (counter < FOLDER_SIZE_THRESHOLD && prevCounter >= FOLDER_SIZE_THRESHOLD) {
        needCutOff = true; // merge current folder
      }

      if (addParentFolder) {
        if (startIndex == index) {
          markEverythingDirty();
          return;
        }

        myPaths.add(path.substring(startIndex, index));
        myPathHashSet.add(previousPrefixHash);

        for (int i = 0; i < prefixHashes.size(); i++) {
          int hash = prefixHashes.getInt(i);
          myPathHashCounters.mergeInt(hash, 1 - prevCounter, (val1, val2) -> Math.max(val1 + val2, 1));
        }
        return;
      }

      // do not increase counter - handle hash collisions
      if (counter < prevCounter) {
        prevCounter = counter;
      }

      prefixHashes.add(prefixHash);
      previousPrefixHash = prefixHash;
      index = nextIndex;
    }

    myPaths.add(path.substring(startIndex, index));
    myPathHashSet.add(previousPrefixHash);

    for (int i = 0; i < prefixHashes.size(); i++) {
      int hash = prefixHashes.getInt(i);
      myPathHashCounters.mergeInt(hash, 1, (val1, val2) -> val1 + val2);
    }
  }
private void markDirtyRelative(@NotNull String path, int startIndex)