[vfs] IJPL-189502 cache-avoiding files use already cached children if available

+ cache-avoiding VirtualFile impl uses already loaded children from VFS, if they are available, instead of accessing the underlying FS

GitOrigin-RevId: 541d5007c0de2331f44f3efefecbdb9930d9da99
This commit is contained in:
Ruslan Cheremin
2025-10-09 21:29:22 +00:00
committed by intellij-monorepo-bot
parent a21e674a8a
commit d5e89ac267
6 changed files with 40 additions and 10 deletions
@@ -342,6 +342,7 @@ c:com.intellij.openapi.fileEditor.OpenFileDescriptor
a:com.intellij.openapi.vfs.newvfs.NewVirtualFile
- com.intellij.openapi.vfs.VirtualFile
- com.intellij.openapi.vfs.VirtualFileWithId
- *:allChildrenLoaded():Z
- *a:isOffline():Z
- *a:setOffline(Z):V
a:com.intellij.openapi.vfs.newvfs.RefreshQueue
@@ -16,6 +16,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.Collection;
import java.util.function.Supplier;
/**
@@ -71,7 +72,13 @@ public final class CacheAvoidingVirtualFileWrapper extends VirtualFile implement
@Override
public VirtualFile[] getChildren() {
//MAYBE RC: cache children once calculated?
if (wrappedFile.allChildrenLoaded()) {//fast-track:
Collection<VirtualFile> cachedChildren = wrappedFile.getCachedChildren();
return cachedChildren.stream()
.map(child -> ((NewVirtualFile)child).asCacheAvoiding())
.toArray(VirtualFile[]::new);
}
NewVirtualFileSystem fileSystem = wrappedFile.getFileSystem();
String[] childNames = fileSystem.list(wrappedFile);
VirtualFile[] children = new VirtualFile[childNames.length];
@@ -84,7 +91,7 @@ public final class CacheAvoidingVirtualFileWrapper extends VirtualFile implement
}
@Override
public @Nullable VirtualFile findChild(@NotNull String childName) {
public VirtualFile findChild(@NotNull String childName) {
NewVirtualFileSystem fileSystem = wrappedFile.getFileSystem();
NewVirtualFile child = wrappedFile.findChildIfCached(childName);
if (child != null) {
@@ -104,14 +111,7 @@ public final class CacheAvoidingVirtualFileWrapper extends VirtualFile implement
@Override
public @NotNull VirtualFile findOrCreateChildData(Object requestor,
@NotNull String name) throws IOException {
VirtualFile child = findChild(name);
if (child != null) return child;
//MAYBE RC: below we create new _cached_ child, which violates this class general contract that it does NOT create new cache
// entries. From one side, it seems to be explicitly requested -- but maybe it is better to still adhere the
// contract? Maybe it is more consistent to create a non-cached child (=fileSystem.createChildFile(requestor, parent, name))
// -- i.e. create physical file, and TransientVirtualFileImpl around it?
child = createChildData(requestor, name);
return new CacheAvoidingVirtualFileWrapper((NewVirtualFile)child);
return findChild(name);
}
//<editor-fold desc="VirtualFile trivial delegates"> =====================================================================================
@@ -95,8 +95,26 @@ public abstract class NewVirtualFile extends VirtualFile implements VirtualFileW
});
}
/**
* @return true if VFS _thinks_ it already cached _in_memory_ all the children of this file, false otherwise.
* It doesn't mean there are no yet-uncached children in the actual underlying FS: VFS may catch up changes
* in the underlying FS with delay -- it just means VFS _thinks_ it caches all the children, i.e., it _was_
* all the children in the folder at some moment.
*/
@ApiStatus.Experimental
public boolean allChildrenLoaded() {
return false;//= safe, but not good for performance
}
/**
* @return children that VFS already loaded in memory. This may be not all the children in the actual underlying FS,
* since: (a) FS changes may be caught to VFS with delay (b) some children could be known to VFS, but not loaded
* in-memory (=stored in VFS persistent storage)
* @see #allChildrenLoaded()
*/
public abstract @NotNull @Unmodifiable Collection<VirtualFile> getCachedChildren();
/** @return all the children that are cached in VFS, including the ones that are not cached-in-memory now */
@SuppressWarnings("SpellCheckingInspection")
public abstract @NotNull @Unmodifiable Iterable<VirtualFile> iterInDbChildren();
@@ -978,6 +978,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
});
}
@Override
public boolean allChildrenLoaded() {
return directoryData.children.areAllChildrenLoaded();
}
@@ -48,6 +48,11 @@ public final class VirtualFileImpl extends VirtualFileSystemEntry {
return null;
}
@Override
public boolean allChildrenLoaded() {
return true;
}
@Override
public @NotNull Collection<VirtualFile> getCachedChildren() {
return Collections.emptyList();
@@ -872,6 +872,11 @@ public abstract class VirtualFileSystemEntry extends NewVirtualFile {
throw new UnsupportedOperationException();
}
@Override
public boolean allChildrenLoaded() {
throw new UnsupportedOperationException();
}
@Override
public @NotNull Collection<VirtualFile> getCachedChildren() {
throw new UnsupportedOperationException();