2323import java .util .Arrays ;
2424
2525/**
26- * Helper class that wraps a byte[] so that it can expand and be reused. Users should call
27- * resizeIfNecessary to make sure the buffer has suitable capacity, and then use the array as
28- * needed .
26+ * Helper class that wraps a byte[] so that it can expand and be reused. Incremental writes use
27+ * ensureCapacity; resizeIfNecessary also considers shrinking and must receive a complete frame's
28+ * size .
2929 *
3030 * <p>Resizing policies: Expanding: If the required size > current capacity * 1.5, expand to the
31- * required size, otherwise expand to current capacity * 1.5. Shrinking: If initial size < the
32- * required size < current capacity * 0.6, and such small requests last for more than 5 times,
33- * shrink to the middle of the required size and current capacity.
31+ * required size, otherwise expand to current capacity * 1.5 when the memory budget allows it.
32+ * Shrinking: If the required size < current capacity * 0.6, and such small requests last for more
33+ * than 5 times, shrink to the middle of the required size and current capacity. The required size
34+ * is bounded below by the initial capacity.
3435 */
3536class AutoResizingBuffer implements AutoCloseable {
3637
@@ -56,23 +57,28 @@ public AutoResizingBuffer(int initialCapacity) throws IOException {
5657 }
5758
5859 public void resizeIfNecessary (int size ) throws IOException {
59- reserveCurrentCapacityIfReleased ();
60+ ensureCapacity (size );
61+ size = Math .max (size , initialCapacity );
6062 final int currentCapacity = this .array .length ;
6163 final double loadFactor = 0.6 ;
64+ if (currentCapacity * loadFactor > size
65+ && bufTooLargeCounter -- <= 0
66+ && System .currentTimeMillis () - lastShrinkTime > RpcUtils .MIN_SHRINK_INTERVAL ) {
67+ resize (size + (currentCapacity - size ) / 2 , size );
68+ bufTooLargeCounter = RpcUtils .MAX_BUFFER_OVERSIZE_TIME ;
69+ lastShrinkTime = System .currentTimeMillis ();
70+ }
71+ }
72+
73+ void ensureCapacity (int size ) throws IOException {
74+ reserveCurrentCapacityIfReleased ();
75+ final int currentCapacity = this .array .length ;
6276 if (currentCapacity < size ) {
6377 // Increase by a factor of 1.5x
6478 int growCapacity = currentCapacity + (currentCapacity >> 1 );
6579 int newCapacity = Math .max (growCapacity , size );
66- resize (newCapacity );
80+ resize (newCapacity , size );
6781 bufTooLargeCounter = RpcUtils .MAX_BUFFER_OVERSIZE_TIME ;
68- } else if (size > initialCapacity
69- && currentCapacity * loadFactor > size
70- && bufTooLargeCounter -- <= 0
71- && System .currentTimeMillis () - lastShrinkTime > RpcUtils .MIN_SHRINK_INTERVAL ) {
72- // do not resize if it is reading the request size and do not shrink too often
73- resize (size + (currentCapacity - size ) / 2 );
74- bufTooLargeCounter = RpcUtils .MAX_BUFFER_OVERSIZE_TIME ;
75- lastShrinkTime = System .currentTimeMillis ();
7682 }
7783 }
7884
@@ -89,11 +95,14 @@ public void close() {
8995 }
9096 }
9197
92- private void resize (int newCapacity ) throws IOException {
98+ private void resize (int newCapacity , int requiredCapacity ) throws IOException {
9399 final int currentCapacity = array .length ;
94100 if (newCapacity > currentCapacity ) {
95- final int delta = newCapacity - currentCapacity ;
96- memoryAccount .allocate (delta );
101+ final int delta =
102+ (int )
103+ memoryAccount .allocate (
104+ newCapacity - currentCapacity , requiredCapacity - currentCapacity );
105+ newCapacity = currentCapacity + delta ;
97106 try {
98107 array = Arrays .copyOf (array , newCapacity );
99108 accountedCapacity += delta ;
0 commit comments