From 3a161ac467d431313d92b02700ecb6118f3b5925 Mon Sep 17 00:00:00 2001 From: Andrey Loskutov Date: Wed, 30 Jul 2014 10:42:30 +0200 Subject: [PATCH] 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 Signed-off-by: Matthias Sohn --- .../eclipse/jgit/fnmatch/FileNameMatcher.java | 16 ++++++++++++--- .../org/eclipse/jgit/ignore/IgnoreRule.java | 20 ++++++++++++++----- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/FileNameMatcher.java b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/FileNameMatcher.java index 92a4837b2..f9c239431 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/FileNameMatcher.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/fnmatch/FileNameMatcher.java @@ -307,7 +307,11 @@ private static AbstractHead createWildCardHead( 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 newHeads = listForLocalUseage; newHeads.clear(); List lastAddedHeads = null; @@ -320,12 +324,14 @@ private void extendStringToMatchByOneCharacter(final char c) { // 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 @@ private static int indexOfUnescaped(final String searchString, 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 FileNameMatcher createMatcherForSuffix() { * @return true, if the string currently being matched does match. */ public boolean isMatch() { + if (heads.isEmpty()) + return false; + final ListIterator headIterator = heads .listIterator(heads.size()); while (headIterator.hasPrevious()) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreRule.java b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreRule.java index fd095d76d..42bbd9e9b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreRule.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/ignore/IgnoreRule.java @@ -191,6 +191,9 @@ public boolean isMatch(String target, boolean isDirectory) { 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 boolean isMatch(String target, boolean isDirectory) { 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 boolean isMatch(String target, boolean isDirectory) { //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; } }