Bug 573161 - [performance] avoid chunked File write
ByteArrayInputStream:transferTo avoids split into 8192 chunks
Change-Id: Ia0759fd6a1028d58673dcbd191a3d48c858bc84c
Signed-off-by: Joerg Kubitz <jkubitz-eclipse@gmx.de>
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.resources/+/179819
Tested-by: Platform Bot <platform-bot@eclipse.org>
Reviewed-by: Andrey Loskutov <loskutov@gmx.de>
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/FileUtil.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/FileUtil.java
index 9b3d44b..fbfa0fc 100644
--- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/FileUtil.java
+++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/utils/FileUtil.java
@@ -392,30 +392,37 @@
return null;
}
- public static final void transferStreams(InputStream source, OutputStream destination, String path, IProgressMonitor monitor) throws CoreException {
+ public static final void transferStreams(InputStream source, OutputStream destination, String path,
+ IProgressMonitor monitor) throws CoreException {
SubMonitor subMonitor = SubMonitor.convert(monitor);
try {
- byte[] buffer = new byte[8192];
- while (true) {
- int bytesRead = -1;
- try {
- bytesRead = source.read(buffer);
- } catch (IOException e) {
- String msg = NLS.bind(Messages.localstore_failedReadDuringWrite, path);
- throw new ResourceException(IResourceStatus.FAILED_READ_LOCAL, new Path(path), msg, e);
- }
- try {
- if (bytesRead == -1) {
- // Bug 332543 - ensure we don't ignore failures on close()
- destination.close();
- break;
+ try {
+ if (source instanceof ByteArrayInputStream) {
+ // ByteArrayInputStream does overload transferTo avoiding buffering
+ ((ByteArrayInputStream) source).transferTo(destination);
+ subMonitor.split(1);
+ } else {
+ byte[] buffer = new byte[8192];
+ while (true) {
+ int bytesRead = -1;
+ try {
+ bytesRead = source.read(buffer);
+ } catch (IOException e) {
+ String msg = NLS.bind(Messages.localstore_failedReadDuringWrite, path);
+ throw new ResourceException(IResourceStatus.FAILED_READ_LOCAL, new Path(path), msg, e);
+ }
+ if (bytesRead == -1) {
+ break;
+ }
+ destination.write(buffer, 0, bytesRead);
+ subMonitor.split(1);
}
- destination.write(buffer, 0, bytesRead);
- } catch (IOException e) {
- String msg = NLS.bind(Messages.localstore_couldNotWrite, path);
- throw new ResourceException(IResourceStatus.FAILED_WRITE_LOCAL, new Path(path), msg, e);
}
- subMonitor.split(1);
+ // Bug 332543 - ensure we don't ignore failures on close()
+ destination.close();
+ } catch (IOException e) {
+ String msg = NLS.bind(Messages.localstore_couldNotWrite, path);
+ throw new ResourceException(IResourceStatus.FAILED_WRITE_LOCAL, new Path(path), msg, e);
}
} finally {
safeClose(source);
diff --git a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/Bug_332543.java b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/Bug_332543.java
index cb0eaff..6615c65 100644
--- a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/Bug_332543.java
+++ b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/Bug_332543.java
@@ -15,6 +15,7 @@
import java.io.*;
import java.net.URI;
+import java.util.function.Function;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.resources.*;
@@ -24,12 +25,13 @@
import org.eclipse.core.tests.resources.ResourceTest;
/**
- * This tests that I/O Exception on OuptuStream#close() after IFile#setContents is correctly reported.
+ * This tests that I/O Exception on OuptuStream#close() after IFile#setContents
+ * is correctly reported.
*/
public class Bug_332543 extends ResourceTest {
/**
- * Wrapper FS which throws an IOException when someone
- * closes an output stream...
+ * Wrapper FS which throws an IOException when someone closes an output
+ * stream...
*/
public static class IOErrOnCloseFileStore extends WrapperFileStore {
public IOErrOnCloseFileStore(IFileStore store) {
@@ -42,7 +44,8 @@
os = new BufferedOutputStream(os) {
@Override
public void close() throws java.io.IOException {
- // We close the output stream (so there aren't issues deleting the project during tear-down)
+ // We close the output stream (so there aren't issues deleting the project
+ // during tear-down)
super.close();
// But we also throw IOException as if the operation had failed.
throw new IOException("Whoops I dunno how to close!");
@@ -58,7 +61,26 @@
super.tearDown();
}
- public void testBug() throws Exception {
+ public void testBugForByteArrayInputStream() throws Exception {
+ testCancel(s -> s);
+ }
+
+ public void testBugForInputStream() throws Exception {
+ testCancel(delegate -> new InputStream() { // Not ArrayInputStream
+ @Override
+ public int read() throws IOException {
+ return delegate.read();
+ }
+
+ @Override
+ public int read(byte b[], int off, int len) throws IOException {
+ return delegate.read(b, off, len);
+ }
+
+ });
+ }
+
+ private void testCancel(Function<ByteArrayInputStream, InputStream> wrap) throws CoreException {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
String proj_name = getUniqueString();
@@ -83,7 +105,7 @@
// Try #setContents on an existing file
try {
- f.setContents(new ByteArrayInputStream("Random".getBytes()), false, true, getMonitor());
+ f.setContents(wrap.apply(new ByteArrayInputStream("Random".getBytes())), false, true, getMonitor());
fail("1.0");
} catch (CoreException e) {
// This is expected.
@@ -92,10 +114,11 @@
// Try create on a non-existent file
f = project.getFile("foo1.txt");
try {
- f.create(new ByteArrayInputStream("Random".getBytes()), false, getMonitor());
+ f.create(wrap.apply(new ByteArrayInputStream("Random".getBytes())), false, getMonitor());
fail("2.0");
} catch (CoreException e) {
// This is expected.
}
}
+
}