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 000000000000..b51318a2fcef --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngine.java @@ -0,0 +1,319 @@ +/* + * 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. + * + *
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.
+ * + *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.
+ * + *Responsibilities of a {@code CacheEngine} include:
+ *Non-responsibilities include:
+ *The name is intended for logging, metrics, diagnostics, and configuration reporting. + * It should be stable for the lifetime of the engine instance.
+ * + * @return engine name + */ + String getName(); + + /** + * Returns the engine type. + * + *This identifies the concrete backend family, such as LRU, BUCKET, or CARROT. The type + * is useful for metrics, diagnostics, and topology assembly.
+ * + * @return engine type + */ + CacheEngineType getType(); + + /** + * 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. + * + *This is primarily useful for implementations such as BucketCache that may buffer writes + * asynchronously.
+ * + * @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. + * + *Implementations may ignore the block type if it is not needed.
+ * + * @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. + * + *This is useful for targeted invalidation during file lifecycle events where only a subset + * of blocks should be removed.
+ * + * @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. + * + *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.
+ * + * @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 total configured cache size, in bytes. + * + * @return total cache size + */ + long size(); + + /** + * 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 getCurrentSize(); + + /** + * 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. + * + *This method is optional because not all engines expose a meaningful fit check.
+ * + * @param block block to check + * @return empty if unsupported; otherwise whether the block fits + */ + default OptionalThis method is optional because not all engines can answer it efficiently.
+ * + * @param key block cache key + * @return empty if unsupported; otherwise whether the block is cached + */ + default OptionalThis method is optional because not all engines expose per-block size cheaply.
+ * + * @param key block cache key + * @return empty if unsupported or not present; otherwise cached block size + */ + default OptionalSome cache backends may perform initialization asynchronously. Engines that do not + * require this may simply return {@code true} immediately.
+ * + * @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. + * + *The default implementation is a no-op.
+ * + * @param config new configuration + */ + default void onConfigurationChange(Configuration config) { + // noop + } +} \ No newline at end of file diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngineType.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngineType.java new file mode 100644 index 000000000000..8a85962c9211 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngineType.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; + +/** + * Identifies the concrete cache engine family. + */ +@InterfaceAudience.Private +public enum CacheEngineType { + /** + * Heap-based LRU cache engine. + */ + LRU, + + /** + * Bucket-based off-heap / file-backed cache engine. + */ + BUCKET, + + /** + * CarrotCache-based engine. + */ + CARROT, + + /** + * Other or custom engine type. + */ + CUSTOM +} \ No newline at end of file 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 000000000000..8361c8faa6c9 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheEngineView.java @@ -0,0 +1,97 @@ +/* + * 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}. + */ +@InterfaceAudience.Private +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 type of the cache engine. + * @return the type of the cache engine + */ + public CacheEngineType getType() { + return engine.getType(); + } + + /** + * 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 getCurrentSize() { + return engine.getCurrentSize(); + } + + /** + * 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(); + } + + /** + * Returns the number of blocks currently stored in the cache. + * @return the number of blocks currently stored in the cache + */ + public boolean canStore(Cacheable block) { + if (block instanceof HFileBlock) { + return engine.blockFitsIntoTheCache((HFileBlock) block).orElse(true); + } + return true; + } +} \ No newline at end of file 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 000000000000..1a11c9e57d93 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheTier.java @@ -0,0 +1,45 @@ +/* + * 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. + * + *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.
+ */ +@InterfaceAudience.Private +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 +} \ No newline at end of file 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 000000000000..049ee978444d --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheTopology.java @@ -0,0 +1,177 @@ +/* + * 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. + * + *{@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.
+ * + *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.
+ * + *Responsibilities of a cache topology include:
+ *Non-responsibilities include:
+ *The name is intended for logging, metrics, diagnostics, and configuration reporting. It + * should be stable for the lifetime of this topology instance.
+ * + * @return topology name + */ + String getName(); + + /** + * Returns the topology type. + * + *The type identifies the topology family, such as single-engine, tiered exclusive, or tiered + * inclusive.
+ * + * @return topology type + */ + CacheTopologyType getType(); + + /** + * Returns the cache engines participating in this topology. + * + *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.
+ * + * @return participating cache engines + */ + ListFor 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.
+ * + * @param tier logical cache tier + * @return cache engine for the tier, or empty if this topology does not define that tier + */ + OptionalFor 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.
+ * + * @return aggregate cache statistics + */ + CacheStats getStats(); + + /** + * Promotes a cached block from one engine to another. + * + *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.
+ * + *Implementations may either copy or move the block depending on topology semantics. For + * example:
+ *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.
+ * + *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.
+ * + * @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. + * + *If the topology does not own the lifecycle of its engines, the implementation should document + * that behavior. The default expectation is that shutting down a topology shuts down participating + * engines.
+ */ + void shutdown(); + + /** + * Returns a read-only view of this topology. + * + *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.
+ * + * @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 000000000000..6dd1a2d40bd8 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheTopologyType.java @@ -0,0 +1,47 @@ +/* + * 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. + */ +@InterfaceAudience.Private +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, + + /** + * A custom topology implementation. + */ + CUSTOM +} \ No newline at end of file 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 000000000000..915c8f0fe03a --- /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}. + * + *This view delegates to the topology and exposes only read-only engine views.
+ */ +@InterfaceAudience.Private +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, L1_L2, or CUSTOM. + * @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 ListThis 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.
+ */ +@InterfaceAudience.Private +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 ListIn 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.
+ * + *This class is introduced as a topology foundation. Production wiring and policy-driven + * routing are handled in later migration phases.
+ */ +@InterfaceAudience.Private +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 ListIn 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.
+ * + *This class is introduced as a topology foundation. Production wiring and policy-driven + * routing are handled in later migration phases.
+ */ +@InterfaceAudience.Private +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