notify BuildManager only if file events affect opened and watched projects (second part of IDEA-122685)

This commit is contained in:
Eugene Zhuravlev
2014-06-01 18:40:46 +04:00
parent c503439a32
commit 1f4d0df305
2 changed files with 88 additions and 123 deletions
@@ -25,7 +25,6 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
@@ -78,7 +77,7 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent {
void execute(VirtualFile file);
}
private static void processRecursively(final VirtualFile fromFile, final boolean dbOnly, final boolean needReadAction, final FileProcessor processor) {
private static void processRecursively(final VirtualFile fromFile, final boolean dbOnly, final FileProcessor processor) {
if (!(fromFile.getFileSystem() instanceof LocalFileSystem)) {
return;
}
@@ -103,77 +102,70 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent {
if (dbOnly) {
return file.isDirectory()? ((NewVirtualFile)file).iterInDbChildren() : null;
}
if (file.equals(fromFile) || !file.isDirectory()) {
return null; // skipping additional checks for the initial file and non-directory files
}
// optimization: for all files that are not under content of currently opened projects iterate over DB children
return isInContentOfOpenedProject(file, needReadAction)? null : ((NewVirtualFile)file).iterInDbChildren();
return null;
}
});
}
private static boolean isInContentOfOpenedProject(@NotNull final VirtualFile file, boolean needReadAction) {
private static boolean isInContentOfOpenedProject(@NotNull final VirtualFile file) {
// probably need a read action to ensure that the project was not disposed during the iteration over the project list
final Computable<Boolean> computation = new Computable<Boolean>() {
public Boolean compute() {
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
if (!project.isInitialized()) {
continue;
}
if (ProjectRootManager.getInstance(project).getFileIndex().isInContent(file)) {
return Boolean.TRUE;
}
}
return Boolean.FALSE;
for (Project project : ProjectManager.getInstance().getOpenProjects()) {
if (!project.isInitialized() || !BuildManager.getInstance().isProjectWatched(project)) {
continue;
}
};
return needReadAction? ApplicationManager.getApplication().runReadAction(computation) : computation.compute();
if (ProjectRootManager.getInstance(project).getFileIndex().isInContent(file)) {
return true;
}
}
return false;
}
private class MyVfsListener extends VirtualFileAdapter {
public void propertyChanged(@NotNull final VirtualFilePropertyEvent event) {
if (VirtualFile.PROP_NAME.equals(event.getPropertyName())) {
final VirtualFile eventFile = event.getFile();
final VirtualFile parent = event.getParent();
if (parent != null) {
final String oldName = (String)event.getOldValue();
final String root = parent.getPath() + "/" + oldName;
final Set<File> toMark = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
if (eventFile.isDirectory()) {
VfsUtilCore.visitChildrenRecursively(eventFile, new VirtualFileVisitor() {
private StringBuilder filePath = new StringBuilder(root);
@Override
public boolean visitFile(@NotNull VirtualFile child) {
if (child.isDirectory()) {
if (!Comparing.equal(child, eventFile)) {
filePath.append("/").append(child.getName());
if (isInContentOfOpenedProject(eventFile)) {
final VirtualFile parent = event.getParent();
if (parent != null) {
final String oldName = (String)event.getOldValue();
final String root = parent.getPath() + "/" + oldName;
final Set<File> toMark = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
if (eventFile.isDirectory()) {
VfsUtilCore.visitChildrenRecursively(eventFile, new VirtualFileVisitor() {
private StringBuilder filePath = new StringBuilder(root);
@Override
public boolean visitFile(@NotNull VirtualFile child) {
if (child.isDirectory()) {
if (!Comparing.equal(child, eventFile)) {
filePath.append("/").append(child.getName());
}
}
else {
String childPath = filePath.toString();
if (!Comparing.equal(child, eventFile)) {
childPath += "/" + child.getName();
}
toMark.add(new File(childPath));
}
return true;
}
@Override
public void afterChildrenVisited(@NotNull VirtualFile file) {
if (file.isDirectory() && !Comparing.equal(file, eventFile)) {
filePath.delete(filePath.length() - file.getName().length() - 1, filePath.length());
}
}
else {
String childPath = filePath.toString();
if (!Comparing.equal(child, eventFile)) {
childPath += "/" + child.getName();
}
toMark.add(new File(childPath));
}
return true;
}
@Override
public void afterChildrenVisited(@NotNull VirtualFile file) {
if (file.isDirectory() && !Comparing.equal(file, eventFile)) {
filePath.delete(filePath.length() - file.getName().length() - 1, filePath.length());
}
}
});
});
}
else {
toMark.add(new File(root));
}
notifyFilesDeleted(toMark);
}
else {
toMark.add(new File(root));
}
notifyFilesDeleted(toMark);
markDirtyIfSource(eventFile, false);
}
markDirtyIfSource(eventFile, false);
}
}
@@ -195,23 +187,25 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent {
public void beforeFileDeletion(@NotNull final VirtualFileEvent event) {
final VirtualFile eventFile = event.getFile();
if ((LOG.isDebugEnabled() && eventFile.isDirectory()) || ourDebugMode) {
final String message = "Processing file deletion: " + eventFile.getPresentableUrl();
LOG.debug(message);
if (ourDebugMode) {
System.out.println(message);
if (isInContentOfOpenedProject(eventFile)) {
if ((LOG.isDebugEnabled() && eventFile.isDirectory()) || ourDebugMode) {
final String message = "Processing file deletion: " + eventFile.getPresentableUrl();
LOG.debug(message);
if (ourDebugMode) {
System.out.println(message);
}
}
final Set<File> pathsToMark = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
processRecursively(eventFile, true, new FileProcessor() {
public void execute(final VirtualFile file) {
pathsToMark.add(new File(file.getPath()));
}
});
notifyFilesDeleted(pathsToMark);
}
final Set<File> pathsToMark = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
processRecursively(eventFile, true, false, new FileProcessor() {
public void execute(final VirtualFile file) {
pathsToMark.add(new File(file.getPath()));
}
});
notifyFilesDeleted(pathsToMark);
}
public void beforeFileMovement(@NotNull final VirtualFileMoveEvent event) {
@@ -219,54 +213,34 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent {
}
private void markDirtyIfSource(final VirtualFile file, final boolean fromMove) {
final Set<File> pathsToMark = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
processRecursively(file, false, false, new FileProcessor() {
public void execute(final VirtualFile file) {
pathsToMark.add(new File(file.getPath()));
}
});
if (fromMove) {
notifyFilesDeleted(pathsToMark);
}
else if (!isIgnoredOrUnderIgnoredDirectory(file)) {
notifyFilesChanged(pathsToMark);
}
}
private void processNewFile(final VirtualFile file) {
if (!isIgnoredOrUnderIgnoredDirectory(file)) { // todo: avoid duplicated isInContent check
if (isInContentOfOpenedProject(file)) {
final Set<File> pathsToMark = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
boolean dbOnly = !isInContentOfOpenedProject(file, false);
processRecursively(file, dbOnly, false, new FileProcessor() {
@Override
public void execute(VirtualFile file) {
processRecursively(file, false, new FileProcessor() {
public void execute(final VirtualFile file) {
pathsToMark.add(new File(file.getPath()));
}
});
notifyFilesChanged(pathsToMark);
if (fromMove) {
notifyFilesDeleted(pathsToMark);
}
else {
notifyFilesChanged(pathsToMark);
}
}
}
}
private static boolean isIgnoredOrUnderIgnoredDirectory(final VirtualFile file) {
final FileTypeManager fileTypeManager = FileTypeManager.getInstance();
if (fileTypeManager.isFileIgnored(file)) {
return true;
private static void processNewFile(final VirtualFile file) {
if (isInContentOfOpenedProject(file)) {
final Set<File> pathsToMark = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
processRecursively(file, false, new FileProcessor() {
@Override
public void execute(VirtualFile file) {
pathsToMark.add(new File(file.getPath()));
}
});
notifyFilesChanged(pathsToMark);
}
//optimization: if file is in content of some project it's definitely not ignored
if (isInContentOfOpenedProject(file, true)) {
return false;
}
VirtualFile current = file.getParent();
while (current != null) {
if (fileTypeManager.isFileIgnored(current)) {
return true;
}
current = current.getParent();
}
return false;
}
private static void notifyFilesChanged(Collection<File> paths) {
@@ -91,7 +91,6 @@ import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.ide.PooledThreadExecutor;
import org.jetbrains.io.ChannelRegistrar;
import org.jetbrains.io.NettyUtil;
@@ -383,12 +382,8 @@ public class BuildManager implements ApplicationComponent{
scheduleAutoMake();
}
public boolean rescanRequired(Project project) {
final String projectPath = getProjectPath(project);
synchronized (myProjectDataMap) {
final ProjectData data = myProjectDataMap.get(projectPath);
return data == null || data.myNeedRescan;
}
public boolean isProjectWatched(Project project) {
return myProjectDataMap.containsKey(getProjectPath(project));
}
@Nullable
@@ -915,6 +910,7 @@ public class BuildManager implements ApplicationComponent{
cmdLine.addParameter("-D" + GlobalOptions.LOG_DIR_OPTION + "=" + FileUtil.toSystemIndependentName(getBuildLogDirectory().getAbsolutePath()));
final File workDirectory = getBuildSystemDirectory();
//noinspection ResultOfMethodCallIgnored
workDirectory.mkdirs();
cmdLine.addParameter("-Djava.io.tmpdir=" + FileUtil.toSystemIndependentName(workDirectory.getPath()) + "/" + TEMP_DIR_NAME);
@@ -1034,11 +1030,6 @@ public class BuildManager implements ApplicationComponent{
return ((InetSocketAddress)serverChannel.localAddress()).getPort();
}
@TestOnly
public void stopWatchingProject(Project project) {
myProjectDataMap.remove(getProjectPath(project));
}
private static String classpathToString(List<String> cp) {
StringBuilder builder = new StringBuilder();
for (String file : cp) {