001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.regionserver;
019
020import static org.junit.jupiter.api.Assertions.assertThrows;
021
022import java.io.IOException;
023import java.util.ArrayList;
024import org.apache.hadoop.conf.Configuration;
025import org.apache.hadoop.fs.FileSystem;
026import org.apache.hadoop.fs.Path;
027import org.apache.hadoop.hbase.HBaseTestingUtil;
028import org.apache.hadoop.hbase.TableName;
029import org.apache.hadoop.hbase.client.SnapshotDescription;
030import org.apache.hadoop.hbase.client.SnapshotType;
031import org.apache.hadoop.hbase.client.Table;
032import org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher;
033import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
034import org.apache.hadoop.hbase.snapshot.SnapshotManifest;
035import org.apache.hadoop.hbase.testclassification.MediumTests;
036import org.apache.hadoop.hbase.testclassification.RegionServerTests;
037import org.apache.hadoop.hbase.util.Bytes;
038import org.apache.hadoop.hbase.util.CommonFSUtils;
039import org.apache.hadoop.hbase.util.RegionSplitter;
040import org.junit.jupiter.api.AfterEach;
041import org.junit.jupiter.api.BeforeEach;
042import org.junit.jupiter.api.Tag;
043import org.junit.jupiter.api.Test;
044import org.slf4j.Logger;
045import org.slf4j.LoggerFactory;
046
047import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
048import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos;
049
050@Tag(RegionServerTests.TAG)
051@Tag(MediumTests.TAG)
052public class TestRSSnapshotVerifier {
053
054  private static final Logger LOG = LoggerFactory.getLogger(TestRSSnapshotVerifier.class);
055  private HBaseTestingUtil TEST_UTIL;
056  private final TableName tableName = TableName.valueOf("TestRSSnapshotVerifier");
057  private final byte[] cf = Bytes.toBytes("cf");
058  private final SnapshotDescription snapshot =
059    new SnapshotDescription("test-snapshot", tableName, SnapshotType.FLUSH);
060  private SnapshotProtos.SnapshotDescription snapshotProto =
061    ProtobufUtil.createHBaseProtosSnapshotDesc(snapshot);
062
063  @BeforeEach
064  public void setup() throws Exception {
065    TEST_UTIL = new HBaseTestingUtil();
066    TEST_UTIL.startMiniCluster(3);
067    final byte[][] splitKeys = new RegionSplitter.HexStringSplit().split(10);
068    Table table = TEST_UTIL.createTable(tableName, cf, splitKeys);
069    TEST_UTIL.loadTable(table, cf, false);
070    TEST_UTIL.getAdmin().flush(tableName);
071
072    // prepare unverified snapshot
073    Configuration conf = TEST_UTIL.getConfiguration();
074    snapshotProto = SnapshotDescriptionUtils.validate(snapshotProto, conf);
075    Path rootDir = CommonFSUtils.getRootDir(conf);
076    Path workingDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(snapshotProto, rootDir, conf);
077    FileSystem workingDirFs = workingDir.getFileSystem(conf);
078    if (!workingDirFs.exists(workingDir)) {
079      workingDirFs.mkdirs(workingDir);
080    }
081    ForeignExceptionDispatcher monitor = new ForeignExceptionDispatcher(snapshot.getName());
082    SnapshotManifest manifest =
083      SnapshotManifest.create(conf, workingDirFs, workingDir, snapshotProto, monitor);
084    manifest.addTableDescriptor(
085      TEST_UTIL.getHBaseCluster().getMaster().getTableDescriptors().get(tableName));
086    SnapshotDescriptionUtils.writeSnapshotInfo(snapshotProto, workingDir, workingDirFs);
087    TEST_UTIL.getHBaseCluster().getRegions(tableName).forEach(r -> {
088      try {
089        r.addRegionToSnapshot(snapshotProto, monitor);
090      } catch (IOException e) {
091        LOG.warn("Failed snapshot region {}", r.getRegionInfo());
092      }
093    });
094    manifest.consolidate();
095  }
096
097  @Test
098  public void testVerifyStoreFile() throws Exception {
099    RSSnapshotVerifier verifier =
100      TEST_UTIL.getHBaseCluster().getRegionServer(0).getRsSnapshotVerifier();
101    HRegion region = TEST_UTIL.getHBaseCluster().getRegions(tableName).stream()
102      .filter(r -> !r.getStore(cf).getStorefiles().isEmpty()).findFirst().get();
103    Path filePath = new ArrayList<>(region.getStore(cf).getStorefiles()).get(0).getPath();
104    TEST_UTIL.getDFSCluster().getFileSystem().delete(filePath, true);
105    LOG.info("delete store file {}", filePath);
106    assertThrows(org.apache.hadoop.hbase.snapshot.CorruptedSnapshotException.class,
107      () -> verifier.verifyRegion(snapshotProto, region.getRegionInfo()));
108  }
109
110  @AfterEach
111  public void teardown() throws Exception {
112    TEST_UTIL.shutdownMiniCluster();
113  }
114}