Browse Source

Fix performance issue with StringBuffer.toString() on JDK 5.

PR: 37169

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@327675 13f79535-47bb-0310-9956-ffa450edef68
master
Stephane Bailliez 19 years ago
parent
commit
f358c00ade
3 changed files with 82 additions and 4 deletions
  1. +4
    -4
      src/main/org/apache/tools/ant/taskdefs/SQLExec.java
  2. +31
    -0
      src/main/org/apache/tools/ant/util/StringUtils.java
  3. +47
    -0
      src/testcases/org/apache/tools/ant/util/StringUtilsTest.java

+ 4
- 4
src/main/org/apache/tools/ant/taskdefs/SQLExec.java View File

@@ -20,6 +20,7 @@ package org.apache.tools.ant.taskdefs;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.util.StringUtils;
import org.apache.tools.ant.types.EnumeratedAttribute;
import org.apache.tools.ant.types.FileSet;

@@ -441,7 +442,7 @@ public class SQLExec extends JDBCTask {
protected void runStatements(Reader reader, PrintStream out)
throws SQLException, IOException {
StringBuffer sql = new StringBuffer();
String line = "";
String line;

BufferedReader in = new BufferedReader(reader);

@@ -481,7 +482,7 @@ public class SQLExec extends JDBCTask {
}
}
if ((delimiterType.equals(DelimiterType.NORMAL)
&& sql.toString().endsWith(delimiter))
&& StringUtils.endsWith(sql, delimiter))
||
(delimiterType.equals(DelimiterType.ROW)
&& line.equals(delimiter))) {
@@ -574,8 +575,7 @@ public class SQLExec extends JDBCTask {
* @throws SQLException on SQL problems.
*/
protected void printResults(PrintStream out) throws SQLException {
ResultSet rs = null;
rs = statement.getResultSet();
ResultSet rs = statement.getResultSet();
try {
printResults(rs, out);
} finally {


+ 31
- 0
src/main/org/apache/tools/ant/util/StringUtils.java View File

@@ -98,4 +98,35 @@ public final class StringUtils {
return sw.toString();
}

/**
* Checks that a string buffer ends up with a given string. It may sound trivial with the existing
* JDK API but the various implementation among JDKs can make those methods extremely resource intensive
* and perform poorly due to massive memory allocation and copying. See
* @param buffer the buffer to perform the check on
* @param suffix the suffix
* @return <code>true</code> if the character sequence represented by the
* argument is a suffix of the character sequence represented by
* the StringBuffer object; <code>false</code> otherwise. Note that the
* result will be <code>true</code> if the argument is the
* empty string.
*/
public static boolean endsWith(StringBuffer buffer, String suffix) {
if (suffix.length() > buffer.length()) {
return false;
}
// this loop is done on purpose to avoid memory allocation performance problems on various JDKs
// StringBuffer.lastIndexOf() was introduced in jdk 1.4 and implementation is ok though does allocation/copying
// StringBuffer.toString().endsWith() does massive memory allocation/copying on JDK 1.5
// See http://issues.apache.org/bugzilla/show_bug.cgi?id=37169
int endIndex = suffix.length() - 1;
int bufferIndex = buffer.length() - 1;
while ( endIndex >= 0 ) {
if ( buffer.charAt(bufferIndex) != suffix.charAt(endIndex) ) {
return false;
}
bufferIndex--;
endIndex--;
}
return true;
}
}

+ 47
- 0
src/testcases/org/apache/tools/ant/util/StringUtilsTest.java View File

@@ -55,4 +55,51 @@ public class StringUtilsTest extends TestCase {
assertEquals("bcbcbc", res);
}

public void testEndsWithBothEmpty() {
assertTrue( StringUtils.endsWith( new StringBuffer(), "") );
}

public void testEndsWithEmptyString() {
assertTrue( StringUtils.endsWith( new StringBuffer("12234545"), "") );
}

public void testEndsWithShorterString() {
assertTrue( StringUtils.endsWith( new StringBuffer("12345678"), "78"));
}

public void testEndsWithSameString() {
assertTrue( StringUtils.endsWith( new StringBuffer("123"), "123"));
}

public void testEndsWithLongerString() {
assertFalse( StringUtils.endsWith( new StringBuffer("12"), "1245"));
}

public void testEndsWithNoMatch() {
assertFalse( StringUtils.endsWith( new StringBuffer("12345678"), "789"));
}

public void testEndsWithEmptyBuffer() {
assertFalse( StringUtils.endsWith( new StringBuffer(""), "12345667") );
}

public void testEndsWithJDKPerf() {
StringBuffer buf = getFilledBuffer(1024*300, 'a');
for (int i = 0; i < 1000; i++) {
assertTrue(buf.toString().endsWith("aa"));
}
}

public void testEndsWithPerf() {
StringBuffer buf = getFilledBuffer(1024*300, 'a');
for (int i = 0; i < 1000; i++) {
assertTrue(StringUtils.endsWith(buf, "aa"));
}
}

private StringBuffer getFilledBuffer(int size, char ch) {
StringBuffer buf = new StringBuffer(size);
for (int i = 0; i < size; i++) { buf.append(ch); };
return buf;
}
}

Loading…
Cancel
Save