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