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

guluo2016 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/master by this push:
     new 5d6b024a5ed HBASE-30336 An extra empty MOB region dir is created under 
the table dir when restoring a MOB table from snapshot (#8558)
5d6b024a5ed is described below

commit 5d6b024a5ed5d9b2f831e9e2808c91feac2c039c
Author: Peng Lu <[email protected]>
AuthorDate: Mon Aug 24 23:57:45 2026 +0800

    HBASE-30336 An extra empty MOB region dir is created under the table dir 
when restoring a MOB table from snapshot (#8558)
    
    Signed-off-by: Xiao Liu <[email protected]>
---
 .../hbase/snapshot/RestoreSnapshotHelper.java      | 26 ++++++-----
 .../snapshot/TestMobRestoreSnapshotHelper.java     | 52 ++++++++++++++++++++++
 2 files changed, 66 insertions(+), 12 deletions(-)

diff --git 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/RestoreSnapshotHelper.java
 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/RestoreSnapshotHelper.java
index f0f1ba3899a..6b40601d154 100644
--- 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/RestoreSnapshotHelper.java
+++ 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/RestoreSnapshotHelper.java
@@ -638,26 +638,28 @@ public class RestoreSnapshotHelper {
     final RegionInfo region) throws IOException {
     // clone region info (change embedded tableName with the new one)
     Path clonedRegionPath = MobUtils.getMobRegionPath(rootDir, 
tableDesc.getTableName());
-    cloneRegion(MobUtils.getMobRegionInfo(tableDesc.getTableName()), 
clonedRegionPath, region,
-      regionManifests.get(region.getEncodedName()));
+    
cloneRegularOrMobRegion(MobUtils.getMobRegionInfo(tableDesc.getTableName()), 
clonedRegionPath,
+      region, regionManifests.get(region.getEncodedName()));
   }
 
   /**
-   * Clone region directory content from the snapshot info. Each region is 
encoded with the table
-   * name, so the cloned region will have a different region name. Instead of 
copying the hfiles a
-   * HFileLink is created.
+   * Clone region directory content from a snapshot manifest. This method is 
used for both regular
+   * regions and MOB regions. Instead of copying the hfiles a HFileLink is 
created.
    * @param regionDir {@link Path} cloned dir
    */
-  private void cloneRegion(final RegionInfo newRegionInfo, final Path 
regionDir,
+  private void cloneRegularOrMobRegion(final RegionInfo newRegionInfo, final 
Path regionDir,
     final RegionInfo snapshotRegionInfo, final SnapshotRegionManifest 
manifest) throws IOException {
     final String tableName = tableDesc.getTableName().getNameAsString();
     final String snapshotName = snapshotDesc.getName();
+    final boolean isMobRegion = MobUtils.isMobRegionInfo(newRegionInfo);
+    final Path parentDir =
+      isMobRegion ? MobUtils.getMobTableDir(rootDir, tableDesc.getTableName()) 
: tableDir;
     for (SnapshotRegionManifest.FamilyFiles familyFiles : 
manifest.getFamilyFilesList()) {
       Path familyDir = new Path(regionDir, 
familyFiles.getFamilyName().toStringUtf8());
       List<StoreFileInfo> clonedFiles = new ArrayList<>();
-      HRegionFileSystem regionFS = (fs.exists(regionDir))
-        ? HRegionFileSystem.openRegionFromFileSystem(conf, fs, tableDir, 
newRegionInfo, false)
-        : HRegionFileSystem.createRegionOnFileSystem(conf, fs, tableDir, 
newRegionInfo);
+      HRegionFileSystem regionFS = fs.exists(regionDir)
+        ? HRegionFileSystem.openRegionFromFileSystem(conf, fs, parentDir, 
newRegionInfo, false)
+        : HRegionFileSystem.createRegionOnFileSystem(conf, fs, parentDir, 
newRegionInfo);
 
       Configuration sftConf = StoreUtils.createStoreConfiguration(conf, 
tableDesc,
         tableDesc.getColumnFamily(familyFiles.getFamilyName().toByteArray()));
@@ -675,7 +677,7 @@ public class RestoreSnapshotHelper {
       for (SnapshotRegionManifest.StoreFile storeFile : 
familyFiles.getStoreFilesList()) {
         LOG.info("Adding HFileLink " + storeFile.getName() + " from cloned 
region " + "in snapshot "
           + snapshotName + " to table=" + tableName);
-        if (MobUtils.isMobRegionInfo(newRegionInfo)) {
+        if (isMobRegion) {
           String mobFileName =
             HFileLink.createHFileLinkName(snapshotRegionInfo, 
storeFile.getName());
           Path mobPath = new Path(familyDir, mobFileName);
@@ -704,8 +706,8 @@ public class RestoreSnapshotHelper {
    */
   private void cloneRegion(final HRegion region, final RegionInfo 
snapshotRegionInfo,
     final SnapshotRegionManifest manifest) throws IOException {
-    cloneRegion(region.getRegionInfo(), new Path(tableDir, 
region.getRegionInfo().getEncodedName()),
-      snapshotRegionInfo, manifest);
+    cloneRegularOrMobRegion(region.getRegionInfo(),
+      new Path(tableDir, region.getRegionInfo().getEncodedName()), 
snapshotRegionInfo, manifest);
   }
 
   /**
diff --git 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/snapshot/TestMobRestoreSnapshotHelper.java
 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/snapshot/TestMobRestoreSnapshotHelper.java
index 380044b733f..be26448bf9b 100644
--- 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/snapshot/TestMobRestoreSnapshotHelper.java
+++ 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/snapshot/TestMobRestoreSnapshotHelper.java
@@ -17,15 +17,24 @@
  */
 package org.apache.hadoop.hbase.snapshot;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 import java.io.IOException;
 import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hbase.HBaseTestingUtil;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.client.Table;
 import org.apache.hadoop.hbase.mob.MobConstants;
+import org.apache.hadoop.hbase.mob.MobUtils;
 import org.apache.hadoop.hbase.snapshot.MobSnapshotTestingUtils.SnapshotMock;
 import org.apache.hadoop.hbase.testclassification.MediumTests;
 import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.util.CommonFSUtils;
 import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -55,4 +64,47 @@ public class TestMobRestoreSnapshotHelper extends 
TestRestoreSnapshotHelper {
     TEST_UTIL.loadTable(table, column);
     TEST_UTIL.getAdmin().snapshot(snapshotName, tableName);
   }
+
+  @Test
+  public void testRestoreMobTableFromSnapshot() throws IOException {
+    TableName mobTableName = TableName.valueOf("testRestoreMobTable");
+    String snapshotName = "testRestoreMobTable_snapshot";
+    createTableAndSnapshot(mobTableName, snapshotName);
+    assertTrue(TEST_UTIL.getAdmin().tableExists(mobTableName));
+    
assertTrue(MobUtils.hasMobColumns(TEST_UTIL.getAdmin().getDescriptor(mobTableName)));
+    assertTrue(TEST_UTIL.getAdmin().listSnapshots().stream()
+      .anyMatch(snapshotDescription -> 
snapshotName.equals(snapshotDescription.getName())));
+
+    // Clone the snapshot to a new MOB table
+    TableName newMobTableName = TableName.valueOf("newTestRestoreMobTable");
+    TEST_UTIL.getAdmin().cloneSnapshot(snapshotName, newMobTableName);
+    assertTrue(TEST_UTIL.getAdmin().tableExists(newMobTableName));
+    
assertTrue(MobUtils.hasMobColumns(TEST_UTIL.getAdmin().getDescriptor(newMobTableName)));
+
+    Path hbaseRootDir = TEST_UTIL.getDefaultRootDirPath();
+    Path mobRegionPath = MobUtils.getMobTableDir(hbaseRootDir, 
newMobTableName);
+    assertTrue(fs.exists(mobRegionPath));
+    Path errorMobRegionPathInTableDir =
+      new Path(CommonFSUtils.getTableDir(hbaseRootDir, newMobTableName),
+        MobUtils.getMobRegionInfo(newMobTableName).getEncodedName());
+    assertFalse(fs.exists(errorMobRegionPathInTableDir));
+
+    try (Table originMobTable = 
TEST_UTIL.getConnection().getTable(mobTableName);
+      Table clonedMobTable = 
TEST_UTIL.getConnection().getTable(newMobTableName)) {
+      assertEquals(HBaseTestingUtil.countRows(originMobTable),
+        HBaseTestingUtil.countRows(clonedMobTable));
+    }
+
+    // Delete the original MOB table and restore it from the snapshot
+    TEST_UTIL.deleteTable(mobTableName);
+    assertFalse(TEST_UTIL.getAdmin().tableExists(mobTableName));
+    TEST_UTIL.getAdmin().cloneSnapshot(snapshotName, mobTableName);
+    assertTrue(TEST_UTIL.getAdmin().tableExists(mobTableName));
+    
assertTrue(MobUtils.hasMobColumns(TEST_UTIL.getAdmin().getDescriptor(mobTableName)));
+    mobRegionPath = MobUtils.getMobTableDir(hbaseRootDir, mobTableName);
+    assertTrue(fs.exists(mobRegionPath));
+    errorMobRegionPathInTableDir = new 
Path(CommonFSUtils.getTableDir(hbaseRootDir, mobTableName),
+      MobUtils.getMobRegionInfo(mobTableName).getEncodedName());
+    assertFalse(fs.exists(errorMobRegionPathInTableDir));
+  }
 }

Reply via email to