13
0
geforkt von Mirrors/Velocity

Take advantage of pooled ByteBufs in Java cipher

ByteBufs are pooled in Velocity, so we can achieve lower memory usage
by using what Netty is going to provide to us for free.
Dieser Commit ist enthalten in:
Andrew Steinborn 2019-06-11 02:04:38 -04:00
Ursprung b0736548a9
Commit ec32def592

Datei anzeigen

@ -2,7 +2,7 @@ package com.velocitypowered.natives.encryption;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import javax.crypto.Cipher; import javax.crypto.Cipher;
@ -23,9 +23,6 @@ public class JavaVelocityCipher implements VelocityCipher {
return new JavaVelocityCipher(false, key); return new JavaVelocityCipher(false, key);
} }
}; };
private static final int INITIAL_BUFFER_SIZE = 1024 * 8;
private static final ThreadLocal<byte[]> inBufLocal = ThreadLocal.withInitial(
() -> new byte[INITIAL_BUFFER_SIZE]);
private final Cipher cipher; private final Cipher cipher;
private boolean disposed = false; private boolean disposed = false;
@ -41,20 +38,12 @@ public class JavaVelocityCipher implements VelocityCipher {
ensureNotDisposed(); ensureNotDisposed();
int inBytes = source.readableBytes(); int inBytes = source.readableBytes();
ByteBuf asHeapBuf = asHeapBuf(source); byte[] asBytes = ByteBufUtil.getBytes(source);
int outputSize = cipher.getOutputSize(inBytes); int outputSize = cipher.getOutputSize(inBytes);
if (!destination.hasArray()) { byte[] outBuf = new byte[outputSize];
byte[] outBuf = new byte[outputSize]; cipher.update(asBytes, 0, inBytes, outBuf);
cipher.update(asHeapBuf.array(), asHeapBuf.arrayOffset(), inBytes, outBuf); destination.writeBytes(outBuf);
destination.writeBytes(outBuf);
} else {
// If the destination we write to is an array, we can use the backing array directly.
destination.ensureWritable(outputSize);
int produced = cipher.update(asHeapBuf.array(), asHeapBuf.arrayOffset(), inBytes,
destination.array(), destination.arrayOffset());
destination.writerIndex(destination.writerIndex() + produced);
}
} }
@Override @Override
@ -62,28 +51,31 @@ public class JavaVelocityCipher implements VelocityCipher {
ensureNotDisposed(); ensureNotDisposed();
int inBytes = source.readableBytes(); int inBytes = source.readableBytes();
ByteBuf asHeapBuf = asHeapBuf(source); ByteBuf asHeapBuf = toHeap(source);
ByteBuf out = ctx.alloc().heapBuffer(cipher.getOutputSize(inBytes)); ByteBuf out = ctx.alloc().heapBuffer(cipher.getOutputSize(inBytes));
out.writerIndex(cipher.update(asHeapBuf.array(), asHeapBuf.arrayOffset(), inBytes, out.array(), try {
out.arrayOffset())); out.writerIndex(
return out; cipher.update(asHeapBuf.array(), asHeapBuf.arrayOffset() + asHeapBuf.readerIndex(),
inBytes, out.array(), out.arrayOffset() + out.writerIndex()));
return out;
} catch (ShortBufferException e) {
out.release();
throw e;
} finally {
asHeapBuf.release();
}
} }
private static ByteBuf asHeapBuf(ByteBuf source) { private static ByteBuf toHeap(ByteBuf src) {
if (source.hasArray()) { if (!src.isDirect()) {
// If this byte buffer is backed by an array, we can just use this buffer directly. return src.retain();
return source;
} }
int inBytes = source.readableBytes(); // Copy into a temporary heap buffer. We could use a local buffer, but Netty pools all buffers,
byte[] inBuf = inBufLocal.get(); // so we'd lose more than we gain.
if (inBuf.length <= inBytes) { ByteBuf asHeapBuf = src.alloc().heapBuffer(src.readableBytes());
inBuf = new byte[inBytes]; asHeapBuf.writeBytes(src);
inBufLocal.set(inBuf); return asHeapBuf;
}
source.readBytes(inBuf, 0, inBytes);
return Unpooled.wrappedBuffer(inBuf, 0, inBytes);
} }
@Override @Override