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.HMsg;
27  import org.apache.hadoop.hbase.HServerInfo;
28  import org.apache.hadoop.hbase.HBaseTestingUtility;
29  import org.apache.hadoop.hbase.HRegionInfo;
30  import org.apache.hadoop.hbase.HServerAddress;
31  import org.apache.hadoop.hbase.client.HBaseAdmin;
32  import org.apache.hadoop.hbase.client.HTable;
33  import org.apache.hadoop.hbase.util.Bytes;
34  import org.apache.hadoop.hbase.util.Pair;
35  
36  import java.io.IOException;
37  import java.util.List;
38  import java.util.concurrent.CountDownLatch;
39  import java.util.concurrent.TimeUnit;
40  
41  import org.junit.AfterClass;
42  import org.junit.BeforeClass;
43  import org.junit.Test;
44  
45  import com.google.common.base.Joiner;
46  
47  import static org.junit.Assert.*;
48  
49  public class TestMaster {
50    private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
51    private static final Log LOG = LogFactory.getLog(TestMasterWithDisabling.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 IOException {
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      HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
71  
72      TEST_UTIL.createTable(TABLENAME, FAMILYNAME);
73      TEST_UTIL.loadTable(new HTable(TABLENAME), FAMILYNAME);
74  
75      List<Pair<HRegionInfo, HServerAddress>> tableRegions =
76        m.getTableRegions(TABLENAME);
77      LOG.info("Regions after load: " + Joiner.on(',').join(tableRegions));
78      assertEquals(1, tableRegions.size());
79      assertArrayEquals(HConstants.EMPTY_START_ROW,
80          tableRegions.get(0).getFirst().getStartKey());
81      assertArrayEquals(HConstants.EMPTY_END_ROW,
82          tableRegions.get(0).getFirst().getEndKey());
83  
84      // Now trigger a split and stop when the split is in progress
85      
86      CountDownLatch aboutToOpen = new CountDownLatch(1);
87      CountDownLatch proceed = new CountDownLatch(1);
88      RegionOpenListener list = new RegionOpenListener(aboutToOpen, proceed);
89      m.getRegionServerOperationQueue().registerRegionServerOperationListener(list);
90  
91      LOG.info("Splitting table");
92      admin.split(TABLENAME);
93      LOG.info("Waiting for split result to be about to open");
94      aboutToOpen.await(60, TimeUnit.SECONDS);
95      try {
96        LOG.info("Making sure we can call getTableRegions while opening");
97        tableRegions = m.getTableRegions(TABLENAME);
98        LOG.info("Regions: " + Joiner.on(',').join(tableRegions));
99        // We have three regions because one is split-in-progress
100       assertEquals(3, tableRegions.size());
101       LOG.info("Making sure we can call getTableRegionClosest while opening");
102       Pair<HRegionInfo,HServerAddress> pair =
103         m.getTableRegionForRow(TABLENAME, Bytes.toBytes("cde"));
104       LOG.info("Result is: " + pair);
105       Pair<HRegionInfo, HServerAddress> tableRegionFromName = m.getTableRegionFromName(pair.getFirst().getRegionName());
106       assertEquals(tableRegionFromName.getFirst(), pair.getFirst());
107     } finally {
108       proceed.countDown();
109     }
110   }
111 
112   static class RegionOpenListener implements RegionServerOperationListener {
113     CountDownLatch aboutToOpen, proceed;
114 
115     public RegionOpenListener(CountDownLatch aboutToOpen, CountDownLatch proceed)
116     {
117       this.aboutToOpen = aboutToOpen;
118       this.proceed = proceed;
119     }
120 
121     @Override
122     public boolean process(HServerInfo serverInfo, HMsg incomingMsg) {
123       if (!incomingMsg.isType(HMsg.Type.MSG_REPORT_OPEN)) {
124         return true;
125       }
126       try {
127         aboutToOpen.countDown();
128         proceed.await(60, TimeUnit.SECONDS);
129       } catch (InterruptedException ie) {
130         throw new RuntimeException(ie);
131       }
132       return true;
133     }
134 
135     @Override
136     public boolean process(RegionServerOperation op) throws IOException {
137       return true;
138     }
139 
140     @Override
141     public void processed(RegionServerOperation op) {
142     }
143   }
144 
145 }