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.master.procedure;
019
020import static org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility.assertProcNotFailed;
021import static org.junit.jupiter.api.Assertions.assertFalse;
022import static org.junit.jupiter.api.Assertions.assertTrue;
023
024import java.util.List;
025import org.apache.hadoop.hbase.HBaseTestingUtil;
026import org.apache.hadoop.hbase.TableName;
027import org.apache.hadoop.hbase.client.RegionInfo;
028import org.apache.hadoop.hbase.client.RegionInfoBuilder;
029import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
030import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility;
031import org.apache.hadoop.hbase.testclassification.MasterTests;
032import org.apache.hadoop.hbase.testclassification.MediumTests;
033import org.apache.hadoop.hbase.util.Bytes;
034import org.junit.jupiter.api.AfterEach;
035import org.junit.jupiter.api.BeforeEach;
036import org.junit.jupiter.api.Tag;
037import org.junit.jupiter.api.Test;
038
039@Tag(MasterTests.TAG)
040@Tag(MediumTests.TAG)
041public class TestRefreshMetaProcedure {
042
043  private static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
044  private ProcedureExecutor<MasterProcedureEnv> procExecutor;
045  List<RegionInfo> activeRegions;
046  TableName tableName = TableName.valueOf("testRefreshMeta");
047
048  @BeforeEach
049  public void setup() throws Exception {
050    TEST_UTIL.getConfiguration().set("USE_META_REPLICAS", "false");
051    TEST_UTIL.startMiniCluster();
052    procExecutor = TEST_UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor();
053    byte[][] splitKeys =
054      new byte[][] { Bytes.toBytes("split1"), Bytes.toBytes("split2"), Bytes.toBytes("split3") };
055    TEST_UTIL.createTable(tableName, Bytes.toBytes("cf"), splitKeys);
056    TEST_UTIL.waitTableAvailable(tableName);
057    TEST_UTIL.getAdmin().flush(tableName);
058    activeRegions = TEST_UTIL.getAdmin().getRegions(tableName);
059    assertFalse(activeRegions.isEmpty());
060  }
061
062  @AfterEach
063  public void tearDown() throws Exception {
064    TEST_UTIL.shutdownMiniCluster();
065  }
066
067  @Test
068  public void testRefreshMetaProcedureExecutesSuccessfully() {
069    RefreshMetaProcedure procedure = new RefreshMetaProcedure(procExecutor.getEnvironment());
070    long procId = procExecutor.submitProcedure(procedure);
071    ProcedureTestingUtility.waitProcedure(procExecutor, procId);
072    assertProcNotFailed(procExecutor.getResult(procId));
073  }
074
075  @Test
076  public void testGetCurrentRegions() throws Exception {
077    RefreshMetaProcedure procedure = new RefreshMetaProcedure(procExecutor.getEnvironment());
078    List<RegionInfo> regions = procedure.getCurrentRegions(TEST_UTIL.getConnection());
079    assertFalse(regions.isEmpty(), "Should have found regions in meta");
080    assertTrue(
081      regions.stream().anyMatch(r -> r.getTable().getNameAsString().equals("testRefreshMeta")),
082      "Should include test table region");
083  }
084
085  @Test
086  public void testScanBackingStorage() throws Exception {
087    RefreshMetaProcedure procedure = new RefreshMetaProcedure(procExecutor.getEnvironment());
088
089    List<RegionInfo> fsRegions = procedure.scanBackingStorage(TEST_UTIL.getConnection());
090
091    assertTrue(
092      activeRegions.stream()
093        .allMatch(reg -> fsRegions.stream()
094          .anyMatch(r -> r.getRegionNameAsString().equals(reg.getRegionNameAsString()))),
095      "All regions from meta should be found in the storage");
096  }
097
098  @Test
099  public void testHasBoundaryChanged() {
100    RefreshMetaProcedure procedure = new RefreshMetaProcedure(procExecutor.getEnvironment());
101    RegionInfo region1 = RegionInfoBuilder.newBuilder(tableName)
102      .setStartKey(Bytes.toBytes("start1")).setEndKey(Bytes.toBytes("end1")).build();
103
104    RegionInfo region2 = RegionInfoBuilder.newBuilder(tableName)
105      .setStartKey(Bytes.toBytes("start2")).setEndKey(Bytes.toBytes("end1")).build();
106
107    RegionInfo region3 = RegionInfoBuilder.newBuilder(tableName)
108      .setStartKey(Bytes.toBytes("start1")).setEndKey(Bytes.toBytes("end2")).build();
109
110    assertTrue(procedure.hasBoundaryChanged(region1, region2),
111      "Different start keys should have been detected");
112
113    assertTrue(procedure.hasBoundaryChanged(region1, region3),
114      "Different end keys should have been detected");
115
116    assertFalse(procedure.hasBoundaryChanged(region1, region1),
117      "Identical boundaries should not have been identified");
118  }
119}