Bug 575242 - Minute-long UI freeze when search-replacing in thousands of files
Summary: Minute-long UI freeze when search-replacing in thousands of files
Status: VERIFIED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: Search (show other bugs)
Version: 3.8.2   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: 4.21 M3   Edit
Assignee: Andrey Loskutov CLA
QA Contact:
URL:
Whiteboard:
Keywords: noteworthy, performance
Depends on:
Blocks:
 
Reported: 2021-08-04 09:58 EDT by Simeon Andreev CLA
Modified: 2021-08-07 09:20 EDT (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Simeon Andreev CLA 2021-08-04 09:58:33 EDT
To reproduce, create a Java project and generate some text files in it. E.g. with (adjust path to folder accordingly):

public class GenerateFiles {

        public static void main(String[] args) {
                Path folder = Paths.get("/tmp/cr150896_ws/Test/folder");
                int n = 5_000;
                String baseContent = "replacement here";
                for (int i = 0; i < n; ++i) {
                        System.out.println("Writing file " + i);
                        String content = baseContent + " n" + i;
                        String fileName = "file" + i + ".txt";
                        Path file = folder.resolve(fileName);
                        try {
                                Files.write(file, content.getBytes());
                        } catch (IOException e) {
                                System.err.println("Failed to write file: " + fileName);
                                e.printStackTrace();
                        }
                }
        }

}

Refresh the folder, use Search, use Replace... and try to replace e.g. "some text" with "replacement". The UI then freezes for upward of 10 minutes (on a HP Z640 workstation and local disk), with a stack trace similar to e.g.:

"main" #1 prio=6 os_prio=0 cpu=347370.93ms elapsed=843.04s tid=0x00007ffff0017000 nid=0x186b5 runnable  [0x00007ffff7fc8000]
   java.lang.Thread.State: RUNNABLE
        at java.lang.StringBuffer.<init>(java.base@11.0.11/StringBuffer.java:152)
        at sun.text.normalizer.ReplaceableString.<init>(java.base@11.0.11/ReplaceableString.java:59)
        at sun.text.normalizer.ReplaceableUCharacterIterator.<init>(java.base@11.0.11/ReplaceableUCharacterIterator.java:62)
        at sun.text.normalizer.UCharacterIterator.getInstance(java.base@11.0.11/UCharacterIterator.java:79)
        at sun.text.normalizer.NormalizerBase.setText(java.base@11.0.11/NormalizerBase.java:709)
        at java.text.CollationElementIterator.setText(java.base@11.0.11/CollationElementIterator.java:511)
        at java.text.RuleBasedCollator.compare(java.base@11.0.11/RuleBasedCollator.java:390)
        - locked <0x0000000604edc4d0> (a java.text.RuleBasedCollator)
        at java.text.Collator.compare(java.base@11.0.11/Collator.java:305)
        at org.eclipse.search.internal.ui.text.FileSearchPage$DecoratorIgnoringViewerSorter.compare(FileSearchPage.java:114)
        at org.eclipse.jface.viewers.ViewerComparator.lambda$0(ViewerComparator.java:206)
        at org.eclipse.jface.viewers.ViewerComparator$$Lambda$556/0x0000000840781040.compare(Unknown Source)
        at java.util.TimSort.mergeHi(java.base@11.0.11/TimSort.java:841)
        at java.util.TimSort.mergeAt(java.base@11.0.11/TimSort.java:520)
        at java.util.TimSort.mergeForceCollapse(java.base@11.0.11/TimSort.java:461)
        at java.util.TimSort.sort(java.base@11.0.11/TimSort.java:254)
        at java.util.Arrays.sort(java.base@11.0.11/Arrays.java:1441)                                                                                                               
        at org.eclipse.jface.viewers.ViewerComparator.sort(ViewerComparator.java:206)                                                                                              
        at org.eclipse.jface.viewers.AbstractTreeViewer.getSortedChildren(AbstractTreeViewer.java:649)                                                                             
        at org.eclipse.jface.viewers.AbstractTreeViewer.updateChildren(AbstractTreeViewer.java:2673)                                                                               
        at org.eclipse.jface.viewers.AbstractTreeViewer.internalRefreshStruct(AbstractTreeViewer.java:1960)
        at org.eclipse.jface.viewers.TreeViewer.internalRefreshStruct(TreeViewer.java:677)
        at org.eclipse.jface.viewers.AbstractTreeViewer.internalRefresh(AbstractTreeViewer.java:1936)
        at org.eclipse.jface.viewers.AbstractTreeViewer.internalRefresh(AbstractTreeViewer.java:1893)
        at org.eclipse.jface.viewers.AbstractTreeViewer.internalRefresh(AbstractTreeViewer.java:1879)
        at org.eclipse.jface.viewers.StructuredViewer.lambda$2(StructuredViewer.java:1461)
        at org.eclipse.jface.viewers.StructuredViewer$$Lambda$538/0x00000008406f8c40.run(Unknown Source)
        at org.eclipse.jface.viewers.StructuredViewer.preservingSelection(StructuredViewer.java:1400)
        at org.eclipse.jface.viewers.TreeViewer.preservingSelection(TreeViewer.java:363)
        at org.eclipse.jface.viewers.StructuredViewer.preservingSelection(StructuredViewer.java:1361)
        at org.eclipse.jface.viewers.StructuredViewer.refresh(StructuredViewer.java:1461)
        at org.eclipse.jface.viewers.ColumnViewer.refresh(ColumnViewer.java:526)
        at org.eclipse.search.internal.ui.text.FileTreeContentProvider.remove(FileTreeContentProvider.java:145)
        at org.eclipse.search.internal.ui.text.FileTreeContentProvider.remove(FileTreeContentProvider.java:152)
        at org.eclipse.search.internal.ui.text.FileTreeContentProvider.remove(FileTreeContentProvider.java:152)
        at org.eclipse.search.internal.ui.text.FileTreeContentProvider.elementsChanged(FileTreeContentProvider.java:216)
        - locked <0x0000000619c12558> (a org.eclipse.search.internal.ui.text.FileTreeContentProvider)
        at org.eclipse.search.internal.ui.text.FileSearchPage.elementsChanged(FileSearchPage.java:322)
        at org.eclipse.search.ui.text.AbstractTextSearchViewPage.runBatchedUpdates(AbstractTextSearchViewPage.java:1240)
        - locked <0x0000000619c0bc80> (a org.eclipse.search.internal.ui.text.FileSearchPage)
        at org.eclipse.search.ui.text.AbstractTextSearchViewPage$UpdateUIJob.runInUIThread(AbstractTextSearchViewPage.java:151)
        at org.eclipse.ui.progress.UIJob.lambda$0(UIJob.java:95)
        at org.eclipse.ui.progress.UIJob$$Lambda$665/0x0000000840822c40.run(Unknown Source)
        at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:40)
        at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:185)
        - locked <0x00000006049c3a10> (a org.eclipse.swt.widgets.RunnableLock)
        at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:5110)
        at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:4596)
        at org.eclipse.jface.operation.ModalContext$ModalContextThread.block(ModalContext.java:166)
        at org.eclipse.jface.operation.ModalContext.run(ModalContext.java:368)
        at org.eclipse.ltk.internal.ui.refactoring.RefactoringWizardDialog2.run(RefactoringWizardDialog2.java:324)
        at org.eclipse.ltk.ui.refactoring.RefactoringWizard.internalPerformFinish(RefactoringWizard.java:636)
        at org.eclipse.ltk.ui.refactoring.UserInputWizardPage.performFinish(UserInputWizardPage.java:148)
        at org.eclipse.search.internal.ui.text.ReplaceConfigurationPage.performFinish(ReplaceConfigurationPage.java:186)
        at org.eclipse.ltk.ui.refactoring.RefactoringWizard.performFinish(RefactoringWizard.java:710)
        at org.eclipse.ltk.internal.ui.refactoring.RefactoringWizardDialog2.okPressed(RefactoringWizardDialog2.java:450)
        at org.eclipse.jface.dialogs.Dialog.buttonPressed(Dialog.java:468)
        at org.eclipse.jface.dialogs.Dialog.lambda$0(Dialog.java:619)
        at org.eclipse.jface.dialogs.Dialog$$Lambda$206/0x00000008402e7440.accept(Unknown Source)
        at org.eclipse.swt.events.SelectionListener$1.widgetSelected(SelectionListener.java:84)
        at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:252)
        at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:89)
        at org.eclipse.swt.widgets.Display.sendEvent(Display.java:5893)
        at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1439)
        at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:5135)
        at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:4593)
        at org.eclipse.jface.window.Window.runEventLoop(Window.java:823)
        at org.eclipse.jface.window.Window.open(Window.java:799)
        at org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation.lambda$0(RefactoringWizardOpenOperation.java:190)
        at org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation$$Lambda$1396/0x0000000840ebf440.run(Unknown Source)
        at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:74)
        at org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation.run(RefactoringWizardOpenOperation.java:209)
        at org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation.run(RefactoringWizardOpenOperation.java:126)
        at org.eclipse.search.internal.ui.text.ReplaceAction.run(ReplaceAction.java:65)
        at org.eclipse.search.internal.ui.text.TextSearchPage.lambda$0(TextSearchPage.java:302)
        at org.eclipse.search.internal.ui.text.TextSearchPage$$Lambda$1393/0x0000000840ebe440.run(Unknown Source)
        at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:40)
        at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:185)
        - locked <0x00000006089a7668> (a org.eclipse.swt.widgets.RunnableLock)
        at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:5110)
        at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:4596)
        at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1158)
        at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:338)
        at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1047)
        at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:155)
        at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:644)
        at org.eclipse.ui.internal.Workbench$$Lambda$236/0x000000084033cc40.run(Unknown Source)
        at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:338)
        at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:551)
        at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:156)
        at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:152)
        at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:203)
        at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:136)
        at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104)
        at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:401)
        at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:255)
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@11.0.11/Native Method)
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@11.0.11/NativeMethodAccessorImpl.java:62)
        at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@11.0.11/DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(java.base@11.0.11/Method.java:566)
        at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:654)
        at org.eclipse.equinox.launcher.Main.basicRun(Main.java:591)
        at org.eclipse.equinox.launcher.Main.run(Main.java:1462)
        at org.eclipse.equinox.launcher.Main.main(Main.java:1435)

