diff --git a/lib/trino-parquet/src/main/java/io/trino/parquet/ParquetReaderUtils.java b/lib/trino-parquet/src/main/java/io/trino/parquet/ParquetReaderUtils.java index a608955e9b8d..77ae5bcf40ab 100644 --- a/lib/trino-parquet/src/main/java/io/trino/parquet/ParquetReaderUtils.java +++ b/lib/trino-parquet/src/main/java/io/trino/parquet/ParquetReaderUtils.java @@ -52,35 +52,35 @@ public static int readUleb128Int(SimpleSliceInputStream input) { byte[] inputBytes = input.getByteArray(); int offset = input.getByteArrayOffset(); - // Manual loop unrolling shows improvements in BenchmarkReadUleb128Int - int inputByte = inputBytes[offset]; - int value = inputByte & 0x7F; - if ((inputByte & 0x80) == 0) { + // Fast paths for 1-byte and 2-byte values (most common for small dictionary indices + // and page/group counts). For 3+ byte values, fall through to a tight loop. This beats + // the fully unrolled 5-branch version on long input sequences (where the unrolled + // version's branch chain depth dominates), while preserving straight-line code for + // the common short values (where the unrolled version wins). + byte b0 = inputBytes[offset]; + if ((b0 & 0x80) == 0) { input.skip(1); - return value; + return b0; } - inputByte = inputBytes[offset + 1]; - value |= (inputByte & 0x7F) << 7; - if ((inputByte & 0x80) == 0) { + byte b1 = inputBytes[offset + 1]; + int value = (b0 & 0x7F) | ((b1 & 0x7F) << 7); + if ((b1 & 0x80) == 0) { input.skip(2); return value; } - inputByte = inputBytes[offset + 2]; - value |= (inputByte & 0x7F) << 14; - if ((inputByte & 0x80) == 0) { - input.skip(3); - return value; - } - inputByte = inputBytes[offset + 3]; - value |= (inputByte & 0x7F) << 21; - if ((inputByte & 0x80) == 0) { - input.skip(4); - return value; + int consumed = 2; + int shift = 14; + byte b; + do { + b = inputBytes[offset + consumed]; + value |= (b & 0x7F) << shift; + shift += 7; + consumed++; } - inputByte = inputBytes[offset + 4]; - verify((inputByte & 0x80) == 0, "ULEB128 variable-width integer should not be longer than 5 bytes"); - input.skip(5); - return value | inputByte << 28; + while ((b & 0x80) != 0 && shift < 35); + verify((b & 0x80) == 0, "ULEB128 variable-width integer should not be longer than 5 bytes"); + input.skip(consumed); + return value; } public static long readUleb128Long(SimpleSliceInputStream input)