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 df8f86f4f158..1ae50a5af3a7 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 @@ -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> 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>(); + List parentChildrenChanges = parentToChildrenEventsChanges.get(changedParent); + if (parentChildrenChanges == null) { + parentToChildrenEventsChanges.put(changedParent, parentChildrenChanges = new SmartList()); + } + parentChildrenChanges.add(event); + } else { + applyEvent(event); + } } + + if (parentToChildrenEventsChanges != null) { + parentToChildrenEventsChanges.forEachEntry(new TObjectObjectProcedure>() { + @Override + public boolean execute(VirtualFile parent, List childrenEvents) { + applyChildrenChangeEvents(parent, childrenEvents); + return true; + } + }); + parentToChildrenEventsChanges.clear(); + } + publisher.after(validated); } + private void applyChildrenChangeEvents(VirtualFile parent, List events) { + final NewVirtualFileSystem delegate = getDelegate(parent); + List childrenToBeAdded = null; + TIntArrayList childrenIdsToBeRemoved = null; + List 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(); + } + + 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(); + } + + 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) {