From f99a286b5eb74c5b02b5b10068069cea885d295a Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Fri, 18 Dec 2020 12:37:28 +0300 Subject: [PATCH] refactor FSRecords storage (next attempt) GitOrigin-RevId: edde88ae63ec3fd76ba185cf344736a4150928b6 --- .../vfs/newvfs/persistent/FSRecords.java | 80 +++++++++---------- .../PersistentFSAttributeAccessor.java | 4 + .../persistent/PersistentFSConnection.java | 15 +++- .../PersistentFSContentAccessor.java | 4 + .../newvfs/persistent/PersistentFSImpl.java | 2 +- .../PersistentFSRecordsStorage.java | 1 + .../persistent/PersistentFSTreeAccessor.java | 2 + 7 files changed, 61 insertions(+), 47 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java index fc1f81e6cea3..ce3ef8fa688d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java @@ -85,16 +85,18 @@ public final class FSRecords { w = lock.writeLock(); } - // return nameId>0 - static int writeAttributesToRecord(int id, int parentId, @NotNull FileAttributes attributes, @NotNull String name) { + /** + * @return nameId > 0 + */ + static int writeAttributesToRecord(int fileId, int parentId, @NotNull FileAttributes attributes, @NotNull String name) { return writeAndHandleErrors(() -> { - int nameId = setName(id, name); + int nameId = setName(fileId, name); - setTimestamp(id, attributes.lastModified); - setLength(id, attributes.isDirectory() ? -1L : attributes.length); + setTimestamp(fileId, attributes.lastModified); + setLength(fileId, attributes.isDirectory() ? -1L : attributes.length); + setFlags(fileId, PersistentFSImpl.fileAttributesToFlags(attributes)); + setParent(fileId, parentId); - setFlags(id, PersistentFSImpl.fileAttributesToFlags(attributes)); - setParent(id, parentId); return nameId; }); } @@ -105,10 +107,13 @@ public final class FSRecords { } @NotNull - public static String diagnosticsForAlreadyCreatedFile(int id, int nameId, @NotNull Object existingData) { + public static String diagnosticsForAlreadyCreatedFile(int fileId, int nameId, @NotNull Object existingData) { invalidateCaches(); - int parentId = getParent(id); - String msg = "File already created: id="+id + "; nameId="+nameId + "("+getNameByNameId(nameId)+"); parentId=" + parentId+ "; existingData=" + existingData; + int parentId = getParent(fileId); + String msg = "File already created: fileId=" + fileId + + "; nameId=" + nameId + "(" + getNameByNameId(nameId) + ")" + + "; parentId=" + parentId + + "; existingData=" + existingData; if (parentId > 0) { msg += "; parent.name=" + getName(parentId); msg += "; parent.children=" + list(parentId); @@ -163,7 +168,7 @@ public final class FSRecords { markAsDeletedRecursively(subRecord); } - writeAndHandleErrors(() -> ourRecordAccessor.addToFreeRecordsList(id, ourConnection)); + ourRecordAccessor.addToFreeRecordsList(id, ourConnection); } @TestOnly @@ -190,22 +195,22 @@ public final class FSRecords { return writeAndHandleErrors(() -> ourTreeAccessor.findOrCreateRootRecord(rootUrl, ourConnection, () -> createRecord())); } - static void deleteRootRecord(int id) { - writeAndHandleErrors(() -> ourTreeAccessor.deleteRootRecord(id, ourConnection)); + static void deleteRootRecord(int fileId) { + writeAndHandleErrors(() -> ourTreeAccessor.deleteRootRecord(fileId, ourConnection)); } - static int @NotNull [] listIds(int id) { - return readAndHandleErrors(() -> ourTreeAccessor.listIds(id, ourConnection)); + static int @NotNull [] listIds(int fileId) { + return readAndHandleErrors(() -> ourTreeAccessor.listIds(fileId, ourConnection)); } - static boolean mayHaveChildren(int id) { - return readAndHandleErrors(() -> ourTreeAccessor.mayHaveChildren(id, ourConnection)); + static boolean mayHaveChildren(int fileId) { + return readAndHandleErrors(() -> ourTreeAccessor.mayHaveChildren(fileId, ourConnection)); } // returns child infos (sorted by id) without (potentially expensive) name (or without even nameId if `loadNameId` is false) @NotNull static ListResult list(int parentId) { - return readAndHandleErrors(() -> doLoadChildren(parentId)); + return readAndHandleErrors(() -> ourTreeAccessor.doLoadChildren(parentId, ourConnection)); } @NotNull @@ -213,14 +218,7 @@ public final class FSRecords { return ContainerUtil.map(list(parentId).children, c -> c.getName()); } - @NotNull - private static ListResult doLoadChildren(int parentId) throws IOException { - checkFileIsValid(parentId); - return ourTreeAccessor.doLoadChildren(parentId, ourConnection); - } - static boolean wereChildrenAccessed(int id) { - checkFileIsValid(id); return readAndHandleErrors(() -> ourTreeAccessor.wereChildrenAccessed(id, ourConnection)); } @@ -289,12 +287,12 @@ public final class FSRecords { ListResult children = list(parentId); ListResult result = childrenConvertor.apply(children); + w.lock(); try { - w.lock(); ListResult toSave; // optimization: if the children were never changed after list(), do not check for duplicates again if (result.childrenWereChangedSinceLastList()) { - children = doLoadChildren(parentId); + children = list(parentId); toSave = childrenConvertor.apply(children); } else { @@ -373,13 +371,12 @@ public final class FSRecords { return ourConnection.getLocalModificationCount(); // This is volatile, only modified under Application.runWriteAction() lock. } - static int getModCount() { - return readAndHandleErrors(ourConnection::getGlobalModCount); + static int getPersistentModCount() { + return readAndHandleErrors(ourConnection::getPersistentModCount); } private static void incModCount(int id) { - int count = ourConnection.incGlobalModCount(); - ourConnection.getRecords().setModCount(id, count); + ourConnection.incModCount(id); } public static int getParent(int id) { @@ -426,6 +423,7 @@ public final class FSRecords { return null; } + @Nullable private VirtualFileSystemEntry findDescendantByIdPath() { VirtualFileSystemEntry parent = foundParent; if (path != null) { @@ -437,6 +435,7 @@ public final class FSRecords { return findChild(parent, id); } + @Nullable private VirtualFileSystemEntry findChild(VirtualFileSystemEntry parent, int childId) { if (!(parent instanceof VirtualDirectoryImpl)) { return null; @@ -507,13 +506,14 @@ public final class FSRecords { return nameId == 0 ? "" : ourConnection.getNames().valueOf(nameId); } - // return nameId>0 - static int setName(int id, @NotNull String name) { + /** + * @return nameId + */ + static int setName(int fileId, @NotNull String name) { return writeAndHandleErrors(() -> { - incModCount(id); + incModCount(fileId); int nameId = ourConnection.getNames().enumerate(name); - assert nameId > 0 : nameId; - ourConnection.getRecords().setNameId(id, nameId); + ourConnection.getRecords().setNameId(fileId, nameId); return nameId; }); } @@ -558,7 +558,6 @@ public final class FSRecords { @Nullable static DataInputStream readContent(int fileId) { ThrowableComputable computable = readAndHandleErrors(() -> { - checkFileIsValid(fileId); return ourContentAccessor.readContent(fileId, ourConnection); }); if (computable == null) return null; @@ -608,15 +607,10 @@ public final class FSRecords { // must be called under r or w lock @Nullable private static DataInputStream readAttribute(int fileId, @NotNull FileAttribute attribute) throws IOException { - checkFileIsValid(fileId); return ourAttributeAccessor.readAttribute(fileId, attribute, ourConnection); } - private static void checkFileIsValid(int fileId) { - assert fileId > 0 : fileId; - } - static int acquireFileContent(int fileId) { return writeAndHandleErrors(() -> ourContentAccessor.acquireContentRecord(fileId, ourConnection)); } @@ -636,7 +630,6 @@ public final class FSRecords { @NotNull static DataOutputStream writeContent(int fileId, boolean readOnly) { - checkFileIsValid(fileId); return new DataOutputStream(ourContentAccessor.new ContentOutputStream(fileId, readOnly, ourConnection)) { @Override public void close() { @@ -651,7 +644,6 @@ public final class FSRecords { } static void writeContent(int fileId, @NotNull ByteArraySequence bytes, boolean readOnly) { - checkFileIsValid(fileId); writeAndHandleErrors(() -> { if (ourContentAccessor.writeContent(fileId, bytes, readOnly, ourConnection)) { incModCount(fileId); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSAttributeAccessor.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSAttributeAccessor.java index 130b4ca606d9..ccd75625e6f4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSAttributeAccessor.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSAttributeAccessor.java @@ -33,6 +33,8 @@ class PersistentFSAttributeAccessor { DataInputStream readAttribute(int fileId, @NotNull FileAttribute attribute, @NotNull PersistentFSConnection connection) throws IOException { + PersistentFSConnection.ensureIdIsValid(fileId); + int recordId = connection.getRecords().getAttributeRecordId(fileId); if (recordId == 0) return null; int encodedAttrId = connection.getAttributeId(attribute.getId()); @@ -83,6 +85,8 @@ class PersistentFSAttributeAccessor { @NotNull FileAttribute attr, boolean toWrite, @NotNull PersistentFSConnection connection) throws IOException { + PersistentFSConnection.ensureIdIsValid(fileId); + int recordId = connection.getRecords().getAttributeRecordId(fileId); int encodedAttrId = connection.getAttributeId(attr.getId()); boolean directoryRecord = false; diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConnection.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConnection.java index 433b94730e16..93511ef9235d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConnection.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSConnection.java @@ -146,13 +146,12 @@ final class PersistentFSConnection { } // No luck. } - int getGlobalModCount() { + int getPersistentModCount() { return myRecords.getGlobalModCount(); } int incGlobalModCount() { incLocalModCount(); - return myRecords.incGlobalModCount(); } @@ -219,6 +218,11 @@ final class PersistentFSConnection { return myPersistentFSPaths; } + public void incModCount(int fileId) { + int count = incGlobalModCount(); + getRecords().setModCount(fileId, count); + } + static void closeStorages(@Nullable PersistentFSRecordsStorage records, @Nullable PersistentStringEnumerator names, @Nullable Storage attributes, @@ -286,4 +290,11 @@ final class PersistentFSConnection { return Math.max(myAttrPageRequested ? 8 : 32, Math.min((int)(requiredLength * 1.2), (requiredLength / 1024 + 1) * 1024)); } } + + /** + * @param id - file id, name id, any other positive id + */ + static void ensureIdIsValid(int id) { + assert id > 0 : id; + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSContentAccessor.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSContentAccessor.java index ff8f0c4d9b50..1c48091166f4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSContentAccessor.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSContentAccessor.java @@ -31,6 +31,7 @@ public class PersistentFSContentAccessor { @Nullable ThrowableComputable readContent(int fileId, @NotNull PersistentFSConnection connection) { + PersistentFSConnection.ensureIdIsValid(fileId); int page = connection.getRecords().getContentRecordId(fileId); if (page == 0) return null; return () -> { @@ -60,6 +61,8 @@ public class PersistentFSContentAccessor { } boolean writeContent(int fileId, @NotNull ByteArraySequence bytes, boolean fixedSize, @NotNull PersistentFSConnection connection) throws IOException { + PersistentFSConnection.ensureIdIsValid(fileId); + boolean modified = false; RefCountingStorage contentStorage = connection.getContents(); @@ -206,6 +209,7 @@ public class PersistentFSContentAccessor { ContentOutputStream(int fileId, boolean readOnly, @NotNull PersistentFSConnection connection) { super(new BufferExposingByteArrayOutputStream()); + PersistentFSConnection.ensureIdIsValid(fileId); myFileId = fileId; myFixedSize = readOnly; myConnection = connection; 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 786b90173c56..15c42faa8841 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 @@ -290,7 +290,7 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable { @Override public int getFilesystemModificationCount() { - return FSRecords.getModCount(); + return FSRecords.getPersistentModCount(); } // return nameId>0 if write successful, -1 if not diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSRecordsStorage.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSRecordsStorage.java index 5d4eb7a3b7db..131a2c29afd7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSRecordsStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSRecordsStorage.java @@ -70,6 +70,7 @@ public class PersistentFSRecordsStorage { } void setNameId(int id, int nameId) { + PersistentFSConnection.ensureIdIsValid(nameId); putRecordInt(id, NAME_OFFSET, nameId); } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSTreeAccessor.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSTreeAccessor.java index b284d0231a2f..367a60cded6b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSTreeAccessor.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSTreeAccessor.java @@ -65,6 +65,8 @@ class PersistentFSTreeAccessor { @NotNull ListResult doLoadChildren(int parentId, @NotNull PersistentFSConnection connection) throws IOException { + PersistentFSConnection.ensureIdIsValid(parentId); + try (DataInputStream input = myAttributeAccessor.readAttribute(parentId, ourChildrenAttr, connection)) { int count = input == null ? 0 : DataInputOutputUtil.readINT(input); List result = count == 0 ? Collections.emptyList() : new ArrayList<>(count);