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.HServerAddress;
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 IOException {
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, HServerAddress>> 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  
90      CountDownLatch aboutToOpen = new CountDownLatch(1);
91      CountDownLatch proceed = new CountDownLatch(1);
92      RegionOpenListener list = new RegionOpenListener(aboutToOpen, proceed);
93      cluster.getMaster().executorService.
94        registerListener(EventType.RS_ZK_REGION_OPENED, list);
95  
96      LOG.info("Splitting table");
97      admin.split(TABLENAME);
98      LOG.info("Waiting for split result to be about to open");
99      aboutToOpen.await(60, TimeUnit.SECONDS);
100     try {
101       LOG.info("Making sure we can call getTableRegions while opening");
102       tableRegions = MetaReader.getTableRegionsAndLocations(
103           m.getCatalogTracker(), Bytes.toString(TABLENAME));
104 
105       LOG.info("Regions: " + Joiner.on(',').join(tableRegions));
106       // We have three regions because one is split-in-progress
107       assertEquals(3, tableRegions.size());
108       LOG.info("Making sure we can call getTableRegionClosest while opening");
109       Pair<HRegionInfo,HServerAddress> pair =
110         m.getTableRegionForRow(TABLENAME, Bytes.toBytes("cde"));
111       LOG.info("Result is: " + pair);
112       Pair<HRegionInfo, HServerAddress> tableRegionFromName =
113         MetaReader.getRegion(m.getCatalogTracker(),
114             pair.getFirst().getRegionName());
115       assertEquals(tableRegionFromName.getFirst(), pair.getFirst());
116     } finally {
117       proceed.countDown();
118     }
119   }
120 
121   static class RegionOpenListener implements EventHandlerListener {
122     CountDownLatch aboutToOpen, proceed;
123 
124     public RegionOpenListener(CountDownLatch aboutToOpen, CountDownLatch proceed)
125     {
126       this.aboutToOpen = aboutToOpen;
127       this.proceed = proceed;
128     }
129 
130     @Override
131     public void afterProcess(EventHandler event) {
132       if (event.getEventType() != EventType.RS_ZK_REGION_OPENED) {
133         return;
134       }
135       try {
136         aboutToOpen.countDown();
137         proceed.await(60, TimeUnit.SECONDS);
138       } catch (InterruptedException ie) {
139         throw new RuntimeException(ie);
140       }
141       return;
142     }
143 
144     @Override
145     public void beforeProcess(EventHandler event) {
146     }
147   }
148 }