aboutsummaryrefslogtreecommitdiffstats
path: root/lib/jinterface
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 /lib/jinterface
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.
Diffstat (limited to 'lib/jinterface')
-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()],