private void applyChildrenChangeEvents(VirtualFile parent, List<VFileEvent> events) { final NewVirtualFileSystem delegate = getDelegate(parent); TIntArrayList childrenIdsUpdated = new TIntArrayList(); List<VirtualFile> childrenToBeUpdated = new SmartList<VirtualFile>(); final int parentId = getFileId(parent); assert parentId != 0; TIntHashSet parentChildrenIds = new TIntHashSet(FSRecords.list(parentId)); boolean hasRemovedChildren = false; 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); assert parent instanceof VirtualDirectoryImpl : parent; final VirtualDirectoryImpl dir = (VirtualDirectoryImpl) parent; VirtualFileSystemEntry child = dir.createChild(name, childId, dir.getFileSystem()); childrenToBeUpdated.add(child); childrenIdsUpdated.add(childId); parentChildrenIds.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; } hasRemovedChildren = true; int id = getFileId(file); childrenToBeUpdated.add(file); childrenIdsUpdated.add(-id); parentChildrenIds.remove(id); } } FSRecords.updateList(parentId, parentChildrenIds.toArray()); if (hasRemovedChildren) clearIdCache(); VirtualDirectoryImpl parentImpl = (VirtualDirectoryImpl) parent; for (int i = 0, len = childrenIdsUpdated.size(); i < len; ++i) { final int childId = childrenIdsUpdated.get(i); final VirtualFile childFile = childrenToBeUpdated.get(i); if (childId > 0) { parentImpl.addChild((VirtualFileSystemEntry) childFile); } else { FSRecords.deleteRecordRecursively(-childId); parentImpl.removeChild(childFile); invalidateSubtree(childFile); } } }
@RequiredWriteAction @Override public void processEvents(@NotNull List<VFileEvent> events) { ApplicationManager.getApplication().assertWriteAccessAllowed(); List<VFileEvent> validated = validateEvents(events); BulkFileListener publisher = myEventBus.syncPublisher(VirtualFileManager.VFS_CHANGES); publisher.before(validated); THashMap<VirtualFile, List<VFileEvent>> parentToChildrenEventsChanges = null; for (VFileEvent event : validated) { VirtualFile changedParent = null; if (event instanceof VFileCreateEvent) { changedParent = ((VFileCreateEvent) event).getParent(); ((VFileCreateEvent) event).resetCache(); } 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); }
@Override @NotNull public VirtualFile[] getLocalRoots() { List<VirtualFile> roots = ContainerUtil.newSmartList(); myRootsLock.readLock().lock(); try { for (NewVirtualFile root : myRoots.values()) { if (root.isInLocalFileSystem() && !(root.getFileSystem() instanceof TempFileSystem)) { roots.add(root); } } } finally { myRootsLock.readLock().unlock(); } return VfsUtilCore.toVirtualFileArray(roots); }
@Override @NotNull public VirtualFile[] getRoots(@NotNull final NewVirtualFileSystem fs) { final List<VirtualFile> roots = new ArrayList<VirtualFile>(); myRootsLock.readLock().lock(); try { for (NewVirtualFile root : myRoots.values()) { if (root.getFileSystem() == fs) { roots.add(root); } } } finally { myRootsLock.readLock().unlock(); } return VfsUtilCore.toVirtualFileArray(roots); }
@NotNull private static FSRecords.NameId[] persistAllChildren( @NotNull final VirtualFile file, final int id, @NotNull FSRecords.NameId[] current) { final NewVirtualFileSystem fs = replaceWithNativeFS(getDelegate(file)); String[] delegateNames = VfsUtil.filterNames(fs.list(file)); if (delegateNames.length == 0 && current.length > 0) { return current; } Set<String> toAdd = ContainerUtil.newHashSet(delegateNames); for (FSRecords.NameId nameId : current) { toAdd.remove(nameId.name.toString()); } final TIntArrayList childrenIds = new TIntArrayList(current.length + toAdd.size()); final List<FSRecords.NameId> nameIds = ContainerUtil.newArrayListWithCapacity(current.length + toAdd.size()); for (FSRecords.NameId nameId : current) { childrenIds.add(nameId.id); nameIds.add(nameId); } for (String newName : toAdd) { FakeVirtualFile child = new FakeVirtualFile(file, newName); FileAttributes attributes = fs.getAttributes(child); if (attributes != null) { int childId = createAndFillRecord(fs, child, id, attributes); childrenIds.add(childId); nameIds.add(new FSRecords.NameId(childId, FileNameCache.storeName(newName), newName)); } } FSRecords.updateList(id, childrenIds.toNativeArray()); setChildrenCached(id); return nameIds.toArray(new FSRecords.NameId[nameIds.size()]); }
@NotNull private static List<VFileEvent> validateEvents(@NotNull List<VFileEvent> events) { final List<EventWrapper> deletionEvents = ContainerUtil.newArrayList(); for (int i = 0, size = events.size(); i < size; i++) { final VFileEvent event = events.get(i); if (event instanceof VFileDeleteEvent && event.isValid()) { deletionEvents.add(new EventWrapper((VFileDeleteEvent) event, i)); } } final TIntHashSet invalidIDs; if (deletionEvents.isEmpty()) { invalidIDs = EmptyIntHashSet.INSTANCE; } else { ContainerUtil.quickSort(deletionEvents, DEPTH_COMPARATOR); invalidIDs = new TIntHashSet(deletionEvents.size()); final Set<VirtualFile> dirsToBeDeleted = new THashSet<VirtualFile>(deletionEvents.size()); nextEvent: for (EventWrapper wrapper : deletionEvents) { final VirtualFile candidate = wrapper.event.getFile(); VirtualFile parent = candidate; while (parent != null) { if (dirsToBeDeleted.contains(parent)) { invalidIDs.add(wrapper.id); continue nextEvent; } parent = parent.getParent(); } if (candidate.isDirectory()) { dirsToBeDeleted.add(candidate); } } } final List<VFileEvent> filtered = new ArrayList<VFileEvent>(events.size() - invalidIDs.size()); for (int i = 0, size = events.size(); i < size; i++) { final VFileEvent event = events.get(i); if (event.isValid() && !(event instanceof VFileDeleteEvent && invalidIDs.contains(i))) { filtered.add(event); } } return filtered; }