Optimize native handling further.
We now try to work within the boundaries given by the native. In the case of Java natives, we work with byte arrays. With natives, always use direct buffers. However, the numbers do favor the natives, since they work with direct byte buffers, without any copying. For the most part, this commit is intended to improve the lives of Velocity users on Windows.
This commit is contained in:
@@ -85,7 +85,7 @@ Java_com_velocitypowered_natives_compression_NativeZlibDeflate_process(JNIEnv *e
|
||||
jint sourceLength,
|
||||
jlong destinationAddress,
|
||||
jint destinationLength,
|
||||
jboolean flush)
|
||||
jboolean finish)
|
||||
{
|
||||
z_stream* stream = (z_stream*) ctx;
|
||||
stream->next_in = (Bytef *) sourceAddress;
|
||||
@@ -93,7 +93,7 @@ Java_com_velocitypowered_natives_compression_NativeZlibDeflate_process(JNIEnv *e
|
||||
stream->avail_in = sourceLength;
|
||||
stream->avail_out = destinationLength;
|
||||
|
||||
int res = deflate(stream, flush ? Z_FINISH : Z_NO_FLUSH);
|
||||
int res = deflate(stream, finish ? Z_FINISH : Z_NO_FLUSH);
|
||||
switch (res) {
|
||||
case Z_STREAM_END:
|
||||
// The stream has ended.
|
||||
|
@@ -27,9 +27,14 @@ public class JavaVelocityCompressor implements VelocityCompressor {
|
||||
public void inflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
|
||||
ensureNotDisposed();
|
||||
|
||||
byte[] inData = new byte[source.readableBytes()];
|
||||
source.readBytes(inData);
|
||||
inflater.setInput(inData);
|
||||
if (source.hasArray()) {
|
||||
inflater.setInput(source.array(), source.arrayOffset(), source.readableBytes());
|
||||
} else {
|
||||
byte[] inData = new byte[source.readableBytes()];
|
||||
source.readBytes(inData);
|
||||
inflater.setInput(inData);
|
||||
}
|
||||
|
||||
while (!inflater.finished()) {
|
||||
int read = inflater.inflate(buf);
|
||||
destination.writeBytes(buf, 0, read);
|
||||
@@ -41,9 +46,13 @@ public class JavaVelocityCompressor implements VelocityCompressor {
|
||||
public void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
|
||||
ensureNotDisposed();
|
||||
|
||||
byte[] inData = new byte[source.readableBytes()];
|
||||
source.readBytes(inData);
|
||||
deflater.setInput(inData);
|
||||
if (source.hasArray()) {
|
||||
deflater.setInput(source.array(), source.arrayOffset(), source.readableBytes());
|
||||
} else {
|
||||
byte[] inData = new byte[source.readableBytes()];
|
||||
source.readBytes(inData);
|
||||
deflater.setInput(inData);
|
||||
}
|
||||
deflater.finish();
|
||||
while (!deflater.finished()) {
|
||||
int bytes = deflater.deflate(buf);
|
||||
|
@@ -13,8 +13,7 @@ class NativeZlibDeflate {
|
||||
native long free(long ctx);
|
||||
|
||||
native int process(long ctx, long sourceAddress, int sourceLength, long destinationAddress,
|
||||
int destinationLength,
|
||||
boolean flush);
|
||||
int destinationLength, boolean finish);
|
||||
|
||||
native void reset(long ctx);
|
||||
|
||||
|
@@ -2,6 +2,7 @@ package com.velocitypowered.natives.encryption;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import java.security.GeneralSecurityException;
|
||||
import javax.crypto.Cipher;
|
||||
@@ -22,7 +23,7 @@ public class JavaVelocityCipher implements VelocityCipher {
|
||||
return new JavaVelocityCipher(false, key);
|
||||
}
|
||||
};
|
||||
private static final int INITIAL_BUFFER_SIZE = 1024 * 16;
|
||||
private static final int INITIAL_BUFFER_SIZE = 1024 * 8;
|
||||
private static final ThreadLocal<byte[]> inBufLocal = ThreadLocal.withInitial(
|
||||
() -> new byte[INITIAL_BUFFER_SIZE]);
|
||||
|
||||
@@ -40,12 +41,19 @@ public class JavaVelocityCipher implements VelocityCipher {
|
||||
ensureNotDisposed();
|
||||
|
||||
int inBytes = source.readableBytes();
|
||||
byte[] inBuf = slurp(source);
|
||||
ByteBuf asHeapBuf = asHeapBuf(source);
|
||||
|
||||
int outputSize = cipher.getOutputSize(inBytes);
|
||||
byte[] outBuf = new byte[outputSize];
|
||||
cipher.update(inBuf, 0, inBytes, outBuf);
|
||||
destination.writeBytes(outBuf);
|
||||
if (!destination.hasArray()) {
|
||||
byte[] outBuf = new byte[outputSize];
|
||||
cipher.update(asHeapBuf.array(), asHeapBuf.arrayOffset(), inBytes, outBuf);
|
||||
destination.writeBytes(outBuf);
|
||||
} else {
|
||||
// If the destination we write to is an array, we can use the backing array directly.
|
||||
destination.ensureWritable(outputSize);
|
||||
destination.writerIndex(cipher.update(asHeapBuf.array(), asHeapBuf.arrayOffset(), inBytes,
|
||||
destination.array(), destination.arrayOffset()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,14 +61,20 @@ public class JavaVelocityCipher implements VelocityCipher {
|
||||
ensureNotDisposed();
|
||||
|
||||
int inBytes = source.readableBytes();
|
||||
byte[] inBuf = slurp(source);
|
||||
ByteBuf asHeapBuf = asHeapBuf(source);
|
||||
|
||||
ByteBuf out = ctx.alloc().heapBuffer(cipher.getOutputSize(inBytes));
|
||||
out.writerIndex(cipher.update(inBuf, 0, inBytes, out.array(), out.arrayOffset()));
|
||||
out.writerIndex(cipher.update(asHeapBuf.array(), asHeapBuf.arrayOffset(), inBytes, out.array(),
|
||||
out.arrayOffset()));
|
||||
return out;
|
||||
}
|
||||
|
||||
private static byte[] slurp(ByteBuf source) {
|
||||
private static ByteBuf asHeapBuf(ByteBuf source) {
|
||||
if (source.hasArray()) {
|
||||
// If this byte buffer is backed by an array, we can just use this buffer directly.
|
||||
return source;
|
||||
}
|
||||
|
||||
int inBytes = source.readableBytes();
|
||||
byte[] inBuf = inBufLocal.get();
|
||||
if (inBuf.length <= inBytes) {
|
||||
@@ -68,7 +82,7 @@ public class JavaVelocityCipher implements VelocityCipher {
|
||||
inBufLocal.set(inBuf);
|
||||
}
|
||||
source.readBytes(inBuf, 0, inBytes);
|
||||
return inBuf;
|
||||
return Unpooled.wrappedBuffer(inBuf, 0, inBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -30,4 +30,31 @@ public class MoreByteBufUtils {
|
||||
newBuf.writeBytes(buf);
|
||||
return newBuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ByteBuf} that will have the best performance with the specified
|
||||
* {@code nativeStuff}.
|
||||
*
|
||||
* @param alloc the {@link ByteBufAllocator} to use
|
||||
* @param nativeStuff the native we are working with
|
||||
* @return a buffer compatible with the native
|
||||
*/
|
||||
public static ByteBuf preferredBuffer(ByteBufAllocator alloc, Native nativeStuff) {
|
||||
return nativeStuff.isNative() ? alloc.directBuffer() : alloc.heapBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ByteBuf} that will have the best performance with the specified
|
||||
* {@code nativeStuff}.
|
||||
*
|
||||
* @param alloc the {@link ByteBufAllocator} to use
|
||||
* @param nativeStuff the native we are working with
|
||||
* @param initialCapacity the initial capacity to allocate
|
||||
* @return a buffer compatible with the native
|
||||
*/
|
||||
public static ByteBuf preferredBuffer(ByteBufAllocator alloc, Native nativeStuff,
|
||||
int initialCapacity) {
|
||||
return nativeStuff.isNative() ? alloc.directBuffer(initialCapacity) : alloc
|
||||
.heapBuffer(initialCapacity);
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Reference in New Issue
Block a user