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.assignment;
019
020import static org.junit.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertNotNull;
022
023import java.io.IOException;
024import java.util.Set;
025import org.apache.hadoop.hbase.HBaseTestingUtil;
026import org.apache.hadoop.hbase.ServerName;
027import org.apache.hadoop.hbase.TableName;
028import org.apache.hadoop.hbase.Waiter;
029import org.apache.hadoop.hbase.Waiter.ExplainingPredicate;
030import org.apache.hadoop.hbase.client.Put;
031import org.apache.hadoop.hbase.client.RegionInfo;
032import org.apache.hadoop.hbase.client.Table;
033import org.apache.hadoop.hbase.master.HMaster;
034import org.apache.hadoop.hbase.master.RegionState.State;
035import org.apache.hadoop.hbase.master.procedure.ProcedureSyncWait;
036import org.apache.hadoop.hbase.util.Bytes;
037import org.apache.hadoop.hbase.util.Threads;
038import org.apache.yetus.audience.InterfaceAudience;
039import org.apache.yetus.audience.InterfaceStability;
040import org.slf4j.Logger;
041import org.slf4j.LoggerFactory;
042
043@InterfaceAudience.Private
044@InterfaceStability.Evolving
045public final class AssignmentTestingUtil {
046  private static final Logger LOG = LoggerFactory.getLogger(AssignmentTestingUtil.class);
047
048  private AssignmentTestingUtil() {
049  }
050
051  public static void waitForRegionToBeInTransition(final HBaseTestingUtil util,
052    final RegionInfo hri) {
053    while (!isRegionInTransition(hri, getMaster(util).getAssignmentManager())) {
054      Threads.sleep(10);
055    }
056  }
057
058  public static boolean isRegionInTransition(RegionInfo hri, AssignmentManager am) {
059    return am.getRegionsInTransition().stream()
060      .anyMatch(rsn -> rsn.getRegionInfo().getEncodedName().equals(hri.getEncodedName()));
061  }
062
063  public static void waitForRsToBeDead(final HBaseTestingUtil util, final ServerName serverName)
064    throws Exception {
065    util.waitFor(60000, new ExplainingPredicate<Exception>() {
066      @Override
067      public boolean evaluate() {
068        return getMaster(util).getServerManager().isServerDead(serverName);
069      }
070
071      @Override
072      public String explainFailure() {
073        return "Server " + serverName + " is not dead";
074      }
075    });
076  }
077
078  public static void stopRs(final HBaseTestingUtil util, final ServerName serverName)
079    throws Exception {
080    LOG.info("STOP REGION SERVER " + serverName);
081    util.getMiniHBaseCluster().stopRegionServer(serverName);
082    waitForRsToBeDead(util, serverName);
083  }
084
085  public static void killRs(final HBaseTestingUtil util, final ServerName serverName)
086    throws Exception {
087    LOG.info("KILL REGION SERVER " + serverName);
088    util.getMiniHBaseCluster().killRegionServer(serverName);
089    waitForRsToBeDead(util, serverName);
090  }
091
092  public static void crashRs(final HBaseTestingUtil util, final ServerName serverName,
093    final boolean kill) throws Exception {
094    if (kill) {
095      killRs(util, serverName);
096    } else {
097      stopRs(util, serverName);
098    }
099  }
100
101  public static ServerName crashRsWithRegion(final HBaseTestingUtil util, final RegionInfo hri,
102    final boolean kill) throws Exception {
103    ServerName serverName = getServerHoldingRegion(util, hri);
104    crashRs(util, serverName, kill);
105    return serverName;
106  }
107
108  public static ServerName getServerHoldingRegion(final HBaseTestingUtil util, final RegionInfo hri)
109    throws Exception {
110    ServerName serverName =
111      util.getMiniHBaseCluster().getServerHoldingRegion(hri.getTable(), hri.getRegionName());
112    ServerName amServerName =
113      getMaster(util).getAssignmentManager().getRegionStates().getRegionServerOfRegion(hri);
114
115    // Make sure AM and MiniCluster agrees on the Server holding the region
116    // and that the server is online.
117    assertEquals(amServerName, serverName);
118    assertEquals(true, getMaster(util).getServerManager().isServerOnline(serverName));
119    return serverName;
120  }
121
122  public static boolean isServerHoldingMeta(final HBaseTestingUtil util,
123    final ServerName serverName) throws Exception {
124    for (RegionInfo hri : getMetaRegions(util)) {
125      if (serverName.equals(getServerHoldingRegion(util, hri))) {
126        return true;
127      }
128    }
129    return false;
130  }
131
132  public static Set<RegionInfo> getMetaRegions(final HBaseTestingUtil util) {
133    return getMaster(util).getAssignmentManager().getMetaRegionSet();
134  }
135
136  private static HMaster getMaster(final HBaseTestingUtil util) {
137    return util.getMiniHBaseCluster().getMaster();
138  }
139
140  public static boolean waitForAssignment(AssignmentManager am, RegionInfo regionInfo)
141    throws IOException {
142    // This method can be called before the regionInfo has made it into the regionStateMap
143    // so wait around here a while.
144    Waiter.waitFor(am.getConfiguration(), 10000,
145      () -> am.getRegionStates().getRegionStateNode(regionInfo) != null);
146    RegionStateNode regionNode = am.getRegionStates().getRegionStateNode(regionInfo);
147    // Wait until the region has already been open, or we have a TRSP along with it.
148    Waiter.waitFor(am.getConfiguration(), 30000,
149      () -> regionNode.isInState(State.OPEN) || regionNode.isTransitionScheduled());
150    TransitRegionStateProcedure proc = regionNode.getProcedure();
151    regionNode.lock();
152    try {
153      if (regionNode.isInState(State.OPEN)) {
154        return true;
155      }
156      proc = regionNode.getProcedure();
157    } finally {
158      regionNode.unlock();
159    }
160    assertNotNull(proc);
161    ProcedureSyncWait.waitForProcedureToCompleteIOE(am.getMaster().getMasterProcedureExecutor(),
162      proc, 5L * 60 * 1000);
163    return true;
164  }
165
166  public static void insertData(final HBaseTestingUtil UTIL, final TableName tableName,
167    int rowCount, int startRowNum, String... cfs) throws IOException {
168    insertData(UTIL, tableName, rowCount, startRowNum, false, cfs);
169  }
170
171  public static void insertData(final HBaseTestingUtil UTIL, final TableName tableName,
172    int rowCount, int startRowNum, boolean flushOnce, String... cfs) throws IOException {
173    Table t = UTIL.getConnection().getTable(tableName);
174    Put p;
175    for (int i = 0; i < rowCount / 2; i++) {
176      p = new Put(Bytes.toBytes("" + (startRowNum + i)));
177      for (String cf : cfs) {
178        p.addColumn(Bytes.toBytes(cf), Bytes.toBytes("q"), Bytes.toBytes(i));
179      }
180      t.put(p);
181      p = new Put(Bytes.toBytes("" + (startRowNum + rowCount - i - 1)));
182      for (String cf : cfs) {
183        p.addColumn(Bytes.toBytes(cf), Bytes.toBytes("q"), Bytes.toBytes(i));
184      }
185      t.put(p);
186      if (i % 5 == 0 && !flushOnce) {
187        UTIL.getAdmin().flush(tableName);
188      }
189    }
190    if (flushOnce) {
191      UTIL.getAdmin().flush(tableName);
192    }
193  }
194}