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;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertNotNull;
22  import static org.junit.Assert.assertNull;
23  import static org.junit.Assert.assertTrue;
24  
25  import java.io.IOException;
26  import java.util.ArrayList;
27  import java.util.List;
28  import java.util.NavigableMap;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.hadoop.hbase.client.ClusterConnection;
33  import org.apache.hadoop.hbase.client.HConnectionTestingUtility;
34  import org.apache.hadoop.hbase.client.Result;
35  import org.apache.hadoop.hbase.ipc.PayloadCarryingRpcController;
36  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
37  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ScanRequest;
38  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.ScanResponse;
39  import org.apache.hadoop.hbase.testclassification.MediumTests;
40  import org.apache.hadoop.hbase.util.Bytes;
41  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
42  import org.junit.After;
43  import org.junit.Before;
44  import org.junit.Test;
45  import org.junit.experimental.categories.Category;
46  import org.mockito.Mockito;
47  import org.mockito.invocation.InvocationOnMock;
48  import org.mockito.stubbing.Answer;
49  
50  import com.google.protobuf.RpcController;
51  import com.google.protobuf.ServiceException;
52  
53  /**
54   * Test MetaTableAccessor but without spinning up a cluster.
55   * We mock regionserver back and forth (we do spin up a zk cluster).
56   */
57  @Category(MediumTests.class)
58  public class TestMetaTableAccessorNoCluster {
59    private static final Log LOG = LogFactory.getLog(TestMetaTableAccessorNoCluster.class);
60    private static final  HBaseTestingUtility UTIL = new HBaseTestingUtility();
61    private static final Abortable ABORTABLE = new Abortable() {
62      boolean aborted = false;
63      @Override
64      public void abort(String why, Throwable e) {
65        LOG.info(why, e);
66        this.aborted = true;
67        throw new RuntimeException(e);
68      }
69      @Override
70      public boolean isAborted()  {
71        return this.aborted;
72      }
73    };
74  
75    @Before
76    public void before() throws Exception {
77      UTIL.startMiniZKCluster();
78    }
79  
80    @After
81    public void after() throws IOException {
82      UTIL.shutdownMiniZKCluster();
83    }
84  
85    @Test
86    public void testGetHRegionInfo() throws IOException {
87      assertNull(HRegionInfo.getHRegionInfo(new Result()));
88  
89      List<Cell> kvs = new ArrayList<Cell>();
90      Result r = Result.create(kvs);
91      assertNull(HRegionInfo.getHRegionInfo(r));
92  
93      byte [] f = HConstants.CATALOG_FAMILY;
94      // Make a key value that doesn't have the expected qualifier.
95      kvs.add(new KeyValue(HConstants.EMPTY_BYTE_ARRAY, f,
96        HConstants.SERVER_QUALIFIER, f));
97      r = Result.create(kvs);
98      assertNull(HRegionInfo.getHRegionInfo(r));
99      // Make a key that does not have a regioninfo value.
100     kvs.add(new KeyValue(HConstants.EMPTY_BYTE_ARRAY, f,
101       HConstants.REGIONINFO_QUALIFIER, f));
102     HRegionInfo hri = HRegionInfo.getHRegionInfo(Result.create(kvs));
103     assertTrue(hri == null);
104     // OK, give it what it expects
105     kvs.clear();
106     kvs.add(new KeyValue(HConstants.EMPTY_BYTE_ARRAY, f,
107       HConstants.REGIONINFO_QUALIFIER,
108       HRegionInfo.FIRST_META_REGIONINFO.toByteArray()));
109     hri = HRegionInfo.getHRegionInfo(Result.create(kvs));
110     assertNotNull(hri);
111     assertTrue(hri.equals(HRegionInfo.FIRST_META_REGIONINFO));
112   }
113 
114   /**
115    * Test that MetaTableAccessor will ride over server throwing
116    * "Server not running" IOEs.
117    * @see @link {https://issues.apache.org/jira/browse/HBASE-3446}
118    * @throws IOException
119    * @throws InterruptedException
120    */
121   @Test
122   public void testRideOverServerNotRunning()
123       throws IOException, InterruptedException, ServiceException {
124     // Need a zk watcher.
125     ZooKeeperWatcher zkw = new ZooKeeperWatcher(UTIL.getConfiguration(),
126       this.getClass().getSimpleName(), ABORTABLE, true);
127     // This is a servername we use in a few places below.
128     ServerName sn = ServerName.valueOf("example.com", 1234, System.currentTimeMillis());
129 
130     ClusterConnection connection = null;
131     try {
132       // Mock an ClientProtocol. Our mock implementation will fail a few
133       // times when we go to open a scanner.
134       final ClientProtos.ClientService.BlockingInterface implementation =
135         Mockito.mock(ClientProtos.ClientService.BlockingInterface.class);
136       // When scan called throw IOE 'Server not running' a few times
137       // before we return a scanner id.  Whats WEIRD is that these
138       // exceptions do not show in the log because they are caught and only
139       // printed if we FAIL.  We eventually succeed after retry so these don't
140       // show.  We will know if they happened or not because we will ask
141       // mockito at the end of this test to verify that scan was indeed
142       // called the wanted number of times.
143       List<Cell> kvs = new ArrayList<Cell>();
144       final byte [] rowToVerify = Bytes.toBytes("rowToVerify");
145       kvs.add(new KeyValue(rowToVerify,
146         HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER,
147         HRegionInfo.FIRST_META_REGIONINFO.toByteArray()));
148       kvs.add(new KeyValue(rowToVerify,
149         HConstants.CATALOG_FAMILY, HConstants.SERVER_QUALIFIER,
150         Bytes.toBytes(sn.getHostAndPort())));
151       kvs.add(new KeyValue(rowToVerify,
152         HConstants.CATALOG_FAMILY, HConstants.STARTCODE_QUALIFIER,
153         Bytes.toBytes(sn.getStartcode())));
154       final List<CellScannable> cellScannables = new ArrayList<CellScannable>(1);
155       cellScannables.add(Result.create(kvs));
156       final ScanResponse.Builder builder = ScanResponse.newBuilder();
157       for (CellScannable result : cellScannables) {
158         builder.addCellsPerResult(((Result)result).size());
159       }
160       Mockito.when(implementation.scan((RpcController) Mockito.any(), (ScanRequest) Mockito.any()))
161           .thenThrow(new ServiceException("Server not running (1 of 3)"))
162           .thenThrow(new ServiceException("Server not running (2 of 3)"))
163           .thenThrow(new ServiceException("Server not running (3 of 3)"))
164           .thenReturn(ScanResponse.newBuilder().setScannerId(1234567890L).build())
165           .thenAnswer(new Answer<ScanResponse>() {
166             public ScanResponse answer(InvocationOnMock invocation) throws Throwable {
167               ((PayloadCarryingRpcController) invocation.getArguments()[0]).setCellScanner(CellUtil
168                   .createCellScanner(cellScannables));
169               return builder.build();
170             }
171           }).thenReturn(ScanResponse.newBuilder().setMoreResults(false).build());
172       // Associate a spied-upon HConnection with UTIL.getConfiguration.  Need
173       // to shove this in here first so it gets picked up all over; e.g. by
174       // HTable.
175       connection = HConnectionTestingUtility.getSpiedConnection(UTIL.getConfiguration());
176       
177       // Fix the location lookup so it 'works' though no network.  First
178       // make an 'any location' object.
179       final HRegionLocation anyLocation =
180         new HRegionLocation(HRegionInfo.FIRST_META_REGIONINFO, sn);
181       final RegionLocations rl = new RegionLocations(anyLocation);
182       // Return the RegionLocations object when locateRegion
183       // The ugly format below comes of 'Important gotcha on spying real objects!' from
184       // http://mockito.googlecode.com/svn/branches/1.6/javadoc/org/mockito/Mockito.html
185       ClusterConnection cConnection =
186           HConnectionTestingUtility.getSpiedClusterConnection(UTIL.getConfiguration());
187       Mockito.doReturn(rl).when
188       (cConnection).locateRegion((TableName)Mockito.any(), (byte[])Mockito.any(),
189               Mockito.anyBoolean(), Mockito.anyBoolean(), Mockito.anyInt());
190 
191       // Now shove our HRI implementation into the spied-upon connection.
192       Mockito.doReturn(implementation).
193         when(connection).getClient(Mockito.any(ServerName.class));
194 
195       // Scan meta for user tables and verify we got back expected answer.
196       NavigableMap<HRegionInfo, Result> hris =
197         MetaTableAccessor.getServerUserRegions(connection, sn);
198       assertEquals(1, hris.size());
199       assertTrue(hris.firstEntry().getKey().equals(HRegionInfo.FIRST_META_REGIONINFO));
200       assertTrue(Bytes.equals(rowToVerify, hris.firstEntry().getValue().getRow()));
201       // Finally verify that scan was called four times -- three times
202       // with exception and then on 4th, 5th and 6th attempt we succeed
203       Mockito.verify(implementation, Mockito.times(6)).
204         scan((RpcController)Mockito.any(), (ScanRequest)Mockito.any());
205     } finally {
206       if (connection != null && !connection.isClosed()) connection.close();
207       zkw.close();
208     }
209   }
210 }