IDEA-134002 IDE very slow after file movements

This commit is contained in:
peter
2015-01-09 19:03:05 +01:00
parent 273789ceb9
commit dc2ecf7cd8
3 changed files with 54 additions and 12 deletions
@@ -20,7 +20,6 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.vfs.InvalidVirtualFileAccessException;
import com.intellij.openapi.vfs.newvfs.persistent.FSRecords;
import com.intellij.util.ArrayUtil;
import com.intellij.util.SmartFMap;
import com.intellij.util.concurrency.AtomicFieldUpdater;
import com.intellij.util.containers.ConcurrentBitSet;
import com.intellij.util.containers.ConcurrentIntObjectMap;
@@ -82,7 +81,7 @@ public class VfsData {
private static final ConcurrentIntObjectMap<Segment> ourSegments = ContainerUtil.createConcurrentIntObjectMap();
private static final ConcurrentBitSet ourInvalidatedIds = new ConcurrentBitSet();
private static TIntHashSet ourDyingIds = new TIntHashSet();
private static volatile SmartFMap<VirtualFileSystemEntry, VirtualDirectoryImpl> ourChangedParents = SmartFMap.emptyMap();
private static final ConcurrentIntObjectMap<VirtualDirectoryImpl> ourChangedParents = ContainerUtil.createConcurrentIntObjectMap();
static {
ApplicationManager.getApplication().addApplicationListener(new ApplicationAdapter() {
@@ -102,7 +101,7 @@ public class VfsData {
if (!ourDyingIds.isEmpty()) {
for (int id : ourDyingIds.toArray()) {
assertNotNull(getSegment(id, false)).myObjectArray.set(getOffset(id), ourDeadMarker);
ourChangedParents = ourChangedParents.minus(new VirtualFileImpl(id, null, null));
ourChangedParents.remove(id);
}
ourDyingIds = new TIntHashSet();
}
@@ -165,15 +164,12 @@ public class VfsData {
}
@Nullable
static VirtualDirectoryImpl getChangedParent(VirtualFileSystemEntry child) {
SmartFMap<VirtualFileSystemEntry, VirtualDirectoryImpl> map = ourChangedParents;
return map == (SmartFMap)SmartFMap.emptyMap() ? null : map.get(child);
static VirtualDirectoryImpl getChangedParent(int id) {
return ourChangedParents.get(id);
}
static void changeParent(VirtualFileSystemEntry child, VirtualDirectoryImpl parent) {
synchronized (ourDeadMarker) {
ourChangedParents = ourChangedParents.plus(child, parent);
}
static void changeParent(int id, VirtualDirectoryImpl parent) {
ourChangedParents.put(id, parent);
}
static void invalidateFile(int id) {
@@ -102,7 +102,7 @@ public abstract class VirtualFileSystemEntry extends NewVirtualFile {
@Override
public VirtualDirectoryImpl getParent() {
VirtualDirectoryImpl changedParent = VfsData.getChangedParent(this);
VirtualDirectoryImpl changedParent = VfsData.getChangedParent(myId);
return changedParent != null ? changedParent : myParent;
}
@@ -329,7 +329,7 @@ public abstract class VirtualFileSystemEntry extends NewVirtualFile {
parent.removeChild(this);
VirtualDirectoryImpl directory = (VirtualDirectoryImpl)newParent;
VfsData.changeParent(this, directory);
VfsData.changeParent(myId, directory);
directory.addChild(this);
updateLinkStatus();
}
@@ -417,6 +417,52 @@ public class VfsUtilTest extends PlatformLangTestCase {
}
public void testGetParentPerformance() throws IOException {
File tempDir = createTempDirectory();
final VirtualFile vDir = refreshAndFindFile(tempDir);
assertNotNull(vDir);
assertTrue(vDir.isDirectory());
final int depth = 10;
new WriteCommandAction.Simple(getProject()) {
@Override
protected void run() throws Throwable {
VirtualFile dir = vDir;
for (int i=0; i<depth; i++) {
dir = dir.createChildDirectory(this, "foo");
}
final VirtualFile leafDir = dir;
ThrowableRunnable checkPerformance = new ThrowableRunnable() {
private VirtualFile findRoot(VirtualFile file) {
while (true) {
VirtualFile parent = file.getParent();
if (parent == null) {
return file;
}
file = parent;
}
}
@Override
public void run() throws Throwable {
for (int i = 0; i < 5000000; i++) {
checkRootsEqual();
}
}
private void checkRootsEqual() {
assertEquals(findRoot(vDir), findRoot(leafDir));
}
};
int time = 1200;
PlatformTestUtil.startPerformanceTest("getParent is slow before movement", time, checkPerformance).assertTiming();
VirtualFile dir1 = vDir.createChildDirectory(this, "dir1");
VirtualFile dir2 = vDir.createChildDirectory(this, "dir2");
for (int i = 0; i < 13; i++) { /*13 is max length with THashMap capacity of 17, we get plenty collisions then*/
dir1.createChildData(this, "a" + i + ".txt").move(this, dir2);
}
PlatformTestUtil.startPerformanceTest("getParent is slow after movement", time, checkPerformance).assertTiming();
}
}.execute();
}
public void testFindRootWithDenormalizedPath() throws IOException {
File tempJar = IoTestUtil.createTestJar();
VirtualFile jar = refreshAndFindFile(tempJar);