View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.master;
20  
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertNotEquals;
23  import static org.junit.Assert.assertTrue;
24  
25  import java.util.List;
26  import java.util.Map;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.hadoop.conf.Configuration;
31  import org.apache.hadoop.hbase.HBaseTestingUtility;
32  import org.apache.hadoop.hbase.HConstants;
33  import org.apache.hadoop.hbase.HRegionInfo;
34  import org.apache.hadoop.hbase.MiniHBaseCluster;
35  import org.apache.hadoop.hbase.ServerName;
36  import org.apache.hadoop.hbase.TableExistsException;
37  import org.apache.hadoop.hbase.TableName;
38  import org.apache.hadoop.hbase.client.Connection;
39  import org.apache.hadoop.hbase.client.ConnectionFactory;
40  import org.apache.hadoop.hbase.client.MetaScanner;
41  import org.apache.hadoop.hbase.executor.EventType;
42  import org.apache.hadoop.hbase.testclassification.LargeTests;
43  import org.apache.hadoop.hbase.util.Bytes;
44  import org.apache.hadoop.hbase.util.JVMClusterUtil;
45  import org.apache.hadoop.hbase.util.Threads;
46  import org.apache.hadoop.hbase.zookeeper.ZKAssign;
47  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
48  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
49  import org.junit.After;
50  import org.junit.Test;
51  import org.junit.experimental.categories.Category;
52  
53  @Category(LargeTests.class)
54  public class TestRestartCluster {
55    private static final Log LOG = LogFactory.getLog(TestRestartCluster.class);
56    private HBaseTestingUtility UTIL = new HBaseTestingUtility();
57  
58    private static final byte[] TABLENAME = Bytes.toBytes("master_transitions");
59    private static final byte [][] FAMILIES = {Bytes.toBytes("a")};
60    private static final TableName[] TABLES = {
61        TableName.valueOf("restartTableOne"),
62        TableName.valueOf("restartTableTwo"),
63        TableName.valueOf("restartTableThree")
64    };
65    private static final byte [] FAMILY = Bytes.toBytes("family");
66  
67    @After public void tearDown() throws Exception {
68      UTIL.shutdownMiniCluster();
69    }
70  
71    @Test (timeout=300000) public void testRestartClusterAfterKill()
72    throws Exception {
73      UTIL.getConfiguration().setBoolean("hbase.assignment.usezk", true);
74      UTIL.startMiniZKCluster();
75      ZooKeeperWatcher zooKeeper =
76        new ZooKeeperWatcher(UTIL.getConfiguration(), "cluster1", null, true);
77  
78      // create the unassigned region, throw up a region opened state for META
79      String unassignedZNode = zooKeeper.assignmentZNode;
80      ZKUtil.createAndFailSilent(zooKeeper, unassignedZNode);
81  
82      ServerName sn = ServerName.valueOf(HMaster.MASTER, 1, System.currentTimeMillis());
83  
84      ZKAssign.createNodeOffline(zooKeeper, HRegionInfo.FIRST_META_REGIONINFO, sn);
85  
86      LOG.debug("Created UNASSIGNED zNode for ROOT and hbase:meta regions in state " +
87          EventType.M_ZK_REGION_OFFLINE);
88  
89      // start the HB cluster
90      LOG.info("Starting HBase cluster...");
91      UTIL.startMiniCluster(2);
92  
93      UTIL.createTable(TABLENAME, FAMILIES);
94      LOG.info("Created a table, waiting for table to be available...");
95      UTIL.waitTableAvailable(TABLENAME, 60*1000);
96  
97      LOG.info("Master deleted unassigned region and started up successfully.");
98    }
99  
100   @Test (timeout=300000)
101   public void testClusterRestart() throws Exception {
102     UTIL.startMiniCluster(3);
103     Connection connection = UTIL.getConnection();
104 
105     while (!UTIL.getMiniHBaseCluster().getMaster().isInitialized()) {
106       Threads.sleep(1);
107     }
108     LOG.info("\n\nCreating tables");
109     for(TableName TABLE : TABLES) {
110       UTIL.createTable(TABLE, FAMILY);
111     }
112     for(TableName TABLE : TABLES) {
113       UTIL.waitTableEnabled(TABLE);
114     }
115 
116     List<HRegionInfo> allRegions =
117         MetaScanner.listAllRegions(UTIL.getConfiguration(), connection, true);
118     assertEquals(4, allRegions.size());
119 
120     LOG.info("\n\nShutting down cluster");
121     UTIL.shutdownMiniHBaseCluster();
122 
123     LOG.info("\n\nSleeping a bit");
124     Thread.sleep(2000);
125 
126     LOG.info("\n\nStarting cluster the second time");
127     UTIL.restartHBaseCluster(3);
128 
129     // Need to use a new 'Configuration' so we make a new HConnection.
130     // Otherwise we're reusing an HConnection that has gone stale because
131     // the shutdown of the cluster also called shut of the connection.
132     connection = UTIL.getConnection();
133     allRegions =
134         MetaScanner.listAllRegions(new Configuration(UTIL.getConfiguration()), connection, true);
135     assertEquals(4, allRegions.size());
136     LOG.info("\n\nWaiting for tables to be available");
137     for(TableName TABLE: TABLES) {
138       try {
139         UTIL.createTable(TABLE, FAMILY);
140         assertTrue("Able to create table that should already exist", false);
141       } catch(TableExistsException tee) {
142         LOG.info("Table already exists as expected");
143       }
144       UTIL.waitTableAvailable(TABLE);
145     }
146   }
147 
148   /**
149    * This tests retaining assignments on a cluster restart
150    */
151   @Test (timeout=300000)
152   public void testRetainAssignmentOnRestart() throws Exception {
153     UTIL.startMiniCluster(2);
154     while (!UTIL.getMiniHBaseCluster().getMaster().isInitialized()) {
155       Threads.sleep(1);
156     }
157     // Turn off balancer
158     UTIL.getMiniHBaseCluster().getMaster().
159       getMasterRpcServices().synchronousBalanceSwitch(false);
160     LOG.info("\n\nCreating tables");
161     for(TableName TABLE : TABLES) {
162       UTIL.createTable(TABLE, FAMILY);
163     }
164     for(TableName TABLE : TABLES) {
165       UTIL.waitTableEnabled(TABLE);
166     }
167 
168     HMaster master = UTIL.getMiniHBaseCluster().getMaster();
169     AssignmentManager am = master.getAssignmentManager();
170     am.waitUntilNoRegionsInTransition(120000);
171 
172     // We don't have to use SnapshotOfRegionAssignmentFromMeta.
173     // We use it here because AM used to use it to load all user region placements
174     SnapshotOfRegionAssignmentFromMeta snapshot = new SnapshotOfRegionAssignmentFromMeta(
175       master.getConnection());
176     snapshot.initialize();
177     Map<HRegionInfo, ServerName> regionToRegionServerMap
178       = snapshot.getRegionToRegionServerMap();
179 
180     MiniHBaseCluster cluster = UTIL.getHBaseCluster();
181     List<JVMClusterUtil.RegionServerThread> threads = cluster.getLiveRegionServerThreads();
182     assertEquals(2, threads.size());
183     int[] rsPorts = new int[2];
184     for (int i = 0; i < 2; i++) {
185       rsPorts[i] = threads.get(i).getRegionServer().getServerName().getPort();
186     }
187     for (ServerName serverName: regionToRegionServerMap.values()) {
188       boolean found = false; // Test only, no need to optimize
189       for (int k = 0; k < 2 && !found; k++) {
190         found = serverName.getPort() == rsPorts[k];
191       }
192       assertTrue(found);
193     }
194 
195     LOG.info("\n\nShutting down HBase cluster");
196     cluster.shutdown();
197     cluster.waitUntilShutDown();
198 
199     LOG.info("\n\nSleeping a bit");
200     Thread.sleep(2000);
201 
202     LOG.info("\n\nStarting cluster the second time with the same ports");
203     try {
204       cluster.getConf().setInt(
205         ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART, 2);
206       master = cluster.startMaster().getMaster();
207       for (int i = 0; i < 2; i++) {
208         cluster.getConf().setInt(HConstants.REGIONSERVER_PORT, rsPorts[i]);
209         cluster.startRegionServer();
210       }
211     } finally {
212       // Reset region server port so as not to conflict with other tests
213       cluster.getConf().setInt(HConstants.REGIONSERVER_PORT, 0);
214       cluster.getConf().setInt(
215         ServerManager.WAIT_ON_REGIONSERVERS_MINTOSTART, 1);
216     }
217 
218     // Make sure live regionservers are on the same host/port
219     List<ServerName> localServers = master.getServerManager().getOnlineServersList();
220     assertEquals(2, localServers.size());
221     for (int i = 0; i < 2; i++) {
222       boolean found = false;
223       for (ServerName serverName: localServers) {
224         if (serverName.getPort() == rsPorts[i]) {
225           found = true;
226           break;
227         }
228       }
229       assertTrue(found);
230     }
231 
232     // Wait till master is initialized and all regions are assigned
233     RegionStates regionStates = master.getAssignmentManager().getRegionStates();
234     int expectedRegions = regionToRegionServerMap.size() + 1;
235     while (!master.isInitialized()
236         || regionStates.getRegionAssignments().size() != expectedRegions) {
237       Threads.sleep(100);
238     }
239 
240     snapshot =new SnapshotOfRegionAssignmentFromMeta(master.getConnection());
241     snapshot.initialize();
242     Map<HRegionInfo, ServerName> newRegionToRegionServerMap =
243       snapshot.getRegionToRegionServerMap();
244     assertEquals(regionToRegionServerMap.size(), newRegionToRegionServerMap.size());
245     for (Map.Entry<HRegionInfo, ServerName> entry: newRegionToRegionServerMap.entrySet()) {
246       if (TableName.NAMESPACE_TABLE_NAME.equals(entry.getKey().getTable())) continue;
247       ServerName oldServer = regionToRegionServerMap.get(entry.getKey());
248       ServerName currentServer = entry.getValue();
249       assertEquals(oldServer.getHostAndPort(), currentServer.getHostAndPort());
250       assertNotEquals(oldServer.getStartcode(), currentServer.getStartcode());
251     }
252   }
253 }