Skip to content

Commit 00075ea

Browse files
authored
HBASE-22663 The HeapAllocationRatio in WebUI is not accurate because all of the heap allocation will happen in another separated allocator named HEAP (#365)
1 parent 1ad48c1 commit 00075ea

File tree

4 files changed

+60
-11
lines changed

4 files changed

+60
-11
lines changed

hbase-common/src/main/java/org/apache/hadoop/hbase/io/ByteBuffAllocator.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.slf4j.LoggerFactory;
3838

3939
import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
40+
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
4041

4142
/**
4243
* ByteBuffAllocator is used for allocating/freeing the ByteBuffers from/to NIO ByteBuffer pool, and
@@ -159,7 +160,10 @@ public interface Recycler {
159160
* reservoir is enabled and the reservoir has enough buffers, otherwise the allocator will just
160161
* allocate the insufficient buffers from on-heap to meet the requirement.
161162
* @param conf which get the arguments to initialize the allocator.
162-
* @param reservoirEnabled indicate whether the reservoir is enabled or disabled.
163+
* @param reservoirEnabled indicate whether the reservoir is enabled or disabled. NOTICE: if
164+
* reservoir is enabled, then we will use the pool allocator to allocate off-heap
165+
* ByteBuffers and use the HEAP allocator to allocate heap ByteBuffers. Otherwise if
166+
* reservoir is disabled then all allocations will happen in HEAP instance.
163167
* @return ByteBuffAllocator to manage the byte buffers.
164168
*/
165169
public static ByteBuffAllocator create(Configuration conf, boolean reservoirEnabled) {
@@ -192,7 +196,7 @@ public static ByteBuffAllocator create(Configuration conf, boolean reservoirEnab
192196
int minSizeForReservoirUse = conf.getInt(MIN_ALLOCATE_SIZE_KEY, poolBufSize / 6);
193197
return new ByteBuffAllocator(true, maxBuffCount, poolBufSize, minSizeForReservoirUse);
194198
} else {
195-
return new ByteBuffAllocator(false, 0, poolBufSize, Integer.MAX_VALUE);
199+
return HEAP;
196200
}
197201
}
198202

@@ -247,12 +251,22 @@ public int getTotalBufferCount() {
247251
return maxBufCount;
248252
}
249253

250-
public double getHeapAllocationRatio() {
251-
long heapAllocBytes = heapAllocationBytes.sum(), poolAllocBytes = poolAllocationBytes.sum();
252-
double heapDelta = heapAllocBytes - lastHeapAllocationBytes;
253-
double poolDelta = poolAllocBytes - lastPoolAllocationBytes;
254-
lastHeapAllocationBytes = heapAllocBytes;
255-
lastPoolAllocationBytes = poolAllocBytes;
254+
public static double getHeapAllocationRatio(ByteBuffAllocator... allocators) {
255+
double heapDelta = 0.0, poolDelta = 0.0;
256+
long heapAllocBytes, poolAllocBytes;
257+
// If disabled the pool allocator, then we use the global HEAP allocator. otherwise we use
258+
// the pool allocator to allocate offheap ByteBuffers and use the HEAP to allocate heap
259+
// ByteBuffers. So here we use a HashSet to remove the duplicated allocator object in disable
260+
// case.
261+
for (ByteBuffAllocator alloc : Sets.newHashSet(allocators)) {
262+
heapAllocBytes = alloc.heapAllocationBytes.sum();
263+
poolAllocBytes = alloc.poolAllocationBytes.sum();
264+
heapDelta += (heapAllocBytes - alloc.lastHeapAllocationBytes);
265+
poolDelta += (poolAllocBytes - alloc.lastPoolAllocationBytes);
266+
alloc.lastHeapAllocationBytes = heapAllocBytes;
267+
alloc.lastPoolAllocationBytes = poolAllocBytes;
268+
}
269+
// Calculate the heap allocation ratio.
256270
if (Math.abs(heapDelta + poolDelta) < 1e-3) {
257271
return 0.0;
258272
}

hbase-common/src/test/java/org/apache/hadoop/hbase/io/TestByteBuffAllocator.java

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
package org.apache.hadoop.hbase.io;
2020

21+
import static org.apache.hadoop.hbase.io.ByteBuffAllocator.HEAP;
22+
import static org.apache.hadoop.hbase.io.ByteBuffAllocator.getHeapAllocationRatio;
2123
import static org.junit.Assert.assertEquals;
2224
import static org.junit.Assert.assertFalse;
2325
import static org.junit.Assert.assertTrue;
@@ -162,7 +164,7 @@ public void testNegativeAllocatedSize() {
162164
@Test
163165
public void testAllocateOneBuffer() {
164166
// Allocate from on-heap
165-
ByteBuffAllocator allocator = ByteBuffAllocator.HEAP;
167+
ByteBuffAllocator allocator = HEAP;
166168
ByteBuff buf = allocator.allocateOneBuffer();
167169
assertTrue(buf.hasArray());
168170
assertEquals(ByteBuffAllocator.DEFAULT_BUFFER_SIZE, buf.remaining());
@@ -367,4 +369,37 @@ public void testDeprecatedConfigs() {
367369
conf.setBoolean(ByteBuffAllocator.ALLOCATOR_POOL_ENABLED_KEY, false);
368370
Assert.assertFalse(conf.getBoolean(ByteBuffAllocator.ALLOCATOR_POOL_ENABLED_KEY, true));
369371
}
372+
373+
@Test
374+
public void testHeapAllocationRatio() {
375+
Configuration conf = new Configuration();
376+
conf.setInt(ByteBuffAllocator.MAX_BUFFER_COUNT_KEY, 11);
377+
conf.setInt(ByteBuffAllocator.BUFFER_SIZE_KEY, 2048);
378+
ByteBuffAllocator alloc1 = ByteBuffAllocator.create(conf, true);
379+
Assert.assertEquals(getHeapAllocationRatio(alloc1), 0.0f, 1e-6);
380+
alloc1.allocate(1);
381+
Assert.assertEquals(getHeapAllocationRatio(alloc1), 1.0f, 1e-6);
382+
383+
alloc1.allocate(2048 / 6 - 1);
384+
Assert.assertEquals(getHeapAllocationRatio(alloc1), 1.0f, 1e-6);
385+
386+
alloc1.allocate(24);
387+
alloc1.allocate(1024);
388+
Assert.assertEquals(getHeapAllocationRatio(alloc1), 24 / (24f + 2048), 1e-6);
389+
Assert.assertEquals(getHeapAllocationRatio(alloc1), 0.0f, 1e-6);
390+
391+
// Allocate something from HEAP
392+
HEAP.allocate(1024);
393+
alloc1.allocate(24);
394+
alloc1.allocate(1024);
395+
Assert.assertEquals(getHeapAllocationRatio(HEAP, alloc1), (1024f + 24) / (1024f + 24 + 2048),
396+
1e-6);
397+
Assert.assertEquals(getHeapAllocationRatio(HEAP, alloc1), 0.0f, 1e-6);
398+
399+
// Check duplicated heap allocator, say even if we passed (HEAP, HEAP, alloc1), it will only
400+
// caculate the allocation from (HEAP, alloc1).
401+
HEAP.allocate(1024);
402+
alloc1.allocate(1024);
403+
Assert.assertEquals(getHeapAllocationRatio(HEAP, HEAP, alloc1), 1024f / (1024f + 2048f), 1e-6);
404+
}
370405
}

hbase-server/src/main/jamon/org/apache/hadoop/hbase/tmpl/regionserver/ServerMetricsTmpl.jamon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ ByteBuffAllocator bbAllocator;
248248
<tr>
249249
<td><% bbAllocator.getHeapAllocationBytes() %></td>
250250
<td><% bbAllocator.getPoolAllocationBytes() %></td>
251-
<td><% String.format("%.3f", bbAllocator.getHeapAllocationRatio() * 100) %><% "%" %></td>
251+
<td><% String.format("%.3f", ByteBuffAllocator.getHeapAllocationRatio(bbAllocator, ByteBuffAllocator.HEAP) * 100) %><% "%" %></td>
252252
<td><% bbAllocator.getTotalBufferCount() %></td>
253253
<td><% bbAllocator.getUsedBufferCount() %></td>
254254
<td><% bbAllocator.getBufferSize() %></td>

hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MetricsRegionServerWrapperImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1021,7 +1021,7 @@ public long getByteBuffAllocatorPoolAllocationBytes() {
10211021

10221022
@Override
10231023
public double getByteBuffAllocatorHeapAllocRatio() {
1024-
return this.allocator.getHeapAllocationRatio();
1024+
return ByteBuffAllocator.getHeapAllocationRatio(allocator, ByteBuffAllocator.HEAP);
10251025
}
10261026

10271027
@Override

0 commit comments

Comments
 (0)