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 151319e165a2..0a57aeb4c02e 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 static List getSnapshotList(final Configuration conf 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 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 000000000000..10916d8dfb66 --- /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 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()); + } +}