CopyOnWriteFileSystem.java
net.minecraft.util.filefix.virtualfilesystem.CopyOnWriteFileSystem
信息
- 全限定名:net.minecraft.util.filefix.virtualfilesystem.CopyOnWriteFileSystem
- 类型:public class
- 包:net.minecraft.util.filefix.virtualfilesystem
- 源码路径:src/main/java/net/minecraft/util/filefix/virtualfilesystem/CopyOnWriteFileSystem.java
- 起始行号:L28
- 继承:FileSystem
- 职责:
TODO
字段/常量
-
FILE_ATTRIBUTE_VIEWS- 类型:
Set<String> - 修饰符:
private static final - 源码定位:
L29 - 说明:
TODO
- 类型:
-
LOGGER- 类型:
Logger - 修饰符:
private static final - 源码定位:
L30 - 说明:
TODO
- 类型:
-
store- 类型:
CopyOnWriteFileStore - 修饰符:
private final - 源码定位:
L31 - 说明:
TODO
- 类型:
-
provider- 类型:
CopyOnWriteFSProvider - 修饰符:
private final - 源码定位:
L32 - 说明:
TODO
- 类型:
-
baseDirectory- 类型:
Path - 修饰符:
private final - 源码定位:
L33 - 说明:
TODO
- 类型:
-
skippedPaths- 类型:
PathMatcher - 修饰符:
private final - 源码定位:
L34 - 说明:
TODO
- 类型:
-
tmpDirectory- 类型:
Path - 修饰符:
private final - 源码定位:
L35 - 说明:
TODO
- 类型:
-
rootPath- 类型:
CopyOnWriteFSPath - 修饰符:
private final - 源码定位:
L36 - 说明:
TODO
- 类型:
-
tmpFileIndex- 类型:
AtomicInteger - 修饰符:
private final - 源码定位:
L37 - 说明:
TODO
- 类型:
-
fileTree- 类型:
DirectoryNode - 修饰符:
private - 源码定位:
L38 - 说明:
TODO
- 类型:
内部类/嵌套类型
net.minecraft.util.filefix.virtualfilesystem.CopyOnWriteFileSystem.Moves- 类型:
record - 修饰符:
public - 源码定位:
L294 - 说明:
TODO
- 类型:
构造器
private CopyOnWriteFileSystem(String name, Path baseDirectory, Path tmpDirectory, PathMatcher skippedPaths) @ L40
- 构造器名:CopyOnWriteFileSystem
- 源码定位:L40
- 修饰符:private
参数:
- name: String
- baseDirectory: Path
- tmpDirectory: Path
- skippedPaths: PathMatcher
说明:
TODO
方法
下面的方法块按源码顺序生成。
public static CopyOnWriteFileSystem create(String name, Path baseDirectory, Path tmpDirectory, PathMatcher skippedPaths) @ L50
- 方法名:create
- 源码定位:L50
- 返回类型:CopyOnWriteFileSystem
- 修饰符:public static
参数:
- name: String
- baseDirectory: Path
- tmpDirectory: Path
- skippedPaths: PathMatcher
说明:
TODO
private DirectoryNode buildFileTreeFrom(Path baseDirectory) @ L60
- 方法名:buildFileTreeFrom
- 源码定位:L60
- 返回类型:DirectoryNode
- 修饰符:private
参数:
- baseDirectory: Path
说明:
TODO
protected void resetFileTreeToBaseFolderContent() @ L108
- 方法名:resetFileTreeToBaseFolderContent
- 源码定位:L108
- 返回类型:void
- 修饰符:protected
参数:
- 无
说明:
TODO
public CopyOnWriteFSProvider provider() @ L113
- 方法名:provider
- 源码定位:L113
- 返回类型:CopyOnWriteFSProvider
- 修饰符:public
参数:
- 无
说明:
TODO
public void close() @ L117
- 方法名:close
- 源码定位:L117
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public boolean isOpen() @ L124
- 方法名:isOpen
- 源码定位:L124
- 返回类型:boolean
- 修饰符:public
参数:
- 无
说明:
TODO
public boolean isReadOnly() @ L129
- 方法名:isReadOnly
- 源码定位:L129
- 返回类型:boolean
- 修饰符:public
参数:
- 无
说明:
TODO
public String getSeparator() @ L134
- 方法名:getSeparator
- 源码定位:L134
- 返回类型:String
- 修饰符:public
参数:
- 无
说明:
TODO
public Iterable<Path> getRootDirectories() @ L139
- 方法名:getRootDirectories
- 源码定位:L139
- 返回类型:Iterable
- 修饰符:public
参数:
- 无
说明:
TODO
public Iterable<FileStore> getFileStores() @ L144
- 方法名:getFileStores
- 源码定位:L144
- 返回类型:Iterable
- 修饰符:public
参数:
- 无
说明:
TODO
public Set<String> supportedFileAttributeViews() @ L149
- 方法名:supportedFileAttributeViews
- 源码定位:L149
- 返回类型:Set
- 修饰符:public
参数:
- 无
说明:
TODO
public CopyOnWriteFSPath getPath(String first, String... more) @ L154
- 方法名:getPath
- 源码定位:L154
- 返回类型:CopyOnWriteFSPath
- 修饰符:public
参数:
- first: String
- more: String…
说明:
TODO
public PathMatcher getPathMatcher(String syntaxAndPattern) @ L158
- 方法名:getPathMatcher
- 源码定位:L158
- 返回类型:PathMatcher
- 修饰符:public
参数:
- syntaxAndPattern: String
说明:
TODO
public UserPrincipalLookupService getUserPrincipalLookupService() @ L163
- 方法名:getUserPrincipalLookupService
- 源码定位:L163
- 返回类型:UserPrincipalLookupService
- 修饰符:public
参数:
- 无
说明:
TODO
public WatchService newWatchService() @ L168
- 方法名:newWatchService
- 源码定位:L168
- 返回类型:WatchService
- 修饰符:public
参数:
- 无
说明:
TODO
public CopyOnWriteFileStore store() @ L173
- 方法名:store
- 源码定位:L173
- 返回类型:CopyOnWriteFileStore
- 修饰符:public
参数:
- 无
说明:
TODO
public CopyOnWriteFSPath rootPath() @ L177
- 方法名:rootPath
- 源码定位:L177
- 返回类型:CopyOnWriteFSPath
- 修饰符:public
参数:
- 无
说明:
TODO
DirectoryNode fileTree() @ L181
- 方法名:fileTree
- 源码定位:L181
- 返回类型:DirectoryNode
- 修饰符:package-private
参数:
- 无
说明:
TODO
public Path baseDirectory() @ L185
- 方法名:baseDirectory
- 源码定位:L185
- 返回类型:Path
- 修饰符:public
参数:
- 无
说明:
TODO
public Path tmpDirectory() @ L189
- 方法名:tmpDirectory
- 源码定位:L189
- 返回类型:Path
- 修饰符:public
参数:
- 无
说明:
TODO
Path createTemporaryFilePath() @ L193
- 方法名:createTemporaryFilePath
- 源码定位:L193
- 返回类型:Path
- 修饰符:package-private
参数:
- 无
说明:
TODO
public FileSystem backingFileSystem() @ L197
- 方法名:backingFileSystem
- 源码定位:L197
- 返回类型:FileSystem
- 修饰符:public
参数:
- 无
说明:
TODO
public CopyOnWriteFileSystem.Moves collectMoveOperations(Path outPath) @ L201
- 方法名:collectMoveOperations
- 源码定位:L201
- 返回类型:CopyOnWriteFileSystem.Moves
- 修饰符:public
参数:
- outPath: Path
说明:
TODO
private void collectMoveOperations(Path outPath, DirectoryNode folder, CopyOnWriteFileSystem.Moves result) @ L207
- 方法名:collectMoveOperations
- 源码定位:L207
- 返回类型:void
- 修饰符:private
参数:
- outPath: Path
- folder: DirectoryNode
- result: CopyOnWriteFileSystem.Moves
说明:
TODO
public static void createDirectories(List<Path> directories) @ L229
- 方法名:createDirectories
- 源码定位:L229
- 返回类型:void
- 修饰符:public static
参数:
- directories: List
说明:
TODO
public static void hardLinkFiles(List<FileMove> moves) @ L235
- 方法名:hardLinkFiles
- 源码定位:L235
- 返回类型:void
- 修饰符:public static
参数:
- moves: List
说明:
TODO
public static void moveFiles(List<FileMove> moves) @ L247
- 方法名:moveFiles
- 源码定位:L247
- 返回类型:void
- 修饰符:public static
参数:
- moves: List
说明:
TODO
public static void moveFilesWithRetry(List<FileMove> moves, CopyOption... options) @ L253
- 方法名:moveFilesWithRetry
- 源码定位:L253
- 返回类型:void
- 修饰符:public static
参数:
- moves: List
- options: CopyOption…
说明:
TODO
public static List<FileMove> tryRevertMoves(List<FileMove> moves, CopyOption... options) @ L265
- 方法名:tryRevertMoves
- 源码定位:L265
- 返回类型:List
- 修饰符:public static
参数:
- moves: List
- options: CopyOption…
说明:
TODO
代码
public class CopyOnWriteFileSystem extends FileSystem {
private static final Set<String> FILE_ATTRIBUTE_VIEWS = Set.of("basic");
private static final Logger LOGGER = LogUtils.getLogger();
private final CopyOnWriteFileStore store;
private final CopyOnWriteFSProvider provider;
private final Path baseDirectory;
private final PathMatcher skippedPaths;
private final Path tmpDirectory;
private final CopyOnWriteFSPath rootPath;
private final AtomicInteger tmpFileIndex = new AtomicInteger();
private DirectoryNode fileTree;
private CopyOnWriteFileSystem(String name, Path baseDirectory, Path tmpDirectory, PathMatcher skippedPaths) throws IOException {
this.baseDirectory = baseDirectory;
this.tmpDirectory = tmpDirectory;
this.skippedPaths = skippedPaths;
this.provider = new CopyOnWriteFSProvider(this);
this.store = new CopyOnWriteFileStore(name, this);
this.rootPath = this.getPath("/");
this.fileTree = this.buildFileTreeFrom(baseDirectory);
}
public static CopyOnWriteFileSystem create(String name, Path baseDirectory, Path tmpDirectory, PathMatcher skippedPaths) throws IOException {
if (Files.exists(tmpDirectory)) {
throw new CowFSCreationException("Temporary directory already exists: " + tmpDirectory);
} else {
CopyOnWriteFileSystem fileSystem = new CopyOnWriteFileSystem(name, baseDirectory, tmpDirectory, skippedPaths);
Files.createDirectory(tmpDirectory);
return fileSystem;
}
}
private DirectoryNode buildFileTreeFrom(Path baseDirectory) throws IOException {
final DirectoryNode fileTree = new DirectoryNode(this.rootPath);
Files.walkFileTree(baseDirectory, new SimpleFileVisitor<Path>() {
{
Objects.requireNonNull(CopyOnWriteFileSystem.this);
}
public FileVisitResult visitFile(Path realPath, BasicFileAttributes attrs) throws IOException {
checkAttributes(realPath, attrs);
if (CopyOnWriteFileSystem.this.skippedPaths.matches(realPath)) {
return FileVisitResult.CONTINUE;
} else {
CopyOnWriteFSPath cowPath = this.toCowPath(realPath);
DirectoryNode parentNode = fileTree.directoryByPath(Objects.requireNonNull(cowPath.getParent()));
parentNode.addChild(new FileNode(cowPath, realPath, false));
return FileVisitResult.CONTINUE;
}
}
public FileVisitResult preVisitDirectory(Path realPath, BasicFileAttributes attrs) throws IOException {
checkAttributes(realPath, attrs);
if (CopyOnWriteFileSystem.this.skippedPaths.matches(realPath)) {
return FileVisitResult.SKIP_SUBTREE;
} else if (realPath.equals(baseDirectory)) {
return FileVisitResult.CONTINUE;
} else {
CopyOnWriteFSPath cowPath = this.toCowPath(realPath);
DirectoryNode parentNode = fileTree.directoryByPath(Objects.requireNonNull(cowPath.getParent()));
parentNode.addChild(new DirectoryNode(cowPath));
return FileVisitResult.CONTINUE;
}
}
private static void checkAttributes(Path realPath, BasicFileAttributes attrs) throws CowFSCreationException {
if (!attrs.isRegularFile() && !attrs.isDirectory()) {
throw new CowFSSymlinkException("Cannot build copy-on-write file system when symlink is present: " + realPath);
} else if (!Files.isWritable(realPath)) {
throw new CowFSCreationException("Cannot build copy-on-write file system, missing write access for file: " + realPath);
}
}
private CopyOnWriteFSPath toCowPath(Path realPath) {
return fileTree.path().resolve(baseDirectory.relativize(realPath).toString());
}
});
return fileTree;
}
@VisibleForTesting
protected void resetFileTreeToBaseFolderContent() throws IOException {
this.fileTree = this.buildFileTreeFrom(this.baseDirectory);
}
public CopyOnWriteFSProvider provider() {
return this.provider;
}
@Override
public void close() throws IOException {
if (Files.exists(this.tmpDirectory)) {
PathUtils.deleteDirectory(this.tmpDirectory);
}
}
@Override
public boolean isOpen() {
return true;
}
@Override
public boolean isReadOnly() {
return false;
}
@Override
public String getSeparator() {
return this.backingFileSystem().getSeparator();
}
@Override
public Iterable<Path> getRootDirectories() {
return List.of(this.rootPath());
}
@Override
public Iterable<FileStore> getFileStores() {
return List.of(this.store);
}
@Override
public Set<String> supportedFileAttributeViews() {
return FILE_ATTRIBUTE_VIEWS;
}
public CopyOnWriteFSPath getPath(String first, String... more) {
return CopyOnWriteFSPath.of(this, first, more);
}
@Override
public PathMatcher getPathMatcher(String syntaxAndPattern) {
throw new UnsupportedOperationException();
}
@Override
public UserPrincipalLookupService getUserPrincipalLookupService() {
throw new UnsupportedOperationException();
}
@Override
public WatchService newWatchService() {
throw new UnsupportedOperationException();
}
public CopyOnWriteFileStore store() {
return this.store;
}
public CopyOnWriteFSPath rootPath() {
return this.rootPath;
}
DirectoryNode fileTree() {
return this.fileTree;
}
public Path baseDirectory() {
return this.baseDirectory;
}
public Path tmpDirectory() {
return this.tmpDirectory;
}
Path createTemporaryFilePath() {
return this.tmpDirectory.resolve("tmp_" + this.tmpFileIndex.incrementAndGet());
}
public FileSystem backingFileSystem() {
return this.tmpDirectory.getFileSystem();
}
public CopyOnWriteFileSystem.Moves collectMoveOperations(Path outPath) {
CopyOnWriteFileSystem.Moves result = new CopyOnWriteFileSystem.Moves(new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
this.collectMoveOperations(outPath, this.fileTree, result);
return result;
}
private void collectMoveOperations(Path outPath, DirectoryNode folder, CopyOnWriteFileSystem.Moves result) {
for (Node childNode : folder.children()) {
Path target = outPath.resolve(Objects.requireNonNull(childNode.name()));
switch (childNode) {
case FileNode fileNode:
FileMove move = new FileMove(fileNode.storagePath(), target);
if (fileNode.isCopy) {
result.copiedFiles.add(move);
} else {
result.preexistingFiles.add(move);
}
break;
case DirectoryNode directoryNode:
result.directories.add(target);
this.collectMoveOperations(target, directoryNode, result);
break;
default:
throw new MatchException(null, null);
}
}
}
public static void createDirectories(List<Path> directories) throws IOException {
for (Path directory : directories) {
Files.createDirectory(directory);
}
}
public static void hardLinkFiles(List<FileMove> moves) throws IOException {
for (FileMove move : moves) {
if (!Files.exists(move.to())) {
if (!Files.isRegularFile(move.from())) {
throw new IllegalStateException("Not a regular file: " + move.from());
}
Files.createLink(move.to(), move.from());
}
}
}
public static void moveFiles(List<FileMove> moves) throws IOException {
for (FileMove move : moves) {
Files.move(move.from(), move.to());
}
}
public static void moveFilesWithRetry(List<FileMove> moves, CopyOption... options) throws IOException {
for (FileMove move : moves) {
if (Files.exists(move.from()) || !Files.exists(move.to())) {
if (!Files.isRegularFile(move.from())) {
throw new IOException("Not a regular file: " + move.from());
}
Files.move(move.from(), move.to(), options);
}
}
}
public static List<FileMove> tryRevertMoves(List<FileMove> moves, CopyOption... options) {
List<FileMove> failedMoves = new ArrayList<>();
for (FileMove move : moves) {
if (Files.exists(move.to()) || !Files.exists(move.from())) {
if (Files.isRegularFile(move.to())) {
boolean success = Util.safeMoveFile(move.to(), move.from(), options);
if (success) {
LOGGER.info("Reverted move from {} to {}", move.from(), move.to());
} else {
LOGGER.error("Failed to revert move from {} to {}", move.from(), move.to());
failedMoves.add(move);
}
} else {
LOGGER.error("Skipping reverting move from {} to {} as it's not a file", move.from(), move.to());
failedMoves.add(move);
}
}
}
if (failedMoves.isEmpty()) {
LOGGER.info("Successfully reverted back to previous world state");
} else {
LOGGER.error("Completed reverting with errors");
}
return failedMoves;
}
public record Moves(List<Path> directories, List<FileMove> copiedFiles, List<FileMove> preexistingFiles) {
}
}引用的其他类
-
- 引用位置:
方法调用 - 关联成员:
Util.safeMoveFile()
- 引用位置:
-
- 引用位置:
字段/方法调用/返回值 - 关联成员:
CopyOnWriteFSPath.of()
- 引用位置:
-
- 引用位置:
字段/构造调用/返回值 - 关联成员:
CopyOnWriteFSProvider()
- 引用位置:
-
- 引用位置:
字段/构造调用/返回值 - 关联成员:
CopyOnWriteFileStore()
- 引用位置:
-
- 引用位置:
参数/字段/构造调用/返回值 - 关联成员:
DirectoryNode()
- 引用位置:
-
- 引用位置:
参数/构造调用/返回值 - 关联成员:
FileMove()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
FileNode()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
CowFSCreationException()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
CowFSSymlinkException()
- 引用位置: