From e8eb8cf8a69d92a1e56387c958f22aa9ea8aa452 Mon Sep 17 00:00:00 2001 From: Jeffrey Morlan Date: Sat, 3 Mar 2018 15:25:37 -0800 Subject: [PATCH] Fix indexing performance issue If you open two source roots quickly, there's a "thrashing" effect where each file added from the second root invalidates programCache and forces the first root's error checking task to rebuild its program(s). When this happens, error checking takes a long time: O(num files^2). This can also happen if you delete many files from one root while another root is error checking. Fix this by adding/removing all indexables at once with the lock held. --- src/netbeanstypescript/TSIndexerFactory.java | 16 +++++++--- src/netbeanstypescript/TSService.java | 33 +++++++++++--------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/netbeanstypescript/TSIndexerFactory.java b/src/netbeanstypescript/TSIndexerFactory.java index 95e30d6..eec83a9 100644 --- a/src/netbeanstypescript/TSIndexerFactory.java +++ b/src/netbeanstypescript/TSIndexerFactory.java @@ -38,6 +38,8 @@ package netbeanstypescript; import java.net.URL; +import java.util.ArrayList; +import java.util.List; import java.util.logging.Level; import java.util.prefs.Preferences; import org.netbeans.api.progress.ProgressHandle; @@ -45,6 +47,7 @@ import org.netbeans.api.project.FileOwnerQuery; import org.netbeans.api.project.Project; import org.netbeans.api.project.ProjectUtils; +import org.netbeans.modules.parsing.api.Snapshot; import org.netbeans.modules.parsing.api.Source; import org.netbeans.modules.parsing.spi.indexing.Context; import org.netbeans.modules.parsing.spi.indexing.CustomIndexer; @@ -52,6 +55,7 @@ import org.netbeans.modules.parsing.spi.indexing.Indexable; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; +import org.openide.util.Pair; /** * This "indexer" doesn't really index anything, it's just a way to read all the TS files in a @@ -78,15 +82,19 @@ protected void index(Iterable files, Context context) { if (root == null) { return; } + List> snapshots = new ArrayList<>(); for (Indexable indxbl: files) { FileObject fo = root.getFileObject(indxbl.getRelativePath()); if (fo == null) continue; if ("text/typescript".equals(FileUtil.getMIMEType(fo))) { - TSService.addFile(Source.create(fo).createSnapshot(), indxbl, context); + snapshots.add(Pair.of(indxbl, Source.create(fo).createSnapshot())); } else if (fo.getNameExt().equals("tsconfig.json")) { - TSService.addFile(Source.create(fo).createSnapshot(), indxbl, context); + snapshots.add(Pair.of(indxbl, Source.create(fo).createSnapshot())); } } + if (! snapshots.isEmpty()) { + TSService.addFiles(snapshots, context); + } } }; } @@ -105,9 +113,7 @@ public boolean supportsEmbeddedIndexers() { @Override public void filesDeleted(Iterable deleted, Context context) { - for (Indexable i: deleted) { - TSService.removeFile(i, context); - } + TSService.removeFiles(deleted, context); } @Override diff --git a/src/netbeanstypescript/TSService.java b/src/netbeanstypescript/TSService.java index 0d44cd3..458c804 100644 --- a/src/netbeanstypescript/TSService.java +++ b/src/netbeanstypescript/TSService.java @@ -73,6 +73,7 @@ import org.openide.filesystems.FileUtil; import org.openide.filesystems.URLMapper; import org.openide.modules.InstalledFileLocator; +import org.openide.util.Pair; import org.openide.util.RequestProcessor; /** @@ -270,7 +271,7 @@ private static class FileData { String path; } - static void addFile(Snapshot snapshot, Indexable indxbl, Context cntxt) { + static void addFiles(List> files, Context cntxt) { lock.lock(); try { URL rootURL = cntxt.getRootURI(); @@ -284,16 +285,18 @@ static void addFile(Snapshot snapshot, Indexable indxbl, Context cntxt) { } programs.put(rootURL, program); - FileData fi = new FileData(); - fi.program = program; - fi.fileObject = snapshot.getSource().getFileObject(); - fi.indexable = indxbl; - fi.path = fi.fileObject.getPath(); - allFiles.put(fi.path, fi); - - program.addFile(fi, snapshot, cntxt.checkForEditorModifications()); - if (! cntxt.isAllFilesIndexing() && ! cntxt.checkForEditorModifications()) { - program.needCompileOnSave.add(fi.fileObject); + for (Pair item: files) { + FileData fi = new FileData(); + fi.program = program; + fi.fileObject = item.second().getSource().getFileObject(); + fi.indexable = item.first(); + fi.path = fi.fileObject.getPath(); + allFiles.put(fi.path, fi); + + program.addFile(fi, item.second(), cntxt.checkForEditorModifications()); + if (! cntxt.isAllFilesIndexing() && ! cntxt.checkForEditorModifications()) { + program.needCompileOnSave.add(fi.fileObject); + } } } catch (Exception e) { throw new RuntimeException(e); @@ -302,14 +305,16 @@ static void addFile(Snapshot snapshot, Indexable indxbl, Context cntxt) { } } - static void removeFile(Indexable indxbl, Context cntxt) { + static void removeFiles(Iterable indxbls, Context cntxt) { lock.lock(); try { ProgramData program = programs.get(cntxt.getRootURI()); if (program != null) { try { - String path = program.removeFile(indxbl); - allFiles.remove(path); + for (Indexable indxbl: indxbls) { + String path = program.removeFile(indxbl); + allFiles.remove(path); + } } catch (Exception e) { throw new RuntimeException(e); }