diff options
author | Nico Kruber <[email protected]> | 2013-01-25 16:12:41 +0100 |
---|---|---|
committer | Fredrik Gustafsson <[email protected]> | 2013-02-04 09:52:34 +0100 |
commit | 9239bca48cad7653b43f89f71c49b3d0be682c51 (patch) | |
tree | 6ae33e05457f01ffce635b548b100c1aeeb278f6 | |
parent | 8e5e2a11f069935644ff5404ffd8758773834f29 (diff) | |
download | otp-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.java | 43 | ||||
-rw-r--r-- | lib/jinterface/test/nc_SUITE.erl | 10 |
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()], |