From 734367c4b52310c8b1a82d615d3a8249c5be2fdc Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 13 Mar 2023 14:42:56 +0100 Subject: [PATCH] IDEA-314136 PersistentFSImpl.clearIdCache is too slow GitOrigin-RevId: 3115c486c47a73e35083b2035dec8062edc73c89 --- .../newvfs/persistent/PersistentFSImpl.java | 2 +- .../persistent/VirtualDirectoryCache.java | 47 ++++++++++++------- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java index 4b191748e915..0317d46fbe5c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java @@ -1810,7 +1810,7 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable { } @TestOnly - @NotNull Collection getDirCache() { + @NotNull Iterable getDirCache() { return myIdToDirCache.getCachedDirs(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VirtualDirectoryCache.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VirtualDirectoryCache.java index c05747d37799..c2b970fec49e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VirtualDirectoryCache.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/VirtualDirectoryCache.java @@ -4,48 +4,63 @@ package com.intellij.openapi.vfs.newvfs.persistent; import com.intellij.concurrency.ConcurrentCollectionFactory; import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry; import com.intellij.util.containers.ConcurrentIntObjectMap; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; - -import java.util.Collection; +import org.jetbrains.annotations.TestOnly; final class VirtualDirectoryCache { - // FS roots must be in this map too. findFileById() relies on this. - private final ConcurrentIntObjectMap myIdToDirCache = - ConcurrentCollectionFactory.createConcurrentIntObjectSoftValueMap(); + // FS roots only (dirs with .getParent()==null) + private final ConcurrentIntObjectMap myIdToRootCache = ConcurrentCollectionFactory.createConcurrentIntObjectMap(); + // FS inner dirs only (dirs with .getParent()!=null), separated from the root cache to speedup clear + private final ConcurrentIntObjectMap myIdToDirCache = ConcurrentCollectionFactory.createConcurrentIntObjectSoftValueMap(); - @NotNull VirtualFileSystemEntry getOrCacheDir(@NotNull VirtualFileSystemEntry newDir) { + @NotNull + VirtualFileSystemEntry getOrCacheDir(@NotNull VirtualFileSystemEntry newDir) { int id = newDir.getId(); - VirtualFileSystemEntry dir = myIdToDirCache.get(id); + ConcurrentIntObjectMap cache = getCache(newDir); + VirtualFileSystemEntry dir = cache.get(id); if (dir != null) return dir; - return myIdToDirCache.cacheOrGet(id, newDir); + return cache.cacheOrGet(id, newDir); + } + + private ConcurrentIntObjectMap getCache(@NotNull VirtualFileSystemEntry newDir) { + return newDir.getParent() == null ? myIdToRootCache : myIdToDirCache; } void cacheDir(@NotNull VirtualFileSystemEntry newDir) { - myIdToDirCache.put(newDir.getId(), newDir); + getCache(newDir).put(newDir.getId(), newDir); } - @Nullable VirtualFileSystemEntry cacheDirIfAbsent(@NotNull VirtualFileSystemEntry newDir) { - return myIdToDirCache.putIfAbsent(newDir.getId(), newDir); + @Nullable + VirtualFileSystemEntry cacheDirIfAbsent(@NotNull VirtualFileSystemEntry newDir) { + return getCache(newDir).putIfAbsent(newDir.getId(), newDir); } - @Nullable VirtualFileSystemEntry getCachedDir(int id) { - return myIdToDirCache.get(id); + @Nullable + VirtualFileSystemEntry getCachedDir(int id) { + VirtualFileSystemEntry dir = myIdToDirCache.get(id); + if (dir != null) return dir; + return myIdToRootCache.get(id); } void dropNonRootCachedDirs() { - myIdToDirCache.entrySet().removeIf(e -> e.getValue().getParent() != null); + myIdToDirCache.clear(); } void remove(int id) { myIdToDirCache.remove(id); + myIdToRootCache.remove(id); } - @NotNull Collection getCachedDirs() { - return myIdToDirCache.values(); + @TestOnly + @NotNull + Iterable getCachedDirs() { + return ContainerUtil.concat(myIdToDirCache.values(), myIdToRootCache.values()); } void clear() { myIdToDirCache.clear(); + myIdToRootCache.clear(); } }