Skip to content

Commit 701154d

Browse files
committed
Deflate caching improvements
1 parent ba65304 commit 701154d

File tree

2 files changed

+46
-27
lines changed

2 files changed

+46
-27
lines changed

src/main/java/software/coley/llzip/format/compression/UnsafeDeflateDecompressor.java

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,68 +9,89 @@
99
import java.util.ArrayDeque;
1010
import java.util.Deque;
1111
import java.util.zip.DataFormatException;
12+
import java.util.zip.Inflater;
1213
import java.util.zip.ZipException;
1314

1415
/**
1516
* Optimized implementation of {@link DeflateDecompressor} with unsafe resetting for more throughput.
1617
*
1718
* @author xDark
1819
*/
20+
@SuppressWarnings("UnnecessaryLocalVariable")
1921
public class UnsafeDeflateDecompressor implements Decompressor {
20-
private static final Deque<UnsafeInflater> INFLATERS = new ArrayDeque<>();
22+
private static final int DEFLATE_CACHE_LIMIT = 64;
23+
private static final Deque<DeflateEntry> DEFLATE_ENTRIES = new ArrayDeque<>();
24+
private static final byte[] emptyBuf = new byte[0];
25+
26+
static {
27+
Deque<DeflateEntry> entries = DEFLATE_ENTRIES;
28+
for (int i = 0; i < DEFLATE_CACHE_LIMIT; i++) {
29+
entries.push(new DeflateEntry());
30+
}
31+
}
2132

2233
@Override
2334
public ByteData decompress(LocalFileHeader header, ByteData data) throws IOException {
2435
if (header.getCompressionMethod() != ZipCompressions.DEFLATED)
2536
throw new IOException("LocalFileHeader contents not using 'Deflated'!");
2637
FastWrapOutputStream out = new FastWrapOutputStream();
27-
UnsafeInflater inflater;
28-
Deque<UnsafeInflater> inflaters = INFLATERS;
38+
DeflateEntry entry;
39+
Deque<DeflateEntry> inflaters = DEFLATE_ENTRIES;
2940
synchronized (inflaters) {
30-
inflater = inflaters.poll();
31-
if (inflater == null) {
32-
inflater = new UnsafeInflater(true);
33-
}
41+
entry = inflaters.poll();
42+
}
43+
if (entry == null) {
44+
entry = new DeflateEntry();
45+
} else {
46+
// Normal 'Inflater' reset() is synchronized and bottlenecks us,
47+
// but we're using 'UnsafeInflater' which bypasses that.
48+
entry.inflater.reset();
3449
}
3550
try {
36-
byte[] output = new byte[1024];
37-
byte[] buffer = new byte[1024];
51+
byte[] output = entry.decompress;
52+
byte[] buffer = entry.buffer;
53+
Inflater inflater = entry.inflater;
3854
long position = 0L;
3955
long length = data.length();
56+
inflater.setInput(emptyBuf);
4057
do {
4158
if (inflater.needsInput()) {
4259
int remaining = (int) Math.min(buffer.length, length);
43-
if (remaining == 0) {
44-
break;
60+
if (remaining != 0) {
61+
data.get(position, buffer, 0, remaining);
62+
length -= remaining;
63+
position += remaining;
64+
inflater.setInput(buffer, 0, remaining);
4565
}
46-
data.get(position, buffer, 0, remaining);
47-
length -= remaining;
48-
position += remaining;
49-
inflater.setInput(buffer, 0, remaining);
5066
}
5167
int count = inflater.inflate(output);
5268
if (count != 0) {
5369
out.write(output, 0, count);
5470
}
55-
} while (!inflater.finished() && !inflater.needsDictionary());
71+
} while (!inflater.finished());
5672
} catch (DataFormatException e) {
57-
String s = e.getMessage();
58-
throw (ZipException) new ZipException(s != null ? null : "Invalid ZLIB data format").initCause(e);
73+
String msg = e.getMessage();
74+
throw (ZipException) new ZipException(msg != null ? null : "Invalid ZLIB data format").initCause(e);
5975
} finally {
6076
end:
6177
{
62-
if (inflaters.size() < 32) {
78+
if (inflaters.size() < DEFLATE_CACHE_LIMIT) {
6379
synchronized (inflaters) {
64-
if (inflaters.size() < 32) {
65-
inflater.fastReset();
66-
inflaters.push(inflater);
80+
if (inflaters.size() < DEFLATE_CACHE_LIMIT) {
81+
inflaters.addFirst(entry);
6782
break end;
6883
}
6984
}
7085
}
71-
inflater.end();
86+
entry.inflater.end();
7287
}
7388
}
7489
return out.wrap();
7590
}
91+
92+
private static final class DeflateEntry {
93+
final Inflater inflater = new UnsafeInflater(true);
94+
final byte[] decompress = new byte[1024];
95+
final byte[] buffer = new byte[8192];
96+
}
7697
}

src/main/java/software/coley/llzip/util/UnsafeInflater.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,8 @@ public UnsafeInflater(boolean nowrap) {
5454
super(nowrap);
5555
}
5656

57-
/**
58-
* {@link #reset()} but without synchronization.
59-
*/
60-
public void fastReset() {
57+
@Override
58+
public void reset() {
6159
try {
6260
Object zsRefValue = UNSAFE.getObject(this, off_zsRef);
6361
if (mh_address == null) {

0 commit comments

Comments
 (0)