aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNico Kruber <[email protected]>2013-01-25 16:12:41 +0100
committerFredrik Gustafsson <[email protected]>2013-02-04 09:52:34 +0100
commit9239bca48cad7653b43f89f71c49b3d0be682c51 (patch)
tree6ae33e05457f01ffce635b548b100c1aeeb278f6
parent8e5e2a11f069935644ff5404ffd8758773834f29 (diff)
downloadotp-9239bca48cad7653b43f89f71c49b3d0be682c51.tar.gz
otp-9239bca48cad7653b43f89f71c49b3d0be682c51.tar.bz2
otp-9239bca48cad7653b43f89f71c49b3d0be682c51.zip
jinterface: don't return compressed external term if bigger than uncompressed
Now, OtpOutputStream#write_compressed() uses the same mechanism as erts_term_to_binary() in external.c: it tries to compress the given term into a buffer of the size of the uncompressed term and if this is not possible, i.e. the compression plus headers is bigger, it uses the uncompressed external term format instead.
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java43
-rw-r--r--lib/jinterface/test/nc_SUITE.erl10
2 files changed, 46 insertions, 7 deletions
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java
index 8c3f48968e..541df20369 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpOutputStream.java
@@ -48,6 +48,8 @@ public class OtpOutputStream extends ByteArrayOutputStream {
private static final BigDecimal ten = new BigDecimal(10.0);
private static final BigDecimal one = new BigDecimal(1.0);
+ private boolean fixedSize = false;
+
/**
* Create a stream with the default initial size (2048 bytes).
*/
@@ -101,10 +103,16 @@ public class OtpOutputStream extends ByteArrayOutputStream {
* the storage of an <tt>OtpOutputStream</tt> instance.
*/
public void trimToSize() {
- if (super.count < super.buf.length) {
- final byte[] tmp = new byte[super.count];
- System.arraycopy(super.buf, 0, tmp, 0, super.count);
+ resize(super.count);
+ }
+
+ private void resize(int size) {
+ if (size < super.buf.length) {
+ final byte[] tmp = new byte[size];
+ System.arraycopy(super.buf, 0, tmp, 0, size);
super.buf = tmp;
+ } else if (size > super.buf.length) {
+ ensureCapacity(size);
}
}
@@ -118,6 +126,9 @@ public class OtpOutputStream extends ByteArrayOutputStream {
public void ensureCapacity(int minCapacity) {
int oldCapacity = super.buf.length;
if (minCapacity > oldCapacity) {
+ if (fixedSize) {
+ throw new IllegalArgumentException("Trying to increase fixed-size buffer");
+ }
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity < oldCapacity + defaultIncrement)
newCapacity = oldCapacity + defaultIncrement;
@@ -796,6 +807,7 @@ public class OtpOutputStream extends ByteArrayOutputStream {
* compress if the original term is smaller.
*/
if (oos.size() < 5) {
+ // fast path for small terms
try {
oos.writeTo(this);
// if the term is written as a compressed term, the output
@@ -806,16 +818,37 @@ public class OtpOutputStream extends ByteArrayOutputStream {
"Intermediate stream failed for Erlang object " + o);
}
} else {
- write1(OtpExternal.compressedTag);
- write4BE(oos.size());
+ int startCount = super.count;
+ // we need destCount bytes for an uncompressed term
+ // -> if compression uses more, use the uncompressed term!
+ int destCount = startCount + oos.size();
+ this.resize(destCount);
+ this.fixedSize = true;
final java.util.zip.DeflaterOutputStream dos = new java.util.zip.DeflaterOutputStream(
this);
try {
+ write1(OtpExternal.compressedTag);
+ write4BE(oos.size());
oos.writeTo(dos);
dos.close(); // note: closes this, too!
+ } catch (final IllegalArgumentException e) {
+ // could not make the value smaller than originally
+ // -> reset to starting count, write uncompressed
+ super.count = startCount;
+ try {
+ oos.writeTo(this);
+ // if the term is written as a compressed term, the output
+ // stream is closed, so we do this here, too
+ this.close();
+ } catch (IOException e2) {
+ throw new java.lang.IllegalArgumentException(
+ "Intermediate stream failed for Erlang object " + o);
+ }
} catch (final IOException e) {
throw new java.lang.IllegalArgumentException(
"Intermediate stream failed for Erlang object " + o);
+ } finally {
+ this.fixedSize = false;
}
}
}
diff --git a/lib/jinterface/test/nc_SUITE.erl b/lib/jinterface/test/nc_SUITE.erl
index 9c88400c2a..ba96ecf8a6 100644
--- a/lib/jinterface/test/nc_SUITE.erl
+++ b/lib/jinterface/test/nc_SUITE.erl
@@ -188,7 +188,10 @@ decompress_roundtrip(doc) -> [];
decompress_roundtrip(suite) -> [];
decompress_roundtrip(Config) when is_list(Config) ->
Terms =
- [0.0,
+ [{},
+ {a,b,c},
+ [],
+ 0.0,
math:sqrt(2),
<<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,31:5>>,
make_ref()],
@@ -206,7 +209,10 @@ compress_roundtrip(doc) -> [];
compress_roundtrip(suite) -> [];
compress_roundtrip(Config) when is_list(Config) ->
Terms =
- [0.0,
+ [{},
+ {a,b,c},
+ [],
+ 0.0,
math:sqrt(2),
<<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,31:5>>,
make_ref()],