From e374f66527d46a03d2af7f55f7f714ff978d6f23 Mon Sep 17 00:00:00 2001 From: Anuj Sharma Date: Tue, 10 Mar 2026 16:57:42 +0530 Subject: [PATCH] HBASE-29960 java.lang.IllegalStateException: Should not call create writer on secondary replicas or in read-only mode --- .../org/apache/hadoop/hbase/TableName.java | 10 ++ .../StoreFileTrackerBase.java | 4 +- .../access/RegionReadOnlyController.java | 48 +++--- .../DummyStoreFileTrackerForReadOnlyMode.java | 29 +++- .../TestStoreFileTrackerBaseReadOnlyMode.java | 66 +++++++-- .../TestReadOnlyControllerRegionObserver.java | 138 ++++++++++++++++++ 6 files changed, 255 insertions(+), 40 deletions(-) diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/TableName.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/TableName.java index 73008c7ad5fd..0201d289bea1 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/TableName.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/TableName.java @@ -139,6 +139,7 @@ public static boolean isMetaTableName(final TableName tn) { private final boolean systemTable; private final boolean backupsTable; private final int hashCode; + private final boolean writableInReadOnlyMode; /** * Check passed byte array, "tableName", is legal user-space table name. @@ -305,6 +306,10 @@ public boolean isBackupsTable() { return backupsTable; } + public boolean isWritableInReadOnlyMode() { + return writableInReadOnlyMode; + } + @Override public String toString() { return nameAsString; @@ -329,6 +334,7 @@ private TableName(ByteBuffer namespace, ByteBuffer qualifier) throws IllegalArgu this.namespaceAsString = NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR; this.systemTable = false; this.backupsTable = false; + this.writableInReadOnlyMode = false; // The name does not include the namespace when it's the default one. this.nameAsString = qualifierAsString; @@ -339,17 +345,20 @@ private TableName(ByteBuffer namespace, ByteBuffer qualifier) throws IllegalArgu this.namespaceAsString = NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR; this.systemTable = true; this.backupsTable = false; + this.writableInReadOnlyMode = true; } else if (Bytes.equals(NamespaceDescriptor.BACKUP_NAMESPACE_NAME, namespace)) { this.namespace = NamespaceDescriptor.BACKUP_NAMESPACE_NAME; this.namespaceAsString = NamespaceDescriptor.BACKUP_NAMESPACE_NAME_STR; this.systemTable = true; this.backupsTable = true; + this.writableInReadOnlyMode = false; } else { this.namespace = new byte[namespace.remaining()]; namespace.duplicate().get(this.namespace); this.namespaceAsString = Bytes.toString(this.namespace); this.systemTable = false; this.backupsTable = false; + this.writableInReadOnlyMode = Bytes.equals(Bytes.toBytes("master"), namespace); } this.nameAsString = namespaceAsString + NAMESPACE_DELIM + qualifierAsString; this.name = Bytes.toBytes(nameAsString); @@ -370,6 +379,7 @@ private TableName(String qualifier) { this.namespaceAsString = NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR; this.systemTable = true; this.backupsTable = false; + this.writableInReadOnlyMode = true; // WARNING: nameAsString is different than name for old meta & root! // This is by design. 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 29d8e0bcb485..171be251e99f 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 @@ -141,7 +141,9 @@ private HFileContext createFileContext(Compression.Algorithm compression, @Override public final StoreFileWriter createWriter(CreateStoreFileWriterParams params) throws IOException { - if (!isPrimaryReplica || isReadOnlyEnabled()) { + if ( + !isPrimaryReplica || (isReadOnlyEnabled() && !ctx.getTableName().isWritableInReadOnlyMode()) + ) { throw new IllegalStateException( "Should not call create writer on secondary replicas or in read-only mode"); } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/RegionReadOnlyController.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/RegionReadOnlyController.java index 411b4459f129..cbd16b74b59e 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/RegionReadOnlyController.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/RegionReadOnlyController.java @@ -23,7 +23,6 @@ import org.apache.hadoop.fs.Path; import org.apache.hadoop.hbase.CompareOperator; import org.apache.hadoop.hbase.HBaseInterfaceAudience; -import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Append; import org.apache.hadoop.hbase.client.CheckAndMutate; import org.apache.hadoop.hbase.client.CheckAndMutateResult; @@ -60,8 +59,9 @@ public class RegionReadOnlyController extends AbstractReadOnlyController implements RegionCoprocessor, RegionObserver { - private boolean isOnMeta(final ObserverContext c) { - return TableName.isMetaTableName(c.getEnvironment().getRegionInfo().getTable()); + private boolean + isWritableInReadOnlyMode(final ObserverContext c) { + return c.getEnvironment().getRegionInfo().getTable().isWritableInReadOnlyMode(); } @Override @@ -72,7 +72,7 @@ public Optional getRegionObserver() { @Override public void preFlushScannerOpen(ObserverContext c, Store store, ScanOptions options, FlushLifeCycleTracker tracker) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } RegionObserver.super.preFlushScannerOpen(c, store, options, tracker); @@ -81,7 +81,7 @@ public void preFlushScannerOpen(ObserverContext c, FlushLifeCycleTracker tracker) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } RegionObserver.super.preFlush(c, tracker); @@ -90,7 +90,7 @@ public void preFlush(final ObserverContext c, Store store, InternalScanner scanner, FlushLifeCycleTracker tracker) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } return RegionObserver.super.preFlush(c, store, scanner, tracker); @@ -123,7 +123,7 @@ public InternalScanner preMemStoreCompactionCompact( public void preCompactSelection(ObserverContext c, Store store, List candidates, CompactionLifeCycleTracker tracker) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } RegionObserver.super.preCompactSelection(c, store, candidates, tracker); @@ -133,7 +133,7 @@ public void preCompactSelection(ObserverContext c, Store store, ScanType scanType, ScanOptions options, CompactionLifeCycleTracker tracker, CompactionRequest request) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } RegionObserver.super.preCompactScannerOpen(c, store, scanType, options, tracker, request); @@ -143,7 +143,7 @@ public void preCompactScannerOpen(ObserverContext c, Store store, InternalScanner scanner, ScanType scanType, CompactionLifeCycleTracker tracker, CompactionRequest request) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } return RegionObserver.super.preCompact(c, store, scanner, scanType, tracker, request); @@ -152,7 +152,7 @@ public InternalScanner preCompact(ObserverContext c, Put put, WALEdit edit, Durability durability) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } RegionObserver.super.prePut(c, put, edit, durability); @@ -161,7 +161,7 @@ public void prePut(ObserverContext c, Pu @Override public void prePut(ObserverContext c, Put put, WALEdit edit) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } RegionObserver.super.prePut(c, put, edit); @@ -170,7 +170,7 @@ public void prePut(ObserverContext c, Pu @Override public void preDelete(ObserverContext c, Delete delete, WALEdit edit, Durability durability) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } RegionObserver.super.preDelete(c, delete, edit, durability); @@ -179,7 +179,7 @@ public void preDelete(ObserverContext c, @Override public void preDelete(ObserverContext c, Delete delete, WALEdit edit) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } RegionObserver.super.preDelete(c, delete, edit); @@ -188,7 +188,7 @@ public void preDelete(ObserverContext c, @Override public void preBatchMutate(ObserverContext c, MiniBatchOperationInProgress miniBatchOp) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } RegionObserver.super.preBatchMutate(c, miniBatchOp); @@ -198,7 +198,7 @@ public void preBatchMutate(ObserverContext c, byte[] row, byte[] family, byte[] qualifier, CompareOperator op, ByteArrayComparable comparator, Put put, boolean result) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } return RegionObserver.super.preCheckAndPut(c, row, family, qualifier, op, comparator, put, @@ -208,7 +208,7 @@ public boolean preCheckAndPut(ObserverContext c, byte[] row, Filter filter, Put put, boolean result) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } return RegionObserver.super.preCheckAndPut(c, row, filter, put, result); @@ -219,7 +219,7 @@ public boolean preCheckAndPutAfterRowLock( ObserverContext c, byte[] row, byte[] family, byte[] qualifier, CompareOperator op, ByteArrayComparable comparator, Put put, boolean result) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } return RegionObserver.super.preCheckAndPutAfterRowLock(c, row, family, qualifier, op, @@ -230,7 +230,7 @@ public boolean preCheckAndPutAfterRowLock( public boolean preCheckAndPutAfterRowLock( ObserverContext c, byte[] row, Filter filter, Put put, boolean result) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } return RegionObserver.super.preCheckAndPutAfterRowLock(c, row, filter, put, result); @@ -240,7 +240,7 @@ public boolean preCheckAndPutAfterRowLock( public boolean preCheckAndDelete(ObserverContext c, byte[] row, byte[] family, byte[] qualifier, CompareOperator op, ByteArrayComparable comparator, Delete delete, boolean result) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } return RegionObserver.super.preCheckAndDelete(c, row, family, qualifier, op, comparator, delete, @@ -250,7 +250,7 @@ public boolean preCheckAndDelete(ObserverContext c, byte[] row, Filter filter, Delete delete, boolean result) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } return RegionObserver.super.preCheckAndDelete(c, row, filter, delete, result); @@ -261,7 +261,7 @@ public boolean preCheckAndDeleteAfterRowLock( ObserverContext c, byte[] row, byte[] family, byte[] qualifier, CompareOperator op, ByteArrayComparable comparator, Delete delete, boolean result) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } return RegionObserver.super.preCheckAndDeleteAfterRowLock(c, row, family, qualifier, op, @@ -272,7 +272,7 @@ public boolean preCheckAndDeleteAfterRowLock( public boolean preCheckAndDeleteAfterRowLock( ObserverContext c, byte[] row, Filter filter, Delete delete, boolean result) throws IOException { - if (!isOnMeta(c)) { + if (!isWritableInReadOnlyMode(c)) { internalReadOnlyGuard(); } return RegionObserver.super.preCheckAndDeleteAfterRowLock(c, row, filter, delete, result); @@ -339,7 +339,7 @@ public Result preIncrementAfterRowLock(ObserverContext ctx, RegionInfo info, Path edits) throws IOException { - if (!isOnMeta(ctx)) { + if (!isWritableInReadOnlyMode(ctx)) { internalReadOnlyGuard(); } RegionObserver.super.preReplayWALs(ctx, info, edits); @@ -363,7 +363,7 @@ public void preCommitStoreFile(ObserverContext ctx, WALKey key, WALEdit edit) throws IOException { // Only allow this operation for meta table - if (!TableName.isMetaTableName(key.getTableName())) { + if (!key.getTableName().isWritableInReadOnlyMode()) { internalReadOnlyGuard(); } RegionObserver.super.preWALAppend(ctx, key, edit); diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/storefiletracker/DummyStoreFileTrackerForReadOnlyMode.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/storefiletracker/DummyStoreFileTrackerForReadOnlyMode.java index 5f8268b3ac7c..712199ade99d 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/storefiletracker/DummyStoreFileTrackerForReadOnlyMode.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/storefiletracker/DummyStoreFileTrackerForReadOnlyMode.java @@ -22,16 +22,41 @@ import java.util.Collections; import java.util.List; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.RegionInfo; +import org.apache.hadoop.hbase.client.RegionInfoBuilder; +import org.apache.hadoop.hbase.regionserver.HRegionFileSystem; +import org.apache.hadoop.hbase.regionserver.StoreContext; import org.apache.hadoop.hbase.regionserver.StoreFileInfo; +import org.mockito.Mockito; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class DummyStoreFileTrackerForReadOnlyMode extends StoreFileTrackerBase { + private static final Logger LOG = + LoggerFactory.getLogger(DummyStoreFileTrackerForReadOnlyMode.class); + private boolean readOnlyUsed = false; private boolean compactionExecuted = false; private boolean addExecuted = false; private boolean setExecuted = false; - public DummyStoreFileTrackerForReadOnlyMode(Configuration conf, boolean isPrimaryReplica) { - super(conf, isPrimaryReplica, null); + private static StoreContext buildStoreContext(Configuration conf, TableName tableName) { + RegionInfo regionInfo = RegionInfoBuilder.newBuilder(tableName).build(); + HRegionFileSystem hfs = Mockito.mock(HRegionFileSystem.class); + try { + Mockito.when(hfs.getRegionInfo()).thenReturn(regionInfo); + Mockito.when(hfs.getFileSystem()).thenReturn(FileSystem.get(conf)); + } catch (IOException e) { + LOG.error("Failed to get FileSystem for StoreContext creation", e); + } + return StoreContext.getBuilder().withRegionFileSystem(hfs).build(); + } + + public DummyStoreFileTrackerForReadOnlyMode(Configuration conf, boolean isPrimaryReplica, + TableName tableName) { + super(conf, isPrimaryReplica, buildStoreContext(conf, tableName)); } @Override diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/storefiletracker/TestStoreFileTrackerBaseReadOnlyMode.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/storefiletracker/TestStoreFileTrackerBaseReadOnlyMode.java index 8a1cee55832a..0b779835dbc2 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/storefiletracker/TestStoreFileTrackerBaseReadOnlyMode.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/storefiletracker/TestStoreFileTrackerBaseReadOnlyMode.java @@ -19,11 +19,14 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.util.Collections; import org.apache.hadoop.hbase.HBaseClassTestRule; +import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.TestRefreshHFilesBase; import org.apache.hadoop.hbase.master.procedure.TestRefreshHFilesProcedureWithReadOnlyConf; +import org.apache.hadoop.hbase.master.region.MasterRegionFactory; import org.apache.hadoop.hbase.regionserver.CreateStoreFileWriterParams; import org.apache.hadoop.hbase.testclassification.RegionServerTests; import org.apache.hadoop.hbase.testclassification.SmallTests; @@ -41,6 +44,8 @@ public class TestStoreFileTrackerBaseReadOnlyMode extends TestRefreshHFilesBase public static final HBaseClassTestRule CLASS_RULE = HBaseClassTestRule.forClass(TestRefreshHFilesProcedureWithReadOnlyConf.class); + TableName tableName = TableName.valueOf("TestStoreFileTrackerBaseReadOnlyMode"); + @Before public void setup() throws Exception { // When true is passed only setup for readonly property is done. @@ -57,7 +62,7 @@ public void tearDown() throws Exception { public void testLoadReadOnlyWhenGlobalReadOnlyEnabled() throws Exception { try { setReadOnlyMode(true); - tracker = new DummyStoreFileTrackerForReadOnlyMode(conf, true); + tracker = new DummyStoreFileTrackerForReadOnlyMode(conf, true, tableName); tracker.load(); assertTrue("Tracker should be in read-only mode", tracker.wasReadOnlyLoad()); } catch (Exception e) { @@ -71,7 +76,7 @@ public void testLoadReadOnlyWhenGlobalReadOnlyEnabled() throws Exception { public void testReplaceSkippedWhenGlobalReadOnlyEnabled() throws Exception { try { setReadOnlyMode(true); - tracker = new DummyStoreFileTrackerForReadOnlyMode(conf, true); + tracker = new DummyStoreFileTrackerForReadOnlyMode(conf, true, tableName); tracker.replace(Collections.emptyList(), Collections.emptyList()); assertFalse("Compaction should not be executed in readonly mode", tracker.wasCompactionExecuted()); @@ -84,7 +89,7 @@ public void testReplaceSkippedWhenGlobalReadOnlyEnabled() throws Exception { @Test public void testReplaceExecutedWhenWritable() throws Exception { - tracker = new DummyStoreFileTrackerForReadOnlyMode(conf, true); + tracker = new DummyStoreFileTrackerForReadOnlyMode(conf, true, tableName); tracker.replace(Collections.emptyList(), Collections.emptyList()); assertTrue("Compaction should run when not readonly", tracker.wasCompactionExecuted()); } @@ -93,7 +98,7 @@ public void testReplaceExecutedWhenWritable() throws Exception { public void testAddSkippedWhenGlobalReadOnlyEnabled() throws Exception { try { setReadOnlyMode(true); - tracker = new DummyStoreFileTrackerForReadOnlyMode(conf, true); + tracker = new DummyStoreFileTrackerForReadOnlyMode(conf, true, tableName); tracker.add(Collections.emptyList()); assertFalse("Add should not be executed in readonly mode", tracker.wasAddExecuted()); } catch (Exception e) { @@ -105,7 +110,7 @@ public void testAddSkippedWhenGlobalReadOnlyEnabled() throws Exception { @Test public void testAddExecutedWhenWritable() throws Exception { - tracker = new DummyStoreFileTrackerForReadOnlyMode(conf, true); + tracker = new DummyStoreFileTrackerForReadOnlyMode(conf, true, tableName); tracker.add(Collections.emptyList()); assertTrue("Add should run when not readonly", tracker.wasAddExecuted()); } @@ -114,7 +119,7 @@ public void testAddExecutedWhenWritable() throws Exception { public void testSetSkippedWhenGlobalReadOnlyEnabled() throws Exception { try { setReadOnlyMode(true); - tracker = new DummyStoreFileTrackerForReadOnlyMode(conf, true); + tracker = new DummyStoreFileTrackerForReadOnlyMode(conf, true, tableName); tracker.set(Collections.emptyList()); assertFalse("Set should not be executed in readonly mode", tracker.wasSetExecuted()); } catch (Exception e) { @@ -126,21 +131,56 @@ public void testSetSkippedWhenGlobalReadOnlyEnabled() throws Exception { @Test public void testSetExecutedWhenWritable() throws Exception { - tracker = new DummyStoreFileTrackerForReadOnlyMode(conf, true); + tracker = new DummyStoreFileTrackerForReadOnlyMode(conf, true, tableName); tracker.set(Collections.emptyList()); assertTrue("Set should run when not readonly", tracker.wasSetExecuted()); } - @Test(expected = IllegalStateException.class) - public void testCreateWriterThrowExceptionWhenGlobalReadOnlyEnabled() throws Exception { + private CreateStoreFileWriterParams createParams() { + return CreateStoreFileWriterParams.create().maxKeyCount(4).isCompaction(false) + .includeMVCCReadpoint(true).includesTag(false).shouldDropBehind(false); + } + + private void assertIllegalStateThrown(TableName tableName) throws Exception { + try { + setReadOnlyMode(true); + tracker = new DummyStoreFileTrackerForReadOnlyMode(conf, true, tableName); + tracker.createWriter(createParams()); + fail("Expected IllegalStateException"); + } finally { + setReadOnlyMode(false); + } + } + + private void assertNoIllegalStateThrown(TableName tableName) throws Exception { try { setReadOnlyMode(true); - tracker = new DummyStoreFileTrackerForReadOnlyMode(conf, true); - CreateStoreFileWriterParams params = CreateStoreFileWriterParams.create().maxKeyCount(4) - .isCompaction(false).includeMVCCReadpoint(true).includesTag(false).shouldDropBehind(false); - tracker.createWriter(params); + tracker = new DummyStoreFileTrackerForReadOnlyMode(conf, true, tableName); + try { + tracker.createWriter(createParams()); + } catch (IllegalStateException e) { + fail("Should not throw IllegalStateException for table " + tableName); + } catch (Exception e) { + // Ignore other exceptions as they are not the focus of this test + } } finally { setReadOnlyMode(false); } } + + @Test(expected = IllegalStateException.class) + public void testCreateWriterThrowExceptionWhenGlobalReadOnlyEnabled() throws Exception { + assertIllegalStateThrown(tableName); + } + + @Test + public void testCreateWriterNoExceptionMetaTableWhenGlobalReadOnlyEnabled() throws Exception { + assertNoIllegalStateThrown(TableName.META_TABLE_NAME); + } + + @Test + public void testCreateWriterNoExceptionMasterStoreTableWhenGlobalReadOnlyEnabled() + throws Exception { + assertNoIllegalStateThrown(MasterRegionFactory.TABLE_NAME); + } } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestReadOnlyControllerRegionObserver.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestReadOnlyControllerRegionObserver.java index d7176b900552..f56a88399531 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestReadOnlyControllerRegionObserver.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestReadOnlyControllerRegionObserver.java @@ -40,6 +40,7 @@ import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment; import org.apache.hadoop.hbase.filter.ByteArrayComparable; import org.apache.hadoop.hbase.filter.Filter; +import org.apache.hadoop.hbase.master.region.MasterRegionFactory; import org.apache.hadoop.hbase.regionserver.FlushLifeCycleTracker; import org.apache.hadoop.hbase.regionserver.InternalScanner; import org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress; @@ -175,6 +176,10 @@ private void mockOperationForMetaTable() { when(regionInfo.getTable()).thenReturn(TableName.META_TABLE_NAME); } + private void mockOperationMasterStoreTable() { + when(regionInfo.getTable()).thenReturn(MasterRegionFactory.TABLE_NAME); + } + @Test(expected = DoNotRetryIOException.class) public void testPreFlushV1ReadOnlyException() throws IOException { regionReadOnlyController.preFlush(c, flushLifeCycleTracker); @@ -186,6 +191,12 @@ public void testPreFlushV1ReadOnlyMetaNoException() throws IOException { regionReadOnlyController.preFlush(c, flushLifeCycleTracker); } + @Test + public void testPreFlushV1ReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preFlush(c, flushLifeCycleTracker); + } + @Test(expected = DoNotRetryIOException.class) public void testPreFlushV2ReadOnlyException() throws IOException { regionReadOnlyController.preFlush(c, store, scanner, flushLifeCycleTracker); @@ -197,6 +208,12 @@ public void testPreFlushV2ReadOnlyMetaNoException() throws IOException { regionReadOnlyController.preFlush(c, store, scanner, flushLifeCycleTracker); } + @Test + public void testPreFlushV2ReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preFlush(c, store, scanner, flushLifeCycleTracker); + } + @Test(expected = DoNotRetryIOException.class) public void testPreFlushScannerOpenReadOnlyException() throws IOException { regionReadOnlyController.preFlushScannerOpen(c, store, options, flushLifeCycleTracker); @@ -208,6 +225,12 @@ public void testPreFlushScannerOpenReadOnlyMetaNoException() throws IOException regionReadOnlyController.preFlushScannerOpen(c, store, options, flushLifeCycleTracker); } + @Test + public void testPreFlushScannerOpenReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preFlushScannerOpen(c, store, options, flushLifeCycleTracker); + } + @Test(expected = DoNotRetryIOException.class) public void testPreMemStoreCompactionReadOnlyException() throws IOException { regionReadOnlyController.preMemStoreCompaction(c, store); @@ -234,6 +257,12 @@ public void testPreCompactSelectionReadOnlyMetaNoException() throws IOException regionReadOnlyController.preCompactSelection(c, store, candidates, compactionLifeCycleTracker); } + @Test + public void testPreCompactSelectionReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preCompactSelection(c, store, candidates, compactionLifeCycleTracker); + } + @Test(expected = DoNotRetryIOException.class) public void testPreCompactScannerOpenReadOnlyException() throws IOException { regionReadOnlyController.preCompactScannerOpen(c, store, scanType, options, @@ -247,6 +276,13 @@ public void testPreCompactScannerOpenReadOnlyMetaNoException() throws IOExceptio compactionLifeCycleTracker, compactionRequest); } + @Test + public void testPreCompactScannerOpenReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preCompactScannerOpen(c, store, scanType, options, + compactionLifeCycleTracker, compactionRequest); + } + @Test(expected = DoNotRetryIOException.class) public void testPreCompactReadOnlyException() throws IOException { regionReadOnlyController.preCompact(c, store, scanner, scanType, compactionLifeCycleTracker, @@ -260,6 +296,13 @@ public void testPreCompactReadOnlyMetaNoException() throws IOException { compactionRequest); } + @Test + public void testPreCompactReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preCompact(c, store, scanner, scanType, compactionLifeCycleTracker, + compactionRequest); + } + @Test(expected = DoNotRetryIOException.class) public void testPrePutV1ReadOnlyException() throws IOException { regionReadOnlyController.prePut(c, put, edit); @@ -271,6 +314,12 @@ public void testPrePutV1ReadOnlyMetaNoException() throws IOException { regionReadOnlyController.prePut(c, put, edit); } + @Test + public void testPrePutV1ReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.prePut(c, put, edit); + } + @Test(expected = DoNotRetryIOException.class) public void testPrePutV2ReadOnlyException() throws IOException { regionReadOnlyController.prePut(c, put, edit, durability); @@ -282,6 +331,12 @@ public void testPrePutV2ReadOnlyMetaNoException() throws IOException { regionReadOnlyController.prePut(c, put, edit, durability); } + @Test + public void testPrePutV2ReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.prePut(c, put, edit, durability); + } + @Test(expected = DoNotRetryIOException.class) public void testPreDeleteV1ReadOnlyException() throws IOException { regionReadOnlyController.preDelete(c, delete, edit); @@ -293,6 +348,12 @@ public void testPreDeleteV1ReadOnlyMetaNoException() throws IOException { regionReadOnlyController.preDelete(c, delete, edit); } + @Test + public void testPreDeleteV1ReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preDelete(c, delete, edit); + } + @Test(expected = DoNotRetryIOException.class) public void testPreDeleteV2ReadOnlyException() throws IOException { regionReadOnlyController.preDelete(c, delete, edit, durability); @@ -304,6 +365,12 @@ public void testPreDeleteV2ReadOnlyMetaNoException() throws IOException { regionReadOnlyController.preDelete(c, delete, edit, durability); } + @Test + public void testPreDeleteV2ReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preDelete(c, delete, edit, durability); + } + @Test(expected = DoNotRetryIOException.class) public void testPreBatchMutateReadOnlyException() throws IOException { regionReadOnlyController.preBatchMutate(c, miniBatchOp); @@ -315,6 +382,12 @@ public void testPreBatchMutateReadOnlyMetaNoException() throws IOException { regionReadOnlyController.preBatchMutate(c, miniBatchOp); } + @Test + public void testPreBatchMutateReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preBatchMutate(c, miniBatchOp); + } + @Test(expected = DoNotRetryIOException.class) public void testPreCheckAndPutV1ReadOnlyException() throws IOException { regionReadOnlyController.preCheckAndPut(c, row, family, qualifier, op, comparator, put, result); @@ -326,6 +399,12 @@ public void testPreCheckAndPutV1ReadOnlyMetaNoException() throws IOException { regionReadOnlyController.preCheckAndPut(c, row, family, qualifier, op, comparator, put, result); } + @Test + public void testPreCheckAndPutV1ReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preCheckAndPut(c, row, family, qualifier, op, comparator, put, result); + } + @Test(expected = DoNotRetryIOException.class) public void testPreCheckAndPutV2ReadOnlyException() throws IOException { regionReadOnlyController.preCheckAndPut(c, row, filter, put, result); @@ -337,6 +416,12 @@ public void testPreCheckAndPutV2ReadOnlyMetaNoException() throws IOException { regionReadOnlyController.preCheckAndPut(c, row, filter, put, result); } + @Test + public void testPreCheckAndPutV2ReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preCheckAndPut(c, row, filter, put, result); + } + @Test(expected = DoNotRetryIOException.class) public void testPreCheckAndPutAfterRowLockV1ReadOnlyException() throws IOException { regionReadOnlyController.preCheckAndPutAfterRowLock(c, row, family, qualifier, op, comparator, @@ -350,6 +435,13 @@ public void testPreCheckAndPutAfterRowLockV1ReadOnlyMetaNoException() throws IOE put, result); } + @Test + public void testPreCheckAndPutAfterRowLockV1ReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preCheckAndPutAfterRowLock(c, row, family, qualifier, op, comparator, + put, result); + } + @Test(expected = DoNotRetryIOException.class) public void testPreCheckAndPutAfterRowLockV2ReadOnlyException() throws IOException { regionReadOnlyController.preCheckAndPutAfterRowLock(c, row, filter, put, result); @@ -361,6 +453,12 @@ public void testPreCheckAndPutAfterRowLockV2ReadOnlyMetaNoException() throws IOE regionReadOnlyController.preCheckAndPutAfterRowLock(c, row, filter, put, result); } + @Test + public void testPreCheckAndPutAfterRowLockV2ReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preCheckAndPutAfterRowLock(c, row, filter, put, result); + } + @Test(expected = DoNotRetryIOException.class) public void testPreCheckAndDeleteV1ReadOnlyException() throws IOException { regionReadOnlyController.preCheckAndDelete(c, row, family, qualifier, op, comparator, delete, @@ -374,6 +472,13 @@ public void testPreCheckAndDeleteV1ReadOnlyMetaNoException() throws IOException result); } + @Test + public void testPreCheckAndDeleteV1ReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preCheckAndDelete(c, row, family, qualifier, op, comparator, delete, + result); + } + @Test(expected = DoNotRetryIOException.class) public void testPreCheckAndDeleteV2ReadOnlyException() throws IOException { regionReadOnlyController.preCheckAndDelete(c, row, filter, delete, result); @@ -385,6 +490,12 @@ public void testPreCheckAndDeleteV2ReadOnlyMetaNoException() throws IOException regionReadOnlyController.preCheckAndDelete(c, row, filter, delete, result); } + @Test + public void testPreCheckAndDeleteV2ReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preCheckAndDelete(c, row, filter, delete, result); + } + @Test(expected = DoNotRetryIOException.class) public void testPreCheckAndDeleteAfterRowLockV1ReadOnlyException() throws IOException { regionReadOnlyController.preCheckAndDeleteAfterRowLock(c, row, family, qualifier, op, @@ -398,6 +509,14 @@ public void testPreCheckAndDeleteAfterRowLockV1ReadOnlyMetaNoException() throws comparator, delete, result); } + @Test + public void testPreCheckAndDeleteAfterRowLockV1ReadOnlyMasterStoreNoException() + throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preCheckAndDeleteAfterRowLock(c, row, family, qualifier, op, + comparator, delete, result); + } + @Test(expected = DoNotRetryIOException.class) public void testPreCheckAndDeleteAfterRowLockV2ReadOnlyException() throws IOException { regionReadOnlyController.preCheckAndDeleteAfterRowLock(c, row, filter, delete, result); @@ -409,6 +528,13 @@ public void testPreCheckAndDeleteAfterRowLockV2ReadOnlyMetaNoException() throws regionReadOnlyController.preCheckAndDeleteAfterRowLock(c, row, filter, delete, result); } + @Test + public void testPreCheckAndDeleteAfterRowLockV2ReadOnlyMasterStoreNoException() + throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preCheckAndDeleteAfterRowLock(c, row, filter, delete, result); + } + @Test(expected = DoNotRetryIOException.class) public void testPreCheckAndMutateReadOnlyException() throws IOException { regionReadOnlyController.preCheckAndMutate(c, checkAndMutate, checkAndMutateResult); @@ -460,6 +586,12 @@ public void testPreReplayWALsReadOnlyMetaNoException() throws IOException { regionReadOnlyController.preReplayWALs(ctx, info, edits); } + @Test + public void testPreReplayWALsReadOnlyMasterStoreNoException() throws IOException { + mockOperationMasterStoreTable(); + regionReadOnlyController.preReplayWALs(ctx, info, edits); + } + @Test(expected = DoNotRetryIOException.class) public void testPreBulkLoadHFileReadOnlyException() throws IOException { regionReadOnlyController.preBulkLoadHFile(ctx, familyPaths); @@ -480,4 +612,10 @@ public void testPreWALAppendReadOnlyMetaNoException() throws IOException { when(key.getTableName()).thenReturn(TableName.META_TABLE_NAME); regionReadOnlyController.preWALAppend(ctx, key, edit); } + + @Test + public void testPreWALAppendReadOnlyMasterStoreNoException() throws IOException { + when(key.getTableName()).thenReturn(MasterRegionFactory.TABLE_NAME); + regionReadOnlyController.preWALAppend(ctx, key, edit); + } }