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.util;
019
020import static org.junit.Assert.assertEquals;
021
022import java.io.File;
023import java.io.FileWriter;
024import org.apache.hadoop.conf.Configuration;
025import org.apache.hadoop.hbase.HBaseClassTestRule;
026import org.apache.hadoop.hbase.HBaseTestingUtility;
027import org.apache.hadoop.hbase.HColumnDescriptor;
028import org.apache.hadoop.hbase.HConstants;
029import org.apache.hadoop.hbase.HTableDescriptor;
030import org.apache.hadoop.hbase.MiniHBaseCluster;
031import org.apache.hadoop.hbase.TableName;
032import org.apache.hadoop.hbase.Waiter.Predicate;
033import org.apache.hadoop.hbase.client.Admin;
034import org.apache.hadoop.hbase.regionserver.HRegionServer;
035import org.apache.hadoop.hbase.testclassification.MediumTests;
036import org.apache.hadoop.hbase.util.RegionMover.RegionMoverBuilder;
037import org.junit.AfterClass;
038import org.junit.Before;
039import org.junit.BeforeClass;
040import org.junit.ClassRule;
041import org.junit.Test;
042import org.junit.experimental.categories.Category;
043import org.slf4j.Logger;
044import org.slf4j.LoggerFactory;
045
046
047/**
048 * Tests for Region Mover Load/Unload functionality with and without ack mode and also to test
049 * exclude functionality useful for rack decommissioning
050 */
051@Category(MediumTests.class)
052public class TestRegionMover {
053
054  @ClassRule
055  public static final HBaseClassTestRule CLASS_RULE =
056      HBaseClassTestRule.forClass(TestRegionMover.class);
057
058  final Logger LOG = LoggerFactory.getLogger(getClass());
059  protected final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
060
061  @BeforeClass
062  public static void setUpBeforeClass() throws Exception {
063    TEST_UTIL.startMiniCluster(3);
064  }
065
066  @AfterClass
067  public static void tearDownAfterClass() throws Exception {
068    TEST_UTIL.shutdownMiniCluster();
069  }
070
071  @Before
072  public void setUp() throws Exception {
073    // Create a pre-split table just to populate some regions
074    TableName tableName = TableName.valueOf("testRegionMover");
075    Admin admin = TEST_UTIL.getAdmin();
076    if (admin.tableExists(tableName)) {
077      TEST_UTIL.deleteTable(tableName);
078    }
079    HTableDescriptor tableDesc = new HTableDescriptor(tableName);
080    HColumnDescriptor fam1 = new HColumnDescriptor("fam1");
081    tableDesc.addFamily(fam1);
082
083    try {
084      admin.setBalancerRunning(false, true);
085      String startKey = "a";
086      String endKey = "z";
087      admin.createTable(tableDesc, startKey.getBytes(), endKey.getBytes(), 9);
088    } finally {
089      if (admin != null) {
090        admin.close();
091      }
092    }
093  }
094
095  @Test
096  public void testLoadWithAck() throws Exception {
097    MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
098    HRegionServer regionServer = cluster.getRegionServer(0);
099    String rsName = regionServer.getServerName().getHostname();
100    int port = regionServer.getServerName().getPort();
101    int noRegions = regionServer.getNumberOfOnlineRegions();
102    String rs = rsName + ":" + Integer.toString(port);
103    RegionMoverBuilder rmBuilder = new RegionMoverBuilder(rs, TEST_UTIL.getConfiguration())
104      .ack(true).maxthreads(8);
105    RegionMover rm = rmBuilder.build();
106    LOG.info("Unloading " + rs);
107    rm.unload();
108    assertEquals(0, regionServer.getNumberOfOnlineRegions());
109    LOG.info("Successfully Unloaded\nNow Loading");
110    rm.load();
111    assertEquals(noRegions, regionServer.getNumberOfOnlineRegions());
112  }
113
114  /** Test to unload a regionserver first and then load it using no Ack mode
115   * we check if some regions are loaded on the region server(since no ack is best effort)
116   */
117  @Test
118  public void testLoadWithoutAck() throws Exception {
119    MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
120    final HRegionServer regionServer = cluster.getRegionServer(0);
121    String rsName = regionServer.getServerName().getHostname();
122    int port = regionServer.getServerName().getPort();
123    int noRegions = regionServer.getNumberOfOnlineRegions();
124    String rs = rsName + ":" + Integer.toString(port);
125    RegionMoverBuilder rmBuilder = new RegionMoverBuilder(rs, TEST_UTIL.getConfiguration())
126      .ack(true);
127    RegionMover rm = rmBuilder.build();
128    LOG.info("Unloading " + rs);
129    rm.unload();
130    assertEquals(0, regionServer.getNumberOfOnlineRegions());
131    LOG.info("Successfully Unloaded\nNow Loading");
132    rm = rmBuilder.ack(false).build();
133    rm.load();
134    TEST_UTIL.waitFor(5000, 500, new Predicate<Exception>() {
135      @Override
136      public boolean evaluate() throws Exception {
137        return regionServer.getNumberOfOnlineRegions() > 0;
138      }
139    });
140  }
141
142  @Test
143  public void testUnloadWithoutAck() throws Exception {
144    MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
145    final HRegionServer regionServer = cluster.getRegionServer(0);
146    final int noRegions = regionServer.getNumberOfOnlineRegions();
147    String rsName = regionServer.getServerName().getHostname();
148    int port = regionServer.getServerName().getPort();
149    String rs = rsName + ":" + Integer.toString(port);
150    RegionMoverBuilder rmBuilder = new RegionMoverBuilder(rs, TEST_UTIL.getConfiguration())
151      .ack(false);
152    RegionMover rm = rmBuilder.build();
153    LOG.info("Unloading " + rs);
154    rm.unload();
155    TEST_UTIL.waitFor(5000, 500, new Predicate<Exception>() {
156      @Override
157      public boolean evaluate() throws Exception {
158        return regionServer.getNumberOfOnlineRegions() < noRegions;
159      }
160    });
161  }
162
163  @Test
164  public void testUnloadWithAck() throws Exception {
165    MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
166    HRegionServer regionServer = cluster.getRegionServer(0);
167    String rsName = regionServer.getServerName().getHostname();
168    int port = regionServer.getServerName().getPort();
169    String rs = rsName + ":" + Integer.toString(port);
170    RegionMoverBuilder rmBuilder = new RegionMoverBuilder(rs, TEST_UTIL.getConfiguration())
171      .ack(true);
172    RegionMover rm = rmBuilder.build();
173    rm.unload();
174    LOG.info("Unloading " + rs);
175    assertEquals(0, regionServer.getNumberOfOnlineRegions());
176  }
177
178  /**
179   * Test that loading the same region set doesn't cause timeout loop during meta load.
180   */
181  @Test
182  public void testRepeatedLoad() throws Exception {
183    MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
184    HRegionServer regionServer = cluster.getRegionServer(0);
185    String rsName = regionServer.getServerName().getHostname();
186    int port = regionServer.getServerName().getPort();
187    String rs = rsName + ":" + Integer.toString(port);
188    RegionMoverBuilder rmBuilder = new RegionMoverBuilder(rs, TEST_UTIL.getConfiguration())
189      .ack(true);
190    RegionMover rm = rmBuilder.build();
191    rm.unload();
192    assertEquals(0, regionServer.getNumberOfOnlineRegions());
193    rmBuilder = new RegionMoverBuilder(rs, TEST_UTIL.getConfiguration()).ack(true);
194    rm = rmBuilder.build();
195    rm.load();
196    rm.load(); //Repeat the same load. It should be very fast because all regions are already moved.
197  }
198
199  /**
200   * To test that we successfully exclude a server from the unloading process We test for the number
201   * of regions on Excluded server and also test that regions are unloaded successfully
202   */
203  @Test
204  public void testExclude() throws Exception {
205    MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
206    File excludeFile = new File(TEST_UTIL.getDataTestDir().toUri().getPath(), "exclude_file");
207    FileWriter fos = new FileWriter(excludeFile);
208    HRegionServer excludeServer = cluster.getRegionServer(1);
209    String excludeHostname = excludeServer.getServerName().getHostname();
210    int excludeServerPort = excludeServer.getServerName().getPort();
211    int regionsExcludeServer = excludeServer.getNumberOfOnlineRegions();
212    String excludeServerName = excludeHostname + ":" + Integer.toString(excludeServerPort);
213    fos.write(excludeServerName);
214    fos.close();
215    HRegionServer regionServer = cluster.getRegionServer(0);
216    String rsName = regionServer.getServerName().getHostname();
217    int port = regionServer.getServerName().getPort();
218    String rs = rsName + ":" + Integer.toString(port);
219    RegionMoverBuilder rmBuilder = new RegionMoverBuilder(rs, TEST_UTIL.getConfiguration())
220      .ack(true).excludeFile(excludeFile.getCanonicalPath());
221    RegionMover rm = rmBuilder.build();
222    rm.unload();
223    LOG.info("Unloading " + rs);
224    assertEquals(0, regionServer.getNumberOfOnlineRegions());
225    assertEquals(regionsExcludeServer, cluster.getRegionServer(1).getNumberOfOnlineRegions());
226    LOG.info("Before:" + regionsExcludeServer + " After:"
227        + cluster.getRegionServer(1).getNumberOfOnlineRegions());
228  }
229
230  @Test
231  public void testRegionServerPort() {
232    MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
233    HRegionServer regionServer = cluster.getRegionServer(0);
234    String rsName = regionServer.getServerName().getHostname();
235
236    final int PORT = 16021;
237    Configuration conf = TEST_UTIL.getConfiguration();
238    String originalPort = conf.get(HConstants.REGIONSERVER_PORT);
239    conf.set(HConstants.REGIONSERVER_PORT, Integer.toString(PORT));
240    RegionMoverBuilder rmBuilder = new RegionMoverBuilder(rsName, conf);
241    assertEquals(PORT, rmBuilder.port);
242    if (originalPort != null) {
243      conf.set(HConstants.REGIONSERVER_PORT, originalPort);
244    }
245  }
246}