Skip to content

Commit a43889d

Browse files
EcljpseB0Tjukzi
authored andcommitted
[performance] QuickTextSearcher avoid streaming
For small files read and decode the whole file content at once. * Avoid exceptions. Quick Search (crtl alt shift L) the whole platform workspace (any String that can not be found): 4s -> 2sec
1 parent e9f49ae commit a43889d

File tree

2 files changed

+52
-20
lines changed

2 files changed

+52
-20
lines changed

bundles/org.eclipse.text.quicksearch/src/org/eclipse/text/quicksearch/internal/core/QuickTextSearcher.java

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
package org.eclipse.text.quicksearch.internal.core;
1414

1515
import java.io.InputStreamReader;
16+
import java.io.Reader;
17+
import java.io.StringReader;
18+
import java.io.UnsupportedEncodingException;
1619
import java.util.Iterator;
1720
import java.util.Set;
1821
import java.util.concurrent.ConcurrentHashMap;
@@ -23,6 +26,7 @@
2326

2427
import org.eclipse.core.resources.IFile;
2528
import org.eclipse.core.resources.IResource;
29+
import org.eclipse.core.runtime.CoreException;
2630
import org.eclipse.core.runtime.IProgressMonitor;
2731
import org.eclipse.core.runtime.IStatus;
2832
import org.eclipse.core.runtime.Status;
@@ -36,6 +40,7 @@
3640
import org.eclipse.text.quicksearch.internal.util.LineReader;
3741

3842
public class QuickTextSearcher {
43+
private static int MAX_BUFFER_LENGTH = 999_999; // read max 1MB bytes => max 2MB chars.
3944
private final QuickTextSearchRequestor requestor;
4045
private QuickTextQuery query;
4146

@@ -155,7 +160,7 @@ private static boolean search(IFile f, BooleanSupplier canceled,
155160
if (canceled.getAsBoolean()) {
156161
return false;
157162
}
158-
try (LineReader lr = new LineReader(new InputStreamReader(f.getContents(true), f.getCharset()),
163+
try (LineReader lr = new LineReader(getReader(f),
159164
maxLineLength)) {
160165
String line;
161166
int lineIndex = 1;
@@ -179,6 +184,15 @@ private static boolean search(IFile f, BooleanSupplier canceled,
179184
return true;
180185
}
181186

187+
private static Reader getReader(IFile f) throws UnsupportedEncodingException, CoreException {
188+
String shortString = toShortString(f);
189+
if (shortString != null) {
190+
return new StringReader(shortString);
191+
} else {
192+
return new InputStreamReader(f.getContents(true), f.getCharset());
193+
}
194+
}
195+
182196
@Override
183197
public void resume() {
184198
//Only resume if we don't already exceed the maxResult limit.
@@ -188,7 +202,26 @@ public void resume() {
188202
}
189203

190204
}
191-
205+
/**
206+
* Try to get a content as String. Avoids Streaming.
207+
*/
208+
private static String toShortString(IFile file) {
209+
/**
210+
* Just any number such that the most source files will fit in. And not too
211+
* big to avoid out of memory.
212+
**/
213+
try {
214+
byte[] content = file.readNBytes(MAX_BUFFER_LENGTH);
215+
int length = content.length;
216+
if (length >= MAX_BUFFER_LENGTH) {
217+
return null;
218+
}
219+
String charset = file.getCharset();
220+
return new String(content, charset);
221+
} catch (Exception e) {
222+
return null;
223+
}
224+
}
192225
/**
193226
* This job updates already found matches when the query is changed.
194227
* Both the walker job and this job share the same scheduling rule so

bundles/org.eclipse.text.quicksearch/src/org/eclipse/text/quicksearch/internal/util/LineReader.java

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import java.io.BufferedReader;
1616
import java.io.IOException;
1717
import java.io.Reader;
18+
import java.io.StringReader;
1819

1920
/**
2021
* Provides a helper to efficiently split a file into
@@ -30,7 +31,7 @@ public class LineReader implements AutoCloseable{
3031
private static final int EXPECTED_LINE_LENGTH = 160;
3132
public static final int DEFAULT_MAX_LINE_LENGTH = 1000;
3233

33-
private BufferedReader input;
34+
private Reader input;
3435

3536
//This simple implementation just wraps a BufferedReader and StringBuilder
3637
//to do the buffering and String building.
@@ -43,21 +44,23 @@ public LineReader(Reader reader) {
4344

4445
public LineReader(Reader reader, int maxLineLength) {
4546
input = buffered(reader);
46-
MAX_LINE_LENGTH = maxLineLength;
47+
this.maxLineLength = maxLineLength;
4748
}
4849

4950

5051
private StringBuilder line = new StringBuilder(EXPECTED_LINE_LENGTH);
5152

52-
private final int MAX_LINE_LENGTH;
53+
private final int maxLineLength;
5354
private int lineOffset = -1; //Start pos of last line read.
5455
private int offset = 0; //position of next char in input.
5556
private int mark = 0; //mark offset in underlying stream
5657

57-
private BufferedReader buffered(Reader reader) {
58+
private Reader buffered(Reader reader) {
5859
//If already buffered don't wrap it again.
59-
if (reader instanceof BufferedReader) {
60-
return (BufferedReader) reader;
60+
if (reader instanceof StringReader sr) {
61+
return sr;
62+
} else if (reader instanceof BufferedReader br) {
63+
return br;
6164
} else {
6265
return new BufferedReader(reader);
6366
}
@@ -68,24 +71,19 @@ private BufferedReader buffered(Reader reader) {
6871
*/
6972
@Override
7073
public void close() {
71-
BufferedReader toClose = null;
72-
synchronized (input) {
73-
if (input==null) {
74-
return;
75-
}
76-
toClose = input;
74+
Reader toClose = input;
75+
try (toClose) {
7776
input = null;
78-
}
79-
try {
80-
toClose.close();
81-
} catch (IOException e) {
77+
} catch (IOException closeException) {
8278
//Ignore.
79+
} finally {
80+
input = null;
8381
}
8482
}
8583

8684
public String readLine() throws IOException {
8785
lineOffset = offset; //remember start of line
88-
int maxOffset = offset + MAX_LINE_LENGTH;
86+
int maxOffset = offset + maxLineLength;
8987
//Read text until we see either a CR, CR LF or LF.
9088
int c = read();
9189
if (c==-1) {
@@ -96,7 +94,8 @@ public String readLine() throws IOException {
9694
line.append((char)c);
9795
c = read();
9896
if (offset>maxOffset) {
99-
throw new IOException("Very long lines of text. Minified file?"); //$NON-NLS-1$
97+
// Very long lines of text. Minified file?
98+
return null;
10099
}
101100
}
102101
//Last char read was some kind of line terminator. But only read first char of it.

0 commit comments

Comments
 (0)