Likely the Search results view is not batching the remove operation, or some other expensive operation.
Comment 1 Andrey Loskutov CLA 2021-08-04 12:14:52 EDT
Patch: https://git.eclipse.org/r/c/platform/eclipse.platform.text/+/183701

Briefly checked, that reduces wait time to < 1 second.

Have not tested other use cases.
Comment 2 Andrey Loskutov CLA 2021-08-05 11:52:20 EDT
I've tested various "Search" use cases now and I see no functional changes, only performance improvement for most cases.

I've tried selecting different expanded nodes in same / multiple files and either remove one/some of them from Search results, or deleting related / not related files with search matches - in all cases the behavior with the patch seem to be identical - right elements are removed, tree is properly updated, remaining selected elements are still selected etc.
Comment 3 Eclipse Genie CLA 2021-08-05 15:43:49 EDT
New Gerrit change created: https://git.eclipse.org/r/c/platform/eclipse.platform.text/+/183747
Comment 4 Eclipse Genie CLA 2021-08-05 15:43:51 EDT
New Gerrit change created: https://git.eclipse.org/r/c/platform/eclipse.platform.text/+/183748
Comment 5 Simeon Andreev CLA 2021-08-06 02:56:27 EDT
Generating 100 000 matches, the Search view struggles with even populating its tree; regardless of how replacing behaves, the UI is frozen for 10+ minutes:

