Skip to content

Commit 6001499

Browse files
authored
Eliminate redundant bounds checks in CompositeByteBuf accessors (#16525)
Motivation: Every _getXxx/_setXxx in CompositeByteBuf delegates to the underlying buffer's public API (e.g. c.buf.getByte()), which re-checks bounds that the composite level already validated. Modifications: - Add an `abuf` field to Component that caches `(AbstractByteBuf) buf` at construction time, or null for non-AbstractByteBuf wrappers - Use abuf._getXxx() (no bounds check) when available, fall back to buf.getXxx() otherwise - Add sequentialReadBytes and sequentialGetBytes JMH benchmarks Result: Redundant bounds checks eliminated on the hot path.
1 parent a7fbb6f commit 6001499

2 files changed

Lines changed: 179 additions & 21 deletions

File tree

buffer/src/main/java/io/netty/buffer/CompositeByteBuf.java

Lines changed: 106 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,7 @@ public CompositeByteBuf removeComponent(int cIndex) {
615615
Component comp = components[cIndex];
616616
if (lastAccessed == comp) {
617617
lastAccessed = null;
618+
lastAccessedIndex = 0;
618619
}
619620
comp.free();
620621
removeComp(cIndex);
@@ -646,6 +647,7 @@ public CompositeByteBuf removeComponents(int cIndex, int numComponents) {
646647
}
647648
if (lastAccessed == c) {
648649
lastAccessed = null;
650+
lastAccessedIndex = 0;
649651
}
650652
c.free();
651653
}
@@ -856,6 +858,7 @@ public CompositeByteBuf capacity(int newCapacity) {
856858
}
857859
} else if (newCapacity < oldCapacity) {
858860
lastAccessed = null;
861+
lastAccessedIndex = 0;
859862
int i = size - 1;
860863
for (int bytesToTrim = oldCapacity - newCapacity; i >= 0; i--) {
861864
Component c = components[i];
@@ -952,20 +955,36 @@ public int toByteIndex(int cIndex) {
952955
@Override
953956
public byte getByte(int index) {
954957
Component c = findComponent(index);
955-
return c.buf.getByte(c.idx(index));
958+
return c.abuf != null ? c.abuf._getByte(c.idx(index)) : c.buf.getByte(c.idx(index));
959+
}
960+
961+
@Override
962+
public byte readByte() {
963+
checkReadableBytes(1);
964+
int rIdx = readerIndex;
965+
Component c = lastAccessed;
966+
if (c == null) {
967+
c = findIt(rIdx);
968+
} else if (rIdx >= c.endOffset) {
969+
c = findComponentForRead(rIdx);
970+
} else if (rIdx < c.offset) {
971+
c = findIt(rIdx);
972+
}
973+
readerIndex = rIdx + 1;
974+
return c.abuf != null ? c.abuf._getByte(rIdx + c.adjustment) : c.buf.getByte(rIdx + c.adjustment);
956975
}
957976

958977
@Override
959978
protected byte _getByte(int index) {
960979
Component c = findComponent0(index);
961-
return c.buf.getByte(c.idx(index));
980+
return c.abuf != null ? c.abuf._getByte(c.idx(index)) : c.buf.getByte(c.idx(index));
962981
}
963982

964983
@Override
965984
protected short _getShort(int index) {
966985
Component c = findComponent0(index);
967986
if (index + 2 <= c.endOffset) {
968-
return c.buf.getShort(c.idx(index));
987+
return c.abuf != null ? c.abuf._getShort(c.idx(index)) : c.buf.getShort(c.idx(index));
969988
} else if (order() == ByteOrder.BIG_ENDIAN) {
970989
return (short) ((_getByte(index) & 0xff) << 8 | _getByte(index + 1) & 0xff);
971990
} else {
@@ -977,7 +996,7 @@ protected short _getShort(int index) {
977996
protected short _getShortLE(int index) {
978997
Component c = findComponent0(index);
979998
if (index + 2 <= c.endOffset) {
980-
return c.buf.getShortLE(c.idx(index));
999+
return c.abuf != null ? c.abuf._getShortLE(c.idx(index)) : c.buf.getShortLE(c.idx(index));
9811000
} else if (order() == ByteOrder.BIG_ENDIAN) {
9821001
return (short) (_getByte(index) & 0xff | (_getByte(index + 1) & 0xff) << 8);
9831002
} else {
@@ -989,7 +1008,8 @@ protected short _getShortLE(int index) {
9891008
protected int _getUnsignedMedium(int index) {
9901009
Component c = findComponent0(index);
9911010
if (index + 3 <= c.endOffset) {
992-
return c.buf.getUnsignedMedium(c.idx(index));
1011+
return c.abuf != null ? c.abuf._getUnsignedMedium(c.idx(index))
1012+
: c.buf.getUnsignedMedium(c.idx(index));
9931013
} else if (order() == ByteOrder.BIG_ENDIAN) {
9941014
return (_getShort(index) & 0xffff) << 8 | _getByte(index + 2) & 0xff;
9951015
} else {
@@ -1001,7 +1021,8 @@ protected int _getUnsignedMedium(int index) {
10011021
protected int _getUnsignedMediumLE(int index) {
10021022
Component c = findComponent0(index);
10031023
if (index + 3 <= c.endOffset) {
1004-
return c.buf.getUnsignedMediumLE(c.idx(index));
1024+
return c.abuf != null ? c.abuf._getUnsignedMediumLE(c.idx(index))
1025+
: c.buf.getUnsignedMediumLE(c.idx(index));
10051026
} else if (order() == ByteOrder.BIG_ENDIAN) {
10061027
return _getShortLE(index) & 0xffff | (_getByte(index + 2) & 0xff) << 16;
10071028
} else {
@@ -1013,7 +1034,7 @@ protected int _getUnsignedMediumLE(int index) {
10131034
protected int _getInt(int index) {
10141035
Component c = findComponent0(index);
10151036
if (index + 4 <= c.endOffset) {
1016-
return c.buf.getInt(c.idx(index));
1037+
return c.abuf != null ? c.abuf._getInt(c.idx(index)) : c.buf.getInt(c.idx(index));
10171038
} else if (order() == ByteOrder.BIG_ENDIAN) {
10181039
return (_getShort(index) & 0xffff) << 16 | _getShort(index + 2) & 0xffff;
10191040
} else {
@@ -1025,7 +1046,7 @@ protected int _getInt(int index) {
10251046
protected int _getIntLE(int index) {
10261047
Component c = findComponent0(index);
10271048
if (index + 4 <= c.endOffset) {
1028-
return c.buf.getIntLE(c.idx(index));
1049+
return c.abuf != null ? c.abuf._getIntLE(c.idx(index)) : c.buf.getIntLE(c.idx(index));
10291050
} else if (order() == ByteOrder.BIG_ENDIAN) {
10301051
return _getShortLE(index) & 0xffff | (_getShortLE(index + 2) & 0xffff) << 16;
10311052
} else {
@@ -1037,7 +1058,7 @@ protected int _getIntLE(int index) {
10371058
protected long _getLong(int index) {
10381059
Component c = findComponent0(index);
10391060
if (index + 8 <= c.endOffset) {
1040-
return c.buf.getLong(c.idx(index));
1061+
return c.abuf != null ? c.abuf._getLong(c.idx(index)) : c.buf.getLong(c.idx(index));
10411062
} else if (order() == ByteOrder.BIG_ENDIAN) {
10421063
return (_getInt(index) & 0xffffffffL) << 32 | _getInt(index + 4) & 0xffffffffL;
10431064
} else {
@@ -1049,7 +1070,7 @@ protected long _getLong(int index) {
10491070
protected long _getLongLE(int index) {
10501071
Component c = findComponent0(index);
10511072
if (index + 8 <= c.endOffset) {
1052-
return c.buf.getLongLE(c.idx(index));
1073+
return c.abuf != null ? c.abuf._getLongLE(c.idx(index)) : c.buf.getLongLE(c.idx(index));
10531074
} else if (order() == ByteOrder.BIG_ENDIAN) {
10541075
return _getIntLE(index) & 0xffffffffL | (_getIntLE(index + 4) & 0xffffffffL) << 32;
10551076
} else {
@@ -1180,14 +1201,22 @@ public CompositeByteBuf getBytes(int index, OutputStream out, int length) throws
11801201
@Override
11811202
public CompositeByteBuf setByte(int index, int value) {
11821203
Component c = findComponent(index);
1183-
c.buf.setByte(c.idx(index), value);
1204+
if (c.abuf != null) {
1205+
c.abuf._setByte(c.idx(index), value);
1206+
} else {
1207+
c.buf.setByte(c.idx(index), value);
1208+
}
11841209
return this;
11851210
}
11861211

11871212
@Override
11881213
protected void _setByte(int index, int value) {
11891214
Component c = findComponent0(index);
1190-
c.buf.setByte(c.idx(index), value);
1215+
if (c.abuf != null) {
1216+
c.abuf._setByte(c.idx(index), value);
1217+
} else {
1218+
c.buf.setByte(c.idx(index), value);
1219+
}
11911220
}
11921221

11931222
@Override
@@ -1201,7 +1230,11 @@ public CompositeByteBuf setShort(int index, int value) {
12011230
protected void _setShort(int index, int value) {
12021231
Component c = findComponent0(index);
12031232
if (index + 2 <= c.endOffset) {
1204-
c.buf.setShort(c.idx(index), value);
1233+
if (c.abuf != null) {
1234+
c.abuf._setShort(c.idx(index), value);
1235+
} else {
1236+
c.buf.setShort(c.idx(index), value);
1237+
}
12051238
} else if (order() == ByteOrder.BIG_ENDIAN) {
12061239
_setByte(index, (byte) (value >>> 8));
12071240
_setByte(index + 1, (byte) value);
@@ -1215,7 +1248,11 @@ protected void _setShort(int index, int value) {
12151248
protected void _setShortLE(int index, int value) {
12161249
Component c = findComponent0(index);
12171250
if (index + 2 <= c.endOffset) {
1218-
c.buf.setShortLE(c.idx(index), value);
1251+
if (c.abuf != null) {
1252+
c.abuf._setShortLE(c.idx(index), value);
1253+
} else {
1254+
c.buf.setShortLE(c.idx(index), value);
1255+
}
12191256
} else if (order() == ByteOrder.BIG_ENDIAN) {
12201257
_setByte(index, (byte) value);
12211258
_setByte(index + 1, (byte) (value >>> 8));
@@ -1236,7 +1273,11 @@ public CompositeByteBuf setMedium(int index, int value) {
12361273
protected void _setMedium(int index, int value) {
12371274
Component c = findComponent0(index);
12381275
if (index + 3 <= c.endOffset) {
1239-
c.buf.setMedium(c.idx(index), value);
1276+
if (c.abuf != null) {
1277+
c.abuf._setMedium(c.idx(index), value);
1278+
} else {
1279+
c.buf.setMedium(c.idx(index), value);
1280+
}
12401281
} else if (order() == ByteOrder.BIG_ENDIAN) {
12411282
_setShort(index, (short) (value >> 8));
12421283
_setByte(index + 2, (byte) value);
@@ -1250,7 +1291,11 @@ protected void _setMedium(int index, int value) {
12501291
protected void _setMediumLE(int index, int value) {
12511292
Component c = findComponent0(index);
12521293
if (index + 3 <= c.endOffset) {
1253-
c.buf.setMediumLE(c.idx(index), value);
1294+
if (c.abuf != null) {
1295+
c.abuf._setMediumLE(c.idx(index), value);
1296+
} else {
1297+
c.buf.setMediumLE(c.idx(index), value);
1298+
}
12541299
} else if (order() == ByteOrder.BIG_ENDIAN) {
12551300
_setShortLE(index, (short) value);
12561301
_setByte(index + 2, (byte) (value >>> 16));
@@ -1271,7 +1316,11 @@ public CompositeByteBuf setInt(int index, int value) {
12711316
protected void _setInt(int index, int value) {
12721317
Component c = findComponent0(index);
12731318
if (index + 4 <= c.endOffset) {
1274-
c.buf.setInt(c.idx(index), value);
1319+
if (c.abuf != null) {
1320+
c.abuf._setInt(c.idx(index), value);
1321+
} else {
1322+
c.buf.setInt(c.idx(index), value);
1323+
}
12751324
} else if (order() == ByteOrder.BIG_ENDIAN) {
12761325
_setShort(index, (short) (value >>> 16));
12771326
_setShort(index + 2, (short) value);
@@ -1285,7 +1334,11 @@ protected void _setInt(int index, int value) {
12851334
protected void _setIntLE(int index, int value) {
12861335
Component c = findComponent0(index);
12871336
if (index + 4 <= c.endOffset) {
1288-
c.buf.setIntLE(c.idx(index), value);
1337+
if (c.abuf != null) {
1338+
c.abuf._setIntLE(c.idx(index), value);
1339+
} else {
1340+
c.buf.setIntLE(c.idx(index), value);
1341+
}
12891342
} else if (order() == ByteOrder.BIG_ENDIAN) {
12901343
_setShortLE(index, (short) value);
12911344
_setShortLE(index + 2, (short) (value >>> 16));
@@ -1306,7 +1359,11 @@ public CompositeByteBuf setLong(int index, long value) {
13061359
protected void _setLong(int index, long value) {
13071360
Component c = findComponent0(index);
13081361
if (index + 8 <= c.endOffset) {
1309-
c.buf.setLong(c.idx(index), value);
1362+
if (c.abuf != null) {
1363+
c.abuf._setLong(c.idx(index), value);
1364+
} else {
1365+
c.buf.setLong(c.idx(index), value);
1366+
}
13101367
} else if (order() == ByteOrder.BIG_ENDIAN) {
13111368
_setInt(index, (int) (value >>> 32));
13121369
_setInt(index + 4, (int) value);
@@ -1320,7 +1377,11 @@ protected void _setLong(int index, long value) {
13201377
protected void _setLongLE(int index, long value) {
13211378
Component c = findComponent0(index);
13221379
if (index + 8 <= c.endOffset) {
1323-
c.buf.setLongLE(c.idx(index), value);
1380+
if (c.abuf != null) {
1381+
c.abuf._setLongLE(c.idx(index), value);
1382+
} else {
1383+
c.buf.setLongLE(c.idx(index), value);
1384+
}
13241385
} else if (order() == ByteOrder.BIG_ENDIAN) {
13251386
_setIntLE(index, (int) value);
13261387
_setIntLE(index + 4, (int) (value >>> 32));
@@ -1613,6 +1674,7 @@ public ByteBuf internalComponentAtOffset(int offset) {
16131674

16141675
// weak cache - check it first when looking for component
16151676
private Component lastAccessed;
1677+
private int lastAccessedIndex;
16161678

16171679
private Component findComponent(int offset) {
16181680
Component la = lastAccessed;
@@ -1632,6 +1694,22 @@ private Component findComponent0(int offset) {
16321694
return findIt(offset);
16331695
}
16341696

1697+
/**
1698+
* Sequential-read fast path: try the next component(s) before falling back to binary search.
1699+
*/
1700+
private Component findComponentForRead(int offset) {
1701+
int cc = componentCount;
1702+
for (int next = lastAccessedIndex + 1; next < cc; next++) {
1703+
Component c = components[next];
1704+
if (c.endOffset > c.offset) {
1705+
lastAccessed = c;
1706+
lastAccessedIndex = next;
1707+
return c;
1708+
}
1709+
}
1710+
return findIt(offset);
1711+
}
1712+
16351713
private Component findIt(int offset) {
16361714
for (int low = 0, high = componentCount; low <= high;) {
16371715
int mid = low + high >>> 1;
@@ -1646,6 +1724,7 @@ private Component findIt(int offset) {
16461724
high = mid - 1;
16471725
} else {
16481726
lastAccessed = c;
1727+
lastAccessedIndex = mid;
16491728
return c;
16501729
}
16511730
}
@@ -1785,6 +1864,7 @@ private void consolidate0(int cIndex, int numComponents) {
17851864
components[i].transferTo(consolidated);
17861865
}
17871866
lastAccessed = null;
1867+
lastAccessedIndex = 0;
17881868
removeCompRange(cIndex + 1, endCIndex);
17891869
components[cIndex] = newComponent(consolidated, 0);
17901870
if (cIndex != 0 || numComponents != componentCount) {
@@ -1809,6 +1889,7 @@ public CompositeByteBuf discardReadComponents() {
18091889
components[i].free();
18101890
}
18111891
lastAccessed = null;
1892+
lastAccessedIndex = 0;
18121893
clearComps();
18131894
setIndex(0, 0);
18141895
adjustMarkers(readerIndex);
@@ -1831,6 +1912,7 @@ public CompositeByteBuf discardReadComponents() {
18311912
Component la = lastAccessed;
18321913
if (la != null && la.endOffset <= readerIndex) {
18331914
lastAccessed = null;
1915+
lastAccessedIndex = 0;
18341916
}
18351917
removeCompRange(0, firstComponentId);
18361918

@@ -1857,6 +1939,7 @@ public CompositeByteBuf discardReadBytes() {
18571939
components[i].free();
18581940
}
18591941
lastAccessed = null;
1942+
lastAccessedIndex = 0;
18601943
clearComps();
18611944
setIndex(0, 0);
18621945
adjustMarkers(readerIndex);
@@ -1888,6 +1971,7 @@ public CompositeByteBuf discardReadBytes() {
18881971
Component la = lastAccessed;
18891972
if (la != null && la.endOffset <= readerIndex) {
18901973
lastAccessed = null;
1974+
lastAccessedIndex = 0;
18911975
}
18921976

18931977
removeCompRange(0, firstComponentId);
@@ -1913,6 +1997,7 @@ public String toString() {
19131997
private static final class Component {
19141998
final ByteBuf srcBuf; // the originally added buffer
19151999
final ByteBuf buf; // srcBuf unwrapped zero or more times
2000+
final AbstractByteBuf abuf; // buf cast to AbstractByteBuf, or null if not an instance
19162001

19172002
int srcAdjustment; // index of the start of this CompositeByteBuf relative to srcBuf
19182003
int adjustment; // index of the start of this CompositeByteBuf relative to buf
@@ -1927,6 +2012,7 @@ private static final class Component {
19272012
this.srcBuf = srcBuf;
19282013
this.srcAdjustment = srcOffset - offset;
19292014
this.buf = buf;
2015+
this.abuf = buf instanceof AbstractByteBuf ? (AbstractByteBuf) buf : null;
19302016
this.adjustment = bufOffset - offset;
19312017
this.offset = offset;
19322018
this.endOffset = offset + len;

0 commit comments

Comments
 (0)