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.client;
19  
20  import static org.junit.Assert.fail;
21  import static org.mockito.Mockito.mock;
22  import static org.mockito.Mockito.when;
23  
24  import java.io.IOException;
25  import java.util.ArrayList;
26  
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.hbase.HBaseConfiguration;
29  import org.apache.hadoop.hbase.HBaseTestingUtility;
30  import org.apache.hadoop.hbase.HConstants;
31  import org.apache.hadoop.hbase.HTableDescriptor;
32  import org.apache.hadoop.hbase.testclassification.SmallTests;
33  import org.apache.hadoop.hbase.MasterNotRunningException;
34  import org.apache.hadoop.hbase.PleaseHoldException;
35  import org.apache.hadoop.hbase.TableName;
36  import org.apache.hadoop.hbase.ZooKeeperConnectionException;
37  import org.apache.hadoop.hbase.ipc.PayloadCarryingRpcController;
38  import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
39  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.BalanceRequest;
40  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.CreateTableRequest;
41  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.DispatchMergingRegionsRequest;
42  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.EnableCatalogJanitorRequest;
43  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableDescriptorsRequest;
44  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest;
45  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsCatalogJanitorEnabledRequest;
46  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.MoveRegionRequest;
47  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.OfflineRegionRequest;
48  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.RunCatalogScanRequest;
49  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SetBalancerRunningRequest;
50  import org.junit.Ignore;
51  import org.junit.Test;
52  import org.junit.experimental.categories.Category;
53  import org.mockito.Matchers;
54  import org.mockito.Mockito;
55  import org.mockito.invocation.InvocationOnMock;
56  import org.mockito.stubbing.Answer;
57  import org.mortbay.log.Log;
58  
59  import com.google.protobuf.RpcController;
60  import com.google.protobuf.ServiceException;
61  
62  @Category(SmallTests.class)
63  public class TestHBaseAdminNoCluster {
64    /**
65     * Verify that PleaseHoldException gets retried.
66     * HBASE-8764
67     * @throws IOException
68     * @throws ZooKeeperConnectionException
69     * @throws MasterNotRunningException
70     * @throws ServiceException
71     */
72    //TODO: Clean up, with Procedure V2 and nonce to prevent the same procedure to call mulitple
73    // time, this test is invalid anymore. Just keep the test around for some time before
74    // fully removing it.
75    @Ignore
76    @Test
77    public void testMasterMonitorCallableRetries()
78    throws MasterNotRunningException, ZooKeeperConnectionException, IOException, ServiceException {
79      Configuration configuration = HBaseConfiguration.create();
80      // Set the pause and retry count way down.
81      configuration.setLong(HConstants.HBASE_CLIENT_PAUSE, 1);
82      final int count = 10;
83      configuration.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, count);
84      // Get mocked connection.   Getting the connection will register it so when HBaseAdmin is
85      // constructed with same configuration, it will find this mocked connection.
86      ClusterConnection connection = HConnectionTestingUtility.getMockedConnection(configuration);
87      // Mock so we get back the master interface.  Make it so when createTable is called, we throw
88      // the PleaseHoldException.
89      MasterKeepAliveConnection masterAdmin = Mockito.mock(MasterKeepAliveConnection.class);
90      Mockito.when(masterAdmin.createTable((RpcController)Mockito.any(),
91        (CreateTableRequest)Mockito.any())).
92          thenThrow(new ServiceException("Test fail").initCause(new PleaseHoldException("test")));
93      Mockito.when(connection.getKeepAliveMasterService()).thenReturn(masterAdmin);
94      RpcControllerFactory rpcControllerFactory = Mockito.mock(RpcControllerFactory.class);
95      Mockito.when(connection.getRpcControllerFactory()).thenReturn(rpcControllerFactory);
96      Mockito.when(rpcControllerFactory.newController()).thenReturn(
97          Mockito.mock(PayloadCarryingRpcController.class));
98  
99      // we need a real retrying caller
100     RpcRetryingCallerFactory callerFactory = new RpcRetryingCallerFactory(configuration);
101     Mockito.when(connection.getRpcRetryingCallerFactory()).thenReturn(callerFactory);
102     Admin admin = new HBaseAdmin(connection);
103     try {
104       HTableDescriptor htd =
105         new HTableDescriptor(TableName.valueOf("testMasterMonitorCollableRetries"));
106       // Pass any old htable descriptor; not important
107       try {
108         admin.createTable(htd, HBaseTestingUtility.KEYS_FOR_HBA_CREATE_TABLE);
109         fail();
110       } catch (RetriesExhaustedException e) {
111         Log.info("Expected fail", e);
112       }
113       // Assert we were called 'count' times.
114       Mockito.verify(masterAdmin, Mockito.atLeast(count)).createTable((RpcController)Mockito.any(),
115         (CreateTableRequest)Mockito.any());
116     } finally {
117       admin.close();
118       if (connection != null) connection.close();
119     }
120   }
121 
122   @Test
123   public void testMasterOperationsRetries() throws Exception {
124 
125     // Admin.listTables()
126     testMasterOperationIsRetried(new MethodCaller() {
127       @Override
128       public void call(Admin admin) throws Exception {
129         admin.listTables();
130       }
131       @Override
132       public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception {
133         Mockito.verify(masterAdmin, Mockito.atLeast(count))
134           .getTableDescriptors((RpcController)Mockito.any(),
135             (GetTableDescriptorsRequest)Mockito.any());
136       }
137     });
138 
139     // Admin.listTableNames()
140     testMasterOperationIsRetried(new MethodCaller() {
141       @Override
142       public void call(Admin admin) throws Exception {
143         admin.listTableNames();
144       }
145       @Override
146       public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception {
147         Mockito.verify(masterAdmin, Mockito.atLeast(count))
148           .getTableNames((RpcController)Mockito.any(),
149             (GetTableNamesRequest)Mockito.any());
150       }
151     });
152 
153     // Admin.getTableDescriptor()
154     testMasterOperationIsRetried(new MethodCaller() {
155       @Override
156       public void call(Admin admin) throws Exception {
157         admin.getTableDescriptor(TableName.valueOf("getTableDescriptor"));
158       }
159       @Override
160       public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception {
161         Mockito.verify(masterAdmin, Mockito.atLeast(count))
162           .getTableDescriptors((RpcController)Mockito.any(),
163             (GetTableDescriptorsRequest)Mockito.any());
164       }
165     });
166 
167     // Admin.getTableDescriptorsByTableName()
168     testMasterOperationIsRetried(new MethodCaller() {
169       @Override
170       public void call(Admin admin) throws Exception {
171         admin.getTableDescriptorsByTableName(new ArrayList<TableName>());
172       }
173       @Override
174       public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception {
175         Mockito.verify(masterAdmin, Mockito.atLeast(count))
176           .getTableDescriptors((RpcController)Mockito.any(),
177             (GetTableDescriptorsRequest)Mockito.any());
178       }
179     });
180 
181     // Admin.move()
182     testMasterOperationIsRetried(new MethodCaller() {
183       @Override
184       public void call(Admin admin) throws Exception {
185         admin.move(new byte[0], null);
186       }
187       @Override
188       public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception {
189         Mockito.verify(masterAdmin, Mockito.atLeast(count))
190           .moveRegion((RpcController)Mockito.any(),
191             (MoveRegionRequest)Mockito.any());
192       }
193     });
194 
195     // Admin.offline()
196     testMasterOperationIsRetried(new MethodCaller() {
197       @Override
198       public void call(Admin admin) throws Exception {
199         admin.offline(new byte[0]);
200       }
201       @Override
202       public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception {
203         Mockito.verify(masterAdmin, Mockito.atLeast(count))
204           .offlineRegion((RpcController)Mockito.any(),
205             (OfflineRegionRequest)Mockito.any());
206       }
207     });
208 
209     // Admin.setBalancerRunning()
210     testMasterOperationIsRetried(new MethodCaller() {
211       @Override
212       public void call(Admin admin) throws Exception {
213         admin.setBalancerRunning(true, true);
214       }
215       @Override
216       public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception {
217         Mockito.verify(masterAdmin, Mockito.atLeast(count))
218           .setBalancerRunning((RpcController)Mockito.any(),
219             (SetBalancerRunningRequest)Mockito.any());
220       }
221     });
222 
223     // Admin.balancer()
224     testMasterOperationIsRetried(new MethodCaller() {
225       @Override
226       public void call(Admin admin) throws Exception {
227         admin.balancer();
228       }
229       @Override
230       public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception {
231         Mockito.verify(masterAdmin, Mockito.atLeast(count))
232           .balance((RpcController)Mockito.any(),
233             (BalanceRequest)Mockito.any());
234       }
235     });
236 
237     // Admin.enabledCatalogJanitor()
238     testMasterOperationIsRetried(new MethodCaller() {
239       @Override
240       public void call(Admin admin) throws Exception {
241         admin.enableCatalogJanitor(true);
242       }
243       @Override
244       public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception {
245         Mockito.verify(masterAdmin, Mockito.atLeast(count))
246           .enableCatalogJanitor((RpcController)Mockito.any(),
247             (EnableCatalogJanitorRequest)Mockito.any());
248       }
249     });
250 
251     // Admin.runCatalogScan()
252     testMasterOperationIsRetried(new MethodCaller() {
253       @Override
254       public void call(Admin admin) throws Exception {
255         admin.runCatalogScan();
256       }
257       @Override
258       public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception {
259         Mockito.verify(masterAdmin, Mockito.atLeast(count))
260           .runCatalogScan((RpcController)Mockito.any(),
261             (RunCatalogScanRequest)Mockito.any());
262       }
263     });
264 
265     // Admin.isCatalogJanitorEnabled()
266     testMasterOperationIsRetried(new MethodCaller() {
267       @Override
268       public void call(Admin admin) throws Exception {
269         admin.isCatalogJanitorEnabled();
270       }
271       @Override
272       public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception {
273         Mockito.verify(masterAdmin, Mockito.atLeast(count))
274           .isCatalogJanitorEnabled((RpcController)Mockito.any(),
275             (IsCatalogJanitorEnabledRequest)Mockito.any());
276       }
277     });
278     // Admin.mergeRegions()
279     testMasterOperationIsRetried(new MethodCaller() {
280       @Override
281       public void call(Admin admin) throws Exception {
282         admin.mergeRegions(new byte[0], new byte[0], true);
283       }
284       @Override
285       public void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception {
286         Mockito.verify(masterAdmin, Mockito.atLeast(count))
287           .dispatchMergingRegions((RpcController)Mockito.any(),
288             (DispatchMergingRegionsRequest)Mockito.any());
289       }
290     });
291   }
292 
293   private static interface MethodCaller {
294     void call(Admin admin) throws Exception;
295     void verify(MasterKeepAliveConnection masterAdmin, int count) throws Exception;
296   }
297 
298   private void testMasterOperationIsRetried(MethodCaller caller) throws Exception {
299     Configuration configuration = HBaseConfiguration.create();
300     // Set the pause and retry count way down.
301     configuration.setLong(HConstants.HBASE_CLIENT_PAUSE, 1);
302     final int count = 10;
303     configuration.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, count);
304 
305     ClusterConnection connection = mock(ClusterConnection.class);
306     when(connection.getConfiguration()).thenReturn(configuration);
307     MasterKeepAliveConnection masterAdmin =
308         Mockito.mock(MasterKeepAliveConnection.class, new Answer() {
309           @Override
310           public Object answer(InvocationOnMock invocation) throws Throwable {
311             if (invocation.getMethod().getName().equals("close")) {
312               return null;
313             }
314             throw new MasterNotRunningException(); // all methods will throw an exception
315           }
316         });
317     Mockito.when(connection.getKeepAliveMasterService()).thenReturn(masterAdmin);
318     RpcControllerFactory rpcControllerFactory = Mockito.mock(RpcControllerFactory.class);
319     Mockito.when(connection.getRpcControllerFactory()).thenReturn(rpcControllerFactory);
320     Mockito.when(rpcControllerFactory.newController()).thenReturn(
321       Mockito.mock(PayloadCarryingRpcController.class));
322 
323     // we need a real retrying caller
324     RpcRetryingCallerFactory callerFactory = new RpcRetryingCallerFactory(configuration);
325     Mockito.when(connection.getRpcRetryingCallerFactory()).thenReturn(callerFactory);
326 
327     Admin admin = null;
328     try {
329       admin = Mockito.spy(new HBaseAdmin(connection));
330       // mock the call to getRegion since in the absence of a cluster (which means the meta
331       // is not assigned), getRegion can't function
332       Mockito.doReturn(null).when(((HBaseAdmin)admin)).getRegion(Matchers.<byte[]>any());
333       try {
334         caller.call(admin); // invoke the HBaseAdmin method
335         fail();
336       } catch (RetriesExhaustedException e) {
337         Log.info("Expected fail", e);
338       }
339       // Assert we were called 'count' times.
340       caller.verify(masterAdmin, count);
341     } finally {
342       if (admin != null) {admin.close();}
343     }
344   }
345 }