You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by bo...@apache.org on 2004/12/03 09:04:44 UTC
cvs commit: ant/src/main/org/apache/tools/ant DirectoryScanner.java
bodewig 2004/12/03 00:04:43
Modified: src/main/org/apache/tools/ant DirectoryScanner.java
Log:
Try to speed up DirectoryScanner by using hash lookups instead of
linear searches and pattern matching on non-wildcard patterns.
Suggested by: Dominique Devienne
Revision Changes Path
1.75 +123 -8 ant/src/main/org/apache/tools/ant/DirectoryScanner.java
Index: DirectoryScanner.java
===================================================================
RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/DirectoryScanner.java,v
retrieving revision 1.74
retrieving revision 1.75
diff -u -r1.74 -r1.75
--- DirectoryScanner.java 22 Nov 2004 09:23:26 -0000 1.74
+++ DirectoryScanner.java 3 Dec 2004 08:04:43 -0000 1.75
@@ -19,6 +19,7 @@
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
@@ -247,6 +248,66 @@
protected boolean everythingIncluded = true;
/**
+ * Set of all include patterns that are full file names and don't
+ * contain any wildcards.
+ *
+ * <p>If this instance is not case sensitive, the file names get
+ * turned to lower case.</p>
+ *
+ * <p>Gets lazily initialized on the first invocation of
+ * isIncluded or isExcluded and cleared at the end of the scan
+ * method (cleared in clearCaches, actually).</p>
+ *
+ * @since Ant 1.7
+ */
+ private Set includeNonPatterns = new HashSet();
+
+ /**
+ * Set of all include patterns that are full file names and don't
+ * contain any wildcards.
+ *
+ * <p>If this instance is not case sensitive, the file names get
+ * turned to lower case.</p>
+ *
+ * <p>Gets lazily initialized on the first invocation of
+ * isIncluded or isExcluded and cleared at the end of the scan
+ * method (cleared in clearCaches, actually).</p>
+ *
+ * @since Ant 1.7
+ */
+ private Set excludeNonPatterns = new HashSet();
+
+ /**
+ * Array of all include patterns that contain wildcards.
+ *
+ * <p>Gets lazily initialized on the first invocation of
+ * isIncluded or isExcluded and cleared at the end of the scan
+ * method (cleared in clearCaches, actually).</p>
+ *
+ * @since Ant 1.7
+ */
+ private String[] includePatterns;
+
+ /**
+ * Array of all exclude patterns that contain wildcards.
+ *
+ * <p>Gets lazily initialized on the first invocation of
+ * isIncluded or isExcluded and cleared at the end of the scan
+ * method (cleared in clearCaches, actually).</p>
+ *
+ * @since Ant 1.7
+ */
+ private String[] excludePatterns;
+
+ /**
+ * Have the non-pattern sets and pattern arrays for in- and
+ * excludes been initialized?
+ *
+ * @since Ant 1.7
+ */
+ private boolean areNonPatternSetsReady = false;
+
+ /**
* Sole constructor.
*/
public DirectoryScanner() {
@@ -699,7 +760,7 @@
}
}
- if ((myfile == null || !myfile.exists()) && !isCaseSensitive) {
+ if ((myfile == null || !myfile.exists()) && !isCaseSensitive()) {
File f = findFileCaseInsensitive(basedir, currentelement);
if (f.exists()) {
// adapt currentelement to the case we've
@@ -732,10 +793,10 @@
scandir(myfile, currentelement, true);
}
} else {
- if (isCaseSensitive
+ if (isCaseSensitive()
&& originalpattern.equals(currentelement)) {
accountForIncludedFile(currentelement, myfile);
- } else if (!isCaseSensitive
+ } else if (!isCaseSensitive()
&& originalpattern
.equalsIgnoreCase(currentelement)) {
accountForIncludedFile(currentelement, myfile);
@@ -950,8 +1011,21 @@
* include pattern, or <code>false</code> otherwise.
*/
protected boolean isIncluded(String name) {
- for (int i = 0; i < includes.length; i++) {
- if (matchPath(includes[i], name, isCaseSensitive)) {
+ if (!areNonPatternSetsReady) {
+ includePatterns = fillNonPatternSet(includeNonPatterns, includes);
+ excludePatterns = fillNonPatternSet(excludeNonPatterns, excludes);
+ areNonPatternSetsReady = true;
+ }
+
+ if ((isCaseSensitive() && includeNonPatterns.contains(name))
+ ||
+ (!isCaseSensitive()
+ && includeNonPatterns.contains(name.toUpperCase()))) {
+ return true;
+ }
+
+ for (int i = 0; i < includePatterns.length; i++) {
+ if (matchPath(includePatterns[i], name, isCaseSensitive())) {
return true;
}
}
@@ -968,7 +1042,7 @@
*/
protected boolean couldHoldIncluded(String name) {
for (int i = 0; i < includes.length; i++) {
- if (matchPatternStart(includes[i], name, isCaseSensitive)) {
+ if (matchPatternStart(includes[i], name, isCaseSensitive())) {
if (isMorePowerfulThanExcludes(name, includes[i])) {
return true;
}
@@ -1011,8 +1085,21 @@
* exclude pattern, or <code>false</code> otherwise.
*/
protected boolean isExcluded(String name) {
- for (int i = 0; i < excludes.length; i++) {
- if (matchPath(excludes[i], name, isCaseSensitive)) {
+ if (!areNonPatternSetsReady) {
+ includePatterns = fillNonPatternSet(includeNonPatterns, includes);
+ excludePatterns = fillNonPatternSet(excludeNonPatterns, excludes);
+ areNonPatternSetsReady = true;
+ }
+
+ if ((isCaseSensitive() && excludeNonPatterns.contains(name))
+ ||
+ (!isCaseSensitive()
+ && excludeNonPatterns.contains(name.toUpperCase()))) {
+ return true;
+ }
+
+ for (int i = 0; i < excludePatterns.length; i++) {
+ if (matchPath(excludePatterns[i], name, isCaseSensitive())) {
return true;
}
}
@@ -1414,5 +1501,33 @@
private void clearCaches() {
fileListMap.clear();
scannedDirs.clear();
+ includeNonPatterns.clear();
+ excludeNonPatterns.clear();
+ includePatterns = excludePatterns = null;
+ areNonPatternSetsReady = false;
}
+
+ /**
+ * Adds all patterns that are no real patterns (doesn't contain
+ * wildcards) to the set and returns the real patterns.
+ *
+ * @since Ant 1.7
+ */
+ private String[] fillNonPatternSet(Set set, String[] patterns) {
+ ArrayList al = new ArrayList(patterns.length);
+ for (int i = 0; i < patterns.length; i++) {
+ if (!SelectorUtils.hasWildcards(patterns[i])) {
+ if (isCaseSensitive()) {
+ set.add(patterns[i]);
+ } else {
+ set.add(patterns[i].toUpperCase());
+ }
+ } else {
+ al.add(patterns[i]);
+ }
+ }
+ return set.size() == 0 ? patterns
+ : (String[]) al.toArray(new String[al.size()]);
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org
Re: cvs commit: ant/src/main/org/apache/tools/ant
DirectoryScanner.java
Posted by Stefan Bodewig <bo...@apache.org>.
On Fri, 03 Dec 2004, Stefan Bodewig <bo...@apache.org> wrote:
> I'll watch the next Gump run closely, both for breaking builds as
> well as performance impact.
No obvious breaks.
The run took 179 minutes, the previous one 184, but I don't think it
is related to my change (but rather to CVS and SVN updates being
faster this time).
Stefan
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org
Re: cvs commit: ant/src/main/org/apache/tools/ant
DirectoryScanner.java
Posted by Stefan Bodewig <bo...@apache.org>.
On 3 Dec 2004, <bo...@apache.org> wrote:
> Try to speed up DirectoryScanner by using hash lookups instead of
> linear searches and pattern matching on non-wildcard patterns.
I threatened to do it. I'll watch the next Gump run closely, both for
breaking builds as well as performance impact. I don't think things
have gotten much worse in cases where all patterns contain wildcards,
but it really should improve things if no wildcards are there at all.
> - if ((myfile == null || !myfile.exists()) && !isCaseSensitive) {
> + if ((myfile == null || !myfile.exists()) && !isCaseSensitive()) {
I also changed these in a few places since isCaseSensitive() is
non-final and protected. If subclasses override this method, it
should have some effect IMHO.
> + * Set of all include patterns that are full file names and don't
> + * contain any wildcards.
> + *
> + * <p>Gets lazily initialized on the first invocation of
> + * isIncluded or isExcluded and cleared at the end of the scan
> + * method (cleared in clearCaches, actually).</p>
My first attempt initialized them in scan(), but that doesn't mix with
subclasses like ZipScanner that invoke isIncluded and isExcluded but
never invoke scan at all.
Stefan
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org