X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.db.server%2Fsrc%2Forg%2Fsimantics%2Fdb%2Fserver%2Finternal%2FClusterDecompressor.java;fp=bundles%2Forg.simantics.db.server%2Fsrc%2Forg%2Fsimantics%2Fdb%2Fserver%2Finternal%2FClusterDecompressor.java;h=1beaf2cda06b619bbd1fcaa8bbce49389e6099a1;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.db.server/src/org/simantics/db/server/internal/ClusterDecompressor.java b/bundles/org.simantics.db.server/src/org/simantics/db/server/internal/ClusterDecompressor.java new file mode 100644 index 000000000..1beaf2cda --- /dev/null +++ b/bundles/org.simantics.db.server/src/org/simantics/db/server/internal/ClusterDecompressor.java @@ -0,0 +1,157 @@ +package org.simantics.db.server.internal; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +import org.simantics.fastlz.FastLZ; +import org.simantics.fastlz.FastLZJava; + + +/** + * @author Tuukka Lehtonen + */ +public class ClusterDecompressor { + + private byte[] inflateBuffer; + + public Object[] inflateCluster(int inflateSize, ByteBuffer deflatedCluster) + throws CompressionException { + int deflatedSize = deflatedCluster.limit(); + Object[] arrays = new Object[3]; + int inflated = decompressCluster(deflatedCluster, deflatedSize, inflateSize, arrays); + if (inflated != inflateSize) + throw new CompressionException("decompression error, inflated " + + inflated + " bytes when " + inflateSize + " expected."); + return arrays; + } + + /** + * Wrapper for the old native direct byte buffer version of cluster + * decompression. + * + * @param deflated + * @param deflatedSize + * @param inflatedSize + * @param arrays + * expects an array of 3 elements. The decompression result will + * be stored in here. [0] = cluster long array (long[]), [1] = + * cluster int array (int[]), [2] = cluster byte array (byte[]). + * @return the amount of bytes inflated from the deflated cluster. Matches + * inflatedSize when successful. + * + * @see FastLZ#decompressCluster(ByteBuffer, int, int, Object[]) + */ + public int decompressCluster(ByteBuffer deflated, int deflatedSize, int inflatedSize, Object[] arrays) { + if (deflated.isDirect()) { + if (FastLZ.isNativeInitialized()) { + FastLZ.decompressCluster(deflated, deflatedSize, inflatedSize, arrays); + return inflatedSize; + } + // REALLY SLOW FALLBACK: java code for direct byte buffers + } + byte[] array = null; + if (deflated.hasArray()) { + array = deflated.array(); + } else { + // SLOW FALLBACK: read-only heap byte buffer + array = new byte[deflatedSize]; + int pos = deflated.position(); + deflated.position(0); + deflated.get(array, 0, deflatedSize); + deflated.position(pos); + } + return decompressCluster(array, deflatedSize, inflatedSize, arrays); + } + + /** + * @param deflated + * @param deflatedSize + * @param inflatedSize + * @param arrays + * @return + */ + public synchronized int decompressCluster(byte[] deflated, int deflatedSize, int inflatedSize, Object[] arrays) { + if (inflateBuffer == null) { + inflateBuffer = new byte[inflatedSize]; + } else if (inflateBuffer.length < inflatedSize) { + inflateBuffer = new byte[inflatedSize]; + } + return decompressCluster(deflated, deflatedSize, inflateBuffer, inflatedSize, arrays); + } + + /** + * @param deflated + * @param deflatedSize + * @param inflated + * @param inflatedSize + * @param arrays + * @return amount of bytes inflated from the original deflated buffer. + * Should match inflatedSize if everything went ok, otherwise will + * not. + */ + public static int decompressCluster(byte[] deflated, int deflatedSize, byte[] inflated, int inflatedSize, Object[] arrays) { + if (inflated.length < inflatedSize) + throw new IllegalArgumentException("inflate buffer size (" + inflated.length + ") is smaller than inflated size (" + inflatedSize + ")"); + + int decompressedBytes = FastLZJava.decompress(deflated, 0, deflatedSize, inflated, 0, inflatedSize); + if (decompressedBytes != inflatedSize) + return decompressedBytes; + + int offset = 0; + + int longCount = readInt(inflated, offset); + long[] longs = new long[longCount]; + copyLongs(inflated, offset + 4, longs); + offset += 4 + 8*longCount; + + int intCount = readInt(inflated, offset); + int[] ints = new int[intCount]; + copyInts(inflated, offset + 4, ints); + offset += 4 + 4*intCount; + + int byteCount = readInt(inflated, offset); + byte[] bytes = Arrays.copyOfRange(inflated, offset + 4, offset + 4 + byteCount); + + arrays[0] = longs; + arrays[1] = ints; + arrays[2] = bytes; + + return decompressedBytes; + } + + private static void copyInts(byte[] bytes, int i, int[] ints) { + int offset = i; + int count = ints.length; + for (int a = 0; a < count; ++a, offset += 4) { + int value = (((int) bytes[offset] & 0xff)) | + (((int) bytes[offset+1] & 0xff) << 8) | + (((int) bytes[offset+2] & 0xff) << 16) | + (((int) bytes[offset+3] & 0xff) << 24); + ints[a] = value; + } + } + + private static void copyLongs(byte[] bytes, int i, long[] longs) { + int offset = i; + int count = longs.length; + for (int a = 0; a < count; ++a, offset += 8) { + long value = (((long) bytes[offset] & 0xff)) | + (((long) bytes[offset+1] & 0xff) << 8) | + (((long) bytes[offset+2] & 0xff) << 16) | + (((long) bytes[offset+3] & 0xff) << 24) | + (((long) bytes[offset+4] & 0xff) << 32) | + (((long) bytes[offset+5] & 0xff) << 40) | + (((long) bytes[offset+6] & 0xff) << 48) | + (((long) bytes[offset+7] & 0xff) << 56); + longs[a] = value; + } + } + + private static int readInt(byte[] array, int offset) { + return (((int) array[offset] & 0xff)) | + (((int) array[offset+1] & 0xff) << 8) | + (((int) array[offset+2] & 0xff) << 16) | + (((int) array[offset+3] & 0xff) << 24); + } + +}