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

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


The following commit(s) were added to refs/heads/branch-2 by this push:
     new e36cf744095 HBASE-30221 FNFE may occur when executing `hbase snapshot 
info --list-snapshots` (branch-2) (#8355)
e36cf744095 is described below

commit e36cf744095081198836a8a29d6153f25ba75500
Author: Peng Lu <[email protected]>
AuthorDate: Wed Jun 17 20:18:14 2026 +0800

    HBASE-30221 FNFE may occur when executing `hbase snapshot info 
--list-snapshots` (branch-2) (#8355)
    
    Signed-off-by: Duo Zhang <[email protected]>
---
 .../apache/hadoop/hbase/snapshot/SnapshotInfo.java |   5 +-
 .../hbase/master/snapshot/TestSnapshotInfo.java    | 105 +++++++++++++++++++++
 2 files changed, 109 insertions(+), 1 deletion(-)

diff --git 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotInfo.java 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotInfo.java
index 151319e165a..0a57aeb4c02 100644
--- 
a/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotInfo.java
+++ 
b/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotInfo.java
@@ -628,8 +628,11 @@ public final class SnapshotInfo extends AbstractHBaseTool {
     Path rootDir = CommonFSUtils.getRootDir(conf);
     FileSystem fs = FileSystem.get(rootDir.toUri(), conf);
     Path snapshotDir = SnapshotDescriptionUtils.getSnapshotsDir(rootDir);
-    FileStatus[] snapshots = fs.listStatus(snapshotDir,
+    FileStatus[] snapshots = CommonFSUtils.listStatus(fs, snapshotDir,
       new SnapshotDescriptionUtils.CompletedSnaphotDirectoriesFilter(fs));
+    if (snapshots == null) {
+      return Collections.emptyList();
+    }
     List<SnapshotDescription> snapshotLists = new 
ArrayList<>(snapshots.length);
     for (FileStatus snapshotDirStat : snapshots) {
       SnapshotProtos.SnapshotDescription snapshotDesc =
diff --git 
a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/snapshot/TestSnapshotInfo.java
 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/snapshot/TestSnapshotInfo.java
new file mode 100644
index 00000000000..10916d8dfb6
--- /dev/null
+++ 
b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/snapshot/TestSnapshotInfo.java
@@ -0,0 +1,105 @@
+/*
+ * 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.master.snapshot;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.util.List;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hbase.HBaseTestingUtility;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
+import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
+import org.apache.hadoop.hbase.client.SnapshotDescription;
+import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
+import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
+import org.apache.hadoop.hbase.snapshot.SnapshotInfo;
+import org.apache.hadoop.hbase.testclassification.MasterTests;
+import org.apache.hadoop.hbase.testclassification.MediumTests;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+
+@Tag(MasterTests.TAG)
+@Tag(MediumTests.TAG)
+public class TestSnapshotInfo {
+  private final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
+
+  private Path rootDir;
+  private FileSystem fs;
+  private Configuration conf;
+  private Admin admin;
+  private String currentTestName;
+
+  @BeforeEach
+  public void setup(TestInfo testInfo) throws Exception {
+    TEST_UTIL.startMiniCluster(1);
+    rootDir = TEST_UTIL.getDefaultRootDirPath();
+    fs = TEST_UTIL.getTestFileSystem();
+    conf = TEST_UTIL.getConfiguration();
+    admin = TEST_UTIL.getAdmin();
+    currentTestName = testInfo.getTestMethod().get().getName();
+  }
+
+  @AfterEach
+  public void tearDown() throws IOException {
+    admin.close();
+    TEST_UTIL.shutdownMiniCluster();
+    TEST_UTIL.getTestFileSystem().delete(TEST_UTIL.getDataTestDir(), true);
+  }
+
+  @Test
+  public void testGetSnapshotList() throws IOException {
+    Path snapshotDir = SnapshotDescriptionUtils.getSnapshotsDir(rootDir);
+
+    // HBase cluster has just started, .hbase-snapshot directory doesn't exist
+    assertFalse(fs.exists(snapshotDir));
+    List<SnapshotDescription> snapshotDescList = 
SnapshotInfo.getSnapshotList(conf);
+    assertTrue(snapshotDescList.isEmpty());
+
+    TableName tableName = TableName.valueOf(currentTestName);
+    TableDescriptorBuilder tableDescriptorBuilder = 
TableDescriptorBuilder.newBuilder(tableName);
+    ColumnFamilyDescriptor columnFamilyDescriptor =
+      ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("info")).build();
+    tableDescriptorBuilder.setColumnFamily(columnFamilyDescriptor);
+    admin.createTable(tableDescriptorBuilder.build());
+    assertTrue(admin.tableExists(tableName));
+    String snapshotName = "snapshot_" + currentTestName;
+    admin.snapshot(snapshotName, tableName);
+
+    // .hbase-snapshot directory exists after snapshotting a table
+    assertTrue(fs.exists(snapshotDir));
+    snapshotDescList = SnapshotInfo.getSnapshotList(conf);
+    assertFalse(snapshotDescList.isEmpty());
+
+    // Deleting snapshot and cluster has no snapshots, .hbase-snapshot 
directory would still exist
+    admin.deleteSnapshot(snapshotName);
+    assertTrue(fs.exists(snapshotDir));
+    assertTrue(fs.exists(new Path(snapshotDir, 
SnapshotDescriptionUtils.SNAPSHOT_TMP_DIR_NAME)));
+    snapshotDescList = SnapshotInfo.getSnapshotList(conf);
+    assertTrue(snapshotDescList.isEmpty());
+  }
+}

Reply via email to