private synchronized VirtualFilePointerImpl getOrCreate(
      VirtualFile file,
      @NotNull String url,
      Disposable parentDisposable,
      @Nullable VirtualFilePointerListener listener,
      String path) {
    TreeMap<String, VirtualFilePointerImpl> urlToPointer = myUrlToPointerMaps.get(listener);
    if (urlToPointer == null) {
      urlToPointer = new TreeMap<String, VirtualFilePointerImpl>(COMPARATOR);
      myUrlToPointerMaps.put(listener, urlToPointer);
    }
    VirtualFilePointerImpl pointer = urlToPointer.get(path);

    if (pointer == null) {
      pointer =
          new VirtualFilePointerImpl(file, url, myVirtualFileManager, listener, parentDisposable);
      urlToPointer.put(path, pointer);
    }
    return pointer;
  }
    @Override
    public void after(@NotNull final List<? extends VFileEvent> events) {
      cleanContainerCaches();

      if (myUrlsToUpdate == null) {
        return;
      }
      for (String url : myUrlsToUpdate) {
        synchronized (VirtualFilePointerManagerImpl.this) {
          for (TreeMap<String, VirtualFilePointerImpl> urlToPointer : myUrlToPointerMaps.values()) {
            VirtualFilePointerImpl pointer = urlToPointer.remove(url);
            if (pointer != null) {
              String path = VfsUtil.urlToPath(pointer.getUrl());
              urlToPointer.put(path, pointer);
            }
          }
        }
      }

      for (VirtualFilePointer pointer : myPointersToUpdate) {
        ((VirtualFilePointerImpl) pointer).update();
      }

      for (EventDescriptor event : myEvents) {
        event.fireAfter();
      }

      if (!myPointersToUpdate.isEmpty()) {
        VirtualFilePointer[] arr =
            myPointersToUpdate.toArray(new VirtualFilePointer[myPointersToUpdate.size()]);
        myBus.syncPublisher(VirtualFilePointerListener.TOPIC).validityChanged(arr);
      }

      myUrlsToUpdate = null;
      myEvents = null;
      myPointersToUpdate = null;
    }