From 3e1789b40378ecafc2698b729300cb1f86c8a32f Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Wed, 19 Jun 2013 20:11:42 +0400 Subject: [PATCH] more compact storage of changed/deleted paths --- .../compiler/server/BuildManager.java | 125 ++++++++++++++++-- 1 file changed, 114 insertions(+), 11 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index a9ad726ab623..91697e246338 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -69,11 +69,13 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.newvfs.BulkFileListener; import com.intellij.openapi.vfs.newvfs.events.VFileEvent; +import com.intellij.openapi.vfs.newvfs.impl.FileNameCache; import com.intellij.util.Alarm; import com.intellij.util.Function; import com.intellij.util.SmartList; import com.intellij.util.concurrency.Semaphore; import com.intellij.util.concurrency.SequentialTaskExecutor; +import com.intellij.util.containers.IntArrayList; import com.intellij.util.io.storage.HeavyProcessLatch; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.net.NetUtils; @@ -391,12 +393,20 @@ public class BuildManager implements ApplicationComponent{ synchronized (myProjectDataMap) { ProjectData data = myProjectDataMap.get(projectPath); if (data != null && !data.myNeedRescan) { - return new ArrayList(data.myChanged); + return convertToStringPaths(data.myChanged); } return null; } } + private static List convertToStringPaths(final Collection interned) { + final ArrayList list = new ArrayList(interned.size()); + for (InternedPath path : interned) { + list.add(path.getValue()); + } + return list; + } + @Nullable private static String getProjectPath(final Project project) { final String url = project.getPresentableUrl(); @@ -548,9 +558,9 @@ public class BuildManager implements ApplicationComponent{ LOG.info("Scheduling build for " + projectPath + "; CHANGED: " + - new HashSet(data.myChanged) + + new HashSet(convertToStringPaths(data.myChanged)) + "; DELETED: " + - new HashSet(data.myDeleted)); + new HashSet(convertToStringPaths(data.myDeleted))); } currentFSChanges = data.getAndResetRescanFlag() ? null : data.createNextEvent(); projectTaskQueue = data.taskQueue; @@ -1107,8 +1117,8 @@ public class BuildManager implements ApplicationComponent{ private static class ProjectData { final SequentialTaskExecutor taskQueue; - private final Set myChanged = new THashSet(FileUtil.PATH_HASHING_STRATEGY); - private final Set myDeleted = new THashSet(FileUtil.PATH_HASHING_STRATEGY); + private final Set myChanged = new THashSet(); + private final Set myDeleted = new THashSet(); private long myNextEventOrdinal = 0L; private boolean myNeedRescan = true; @@ -1118,15 +1128,21 @@ public class BuildManager implements ApplicationComponent{ public void addChanged(Collection paths) { if (!myNeedRescan) { - myDeleted.removeAll(paths); - myChanged.addAll(paths); + for (String path : paths) { + final InternedPath _path = InternedPath.create(path); + myDeleted.remove(_path); + myChanged.add(_path); + } } } public void addDeleted(Collection paths) { if (!myNeedRescan) { - myChanged.removeAll(paths); - myDeleted.addAll(paths); + for (String path : paths) { + final InternedPath _path = InternedPath.create(path); + myChanged.remove(_path); + myDeleted.add(_path); + } } } @@ -1134,10 +1150,17 @@ public class BuildManager implements ApplicationComponent{ final CmdlineRemoteProto.Message.ControllerMessage.FSEvent.Builder builder = CmdlineRemoteProto.Message.ControllerMessage.FSEvent.newBuilder(); builder.setOrdinal(++myNextEventOrdinal); - builder.addAllChangedPaths(myChanged); + + for (InternedPath path : myChanged) { + builder.addChangedPaths(path.getValue()); + } myChanged.clear(); - builder.addAllDeletedPaths(myDeleted); + + for (InternedPath path : myDeleted) { + builder.addDeletedPaths(path.getValue()); + } myDeleted.clear(); + return builder.build(); } @@ -1155,4 +1178,84 @@ public class BuildManager implements ApplicationComponent{ } } + private static abstract class InternedPath { + protected final int[] myPath; + + /** + * @param path assuming system-independent path with forward slashes + */ + protected InternedPath(String path) { + final IntArrayList list = new IntArrayList(); + final StringTokenizer tokenizer = new StringTokenizer(path, "/", false); + while(tokenizer.hasMoreTokens()) { + final String element = tokenizer.nextToken(); + list.add(FileNameCache.storeName(element)); + } + myPath = list.toArray(); + } + + public abstract String getValue(); + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + InternedPath path = (InternedPath)o; + + if (!Arrays.equals(myPath, path.myPath)) return false; + + return true; + } + + @Override + public int hashCode() { + return Arrays.hashCode(myPath); + } + + public static InternedPath create(String path) { + return path.startsWith("/")? new XInternedPath(path) : new WinInternedPath(path); + } + } + + private static class WinInternedPath extends InternedPath { + private WinInternedPath(String path) { + super(path); + } + + public String getValue() { + if (myPath.length == 1) { + final String name = FileNameCache.getVFileName(myPath[0]); + // handle case of windows drive letter + return name.length() == 2 && name.endsWith(":")? name + "/" : name; + } + + final StringBuilder buf = new StringBuilder(); + for (int element : myPath) { + if (buf.length() > 0) { + buf.append("/"); + } + buf.append(FileNameCache.getVFileName(element)); + } + return buf.toString(); + } + } + + private static class XInternedPath extends InternedPath { + private XInternedPath(String path) { + super(path); + } + + public String getValue() { + if (myPath.length > 0) { + final StringBuilder buf = new StringBuilder(); + for (int element : myPath) { + buf.append("/").append(FileNameCache.getVFileName(element)); + } + return buf.toString(); + } + return "/"; + } + } + }