From a6ddc137ee5c9181e8b1c1d68686bfca0b0e9aa5 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Fri, 21 Aug 2020 01:05:04 -0400 Subject: [PATCH] Reduce varint reading cost from max(1, 2n) to n+1 operations on ByteBuf The previous code, in an attempt to avoid exceptions, checked in.isReadable() each iteration of the loop. This isn't very efficient since it's possible for us to know the maximum size of the varint to read: it's the minimum of either the largest size a varint can be (5 bytes) or the size of the remaining readable bytes in the buffer. --- .../proxy/protocol/ProtocolUtils.java | 16 +++++----------- .../netty/MinecraftVarintFrameDecoder.java | 2 -- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index baa5bc176..2804a978a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -67,21 +67,15 @@ public enum ProtocolUtils { */ public static int readVarIntSafely(ByteBuf buf) { int i = 0; - int j = 0; - while (true) { - if (!buf.isReadable()) { - return Integer.MIN_VALUE; - } + int maxRead = Math.min(5, buf.readableBytes()); + for (int j = 0; j < maxRead; j++) { int k = buf.readByte(); - i |= (k & 0x7F) << j++ * 7; - if (j > 5) { - return Integer.MIN_VALUE; - } + i |= (k & 0x7F) << j * 7; if ((k & 0x80) != 128) { - break; + return i; } } - return i; + return Integer.MIN_VALUE; } /** diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java index 18e35898d..3415c12da 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java @@ -42,8 +42,6 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder { if (in.isReadable(minimumRead)) { out.add(in.retainedSlice(varintEnd + 1, reader.readVarint)); in.skipBytes(minimumRead); - } else { - return; } } } else if (reader.result == DecodeResult.TOO_BIG) {