Skip to content

Commit 44b64e4

Browse files
ndimidukjinhyukify
andauthored
HBASE-28600 Enable setting blockcache on-heap sizes in bytes (#6422) (#6529)
Signed-off-by: Nick Dimiduk <[email protected]> Co-authored-by: JinHyuk Kim <[email protected]>
1 parent 3db58b1 commit 44b64e4

File tree

5 files changed

+79
-26
lines changed

5 files changed

+79
-26
lines changed

hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,11 @@ public enum OperationStatusCode {
10121012

10131013
public static final float HFILE_BLOCK_CACHE_SIZE_DEFAULT = 0.4f;
10141014

1015+
/**
1016+
* Configuration key for the memory size of the block cache
1017+
*/
1018+
public static final String HFILE_BLOCK_CACHE_MEMORY_SIZE_KEY = "hfile.block.cache.memory.size";
1019+
10151020
/**
10161021
* Configuration key for setting the fix size of the block size, default do nothing and it should
10171022
* be explicitly set by user or only used within ClientSideRegionScanner. if it's set less than

hbase-common/src/main/resources/hbase-default.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,14 @@ possible configurations would overwhelm and obscure the important.
10101010
Set to 0 to disable but it's not recommended; you need at least
10111011
enough cache to hold the storefile indices.</description>
10121012
</property>
1013+
<property>
1014+
<name>hfile.block.cache.memory.size</name>
1015+
<value></value>
1016+
<description>Defines the maximum heap memory allocated for the HFile block cache,
1017+
specified in bytes or human-readable formats like '10m' for megabytes or '10g' for gigabytes.
1018+
This configuration allows setting an absolute memory size instead of a percentage of the maximum heap.
1019+
Takes precedence over hfile.block.cache.size if both are specified.</description>
1020+
</property>
10131021
<property>
10141022
<name>hfile.block.index.cacheonwrite</name>
10151023
<value>false</value>

hbase-server/src/main/java/org/apache/hadoop/hbase/io/util/MemorySizeUtil.java

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.lang.management.MemoryType;
2222
import java.lang.management.MemoryUsage;
2323
import org.apache.hadoop.conf.Configuration;
24+
import org.apache.hadoop.conf.StorageUnit;
2425
import org.apache.hadoop.hbase.HConstants;
2526
import org.apache.hadoop.hbase.regionserver.MemStoreLAB;
2627
import org.apache.hadoop.hbase.util.Pair;
@@ -93,11 +94,16 @@ public static void checkForClusterFreeHeapMemoryLimit(Configuration conf) {
9394
) {
9495
throw new RuntimeException("Current heap configuration for MemStore and BlockCache exceeds "
9596
+ "the threshold required for successful cluster operation. "
96-
+ "The combined value cannot exceed 0.8. Please check "
97-
+ "the settings for hbase.regionserver.global.memstore.size and "
98-
+ "hfile.block.cache.size in your configuration. "
99-
+ "hbase.regionserver.global.memstore.size is " + globalMemstoreSize
100-
+ " hfile.block.cache.size is " + blockCacheUpperLimit);
97+
+ "The combined value cannot exceed 0.8. Please check " + "the settings for "
98+
+ MEMSTORE_SIZE_KEY + " and either " + HConstants.HFILE_BLOCK_CACHE_MEMORY_SIZE_KEY + " or "
99+
+ HConstants.HFILE_BLOCK_CACHE_SIZE_KEY + " in your configuration. " + MEMSTORE_SIZE_KEY
100+
+ "=" + globalMemstoreSize + ", " + HConstants.HFILE_BLOCK_CACHE_MEMORY_SIZE_KEY + "="
101+
+ conf.get(HConstants.HFILE_BLOCK_CACHE_MEMORY_SIZE_KEY) + ", "
102+
+ HConstants.HFILE_BLOCK_CACHE_SIZE_KEY + "="
103+
+ conf.get(HConstants.HFILE_BLOCK_CACHE_SIZE_KEY) + ". (Note: If both "
104+
+ HConstants.HFILE_BLOCK_CACHE_MEMORY_SIZE_KEY + " and "
105+
+ HConstants.HFILE_BLOCK_CACHE_SIZE_KEY + " are set, " + "the system will use "
106+
+ HConstants.HFILE_BLOCK_CACHE_MEMORY_SIZE_KEY + ")");
101107
}
102108
}
103109

@@ -195,10 +201,30 @@ public static long getOnheapGlobalMemStoreSize(Configuration conf) {
195201
* Retrieve configured size for on heap block cache as percentage of total heap.
196202
*/
197203
public static float getBlockCacheHeapPercent(final Configuration conf) {
198-
// L1 block cache is always on heap
199-
float l1CachePercent = conf.getFloat(HConstants.HFILE_BLOCK_CACHE_SIZE_KEY,
204+
// Check if an explicit block cache size is configured.
205+
long l1CacheSizeInBytes = getBlockCacheSizeInBytes(conf);
206+
if (l1CacheSizeInBytes > 0) {
207+
final MemoryUsage usage = safeGetHeapMemoryUsage();
208+
return usage == null ? 0 : (float) l1CacheSizeInBytes / usage.getMax();
209+
}
210+
211+
return conf.getFloat(HConstants.HFILE_BLOCK_CACHE_SIZE_KEY,
200212
HConstants.HFILE_BLOCK_CACHE_SIZE_DEFAULT);
201-
return l1CachePercent;
213+
}
214+
215+
/**
216+
* Retrieve an explicit block cache size in bytes in the configuration.
217+
* @param conf used to read cache configs
218+
* @return the number of bytes to use for LRU, negative if disabled.
219+
* @throws IllegalArgumentException if HFILE_BLOCK_CACHE_MEMORY_SIZE_KEY format is invalid
220+
*/
221+
public static long getBlockCacheSizeInBytes(Configuration conf) {
222+
final String key = HConstants.HFILE_BLOCK_CACHE_MEMORY_SIZE_KEY;
223+
try {
224+
return Long.parseLong(conf.get(key));
225+
} catch (NumberFormatException e) {
226+
return (long) conf.getStorageSize(key, -1, StorageUnit.BYTES);
227+
}
202228
}
203229

204230
/**
@@ -207,27 +233,30 @@ public static float getBlockCacheHeapPercent(final Configuration conf) {
207233
* @throws IllegalArgumentException if HFILE_BLOCK_CACHE_SIZE_KEY is > 1.0
208234
*/
209235
public static long getOnHeapCacheSize(final Configuration conf) {
210-
float cachePercentage = conf.getFloat(HConstants.HFILE_BLOCK_CACHE_SIZE_KEY,
211-
HConstants.HFILE_BLOCK_CACHE_SIZE_DEFAULT);
236+
final float cachePercentage = getBlockCacheHeapPercent(conf);
212237
if (cachePercentage <= 0.0001f) {
213238
return -1;
214239
}
215240
if (cachePercentage > 1.0) {
216241
throw new IllegalArgumentException(
217242
HConstants.HFILE_BLOCK_CACHE_SIZE_KEY + " must be between 0.0 and 1.0, and not > 1.0");
218243
}
219-
long max = -1L;
244+
220245
final MemoryUsage usage = safeGetHeapMemoryUsage();
221-
if (usage != null) {
222-
max = usage.getMax();
246+
if (usage == null) {
247+
return -1;
223248
}
249+
final long heapMax = usage.getMax();
224250
float onHeapCacheFixedSize =
225251
(float) conf.getLong(HConstants.HFILE_ONHEAP_BLOCK_CACHE_FIXED_SIZE_KEY,
226-
HConstants.HFILE_ONHEAP_BLOCK_CACHE_FIXED_SIZE_DEFAULT) / max;
252+
HConstants.HFILE_ONHEAP_BLOCK_CACHE_FIXED_SIZE_DEFAULT) / heapMax;
227253
// Calculate the amount of heap to give the heap.
228-
return (onHeapCacheFixedSize > 0 && onHeapCacheFixedSize < cachePercentage)
229-
? (long) (max * onHeapCacheFixedSize)
230-
: (long) (max * cachePercentage);
254+
if (onHeapCacheFixedSize > 0 && onHeapCacheFixedSize < cachePercentage) {
255+
return (long) (heapMax * onHeapCacheFixedSize);
256+
} else {
257+
final long cacheSizeInBytes = getBlockCacheSizeInBytes(conf);
258+
return cacheSizeInBytes > 0 ? cacheSizeInBytes : (long) (heapMax * cachePercentage);
259+
}
231260
}
232261

233262
/**
@@ -243,5 +272,4 @@ public static long getBucketCacheSize(final Configuration conf) {
243272
}
244273
return (long) (bucketCacheSize * 1024 * 1024);
245274
}
246-
247275
}

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

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
package org.apache.hadoop.hbase.regionserver;
1919

20+
import static org.apache.hadoop.hbase.HConstants.HFILE_BLOCK_CACHE_MEMORY_SIZE_KEY;
2021
import static org.apache.hadoop.hbase.HConstants.HFILE_BLOCK_CACHE_SIZE_KEY;
2122

2223
import java.lang.management.MemoryUsage;
@@ -128,8 +129,7 @@ private ResizableBlockCache toResizableBlockCache(BlockCache blockCache) {
128129
private boolean doInit(Configuration conf) {
129130
boolean tuningEnabled = true;
130131
globalMemStorePercent = MemorySizeUtil.getGlobalMemStoreHeapPercent(conf, false);
131-
blockCachePercent =
132-
conf.getFloat(HFILE_BLOCK_CACHE_SIZE_KEY, HConstants.HFILE_BLOCK_CACHE_SIZE_DEFAULT);
132+
blockCachePercent = MemorySizeUtil.getBlockCacheHeapPercent(conf);
133133
MemorySizeUtil.checkForClusterFreeHeapMemoryLimit(conf);
134134
// Initialize max and min range for memstore heap space
135135
globalMemStorePercentMinRange =
@@ -160,16 +160,20 @@ private boolean doInit(Configuration conf) {
160160
blockCachePercentMinRange = conf.getFloat(BLOCK_CACHE_SIZE_MIN_RANGE_KEY, blockCachePercent);
161161
blockCachePercentMaxRange = conf.getFloat(BLOCK_CACHE_SIZE_MAX_RANGE_KEY, blockCachePercent);
162162
if (blockCachePercent < blockCachePercentMinRange) {
163-
LOG.warn("Setting " + BLOCK_CACHE_SIZE_MIN_RANGE_KEY + " to " + blockCachePercent
164-
+ ", same value as " + HFILE_BLOCK_CACHE_SIZE_KEY
165-
+ " because supplied value greater than initial block cache size.");
163+
LOG.warn(
164+
"Setting {} to {} (lookup order: {} -> {}), "
165+
+ "because supplied value greater than initial block cache size.",
166+
BLOCK_CACHE_SIZE_MIN_RANGE_KEY, blockCachePercent, HFILE_BLOCK_CACHE_MEMORY_SIZE_KEY,
167+
HFILE_BLOCK_CACHE_SIZE_KEY);
166168
blockCachePercentMinRange = blockCachePercent;
167169
conf.setFloat(BLOCK_CACHE_SIZE_MIN_RANGE_KEY, blockCachePercentMinRange);
168170
}
169171
if (blockCachePercent > blockCachePercentMaxRange) {
170-
LOG.warn("Setting " + BLOCK_CACHE_SIZE_MAX_RANGE_KEY + " to " + blockCachePercent
171-
+ ", same value as " + HFILE_BLOCK_CACHE_SIZE_KEY
172-
+ " because supplied value less than initial block cache size.");
172+
LOG.warn(
173+
"Setting {} to {} (lookup order: {} -> {}), "
174+
+ "because supplied value less than initial block cache size.",
175+
BLOCK_CACHE_SIZE_MAX_RANGE_KEY, blockCachePercent, HFILE_BLOCK_CACHE_MEMORY_SIZE_KEY,
176+
HFILE_BLOCK_CACHE_SIZE_KEY);
173177
blockCachePercentMaxRange = blockCachePercent;
174178
conf.setFloat(BLOCK_CACHE_SIZE_MAX_RANGE_KEY, blockCachePercentMaxRange);
175179
}

hbase-server/src/test/java/org/apache/hadoop/hbase/io/hfile/TestCacheConfig.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,14 @@ public void testGetOnHeapCacheSize() {
396396
long onHeapCacheSize = MemorySizeUtil.getOnHeapCacheSize(copyConf);
397397
assertEquals(null, copyConf.get(HConstants.HFILE_ONHEAP_BLOCK_CACHE_FIXED_SIZE_KEY));
398398
assertTrue(onHeapCacheSize > 0 && onHeapCacheSize != fixedSize);
399+
// when HBASE_BLOCK_CACHE_MEMORY_SIZE is set in number
400+
copyConf.setLong(HConstants.HFILE_BLOCK_CACHE_MEMORY_SIZE_KEY, 3 * 1024 * 1024);
401+
onHeapCacheSize = MemorySizeUtil.getOnHeapCacheSize(copyConf);
402+
assertEquals(3 * 1024 * 1024, onHeapCacheSize);
403+
// when HBASE_BLOCK_CACHE_MEMORY_SIZE is set in human-readable format
404+
copyConf.set(HConstants.HFILE_BLOCK_CACHE_MEMORY_SIZE_KEY, "2m");
405+
onHeapCacheSize = MemorySizeUtil.getOnHeapCacheSize(copyConf);
406+
assertEquals(2 * 1024 * 1024, onHeapCacheSize);
399407
// when HBASE_BLOCK_CACHE_FIXED_SIZE_KEY is set, it will be a fixed size
400408
copyConf.setLong(HConstants.HFILE_ONHEAP_BLOCK_CACHE_FIXED_SIZE_KEY, fixedSize);
401409
onHeapCacheSize = MemorySizeUtil.getOnHeapCacheSize(copyConf);

0 commit comments

Comments
 (0)