"main" #1 prio=6 os_prio=0 cpu=43454.15ms elapsed=108.45s tid=0x00007ffff0017800 nid=0xa312 runnable  [0x00007ffff7fca000]
   java.lang.Thread.State: RUNNABLE
        at org.eclipse.swt.internal.gtk.GTK.gtk_tree_store_append(Native Method)
        at org.eclipse.swt.widgets.Tree.createItem(Tree.java:992)
        at org.eclipse.swt.widgets.TreeItem.<init>(TreeItem.java:168)
        at org.eclipse.swt.widgets.TreeItem.<init>(TreeItem.java:128)
        at org.eclipse.jface.viewers.TreeViewer.createNewRowPart(TreeViewer.java:769)
        at org.eclipse.jface.viewers.TreeViewer.newItem(TreeViewer.java:276)
        at org.eclipse.jface.viewers.AbstractTreeViewer.updatePlus(AbstractTreeViewer.java:2920)
        at org.eclipse.jface.viewers.TreeViewer.updatePlus(TreeViewer.java:794)
        at org.eclipse.jface.viewers.AbstractTreeViewer.createTreeItem(AbstractTreeViewer.java:854)
        at org.eclipse.jface.viewers.AbstractTreeViewer.createChildren(AbstractTreeViewer.java:831)
        at org.eclipse.jface.viewers.TreeViewer.createChildren(TreeViewer.java:604)
        at org.eclipse.jface.viewers.AbstractTreeViewer.createChildren(AbstractTreeViewer.java:779)
        at org.eclipse.jface.viewers.AbstractTreeViewer.setExpandedState(AbstractTreeViewer.java:2526)                                                                             
        at org.eclipse.search2.internal.ui.basic.views.TreeViewerNavigator.getChildren(TreeViewerNavigator.java:140)                                                               
        at org.eclipse.search2.internal.ui.basic.views.TreeViewerNavigator.getFirstChildWithMatches(TreeViewerNavigator.java:129)                                                  
        at org.eclipse.search2.internal.ui.basic.views.TreeViewerNavigator.getFirstChildWithMatches(TreeViewerNavigator.java:136)                                                  
        at org.eclipse.search2.internal.ui.basic.views.TreeViewerNavigator.getNextItemForward(TreeViewerNavigator.java:106)
        at org.eclipse.search2.internal.ui.basic.views.TreeViewerNavigator.navigateNext(TreeViewerNavigator.java:41)
        at org.eclipse.search.ui.text.AbstractTextSearchViewPage.navigateNext(AbstractTextSearchViewPage.java:989)
        at org.eclipse.search.ui.text.AbstractTextSearchViewPage$UpdateUIJob.runInUIThread(AbstractTextSearchViewPage.java:162)
        at org.eclipse.ui.progress.UIJob.lambda$0(UIJob.java:95)
        at org.eclipse.ui.progress.UIJob$$Lambda$715/0x00000008409b2040.run(Unknown Source)
        at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:40)
        at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:185)
        - locked <0x00000000dc4851b8> (a org.eclipse.swt.widgets.RunnableLock)
        at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:5115)
        at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:4601)
        at org.eclipse.jface.operation.ModalContext$ModalContextThread.block(ModalContext.java:166)
        at org.eclipse.jface.operation.ModalContext.run(ModalContext.java:368)
        at org.eclipse.jface.dialogs.ProgressMonitorDialog.run(ProgressMonitorDialog.java:468)
        at org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog.run(ProgressMonitorJobsDialog.java:228)
        at org.eclipse.ui.internal.progress.ProgressManager.lambda$26(ProgressManager.java:821)
        at org.eclipse.ui.internal.progress.ProgressManager$$Lambda$832/0x0000000840b65840.run(Unknown Source)
        at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:74)
        at org.eclipse.ui.internal.progress.ProgressManager.busyCursorWhile(ProgressManager.java:854)
        at org.eclipse.ui.internal.progress.ProgressManager.busyCursorWhile(ProgressManager.java:830)
        at org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation.checkInitialConditions(RefactoringWizardOpenOperation.java:222)
        at org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation.lambda$0(RefactoringWizardOpenOperation.java:173)
        at org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation$$Lambda$831/0x0000000840b67040.run(Unknown Source)
        at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:74)
        at org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation.run(RefactoringWizardOpenOperation.java:209)
        at org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation.run(RefactoringWizardOpenOperation.java:126)
        at org.eclipse.search.internal.ui.text.ReplaceAction.run(ReplaceAction.java:65)
        at org.eclipse.search.internal.ui.text.TextSearchPage.lambda$0(TextSearchPage.java:302)
        at org.eclipse.search.internal.ui.text.TextSearchPage$$Lambda$1156/0x0000000840defc40.run(Unknown Source)

