You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ps...@apache.org on 2026/09/25 09:01:53 UTC

(hbase) branch HBASE-30018 updated: HBASE-30384 Add dynamic cache sizing support for CacheEngine-based caches (#8702)

This is an automated email from the ASF dual-hosted git repository.

petersomogyi pushed a commit to branch HBASE-30018
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/HBASE-30018 by this push:
     new 4fac6b8e932 HBASE-30384 Add dynamic cache sizing support for CacheEngine-based caches (#8702)
4fac6b8e932 is described below

commit 4fac6b8e932cad5aa2ad3819829a38517f46e64b
Author: Vladimir Rodionov <vl...@gmail.com>
AuthorDate: Fri Sep 25 02:01:46 2026 -0700

    HBASE-30384 Add dynamic cache sizing support for CacheEngine-based caches (#8702)
    
    Signed-off-by: Peter Somogyi <ps...@apache.org>
---
 .../hadoop/hbase/io/hfile/cache/CacheEngines.java  |  4 +++
 .../hbase/io/hfile/cache/LruCacheEngine.java       |  3 +-
 ...a => ResizableBlockCacheBackedCacheEngine.java} | 34 +++++++++++++---------
 ...CacheEngines.java => ResizableCacheEngine.java} | 28 +++++++-----------
 .../hbase/io/hfile/cache/TestCacheEngines.java     | 29 ++++++++++++++++--
 5 files changed, 63 insertions(+), 35 deletions(-)

diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngines.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngines.java
index a9707b11676..add7a69c385 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngines.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngines.java
@@ -19,6 +19,7 @@ package org.apache.hadoop.hbase.io.hfile.cache;
 
 import java.util.Objects;
 import org.apache.hadoop.hbase.io.hfile.BlockCache;
+import org.apache.hadoop.hbase.io.hfile.ResizableBlockCache;
 import org.apache.yetus.audience.InterfaceAudience;
 
 /**
@@ -43,6 +44,9 @@ public final class CacheEngines {
    */
   public static CacheEngine fromBlockCache(BlockCache blockCache) {
     Objects.requireNonNull(blockCache, "blockCache must not be null");
+    if (blockCache instanceof ResizableBlockCache) {
+      return new ResizableBlockCacheBackedCacheEngine((ResizableBlockCache) blockCache);
+    }
     return new BlockCacheBackedCacheEngine(blockCache);
   }
 }
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/LruCacheEngine.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/LruCacheEngine.java
index 2717a555314..53ad44e45d5 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/LruCacheEngine.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/LruCacheEngine.java
@@ -88,7 +88,7 @@ import org.apache.hbase.thirdparty.com.google.common.util.concurrent.ThreadFacto
  * </p>
  */
 @InterfaceAudience.Private
