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 cdec4dfba41 HBASE-30221 FNFE may occur when executing `hbase snapshot
info --list-snapshots` (#8340)
cdec4dfba41 is described below
commit cdec4dfba418db514b6c374c555418890a9cf728
Author: Peng Lu <[email protected]>
AuthorDate: Mon Jun 15 23:23:40 2026 +0800
HBASE-30221 FNFE may occur when executing `hbase snapshot info
--list-snapshots` (#8340)
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..3fb997907aa
--- /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.Assert.assertFalse;
+import static org.junit.Assert.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.HBaseTestingUtil;
+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 HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
+
+ 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());
+ }
+}