Skip to content

Commit 7ab95e3

Browse files
committed
InstalledFileLocatorImpl: avoid recompiling regex in hot code
clusterFor() is called often during startup and flamegraph showed that the regex pattern as bottleneck. -> implement the dynamic part of the regex by hand so that the constant part can be put in a static field.
1 parent 26a05a6 commit 7ab95e3

1 file changed

Lines changed: 66 additions & 50 deletions

File tree

platform/core.startup/src/org/netbeans/core/startup/InstalledFileLocatorImpl.java

Lines changed: 66 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import java.io.FileReader;
2727
import java.io.IOException;
2828
import java.io.InputStream;
29-
import java.io.Reader;
3029
import java.util.ArrayList;
3130
import java.util.Arrays;
3231
import java.util.Collections;
@@ -62,7 +61,7 @@ public final class InstalledFileLocatorImpl extends InstalledFileLocator {
6261
private final File[] dirs;
6362
public InstalledFileLocatorImpl() {
6463
List<File> _dirs = computeDirs();
65-
dirs = _dirs.toArray(new File[0]);
64+
dirs = _dirs.toArray(File[]::new);
6665
}
6766

6867
private static void addDir(List<File> _dirs, String d) {
@@ -99,41 +98,42 @@ private static void addDir(List<File> _dirs, String d) {
9998
*/
10099
public static synchronized void prepareCache() {
101100
assert fileCache == null;
102-
fileCache = new HashMap<String,Map<File,Set<String>>>();
103-
clusterCache = new HashMap<String,List<File>>();
101+
fileCache = new HashMap<>();
102+
clusterCache = new HashMap<>();
104103

105104
try {
106105
InputStream is = Stamps.getModulesJARs().asStream("all-files.dat");
107106
if (is == null) {
108107
return;
109108
}
110-
DataInputStream dis = new DataInputStream(is);
111-
int filesSize = dis.readInt();
112-
for (int i = 0; i < filesSize; i++) {
113-
String key = dis.readUTF();
114-
Map<File,Set<String>> fileToKids = new HashMap<File, Set<String>>();
115-
int filesToKids = dis.readInt();
116-
for (int j = 0; j < filesToKids; j++) {
117-
final String read = RelPaths.readRelativePath(dis);
118-
File f = new File(read);
119-
int kidsSize = dis.readInt();
120-
List<String> kids = new ArrayList<String>(kidsSize);
121-
for (int k = 0; k < kidsSize; k++) {
122-
kids.add(dis.readUTF());
109+
try (DataInputStream dis = new DataInputStream(is)) {
110+
int filesSize = dis.readInt();
111+
for (int i = 0; i < filesSize; i++) {
112+
String key = dis.readUTF();
113+
Map<File, Set<String>> fileToKids = new HashMap<>();
114+
int filesToKids = dis.readInt();
115+
for (int j = 0; j < filesToKids; j++) {
116+
final String read = RelPaths.readRelativePath(dis);
117+
File f = new File(read);
118+
int kidsSize = dis.readInt();
119+
List<String> kids = new ArrayList<>(kidsSize);
120+
for (int k = 0; k < kidsSize; k++) {
121+
kids.add(dis.readUTF());
122+
}
123+
fileToKids.put(f, new HashSet<>(kids));
123124
}
124-
fileToKids.put(f, new HashSet<String>(kids));
125+
fileCache.put(key, fileToKids);
125126
}
126-
fileCache.put(key, fileToKids);
127-
}
128-
int clusterSize = dis.readInt();
129-
for (int i = 0; i < clusterSize; i++) {
130-
String key = dis.readUTF();
131-
int valueSize = dis.readInt();
132-
List<File> values = new ArrayList<File>(valueSize);
133-
for (int j = 0; j < valueSize; j++) {
134-
values.add(new File(RelPaths.readRelativePath(dis)));
127+
int clusterSize = dis.readInt();
128+
for (int i = 0; i < clusterSize; i++) {
129+
String key = dis.readUTF();
130+
int valueSize = dis.readInt();
131+
List<File> values = new ArrayList<>(valueSize);
132+
for (int j = 0; j < valueSize; j++) {
133+
values.add(new File(RelPaths.readRelativePath(dis)));
134+
}
135+
clusterCache.put(key, values);
135136
}
136-
clusterCache.put(key, values);
137137
}
138138
} catch (IOException ex) {
139139
LOG.log(Level.INFO, null, ex);
@@ -242,7 +242,7 @@ private Set<File> doLocate(String relativePath, boolean localized, boolean singl
242242
} else if (files == null) {
243243
files = f;
244244
} else {
245-
files = new LinkedHashSet<File>(files);
245+
files = new LinkedHashSet<>(files);
246246
files.addAll(f);
247247
}
248248
}
@@ -267,11 +267,11 @@ private Set<File> locateExactPath(String prefix, String name, boolean single, St
267267
assert owned(codeNameBase, dir, path);
268268
File f = makeFile(dir, path);
269269
if (single) {
270-
return Collections.singleton(f);
270+
return Set.of(f);
271271
} else if (files == null) {
272-
files = Collections.singleton(f);
272+
files = Set.of(f);
273273
} else {
274-
files = new LinkedHashSet<File>(files);
274+
files = new LinkedHashSet<>(files);
275275
files.add(f);
276276
}
277277
}
@@ -282,11 +282,11 @@ private Set<File> locateExactPath(String prefix, String name, boolean single, St
282282
if (f.exists()) {
283283
assert owned(codeNameBase, dir, path);
284284
if (single) {
285-
return Collections.singleton(f);
285+
return Set.of(f);
286286
} else if (files == null) {
287-
files = Collections.singleton(f);
287+
files = Set.of(f);
288288
} else {
289-
files = new LinkedHashSet<File>(files);
289+
files = new LinkedHashSet<>(files);
290290
files.add(f);
291291
}
292292
}
@@ -301,14 +301,14 @@ private List<File> clustersFor(String codeNameBase, String path) {
301301
return Arrays.asList(dirs);
302302
}
303303
String codeNameBaseDashes = codeNameBase.replace('.', '-');
304-
if (path.matches("(modules/(locale/)?)?" + codeNameBaseDashes + "(_[^/]+)?[.]jar")) { // NOI18N
304+
if (isBaseInPath(codeNameBaseDashes, path)) {
305305
// Called very commonly during startup; cannot afford to do exact check each time.
306306
// Anyway if the module is there it is almost certainly installed in the same cluster.
307307
return Arrays.asList(dirs);
308308
}
309309
List<File> clusters = clusterCache != null ? clusterCache.get(codeNameBase) : null;
310310
if (clusters == null) {
311-
clusters = new ArrayList<File>(1);
311+
clusters = new ArrayList<>(1);
312312
String rel = "update_tracking/" + codeNameBaseDashes + ".xml"; // NOI18N
313313
for (File dir : dirs) {
314314
File tracking = new File(dir, rel);
@@ -331,8 +331,29 @@ private List<File> clustersFor(String codeNameBase, String path) {
331331
return clusters;
332332
}
333333

334+
private static final Pattern TAIL = Pattern.compile("(_[^/]+)?[.]jar"); // NOI18N
335+
336+
// hot section: avoids recompiling the pattern by unrolling the prefix manually
337+
private static boolean isBaseInPath(String codeNameBaseDashes, String path) {
338+
// return path.matches("(modules/(locale/)?)?" + codeNameBaseDashes + "(_[^/]+)?[.]jar");
339+
int pos = 0;
340+
if (path.startsWith("modules/")) { // NOI18N
341+
pos += "modules/".length(); // NOI18N
342+
if (path.startsWith("locale/", pos)) { // NOI18N
343+
pos += "locale/".length(); // NOI18N
344+
}
345+
}
346+
if (path.startsWith(codeNameBaseDashes, pos)) {
347+
pos += codeNameBaseDashes.length();
348+
if (TAIL.matcher(path.substring(pos)).matches()) {
349+
return true;
350+
}
351+
}
352+
return false;
353+
}
354+
334355
private static String[] prefixAndName(String relativePath) {
335-
if (relativePath.length() == 0) {
356+
if (relativePath.isEmpty()) {
336357
throw new IllegalArgumentException("Cannot look up \"\" in InstalledFileLocator.locate"); // NOI18N
337358
}
338359
if (relativePath.charAt(0) == '/') {
@@ -359,7 +380,7 @@ private Map<File,Set<String>> fileCachePerPrefix(String prefix) {
359380
assert Thread.holdsLock(InstalledFileLocatorImpl.class);
360381
Map<File,Set<String>> fileCachePerPrefix = fileCache.get(prefix);
361382
if (fileCachePerPrefix == null) {
362-
fileCachePerPrefix = new HashMap<File,Set<String>>(dirs.length * 2);
383+
fileCachePerPrefix = new HashMap<>(dirs.length * 2);
363384
for (int i = 0; i < dirs.length; i++) {
364385
File root = dirs[i];
365386
File d;
@@ -375,7 +396,7 @@ private Map<File,Set<String>> fileCachePerPrefix(String prefix) {
375396
if (isDir) {
376397
String[] kids = d.list();
377398
if (kids != null) {
378-
fileCachePerPrefix.put(root, new HashSet<String>(Arrays.asList(kids)));
399+
fileCachePerPrefix.put(root, new HashSet<>(Arrays.asList(kids)));
379400
} else {
380401
Util.err.log(Level.WARNING, "could not read files in {0} at {1}", new Object[] {d, findCaller()});
381402
}
@@ -419,7 +440,7 @@ private static synchronized boolean owned(String codeNameBase, File dir, String
419440
LOG.log(Level.FINE, "No update tracking found in {0}", dir);
420441
return true;
421442
}
422-
ownershipByModule = new HashMap<String,Set<String>>();
443+
ownershipByModule = new HashMap<>();
423444
ownershipByModuleByCluster.put(dir, ownershipByModule);
424445
}
425446
Set<String> ownership = ownershipByModule.get(codeNameBase);
@@ -429,25 +450,20 @@ private static synchronized boolean owned(String codeNameBase, File dir, String
429450
LOG.log(Level.WARNING, "no such module {0} at {1}", new Object[] {list, findCaller()});
430451
return true;
431452
}
432-
ownership = new HashSet<String>();
453+
ownership = new HashSet<>();
433454
try {
434455
// Could do a proper XML parse but likely too slow.
435456
if (LOG.isLoggable(Level.FINE)) {
436457
LOG.log(Level.FINE, "Parsing {0} due to {1}", new Object[] {list, path});
437458
}
438-
Reader r = new FileReader(list);
439-
try {
440-
BufferedReader br = new BufferedReader(r);
459+
try (BufferedReader br = new BufferedReader(new FileReader(list))) {
441460
String line;
442461
while ((line = br.readLine()) != null) {
443462
Matcher m = FILE_PATTERN.matcher(line);
444463
if (m.matches()) {
445464
ownership.add(m.group(1));
446465
}
447466
}
448-
br.close();
449-
} finally {
450-
r.close();
451467
}
452468
} catch (IOException x) {
453469
LOG.log(Level.INFO, "could not parse " + list, x);
@@ -476,7 +492,7 @@ private static synchronized boolean owned(String codeNameBase, File dir, String
476492
return true;
477493
}
478494
private static final Pattern FILE_PATTERN = Pattern.compile("\\s*<file.+name=[\"']([^\"']+)[\"'].*/>");
479-
private static final Map<File,Map<String,Set<String>>> ownershipByModuleByCluster = new HashMap<File,Map<String,Set<String>>>();
495+
private static final Map<File, Map<String, Set<String>>> ownershipByModuleByCluster = new HashMap<>();
480496

481497
private static String findCaller() {
482498
for (StackTraceElement line : Thread.currentThread().getStackTrace()) {
@@ -492,7 +508,7 @@ private static synchronized void scheduleSave() {
492508
}
493509

494510
static List<File> computeDirs() {
495-
List<File> _dirs = new ArrayList<File>();
511+
List<File> _dirs = new ArrayList<>();
496512
addDir(_dirs, System.getProperty("netbeans.user")); // NOI18N
497513
String nbdirs = System.getProperty("netbeans.dirs"); // #27151
498514
if (nbdirs != null) {

0 commit comments

Comments
 (0)