View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.master;
19  
20  
21  import static org.junit.Assert.assertFalse;
22  import static org.junit.Assert.assertTrue;
23  
24  import java.io.IOException;
25  import java.net.InetAddress;
26  import java.net.UnknownHostException;
27  import java.util.ArrayList;
28  import java.util.List;
29  import java.util.Set;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  import org.apache.hadoop.conf.Configuration;
34  import org.apache.hadoop.hbase.Abortable;
35  import org.apache.hadoop.hbase.CoordinatedStateException;
36  import org.apache.hadoop.hbase.CoordinatedStateManager;
37  import org.apache.hadoop.hbase.CoordinatedStateManagerFactory;
38  import org.apache.hadoop.hbase.HBaseTestingUtility;
39  import org.apache.hadoop.hbase.HConstants;
40  import org.apache.hadoop.hbase.HRegionInfo;
41  import org.apache.hadoop.hbase.testclassification.MediumTests;
42  import org.apache.hadoop.hbase.MetaMockingUtil;
43  import org.apache.hadoop.hbase.Server;
44  import org.apache.hadoop.hbase.ServerLoad;
45  import org.apache.hadoop.hbase.ServerName;
46  import org.apache.hadoop.hbase.TableName;
47  import org.apache.hadoop.hbase.ZooKeeperConnectionException;
48  import org.apache.hadoop.hbase.client.ClusterConnection;
49  import org.apache.hadoop.hbase.client.HConnectionTestingUtility;
50  import org.apache.hadoop.hbase.client.Result;
51  import org.apache.hadoop.hbase.monitoring.MonitoredTask;
52  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
53  import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionServerReportRequest;
54  import org.apache.hadoop.hbase.util.FSUtils;
55  import org.apache.hadoop.hbase.util.Threads;
56  import org.apache.hadoop.hbase.zookeeper.MetaTableLocator;
57  import org.apache.hadoop.hbase.zookeeper.ZKAssign;
58  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
59  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
60  import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
61  import org.apache.zookeeper.KeeperException;
62  import org.junit.After;
63  import org.junit.AfterClass;
64  import org.junit.BeforeClass;
65  import org.junit.Test;
66  import org.junit.experimental.categories.Category;
67  import org.mockito.Mockito;
68  
69  import com.google.protobuf.ServiceException;
70  
71  /**
72   * Standup the master and fake it to test various aspects of master function.
73   * Does NOT spin up a mini hbase nor mini dfs cluster testing master (it does
74   * put up a zk cluster but this is usually pretty fast compared).  Also, should
75   * be possible to inject faults at points difficult to get at in cluster context.
76   * TODO: Speed up the zk connection by Master.  It pauses 5 seconds establishing
77   * session.
78   */
79  @Category(MediumTests.class)
80  public class TestMasterNoCluster {
81    private static final Log LOG = LogFactory.getLog(TestMasterNoCluster.class);
82    private static final HBaseTestingUtility TESTUTIL = new HBaseTestingUtility();
83  
84    @BeforeClass
85    public static void setUpBeforeClass() throws Exception {
86      Configuration c = TESTUTIL.getConfiguration();
87      // We use local filesystem.  Set it so it writes into the testdir.
88      FSUtils.setRootDir(c, TESTUTIL.getDataTestDir());
89      DefaultMetricsSystem.setMiniClusterMode(true);
90      // Startup a mini zk cluster.
91      TESTUTIL.startMiniZKCluster();
92    }
93  
94    @AfterClass
95    public static void tearDownAfterClass() throws Exception {
96      TESTUTIL.shutdownMiniZKCluster();
97    }
98  
99    @After
100   public void tearDown()
101   throws KeeperException, ZooKeeperConnectionException, IOException {
102     // Make sure zk is clean before we run the next test.
103     ZooKeeperWatcher zkw = new ZooKeeperWatcher(TESTUTIL.getConfiguration(),
104         "@Before", new Abortable() {
105       @Override
106       public void abort(String why, Throwable e) {
107         throw new RuntimeException(why, e);
108       }
109 
110       @Override
111       public boolean isAborted() {
112         return false;
113       }
114     });
115     ZKUtil.deleteNodeRecursively(zkw, zkw.baseZNode);
116     zkw.close();
117   }
118 
119   /**
120    * Test starting master then stopping it before its fully up.
121    * @throws IOException
122    * @throws KeeperException
123    * @throws InterruptedException
124    */
125   @Test (timeout=30000)
126   public void testStopDuringStart()
127   throws IOException, KeeperException, InterruptedException {
128     CoordinatedStateManager cp = CoordinatedStateManagerFactory.getCoordinatedStateManager(
129       TESTUTIL.getConfiguration());
130     HMaster master = new HMaster(TESTUTIL.getConfiguration(), cp);
131     master.start();
132     // Immediately have it stop.  We used hang in assigning meta.
133     master.stopMaster();
134     master.join();
135   }
136 
137   /**
138    * Test master failover.
139    * Start up three fake regionservers and a master.
140    * @throws IOException
141    * @throws KeeperException
142    * @throws InterruptedException
143    */
144   @Test (timeout=30000)
145   public void testFailover()
146   throws IOException, KeeperException, InterruptedException, ServiceException {
147     final long now = System.currentTimeMillis();
148     // Names for our three servers.  Make the port numbers match hostname.
149     // Will come in use down in the server when we need to figure how to respond.
150     final ServerName sn0 = ServerName.valueOf("0.example.org", 0, now);
151     final ServerName sn1 = ServerName.valueOf("1.example.org", 1, now);
152     final ServerName sn2 = ServerName.valueOf("2.example.org", 2, now);
153     final ServerName [] sns = new ServerName [] {sn0, sn1, sn2};
154     // Put up the mock servers
155     final Configuration conf = TESTUTIL.getConfiguration();
156     final MockRegionServer rs0 = new MockRegionServer(conf, sn0);
157     final MockRegionServer rs1 = new MockRegionServer(conf, sn1);
158     final MockRegionServer rs2 = new MockRegionServer(conf, sn2);
159     // Put some data into the servers.  Make it look like sn0 has the metaH
160     // Put data into sn2 so it looks like it has a few regions for a table named 't'.
161     MetaTableLocator.setMetaLocation(rs0.getZooKeeper(),
162       rs0.getServerName(), RegionState.State.OPEN);
163     final TableName tableName = TableName.valueOf("t");
164     Result [] results = new Result [] {
165       MetaMockingUtil.getMetaTableRowResult(
166         new HRegionInfo(tableName, HConstants.EMPTY_START_ROW, HBaseTestingUtility.KEYS[1]),
167         rs2.getServerName()),
168       MetaMockingUtil.getMetaTableRowResult(
169         new HRegionInfo(tableName, HBaseTestingUtility.KEYS[1], HBaseTestingUtility.KEYS[2]),
170         rs2.getServerName()),
171       MetaMockingUtil.getMetaTableRowResult(new HRegionInfo(tableName, HBaseTestingUtility.KEYS[2],
172           HConstants.EMPTY_END_ROW),
173         rs2.getServerName())
174     };
175     rs1.setNextResults(HRegionInfo.FIRST_META_REGIONINFO.getRegionName(), results);
176 
177     // Create master.  Subclass to override a few methods so we can insert mocks
178     // and get notification on transitions.  We need to fake out any rpcs the
179     // master does opening/closing regions.  Also need to fake out the address
180     // of the 'remote' mocked up regionservers.
181     CoordinatedStateManager cp = CoordinatedStateManagerFactory.getCoordinatedStateManager(
182       TESTUTIL.getConfiguration());
183     HMaster master = new HMaster(conf, cp) {
184       InetAddress getRemoteInetAddress(final int port, final long serverStartCode)
185       throws UnknownHostException {
186         // Return different address dependent on port passed.
187         if (port > sns.length) {
188           return super.getRemoteInetAddress(port, serverStartCode);
189         }
190         ServerName sn = sns[port];
191         return InetAddress.getByAddress(sn.getHostname(),
192           new byte [] {10, 0, 0, (byte)sn.getPort()});
193       }
194 
195       @Override
196       ServerManager createServerManager(Server master, MasterServices services)
197       throws IOException {
198         ServerManager sm = super.createServerManager(master, services);
199         // Spy on the created servermanager
200         ServerManager spy = Mockito.spy(sm);
201         // Fake a successful close.
202         Mockito.doReturn(true).when(spy).
203           sendRegionClose((ServerName)Mockito.any(), (HRegionInfo)Mockito.any(),
204             Mockito.anyInt(), (ServerName)Mockito.any(), Mockito.anyBoolean());
205         return spy;
206       }
207 
208       @Override
209       public ClusterConnection getConnection() {
210         // Insert a mock for the connection, use TESTUTIL.getConfiguration rather than
211         // the conf from the master; the conf will already have an HConnection
212         // associate so the below mocking of a connection will fail.
213         try {
214           return HConnectionTestingUtility.getMockedConnectionAndDecorate(
215             TESTUTIL.getConfiguration(), rs0, rs0, rs0.getServerName(),
216             HRegionInfo.FIRST_META_REGIONINFO);
217         } catch (IOException e) {
218           return null;
219         }
220       }
221 
222       @Override
223       void initNamespace() {
224       }
225     };
226     master.start();
227 
228     try {
229       // Wait till master is up ready for RPCs.
230       while (!master.serviceStarted) Threads.sleep(10);
231       // Fake master that there are regionservers out there.  Report in.
232       for (int i = 0; i < sns.length; i++) {
233         RegionServerReportRequest.Builder request = RegionServerReportRequest.newBuilder();;
234         ServerName sn = ServerName.parseVersionedServerName(sns[i].getVersionedBytes());
235         request.setServer(ProtobufUtil.toServerName(sn));
236         request.setLoad(ServerLoad.EMPTY_SERVERLOAD.obtainServerLoadPB());
237         master.getMasterRpcServices().regionServerReport(null, request.build());
238       }
239       ZooKeeperWatcher zkw = master.getZooKeeper();
240       // Master should now come up.
241       while (!master.isInitialized()) {
242         // Fake meta is closed on rs0, try several times in case the event is lost
243         // due to race with HMaster#assignMeta
244         ZKAssign.transitionNodeClosed(zkw,
245           HRegionInfo.FIRST_META_REGIONINFO, sn0, -1);
246         Threads.sleep(100);
247       }
248       assertTrue(master.isInitialized());
249     } finally {
250       rs0.stop("Test is done");
251       rs1.stop("Test is done");
252       rs2.stop("Test is done");
253       master.stopMaster();
254       master.join();
255     }
256   }
257 
258   @Test
259   public void testNotPullingDeadRegionServerFromZK()
260       throws IOException, KeeperException, InterruptedException {
261     final Configuration conf = TESTUTIL.getConfiguration();
262     final ServerName newServer = ServerName.valueOf("test.sample", 1, 101);
263     final ServerName deadServer = ServerName.valueOf("test.sample", 1, 100);
264     final MockRegionServer rs0 = new MockRegionServer(conf, newServer);
265 
266     CoordinatedStateManager cp = CoordinatedStateManagerFactory.getCoordinatedStateManager(
267       TESTUTIL.getConfiguration());
268     HMaster master = new HMaster(conf, cp) {
269       @Override
270       void assignMeta(MonitoredTask status, Set<ServerName> previouslyFailedMeatRSs, int replicaId)
271       { }
272 
273       @Override
274       void initializeZKBasedSystemTrackers() throws IOException,
275       InterruptedException, KeeperException, CoordinatedStateException {
276         super.initializeZKBasedSystemTrackers();
277         // Record a newer server in server manager at first
278         serverManager.recordNewServerWithLock(newServer, ServerLoad.EMPTY_SERVERLOAD);
279 
280         List<ServerName> onlineServers = new ArrayList<ServerName>();
281         onlineServers.add(deadServer);
282         onlineServers.add(newServer);
283         // Mock the region server tracker to pull the dead server from zk
284         regionServerTracker = Mockito.spy(regionServerTracker);
285         Mockito.doReturn(onlineServers).when(
286           regionServerTracker).getOnlineServers();
287       }
288 
289       @Override
290       public ClusterConnection getConnection() {
291         // Insert a mock for the connection, use TESTUTIL.getConfiguration rather than
292         // the conf from the master; the conf will already have an HConnection
293         // associate so the below mocking of a connection will fail.
294         try {
295           return HConnectionTestingUtility.getMockedConnectionAndDecorate(
296             TESTUTIL.getConfiguration(), rs0, rs0, rs0.getServerName(),
297             HRegionInfo.FIRST_META_REGIONINFO);
298         } catch (IOException e) {
299           return null;
300         }
301       }
302 
303       @Override
304       void initNamespace() {
305       }
306     };
307     master.start();
308 
309     try {
310       // Wait till master is initialized.
311       while (!master.isInitialized()) Threads.sleep(10);
312       LOG.info("Master is initialized");
313 
314       assertFalse("The dead server should not be pulled in",
315         master.serverManager.isServerOnline(deadServer));
316     } finally {
317       master.stopMaster();
318       master.join();
319     }
320   }
321 }