Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-17 05:20:14 +01:00
Replace old Java compressor with Java 11 compressor
Dieser Commit ist enthalten in:
Ursprung
bcff8a04bc
Commit
13a63eff76
@ -1,140 +0,0 @@
|
|||||||
package com.velocitypowered.natives.compression;
|
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
|
||||||
import static com.velocitypowered.natives.compression.CompressorUtils.ZLIB_BUFFER_SIZE;
|
|
||||||
import static com.velocitypowered.natives.compression.CompressorUtils.ensureMaxSize;
|
|
||||||
|
|
||||||
import com.velocitypowered.natives.util.BufferPreference;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.invoke.MethodType;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.zip.DataFormatException;
|
|
||||||
import java.util.zip.Deflater;
|
|
||||||
import java.util.zip.Inflater;
|
|
||||||
|
|
||||||
public class Java11VelocityCompressor implements VelocityCompressor {
|
|
||||||
|
|
||||||
public static final VelocityCompressorFactory FACTORY = Java11VelocityCompressor::new;
|
|
||||||
|
|
||||||
// The use of MethodHandle is intentional. Velocity targets Java 8, and these methods don't exist
|
|
||||||
// in Java 8. This was also the most performant solution I could find, only slightly slower than a
|
|
||||||
// direct method call without long warmup times, requiring bytecode generation through ASM, or
|
|
||||||
// other stuff.
|
|
||||||
private static final MethodHandle DEFLATE_SET_INPUT;
|
|
||||||
private static final MethodHandle INFLATE_SET_INPUT;
|
|
||||||
private static final MethodHandle DEFLATE_CALL;
|
|
||||||
private static final MethodHandle INFLATE_CALL;
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
DEFLATE_SET_INPUT = MethodHandles.lookup().findVirtual(Deflater.class, "setInput",
|
|
||||||
MethodType.methodType(void.class, ByteBuffer.class));
|
|
||||||
INFLATE_SET_INPUT = MethodHandles.lookup().findVirtual(Inflater.class, "setInput",
|
|
||||||
MethodType.methodType(void.class, ByteBuffer.class));
|
|
||||||
|
|
||||||
DEFLATE_CALL = MethodHandles.lookup().findVirtual(Deflater.class, "deflate",
|
|
||||||
MethodType.methodType(int.class, ByteBuffer.class));
|
|
||||||
INFLATE_CALL = MethodHandles.lookup().findVirtual(Inflater.class, "inflate",
|
|
||||||
MethodType.methodType(int.class, ByteBuffer.class));
|
|
||||||
} catch (NoSuchMethodException | IllegalAccessException e) {
|
|
||||||
throw new AssertionError("Can't use Java 11 compressor on your version of Java");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Deflater deflater;
|
|
||||||
private final Inflater inflater;
|
|
||||||
private boolean disposed = false;
|
|
||||||
|
|
||||||
private Java11VelocityCompressor(int level) {
|
|
||||||
this.deflater = new Deflater(level);
|
|
||||||
this.inflater = new Inflater();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void inflate(ByteBuf source, ByteBuf destination, int uncompressedSize)
|
|
||||||
throws DataFormatException {
|
|
||||||
ensureNotDisposed();
|
|
||||||
|
|
||||||
// We (probably) can't nicely deal with >=1 buffer nicely, so let's scream loudly.
|
|
||||||
checkArgument(source.nioBufferCount() == 1, "source has multiple backing buffers");
|
|
||||||
checkArgument(destination.nioBufferCount() == 1, "destination has multiple backing buffers");
|
|
||||||
|
|
||||||
try {
|
|
||||||
int origIdx = source.readerIndex();
|
|
||||||
INFLATE_SET_INPUT.invokeExact(inflater, source.nioBuffer());
|
|
||||||
|
|
||||||
while (!inflater.finished() && inflater.getBytesRead() < source.readableBytes()) {
|
|
||||||
if (!destination.isWritable()) {
|
|
||||||
ensureMaxSize(destination, uncompressedSize);
|
|
||||||
destination.ensureWritable(ZLIB_BUFFER_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer destNioBuf = destination.nioBuffer(destination.writerIndex(),
|
|
||||||
destination.writableBytes());
|
|
||||||
int produced = (int) INFLATE_CALL.invokeExact(inflater, destNioBuf);
|
|
||||||
source.readerIndex(origIdx + inflater.getTotalIn());
|
|
||||||
destination.writerIndex(destination.writerIndex() + produced);
|
|
||||||
}
|
|
||||||
|
|
||||||
inflater.reset();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
if (e instanceof DataFormatException) {
|
|
||||||
throw (DataFormatException) e;
|
|
||||||
}
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
|
|
||||||
ensureNotDisposed();
|
|
||||||
|
|
||||||
// We (probably) can't nicely deal with >=1 buffer nicely, so let's scream loudly.
|
|
||||||
checkArgument(source.nioBufferCount() == 1, "source has multiple backing buffers");
|
|
||||||
checkArgument(destination.nioBufferCount() == 1, "destination has multiple backing buffers");
|
|
||||||
|
|
||||||
try {
|
|
||||||
int origIdx = source.readerIndex();
|
|
||||||
DEFLATE_SET_INPUT.invokeExact(deflater, source.nioBuffer());
|
|
||||||
deflater.finish();
|
|
||||||
|
|
||||||
while (!deflater.finished()) {
|
|
||||||
if (!destination.isWritable()) {
|
|
||||||
destination.ensureWritable(ZLIB_BUFFER_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer destNioBuf = destination.nioBuffer(destination.writerIndex(),
|
|
||||||
destination.writableBytes());
|
|
||||||
int produced = (int) DEFLATE_CALL.invokeExact(deflater, destNioBuf);
|
|
||||||
source.readerIndex(origIdx + deflater.getTotalIn());
|
|
||||||
destination.writerIndex(destination.writerIndex() + produced);
|
|
||||||
}
|
|
||||||
|
|
||||||
deflater.reset();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
if (e instanceof DataFormatException) {
|
|
||||||
throw (DataFormatException) e;
|
|
||||||
}
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
disposed = true;
|
|
||||||
deflater.end();
|
|
||||||
inflater.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ensureNotDisposed() {
|
|
||||||
checkState(!disposed, "Object already disposed");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BufferPreference preferredBufferType() {
|
|
||||||
return BufferPreference.DIRECT_PREFERRED;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +1,13 @@
|
|||||||
package com.velocitypowered.natives.compression;
|
package com.velocitypowered.natives.compression;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
import static com.velocitypowered.natives.compression.CompressorUtils.ZLIB_BUFFER_SIZE;
|
import static com.velocitypowered.natives.compression.CompressorUtils.ZLIB_BUFFER_SIZE;
|
||||||
import static com.velocitypowered.natives.compression.CompressorUtils.ensureMaxSize;
|
import static com.velocitypowered.natives.compression.CompressorUtils.ensureMaxSize;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import com.velocitypowered.natives.util.BufferPreference;
|
import com.velocitypowered.natives.util.BufferPreference;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.zip.DataFormatException;
|
import java.util.zip.DataFormatException;
|
||||||
import java.util.zip.Deflater;
|
import java.util.zip.Deflater;
|
||||||
import java.util.zip.Inflater;
|
import java.util.zip.Inflater;
|
||||||
@ -16,7 +18,6 @@ public class JavaVelocityCompressor implements VelocityCompressor {
|
|||||||
|
|
||||||
private final Deflater deflater;
|
private final Deflater deflater;
|
||||||
private final Inflater inflater;
|
private final Inflater inflater;
|
||||||
private byte[] buf = new byte[0];
|
|
||||||
private boolean disposed = false;
|
private boolean disposed = false;
|
||||||
|
|
||||||
private JavaVelocityCompressor(int level) {
|
private JavaVelocityCompressor(int level) {
|
||||||
@ -29,92 +30,54 @@ public class JavaVelocityCompressor implements VelocityCompressor {
|
|||||||
throws DataFormatException {
|
throws DataFormatException {
|
||||||
ensureNotDisposed();
|
ensureNotDisposed();
|
||||||
|
|
||||||
final int available = source.readableBytes();
|
// We (probably) can't nicely deal with >=1 buffer nicely, so let's scream loudly.
|
||||||
this.setInflaterInput(source);
|
checkArgument(source.nioBufferCount() == 1, "source has multiple backing buffers");
|
||||||
|
checkArgument(destination.nioBufferCount() == 1, "destination has multiple backing buffers");
|
||||||
|
|
||||||
if (destination.hasArray()) {
|
int origIdx = source.readerIndex();
|
||||||
this.inflateDestinationIsHeap(destination, available, uncompressedSize);
|
inflater.setInput(source.nioBuffer());
|
||||||
} else {
|
|
||||||
if (buf.length == 0) {
|
|
||||||
buf = new byte[ZLIB_BUFFER_SIZE];
|
|
||||||
}
|
|
||||||
while (!inflater.finished() && inflater.getBytesRead() < available) {
|
|
||||||
ensureMaxSize(destination, uncompressedSize);
|
|
||||||
int read = inflater.inflate(buf);
|
|
||||||
destination.writeBytes(buf, 0, read);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inflater.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setInflaterInput(ByteBuf source) {
|
while (!inflater.finished() && inflater.getBytesRead() < source.readableBytes()) {
|
||||||
final int available = source.readableBytes();
|
|
||||||
if (source.hasArray()) {
|
|
||||||
inflater.setInput(source.array(), source.arrayOffset() + source.readerIndex(), available);
|
|
||||||
} else {
|
|
||||||
byte[] inData = new byte[available];
|
|
||||||
source.readBytes(inData);
|
|
||||||
inflater.setInput(inData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void inflateDestinationIsHeap(ByteBuf destination, int available, int max)
|
|
||||||
throws DataFormatException {
|
|
||||||
while (!inflater.finished() && inflater.getBytesRead() < available) {
|
|
||||||
if (!destination.isWritable()) {
|
if (!destination.isWritable()) {
|
||||||
ensureMaxSize(destination, max);
|
ensureMaxSize(destination, uncompressedSize);
|
||||||
destination.ensureWritable(ZLIB_BUFFER_SIZE);
|
destination.ensureWritable(ZLIB_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
ensureMaxSize(destination, max);
|
ByteBuffer destNioBuf = destination.nioBuffer(destination.writerIndex(),
|
||||||
int produced = inflater.inflate(destination.array(), destination.arrayOffset()
|
destination.writableBytes());
|
||||||
+ destination.writerIndex(), destination.writableBytes());
|
int produced = inflater.inflate(destNioBuf);
|
||||||
|
source.readerIndex(origIdx + inflater.getTotalIn());
|
||||||
destination.writerIndex(destination.writerIndex() + produced);
|
destination.writerIndex(destination.writerIndex() + produced);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inflater.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
|
public void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
|
||||||
ensureNotDisposed();
|
ensureNotDisposed();
|
||||||
|
|
||||||
this.setDeflaterInput(source);
|
// We (probably) can't nicely deal with >=1 buffer nicely, so let's scream loudly.
|
||||||
|
checkArgument(source.nioBufferCount() == 1, "source has multiple backing buffers");
|
||||||
|
checkArgument(destination.nioBufferCount() == 1, "destination has multiple backing buffers");
|
||||||
|
|
||||||
|
final int origIdx = source.readerIndex();
|
||||||
|
deflater.setInput(source.nioBuffer());
|
||||||
deflater.finish();
|
deflater.finish();
|
||||||
|
|
||||||
if (destination.hasArray()) {
|
|
||||||
this.deflateDestinationIsHeap(destination);
|
|
||||||
} else {
|
|
||||||
if (buf.length == 0) {
|
|
||||||
buf = new byte[ZLIB_BUFFER_SIZE];
|
|
||||||
}
|
|
||||||
while (!deflater.finished()) {
|
|
||||||
int bytes = deflater.deflate(buf);
|
|
||||||
destination.writeBytes(buf, 0, bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deflater.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setDeflaterInput(ByteBuf source) {
|
|
||||||
if (source.hasArray()) {
|
|
||||||
deflater.setInput(source.array(), source.arrayOffset() + source.readerIndex(),
|
|
||||||
source.readableBytes());
|
|
||||||
} else {
|
|
||||||
byte[] inData = new byte[source.readableBytes()];
|
|
||||||
source.readBytes(inData);
|
|
||||||
deflater.setInput(inData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deflateDestinationIsHeap(ByteBuf destination) {
|
|
||||||
while (!deflater.finished()) {
|
while (!deflater.finished()) {
|
||||||
if (!destination.isWritable()) {
|
if (!destination.isWritable()) {
|
||||||
destination.ensureWritable(ZLIB_BUFFER_SIZE);
|
destination.ensureWritable(ZLIB_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int produced = deflater.deflate(destination.array(), destination.arrayOffset()
|
ByteBuffer destNioBuf = destination.nioBuffer(destination.writerIndex(),
|
||||||
+ destination.writerIndex(), destination.writableBytes());
|
destination.writableBytes());
|
||||||
|
int produced = deflater.deflate(destNioBuf);
|
||||||
destination.writerIndex(destination.writerIndex() + produced);
|
destination.writerIndex(destination.writerIndex() + produced);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
source.readerIndex(origIdx + deflater.getTotalIn());
|
||||||
|
deflater.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -125,11 +88,11 @@ public class JavaVelocityCompressor implements VelocityCompressor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void ensureNotDisposed() {
|
private void ensureNotDisposed() {
|
||||||
Preconditions.checkState(!disposed, "Object already disposed");
|
checkState(!disposed, "Object already disposed");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BufferPreference preferredBufferType() {
|
public BufferPreference preferredBufferType() {
|
||||||
return BufferPreference.HEAP_PREFERRED;
|
return BufferPreference.DIRECT_PREFERRED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package com.velocitypowered.natives.util;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.velocitypowered.natives.NativeSetupException;
|
import com.velocitypowered.natives.NativeSetupException;
|
||||||
import com.velocitypowered.natives.compression.Java11VelocityCompressor;
|
|
||||||
import com.velocitypowered.natives.compression.JavaVelocityCompressor;
|
import com.velocitypowered.natives.compression.JavaVelocityCompressor;
|
||||||
import com.velocitypowered.natives.compression.LibdeflateVelocityCompressor;
|
import com.velocitypowered.natives.compression.LibdeflateVelocityCompressor;
|
||||||
import com.velocitypowered.natives.compression.VelocityCompressorFactory;
|
import com.velocitypowered.natives.compression.VelocityCompressorFactory;
|
||||||
@ -71,9 +70,7 @@ public class Natives {
|
|||||||
"libdeflate (Linux aarch64)",
|
"libdeflate (Linux aarch64)",
|
||||||
LibdeflateVelocityCompressor.FACTORY),
|
LibdeflateVelocityCompressor.FACTORY),
|
||||||
new NativeCodeLoader.Variant<>(NativeConstraints.JAVA_11, () -> {
|
new NativeCodeLoader.Variant<>(NativeConstraints.JAVA_11, () -> {
|
||||||
}, "Java 11", () -> Java11VelocityCompressor.FACTORY),
|
}, "Java", () -> JavaVelocityCompressor.FACTORY)
|
||||||
new NativeCodeLoader.Variant<>(NativeCodeLoader.ALWAYS, () -> {
|
|
||||||
}, "Java", JavaVelocityCompressor.FACTORY)
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ class VelocityCompressorTest {
|
|||||||
@Test
|
@Test
|
||||||
@EnabledOnJre(JRE.JAVA_11)
|
@EnabledOnJre(JRE.JAVA_11)
|
||||||
void java11IntegrityCheckDirect() throws DataFormatException {
|
void java11IntegrityCheckDirect() throws DataFormatException {
|
||||||
VelocityCompressor compressor = Java11VelocityCompressor.FACTORY
|
VelocityCompressor compressor = JavaVelocityCompressor.FACTORY
|
||||||
.create(Deflater.DEFAULT_COMPRESSION);
|
.create(Deflater.DEFAULT_COMPRESSION);
|
||||||
check(compressor, () -> Unpooled.directBuffer(TEST_DATA.length + 32));
|
check(compressor, () -> Unpooled.directBuffer(TEST_DATA.length + 32));
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ class VelocityCompressorTest {
|
|||||||
@Test
|
@Test
|
||||||
@EnabledOnJre(JRE.JAVA_11)
|
@EnabledOnJre(JRE.JAVA_11)
|
||||||
void java11IntegrityCheckHeap() throws DataFormatException {
|
void java11IntegrityCheckHeap() throws DataFormatException {
|
||||||
VelocityCompressor compressor = Java11VelocityCompressor.FACTORY
|
VelocityCompressor compressor = JavaVelocityCompressor.FACTORY
|
||||||
.create(Deflater.DEFAULT_COMPRESSION);
|
.create(Deflater.DEFAULT_COMPRESSION);
|
||||||
check(compressor, () -> Unpooled.buffer(TEST_DATA.length + 32));
|
check(compressor, () -> Unpooled.buffer(TEST_DATA.length + 32));
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ class VelocityCompressorTest {
|
|||||||
throws DataFormatException {
|
throws DataFormatException {
|
||||||
ByteBuf source = bufSupplier.get();
|
ByteBuf source = bufSupplier.get();
|
||||||
ByteBuf dest = bufSupplier.get();
|
ByteBuf dest = bufSupplier.get();
|
||||||
ByteBuf decompressed = bufSupplier.get();
|
ByteBuf decompressed = Unpooled.directBuffer(16);
|
||||||
|
|
||||||
source.writeBytes(TEST_DATA);
|
source.writeBytes(TEST_DATA);
|
||||||
int uncompressedData = source.readableBytes();
|
int uncompressedData = source.readableBytes();
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren