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.assertTrue;
21  import static org.junit.Assert.fail;
22  
23  import java.io.IOException;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.hbase.HBaseConfiguration;
29  import org.apache.hadoop.hbase.HConstants;
30  import org.apache.hadoop.hbase.testclassification.SmallTests;
31  import org.apache.hadoop.hbase.TableName;
32  import org.apache.hadoop.hbase.ipc.PayloadCarryingRpcController;
33  import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
34  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
35  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsSnapshotDoneRequest;
36  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.IsSnapshotDoneResponse;
37  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SnapshotRequest;
38  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.SnapshotResponse;
39  import org.junit.Test;
40  import org.junit.experimental.categories.Category;
41  import org.mockito.Mockito;
42  
43  import com.google.protobuf.RpcController;
44  
45  /**
46   * Test snapshot logic from the client
47   */
48  @Category(SmallTests.class)
49  public class TestSnapshotFromAdmin {
50  
51    private static final Log LOG = LogFactory.getLog(TestSnapshotFromAdmin.class);
52  
53    /**
54     * Test that the logic for doing 'correct' back-off based on exponential increase and the max-time
55     * passed from the server ensures the correct overall waiting for the snapshot to finish.
56     * @throws Exception
57     */
58    @Test(timeout = 60000)
59    public void testBackoffLogic() throws Exception {
60      final int pauseTime = 100;
61      final int maxWaitTime =
62        HConstants.RETRY_BACKOFF[HConstants.RETRY_BACKOFF.length - 1] * pauseTime;
63      final int numRetries = HConstants.RETRY_BACKOFF.length;
64      // calculate the wait time, if we just do straight backoff (ignoring the expected time from
65      // master)
66      long ignoreExpectedTime = 0;
67      for (int i = 0; i < HConstants.RETRY_BACKOFF.length; i++) {
68        ignoreExpectedTime += HConstants.RETRY_BACKOFF[i] * pauseTime;
69      }
70      // the correct wait time, capping at the maxTime/tries + fudge room
71      final long time = pauseTime * 3 + ((maxWaitTime / numRetries) * 3) + 300;
72      assertTrue("Capped snapshot wait time isn't less that the uncapped backoff time "
73          + "- further testing won't prove anything.", time < ignoreExpectedTime);
74  
75      // setup the mocks
76      ConnectionManager.HConnectionImplementation mockConnection = Mockito
77          .mock(ConnectionManager.HConnectionImplementation.class);
78      Configuration conf = HBaseConfiguration.create();
79      // setup the conf to match the expected properties
80      conf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, numRetries);
81      conf.setLong("hbase.client.pause", pauseTime);
82  
83      // mock the master admin to our mock
84      MasterKeepAliveConnection mockMaster = Mockito.mock(MasterKeepAliveConnection.class);
85      Mockito.when(mockConnection.getConfiguration()).thenReturn(conf);
86      Mockito.when(mockConnection.getKeepAliveMasterService()).thenReturn(mockMaster);
87      // we need a real retrying caller
88      RpcRetryingCallerFactory callerFactory = new RpcRetryingCallerFactory(conf);
89      RpcControllerFactory controllerFactory = Mockito.mock(RpcControllerFactory.class);
90      Mockito.when(controllerFactory.newController()).thenReturn(
91        Mockito.mock(PayloadCarryingRpcController.class));
92      Mockito.when(mockConnection.getRpcRetryingCallerFactory()).thenReturn(callerFactory);
93      Mockito.when(mockConnection.getRpcControllerFactory()).thenReturn(controllerFactory);
94      // set the max wait time for the snapshot to complete
95      SnapshotResponse response = SnapshotResponse.newBuilder()
96          .setExpectedTimeout(maxWaitTime)
97          .build();
98      Mockito
99      .when(
100       mockMaster.snapshot((RpcController) Mockito.any(),
101         Mockito.any(SnapshotRequest.class))).thenReturn(response);
102     // setup the response
103     IsSnapshotDoneResponse.Builder builder = IsSnapshotDoneResponse.newBuilder();
104     builder.setDone(false);
105     // first five times, we return false, last we get success
106     Mockito.when(
107       mockMaster.isSnapshotDone((RpcController) Mockito.any(),
108         Mockito.any(IsSnapshotDoneRequest.class))).thenReturn(builder.build(), builder.build(),
109           builder.build(), builder.build(), builder.build(), builder.setDone(true).build());
110 
111     // setup the admin and run the test
112     Admin admin = new HBaseAdmin(mockConnection);
113     String snapshot = "snapshot";
114     TableName table = TableName.valueOf("table");
115     // get start time
116     long start = System.currentTimeMillis();
117     admin.snapshot(snapshot, table);
118     long finish = System.currentTimeMillis();
119     long elapsed = (finish - start);
120     assertTrue("Elapsed time:" + elapsed + " is more than expected max:" + time, elapsed <= time);
121     admin.close();
122   }
123 
124   /**
125    * Make sure that we validate the snapshot name and the table name before we pass anything across
126    * the wire
127    * @throws Exception on failure
128    */
129   @Test
130   public void testValidateSnapshotName() throws Exception {
131     ConnectionManager.HConnectionImplementation mockConnection = Mockito
132         .mock(ConnectionManager.HConnectionImplementation.class);
133     Configuration conf = HBaseConfiguration.create();
134     Mockito.when(mockConnection.getConfiguration()).thenReturn(conf);
135     // we need a real retrying caller
136     RpcRetryingCallerFactory callerFactory = new RpcRetryingCallerFactory(conf);
137     RpcControllerFactory controllerFactory = Mockito.mock(RpcControllerFactory.class);
138     Mockito.when(controllerFactory.newController()).thenReturn(
139       Mockito.mock(PayloadCarryingRpcController.class));
140     Mockito.when(mockConnection.getRpcRetryingCallerFactory()).thenReturn(callerFactory);
141     Mockito.when(mockConnection.getRpcControllerFactory()).thenReturn(controllerFactory);
142     Admin admin = new HBaseAdmin(mockConnection);
143     SnapshotDescription.Builder builder = SnapshotDescription.newBuilder();
144     // check that invalid snapshot names fail
145     failSnapshotStart(admin, builder.setName(HConstants.SNAPSHOT_DIR_NAME).build());
146     failSnapshotStart(admin, builder.setName("-snapshot").build());
147     failSnapshotStart(admin, builder.setName("snapshot fails").build());
148     failSnapshotStart(admin, builder.setName("snap$hot").build());
149     failSnapshotStart(admin, builder.setName("snap:hot").build());
150     // check the table name also get verified
151     failSnapshotStart(admin, builder.setName("snapshot").setTable(".table").build());
152     failSnapshotStart(admin, builder.setName("snapshot").setTable("-table").build());
153     failSnapshotStart(admin, builder.setName("snapshot").setTable("table fails").build());
154     failSnapshotStart(admin, builder.setName("snapshot").setTable("tab%le").build());
155 
156     // mock the master connection
157     MasterKeepAliveConnection master = Mockito.mock(MasterKeepAliveConnection.class);
158     Mockito.when(mockConnection.getKeepAliveMasterService()).thenReturn(master);
159     SnapshotResponse response = SnapshotResponse.newBuilder().setExpectedTimeout(0).build();
160     Mockito.when(
161       master.snapshot((RpcController) Mockito.any(), Mockito.any(SnapshotRequest.class)))
162         .thenReturn(response);
163     IsSnapshotDoneResponse doneResponse = IsSnapshotDoneResponse.newBuilder().setDone(true).build();
164     Mockito.when(
165       master.isSnapshotDone((RpcController) Mockito.any(),
166           Mockito.any(IsSnapshotDoneRequest.class))).thenReturn(doneResponse);
167 
168       // make sure that we can use valid names
169     admin.snapshot(builder.setName("snapshot").setTable("table").build());
170   }
171 
172   private void failSnapshotStart(Admin admin, SnapshotDescription snapshot) throws IOException {
173     try {
174       admin.snapshot(snapshot);
175       fail("Snapshot should not have succeed with name:" + snapshot.getName());
176     } catch (IllegalArgumentException e) {
177       LOG.debug("Correctly failed to start snapshot:" + e.getMessage());
178     }
179   }
180 }