This is an automated email from the ASF dual-hosted git repository. taklwu pushed a commit to branch HBASE-30018 in repository https://gitbox.apache.org/repos/asf/hbase.git
commit f0ad2ceabb4b4bb309fe9b89b61364b364e08a7d Author: Vladimir Rodionov <[email protected]> AuthorDate: Wed Apr 29 12:56:27 2026 -0700 HBASE-30019 Introduce CacheEngine and CacheTopology abstractions (#8155) Signed-off-by: Tak Lon (Stephen) Wu <[email protected]> Signed-off-by: Wellington Chevreuil <[email protected]> --- .../hadoop/hbase/io/hfile/cache/CacheEngine.java | 292 +++++++++++++++++++++ .../hbase/io/hfile/cache/CacheEngineView.java | 89 +++++++ .../hadoop/hbase/io/hfile/cache/CacheTier.java | 46 ++++ .../hadoop/hbase/io/hfile/cache/CacheTopology.java | 201 ++++++++++++++ .../hbase/io/hfile/cache/CacheTopologyType.java | 42 +++ .../hbase/io/hfile/cache/CacheTopologyView.java | 87 ++++++ .../hbase/io/hfile/cache/SingleEngineTopology.java | 93 +++++++ .../io/hfile/cache/TieredExclusiveTopology.java | 126 +++++++++ .../io/hfile/cache/TieredInclusiveTopology.java | 113 ++++++++ 9 files changed, 1089 insertions(+) diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngine.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngine.java new file mode 100644 index 00000000000..8d6629de3e2 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngine.java @@ -0,0 +1,292 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.io.hfile.cache; + +import java.util.Optional; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.io.hfile.BlockCacheKey; +import org.apache.hadoop.hbase.io.hfile.BlockType; +import org.apache.hadoop.hbase.io.hfile.CacheStats; +import org.apache.hadoop.hbase.io.hfile.Cacheable; +import org.apache.hadoop.hbase.io.hfile.HFileBlock; +import org.apache.yetus.audience.InterfaceAudience; + +/** + * Storage abstraction for a concrete HBase block cache backend. + * <p> + * A {@code CacheEngine} represents the storage layer only. It is responsible for storing, + * retrieving, invalidating, and reporting statistics for cached blocks. It does not perform tier + * orchestration, admission control, placement decisions, or promotion/demotion across cache levels. + * </p> + * <p> + * This interface is intentionally aligned with the storage-oriented subset of the current + * {@code BlockCache} contract so that existing implementations such as LruBlockCache and + * BucketCache can be migrated incrementally with minimal behavioral risk. + * </p> + * <p> + * Responsibilities of a {@code CacheEngine} include: + * </p> + * <ul> + * <li>block lookup</li> + * <li>block insertion</li> + * <li>targeted invalidation / eviction</li> + * <li>capacity and occupancy reporting</li> + * <li>engine-local statistics</li> + * <li>optional implementation-specific fit/capability checks</li> + * </ul> + * <p> + * Non-responsibilities include: + * </p> + * <ul> + * <li>L1/L2 topology orchestration</li> + * <li>admission policy</li> + * <li>tier placement decisions</li> + * <li>promotion or demotion across tiers</li> + * </ul> + */ [email protected] +public interface CacheEngine { + + /** + * Returns a human-readable name for this cache engine instance. + * <p> + * The name is intended for logging, metrics, diagnostics, and configuration reporting. It should + * be stable for the lifetime of the engine instance. + * </p> + * @return engine name + */ + String getName(); + + /** + * Adds a block to the cache. + * @param cacheKey block cache key + * @param buf block contents + * @param inMemory whether the block should be treated as in-memory + */ + void cacheBlock(BlockCacheKey cacheKey, Cacheable buf, boolean inMemory); + + /** + * Adds a block to the cache, optionally waiting for asynchronous cache backends. + * <p> + * This is primarily useful for implementations such as BucketCache that may buffer writes + * asynchronously. + * </p> + * @param cacheKey block cache key + * @param buf block contents + * @param inMemory whether the block should be treated as in-memory + * @param waitWhenCache whether to wait for the cache operation to be accepted/flushed + */ + default void cacheBlock(BlockCacheKey cacheKey, Cacheable buf, boolean inMemory, + boolean waitWhenCache) { + cacheBlock(cacheKey, buf, inMemory); + } + + /** + * Adds a block to the cache, defaulting to non in-memory treatment. + * @param cacheKey block cache key + * @param buf block contents + */ + void cacheBlock(BlockCacheKey cacheKey, Cacheable buf); + + /** + * Fetches a block from the cache. + * @param cacheKey block to fetch + * @param caching whether caching is enabled for the request; used for metrics + * @param repeat whether this is a repeated lookup for the same block; used to avoid + * double-counting misses + * @param updateCacheMetrics whether cache metrics should be updated + * @return cached block, or {@code null} if not present + */ + Cacheable getBlock(BlockCacheKey cacheKey, boolean caching, boolean repeat, + boolean updateCacheMetrics); + + /** + * Fetches a block from the cache with an optional block type hint. + * <p> + * Implementations may ignore the block type if it is not needed. + * </p> + * @param cacheKey block to fetch + * @param caching whether caching is enabled for the request; used for metrics + * @param repeat whether this is a repeated lookup for the same block; used to avoid + * double-counting misses + * @param updateCacheMetrics whether cache metrics should be updated + * @param blockType optional block type hint + * @return cached block, or {@code null} if not present + */ + default Cacheable getBlock(BlockCacheKey cacheKey, boolean caching, boolean repeat, + boolean updateCacheMetrics, BlockType blockType) { + return getBlock(cacheKey, caching, repeat, updateCacheMetrics); + } + + /** + * Evicts a single block from the cache. + * @param cacheKey block to evict + * @return {@code true} if the block existed and was evicted, {@code false} otherwise + */ + boolean evictBlock(BlockCacheKey cacheKey); + + /** + * Evicts all cached blocks for the given HFile. + * @param hfileName HFile name + * @return number of blocks evicted + */ + int evictBlocksByHfileName(String hfileName); + + /** + * Evicts all cached blocks for the given HFile within the specified offset range. + * <p> + * This is useful for targeted invalidation during file lifecycle events where only a subset of + * blocks should be removed. + * </p> + * @param hfileName HFile name + * @param initOffset inclusive start offset + * @param endOffset inclusive end offset + * @return number of blocks evicted + */ + default int evictBlocksRangeByHfileName(String hfileName, long initOffset, long endOffset) { + return 0; + } + + /** + * Evicts all cached blocks associated with the specified region. + * <p> + * This is a new API intended to support region-scoped invalidation in a storage-oriented way, + * without requiring higher-level code to enumerate files first. + * </p> + * @param regionName region name + * @return number of blocks evicted + */ + default int evictBlocksByRegionName(String regionName) { + return 0; + } + + /** + * Returns engine statistics. + * @return cache statistics + */ + CacheStats getStats(); + + /** + * Shuts down this cache engine and releases any owned resources. + */ + void shutdown(); + + /** + * Returns the maximum configured cache size, in bytes. + * @return maximum cache size + */ + long getMaxSize(); + + /** + * Returns the amount of free space available in the cache, in bytes. + * @return free size + */ + long getFreeSize(); + + /** + * Returns the currently occupied cache size, in bytes. + * @return occupied size + */ + long size(); + + /** + * Returns the currently occupied size of data blocks, in bytes. + * @return occupied data-block size + */ + long getCurrentDataSize(); + + /** + * Returns the total number of cached blocks. + * @return total block count + */ + long getBlockCount(); + + /** + * Returns the number of cached data blocks. + * @return data block count + */ + long getDataBlockCount(); + + /** + * Checks whether the given block can fit into this cache engine. + * <p> + * This method is optional because not all engines expose a meaningful fit check. + * </p> + * @param block block to check + * @return empty if unsupported; otherwise whether the block fits + */ + default Optional<Boolean> blockFitsIntoTheCache(HFileBlock block) { + return Optional.empty(); + } + + /** + * Checks whether the block represented by the given key is already cached. + * <p> + * This method is optional because not all engines can answer it efficiently. + * </p> + * @param key block cache key + * @return empty if unsupported; otherwise whether the block is cached + */ + default Optional<Boolean> isAlreadyCached(BlockCacheKey key) { + return Optional.empty(); + } + + /** + * Returns the size of the cached block represented by the given key. + * <p> + * This method is optional because not all engines expose per-block size cheaply. + * </p> + * @param key block cache key + * @return empty if unsupported or not present; otherwise cached block size + */ + default Optional<Integer> getBlockSize(BlockCacheKey key) { + return Optional.empty(); + } + + /** + * Returns whether this cache engine is enabled. + * @return {@code true} if enabled, {@code false} otherwise + */ + default boolean isCacheEnabled() { + return true; + } + + /** + * Waits for asynchronous engine initialization to complete. + * <p> + * Some cache backends may perform initialization asynchronously. Engines that do not require this + * may simply return {@code true} immediately. + * </p> + * @param timeout maximum time to wait + * @return {@code true} if the cache is enabled, {@code false} otherwise + */ + default boolean waitForCacheInitialization(long timeout) { + return true; + } + + /** + * Refreshes this engine's configuration. + * <p> + * The default implementation is a no-op. + * </p> + * @param config new configuration + */ + default void onConfigurationChange(Configuration config) { + // noop + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngineView.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngineView.java new file mode 100644 index 00000000000..b2362d5f561 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngineView.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.io.hfile.cache; + +import org.apache.hadoop.hbase.io.hfile.Cacheable; +import org.apache.hadoop.hbase.io.hfile.HFileBlock; +import org.apache.yetus.audience.InterfaceAudience; + +/** + * Default read-only view over a {@link CacheEngine}. + */ [email protected] +public final class CacheEngineView { + + private final CacheEngine engine; + + /** Create a new view over the given cache engine. */ + + CacheEngineView(CacheEngine engine) { + this.engine = engine; + } + + /* Getters for cache engine properties. */ + /** + * Returns the name of the cache engine. + * @return the name of the cache engine + */ + public String getName() { + return engine.getName(); + } + + /** + * Returns the maximum size of the cache in bytes. + * @return the maximum size of the cache in bytes + */ + public long getMaxSize() { + return engine.getMaxSize(); + } + + /** + * Returns the current size of the cache in bytes. + * @return the current size of the cache in bytes + */ + public long size() { + return engine.size(); + } + + /** + * Returns the free size of the cache in bytes. + * @return the free size of the cache in bytes + */ + public long getFreeSize() { + return engine.getFreeSize(); + } + + /** + * Returns the number of blocks currently stored in the cache. + * @return the number of blocks currently stored in the cache + */ + public long getBlockCount() { + return engine.getBlockCount(); + } + + /** + * Is engine able to store this block. + * @return true - if yes, false - otherwise + */ + public boolean canStore(Cacheable block) { + if (block instanceof HFileBlock) { + return engine.blockFitsIntoTheCache((HFileBlock) block).orElse(true); + } + return true; + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheTier.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheTier.java new file mode 100644 index 00000000000..69f1d51a49a --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheTier.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.io.hfile.cache; + +import org.apache.yetus.audience.InterfaceAudience; + +/** + * Logical cache tier used by topology and policy code. + * <p> + * This enum describes the role an engine plays inside a topology. It is intentionally separate from + * {@link CacheEngineType}, which describes the implementation family of an engine. + * </p> + */ [email protected] +public enum CacheTier { + + /** + * Single-tier topology engine. + */ + SINGLE, + + /** + * First-level cache, usually smaller and optimized for low latency. + */ + L1, + + /** + * Second-level cache, usually larger and optimized for capacity. + */ + L2 +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheTopology.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheTopology.java new file mode 100644 index 00000000000..daf7a053ea4 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheTopology.java @@ -0,0 +1,201 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.io.hfile.cache; + +import java.util.List; +import java.util.Optional; +import org.apache.hadoop.hbase.io.hfile.BlockCacheKey; +import org.apache.hadoop.hbase.io.hfile.CacheStats; +import org.apache.hadoop.hbase.io.hfile.Cacheable; +import org.apache.yetus.audience.InterfaceAudience; + +/** + * Describes orchestration of one or more cache engines. + * <p> + * {@code CacheTopology} is responsible for the structural relationship between cache engines, for + * example a single-engine cache, a tiered exclusive L1/L2 cache, or a tiered inclusive L1/L2 cache. + * </p> + * <p> + * This abstraction does not own storage. Storage belongs to {@link CacheEngine}. This abstraction + * also does not decide admission or write placement. Admission, placement, representation, and + * promotion decisions belong to the policy layer. + * </p> + * <p> + * Responsibilities of a cache topology include: + * </p> + * <ul> + * <li>exposing participating cache engines</li> + * <li>mapping engines to logical tiers such as L1 and L2</li> + * <li>providing aggregate cache statistics</li> + * <li>performing topology-specific promotion when requested by policy</li> + * <li>optionally performing topology-specific demotion</li> + * <li>coordinating shutdown of participating engines</li> + * </ul> + * <p> + * Non-responsibilities include: + * </p> + * <ul> + * <li>block storage</li> + * <li>local eviction algorithms</li> + * <li>cache admission control</li> + * <li>write routing / target tier selection</li> + * <li>HFile read/write path integration</li> + * </ul> + */ [email protected] +public interface CacheTopology { + + /** + * Returns a human-readable topology name. + * <p> + * The name is intended for logging, metrics, diagnostics, and configuration reporting. It should + * be stable for the lifetime of this topology instance. + * </p> + * @return topology name + */ + String getName(); + + /** + * Returns the topology type. + * <p> + * The type identifies the topology family, such as single-engine, tiered exclusive, or tiered + * inclusive. + * </p> + * @return topology type + */ + CacheTopologyType getType(); + + /** + * Returns the cache engines participating in this topology. + * <p> + * The returned list is primarily intended for diagnostics, metrics, and topology inspection. + * Callers should not use it to bypass topology and policy logic for normal cache operations. + * </p> + * @return participating cache engines + */ + List<CacheEngine> getEngines(); + + /** + * Returns the logical cache tiers defined by this topology. + * <p> + * This method describes the structure of the topology in terms of {@link CacheTier} identifiers + * (for example, {@code SINGLE}, {@code L1}, {@code L2}). The returned list defines which tiers + * are present and can be used for lookup, placement, and promotion decisions. + * </p> + * <p> + * The ordering of tiers is significant and should reflect lookup priority (for example, + * {@code L1} before {@code L2}). + * </p> + * <p> + * This method must be explicitly implemented by each topology. Callers must not infer tier + * structure from {@link #getEngines()} or other properties. + * </p> + * @return ordered list of tiers defined by this topology + */ + List<CacheTier> getTiers(); + + /** + * Returns the cache engine associated with the given logical tier, if one exists. + * <p> + * For example, a tiered topology may expose an L1 and L2 engine. A single-engine topology may + * return an engine for {@link CacheTier#SINGLE} and an empty result for L1/L2. + * </p> + * @param tier logical cache tier + * @return cache engine for the tier, or empty if this topology does not define that tier + */ + Optional<CacheEngine> getEngine(CacheTier tier); + + /** + * Returns aggregate topology-level cache statistics. + * <p> + * For a single-engine topology, this may simply return the underlying engine statistics. For a + * multi-engine topology, this should represent an aggregate view suitable for compatibility with + * existing HBase block cache metrics. + * </p> + * @return aggregate cache statistics + */ + CacheStats getStats(); + + /** + * Promotes a cached block from one engine to another. + * <p> + * This method performs the topology-specific mechanics of promotion. The decision whether a block + * should be promoted belongs to the placement/admission policy layer. For example, a policy may + * decide that an index block found in L2 should be promoted to L1, and then call this method to + * perform the promotion. + * </p> + * <p> + * Implementations may either copy or move the block depending on topology semantics. For example: + * </p> + * <ul> + * <li>inclusive may copy the block into the target tier while retaining it in source</li> + * <li>exclusive may move the block into the target tier and remove it from source</li> + * </ul> + * @param cacheKey block cache key + * @param block cached block to promote + * @param sourceEngine engine where the block was found + * @param targetEngine engine where the block should be promoted + * @return {@code true} if promotion was performed, {@code false} otherwise + */ + boolean promote(BlockCacheKey cacheKey, Cacheable block, CacheEngine sourceEngine, + CacheEngine targetEngine); + + /** + * Demotes a cached block from one engine to another. + * <p> + * Demotion is optional because not all topologies or cache engines can support it efficiently. In + * many implementations, eviction does not expose the evicted block in a form that can be cheaply + * demoted. The default implementation therefore performs no action. + * </p> + * <p> + * The decision whether demotion should happen belongs to the policy layer or to a + * topology-specific eviction callback mechanism. This method only provides a standard hook for + * topologies that support demotion. + * </p> + * @param cacheKey block cache key + * @param block cached block to demote + * @param sourceEngine engine from which the block is being demoted + * @param targetEngine engine where the block should be demoted + * @return {@code true} if demotion was performed, {@code false} otherwise + */ + default boolean demote(BlockCacheKey cacheKey, Cacheable block, CacheEngine sourceEngine, + CacheEngine targetEngine) { + return false; + } + + /** + * Shuts down this topology and any cache engines owned by it. + * <p> + * If the topology does not own the life cycle of its engines, the implementation should document + * that behavior. The default expectation is that shutting down a topology shuts down + * participating engines. + * </p> + */ + void shutdown(); + + /** + * Returns a read-only view of this topology. + * <p> + * The returned view is intended for policy implementations, diagnostics, and metrics. It should + * expose topology and engine state without allowing callers to mutate cache contents or bypass + * topology behavior. + * </p> + * @return read-only topology view + */ + CacheTopologyView getView(); +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheTopologyType.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheTopologyType.java new file mode 100644 index 00000000000..50ff46d5bde --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheTopologyType.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.io.hfile.cache; + +import org.apache.yetus.audience.InterfaceAudience; + +/** + * Identifies the structural form of a cache topology. + */ [email protected] +public enum CacheTopologyType { + + /** + * A topology with a single cache engine. + */ + SINGLE, + + /** + * A tiered topology where a block normally resides in only one tier at a time. + */ + TIERED_EXCLUSIVE, + + /** + * A tiered topology where a block present in an upper tier may also remain in a lower tier. + */ + TIERED_INCLUSIVE +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheTopologyView.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheTopologyView.java new file mode 100644 index 00000000000..98c21afd072 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheTopologyView.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.io.hfile.cache; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import org.apache.yetus.audience.InterfaceAudience; + +/** + * Default immutable-style read-only view over a {@link CacheTopology}. + * <p> + * This view delegates to the topology and exposes only read-only engine views. + * </p> + */ [email protected] +public final class CacheTopologyView { + + private final CacheTopology topology; + + /** + * Constructs a CacheTopologyView for the given CacheTopology. + */ + CacheTopologyView(CacheTopology topology) { + this.topology = topology; + } + + /** + * Delegating getters for topology properties and read-only engine views. + */ + + public String getName() { + return topology.getName(); + } + + /** + * Returns the cache topology type, which can be SINGLE, TIERED_EXCLUSIVE, or TIERED_INCLUSIVE. + * @return the cache topology type + */ + public CacheTopologyType getType() { + return topology.getType(); + } + + /** + * Returns the list of cache tiers in this topology. For a single-tier topology, it returns a list + * containing only CacheTier.SINGLE. For a multi-tier topology, it returns a list containing + * CacheTier.L1 and CacheTier.L2. + * @return the list of cache tiers in this topology + */ + public List<CacheTier> getTiers() { + return topology.getTiers(); + } + + /** + * Returns an Optional containing a CacheEngineView for the specified cache tier if it exists in + * the topology, or an empty Optional if the tier is not present. + * @param tier the cache tier for which to retrieve the engine view + * @return an Optional containing the CacheEngineView for the specified tier, or empty if not + * present + */ + public Optional<CacheEngineView> getEngine(CacheTier tier) { + return topology.getEngine(tier).map(CacheEngineView::new); + } + + /** + * Returns a list of CacheEngineView objects representing all cache engines in this topology. + * @return a list of CacheEngineView objects for all engines in this topology + */ + public List<CacheEngineView> getEngines() { + return topology.getEngines().stream().map(CacheEngineView::new).collect(Collectors.toList()); + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/SingleEngineTopology.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/SingleEngineTopology.java new file mode 100644 index 00000000000..c94deabdae5 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/SingleEngineTopology.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.io.hfile.cache; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import org.apache.hadoop.hbase.io.hfile.BlockCacheKey; +import org.apache.hadoop.hbase.io.hfile.CacheStats; +import org.apache.hadoop.hbase.io.hfile.Cacheable; +import org.apache.yetus.audience.InterfaceAudience; + +/** + * Single-engine cache topology. + * <p> + * This topology wraps a single {@link CacheEngine}. It is primarily useful as a baseline topology + * and as a simple bridge for cache configurations that do not use L1/L2 tiering. + * </p> + */ [email protected] +public class SingleEngineTopology implements CacheTopology { + + private final String name; + private final CacheEngine engine; + private final CacheTopologyView view; + + public SingleEngineTopology(String name, CacheEngine engine) { + this.name = name; + this.engine = engine; + this.view = new CacheTopologyView(this); + } + + @Override + public String getName() { + return name; + } + + @Override + public CacheTopologyType getType() { + return CacheTopologyType.SINGLE; + } + + @Override + public List<CacheEngine> getEngines() { + return Collections.singletonList(engine); + } + + @Override + public Optional<CacheEngine> getEngine(CacheTier tier) { + return tier == CacheTier.SINGLE ? Optional.of(engine) : Optional.empty(); + } + + @Override + public CacheTopologyView getView() { + return view; + } + + @Override + public CacheStats getStats() { + return engine.getStats(); + } + + @Override + public boolean promote(BlockCacheKey cacheKey, Cacheable block, CacheEngine sourceEngine, + CacheEngine targetEngine) { + return false; + } + + @Override + public void shutdown() { + engine.shutdown(); + } + + @Override + public List<CacheTier> getTiers() { + return Collections.singletonList(CacheTier.SINGLE); + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/TieredExclusiveTopology.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/TieredExclusiveTopology.java new file mode 100644 index 00000000000..d20d5c8c34e --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/TieredExclusiveTopology.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.io.hfile.cache; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import org.apache.hadoop.hbase.io.hfile.BlockCacheKey; +import org.apache.hadoop.hbase.io.hfile.CacheStats; +import org.apache.hadoop.hbase.io.hfile.Cacheable; +import org.apache.yetus.audience.InterfaceAudience; + +/** + * Tiered exclusive cache topology. + * <p> + * In an exclusive topology, a block should normally reside in only one tier at a time. Promotion + * from L2 to L1 is therefore modeled as a move: insert into L1 and evict from L2. + * </p> + * <p> + * This class is introduced as a topology foundation. Production wiring and policy-driven routing + * are handled in later migration phases. + * </p> + */ [email protected] +public class TieredExclusiveTopology implements CacheTopology { + + private final String name; + private final CacheEngine l1; + private final CacheEngine l2; + private final CacheTopologyView view; + + public TieredExclusiveTopology(String name, CacheEngine l1, CacheEngine l2) { + this.name = name; + this.l1 = l1; + this.l2 = l2; + this.view = new CacheTopologyView(this); + } + + @Override + public String getName() { + return name; + } + + @Override + public CacheTopologyType getType() { + return CacheTopologyType.TIERED_EXCLUSIVE; + } + + @Override + public List<CacheEngine> getEngines() { + return Arrays.asList(l1, l2); + } + + @Override + public List<CacheTier> getTiers() { + return Arrays.asList(CacheTier.L1, CacheTier.L2); + } + + @Override + public Optional<CacheEngine> getEngine(CacheTier tier) { + switch (tier) { + case L1: + return Optional.of(l1); + case L2: + return Optional.of(l2); + default: + return Optional.empty(); + } + } + + @Override + public CacheTopologyView getView() { + return view; + } + + @Override + public CacheStats getStats() { + // TODO: replace with aggregate topology stats in follow-up metrics ticket. + return l1.getStats(); + } + + @Override + public boolean promote(BlockCacheKey cacheKey, Cacheable block, CacheEngine sourceEngine, + CacheEngine targetEngine) { + if (sourceEngine == null || targetEngine == null || block == null) { + return false; + } + + targetEngine.cacheBlock(cacheKey, block); + sourceEngine.evictBlock(cacheKey); + return true; + } + + @Override + public boolean demote(BlockCacheKey cacheKey, Cacheable block, CacheEngine sourceEngine, + CacheEngine targetEngine) { + if (sourceEngine == null || targetEngine == null || block == null) { + return false; + } + + targetEngine.cacheBlock(cacheKey, block); + sourceEngine.evictBlock(cacheKey); + return true; + } + + @Override + public void shutdown() { + l1.shutdown(); + l2.shutdown(); + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/TieredInclusiveTopology.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/TieredInclusiveTopology.java new file mode 100644 index 00000000000..984e7ca98ca --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/TieredInclusiveTopology.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.io.hfile.cache; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import org.apache.hadoop.hbase.io.hfile.BlockCacheKey; +import org.apache.hadoop.hbase.io.hfile.CacheStats; +import org.apache.hadoop.hbase.io.hfile.Cacheable; +import org.apache.yetus.audience.InterfaceAudience; + +/** + * Tiered inclusive cache topology. + * <p> + * In an inclusive topology, a block promoted from L2 to L1 may remain in L2. Promotion is therefore + * modeled as a copy rather than a move. + * </p> + * <p> + * This class is introduced as a topology foundation. Production wiring and policy-driven routing + * are handled in later migration phases. + * </p> + */ [email protected] +public class TieredInclusiveTopology implements CacheTopology { + + private final String name; + private final CacheEngine l1; + private final CacheEngine l2; + private final CacheTopologyView view; + + public TieredInclusiveTopology(String name, CacheEngine l1, CacheEngine l2) { + this.name = name; + this.l1 = l1; + this.l2 = l2; + this.view = new CacheTopologyView(this); + } + + @Override + public String getName() { + return name; + } + + @Override + public CacheTopologyType getType() { + return CacheTopologyType.TIERED_INCLUSIVE; + } + + @Override + public List<CacheEngine> getEngines() { + return Arrays.asList(l1, l2); + } + + @Override + public List<CacheTier> getTiers() { + return Arrays.asList(CacheTier.L1, CacheTier.L2); + } + + @Override + public Optional<CacheEngine> getEngine(CacheTier tier) { + switch (tier) { + case L1: + return Optional.of(l1); + case L2: + return Optional.of(l2); + default: + return Optional.empty(); + } + } + + @Override + public CacheTopologyView getView() { + return view; + } + + @Override + public CacheStats getStats() { + // TODO: replace with aggregate topology stats in follow-up metrics ticket. + return l1.getStats(); + } + + @Override + public boolean promote(BlockCacheKey cacheKey, Cacheable block, CacheEngine sourceEngine, + CacheEngine targetEngine) { + if (targetEngine == null || block == null) { + return false; + } + + targetEngine.cacheBlock(cacheKey, block); + return true; + } + + @Override + public void shutdown() { + l1.shutdown(); + l2.shutdown(); + } +}
