From 45317a1e42d775ecd816b88d3b5440e8676c0af8 Mon Sep 17 00:00:00 2001 From: dParikesit Date: Wed, 18 Mar 2026 13:02:57 -0400 Subject: [PATCH] add fix and test --- .../procedure/CreateNamespaceProcedure.java | 2 +- .../procedure/DeleteNamespaceProcedure.java | 2 +- .../TestCreateNamespaceProcedure.java | 48 +++++++++++++++++++ .../TestDeleteNamespaceProcedure.java | 47 ++++++++++++++++++ 4 files changed, 97 insertions(+), 2 deletions(-) diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CreateNamespaceProcedure.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CreateNamespaceProcedure.java index 726ad6a9b0b5..cc26c1e6513a 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CreateNamespaceProcedure.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/CreateNamespaceProcedure.java @@ -200,7 +200,7 @@ private boolean prepareCreate(final MasterProcedureEnv env) throws IOException { private static void setNamespaceQuota(final MasterProcedureEnv env, final NamespaceDescriptor nsDescriptor) throws IOException { if (env.getMasterServices().isInitialized()) { - env.getMasterServices().getMasterQuotaManager().setNamespaceQuota(nsDescriptor); + ProcedureSyncWait.getMasterQuotaManager(env).setNamespaceQuota(nsDescriptor); } } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/DeleteNamespaceProcedure.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/DeleteNamespaceProcedure.java index dc968da609e0..e0ea1d336e46 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/DeleteNamespaceProcedure.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/DeleteNamespaceProcedure.java @@ -258,6 +258,6 @@ private static void deleteDirectory(MasterProcedureEnv env, String namespaceName **/ private static void removeNamespaceQuota(final MasterProcedureEnv env, final String namespaceName) throws IOException { - env.getMasterServices().getMasterQuotaManager().removeNamespaceQuota(namespaceName); + ProcedureSyncWait.getMasterQuotaManager(env).removeNamespaceQuota(namespaceName); } } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateNamespaceProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateNamespaceProcedure.java index 384be5613006..bcbeff28b681 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateNamespaceProcedure.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestCreateNamespaceProcedure.java @@ -20,6 +20,11 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import java.io.IOException; import org.apache.hadoop.conf.Configuration; @@ -29,9 +34,13 @@ import org.apache.hadoop.hbase.NamespaceExistException; import org.apache.hadoop.hbase.NamespaceNotFoundException; import org.apache.hadoop.hbase.constraint.ConstraintException; +import org.apache.hadoop.hbase.master.MasterServices; import org.apache.hadoop.hbase.procedure2.Procedure; import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility; +import org.apache.hadoop.hbase.procedure2.StateMachineProcedure.Flow; +import org.apache.hadoop.hbase.quotas.MasterQuotaManager; +import org.apache.hadoop.hbase.security.User; import org.apache.hadoop.hbase.testclassification.MasterTests; import org.apache.hadoop.hbase.testclassification.MediumTests; import org.junit.After; @@ -44,6 +53,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.CreateNamespaceState; + @Category({ MasterTests.class, MediumTests.class }) public class TestCreateNamespaceProcedure { @@ -228,6 +239,28 @@ public void testRollbackAndDoubleExecution() throws Exception { } } + @Test + public void testCreateNamespaceQuotaStepWaitsForQuotaManagerAfterInitialization() + throws Exception { + final NamespaceDescriptor nsd = + NamespaceDescriptor.create("testCreateNamespaceWithNullQuotaManager").build(); + final MasterProcedureEnv env = mock(MasterProcedureEnv.class); + final MasterServices masterServices = mock(MasterServices.class); + final MasterQuotaManager masterQuotaManager = mock(MasterQuotaManager.class); + final CreateNamespaceProcedure proc = + createProcedureForQuotaStep(env, nsd, masterServices, masterQuotaManager); + + // The initialized event has already been released, but the quota manager is not available on + // the first poll yet. + when(env.waitInitialized(proc)).thenReturn(false); + + assertFalse(proc.waitInitialized(env)); + assertEquals(Flow.NO_MORE_STATE, + proc.executeFromState(env, CreateNamespaceState.CREATE_NAMESPACE_SET_NAMESPACE_QUOTA)); + assertFalse(proc.isFailed()); + verify(masterQuotaManager).setNamespaceQuota(nsd); + } + private ProcedureExecutor getMasterProcedureExecutor() { return UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor(); } @@ -236,4 +269,19 @@ private void validateNamespaceCreated(NamespaceDescriptor nsd) throws IOExceptio NamespaceDescriptor createdNsDescriptor = UTIL.getAdmin().getNamespaceDescriptor(nsd.getName()); assertNotNull(createdNsDescriptor); } + + private static CreateNamespaceProcedure createProcedureForQuotaStep(MasterProcedureEnv env, + NamespaceDescriptor nsd, MasterServices masterServices, MasterQuotaManager masterQuotaManager) + throws IOException { + Configuration conf = new Configuration(false); + conf.setLong("hbase.master.wait.on.region", 1000); + conf.setInt("hbase.master.event.waiting.time", 1); + when(env.getRequestUser()).thenReturn(User.getCurrent()); + when(env.getMasterConfiguration()).thenReturn(conf); + when(env.getMasterServices()).thenReturn(masterServices); + when(env.isRunning()).thenReturn(true); + when(masterServices.isInitialized()).thenReturn(true); + when(masterServices.getMasterQuotaManager()).thenReturn(null, masterQuotaManager); + return new CreateNamespaceProcedure(env, nsd); + } } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteNamespaceProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteNamespaceProcedure.java index 6df3718327b2..33929919e38b 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteNamespaceProcedure.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestDeleteNamespaceProcedure.java @@ -20,6 +20,11 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import java.io.IOException; import org.apache.hadoop.conf.Configuration; @@ -30,9 +35,13 @@ import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.TableDescriptor; import org.apache.hadoop.hbase.constraint.ConstraintException; +import org.apache.hadoop.hbase.master.MasterServices; import org.apache.hadoop.hbase.procedure2.Procedure; import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility; +import org.apache.hadoop.hbase.procedure2.StateMachineProcedure.Flow; +import org.apache.hadoop.hbase.quotas.MasterQuotaManager; +import org.apache.hadoop.hbase.security.User; import org.apache.hadoop.hbase.testclassification.MasterTests; import org.apache.hadoop.hbase.testclassification.MediumTests; import org.junit.After; @@ -47,6 +56,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.DeleteNamespaceState; + @Category({ MasterTests.class, MediumTests.class }) public class TestDeleteNamespaceProcedure { @@ -209,6 +220,27 @@ public void testRollbackAndDoubleExecution() throws Exception { assertNotNull(createdNsDescriptor); } + @Test + public void testDeleteNamespaceQuotaStepWaitsForQuotaManagerAfterInitialization() + throws Exception { + final String namespaceName = "testDeleteNamespaceWithNullQuotaManager"; + final MasterProcedureEnv env = mock(MasterProcedureEnv.class); + final MasterServices masterServices = mock(MasterServices.class); + final MasterQuotaManager masterQuotaManager = mock(MasterQuotaManager.class); + final DeleteNamespaceProcedure proc = + createProcedureForQuotaStep(env, namespaceName, masterServices, masterQuotaManager); + + // The initialized event has already been released, but the quota manager is not available on + // the first poll yet. + when(env.waitInitialized(proc)).thenReturn(false); + + assertFalse(proc.waitInitialized(env)); + assertEquals(Flow.NO_MORE_STATE, + proc.executeFromState(env, DeleteNamespaceState.DELETE_NAMESPACE_REMOVE_NAMESPACE_QUOTA)); + assertFalse(proc.isFailed()); + verify(masterQuotaManager).removeNamespaceQuota(namespaceName); + } + private ProcedureExecutor getMasterProcedureExecutor() { return UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor(); } @@ -232,4 +264,19 @@ public static void validateNamespaceNotExist(final String nsName) throws IOExcep // Expected } } + + private static DeleteNamespaceProcedure createProcedureForQuotaStep(MasterProcedureEnv env, + String namespaceName, MasterServices masterServices, MasterQuotaManager masterQuotaManager) + throws IOException { + Configuration conf = new Configuration(false); + conf.setLong("hbase.master.wait.on.region", 1000); + conf.setInt("hbase.master.event.waiting.time", 1); + when(env.getRequestUser()).thenReturn(User.getCurrent()); + when(env.getMasterConfiguration()).thenReturn(conf); + when(env.getMasterServices()).thenReturn(masterServices); + when(env.isRunning()).thenReturn(true); + when(masterServices.isInitialized()).thenReturn(true); + when(masterServices.getMasterQuotaManager()).thenReturn(null, masterQuotaManager); + return new DeleteNamespaceProcedure(env, namespaceName); + } }