Skip to content

Commit 67e6dfa

Browse files
iloveeclipselathapatil
authored andcommitted
File search: cache getMatchCount() result to avoid UI hangs
If the search view has matches for 100.000 files, it would hang forever on updating the view via F5 because it asks getMatchCount() for every element and that traverses entire result again and again. This change remembers last computed result and returns that value if there were no further changes on the search result itself. See eclipse-platform#2279
1 parent d12eefb commit 67e6dfa

File tree

1 file changed

+19
-4
lines changed

1 file changed

+19
-4
lines changed

bundles/org.eclipse.search/newsearch/org/eclipse/search/ui/text/AbstractTextSearchResult.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.Set;
2626
import java.util.concurrent.ConcurrentHashMap;
2727
import java.util.concurrent.ConcurrentMap;
28+
import java.util.concurrent.atomic.AtomicInteger;
2829

2930
import org.eclipse.search.ui.ISearchResult;
3031
import org.eclipse.search.ui.ISearchResultListener;
@@ -44,6 +45,7 @@ public abstract class AbstractTextSearchResult implements ISearchResult {
4445
private final ConcurrentMap<Object, Set<Match>> fElementsToMatches;
4546
private final List<ISearchResultListener> fListeners;
4647
private final MatchEvent fMatchEvent;
48+
private final AtomicInteger matchCount;
4749

4850
private MatchFilter[] fMatchFilters;
4951

@@ -54,7 +56,7 @@ protected AbstractTextSearchResult() {
5456
fElementsToMatches= new ConcurrentHashMap<>();
5557
fListeners= new ArrayList<>();
5658
fMatchEvent= new MatchEvent(this);
57-
59+
matchCount = new AtomicInteger(0);
5860
fMatchFilters= null; // filtering disabled by default
5961
}
6062

@@ -156,6 +158,7 @@ private MatchEvent getSearchResultEvent(Collection<Match> matches, int eventKind
156158
}
157159

158160
private boolean didAddMatch(Match match) {
161+
matchCount.set(0);
159162
updateFilterState(match);
160163
return fElementsToMatches.computeIfAbsent(match.getElement(), k -> ConcurrentHashMap.newKeySet()).add(match);
161164
}
@@ -178,6 +181,7 @@ public void removeAll() {
178181
fireChange(new RemoveAllEvent(this));
179182
}
180183
private void doRemoveAll() {
184+
matchCount.set(0);
181185
fElementsToMatches.clear();
182186
}
183187

@@ -215,6 +219,7 @@ public void removeMatches(Match[] matches) {
215219

216220

217221
private boolean didRemoveMatch(Match match) {
222+
matchCount.set(0);
218223
boolean[] existed = new boolean[1];
219224
fElementsToMatches.computeIfPresent(match.getElement(), (f, matches) -> {
220225
existed[0] = matches.remove(match);
@@ -302,11 +307,21 @@ private boolean updateFilterState(Match match) {
302307
* @return total number of matches
303308
*/
304309
public int getMatchCount() {
305-
int count = 0;
310+
final int oldCount = matchCount.get();
311+
if (oldCount != 0) {
312+
return oldCount;
313+
}
314+
// The oldCount is zero here => we have to calculate again
315+
int newCount = 0;
306316
for (Set<Match> element : fElementsToMatches.values()) {
307-
count += element.size();
317+
newCount += element.size();
318+
}
319+
if (matchCount.compareAndSet(0, newCount)) {
320+
// Only return if not changed meanwhile
321+
return newCount;
308322
}
309-
return count;
323+
// Changed once again, fetch again latest value
324+
return getMatchCount();
310325
}
311326

312327
/**

0 commit comments

Comments
 (0)