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 java.io.IOException;
23  import java.util.Set;
24  import java.util.concurrent.CopyOnWriteArraySet;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.hbase.HBaseTestingUtility;
29  import org.apache.hadoop.hbase.HMsg;
30  import org.apache.hadoop.hbase.HServerAddress;
31  import org.apache.hadoop.hbase.HServerInfo;
32  import org.apache.hadoop.hbase.MiniHBaseCluster;
33  import org.apache.hadoop.hbase.client.HTable;
34  import org.apache.hadoop.hbase.regionserver.HRegionServer;
35  import org.apache.hadoop.hbase.util.Bytes;
36  import org.apache.hadoop.hbase.util.Threads;
37  import org.junit.AfterClass;
38  import org.junit.Assert;
39  import org.junit.Before;
40  import org.junit.BeforeClass;
41  import org.junit.Test;
42  
43  /**
44   * Test issues assigning ROOT.
45   */
46  public class TestROOTAssignment {
47    private static final Log LOG = LogFactory.getLog(TestROOTAssignment.class);
48    private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
49    private static final byte [] TABLENAME = Bytes.toBytes("root_assignments");
50    private static final byte [][] FAMILIES =
51      new byte [][] {Bytes.toBytes("family")};
52  
53    /**
54     * Start up a mini cluster and put a small table of many empty regions into it.
55     * @throws Exception
56     */
57    @BeforeClass public static void beforeAllTests() throws Exception {
58      TEST_UTIL.getConfiguration().setInt("hbase.regions.percheckin", 2);
59      // Start a cluster of two regionservers.
60      TEST_UTIL.startMiniCluster(2);
61      // Create a table of three families.  This will assign a region.
62      TEST_UTIL.createTable(TABLENAME, FAMILIES);
63      HTable t = new HTable(TEST_UTIL.getConfiguration(), TABLENAME);
64      int countOfRegions = TEST_UTIL.createMultiRegions(t, FAMILIES[0]);
65      TEST_UTIL.waitUntilAllRegionsAssigned(countOfRegions);
66      HTable table = new HTable(TEST_UTIL.getConfiguration(), TABLENAME);
67      TEST_UTIL.loadTable(table, FAMILIES[0]);
68      table.close();
69    }
70  
71    @AfterClass public static void afterAllTests() throws IOException {
72      TEST_UTIL.shutdownMiniCluster();
73    }
74  
75    @Before public void setup() throws IOException {
76      TEST_UTIL.ensureSomeRegionServersAvailable(2);
77    }
78  
79    /**
80     * Interrupt processing of server shutdown so it gets put on delay queue.
81     */
82    static class PostponeShutdownProcessing implements RegionServerOperationListener {
83      // Map of what we've delayed so we don't do do repeated delays.
84      private final Set<RegionServerOperation> postponed =
85        new CopyOnWriteArraySet<RegionServerOperation>();
86      private boolean done = false;
87      private final HServerAddress rootServerAddress;
88      private final HMaster master;
89   
90      PostponeShutdownProcessing(final HMaster master,
91          final HServerAddress rootServerAddress) {
92        this.master = master;
93        this.rootServerAddress = rootServerAddress;
94      }
95  
96      @Override
97      public boolean process(final RegionServerOperation op) throws IOException {
98        // If a regionserver shutdown and its of the root server, then we want to
99        // delay the processing of the shutdown
100       boolean result = true;
101       if (op instanceof ProcessServerShutdown) {
102         ProcessServerShutdown pss = (ProcessServerShutdown)op;
103         if (pss.getDeadServerAddress().equals(this.rootServerAddress)) {
104           // Don't postpone more than once.
105           if (!this.postponed.contains(pss)) {
106             this.postponed.add(pss);
107             Assert.assertNull(this.master.getRegionManager().getRootRegionLocation());
108             pss.setDelay(1 * 1000);
109             // Return false.  This will add this op to the delayed queue.
110             result = false;
111           }
112         }
113       }
114       return result;
115     }
116 
117     @Override
118     public boolean process(HServerInfo serverInfo, HMsg incomingMsg) {
119       return true;
120     }
121 
122     @Override
123     public void processed(RegionServerOperation op) {
124       if (op instanceof ProcessServerShutdown) {
125         ProcessServerShutdown pss = (ProcessServerShutdown)op;
126         if (pss.getDeadServerAddress().equals(this.rootServerAddress)) {
127           this.done = true;
128         }
129       }
130     }
131 
132     public boolean isDone() {
133       return this.done;
134     }
135   }
136 
137   /**
138    * If the split of the log for the regionserver hosting ROOT doesn't go off
139    * smoothly, if the process server shutdown gets added to the delayed queue
140    * of events to process, then ROOT was not being allocated, ever.
141    * @see <a href="https://issues.apache.org/jira/browse/HBASE-2707">HBASE-2707</a> 
142    */
143   @Test (timeout=300000) public void testROOTDeployedThoughProblemSplittingLog()
144   throws Exception {
145     LOG.info("Running testROOTDeployedThoughProblemSplittingLog");
146     MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
147     final HMaster master = cluster.getMaster();
148     byte [] rootRegion = Bytes.toBytes("-ROOT-,,0");
149     int rootIndex = cluster.getServerWith(rootRegion);
150     final HRegionServer rootHRS = cluster.getRegionServer(rootIndex);
151  
152     // Add our RegionServerOperationsListener
153     PostponeShutdownProcessing listener = new PostponeShutdownProcessing(master,
154       rootHRS.getHServerInfo().getServerAddress());
155     master.getRegionServerOperationQueue().
156       registerRegionServerOperationListener(listener);
157     try {
158       // Now close the server carrying meta.
159       cluster.abortRegionServer(rootIndex);
160 
161       // Wait for processing of the shutdown server.
162       while(!listener.isDone()) Threads.sleep(100);
163       master.getRegionManager().waitForRootRegionLocation();
164     } finally {
165       master.getRegionServerOperationQueue().
166         unregisterRegionServerOperationListener(listener);
167     }
168   }
169 }