Replacing itself then also freezes the UI for minutes (despite all suggested changes so far):

"main" #1 prio=6 os_prio=0 cpu=948236.07ms elapsed=1018.00s tid=0x00007ffff0017800 nid=0xa312 runnable  [0x00007ffff7fca000]
   java.lang.Thread.State: RUNNABLE
        at org.eclipse.swt.internal.gtk.GTK.gtk_tree_store_set(Native Method)
        at org.eclipse.swt.widgets.TreeItem.setBackground(TreeItem.java:1191)
        at org.eclipse.jface.viewers.TreeViewerRow.setBackground(TreeViewerRow.java:96)
        at org.eclipse.jface.viewers.ViewerCell.setBackground(ViewerCell.java:134)
        at org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.update(DelegatingStyledCellLabelProvider.java:127)
        at org.eclipse.jface.viewers.DecoratingStyledCellLabelProvider.update(DecoratingStyledCellLabelProvider.java:134)
        at org.eclipse.jface.viewers.ViewerColumn.refresh(ViewerColumn.java:144)
        at org.eclipse.jface.viewers.AbstractTreeViewer.doUpdateItem(AbstractTreeViewer.java:959)
        at org.eclipse.jface.viewers.AbstractTreeViewer$UpdateItemSafeRunnable.run(AbstractTreeViewer.java:126)
        at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
        at org.eclipse.ui.internal.JFaceUtil$$Lambda$102/0x00000008401d8040.run(Unknown Source)
        at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:174)
        at org.eclipse.jface.viewers.AbstractTreeViewer.doUpdateItem(AbstractTreeViewer.java:1037)
        at org.eclipse.jface.viewers.StructuredViewer$UpdateItemSafeRunnable.run(StructuredViewer.java:427)
        at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
        at org.eclipse.ui.internal.JFaceUtil$$Lambda$102/0x00000008401d8040.run(Unknown Source)
        at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:174)
        at org.eclipse.jface.viewers.StructuredViewer.updateItem(StructuredViewer.java:2111)
        at org.eclipse.jface.viewers.StructuredViewer.internalUpdate(StructuredViewer.java:2094)
        at org.eclipse.jface.viewers.StructuredViewer.update(StructuredViewer.java:2035)
        at org.eclipse.jface.viewers.ColumnViewer.update(ColumnViewer.java:545)
        at org.eclipse.jface.viewers.StructuredViewer.update(StructuredViewer.java:1979)
        at org.eclipse.jface.viewers.StructuredViewer.handleLabelProviderChanged(StructuredViewer.java:1158)
        at org.eclipse.jface.viewers.ContentViewer$1.labelProviderChanged(ContentViewer.java:95)
        at org.eclipse.jface.viewers.BaseLabelProvider$1.run(BaseLabelProvider.java:75)
        at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
        at org.eclipse.ui.internal.JFaceUtil$$Lambda$102/0x00000008401d8040.run(Unknown Source)
        at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:174)
        at org.eclipse.jface.viewers.BaseLabelProvider.fireLabelProviderChanged(BaseLabelProvider.java:72)
        at org.eclipse.jface.viewers.DecoratingStyledCellLabelProvider$$Lambda$460/0x000000084067bc40.labelProviderChanged(Unknown Source)
        at org.eclipse.ui.internal.decorators.DecoratorManager$1.run(DecoratorManager.java:347)
        at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
        at org.eclipse.ui.internal.decorators.DecoratorManager.fireListener(DecoratorManager.java:344)
        at org.eclipse.ui.internal.decorators.DecorationScheduler$3.runInUIThread(DecorationScheduler.java:551)
        at org.eclipse.ui.progress.UIJob.lambda$0(UIJob.java:95)
        at org.eclipse.ui.progress.UIJob$$Lambda$715/0x00000008409b2040.run(Unknown Source)
        at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:40)
        at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:185)
        - locked <0x00000000de800118> (a org.eclipse.swt.widgets.RunnableLock)
        at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:5115)
        at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:4601)
        at org.eclipse.jface.operation.ModalContext$ModalContextThread.block(ModalContext.java:166)
        at org.eclipse.jface.operation.ModalContext.run(ModalContext.java:368)
        at org.eclipse.jface.dialogs.ProgressMonitorDialog.run(ProgressMonitorDialog.java:468)
        at org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog.run(ProgressMonitorJobsDialog.java:228)
        at org.eclipse.ui.internal.progress.ProgressManager.lambda$26(ProgressManager.java:821)
        at org.eclipse.ui.internal.progress.ProgressManager$$Lambda$832/0x0000000840b65840.run(Unknown Source)
        at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:74)
        at org.eclipse.ui.internal.progress.ProgressManager.busyCursorWhile(ProgressManager.java:854)
        at org.eclipse.ui.internal.progress.ProgressManager.busyCursorWhile(ProgressManager.java:830)
        at org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation.checkInitialConditions(RefactoringWizardOpenOperation.java:222)
        at org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation.lambda$0(RefactoringWizardOpenOperation.java:173)
        at org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation$$Lambda$831/0x0000000840b67040.run(Unknown Source)
        at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:74)
        at org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation.run(RefactoringWizardOpenOperation.java:209)
        at org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation.run(RefactoringWizardOpenOperation.java:126)
        at org.eclipse.search.internal.ui.text.ReplaceAction.run(ReplaceAction.java:65)
        at org.eclipse.search.internal.ui.text.TextSearchPage.lambda$0(TextSearchPage.java:302)
        at org.eclipse.search.internal.ui.text.TextSearchPage$$Lambda$1156/0x0000000840defc40.run(Unknown Source)

