1   /**
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.master;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  import org.apache.hadoop.hbase.HConstants;
25  import org.apache.hadoop.hbase.MiniHBaseCluster;
26  import org.apache.hadoop.hbase.HBaseTestingUtility;
27  import org.apache.hadoop.hbase.HRegionInfo;
28  import org.apache.hadoop.hbase.ServerName;
29  import org.apache.hadoop.hbase.catalog.MetaReader;
30  import org.apache.hadoop.hbase.client.HBaseAdmin;
31  import org.apache.hadoop.hbase.client.HTable;
32  import org.apache.hadoop.hbase.executor.EventHandler;
33  import org.apache.hadoop.hbase.executor.EventHandler.EventHandlerListener;
34  import org.apache.hadoop.hbase.executor.EventHandler.EventType;
35  import org.apache.hadoop.hbase.util.Bytes;
36  import org.apache.hadoop.hbase.util.Pair;
37  
38  import java.io.IOException;
39  import java.util.List;
40  import java.util.concurrent.CountDownLatch;
41  import java.util.concurrent.TimeUnit;
42  
43  import org.junit.AfterClass;
44  import org.junit.BeforeClass;
45  import org.junit.Test;
46  
47  import com.google.common.base.Joiner;
48  
49  import static org.junit.Assert.*;
50  
51  public class TestMaster {
52    private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
53    private static final Log LOG = LogFactory.getLog(TestMaster.class);
54    private static final byte[] TABLENAME = Bytes.toBytes("TestMaster");
55    private static final byte[] FAMILYNAME = Bytes.toBytes("fam");
56  
57    @BeforeClass
58    public static void beforeAllTests() throws Exception {
59      // Start a cluster of two regionservers.
60      TEST_UTIL.startMiniCluster(1);
61    }
62  
63    @AfterClass
64    public static void afterAllTests() throws Exception {
65      TEST_UTIL.shutdownMiniCluster();
66    }
67  
68    @Test
69    public void testMasterOpsWhileSplitting() throws Exception {
70      MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
71      HMaster m = cluster.getMaster();
72      HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
73  
74      TEST_UTIL.createTable(TABLENAME, FAMILYNAME);
75      TEST_UTIL.loadTable(new HTable(TEST_UTIL.getConfiguration(), TABLENAME),
76        FAMILYNAME);
77  
78      List<Pair<HRegionInfo, ServerName>> tableRegions =
79        MetaReader.getTableRegionsAndLocations(m.getCatalogTracker(),
80            Bytes.toString(TABLENAME));
81      LOG.info("Regions after load: " + Joiner.on(',').join(tableRegions));
82      assertEquals(1, tableRegions.size());
83      assertArrayEquals(HConstants.EMPTY_START_ROW,
84          tableRegions.get(0).getFirst().getStartKey());
85      assertArrayEquals(HConstants.EMPTY_END_ROW,
86          tableRegions.get(0).getFirst().getEndKey());
87  
88      // Now trigger a split and stop when the split is in progress
89      CountDownLatch split = new CountDownLatch(1);
90      CountDownLatch proceed = new CountDownLatch(1);
91      RegionSplitListener list = new RegionSplitListener(split, proceed);
92      cluster.getMaster().executorService.
93        registerListener(EventType.RS_ZK_REGION_SPLIT, list);
94  
95      LOG.info("Splitting table");
96      admin.split(TABLENAME);
97      LOG.info("Waiting for split result to be about to open");
98      split.await(60, TimeUnit.SECONDS);
99      try {
100       LOG.info("Making sure we can call getTableRegions while opening");
101       tableRegions = MetaReader.getTableRegionsAndLocations(m.getCatalogTracker(),
102         TABLENAME, false);
103 
104       LOG.info("Regions: " + Joiner.on(',').join(tableRegions));
105       // We have three regions because one is split-in-progress
106       assertEquals(3, tableRegions.size());
107       LOG.info("Making sure we can call getTableRegionClosest while opening");
108       Pair<HRegionInfo, ServerName> pair =
109         m.getTableRegionForRow(TABLENAME, Bytes.toBytes("cde"));
110       LOG.info("Result is: " + pair);
111       Pair<HRegionInfo, ServerName> tableRegionFromName =
112         MetaReader.getRegion(m.getCatalogTracker(),
113             pair.getFirst().getRegionName());
114       assertEquals(tableRegionFromName.getFirst(), pair.getFirst());
115     } finally {
116       proceed.countDown();
117     }
118   }
119 
120   static class RegionSplitListener implements EventHandlerListener {
121     CountDownLatch split, proceed;
122 
123     public RegionSplitListener(CountDownLatch split, CountDownLatch proceed) {
124       this.split = split;
125       this.proceed = proceed;
126     }
127 
128     @Override
129     public void afterProcess(EventHandler event) {
130       if (event.getEventType() != EventType.RS_ZK_REGION_SPLIT) {
131         return;
132       }
133       try {
134         split.countDown();
135         proceed.await(60, TimeUnit.SECONDS);
136       } catch (InterruptedException ie) {
137         throw new RuntimeException(ie);
138       }
139       return;
140     }
141 
142     @Override
143     public void beforeProcess(EventHandler event) {
144     }
145   }
146 }