geforkt von Mirrors/Velocity
Implement optimized compression for Java 11+
Using the fact that the Java Deflater/Inflater API now supports ByteBuffers as of Java 11, we can provide performance benefits equivalent to the Velocity 1.0.x native compression on servers running Java 11+ on non-macOS and non-Linux platforms (such as Windows).
Dieser Commit ist enthalten in:
Ursprung
078db5ca65
Commit
7747679ee1
@ -1,5 +1,7 @@
|
|||||||
package com.velocitypowered.natives;
|
package com.velocitypowered.natives;
|
||||||
|
|
||||||
|
import com.velocitypowered.natives.util.BufferPreference;
|
||||||
|
|
||||||
public interface Native {
|
public interface Native {
|
||||||
boolean isNative();
|
BufferPreference preferredBufferType();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,133 @@
|
|||||||
|
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 max) 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, max);
|
||||||
|
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) {
|
||||||
|
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) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
disposed = true;
|
||||||
|
deflater.end();
|
||||||
|
inflater.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureNotDisposed() {
|
||||||
|
checkState(!disposed, "Object already disposed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BufferPreference preferredBufferType() {
|
||||||
|
return BufferPreference.DIRECT_PREFERRED;
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ import static com.velocitypowered.natives.compression.CompressorUtils.ZLIB_BUFFE
|
|||||||
import static com.velocitypowered.natives.compression.CompressorUtils.ensureMaxSize;
|
import static com.velocitypowered.natives.compression.CompressorUtils.ensureMaxSize;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.velocitypowered.natives.util.BufferPreference;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.util.zip.DataFormatException;
|
import java.util.zip.DataFormatException;
|
||||||
import java.util.zip.Deflater;
|
import java.util.zip.Deflater;
|
||||||
@ -77,7 +78,7 @@ public class JavaVelocityCompressor implements VelocityCompressor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isNative() {
|
public BufferPreference preferredBufferType() {
|
||||||
return false;
|
return BufferPreference.HEAP_PREFERRED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import static com.velocitypowered.natives.compression.CompressorUtils.ZLIB_BUFFE
|
|||||||
import static com.velocitypowered.natives.compression.CompressorUtils.ensureMaxSize;
|
import static com.velocitypowered.natives.compression.CompressorUtils.ensureMaxSize;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.velocitypowered.natives.util.BufferPreference;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.util.zip.DataFormatException;
|
import java.util.zip.DataFormatException;
|
||||||
|
|
||||||
@ -82,7 +83,7 @@ public class NativeVelocityCompressor implements VelocityCompressor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isNative() {
|
public BufferPreference preferredBufferType() {
|
||||||
return true;
|
return BufferPreference.DIRECT_REQUIRED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.velocitypowered.natives.encryption;
|
package com.velocitypowered.natives.encryption;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.velocitypowered.natives.util.BufferPreference;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufUtil;
|
import io.netty.buffer.ByteBufUtil;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
@ -88,7 +89,7 @@ public class JavaVelocityCipher implements VelocityCipher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isNative() {
|
public BufferPreference preferredBufferType() {
|
||||||
return false;
|
return BufferPreference.HEAP_PREFERRED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.velocitypowered.natives.encryption;
|
package com.velocitypowered.natives.encryption;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.velocitypowered.natives.util.BufferPreference;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
@ -81,7 +82,7 @@ public class NativeVelocityCipher implements VelocityCipher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isNative() {
|
public BufferPreference preferredBufferType() {
|
||||||
return true;
|
return BufferPreference.DIRECT_REQUIRED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.velocitypowered.natives.util;
|
||||||
|
|
||||||
|
public enum BufferPreference {
|
||||||
|
/**
|
||||||
|
* A heap buffer is preferred (but not required).
|
||||||
|
*/
|
||||||
|
HEAP_PREFERRED,
|
||||||
|
/**
|
||||||
|
* A direct buffer is preferred (but not required).
|
||||||
|
*/
|
||||||
|
DIRECT_PREFERRED,
|
||||||
|
/**
|
||||||
|
* A direct buffer is required.
|
||||||
|
*/
|
||||||
|
DIRECT_REQUIRED
|
||||||
|
}
|
@ -20,9 +20,8 @@ public class MoreByteBufUtils {
|
|||||||
* @return a buffer compatible with the native
|
* @return a buffer compatible with the native
|
||||||
*/
|
*/
|
||||||
public static ByteBuf ensureCompatible(ByteBufAllocator alloc, Native nativeStuff, ByteBuf buf) {
|
public static ByteBuf ensureCompatible(ByteBufAllocator alloc, Native nativeStuff, ByteBuf buf) {
|
||||||
if (!nativeStuff.isNative() || buf.hasMemoryAddress()) {
|
if (nativeStuff.preferredBufferType() != BufferPreference.DIRECT_REQUIRED
|
||||||
// Will always work in either case. JNI code demands a memory address, and if we have a Java
|
|| buf.hasMemoryAddress()) {
|
||||||
// fallback, it uses byte arrays in all cases.
|
|
||||||
return buf.retain();
|
return buf.retain();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +40,8 @@ public class MoreByteBufUtils {
|
|||||||
* @return a buffer compatible with the native
|
* @return a buffer compatible with the native
|
||||||
*/
|
*/
|
||||||
public static ByteBuf preferredBuffer(ByteBufAllocator alloc, Native nativeStuff) {
|
public static ByteBuf preferredBuffer(ByteBufAllocator alloc, Native nativeStuff) {
|
||||||
return nativeStuff.isNative() ? alloc.directBuffer() : alloc.heapBuffer();
|
return nativeStuff.preferredBufferType() != BufferPreference.HEAP_PREFERRED
|
||||||
|
? alloc.directBuffer() : alloc.heapBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,7 +55,7 @@ public class MoreByteBufUtils {
|
|||||||
*/
|
*/
|
||||||
public static ByteBuf preferredBuffer(ByteBufAllocator alloc, Native nativeStuff,
|
public static ByteBuf preferredBuffer(ByteBufAllocator alloc, Native nativeStuff,
|
||||||
int initialCapacity) {
|
int initialCapacity) {
|
||||||
return nativeStuff.isNative() ? alloc.directBuffer(initialCapacity) : alloc
|
return nativeStuff.preferredBufferType() != BufferPreference.HEAP_PREFERRED
|
||||||
.heapBuffer(initialCapacity);
|
? alloc.directBuffer(initialCapacity) : alloc.heapBuffer(initialCapacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ public final class NativeCodeLoader<T> implements Supplier<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T get() {
|
public T get() {
|
||||||
return selected.object;
|
return selected.constructed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> Variant<T> getVariant(List<Variant<T>> variants) {
|
private static <T> Variant<T> getVariant(List<Variant<T>> variants) {
|
||||||
@ -38,9 +38,14 @@ public final class NativeCodeLoader<T> implements Supplier<T> {
|
|||||||
private Status status;
|
private Status status;
|
||||||
private final Runnable setup;
|
private final Runnable setup;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final T object;
|
private final Supplier<T> object;
|
||||||
|
private T constructed;
|
||||||
|
|
||||||
Variant(BooleanSupplier possiblyAvailable, Runnable setup, String name, T object) {
|
Variant(BooleanSupplier possiblyAvailable, Runnable setup, String name, T object) {
|
||||||
|
this(possiblyAvailable, setup, name, () -> object);
|
||||||
|
}
|
||||||
|
|
||||||
|
Variant(BooleanSupplier possiblyAvailable, Runnable setup, String name, Supplier<T> object) {
|
||||||
this.status =
|
this.status =
|
||||||
possiblyAvailable.getAsBoolean() ? Status.POSSIBLY_AVAILABLE : Status.NOT_AVAILABLE;
|
possiblyAvailable.getAsBoolean() ? Status.POSSIBLY_AVAILABLE : Status.NOT_AVAILABLE;
|
||||||
this.setup = setup;
|
this.setup = setup;
|
||||||
@ -57,6 +62,7 @@ public final class NativeCodeLoader<T> implements Supplier<T> {
|
|||||||
if (status == Status.POSSIBLY_AVAILABLE) {
|
if (status == Status.POSSIBLY_AVAILABLE) {
|
||||||
try {
|
try {
|
||||||
setup.run();
|
setup.run();
|
||||||
|
constructed = object.get();
|
||||||
status = Status.SETUP;
|
status = Status.SETUP;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
status = Status.SETUP_FAILURE;
|
status = Status.SETUP_FAILURE;
|
||||||
@ -64,7 +70,7 @@ public final class NativeCodeLoader<T> implements Supplier<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return object;
|
return constructed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import java.util.function.BooleanSupplier;
|
|||||||
|
|
||||||
public class NativeConstraints {
|
public class NativeConstraints {
|
||||||
private static final boolean NATIVES_ENABLED = !Boolean.getBoolean("velocity.natives-disabled");
|
private static final boolean NATIVES_ENABLED = !Boolean.getBoolean("velocity.natives-disabled");
|
||||||
|
private static final boolean IS_AMD64;
|
||||||
private static final boolean CAN_GET_MEMORYADDRESS;
|
private static final boolean CAN_GET_MEMORYADDRESS;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@ -15,19 +16,28 @@ public class NativeConstraints {
|
|||||||
} finally {
|
} finally {
|
||||||
test.release();
|
test.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String osArch = System.getProperty("os.arch", "");
|
||||||
|
// HotSpot on Intel macOS prefers x86_64, but OpenJ9 on macOS and HotSpot/OpenJ9 elsewhere
|
||||||
|
// give amd64.
|
||||||
|
IS_AMD64 = osArch.equals("amd64") || osArch.equals("x86_64");
|
||||||
}
|
}
|
||||||
|
|
||||||
static final BooleanSupplier MACOS = () -> {
|
static final BooleanSupplier MACOS = () -> {
|
||||||
return NATIVES_ENABLED
|
return NATIVES_ENABLED
|
||||||
&& CAN_GET_MEMORYADDRESS
|
&& CAN_GET_MEMORYADDRESS
|
||||||
&& System.getProperty("os.name", "").equalsIgnoreCase("Mac OS X")
|
&& System.getProperty("os.name", "").equalsIgnoreCase("Mac OS X")
|
||||||
&& System.getProperty("os.arch", "").equals("x86_64");
|
&& IS_AMD64;
|
||||||
};
|
};
|
||||||
|
|
||||||
static final BooleanSupplier LINUX = () -> {
|
static final BooleanSupplier LINUX = () -> {
|
||||||
return NATIVES_ENABLED
|
return NATIVES_ENABLED
|
||||||
&& CAN_GET_MEMORYADDRESS
|
&& CAN_GET_MEMORYADDRESS
|
||||||
&& System.getProperty("os.name", "").equalsIgnoreCase("Linux")
|
&& System.getProperty("os.name", "").equalsIgnoreCase("Linux")
|
||||||
&& System.getProperty("os.arch", "").equals("amd64");
|
&& IS_AMD64;
|
||||||
|
};
|
||||||
|
|
||||||
|
static final BooleanSupplier JAVA_11 = () -> {
|
||||||
|
return Double.parseDouble(System.getProperty("java.specification.version")) >= 11;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ 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.NativeVelocityCompressor;
|
import com.velocitypowered.natives.compression.NativeVelocityCompressor;
|
||||||
import com.velocitypowered.natives.compression.VelocityCompressorFactory;
|
import com.velocitypowered.natives.compression.VelocityCompressorFactory;
|
||||||
@ -52,6 +53,8 @@ public class Natives {
|
|||||||
new NativeCodeLoader.Variant<>(NativeConstraints.LINUX,
|
new NativeCodeLoader.Variant<>(NativeConstraints.LINUX,
|
||||||
copyAndLoadNative("/linux_x64/velocity-compress.so"), "native (Linux amd64)",
|
copyAndLoadNative("/linux_x64/velocity-compress.so"), "native (Linux amd64)",
|
||||||
NativeVelocityCompressor.FACTORY),
|
NativeVelocityCompressor.FACTORY),
|
||||||
|
new NativeCodeLoader.Variant<>(NativeConstraints.JAVA_11, () -> {
|
||||||
|
}, "Java 11", () -> Java11VelocityCompressor.FACTORY),
|
||||||
new NativeCodeLoader.Variant<>(NativeCodeLoader.ALWAYS, () -> {
|
new NativeCodeLoader.Variant<>(NativeCodeLoader.ALWAYS, () -> {
|
||||||
}, "Java", JavaVelocityCompressor.FACTORY)
|
}, "Java", JavaVelocityCompressor.FACTORY)
|
||||||
)
|
)
|
||||||
|
@ -6,6 +6,7 @@ import static org.junit.jupiter.api.Assertions.fail;
|
|||||||
import static org.junit.jupiter.api.condition.OS.LINUX;
|
import static org.junit.jupiter.api.condition.OS.LINUX;
|
||||||
import static org.junit.jupiter.api.condition.OS.MAC;
|
import static org.junit.jupiter.api.condition.OS.MAC;
|
||||||
|
|
||||||
|
import com.velocitypowered.natives.util.BufferPreference;
|
||||||
import com.velocitypowered.natives.util.Natives;
|
import com.velocitypowered.natives.util.Natives;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufUtil;
|
import io.netty.buffer.ByteBufUtil;
|
||||||
@ -17,7 +18,9 @@ import java.util.zip.DataFormatException;
|
|||||||
import java.util.zip.Deflater;
|
import java.util.zip.Deflater;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.condition.EnabledOnJre;
|
||||||
import org.junit.jupiter.api.condition.EnabledOnOs;
|
import org.junit.jupiter.api.condition.EnabledOnOs;
|
||||||
|
import org.junit.jupiter.api.condition.JRE;
|
||||||
|
|
||||||
class VelocityCompressorTest {
|
class VelocityCompressorTest {
|
||||||
|
|
||||||
@ -39,7 +42,7 @@ class VelocityCompressorTest {
|
|||||||
@EnabledOnOs({MAC, LINUX})
|
@EnabledOnOs({MAC, LINUX})
|
||||||
void nativeIntegrityCheck() throws DataFormatException {
|
void nativeIntegrityCheck() throws DataFormatException {
|
||||||
VelocityCompressor compressor = Natives.compress.get().create(Deflater.DEFAULT_COMPRESSION);
|
VelocityCompressor compressor = Natives.compress.get().create(Deflater.DEFAULT_COMPRESSION);
|
||||||
if (compressor instanceof JavaVelocityCompressor) {
|
if (compressor.preferredBufferType() != BufferPreference.DIRECT_REQUIRED) {
|
||||||
compressor.dispose();
|
compressor.dispose();
|
||||||
fail("Loaded regular compressor");
|
fail("Loaded regular compressor");
|
||||||
}
|
}
|
||||||
@ -60,6 +63,22 @@ class VelocityCompressorTest {
|
|||||||
check(compressor, () -> Unpooled.buffer(TEST_DATA.length + 32));
|
check(compressor, () -> Unpooled.buffer(TEST_DATA.length + 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnabledOnJre(JRE.JAVA_11)
|
||||||
|
void java11IntegrityCheckDirect() throws DataFormatException {
|
||||||
|
VelocityCompressor compressor = Java11VelocityCompressor.FACTORY
|
||||||
|
.create(Deflater.DEFAULT_COMPRESSION);
|
||||||
|
check(compressor, () -> Unpooled.directBuffer(TEST_DATA.length + 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@EnabledOnJre(JRE.JAVA_11)
|
||||||
|
void java11IntegrityCheckHeap() throws DataFormatException {
|
||||||
|
VelocityCompressor compressor = Java11VelocityCompressor.FACTORY
|
||||||
|
.create(Deflater.DEFAULT_COMPRESSION);
|
||||||
|
check(compressor, () -> Unpooled.buffer(TEST_DATA.length + 32));
|
||||||
|
}
|
||||||
|
|
||||||
private void check(VelocityCompressor compressor, Supplier<ByteBuf> bufSupplier)
|
private void check(VelocityCompressor compressor, Supplier<ByteBuf> bufSupplier)
|
||||||
throws DataFormatException {
|
throws DataFormatException {
|
||||||
ByteBuf source = bufSupplier.get();
|
ByteBuf source = bufSupplier.get();
|
||||||
|
@ -17,7 +17,7 @@ public class VelocityNettyThreadFactory implements ThreadFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Thread newThread(Runnable r) {
|
public Thread newThread(Runnable r) {
|
||||||
String name = String.format(nameFormat, threadNumber.incrementAndGet());
|
String name = String.format(nameFormat, threadNumber.getAndIncrement());
|
||||||
return new FastThreadLocalThread(r, name);
|
return new FastThreadLocalThread(r, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren