IJPL-161551 IjentNioFsPath + BasicFileAttributesHolder: fetch file attributes only when it is explicitly requested

GitOrigin-RevId: 5209a3af25fe96b6c694fcb651ff5789913be9a8
This commit is contained in:
Vladimir Lagunov
2024-09-10 10:11:29 +00:00
committed by intellij-monorepo-bot
parent d0f7bfcd07
commit e52c7130f3
4 changed files with 65 additions and 22 deletions
@@ -6,10 +6,14 @@ import org.jetbrains.annotations.Nullable;
import sun.nio.fs.BasicFileAttributesHolder;
import java.lang.ref.WeakReference;
import java.nio.file.DirectoryStream;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
/**
* This interface allows not adding `--add-exports` to modules where some class implements {@link BasicFileAttributesHolder}.
*
* Also, this interface defines some hacks and helper methods related to {@link BasicFileAttributesHolder}.
*/
public interface BasicFileAttributesHolder2 extends BasicFileAttributesHolder {
/**
@@ -47,4 +51,30 @@ public interface BasicFileAttributesHolder2 extends BasicFileAttributesHolder {
myCachedAttributes.clear();
}
}
static @Nullable BasicFileAttributes getAttributesFromHolder(@NotNull Path path) {
if (path instanceof BasicFileAttributesHolder bafh) {
return bafh.get();
}
return null;
}
/**
* A marker interface for {@link java.nio.file.spi.FileSystemProvider#newDirectoryStream}
* that advises the file system to fetch file attributes and fill {@link BasicFileAttributesHolder}, if it's supported.
* <p>
* Unlike many other methods in {@code FileSystemProvider}, {@code newDirectoryStream} doesn't accept a set of options.
* The easiest way to provide additional information to the method is through the filter argument.
* </p>
* A file system provider should support this feature explicitly.
* This interface has no effect on default filesystems from JDK:
* <ul>
* <li>In the default file system on Windows, file attributes are always fetched, regardless of the filter argument.</li>
* <li>In the default file system on Posix, file attributes are never fetched.</li>
* </ul>
*/
@FunctionalInterface
interface FetchAttributesFilter extends DirectoryStream.Filter<Path> {
FetchAttributesFilter ACCEPT_ALL = path -> true;
}
}
@@ -2,6 +2,7 @@
package com.intellij.platform.ijent.community.impl.nio
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.platform.core.nio.fs.BasicFileAttributesHolder2.FetchAttributesFilter
import com.intellij.platform.ijent.community.impl.IjentFsResultImpl
import com.intellij.platform.ijent.community.impl.nio.IjentNioFileSystemProvider.Companion.newFileSystemMap
import com.intellij.platform.ijent.community.impl.nio.IjentNioFileSystemProvider.UnixFilePermissionBranch.*
@@ -180,23 +181,34 @@ class IjentNioFileSystemProvider : FileSystemProvider() {
val nioFs = dir.nioFs
return fsBlocking {
val children = nioFs.ijentFs
.listDirectoryWithAttrs(ensurePathIsAbsolute(dir.ijentPath), IjentFileSystemApi.SymlinkPolicy.DO_NOT_RESOLVE)
.getOrThrowFileSystemException()
val nioPathList = children.asSequence()
.map { (childName, childStat) ->
val childIjentPath = dir.ijentPath.getChild(childName).getOrThrow()
val childAttrs = when (childStat) {
is IjentPosixFileInfo -> IjentNioPosixFileAttributes(childStat)
is IjentWindowsFileInfo -> TODO()
}
IjentNioPath(childIjentPath, nioFs, childAttrs)
val notFilteredPaths =
if (pathFilter is FetchAttributesFilter) {
nioFs.ijentFs
.listDirectoryWithAttrs(ensurePathIsAbsolute(dir.ijentPath), IjentFileSystemApi.SymlinkPolicy.DO_NOT_RESOLVE)
.getOrThrowFileSystemException()
.asSequence()
.map { (childName, childStat) ->
val childIjentPath = dir.ijentPath.getChild(childName).getOrThrow()
val childAttrs = when (childStat) {
is IjentPosixFileInfo -> IjentNioPosixFileAttributes(childStat)
is IjentWindowsFileInfo -> TODO()
}
IjentNioPath(childIjentPath, nioFs, childAttrs)
}
}
.filter { nioPath ->
pathFilter?.accept(nioPath) != false
else {
nioFs.ijentFs
.listDirectory(ensurePathIsAbsolute(dir.ijentPath))
.getOrThrowFileSystemException()
.asSequence()
.map { childName ->
val childIjentPath = dir.ijentPath.getChild(childName).getOrThrow()
IjentNioPath(childIjentPath, nioFs, null)
}
}
.toMutableList()
val nioPathList = notFilteredPaths.filterTo(mutableListOf()) { nioPath ->
pathFilter?.accept(nioPath) != false
}
object : DirectoryStream<Path> {
// The compiler doesn't (didn't?) allow to relax types here.
@@ -6,6 +6,8 @@ import com.intellij.execution.wsl.WslPath
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.util.io.CaseSensitivityAttribute
import com.intellij.openapi.util.io.FileAttributes
import com.intellij.platform.core.nio.fs.BasicFileAttributesHolder2
import com.intellij.platform.core.nio.fs.BasicFileAttributesHolder2.FetchAttributesFilter
import com.intellij.platform.core.nio.fs.RoutingAwareFileSystemProvider
import com.intellij.platform.ijent.IjentPosixInfo
import com.intellij.platform.ijent.community.impl.nio.IjentNioPath
@@ -315,11 +317,9 @@ class IjentWslNioFileSystemProvider(
lastDirectory = lastDirectory.parent
}
// TODO Add BasicFileAttributesHolder, it gives a huge speed up.
//val stat =
// source.asSafely<BasicFileAttributesHolder>()?.get()
// ?: source.readAttributes(LinkOption.NOFOLLOW_LINKS)
val stat = source.readAttributes<BasicFileAttributes>(LinkOption.NOFOLLOW_LINKS)
val stat =
BasicFileAttributesHolder2.getAttributesFromHolder(source)
?: source.readAttributes(LinkOption.NOFOLLOW_LINKS)
// WindowsPath doesn't support resolve() from paths of different class.
val target = source.relativeTo(sourceRoot).fold(targetRoot) { parent, file ->
@@ -337,7 +337,7 @@ class IjentWslNioFileSystemProvider(
throw err
}
}
Files.newDirectoryStream(source).use { children ->
source.fileSystem.provider().newDirectoryStream(source, FetchAttributesFilter.ACCEPT_ALL).use { children ->
sourceStack.addAll(children.toList().asReversed())
}
}
@@ -2,6 +2,7 @@
package com.intellij.util.io;
import com.intellij.openapi.util.io.NioFiles;
import com.intellij.platform.core.nio.fs.BasicFileAttributesHolder2.FetchAttributesFilter;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -40,7 +41,7 @@ public final class PlatformNioHelper {
@SuppressWarnings({"UnnecessaryFullyQualifiedName", "InstanceofIncompatibleInterface"})
public static void visitDirectory(@NotNull Path directory, @Nullable Set<String> filter, @NotNull BiPredicate<Path, Result<BasicFileAttributes>> consumer)
throws IOException, SecurityException {
try (var dirStream = Files.newDirectoryStream(directory)) {
try (var dirStream = directory.getFileSystem().provider().newDirectoryStream(directory, FetchAttributesFilter.ACCEPT_ALL)) {
for (var path : dirStream) {
if (filter != null && !filter.contains(path.getFileName().toString())) {
continue;