Skip to content

Commit 91373ca

Browse files
#255 implement decompression from direct buffer to heap buffer
1 parent 820038c commit 91373ca

File tree

7 files changed

+162
-5
lines changed

7 files changed

+162
-5
lines changed

src/main/java/org/xerial/snappy/Snappy.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -535,17 +535,19 @@ public static int uncompress(ByteBuffer compressed, ByteBuffer uncompressed)
535535
if (!compressed.isDirect()) {
536536
throw new SnappyError(SnappyErrorCode.NOT_A_DIRECT_BUFFER, "input is not a direct buffer");
537537
}
538-
if (!uncompressed.isDirect()) {
539-
throw new SnappyError(SnappyErrorCode.NOT_A_DIRECT_BUFFER, "destination is not a direct buffer");
540-
}
541538

542539
int cPos = compressed.position();
543540
int cLen = compressed.remaining();
544541

545542
// pos limit
546543
// [ ......UUUUUU.........]
547-
int decompressedSize = impl.rawUncompress(compressed, cPos, cLen, uncompressed,
548-
uncompressed.position());
544+
final int decompressedSize;
545+
if (uncompressed.isDirect()) {
546+
decompressedSize = impl.rawUncompress(compressed, cPos, cLen, uncompressed, uncompressed.position());
547+
} else {
548+
decompressedSize = impl.rawUncompressDirectToHeap(compressed, cPos, cLen,
549+
uncompressed.array(), uncompressed.position());
550+
}
549551
uncompressed.limit(uncompressed.position() + decompressedSize);
550552

551553
return decompressedSize;

src/main/java/org/xerial/snappy/SnappyNative.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,3 +297,35 @@ JNIEXPORT void JNICALL Java_org_xerial_snappy_SnappyNative_arrayCopy
297297
env->ReleasePrimitiveArrayCritical((jarray) output, dest, 0);
298298
}
299299

300+
/*
301+
* Class: org_xerial_snappy_SnappyNative
302+
* Method: rawUncompressDirectToHeap
303+
* Signature: (Ljava/nio/ByteBuffer;IILjava/lang/Object;I)I
304+
*/
305+
JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawUncompressDirectToHeap
306+
(JNIEnv* env, jobject self, jobject compressedBuffer, jint inputPos, jint inputLength,
307+
jobject uncompressedArray, jint outputOffset)
308+
{
309+
char* in = (char*) env->GetDirectBufferAddress(compressedBuffer);
310+
if (in == 0) {
311+
throw_exception(env, self, 3);
312+
return (jint) 0;
313+
}
314+
char* out = (char*) env->GetPrimitiveArrayCritical((jarray) uncompressedArray, 0);
315+
if (out == 0) {
316+
// out of memory
317+
throw_exception(env, self, 4);
318+
return (jint) 0;
319+
}
320+
size_t decompressedLength;
321+
snappy::GetUncompressedLength(in + inputPos, (size_t) inputLength, &decompressedLength);
322+
bool ret = snappy::RawUncompress(in + inputPos, (size_t) inputLength, out + outputOffset);
323+
env->ReleasePrimitiveArrayCritical((jarray) uncompressedArray, out, 0);
324+
if(!ret) {
325+
// failed to decompress
326+
throw_exception(env, self, 5);
327+
return (jint) 0;
328+
}
329+
return (jint) decompressedLength;
330+
}
331+

src/main/java/org/xerial/snappy/SnappyNative.h

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/java/org/xerial/snappy/SnappyNative.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ public native int rawUncompress(ByteBuffer compressed, int inputOffset, int inpu
6363
int outputOffset)
6464
throws IOException;
6565

66+
public native int rawUncompressDirectToHeap(ByteBuffer compressed, int inputOffset, int inputLength,
67+
Object uncompressed, int outputOffset)
68+
throws IOException;
69+
6670
public native int rawUncompress(Object input, int inputOffset, int inputLength, Object output, int outputOffset)
6771
throws IOException;
6872

