From a279f766dc2ebccee6b90cb0f910781c4ae25ce5 Mon Sep 17 00:00:00 2001 From: Anuj Sharma Date: Tue, 14 Oct 2025 17:32:43 +0530 Subject: [PATCH] HBASE-29644: Refresh_meta triggering compaction on user table Link to JIRA: https://issues.apache.org/jira/browse/HBASE-29644 Description: Consider the two cluster setup with one being active and one read replica. If active cluster create a table with FILE based SFT. If you add few rows through active and do flushes to create few Hfiles and then do refresh_meta from read replica its triggering minor compaction. Which should not happen via read replica, it may create inconsitencies because active is not aware of that event. Cause: This is happening because we should block the compaction event in ReadOnlyController but we missed adding read only guard to preCompactSelection() function. Fix: Add internalReadOnlyGuard to preCompactSelection() in ReadOnlyController --- .../hadoop/hbase/regionserver/CompactSplit.java | 15 +++++++++++---- .../storefiletracker/StoreFileTrackerBase.java | 2 +- .../hbase/security/access/ReadOnlyController.java | 11 +++++++++++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/CompactSplit.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/CompactSplit.java index 4ac1d7c6396f..d8398e4c3e29 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/CompactSplit.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/CompactSplit.java @@ -36,6 +36,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.IntSupplier; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.client.RegionInfo; import org.apache.hadoop.hbase.conf.ConfigurationManager; import org.apache.hadoop.hbase.conf.PropagatingConfigurationObserver; @@ -339,8 +340,9 @@ private void requestCompactionInternal(HRegion region, String why, int priority, protected void requestCompactionInternal(HRegion region, HStore store, String why, int priority, boolean selectNow, CompactionLifeCycleTracker tracker, CompactionCompleteTracker completeTracker, User user) throws IOException { - if (!this.isCompactionsEnabled()) { - LOG.info("Ignoring compaction request for " + region + ",because compaction is disabled."); + if (!this.isCompactionsEnabled() || isReadOnlyEnabled()) { + LOG.info("Ignoring compaction request for " + region + + ",because compaction is disabled or read-only mode is on."); return; } @@ -438,8 +440,8 @@ private Optional selectCompaction(HRegion region, HStore stor CompactionLifeCycleTracker tracker, CompactionCompleteTracker completeTracker, User user) throws IOException { // don't even select for compaction if disableCompactions is set to true - if (!isCompactionsEnabled()) { - LOG.info(String.format("User has disabled compactions")); + if (!isCompactionsEnabled() || isReadOnlyEnabled()) { + LOG.info(String.format("User has disabled compactions or read-only mode is on")); return Optional.empty(); } Optional compaction = store.requestCompaction(priority, tracker, user); @@ -856,6 +858,11 @@ public boolean isCompactionsEnabled() { return compactionsEnabled; } + private boolean isReadOnlyEnabled() { + return conf.getBoolean(HConstants.HBASE_GLOBAL_READONLY_ENABLED_KEY, + HConstants.HBASE_GLOBAL_READONLY_ENABLED_DEFAULT); + } + public void setCompactionsEnabled(boolean compactionsEnabled) { this.compactionsEnabled = compactionsEnabled; this.conf.setBoolean(HBASE_REGION_SERVER_ENABLE_COMPACTION, compactionsEnabled); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/storefiletracker/StoreFileTrackerBase.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/storefiletracker/StoreFileTrackerBase.java index bc24ad579444..29d8e0bcb485 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/storefiletracker/StoreFileTrackerBase.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/storefiletracker/StoreFileTrackerBase.java @@ -143,7 +143,7 @@ private HFileContext createFileContext(Compression.Algorithm compression, public final StoreFileWriter createWriter(CreateStoreFileWriterParams params) throws IOException { if (!isPrimaryReplica || isReadOnlyEnabled()) { throw new IllegalStateException( - "Should not call create writer on secondary replicas or in read only mode"); + "Should not call create writer on secondary replicas or in read-only mode"); } // creating new cache config for each new writer final CacheConfig cacheConf = ctx.getCacheConf(); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/ReadOnlyController.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/ReadOnlyController.java index 5b7ab67df0bf..7bd16d10ef31 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/ReadOnlyController.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/ReadOnlyController.java @@ -53,6 +53,9 @@ import org.apache.hadoop.hbase.filter.Filter; import org.apache.hadoop.hbase.regionserver.FlushLifeCycleTracker; import org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress; +import org.apache.hadoop.hbase.regionserver.Store; +import org.apache.hadoop.hbase.regionserver.StoreFile; +import org.apache.hadoop.hbase.regionserver.compactions.CompactionLifeCycleTracker; import org.apache.hadoop.hbase.util.Pair; import org.apache.hadoop.hbase.wal.WALEdit; import org.apache.yetus.audience.InterfaceAudience; @@ -81,6 +84,7 @@ private void internalReadOnlyGuard() throws IOException { @Override public void start(CoprocessorEnvironment env) throws IOException { + this.globalReadOnlyEnabled = env.getConfiguration().getBoolean(HConstants.HBASE_GLOBAL_READONLY_ENABLED_KEY, HConstants.HBASE_GLOBAL_READONLY_ENABLED_DEFAULT); @@ -131,6 +135,13 @@ public void preFlush(final ObserverContext c, + Store store, List candidates, CompactionLifeCycleTracker tracker) + throws IOException { + internalReadOnlyGuard(); + } + @Override public boolean preCheckAndPut(ObserverContext c, byte[] row, byte[] family, byte[] qualifier, CompareOperator op, ByteArrayComparable comparator,