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 ac0d2a3dced3f5ff122a2f2919e254f0866ada41 Author: Vladimir Rodionov <[email protected]> AuthorDate: Thu May 7 12:12:00 2026 -0700 HBASE-30020 Introduce cache placement and admission policy API (#8184) Signed-off-by: Peter Somogyi <[email protected]> Signed-off-by: Tak Lon (Stephen) Wu <[email protected]> Signed-off-by: Wellington Chevreuil <[email protected]> --- .../hbase/io/hfile/cache/AdmissionDecision.java | 89 ++++++++++ .../hbase/io/hfile/cache/AdmissionPriority.java | 42 +++++ .../hfile/cache/CachePlacementAdmissionPolicy.java | 88 ++++++++++ .../hbase/io/hfile/cache/CacheRequestContext.java | 187 +++++++++++++++++++++ .../hbase/io/hfile/cache/CacheWriteContext.java | 166 ++++++++++++++++++ .../hbase/io/hfile/cache/CacheWriteSource.java | 57 +++++++ .../DefaultHBaseCachePlacementAdmissionPolicy.java | 124 ++++++++++++++ .../hbase/io/hfile/cache/PromotionAction.java | 37 ++++ .../hbase/io/hfile/cache/PromotionDecision.java | 122 ++++++++++++++ .../io/hfile/cache/RepresentationDecision.java | 52 ++++++ .../hadoop/hbase/io/hfile/cache/TierDecision.java | 115 +++++++++++++ 11 files changed, 1079 insertions(+) diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/AdmissionDecision.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/AdmissionDecision.java new file mode 100644 index 00000000000..8e173c616f7 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/AdmissionDecision.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.yetus.audience.InterfaceAudience; + +/** + * Result of cache admission evaluation. + */ [email protected] +public final class AdmissionDecision { + + private static final AdmissionDecision ADMIT = new AdmissionDecision(true, "ADMIT"); + + private static final AdmissionDecision REJECT = new AdmissionDecision(false, "REJECT"); + + private final boolean admit; + private final String reason; + + private AdmissionDecision(boolean admit, String reason) { + this.admit = admit; + this.reason = reason; + } + + /** + * Returns a normal-priority admission decision. + * @return admit decision + */ + public static AdmissionDecision admit() { + return ADMIT; + } + + /** + * Returns an admission decision with a reason. + * @param reason reason text + * @return admit decision + */ + public static AdmissionDecision admit(String reason) { + return new AdmissionDecision(true, reason); + } + + /** + * Returns a rejection decision. * @return reject decision + */ + public static AdmissionDecision reject() { + return REJECT; + } + + /** + * Returns a rejection decision with a reason. + * @param reason rejection reason + * @return reject decision + */ + public static AdmissionDecision reject(String reason) { + return new AdmissionDecision(false, reason); + } + + /** + * Returns whether the block should be admitted. + * @return true when admitted + */ + public boolean isAdmitted() { + return admit; + } + + /** + * Returns the decision reason. + * @return decision reason + */ + public String getReason() { + return reason; + } + +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/AdmissionPriority.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/AdmissionPriority.java new file mode 100644 index 00000000000..3157d98061e --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/AdmissionPriority.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; + +/** + * Priority hint associated with an admitted cache block. + */ [email protected] +public enum AdmissionPriority { + + /** + * Low-priority admission, suitable for opportunistic insertions such as prefetch. + */ + LOW, + + /** + * Normal-priority admission. + */ + NORMAL, + + /** + * High-priority admission, suitable for metadata-heavy or latency-sensitive blocks. + */ + HIGH +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CachePlacementAdmissionPolicy.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CachePlacementAdmissionPolicy.java new file mode 100644 index 00000000000..7ce89fdceeb --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CachePlacementAdmissionPolicy.java @@ -0,0 +1,88 @@ +/* + * 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.BlockCacheKey; +import org.apache.hadoop.hbase.io.hfile.Cacheable; +import org.apache.yetus.audience.InterfaceAudience; + +/** + * Policy interface for cache admission, tier placement, representation, and promotion. + * <p> + * This policy decides what should happen for a cache operation. It does not execute cache + * operations directly. Execution belongs to {@link CacheTopology} and storage belongs to + * {@link CacheEngine}. + * </p> + * <p> + * The policy may consult {@link CacheTopologyView} to inspect available tiers and engine capacity, + * but it must not mutate cache state. + * </p> + */ [email protected] +public interface CachePlacementAdmissionPolicy { + + /** + * Decides whether a block should be admitted into the cache. + * @param cacheKey block cache key + * @param block block to cache + * @param context write context describing insertion source and hints + * @param priority admission priority hint + * @param topologyView read-only topology view + * @return admission decision + */ + AdmissionDecision shouldAdmit(BlockCacheKey cacheKey, Cacheable block, CacheWriteContext context, + AdmissionPriority priority, CacheTopologyView topologyView); + + /** + * Selects the target tier for an admitted block. + * @param cacheKey block cache key + * @param block block to cache + * @param context write context describing insertion source and hints + * @param topologyView read-only topology view + * @return tier decision + */ + TierDecision selectTier(BlockCacheKey cacheKey, Cacheable block, CacheWriteContext context, + CacheTopologyView topologyView); + + /** + * Selects the cached representation for an admitted block. + * <p> + * The initial compatibility policy should preserve the representation currently produced by + * existing HBase code paths. + * </p> + * @param cacheKey block cache key + * @param block block to cache + * @param context write context describing insertion source and hints + * @param topologyView read-only topology view + * @return representation decision + */ + RepresentationDecision selectRepresentation(BlockCacheKey cacheKey, Cacheable block, + CacheWriteContext context, CacheTopologyView topologyView); + + /** + * Decides whether a cache hit should trigger promotion to another tier. + * @param cacheKey block cache key + * @param block cached block + * @param sourceTier tier where the block was found + * @param context read request context + * @param topologyView read-only topology view + * @return promotion decision + */ + PromotionDecision shouldPromote(BlockCacheKey cacheKey, Cacheable block, CacheTier sourceTier, + CacheRequestContext context, CacheTopologyView topologyView); +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheRequestContext.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheRequestContext.java new file mode 100644 index 00000000000..17aee5265fd --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheRequestContext.java @@ -0,0 +1,187 @@ +/* + * 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.BlockType; +import org.apache.yetus.audience.InterfaceAudience; + +/** + * Context for cache lookup. + * <p> + * This object carries read-path cache lookup intent. It mirrors the existing low-allocation + * BlockCache request parameters while allowing future call sites to pass structured context. + * </p> + */ [email protected] +public final class CacheRequestContext { + + private final boolean caching; + private final boolean repeat; + private final boolean updateCacheMetrics; + private final BlockType blockType; + private final boolean compaction; + private final boolean prefetch; + + private CacheRequestContext(Builder builder) { + this.caching = builder.caching; + this.repeat = builder.repeat; + this.updateCacheMetrics = builder.updateCacheMetrics; + this.blockType = builder.blockType; + this.compaction = builder.compaction; + this.prefetch = builder.prefetch; + } + + /** + * Creates a new builder. + */ + public static Builder newBuilder() { + return new Builder(); + } + + /** + * Returns whether caching is enabled for this request. + * @return true when caching is enabled + */ + public boolean isCaching() { + return caching; + } + + /** + * Returns whether this is a repeated lookup for the same block. + * @return true when this is a repeated lookup + */ + public boolean isRepeat() { + return repeat; + } + + /** + * Returns whether cache metrics should be updated. + * @return true when metrics should be updated + */ + public boolean isUpdateCacheMetrics() { + return updateCacheMetrics; + } + + /** + * Returns the expected block type, if known. + * @return block type, or null if unknown + */ + public BlockType getBlockType() { + return blockType; + } + + /** + * Returns whether this request is associated with compaction. + * @return true when compaction-related + */ + public boolean isCompaction() { + return compaction; + } + + /** + * Returns whether this request is associated with prefetch. + * @return true when prefetch-related + */ + public boolean isPrefetch() { + return prefetch; + } + + /** + * Builder for {@link CacheRequestContext}. + */ + public static final class Builder { + + private boolean caching; + private boolean repeat; + private boolean updateCacheMetrics = true; + private BlockType blockType; + private boolean compaction; + private boolean prefetch; + + private Builder() { + } + + /** + * Sets whether caching is enabled. + * @param caching true when caching is enabled + * @return this builder + */ + public Builder setCaching(boolean caching) { + this.caching = caching; + return this; + } + + /** + * Sets repeated-lookup status. + * @param repeat true when this is a repeated lookup + * @return this builder + */ + public Builder setRepeat(boolean repeat) { + this.repeat = repeat; + return this; + } + + /** + * Sets whether cache metrics should be updated. + * @param updateCacheMetrics true when metrics should be updated + * @return this builder + */ + public Builder setUpdateCacheMetrics(boolean updateCacheMetrics) { + this.updateCacheMetrics = updateCacheMetrics; + return this; + } + + /** + * Sets the expected block type. + * @param blockType expected block type + * @return this builder + */ + public Builder setBlockType(BlockType blockType) { + this.blockType = blockType; + return this; + } + + /** + * Sets compaction request status. + * @param compaction true when compaction-related + * @return this builder + */ + public Builder setCompaction(boolean compaction) { + this.compaction = compaction; + return this; + } + + /** + * Sets prefetch request status. + * @param prefetch true when prefetch-related + * @return this builder + */ + public Builder setPrefetch(boolean prefetch) { + this.prefetch = prefetch; + return this; + } + + /** + * Builds the context. + * @return cache request context + */ + public CacheRequestContext build() { + return new CacheRequestContext(this); + } + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheWriteContext.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheWriteContext.java new file mode 100644 index 00000000000..e9b2f729f5b --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheWriteContext.java @@ -0,0 +1,166 @@ +/* + * 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.BlockType.BlockCategory; +import org.apache.yetus.audience.InterfaceAudience; + +/** + * Context for cache insertion. + * <p> + * This object carries insertion intent from read-miss population, write path population, prefetch, + * compaction, or promotion. It is intentionally small and immutable. + * </p> + */ [email protected] +public final class CacheWriteContext { + + private final boolean inMemory; + private final boolean waitWhenCache; + private final boolean cacheCompressed; + private final BlockCategory blockCategory; + private final CacheWriteSource source; + + private CacheWriteContext(Builder builder) { + this.inMemory = builder.inMemory; + this.waitWhenCache = builder.waitWhenCache; + this.cacheCompressed = builder.cacheCompressed; + this.blockCategory = builder.blockCategory; + this.source = builder.source; + } + + /** + * Creates a new builder. + */ + public static Builder newBuilder() { + return new Builder(); + } + + /** + * Returns whether this block should receive in-memory treatment. + * @return true when in-memory treatment is requested + */ + public boolean isInMemory() { + return inMemory; + } + + /** + * Returns whether insertion should wait for asynchronous cache acceptance. + * @return true when wait is requested + */ + public boolean isWaitWhenCache() { + return waitWhenCache; + } + + /** + * Returns whether compressed caching is requested. + * @return true when compressed caching is requested + */ + public boolean isCacheCompressed() { + return cacheCompressed; + } + + /** + * Returns the block category, if known. + * @return block category, or null if unknown + */ + public BlockCategory getBlockCategory() { + return blockCategory; + } + + /** + * Returns the source of this cache write. + * @return cache write source + */ + public CacheWriteSource getSource() { + return source; + } + + /** + * Builder for {@link CacheWriteContext}. + */ + public static final class Builder { + + private boolean inMemory; + private boolean waitWhenCache; + private boolean cacheCompressed; + private BlockCategory blockCategory; + private CacheWriteSource source = CacheWriteSource.READ_MISS; + + private Builder() { + } + + /** + * Sets in-memory treatment. + * @param inMemory true when in-memory treatment is requested + * @return this builder + */ + public Builder setInMemory(boolean inMemory) { + this.inMemory = inMemory; + return this; + } + + /** + * Sets wait-on-cache behavior. + * @param waitWhenCache true when insertion should wait + * @return this builder + */ + public Builder setWaitWhenCache(boolean waitWhenCache) { + this.waitWhenCache = waitWhenCache; + return this; + } + + /** + * Sets compressed cache preference. + * @param cacheCompressed true when compressed caching is requested + * @return this builder + */ + public Builder setCacheCompressed(boolean cacheCompressed) { + this.cacheCompressed = cacheCompressed; + return this; + } + + /** + * Sets the block category. + * @param blockCategory block category + * @return this builder + */ + public Builder setBlockCategory(BlockCategory blockCategory) { + this.blockCategory = blockCategory; + return this; + } + + /** + * Sets the cache write source. + * @param source cache write source + * @return this builder + */ + public Builder setSource(CacheWriteSource source) { + this.source = source; + return this; + } + + /** + * Builds the context. + * @return cache write context + */ + public CacheWriteContext build() { + return new CacheWriteContext(this); + } + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheWriteSource.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheWriteSource.java new file mode 100644 index 00000000000..2c98d9d7c94 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/CacheWriteSource.java @@ -0,0 +1,57 @@ +/* + * 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; + +/** + * Source of a cache insertion request. + * <p> + * This value describes where a cache population request originated. It does not replace existing + * {@code CacheConfig} decisions. Callers should invoke cache population only after existing HBase + * logic has determined that the block is eligible for caching. + * </p> + */ [email protected] +public enum CacheWriteSource { + + /** + * Cache population after a read miss. + */ + READ_MISS, + + /** + * Cache population during flush output generation. + */ + FLUSH, + + /** + * Cache population during compaction output generation. + */ + COMPACTION, + + /** + * Cache population by prefetch. + */ + PREFETCH, + + /** + * Cache population caused by promotion from another tier. + */ + PROMOTION +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/DefaultHBaseCachePlacementAdmissionPolicy.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/DefaultHBaseCachePlacementAdmissionPolicy.java new file mode 100644 index 00000000000..039c620a33d --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/DefaultHBaseCachePlacementAdmissionPolicy.java @@ -0,0 +1,124 @@ +/* + * 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.Objects; +import org.apache.hadoop.hbase.io.hfile.BlockCacheKey; +import org.apache.hadoop.hbase.io.hfile.BlockType; +import org.apache.hadoop.hbase.io.hfile.Cacheable; +import org.apache.hadoop.hbase.io.hfile.HFileBlock; +import org.apache.yetus.audience.InterfaceAudience; + +/** + * Default compatibility policy that preserves current HBase block cache behavior. + * <p> + * This policy is intentionally conservative. It admits cache insertion requests by default, assumes + * existing {@code CacheConfig} logic has already decided whether cache population should be + * attempted, preserves the current HBase block representation, and maps metadata-like blocks to L1 + * and data blocks to L2 when a tiered topology is available. + * </p> + */ [email protected] +public class DefaultHBaseCachePlacementAdmissionPolicy implements CachePlacementAdmissionPolicy { + + @Override + public AdmissionDecision shouldAdmit(BlockCacheKey cacheKey, Cacheable block, + CacheWriteContext context, AdmissionPriority priority, CacheTopologyView topologyView) { + Objects.requireNonNull(cacheKey, "cacheKey must not be null"); + Objects.requireNonNull(block, "block must not be null"); + Objects.requireNonNull(context, "context must not be null"); + Objects.requireNonNull(priority, "priority must not be null"); + Objects.requireNonNull(topologyView, "topologyView must not be null"); + + return AdmissionDecision.admit(); + } + + @Override + public TierDecision selectTier(BlockCacheKey cacheKey, Cacheable block, CacheWriteContext context, + CacheTopologyView topologyView) { + Objects.requireNonNull(cacheKey, "cacheKey must not be null"); + Objects.requireNonNull(block, "block must not be null"); + Objects.requireNonNull(context, "context must not be null"); + Objects.requireNonNull(topologyView, "topologyView must not be null"); + /* + * Default compatibility placement prefers metadata/index/bloom blocks in L1 and data blocks in + * L2 when both tiers are available, but falls back to any available tier rather than rejecting + * placement. + */ + if (topologyView.getType() == CacheTopologyType.SINGLE) { + return TierDecision.single(CacheTier.SINGLE); + } + + if (isMetaOrIndexBlock(block)) { + if (topologyView.getEngine(CacheTier.L1).isPresent()) { + return TierDecision.single(CacheTier.L1); + } + if (topologyView.getEngine(CacheTier.L2).isPresent()) { + return TierDecision.single(CacheTier.L2); + } + return TierDecision.none(); + } + + if (topologyView.getEngine(CacheTier.L2).isPresent()) { + return TierDecision.single(CacheTier.L2); + } + if (topologyView.getEngine(CacheTier.L1).isPresent()) { + return TierDecision.single(CacheTier.L1); + } + + return TierDecision.none(); + } + + @Override + public RepresentationDecision selectRepresentation(BlockCacheKey cacheKey, Cacheable block, + CacheWriteContext context, CacheTopologyView topologyView) { + Objects.requireNonNull(cacheKey, "cacheKey must not be null"); + Objects.requireNonNull(block, "block must not be null"); + Objects.requireNonNull(context, "context must not be null"); + Objects.requireNonNull(topologyView, "topologyView must not be null"); + + return RepresentationDecision.CURRENT_HBASE_DEFAULT; + } + + @Override + public PromotionDecision shouldPromote(BlockCacheKey cacheKey, Cacheable block, + CacheTier sourceTier, CacheRequestContext context, CacheTopologyView topologyView) { + Objects.requireNonNull(cacheKey, "cacheKey must not be null"); + Objects.requireNonNull(block, "block must not be null"); + Objects.requireNonNull(sourceTier, "sourceTier must not be null"); + Objects.requireNonNull(context, "context must not be null"); + Objects.requireNonNull(topologyView, "topologyView must not be null"); + /* + * DefaultHBaseCachePlacementAdmissionPolicy should preserve existing placement behavior. If + * meta/index/bloom blocks belong in L1, they should be inserted into L1 when cached. If data + * blocks belong in L2, promoting them to L1 on hit would change current behavior and may + * pollute L1. Therefore the compatibility policy should not promote by default. + */ + return PromotionDecision.none(); + + } + + private static boolean isMetaOrIndexBlock(Cacheable block) { + if (!(block instanceof HFileBlock)) { + return false; + } + + BlockType blockType = ((HFileBlock) block).getBlockType(); + return blockType != null && blockType.getCategory() != BlockType.BlockCategory.DATA; + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/PromotionAction.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/PromotionAction.java new file mode 100644 index 00000000000..94feb91f3d3 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/PromotionAction.java @@ -0,0 +1,37 @@ +/* + * 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; + +/** + * Promotion action selected by cache placement policy. + */ [email protected] +public enum PromotionAction { + + /** + * Do not promote the block. + */ + NONE, + + /** + * Promote the block to another tier. + */ + PROMOTE +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/PromotionDecision.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/PromotionDecision.java new file mode 100644 index 00000000000..87e4cf1584b --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/PromotionDecision.java @@ -0,0 +1,122 @@ +/* + * 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.Objects; +import org.apache.yetus.audience.InterfaceAudience; + +/** + * Decision describing whether and how a cache hit should trigger promotion. + * <p> + * This decision is produced by {@link CachePlacementAdmissionPolicy} and executed by + * {@link CacheTopology}. The policy decides whether promotion should happen and which tier should + * receive the promoted block. The topology decides how promotion is performed for its semantics, + * for example copy for inclusive topology or move for exclusive topology. + * </p> + * <p> + * This class is immutable. The no-promotion decision is represented by {@link #none()}. Promotion + * decisions must include a non-null target tier. + * </p> + */ [email protected] +public final class PromotionDecision { + + private static final PromotionDecision NONE = + new PromotionDecision(PromotionAction.NONE, null, false); + + private final PromotionAction action; + private final CacheTier targetTier; + private final boolean asynchronous; + + private PromotionDecision(PromotionAction action, CacheTier targetTier, boolean asynchronous) { + this.action = Objects.requireNonNull(action, "action must not be null"); + this.targetTier = targetTier; + this.asynchronous = asynchronous; + } + + /** + * Returns a decision that performs no promotion. + * @return no-promotion decision + */ + public static PromotionDecision none() { + return NONE; + } + + /** + * Returns a decision to promote the block to the specified target tier. + * <p> + * The target tier must not be null. The actual promotion mechanics are topology-specific. For + * example, an inclusive topology may copy the block into the target tier while an exclusive + * topology may move the block. + * </p> + * @param targetTier target tier for promotion + * @param asynchronous whether promotion may be performed asynchronously + * @return promotion decision + */ + public static PromotionDecision promoteTo(CacheTier targetTier, boolean asynchronous) { + Objects.requireNonNull(targetTier, "targetTier must not be null"); + return new PromotionDecision(PromotionAction.PROMOTE, targetTier, asynchronous); + } + + /** + * Returns the promotion action. + * @return promotion action + */ + public PromotionAction getAction() { + return action; + } + + /** + * Returns whether this decision requests promotion. + * @return true when promotion is requested + */ + public boolean shouldPromote() { + return action == PromotionAction.PROMOTE; + } + + /** + * Returns whether this decision has a target tier. + * @return true when target tier is available + */ + public boolean hasTargetTier() { + return targetTier != null; + } + + /** + * Returns the target tier for promotion. + * <p> + * This method is valid only when {@link #shouldPromote()} returns true. + * </p> + * @return target tier + * @throws IllegalStateException if this decision does not request promotion + */ + public CacheTier getTargetTier() { + if (targetTier == null) { + throw new IllegalStateException("Promotion target tier is not available"); + } + return targetTier; + } + + /** + * Returns whether promotion may be executed asynchronously. + * @return true when asynchronous promotion is allowed + */ + public boolean isAsynchronous() { + return asynchronous; + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/RepresentationDecision.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/RepresentationDecision.java new file mode 100644 index 00000000000..e30ba8e7172 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/RepresentationDecision.java @@ -0,0 +1,52 @@ +/* + * 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; + +/** + * Decision describing the cached representation for an admitted block. + */ [email protected] +public enum RepresentationDecision { + + /** + * Preserve the representation already produced by current HBase code paths. + */ + + CURRENT_HBASE_DEFAULT, + + /** + * Prefer packed or serialized representation. + */ + + PACKED, + + /** + * Prefer unpacked or ready-to-use representation. + */ + + UNPACKED, + + /** + * Let the target cache engine choose its preferred representation. + */ + + ENGINE_DEFAULT + +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/TierDecision.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/TierDecision.java new file mode 100644 index 00000000000..fb0434b0ff7 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/cache/TierDecision.java @@ -0,0 +1,115 @@ +/* + * 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.Objects; +import org.apache.yetus.audience.InterfaceAudience; + +/** + * Decision describing the target cache tiers for a cache insertion. + * <p> + * This decision explicitly lists the {@link CacheTier}s that should receive the block. It replaces + * implicit or topology-derived placement rules with a clear, ordered set of target tiers. + * </p> + * <p> + * The order of tiers is significant and should reflect placement priority. For example, a policy + * may return {@code [L1, L2]} to indicate that the block should be stored in L1 first and also + * written to L2 (e.g. for inclusive topologies). + * </p> + * <p> + * An empty decision indicates that the block should not be stored in any tier. + * </p> + * <p> + * This class is intentionally simple and immutable. It does not encode topology-specific behavior + * (e.g. inclusive vs exclusive). The {@link CacheTopology} is responsible for interpreting and + * executing this decision. + * </p> + */ [email protected] +public final class TierDecision { + + private static final TierDecision NONE = new TierDecision(List.of()); + + private final List<CacheTier> tiers; + + private TierDecision(List<CacheTier> tiers) { + this.tiers = tiers; + } + + /** + * Returns a decision that does not place the block into any cache tier. + * @return empty tier decision + */ + public static TierDecision none() { + return NONE; + } + + /** + * Returns a decision targeting a single cache tier. + * @param tier target tier + * @return tier decision for a single tier + */ + public static TierDecision single(CacheTier tier) { + Objects.requireNonNull(tier, "tier must not be null"); + return new TierDecision(List.of(tier)); + } + + /** + * Returns a decision targeting multiple cache tiers. + * <p> + * The provided list must not be null, must not contain null elements, and will be copied to + * preserve immutability. + * </p> + * @param tiers ordered list of target tiers + * @return tier decision for multiple tiers, or {@link #none()} if empty + */ + public static TierDecision multiple(List<CacheTier> tiers) { + Objects.requireNonNull(tiers, "tiers must not be null"); + + if (tiers.isEmpty()) { + return NONE; + } + + for (CacheTier tier : tiers) { + Objects.requireNonNull(tier, "tier in tiers must not be null"); + } + + return new TierDecision(List.copyOf(tiers)); + } + + /** + * Returns the ordered list of target tiers. + * <p> + * The returned list is immutable. The order reflects placement priority and may be interpreted by + * the topology when executing the decision. + * </p> + * @return ordered list of target tiers + */ + public List<CacheTier> getTiers() { + return tiers; + } + + /** + * Returns whether this decision contains no target tiers. + * @return true when no tiers are selected + */ + public boolean isEmpty() { + return tiers.isEmpty(); + } +}
