mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
avoid O(N^2) for processing create or delete events (N number of such additions / removals)
This commit is contained in:
+102
-1
@@ -33,6 +33,7 @@ import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ConcurrentIntObjectMap;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.StripedLockIntObjectConcurrentHashMap;
|
||||
@@ -762,12 +763,112 @@ public class PersistentFSImpl extends PersistentFS implements ApplicationCompone
|
||||
|
||||
BulkFileListener publisher = myEventsBus.syncPublisher(VirtualFileManager.VFS_CHANGES);
|
||||
publisher.before(validated);
|
||||
|
||||
THashMap<VirtualFile, List<VFileEvent>> parentToChildrenEventsChanges = null;
|
||||
for (VFileEvent event : validated) {
|
||||
applyEvent(event);
|
||||
VirtualFile changedParent = null;
|
||||
if (event instanceof VFileCreateEvent) {
|
||||
changedParent = ((VFileCreateEvent)event).getParent();
|
||||
} else if (event instanceof VFileDeleteEvent) {
|
||||
changedParent = ((VFileDeleteEvent)event).getFile().getParent();
|
||||
}
|
||||
|
||||
if (changedParent != null) {
|
||||
if (parentToChildrenEventsChanges == null) parentToChildrenEventsChanges = new THashMap<VirtualFile, List<VFileEvent>>();
|
||||
List<VFileEvent> parentChildrenChanges = parentToChildrenEventsChanges.get(changedParent);
|
||||
if (parentChildrenChanges == null) {
|
||||
parentToChildrenEventsChanges.put(changedParent, parentChildrenChanges = new SmartList<VFileEvent>());
|
||||
}
|
||||
parentChildrenChanges.add(event);
|
||||
} else {
|
||||
applyEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
if (parentToChildrenEventsChanges != null) {
|
||||
parentToChildrenEventsChanges.forEachEntry(new TObjectObjectProcedure<VirtualFile, List<VFileEvent>>() {
|
||||
@Override
|
||||
public boolean execute(VirtualFile parent, List<VFileEvent> childrenEvents) {
|
||||
applyChildrenChangeEvents(parent, childrenEvents);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
parentToChildrenEventsChanges.clear();
|
||||
}
|
||||
|
||||
publisher.after(validated);
|
||||
}
|
||||
|
||||
private void applyChildrenChangeEvents(VirtualFile parent, List<VFileEvent> events) {
|
||||
final NewVirtualFileSystem delegate = getDelegate(parent);
|
||||
List<VirtualFile> childrenToBeAdded = null;
|
||||
TIntArrayList childrenIdsToBeRemoved = null;
|
||||
List<VirtualFile> childrenToBeRemoved = null;
|
||||
|
||||
assert parent != null && parent != mySuperRoot;
|
||||
final int parentId = getFileId(parent);
|
||||
assert parentId != 0;
|
||||
TIntHashSet childrenIds = new TIntHashSet(FSRecords.list(parentId));
|
||||
|
||||
for(VFileEvent event:events) {
|
||||
if (event instanceof VFileCreateEvent) {
|
||||
String name = ((VFileCreateEvent)event).getChildName();
|
||||
final VirtualFile fake = new FakeVirtualFile(parent, name);
|
||||
final FileAttributes attributes = delegate.getAttributes(fake);
|
||||
|
||||
if (attributes != null) {
|
||||
final int childId = createAndFillRecord(delegate, fake, parentId, attributes);
|
||||
if (childrenToBeAdded == null) {
|
||||
childrenToBeAdded = new SmartList<VirtualFile>();
|
||||
}
|
||||
|
||||
assert parent instanceof VirtualDirectoryImpl : parent;
|
||||
final VirtualDirectoryImpl dir = (VirtualDirectoryImpl)parent;
|
||||
VirtualFileSystemEntry child = dir.createChild(name, childId, dir.getFileSystem());
|
||||
childrenToBeAdded.add(child);
|
||||
childrenIds.add(childId);
|
||||
}
|
||||
} else if (event instanceof VFileDeleteEvent) {
|
||||
VirtualFile file = ((VFileDeleteEvent)event).getFile();
|
||||
if (!file.exists()) {
|
||||
LOG.error("Deleting a file, which does not exist: " + file.getPath());
|
||||
continue;
|
||||
}
|
||||
|
||||
int id = getFileId(file);
|
||||
|
||||
if(childrenIdsToBeRemoved == null) {
|
||||
childrenIdsToBeRemoved = new TIntArrayList();
|
||||
childrenToBeRemoved = new SmartList<VirtualFile>();
|
||||
}
|
||||
|
||||
childrenIdsToBeRemoved.add(id);
|
||||
childrenToBeRemoved.add(file);
|
||||
childrenIds.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
FSRecords.updateList(parentId, childrenIds.toArray());
|
||||
|
||||
if (childrenToBeAdded != null) {
|
||||
for(VirtualFile addedFile:childrenToBeAdded) {
|
||||
((VirtualDirectoryImpl)parent).addChild((VirtualFileSystemEntry)addedFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (childrenToBeRemoved != null) {
|
||||
clearIdCache();
|
||||
VirtualDirectoryImpl virtualDirectory = (VirtualDirectoryImpl)parent;
|
||||
|
||||
for(int i = 0, len = childrenIdsToBeRemoved.size(); i < len; ++i) {
|
||||
FSRecords.deleteRecordRecursively(childrenIdsToBeRemoved.get(i));
|
||||
VirtualFile removedFile = childrenToBeRemoved.get(i);
|
||||
virtualDirectory.removeChild(removedFile);
|
||||
invalidateSubtree(removedFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public VirtualFileSystemEntry findRoot(@NotNull String basePath, @NotNull NewVirtualFileSystem fs) {
|
||||
|
||||
Reference in New Issue
Block a user