-public class LruCacheEngine implements CacheEngine, HeapSize, Iterable<CachedBlock> {
+public class LruCacheEngine implements ResizableCacheEngine, HeapSize, Iterable<CachedBlock> {
 
   private static final Logger LOG = LoggerFactory.getLogger(LruCacheEngine.class);
 
@@ -376,6 +376,7 @@ public class LruCacheEngine implements CacheEngine, HeapSize, Iterable<CachedBlo
    * </p>
    * @param maxSize new maximum size, in bytes
    */
+  @Override
   public void setMaxSize(long maxSize) {
     this.maxSize = maxSize;
     if (size.get() > acceptableSize() && !evictionInProgress) {
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngines.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/ResizableBlockCacheBackedCacheEngine.java
similarity index 50%
copy from hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngines.java
copy to hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/ResizableBlockCacheBackedCacheEngine.java
index a9707b11676..87627fe8ed4 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngines.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/ResizableBlockCacheBackedCacheEngine.java
@@ -18,31 +18,37 @@
 package org.apache.hadoop.hbase.io.hfile.cache;
 
 import java.util.Objects;
-import org.apache.hadoop.hbase.io.hfile.BlockCache;
+import org.apache.hadoop.hbase.io.hfile.ResizableBlockCache;
 import org.apache.yetus.audience.InterfaceAudience;
 
 /**
- * Factory helpers for {@link CacheEngine} instances.
+ * A {@link CacheEngine} adapter for a legacy {@link ResizableBlockCache}.
  * <p>
- * These helpers are intended to keep transitional wiring concise while existing cache
- * implementations are still based on {@link BlockCache}. Once built-in caches implement
- * {@link CacheEngine} directly, callers can construct or obtain those engines without going through
- * a legacy adapter.
+ * This adapter preserves the dynamic sizing capability while legacy block caches are being migrated
+ * to native {@link CacheEngine} implementations.
  * </p>
  */
 @InterfaceAudience.Private
-public final class CacheEngines {
+public class ResizableBlockCacheBackedCacheEngine extends BlockCacheBackedCacheEngine
+  implements ResizableCacheEngine {
 
-  private CacheEngines() {
+  private final ResizableBlockCache blockCache;
+
+  /**
+   * Creates an engine backed by the supplied resizable block cache.
+   * @param blockCache legacy resizable block cache
+   */
+  public ResizableBlockCacheBackedCacheEngine(ResizableBlockCache blockCache) {
+    super(Objects.requireNonNull(blockCache, "blockCache must not be null"));
+    this.blockCache = blockCache;
   }
 
   /**
-   * Wraps an existing {@link BlockCache} as a {@link CacheEngine}.
-   * @param blockCache block cache to adapt
-   * @return cache engine backed by the supplied block cache
+   * Changes the maximum size of the underlying block cache.
+   * @param maxSize new maximum cache size in bytes
    */
-  public static CacheEngine fromBlockCache(BlockCache blockCache) {
-    Objects.requireNonNull(blockCache, "blockCache must not be null");
-    return new BlockCacheBackedCacheEngine(blockCache);
+  @Override
+  public void setMaxSize(long maxSize) {
+    blockCache.setMaxSize(maxSize);
   }
 }
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngines.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/ResizableCacheEngine.java
similarity index 52%
copy from hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngines.java
copy to hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/ResizableCacheEngine.java
index a9707b11676..e650fee201c 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngines.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/ResizableCacheEngine.java
@@ -17,32 +17,24 @@
  */
 package org.apache.hadoop.hbase.io.hfile.cache;
 
-import java.util.Objects;
-import org.apache.hadoop.hbase.io.hfile.BlockCache;
 import org.apache.yetus.audience.InterfaceAudience;
 
 /**
- * Factory helpers for {@link CacheEngine} instances.
+ * A {@link CacheEngine} whose maximum size can be changed at runtime.
  * <p>
- * These helpers are intended to keep transitional wiring concise while existing cache
- * implementations are still based on {@link BlockCache}. Once built-in caches implement
- * {@link CacheEngine} directly, callers can construct or obtain those engines without going through
- * a legacy adapter.
+ * This capability is intentionally separate from {@link CacheEngine}. Cache engines which have a
+ * fixed capacity do not need to implement dynamic sizing.
  * </p>
  */
 @InterfaceAudience.Private
-public final class CacheEngines {
-
-  private CacheEngines() {
-  }
+public interface ResizableCacheEngine extends CacheEngine {
 
   /**
-   * Wraps an existing {@link BlockCache} as a {@link CacheEngine}.
-   * @param blockCache block cache to adapt
-   * @return cache engine backed by the supplied block cache
+   * Changes the maximum size of this cache engine.
+   * <p>
+   * Implementations may perform eviction as necessary to bring the cache within the new capacity.
+   * </p>
+   * @param maxSize new maximum cache size in bytes
    */
-  public static CacheEngine fromBlockCache(BlockCache blockCache) {
-    Objects.requireNonNull(blockCache, "blockCache must not be null");
-    return new BlockCacheBackedCacheEngine(blockCache);
-  }
+  void setMaxSize(long maxSize);
 }
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/io/hfile/cache/TestCacheEngines.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/io/hfile/cache/TestCacheEngines.java
index bd9d0bb49c1..2002e9ef2b0 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/io/hfile/cache/TestCacheEngines.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/io/hfile/cache/TestCacheEngines.java
@@ -17,12 +17,16 @@
  */
 package org.apache.hadoop.hbase.io.hfile.cache;
 
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
 import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
 import org.apache.hadoop.hbase.io.hfile.BlockCache;
+import org.apache.hadoop.hbase.io.hfile.ResizableBlockCache;
 import org.apache.hadoop.hbase.testclassification.IOTests;
 import org.apache.hadoop.hbase.testclassification.SmallTests;
 import org.junit.jupiter.api.Tag;
@@ -35,9 +39,7 @@ class TestCacheEngines {
   @Test
   void testFromBlockCacheReturnsBlockCacheBackedCacheEngine() {
     BlockCache blockCache = mock(BlockCache.class);
-
     CacheEngine engine = CacheEngines.fromBlockCache(blockCache);
-
     assertTrue(engine instanceof BlockCacheBackedCacheEngine);
     assertSame(blockCache, ((BlockCacheBackedCacheEngine) engine).getBlockCache());
   }
@@ -46,4 +48,27 @@ class TestCacheEngines {
   void testFromBlockCacheRejectsNull() {
     assertThrows(NullPointerException.class, () -> CacheEngines.fromBlockCache(null));
   }
+
+  /**
+   * Verifies that adapting a resizable legacy block cache preserves its dynamic sizing capability.
+   */
+  @Test
+  public void testResizableBlockCachePreservesResizeCapability() {
+    ResizableBlockCache blockCache = mock(ResizableBlockCache.class);
+    CacheEngine engine = CacheEngines.fromBlockCache(blockCache);
+    assertInstanceOf(ResizableCacheEngine.class, engine);
+    ResizableCacheEngine resizableEngine = (ResizableCacheEngine) engine;
+    resizableEngine.setMaxSize(12345L);
+    verify(blockCache).setMaxSize(12345L);
+  }
+
+  /**
+   * Verifies that adapting a non-resizable legacy block cache does not expose dynamic sizing.
+   */
+  @Test
+  public void testNonResizableBlockCacheDoesNotExposeResizeCapability() {
+    BlockCache blockCache = mock(BlockCache.class);
+    CacheEngine engine = CacheEngines.fromBlockCache(blockCache);
+    assertFalse(engine instanceof ResizableCacheEngine);
+  }
 }