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