Browse Source

Small performance optimization for ignore rules/fnmatcher

 - don't check empty segments generated by String.split()
 - don't continue to add segments if the matcher fails to match input
 - don't add empty heads
 - don't iterate over empty heads.

Bug: 440732
Change-Id: I7d04dccfe24d91275d17ba246662337d6dba66df
Signed-off-by: Andrey Loskutov <loskutov@gmx.de>
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
tags/v3.5.0.201409071800-rc1
Andrey Loskutov 9 years ago
parent
commit
3a161ac467

+ 13
- 3
org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/FileNameMatcher.java View File

@@ -307,7 +307,11 @@ public class FileNameMatcher {
return new WildCardHead(star);
}

private void extendStringToMatchByOneCharacter(final char c) {
/**
* @param c new character to append
* @return true to continue, false if the matcher can stop appending
*/
private boolean extendStringToMatchByOneCharacter(final char c) {
final List<Head> newHeads = listForLocalUseage;
newHeads.clear();
List<Head> lastAddedHeads = null;
@@ -320,12 +324,14 @@ public class FileNameMatcher {
// This is the case with the heads "a" and "*" of "a*b" which
// both can return the list ["*","b"]
if (headsToAdd != lastAddedHeads) {
newHeads.addAll(headsToAdd);
if (!headsToAdd.isEmpty())
newHeads.addAll(headsToAdd);
lastAddedHeads = headsToAdd;
}
}
listForLocalUseage = heads;
heads = newHeads;
return !newHeads.isEmpty();
}

private static int indexOfUnescaped(final String searchString,
@@ -349,7 +355,8 @@ public class FileNameMatcher {
public void append(final String stringToMatch) {
for (int i = 0; i < stringToMatch.length(); i++) {
final char c = stringToMatch.charAt(i);
extendStringToMatchByOneCharacter(c);
if (!extendStringToMatchByOneCharacter(c))
break;
}
}

@@ -378,6 +385,9 @@ public class FileNameMatcher {
* @return true, if the string currently being matched does match.
*/
public boolean isMatch() {
if (heads.isEmpty())
return false;

final ListIterator<Head> headIterator = heads
.listIterator(heads.size());
while (headIterator.hasPrevious()) {

+ 15
- 5
org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreRule.java View File

@@ -191,6 +191,9 @@ public class IgnoreRule {
final String[] segments = target.split("/"); //$NON-NLS-1$
for (int idx = 0; idx < segments.length; idx++) {
final String segmentName = segments[idx];
// String.split("/") creates empty segment for leading slash
if (segmentName.length() == 0)
continue;
if (segmentName.equals(pattern) &&
doesMatchDirectoryExpectations(isDirectory, idx, segments.length))
return true;
@@ -207,6 +210,9 @@ public class IgnoreRule {
if (nameOnly) {
for (int idx = 0; idx < segments.length; idx++) {
final String segmentName = segments[idx];
// String.split("/") creates empty segment for leading slash
if (segmentName.length() == 0)
continue;
//Iterate through each sub-directory
matcher.reset();
matcher.append(segmentName);
@@ -218,14 +224,18 @@ public class IgnoreRule {
//TODO: This is the slowest operation
//This matches e.g. "/src/ne?" to "/src/new/file.c"
matcher.reset();

for (int idx = 0; idx < segments.length; idx++) {
final String segmentName = segments[idx];
if (segmentName.length() > 0) {
matcher.append("/" + segmentName); //$NON-NLS-1$
}
// String.split("/") creates empty segment for leading slash
if (segmentName.length() == 0)
continue;

if (matcher.isMatch() &&
doesMatchDirectoryExpectations(isDirectory, idx, segments.length))
matcher.append("/" + segmentName); //$NON-NLS-1$

if (matcher.isMatch()
&& doesMatchDirectoryExpectations(isDirectory, idx,
segments.length))
return true;
}
}

Loading…
Cancel
Save