The main problem here should be that we are filling a GTK+ tree with "too many" elements. I believe a virtual tree/table should be used for this amount of data. Either that or we limit the number of elements shown in the tree. Or we group them in a way that doesn't hang in GTK+ code (e.g. add a root node for every 1k matches, if above 1k matches).

I think the limit might be the easiest option, if it doesn't hinder replacing all matches. I.e. the user should not be told "this operation will replace only the first N matches". A limit might not be easy to add at all (I've not checked how dependent the replacement code is on the UI elements), just likely easier than the other options.

A virtual tree/table is probably the cleanest option, but I don't know if we have the time to make a change like that (in particular, whether we can validate that all use cases work).
Comment 6 Andrey Loskutov CLA 2021-08-06 04:12:39 EDT
(In reply to Simeon Andreev from comment #5)
> Generating 100 000 matches, the Search view struggles with even populating
> its tree; regardless of how replacing behaves, the UI is frozen for 10+
> minutes:

As discussed, please create another bug for that, and attach there your example that causes this hang. I don't see it with 10000 files and 10 matches each, I assume it depends on how the matches are placed.


> The main problem here should be that we are filling a GTK+ tree with "too
> many" elements. I believe a virtual tree/table should be used for this
> amount of data. Either that or we limit the number of elements shown in the
> tree. Or we group them in a way that doesn't hang in GTK+ code (e.g. add a
> root node for every 1k matches, if above 1k matches).
> 
> I think the limit might be the easiest option, if it doesn't hinder
> replacing all matches. I.e. the user should not be told "this operation will
> replace only the first N matches". A limit might not be easy to add at all
> (I've not checked how dependent the replacement code is on the UI elements),
> just likely easier than the other options.
> 
> A virtual tree/table is probably the cleanest option, but I don't know if we
> have the time to make a change like that (in particular, whether we can
> validate that all use cases work).

That's why it should go to a different bug or even two/more. One for JFace/Search regarding the performance of tree creation etc, another one for search limit.

The issue we've originally observed here was the UI hang on performing replace with 25.000 matches, and that should be fixed by linked gerrits.
Comment 10 Andrey Loskutov CLA 2021-08-07 09:20:19 EDT
Verified with I20210806-1800