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.*;
25  import org.apache.hadoop.hbase.catalog.MetaReader;
26  import org.apache.hadoop.hbase.client.HBaseAdmin;
27  import org.apache.hadoop.hbase.client.HTable;
28  import org.apache.hadoop.hbase.executor.EventHandler;
29  import org.apache.hadoop.hbase.executor.EventHandler.EventHandlerListener;
30  import org.apache.hadoop.hbase.executor.EventHandler.EventType;
31  import org.apache.hadoop.hbase.util.Bytes;
32  import org.apache.hadoop.hbase.util.Pair;
33  
34  import java.io.IOException;
35  import java.util.List;
36  import java.util.concurrent.CountDownLatch;
37  import java.util.concurrent.TimeUnit;
38  
39  import org.junit.AfterClass;
40  import org.junit.BeforeClass;
41  import org.junit.Test;
42  
43  import com.google.common.base.Joiner;
44  import org.junit.experimental.categories.Category;
45  
46  import static org.junit.Assert.*;
47  
48  @Category(MediumTests.class)
49  public class TestMaster {
50    private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
51    private static final Log LOG = LogFactory.getLog(TestMaster.class);
52    private static final byte[] TABLENAME = Bytes.toBytes("TestMaster");
53    private static final byte[] FAMILYNAME = Bytes.toBytes("fam");
54  
55    @BeforeClass
56    public static void beforeAllTests() throws Exception {
57      // Start a cluster of two regionservers.
58      TEST_UTIL.startMiniCluster(1);
59    }
60  
61    @AfterClass
62    public static void afterAllTests() throws Exception {
63      TEST_UTIL.shutdownMiniCluster();
64    }
65  
66    @Test
67    public void testMasterOpsWhileSplitting() throws Exception {
68      MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
69      HMaster m = cluster.getMaster();
70  
71      HTable ht = TEST_UTIL.createTable(TABLENAME, FAMILYNAME);
72      assertTrue(m.assignmentManager.getZKTable().isEnabledTable
73          (Bytes.toString(TABLENAME)));
74      TEST_UTIL.loadTable(ht, FAMILYNAME);
75      ht.close();
76  
77      List<Pair<HRegionInfo, ServerName>> tableRegions =
78        MetaReader.getTableRegionsAndLocations(m.getCatalogTracker(),
79            Bytes.toString(TABLENAME));
80      LOG.info("Regions after load: " + Joiner.on(',').join(tableRegions));
81      assertEquals(1, tableRegions.size());
82      assertArrayEquals(HConstants.EMPTY_START_ROW,
83          tableRegions.get(0).getFirst().getStartKey());
84      assertArrayEquals(HConstants.EMPTY_END_ROW,
85          tableRegions.get(0).getFirst().getEndKey());
86  
87      // Now trigger a split and stop when the split is in progress
88      CountDownLatch split = new CountDownLatch(1);
89      CountDownLatch proceed = new CountDownLatch(1);
90      RegionSplitListener list = new RegionSplitListener(split, proceed);
91      cluster.getMaster().executorService.
92        registerListener(EventType.RS_ZK_REGION_SPLIT, list);
93  
94      LOG.info("Splitting table");
95      TEST_UTIL.getHBaseAdmin().split(TABLENAME);
96      LOG.info("Waiting for split result to be about to open");
97      split.await(60, TimeUnit.SECONDS);
98      try {
99        LOG.info("Making sure we can call getTableRegions while opening");
100       tableRegions = MetaReader.getTableRegionsAndLocations(m.getCatalogTracker(),
101         TABLENAME, false);
102 
103       LOG.info("Regions: " + Joiner.on(',').join(tableRegions));
104       // We have three regions because one is split-in-progress
105       assertEquals(3, tableRegions.size());
106       LOG.info("Making sure we can call getTableRegionClosest while opening");
107       Pair<HRegionInfo, ServerName> pair =
108         m.getTableRegionForRow(TABLENAME, Bytes.toBytes("cde"));
109       LOG.info("Result is: " + pair);
110       Pair<HRegionInfo, ServerName> tableRegionFromName =
111         MetaReader.getRegion(m.getCatalogTracker(),
112             pair.getFirst().getRegionName());
113       assertEquals(tableRegionFromName.getFirst(), pair.getFirst());
114     } finally {
115       proceed.countDown();
116     }
117   }
118 
119   static class RegionSplitListener implements EventHandlerListener {
120     CountDownLatch split, proceed;
121 
122     public RegionSplitListener(CountDownLatch split, CountDownLatch proceed) {
123       this.split = split;
124       this.proceed = proceed;
125     }
126 
127     @Override
128     public void afterProcess(EventHandler event) {
129       if (event.getEventType() != EventType.RS_ZK_REGION_SPLIT) {
130         return;
131       }
132       try {
133         split.countDown();
134         proceed.await(60, TimeUnit.SECONDS);
135       } catch (InterruptedException ie) {
136         throw new RuntimeException(ie);
137       }
138       return;
139     }
140 
141     @Override
142     public void beforeProcess(EventHandler event) {
143     }
144   }
145 
146   @org.junit.Rule
147   public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
148     new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
149 }
150