From 6b9ef95f6cddbdc60436bcd8e2047f7f1d13010b Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Fri, 3 Jul 2015 12:50:56 +0300 Subject: [PATCH] optimisation: obtain all parents within one lock --- .../vfs/newvfs/persistent/FSRecords.java | 26 ++++++++ .../newvfs/persistent/PersistentFSImpl.java | 62 +++++-------------- 2 files changed, 40 insertions(+), 48 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 363a3180b02a..b7cd888afbc5 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 @@ -1053,6 +1053,32 @@ public class FSRecords implements Forceable { } } + // returns id, parent(id), parent(parent(id)), ... rootId + @NotNull + public static TIntArrayList getParents(int id) { + TIntArrayList result = new TIntArrayList(10); + r.lock(); + try { + int parentId; + do { + result.add(id); + parentId = getRecordInt(id, PARENT_OFFSET); + if (parentId == id || result.size() % 128 == 0 && result.contains(parentId)) { + LOG.error("Cyclic parent child relations in the database. id = " + parentId); + return result; + } + id = parentId; + } while (parentId != 0); + } + catch (Throwable e) { + throw DbConnection.handleError(e); + } + finally { + r.unlock(); + } + return result; + } + public static void setParent(int id, int parent) { if (id == parent) { LOG.error("Cyclic parent/child relations"); 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 f79f148eff55..a67ed2e8290d 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 @@ -61,7 +61,7 @@ public class PersistentFSImpl extends PersistentFS implements ApplicationCompone private final ReadWriteLock myRootsLock = new ReentrantReadWriteLock(); private final Map myRoots = ContainerUtil.newTroveMap(FileUtil.PATH_HASHING_STRATEGY); - private final TIntObjectHashMap myRootsById = new TIntObjectHashMap(); + private final ConcurrentIntObjectMap myRootsById = ContainerUtil.createConcurrentIntObjectMap(); private final ConcurrentIntObjectMap myIdToDirCache = ContainerUtil.createConcurrentIntObjectMap(); private final Object myInputLock = new Object(); @@ -199,7 +199,7 @@ public class PersistentFSImpl extends PersistentFS implements ApplicationCompone return nameIds.toArray(new FSRecords.NameId[nameIds.size()]); } - public static void setChildrenCached(int id) { + private static void setChildrenCached(int id) { int flags = FSRecords.getFlags(id); FSRecords.setFlags(id, flags | CHILDREN_CACHED_FLAG, true); } @@ -311,11 +311,6 @@ public class PersistentFSImpl extends PersistentFS implements ApplicationCompone return isDirectory(getFileAttributes(getFileId(file))); } - private static int getParent(final int id) { - assert id > 0; - return FSRecords.getParent(id); - } - private static boolean namesEqual(@NotNull VirtualFileSystem fs, @NotNull CharSequence n1, CharSequence n2) { return Comparing.equal(n1, n2, fs.isCaseSensitive()); } @@ -912,9 +907,8 @@ public class PersistentFSImpl extends PersistentFS implements ApplicationCompone return null; } - boolean mark = false; - myRootsLock.writeLock().lock(); + boolean mark = false; try { VirtualFileSystemEntry root = myRoots.get(rootUrl); if (root != null) return root; @@ -962,59 +956,31 @@ public class PersistentFSImpl extends PersistentFS implements ApplicationCompone myIdToDirCache.clear(); } - private static final int DEPTH_LIMIT = 75; - @Override @Nullable public NewVirtualFile findFileById(final int id) { - return findFileById(id, false, null, 0); + return findFileById(id, false); } @Override public NewVirtualFile findFileByIdIfCached(final int id) { - return findFileById(id, true, null, 0); + return findFileById(id, true); } @Nullable - private VirtualFileSystemEntry findFileById(int id, boolean cachedOnly, TIntArrayList visited, int mask) { + private VirtualFileSystemEntry findFileById(int id, boolean cachedOnly) { VirtualFileSystemEntry cached = myIdToDirCache.get(id); if (cached != null) return cached; - if (visited != null && (visited.size() >= DEPTH_LIMIT || (mask & id) == id && visited.contains(id))) { - @NonNls String sb = "Dead loop detected in persistent FS (id=" + id + " cached-only=" + cachedOnly + "):"; - for (int i = 0; i < visited.size(); i++) { - int _id = visited.get(i); - sb += "\n " + _id + " '" + getName(_id) + "' " + - String.format("%02x", getFileAttributes(_id)) + ' ' + myIdToDirCache.containsKey(_id); - } - LOG.error(sb); - return null; - } - - int parentId = getParent(id); - if (parentId >= id) { - if (visited == null) visited = new TIntArrayList(DEPTH_LIMIT); - } - if (visited != null) visited.add(id); - - VirtualFileSystemEntry result; - if (parentId == 0) { - myRootsLock.readLock().lock(); - try { - result = myRootsById.get(id); - } - finally { - myRootsLock.readLock().unlock(); - } - } - else { - VirtualFileSystemEntry parentFile = findFileById(parentId, cachedOnly, visited, mask | id); - if (parentFile instanceof VirtualDirectoryImpl) { - result = ((VirtualDirectoryImpl)parentFile).findChildById(id, cachedOnly); - } - else { - result = null; + TIntArrayList parents = FSRecords.getParents(id); + int rootId = parents.get(parents.size() - 1); + VirtualFileSystemEntry result = myRootsById.get(rootId); + for (int i=parents.size() - 2; i>=0; i--) { + if (result == null) { + break; } + int parentId = parents.get(i); + result = ((VirtualDirectoryImpl)result).findChildById(parentId, cachedOnly); } if (result != null && result.isDirectory()) {