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