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.Assert.assertTrue;
021
022import java.io.IOException;
023import java.util.ArrayList;
024import java.util.Collection;
025import java.util.HashMap;
026import java.util.Map;
027import org.apache.hadoop.conf.Configuration;
028import org.apache.hadoop.hbase.HBaseClassTestRule;
029import org.apache.hadoop.hbase.HBaseTestingUtility;
030import org.apache.hadoop.hbase.HConstants;
031import org.apache.hadoop.hbase.HTableDescriptor;
032import org.apache.hadoop.hbase.ServerName;
033import org.apache.hadoop.hbase.TableName;
034import org.apache.hadoop.hbase.client.RegionInfo;
035import org.apache.hadoop.hbase.client.Table;
036import org.apache.hadoop.hbase.testclassification.MediumTests;
037import org.apache.hadoop.hbase.testclassification.RegionServerTests;
038import org.apache.hadoop.hbase.util.Bytes;
039import org.apache.hadoop.hbase.util.RegionSplitter;
040import org.junit.AfterClass;
041import org.junit.BeforeClass;
042import org.junit.ClassRule;
043import org.junit.Test;
044import org.junit.experimental.categories.Category;
045import org.slf4j.Logger;
046import org.slf4j.LoggerFactory;
047
048@Category({ RegionServerTests.class, MediumTests.class })
049public class TestRegionReplicasAreDistributed {
050
051  @ClassRule
052  public static final HBaseClassTestRule CLASS_RULE =
053    HBaseClassTestRule.forClass(TestRegionReplicasAreDistributed.class);
054
055  private static final Logger LOG = LoggerFactory.getLogger(TestRegionReplicasAreDistributed.class);
056
057  private static final int NB_SERVERS = 3;
058  private static Table table;
059
060  private static final HBaseTestingUtility HTU = new HBaseTestingUtility();
061  private static final byte[] f = HConstants.CATALOG_FAMILY;
062  Map<ServerName, Collection<RegionInfo>> serverVsOnlineRegions;
063  Map<ServerName, Collection<RegionInfo>> serverVsOnlineRegions2;
064  Map<ServerName, Collection<RegionInfo>> serverVsOnlineRegions3;
065  Map<ServerName, Collection<RegionInfo>> serverVsOnlineRegions4;
066
067  @BeforeClass
068  public static void before() throws Exception {
069    HTU.getConfiguration().setInt("hbase.master.wait.on.regionservers.mintostart", 3);
070
071    HTU.startMiniCluster(NB_SERVERS);
072    Thread.sleep(3000);
073    final TableName tableName =
074      TableName.valueOf(TestRegionReplicasAreDistributed.class.getSimpleName());
075
076    // Create table then get the single region for our new table.
077    createTableDirectlyFromHTD(tableName);
078  }
079
080  private static void createTableDirectlyFromHTD(final TableName tableName) throws IOException {
081    HTableDescriptor htd = new HTableDescriptor(tableName);
082    htd.setRegionReplication(3);
083    // create a table with 3 replication
084
085    table = HTU.createTable(htd, new byte[][] { f }, getSplits(20),
086      new Configuration(HTU.getConfiguration()));
087  }
088
089  private static byte[][] getSplits(int numRegions) {
090    RegionSplitter.UniformSplit split = new RegionSplitter.UniformSplit();
091    split.setFirstRow(Bytes.toBytes(0L));
092    split.setLastRow(Bytes.toBytes(Long.MAX_VALUE));
093    return split.split(numRegions);
094  }
095
096  @AfterClass
097  public static void afterClass() throws Exception {
098    HRegionServer.TEST_SKIP_REPORTING_TRANSITION = false;
099    table.close();
100    HTU.shutdownMiniCluster();
101  }
102
103  private HRegionServer getRS() {
104    return HTU.getMiniHBaseCluster().getRegionServer(0);
105  }
106
107  private HRegionServer getSecondaryRS() {
108    return HTU.getMiniHBaseCluster().getRegionServer(1);
109  }
110
111  private HRegionServer getTertiaryRS() {
112    return HTU.getMiniHBaseCluster().getRegionServer(2);
113  }
114
115  @Test
116  public void testRegionReplicasCreatedAreDistributed() throws Exception {
117    try {
118      checkAndAssertRegionDistribution(false);
119      // now diesbale and enable the table again. It should be truly distributed
120      HTU.getAdmin().disableTable(table.getName());
121      LOG.info("Disabled the table " + table.getName());
122      LOG.info("enabling the table " + table.getName());
123      HTU.getAdmin().enableTable(table.getName());
124      LOG.info("Enabled the table " + table.getName());
125      boolean res = checkAndAssertRegionDistribution(true);
126      assertTrue("Region retainment not done ", res);
127    } finally {
128      HTU.getAdmin().disableTable(table.getName());
129      HTU.getAdmin().deleteTable(table.getName());
130    }
131  }
132
133  private boolean checkAndAssertRegionDistribution(boolean checkfourth) throws Exception {
134    Collection<RegionInfo> onlineRegions =
135      new ArrayList<RegionInfo>(getRS().getOnlineRegionsLocalContext().size());
136    for (HRegion region : getRS().getOnlineRegionsLocalContext()) {
137      onlineRegions.add(region.getRegionInfo());
138    }
139    if (this.serverVsOnlineRegions == null) {
140      this.serverVsOnlineRegions = new HashMap<ServerName, Collection<RegionInfo>>();
141      this.serverVsOnlineRegions.put(getRS().getServerName(), onlineRegions);
142    } else {
143      Collection<RegionInfo> existingRegions =
144        new ArrayList<RegionInfo>(this.serverVsOnlineRegions.get(getRS().getServerName()));
145      LOG.info("Count is " + existingRegions.size() + " " + onlineRegions.size());
146      for (RegionInfo existingRegion : existingRegions) {
147        if (!onlineRegions.contains(existingRegion)) {
148          return false;
149        }
150      }
151    }
152    Collection<RegionInfo> onlineRegions2 =
153      new ArrayList<RegionInfo>(getSecondaryRS().getOnlineRegionsLocalContext().size());
154    for (HRegion region : getSecondaryRS().getOnlineRegionsLocalContext()) {
155      onlineRegions2.add(region.getRegionInfo());
156    }
157    if (this.serverVsOnlineRegions2 == null) {
158      this.serverVsOnlineRegions2 = new HashMap<ServerName, Collection<RegionInfo>>();
159      this.serverVsOnlineRegions2.put(getSecondaryRS().getServerName(), onlineRegions2);
160    } else {
161      Collection<RegionInfo> existingRegions = new ArrayList<RegionInfo>(
162        this.serverVsOnlineRegions2.get(getSecondaryRS().getServerName()));
163      LOG.info("Count is " + existingRegions.size() + " " + onlineRegions2.size());
164      for (RegionInfo existingRegion : existingRegions) {
165        if (!onlineRegions2.contains(existingRegion)) {
166          return false;
167        }
168      }
169    }
170    Collection<RegionInfo> onlineRegions3 =
171      new ArrayList<RegionInfo>(getTertiaryRS().getOnlineRegionsLocalContext().size());
172    for (HRegion region : getTertiaryRS().getOnlineRegionsLocalContext()) {
173      onlineRegions3.add(region.getRegionInfo());
174    }
175    if (this.serverVsOnlineRegions3 == null) {
176      this.serverVsOnlineRegions3 = new HashMap<ServerName, Collection<RegionInfo>>();
177      this.serverVsOnlineRegions3.put(getTertiaryRS().getServerName(), onlineRegions3);
178    } else {
179      Collection<RegionInfo> existingRegions =
180        new ArrayList<RegionInfo>(this.serverVsOnlineRegions3.get(getTertiaryRS().getServerName()));
181      LOG.info("Count is " + existingRegions.size() + " " + onlineRegions3.size());
182      for (RegionInfo existingRegion : existingRegions) {
183        if (!onlineRegions3.contains(existingRegion)) {
184          return false;
185        }
186      }
187    }
188    // META and namespace to be added
189    return true;
190  }
191}