5050 * greater than the requested capacity; however, their {@link ByteBuffer#limit(int)}
5151 * is set to the requested capacity.
5252 *
53- * @since 5.7
53+ * @since 5.4
5454 */
5555@ Contract (threading = ThreadingBehavior .SAFE )
5656public final class PooledByteBufferAllocator implements ByteBufferAllocator {
@@ -73,8 +73,10 @@ private static final class LocalCache {
7373 final Deque <ByteBuffer >[] directBuckets ;
7474
7575 LocalCache (final int bucketCount ) {
76- @ SuppressWarnings ("unchecked" ) final Deque <ByteBuffer >[] heap = new Deque [bucketCount ];
77- @ SuppressWarnings ("unchecked" ) final Deque <ByteBuffer >[] direct = new Deque [bucketCount ];
76+ @ SuppressWarnings ("unchecked" )
77+ final Deque <ByteBuffer >[] heap = new Deque [bucketCount ];
78+ @ SuppressWarnings ("unchecked" )
79+ final Deque <ByteBuffer >[] direct = new Deque [bucketCount ];
7880 for (int i = 0 ; i < bucketCount ; i ++) {
7981 heap [i ] = new ArrayDeque <>();
8082 direct [i ] = new ArrayDeque <>();
@@ -87,6 +89,7 @@ private static final class LocalCache {
8789
8890 private final int minCapacity ;
8991 private final int maxCapacity ;
92+ private final int minShift ;
9093 private final int [] bucketCapacities ;
9194 private final GlobalBucket [] heapBuckets ;
9295 private final GlobalBucket [] directBuckets ;
@@ -121,9 +124,11 @@ public PooledByteBufferAllocator(
121124 this .maxGlobalPerBucket = maxGlobalPerBucket ;
122125 this .maxLocalPerBucket = maxLocalPerBucket ;
123126
124- final int bucketCount = bucketCount (this .minCapacity , this .maxCapacity );
125- this .bucketCapacities = new int [bucketCount ];
127+ this .minShift = Integer .numberOfTrailingZeros (this .minCapacity );
128+ final int maxShift = Integer .numberOfTrailingZeros (this .maxCapacity );
129+ final int bucketCount = maxShift - this .minShift + 1 ;
126130
131+ this .bucketCapacities = new int [bucketCount ];
127132 this .heapBuckets = new GlobalBucket [bucketCount ];
128133 this .directBuckets = new GlobalBucket [bucketCount ];
129134
@@ -149,30 +154,24 @@ private static int normalizeCapacity(final int capacity) {
149154 return normalized ;
150155 }
151156
152- private static int bucketCount (final int minCapacity , final int maxCapacity ) {
153- int count = 0 ;
154- int capacity = minCapacity ;
155- while (capacity <= maxCapacity ) {
156- count ++;
157- capacity <<= 1 ;
158- }
159- return count ;
160- }
161-
157+ /**
158+ * Returns the bucket index for the given capacity, or {@code -1} if the
159+ * capacity is greater than {@code maxCapacity}.
160+ * <p>
161+ * This implementation runs in O(1) using bit operations. It assumes
162+ * {@code minCapacity} and {@code maxCapacity} are powers of two.
163+ */
162164 private int bucketIndex (final int capacity ) {
163165 if (capacity <= minCapacity ) {
164166 return 0 ;
165167 }
166168 if (capacity > maxCapacity ) {
167169 return -1 ;
168170 }
169- int idx = 0 ;
170- int current = minCapacity ;
171- while (current < capacity && current < maxCapacity ) {
172- current <<= 1 ;
173- idx ++;
174- }
175- if (idx >= bucketCapacities .length ) {
171+ // Ceil(log2(capacity)) using bit length of (capacity - 1).
172+ final int neededShift = 32 - Integer .numberOfLeadingZeros (capacity - 1 );
173+ final int idx = neededShift - minShift ;
174+ if (idx < 0 || idx >= bucketCapacities .length ) {
176175 return -1 ;
177176 }
178177 return idx ;
@@ -188,8 +187,6 @@ private ByteBuffer allocateInternal(final int requestedCapacity, final boolean d
188187 : ByteBuffer .allocate (requestedCapacity );
189188 }
190189
191- final int bucketCapacity = bucketCapacities [idx ];
192-
193190 final LocalCache cache = localCache .get ();
194191 final Deque <ByteBuffer >[] localBuckets = direct
195192 ? cache .directBuckets
@@ -214,6 +211,7 @@ private ByteBuffer allocateInternal(final int requestedCapacity, final boolean d
214211 return buf ;
215212 }
216213
214+ final int bucketCapacity = bucketCapacities [idx ];
217215 buf = direct
218216 ? ByteBuffer .allocateDirect (bucketCapacity )
219217 : ByteBuffer .allocate (bucketCapacity );
@@ -249,21 +247,24 @@ public void release(final ByteBuffer buffer) {
249247 : cache .heapBuckets ;
250248 final Deque <ByteBuffer > local = localBuckets [idx ];
251249
250+ buffer .clear ();
251+ buffer .limit (bucketCapacities [idx ]);
252+
252253 if (local .size () < maxLocalPerBucket ) {
253- buffer .clear ();
254- buffer .limit (bucketCapacities [idx ]);
255254 local .addFirst (buffer );
256255 return ;
257256 }
258257
258+ if (maxGlobalPerBucket == 0 ) {
259+ return ;
260+ }
261+
259262 final GlobalBucket [] globalArray = direct ? directBuckets : heapBuckets ;
260263 final GlobalBucket global = globalArray [idx ];
261264 final int current = global .size .get ();
262265 if (current >= maxGlobalPerBucket ) {
263266 return ;
264267 }
265- buffer .clear ();
266- buffer .limit (bucketCapacities [idx ]);
267268 global .queue .offer (buffer );
268269 global .size .incrementAndGet ();
269270 }
0 commit comments