From dc93a924ee4d3b53f0271af577148f8a53eedb57 Mon Sep 17 00:00:00 2001 From: Vyom Tewari Date: Wed, 2 Dec 2015 21:32:40 +0100 Subject: [PATCH] 6856817: Poor performance of Writer#append with CharBuffer Poor performance of Writer#append with CharBuffer Reviewed-by: rriggs, dfuchs, sherman, shade --- .../classes/java/io/OutputStreamWriter.java | 23 +++ .../classes/sun/nio/cs/StreamEncoder.java | 20 ++- jdk/test/java/io/Writer/Bug6856817.java | 156 ++++++++++++++++++ 3 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 jdk/test/java/io/Writer/Bug6856817.java diff --git a/jdk/src/java.base/share/classes/java/io/OutputStreamWriter.java b/jdk/src/java.base/share/classes/java/io/OutputStreamWriter.java index 5533ff4bb53..0d597e6bef4 100644 --- a/jdk/src/java.base/share/classes/java/io/OutputStreamWriter.java +++ b/jdk/src/java.base/share/classes/java/io/OutputStreamWriter.java @@ -25,6 +25,7 @@ package java.io; +import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import sun.nio.cs.StreamEncoder; @@ -220,6 +221,28 @@ public class OutputStreamWriter extends Writer { se.write(str, off, len); } + @Override + public Writer append(CharSequence csq, int start, int end) throws IOException { + if (csq == null) { + write("null".subSequence(start, end).toString()); + return this; + } else { + return append(csq.subSequence(start, end)); + } + } + + @Override + public Writer append(CharSequence csq) throws IOException { + if (csq == null) { + se.write("null"); + } else if (csq instanceof CharBuffer) { + se.write((CharBuffer) csq); + } else { + se.write(csq.toString()); + } + return this; + } + /** * Flushes the stream. * diff --git a/jdk/src/java.base/share/classes/sun/nio/cs/StreamEncoder.java b/jdk/src/java.base/share/classes/sun/nio/cs/StreamEncoder.java index fd72238d89f..b41f93c038c 100644 --- a/jdk/src/java.base/share/classes/sun/nio/cs/StreamEncoder.java +++ b/jdk/src/java.base/share/classes/sun/nio/cs/StreamEncoder.java @@ -135,6 +135,18 @@ public class StreamEncoder extends Writer write(cbuf, 0, len); } + public void write(CharBuffer cb) throws IOException { + int position = cb.position(); + try { + synchronized (lock) { + ensureOpen(); + implWrite(cb); + } + } finally { + cb.position(position); + } + } + public void flush() throws IOException { synchronized (lock) { ensureOpen(); @@ -266,9 +278,15 @@ public class StreamEncoder extends Writer throws IOException { CharBuffer cb = CharBuffer.wrap(cbuf, off, len); + implWrite(cb); + } - if (haveLeftoverChar) + void implWrite(CharBuffer cb) + throws IOException + { + if (haveLeftoverChar) { flushLeftoverChar(cb, false); + } while (cb.hasRemaining()) { CoderResult cr = encoder.encode(cb, bb, false); diff --git a/jdk/test/java/io/Writer/Bug6856817.java b/jdk/test/java/io/Writer/Bug6856817.java new file mode 100644 index 00000000000..5f520902c93 --- /dev/null +++ b/jdk/test/java/io/Writer/Bug6856817.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6856817 + * @summary optimize the Writer.append(CharSequence) method + */ +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; + +/** + * + * @author vyom.tewari@oacle.com + */ +public class Bug6856817 { + + private static final String str = "This is just a test string that i am using it to test the CharBuffer.append(CharSequence csq) for little bit performance improvement."; + private static final int BUF_SIZE = 1024; + + /** + * + * @param args + */ + public static void main(String args[]) { + CharBuffer charBuffer = CharBuffer.allocate(BUF_SIZE); + File file = new File("temp.txt"); + file.deleteOnExit(); + + charBuffer.put(str); + charBuffer.flip(); + checkFileContent(charBuffer, file, str); + charBuffer.position(10); + checkFileContent(charBuffer, file, str.substring(10)); + charBuffer.position(charBuffer.limit()); + checkFileContent(charBuffer, file, str.substring(charBuffer.limit())); + + char arr[] = new char[BUF_SIZE]; + charBuffer = CharBuffer.wrap(arr); + charBuffer.put(str); + charBuffer.flip(); + checkFileContent(charBuffer, file, str); + charBuffer.position(10); + checkFileContent(charBuffer, file, str.substring(10)); + charBuffer.position(charBuffer.limit()); + checkFileContent(charBuffer, file, str.substring(charBuffer.limit())); + + char secArr[] = new char[BUF_SIZE]; + charBuffer = CharBuffer.wrap(secArr); + charBuffer.put(str); + charBuffer.position(5); + charBuffer.limit(str.length() - 7); + charBuffer = charBuffer.slice(); + checkFileContent(charBuffer, file, str.substring(5, (str.length() - 7))); + charBuffer.position(10); + checkFileContent(charBuffer, file, str.substring(15, (str.length() - 7))); + charBuffer.position(charBuffer.limit()); + checkFileContent(charBuffer, file, str.substring(charBuffer.limit())); + + charBuffer = ByteBuffer.allocate(BUF_SIZE).asCharBuffer(); + charBuffer.put(str); + charBuffer.flip(); + checkFileContent(charBuffer, file, str); + charBuffer.position(10); + checkFileContent(charBuffer, file, str.substring(10)); + charBuffer.position(charBuffer.limit()); + checkFileContent(charBuffer, file, str.substring(charBuffer.limit())); + + charBuffer = ByteBuffer.allocateDirect(1024).asCharBuffer(); + charBuffer.put(str); + charBuffer.flip(); + checkFileContent(charBuffer, file, str); + charBuffer.position(10); + checkFileContent(charBuffer, file, str.substring(10)); + charBuffer.position(charBuffer.limit()); + checkFileContent(charBuffer, file, str.substring(charBuffer.limit())); + } + + private static void checkFileContent(CharBuffer charBuffer, File file, String expectedValue) { + OutputStreamWriter writer = null; + FileReader reader = null; + int position, limit; + position = charBuffer.position(); + limit = charBuffer.limit(); + try { + OutputStream outputStream = new FileOutputStream(file); + writer = new OutputStreamWriter(outputStream); + writer.append(charBuffer); + writer.close(); + if (!isEqual(position, charBuffer.position())) { + System.out.println(": failed"); + throw new RuntimeException("buffer position before write: " + position + " and position after write: " + charBuffer.position()); + } + if (!isEqual(limit, charBuffer.limit())) { + System.out.println(": failed"); + throw new RuntimeException("buffer limit before write: " + limit + " and limit after write: " + charBuffer.limit()); + } + reader = new FileReader(file); + char arr[] = new char[BUF_SIZE]; + int byteRead = reader.read(arr); + if (byteRead != -1) { + String stringRead = new String(arr, 0, byteRead); + if (expectedValue.equals(stringRead)) { + System.out.println(": passed"); + } else { + System.out.println(": failed"); + throw new RuntimeException("expected :" + expectedValue + " and got:" + stringRead); + } + } + } catch (IOException ex) { + ex.printStackTrace(); + throw new RuntimeException(ex); + } finally { + try { + if (writer != null) { + writer.close(); + } + if (reader != null) { + reader.close(); + } + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + } + + private static boolean isEqual(final int first, final int second) { + return (first == second); + } +}