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: <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()); + } +}
