This is an automated email from the ASF dual-hosted git repository.

andor pushed a commit to branch HBASE-29081
in repository https://gitbox.apache.org/repos/asf/hbase.git

commit dfc7dac23ee9eaf6cab7f98432cca7dda0d07f1f
Author: Abhishek Kothalikar <[email protected]>
AuthorDate: Tue Mar 11 20:03:25 2025 +0530

    HBASE-29082: Support for custom meta table name suffix (#6632)
    
    (cherry picked from commit 7ab9d52801fc5be72b742582d1732a8f5e602d86)
---
 .../java/org/apache/hadoop/hbase/HConstants.java   |  12 +++
 .../java/org/apache/hadoop/hbase/TableName.java    |  37 ++++++-
 .../hadoop/hbase/TestMetaTableForReplica.java      | 114 +++++++++++++++++++++
 3 files changed, 160 insertions(+), 3 deletions(-)

diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java 
b/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java
index eba3eb657ea..3230d92b3e1 100644
--- a/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java
+++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java
@@ -1646,6 +1646,18 @@ public final class HConstants {
    */
   public final static boolean REJECT_DECOMMISSIONED_HOSTS_DEFAULT = false;
 
+  /**
+   * Adds a suffix to the meta table name: value=’test’ -> ‘hbase:meta_test’ 
Added in HBASE-XXXXX to
+   * support having multiple hbase:meta tables (with distinct names )to enable 
storage sharing by
+   * more than one clusters.
+   */
+  public final static String HBASE_META_TABLE_SUFFIX = 
"hbase.meta.table.suffix";
+
+  /**
+   * Default value of {@link #HBASE_META_TABLE_SUFFIX}
+   */
+  public final static String HBASE_META_TABLE_SUFFIX_DEFAULT_VALUE = "";
+
   private HConstants() {
     // Can't be instantiated with this ctor.
   }
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 b6d854c1378..73008c7ad5f 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
@@ -17,16 +17,21 @@
  */
 package org.apache.hadoop.hbase;
 
+import com.google.errorprone.annotations.RestrictedApi;
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArraySet;
 import org.apache.commons.lang3.ArrayUtils;
+import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.yetus.audience.InterfaceAudience;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
+import org.apache.hbase.thirdparty.com.google.common.base.Strings;
 
 /**
  * Immutable POJO class for representing a table name. Which is of the form: 
&lt;table
@@ -44,6 +49,7 @@ import 
org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
  */
 @InterfaceAudience.Public
 public final class TableName implements Comparable<TableName> {
+  private static final Logger LOG = LoggerFactory.getLogger(TableName.class);
 
   /** See {@link #createTableNameIfNecessary(ByteBuffer, ByteBuffer)} */
   private static final Set<TableName> tableCache = new CopyOnWriteArraySet<>();
@@ -65,9 +71,34 @@ public final class TableName implements 
Comparable<TableName> {
   public static final String VALID_USER_TABLE_REGEX = "(?:(?:(?:" + 
VALID_NAMESPACE_REGEX + "\\"
     + NAMESPACE_DELIM + ")?)" + "(?:" + VALID_TABLE_QUALIFIER_REGEX + "))";
 
-  /** The hbase:meta table's name. */
-  public static final TableName META_TABLE_NAME =
-    valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "meta");
+  /**
+   * The name of hbase meta table could either be hbase:meta_xxx or 
'hbase:meta' otherwise. Config
+   * hbase.meta.table.suffix will govern the decision of adding suffix to the 
habase:meta
+   */
+  public static final TableName META_TABLE_NAME;
+  static {
+    Configuration conf = HBaseConfiguration.create();
+    META_TABLE_NAME = initializeHbaseMetaTableName(conf);
+    LOG.info("Meta table name: {}", META_TABLE_NAME);
+  }
+
+  /* Visible for testing only */
+  @RestrictedApi(explanation = "Should only be called in tests", link = "",
+      allowedOnPath = ".*/src/test/.*")
+  public static TableName getDefaultNameOfMetaForReplica() {
+    return valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "meta");
+  }
+
+  public static TableName initializeHbaseMetaTableName(Configuration conf) {
+    String suffix_val = conf.get(HConstants.HBASE_META_TABLE_SUFFIX,
+      HConstants.HBASE_META_TABLE_SUFFIX_DEFAULT_VALUE);
+    LOG.info("Meta table suffix value: {}", suffix_val);
+    if (Strings.isNullOrEmpty(suffix_val)) {
+      return valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "meta");
+    } else {
+      return valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "meta_" + 
suffix_val);
+    }
+  }
 
   /**
    * The Namespace table's name.
diff --git 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/TestMetaTableForReplica.java
 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestMetaTableForReplica.java
new file mode 100644
index 00000000000..d4e3d2c8ce0
--- /dev/null
+++ 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestMetaTableForReplica.java
@@ -0,0 +1,114 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.client.Connection;
+import org.apache.hadoop.hbase.client.ConnectionFactory;
+import org.apache.hadoop.hbase.client.RegionInfo;
+import org.apache.hadoop.hbase.master.HMaster;
+import org.apache.hadoop.hbase.testclassification.MediumTests;
+import org.apache.hadoop.hbase.testclassification.MiscTests;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.util.Pair;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test {@link org.apache.hadoop.hbase.TestMetaTableForReplica}.
+ */
+@Category({ MiscTests.class, MediumTests.class })
+@SuppressWarnings("deprecation")
+public class TestMetaTableForReplica {
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestMetaTableForReplica.class);
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(TestMetaTableForReplica.class);
+  private static final HBaseTestingUtil UTIL = new HBaseTestingUtil();
+  private static Connection connection;
+
+  @Rule
+  public TestName name = new TestName();
+
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    Configuration c = UTIL.getConfiguration();
+    // quicker heartbeat interval for faster DN death notification
+    c.setInt("hbase.ipc.client.connect.max.retries", 1);
+    c.setInt(HConstants.ZK_SESSION_TIMEOUT, 1000);
+    // Start cluster having non-default hbase meta table name
+    c.setStrings(HConstants.HBASE_META_TABLE_SUFFIX, "test");
+    UTIL.startMiniCluster(3);
+    connection = ConnectionFactory.createConnection(c);
+  }
+
+  @AfterClass
+  public static void afterClass() throws Exception {
+    connection.close();
+    UTIL.shutdownMiniCluster();
+  }
+
+  @Test
+  public void testStateOfMetaForReplica() {
+    HMaster m = UTIL.getMiniHBaseCluster().getMaster();
+    assertTrue(m.waitForMetaOnline());
+  }
+
+  @Test
+  public void testNameOfMetaForReplica() {
+    // Check the correctness of the meta table for replica
+    String metaTableName = 
TableName.META_TABLE_NAME.getNameWithNamespaceInclAsString();
+    assertNotNull(metaTableName);
+
+    // Check if name of the meta table for replica is not same as default table
+    assertEquals(0,
+      
TableName.META_TABLE_NAME.compareTo(TableName.getDefaultNameOfMetaForReplica()));
+  }
+
+  @Test
+  public void testGetNonExistentRegionFromMetaFromReplica() throws IOException 
{
+    final String name = this.name.getMethodName();
+    LOG.info("Started " + name);
+    Pair<RegionInfo, ServerName> pair =
+      MetaTableAccessor.getRegion(connection, 
Bytes.toBytes("nonexistent-region"));
+    assertNull(pair);
+    LOG.info("Finished " + name);
+  }
+
+  @Test
+  public void testGetExistentRegionFromMetaFromReplica() throws IOException {
+    final TableName tableName = TableName.valueOf(name.getMethodName());
+    LOG.info("Started " + tableName);
+    UTIL.createTable(tableName, HConstants.CATALOG_FAMILY);
+    assertEquals(1, MetaTableAccessor.getTableRegions(connection, 
tableName).size());
+  }
+}

Reply via email to