mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-16 22:51:17 +07:00
[vfs] more tests and comments
GitOrigin-RevId: bb8e979492b9b08a45fb98025c4aee04f6bdd574
This commit is contained in:
committed by
intellij-monorepo-bot
parent
2af6347624
commit
33c208bb90
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||||
package com.intellij.openapi.vfs.newvfs;
|
package com.intellij.openapi.vfs.newvfs;
|
||||||
|
|
||||||
import com.intellij.analysis.AnalysisBundle;
|
import com.intellij.analysis.AnalysisBundle;
|
||||||
@@ -8,7 +8,10 @@ import com.intellij.openapi.util.Key;
|
|||||||
import com.intellij.openapi.util.Pair;
|
import com.intellij.openapi.util.Pair;
|
||||||
import com.intellij.openapi.util.io.FileAttributes;
|
import com.intellij.openapi.util.io.FileAttributes;
|
||||||
import com.intellij.openapi.util.text.StringUtil;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.openapi.vfs.*;
|
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||||
|
import com.intellij.openapi.vfs.StandardFileSystems;
|
||||||
|
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.openapi.vfs.impl.ArchiveHandler;
|
import com.intellij.openapi.vfs.impl.ArchiveHandler;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -36,6 +39,10 @@ public abstract class ArchiveFileSystem extends NewVirtualFileSystem {
|
|||||||
return isCorrectFileType(file) ? findFileByPath(getRootPathByLocal(file)) : null;
|
return isCorrectFileType(file) ? findFileByPath(getRootPathByLocal(file)) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dresses a local file path to make it a suitable root path for this filesystem.
|
||||||
|
* E.g., VirtualFile("/x/y.jar") -> "/x/y.jar!/"
|
||||||
|
*/
|
||||||
public @NotNull String getRootPathByLocal(@NotNull VirtualFile file) {
|
public @NotNull String getRootPathByLocal(@NotNull VirtualFile file) {
|
||||||
return composeRootPath(file.getPath());
|
return composeRootPath(file.getPath());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1675,8 +1675,6 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (attributes == null || !attributes.isDirectory()) {
|
if (attributes == null || !attributes.isDirectory()) {
|
||||||
//FIXME RC: put special sentinel value into rootsByUrl & idToDirCache so next attempt to resolve the root
|
|
||||||
// doesn't need to repeat the whole lookup process (which is slow)
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// assume roots have the FS default case sensitivity
|
// assume roots have the FS default case sensitivity
|
||||||
@@ -1688,7 +1686,7 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable {
|
|||||||
FileAttributes parentAttributes = loadAttributes(fs, parentPath);
|
FileAttributes parentAttributes = loadAttributes(fs, parentPath);
|
||||||
if (parentAttributes != null) {
|
if (parentAttributes != null) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Must pass FS root path, but got: '" + path + "' (url: " + rootUrl + "), " +
|
"Must pass FS root path, but got: '" + path + "' (url: '" + rootUrl + "'), " +
|
||||||
"which has a parent '" + parentPath + "'. " +
|
"which has a parent '" + parentPath + "'. " +
|
||||||
"Use NewVirtualFileSystem.extractRootPath() for obtaining root path");
|
"Use NewVirtualFileSystem.extractRootPath() for obtaining root path");
|
||||||
}
|
}
|
||||||
@@ -1804,17 +1802,20 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String rootUrl = missedRootUrlRef.get();
|
//TODO RC: tuple (rootUrl, rootPath/name, rootFS) is better to be wrapped as 'record Root(url,path,fs)',
|
||||||
String rootName = vfsPeer.getName(rootId);
|
// with all the normalization methods encapsulated. It will be much better than all the components
|
||||||
String rootPath = getRootPath(rootUrl, rootName);
|
// dancing/messing around individually
|
||||||
NewVirtualFile root = ensureRootCached(rootPath, rootUrl);
|
String missedRootUrl = missedRootUrlRef.get();
|
||||||
|
String missedRootName = vfsPeer.getName(rootId);
|
||||||
|
String missedRootPath = getRootPath(missedRootUrl, missedRootName);
|
||||||
|
NewVirtualFile root = ensureRootCached(missedRootPath, missedRootUrl);
|
||||||
if (root != null) {
|
if (root != null) {
|
||||||
if (root.getId() != rootId) {
|
if (root.getId() != rootId) {
|
||||||
//Diogen reports like 49432216: rootId is _found_ among existing roots, but somehow ensureRootCached(rootPath, rootUrl)
|
//Diogen reports like 49432216: rootId is _found_ among existing roots, but somehow ensureRootCached(rootPath, rootUrl)
|
||||||
// leads to insertion of a _new_ root.
|
// leads to insertion of a _new_ root.
|
||||||
// I suspect this is a bug, and this check is to provide more diagnostics for it:
|
// I suspect this is a bug, and this check is to provide more diagnostics for it:
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"root[#" + rootId + "]{rootName:'" + rootName + "', rootPath:'" + rootPath + "'} cached to something else: " +
|
"root[#" + rootId + "]{rootName: '" + missedRootName + "', rootPath: '" + missedRootPath + "'} cached to something else: " +
|
||||||
"cached [#" + root.getId() + "]" +
|
"cached [#" + root.getId() + "]" +
|
||||||
"{rootName: '" + root.getName() + "', rootPath: '" + root.getPath() + "', rootUrl: '" + root.getUrl() + "'}"
|
"{rootName: '" + root.getName() + "', rootPath: '" + root.getPath() + "', rootUrl: '" + root.getUrl() + "'}"
|
||||||
);
|
);
|
||||||
@@ -1823,10 +1824,11 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rootName == rootPath in case of roots that are not archives
|
* rootPath == rootName in case of roots that are not archives
|
||||||
* but for archives e.g. jars rootName will be just name (see {@link PersistentFSImpl#findRoot})
|
* But for archives e.g. jars rootName will be just file name (see {@link PersistentFSImpl#findRoot(String, NewVirtualFileSystem)})
|
||||||
* so we need to extract path from url (IDEA-341011)
|
* so we need to extract a path from url (IDEA-341011)
|
||||||
* Path should not end with '!' because then '!' won't be stripped and file won't be found (see {@link ArchiveFileSystem#findLocalByRootPath})
|
* (Path should not end with '!' because then '!' won't be stripped and the apt file won't be found, see
|
||||||
|
* {@link ArchiveFileSystem#findLocalByRootPath})
|
||||||
*/
|
*/
|
||||||
private static @NotNull String getRootPath(@NotNull String rootUrl, @NotNull String rootName) {
|
private static @NotNull String getRootPath(@NotNull String rootUrl, @NotNull String rootName) {
|
||||||
NewVirtualFileSystem fs = detectFileSystem(rootUrl);
|
NewVirtualFileSystem fs = detectFileSystem(rootUrl);
|
||||||
@@ -1837,8 +1839,8 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable {
|
|||||||
return rootName;
|
return rootName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
private NewVirtualFile ensureRootCached(@NotNull String missedRootPath,
|
||||||
NewVirtualFile ensureRootCached(@NotNull String missedRootPath, @NotNull String missedRootUrl) {
|
@NotNull String missedRootUrl) {
|
||||||
NewVirtualFileSystem fs = detectFileSystem(missedRootUrl);
|
NewVirtualFileSystem fs = detectFileSystem(missedRootUrl);
|
||||||
if (fs == null) {
|
if (fs == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -1847,8 +1849,8 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable {
|
|||||||
try {
|
try {
|
||||||
NewVirtualFile cachedRoot = findRoot(missedRootPath, fs);
|
NewVirtualFile cachedRoot = findRoot(missedRootPath, fs);
|
||||||
if (LOG.isTraceEnabled()) {
|
if (LOG.isTraceEnabled()) {
|
||||||
LOG.trace("\tforce caching " + missedRootUrl +
|
LOG.trace("\tforce caching " + missedRootUrl + " (protocol: " + fs.getProtocol() + ", path: " + missedRootPath + ")" +
|
||||||
" (protocol: " + fs.getProtocol() + ", path: " + missedRootPath + ") -> " + cachedRoot);
|
" -> " + cachedRoot);
|
||||||
}
|
}
|
||||||
return cachedRoot;
|
return cachedRoot;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import org.junit.jupiter.api.io.TempDir;
|
|||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@@ -23,7 +24,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||||||
|
|
||||||
public class FSRecordsImplTest {
|
public class FSRecordsImplTest {
|
||||||
|
|
||||||
|
|
||||||
private FSRecordsImpl vfs;
|
private FSRecordsImpl vfs;
|
||||||
private Path vfsDir;
|
private Path vfsDir;
|
||||||
|
|
||||||
@@ -33,21 +33,18 @@ public class FSRecordsImplTest {
|
|||||||
int[] rootIds = new int[totalRoots];
|
int[] rootIds = new int[totalRoots];
|
||||||
|
|
||||||
//shuffle roots to make sure rootUrlIds are not sequential:
|
//shuffle roots to make sure rootUrlIds are not sequential:
|
||||||
for (int i = 0; i < totalRoots; i++) {
|
|
||||||
String rootUrl = "file:///root/" + i;
|
|
||||||
rootIds[i] = vfs.findOrCreateRootRecord(rootUrl);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < totalRoots; i++) {
|
for (int i = 0; i < totalRoots; i++) {
|
||||||
String rootUrl = "file:///root/" + (totalRoots - i - 1);
|
String rootUrl = "file:///root/" + (totalRoots - i - 1);
|
||||||
vfs.connection().names().enumerate(rootUrl);
|
vfs.connection().names().enumerate(rootUrl);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < totalRoots; i++) {
|
for (int i = 0; i < totalRoots; i++) {
|
||||||
String rootUrl = "file:///root/" + i;
|
String rootUrl = "file:///root/" + i;
|
||||||
vfs.connection().names().enumerate(rootUrl);
|
|
||||||
rootIds[i] = vfs.findOrCreateRootRecord(rootUrl);
|
rootIds[i] = vfs.findOrCreateRootRecord(rootUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
int[] rootIdsReadBack = vfs.listRoots();
|
int[] rootIdsReadBack = vfs.listRoots();
|
||||||
|
Arrays.sort(rootIds);
|
||||||
|
Arrays.sort(rootIdsReadBack);
|
||||||
assertArrayEquals(
|
assertArrayEquals(
|
||||||
rootIds,
|
rootIds,
|
||||||
rootIdsReadBack,
|
rootIdsReadBack,
|
||||||
@@ -56,22 +53,24 @@ public class FSRecordsImplTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void insertedRoots_CouldBeReadBack_AfterReinitialization() throws Exception {
|
public void insertedRoots_CouldBeReadBack_AfterVFSReinitialization() throws Exception {
|
||||||
int totalRoots = 100_000; //too many roots could exceed attribute storage max record size
|
int totalRoots = 100_000; //too many roots could exceed attribute storage max record size
|
||||||
int[] rootIds = new int[totalRoots];
|
int[] rootIds = new int[totalRoots];
|
||||||
//shuffle roots to make sure rootUrlIds are not sequential:
|
//shuffle roots to make sure rootUrlIds are not sequential:
|
||||||
for (int i = 0; i < totalRoots; i++) {
|
|
||||||
String rootUrl = "file:///root/" + i;
|
|
||||||
rootIds[i] = vfs.findOrCreateRootRecord(rootUrl);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < totalRoots; i++) {
|
for (int i = 0; i < totalRoots; i++) {
|
||||||
String rootUrl = "file:///root/" + (totalRoots - i - 1);
|
String rootUrl = "file:///root/" + (totalRoots - i - 1);
|
||||||
vfs.connection().names().enumerate(rootUrl);
|
vfs.connection().names().enumerate(rootUrl);
|
||||||
}
|
}
|
||||||
|
for (int i = 0; i < totalRoots; i++) {
|
||||||
|
String rootUrl = "file:///root/" + i;
|
||||||
|
rootIds[i] = vfs.findOrCreateRootRecord(rootUrl);
|
||||||
|
}
|
||||||
|
|
||||||
vfs = reloadVFS();
|
vfs = reloadVFS();
|
||||||
|
|
||||||
int[] rootIdsReadBack = vfs.listRoots();
|
int[] rootIdsReadBack = vfs.listRoots();
|
||||||
|
Arrays.sort(rootIds);
|
||||||
|
Arrays.sort(rootIdsReadBack);
|
||||||
assertArrayEquals(
|
assertArrayEquals(
|
||||||
rootIds,
|
rootIds,
|
||||||
rootIdsReadBack,
|
rootIdsReadBack,
|
||||||
@@ -79,6 +78,33 @@ public class FSRecordsImplTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void insertedRoots_CouldBeResolvedByUrl_AfterVFSReinitialization() throws Exception {
|
||||||
|
int totalRoots = 100_000; //too many roots could exceed attribute storage max record size
|
||||||
|
int[] rootIds = new int[totalRoots];
|
||||||
|
//shuffle roots to make sure rootUrlIds are not sequential:
|
||||||
|
for (int i = 0; i < totalRoots; i++) {
|
||||||
|
String rootUrl = "file:///root/" + (totalRoots - i - 1);
|
||||||
|
vfs.connection().names().enumerate(rootUrl);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < totalRoots; i++) {
|
||||||
|
String rootUrl = "file:///root/" + i;
|
||||||
|
rootIds[i] = vfs.findOrCreateRootRecord(rootUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs = reloadVFS();
|
||||||
|
|
||||||
|
for (int i = 0; i < totalRoots; i++) {
|
||||||
|
String rootUrl = "file:///root/" + i;
|
||||||
|
int rootId = vfs.findOrCreateRootRecord(rootUrl);
|
||||||
|
assertEquals(
|
||||||
|
rootIds[i],
|
||||||
|
rootId,
|
||||||
|
"root[" + i + "](url:"+rootUrl+") must be resolved to rootId: #" + rootIds[i] + ", but got #" + rootId + " instead"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void writtenFileContentIsDeduplicated_onlyUniqueContentsAreStored() throws IOException {
|
public void writtenFileContentIsDeduplicated_onlyUniqueContentsAreStored() throws IOException {
|
||||||
|
|||||||
Reference in New Issue
Block a user