Binary file not shown.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package org.xerial.snappy;
2+
3+
import org.junit.Test;
4+
import org.junit.runner.RunWith;
5+
import org.junit.runners.Parameterized;
6+
7+
import java.io.IOException;
8+
import java.nio.ByteBuffer;
9+
import java.util.ArrayList;
10+
import java.util.List;
11+
import java.util.concurrent.ThreadLocalRandom;
12+
13+
import static org.junit.Assert.assertArrayEquals;
14+
15+
@RunWith(Parameterized.class)
16+
public class SnappyGenerativeTest {
17+
18+
@Parameterized.Parameters
19+
public static Iterable<Object[]> data() {
20+
List<Object[]> testCases = new ArrayList<>(100);
21+
for (int i = 0 ; i < testCases.size(); ++i) {
22+
testCases.add(randomData());
23+
}
24+
return testCases;
25+
}
26+
27+
28+
private final byte[] input;
29+
30+
public SnappyGenerativeTest(byte[] input) {
31+
this.input = input;
32+
}
33+
34+
@Test
35+
public void roundTripDirectToDirect() throws IOException {
36+
ByteBuffer in = ByteBuffer.allocateDirect(input.length);
37+
in.put(input);
38+
ByteBuffer compressed = ByteBuffer.allocateDirect(input.length * 2);
39+
Snappy.compress(in, compressed);
40+
Snappy.uncompress(compressed, in);
41+
byte[] result = new byte[input.length];
42+
in.flip();
43+
in.get(result);
44+
assertArrayEquals(input, result);
45+
}
46+
47+
@Test
48+
public void roundTripDirectToHeap() throws IOException {
49+
ByteBuffer in = ByteBuffer.allocateDirect(input.length);
50+
in.put(input);
51+
in.flip();
52+
ByteBuffer compressed = ByteBuffer.allocateDirect(input.length * 2);
53+
Snappy.compress(in, compressed);
54+
ByteBuffer out = ByteBuffer.allocate(input.length);
55+
Snappy.uncompress(compressed, out);
56+
out.flip();
57+
assertArrayEquals(input, out.array());
58+
}
59+
60+
private static Object[] randomData() {
61+
int length = Math.abs(ThreadLocalRandom.current().nextInt(10,10_000));
62+
byte[] data = new byte[length];
63+
ThreadLocalRandom.current().nextBytes(data);
64+
return new Object[] {data};
65+
}
66+
}

src/test/java/org/xerial/snappy/SnappyTest.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,51 @@ public void directBuffer()
113113
assertEquals(origStr, decompressed);
114114
}
115115

116+
117+
@Test
118+
public void directBufferToHeapBuffer() throws Exception
119+
{
120+
121+
StringBuilder s = new StringBuilder();
122+
for (int i = 0; i < 20; ++i) {
123+
s.append("Hello world!");
124+
}
125+
String origStr = s.toString();
126+
byte[] orig = origStr.getBytes();
127+
ByteBuffer src = ByteBuffer.allocateDirect(orig.length);
128+
src.put(orig);
129+
src.flip();
130+
_logger.debug("input size: " + src.remaining());
131+
int maxCompressedLen = Snappy.maxCompressedLength(src.remaining());
132+
_logger.debug("max compressed length:" + maxCompressedLen);
133+
134+
ByteBuffer compressed = ByteBuffer.allocateDirect(maxCompressedLen);
135+
int compressedSize = Snappy.compress(src, compressed);
136+
_logger.debug("compressed length: " + compressedSize);
137+
138+
assertEquals(0, src.position());
139+
assertEquals(orig.length, src.remaining());
140+
assertEquals(orig.length, src.limit());
141+
142+
assertEquals(0, compressed.position());
143+
assertEquals(compressedSize, compressed.limit());
144+
assertEquals(compressedSize, compressed.remaining());
145+
146+
int uncompressedLen = Snappy.uncompressedLength(compressed);
147+
_logger.debug("uncompressed length: " + uncompressedLen);
148+
ByteBuffer extract = ByteBuffer.allocate(uncompressedLen);
149+
int uncompressedLen2 = Snappy.uncompress(compressed, extract);
150+
assertEquals(uncompressedLen, uncompressedLen2);
151+
assertEquals(uncompressedLen, extract.remaining());
152+
153+
byte[] b = new byte[uncompressedLen];
154+
extract.get(b);
155+
String decompressed = new String(b);
156+
_logger.debug(decompressed);
157+
158+
assertEquals(origStr, decompressed);
159+
}
160+
116161
@Test
117162
public void bufferOffset()
118163
throws Exception

0 commit comments

Comments
 (0)