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.assertTrue;
21  
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.List;
25  import java.util.NavigableMap;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.hadoop.hbase.Abortable;
30  import org.apache.hadoop.hbase.HBaseTestingUtility;
31  import org.apache.hadoop.hbase.HConstants;
32  import org.apache.hadoop.hbase.HRegionInfo;
33  import org.apache.hadoop.hbase.HRegionLocation;
34  import org.apache.hadoop.hbase.KeyValue;
35  import org.apache.hadoop.hbase.ServerName;
36  import org.apache.hadoop.hbase.client.HConnection;
37  import org.apache.hadoop.hbase.client.HConnectionManager;
38  import org.apache.hadoop.hbase.client.HConnectionTestingUtility;
39  import org.apache.hadoop.hbase.client.Result;
40  import org.apache.hadoop.hbase.client.Scan;
41  import org.apache.hadoop.hbase.ipc.HRegionInterface;
42  import org.apache.hadoop.hbase.util.Bytes;
43  import org.apache.hadoop.hbase.util.Writables;
44  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
45  import org.junit.After;
46  import org.junit.Before;
47  import org.junit.Test;
48  import org.mockito.Mockito;
49  
50  /**
51   * Test MetaReader/Editor but without spinning up a cluster.
52   * We mock regionserver back and forth (we do spin up a zk cluster).
53   */
54  public class TestMetaReaderEditorNoCluster {
55    private static final Log LOG = LogFactory.getLog(TestMetaReaderEditorNoCluster.class);
56    private static final  HBaseTestingUtility UTIL = new HBaseTestingUtility();
57    private static final Abortable ABORTABLE = new Abortable() {
58      boolean aborted = false;
59      @Override
60      public void abort(String why, Throwable e) {
61        LOG.info(why, e);
62        this.aborted = true;
63        throw new RuntimeException(e);
64      }
65      @Override
66      public boolean isAborted()  {
67        return this.aborted;
68      }
69    };
70  
71    @Before
72    public void before() throws Exception {
73      UTIL.startMiniZKCluster();
74    }
75  
76    @After
77    public void after() throws IOException {
78      UTIL.shutdownMiniZKCluster();
79    }
80  
81    /**
82     * Test that MetaReader will ride over server throwing
83     * "Server not running" IOEs.
84     * @see https://issues.apache.org/jira/browse/HBASE-3446
85     * @throws IOException 
86     * @throws InterruptedException 
87     */
88    @Test
89    public void testRideOverServerNotRunning() throws IOException, InterruptedException {
90      // Need a zk watcher.
91      ZooKeeperWatcher zkw = new ZooKeeperWatcher(UTIL.getConfiguration(),
92        this.getClass().getSimpleName(), ABORTABLE, true);
93      // This is a servername we use in a few places below.
94      ServerName sn = new ServerName("example.com", 1234, System.currentTimeMillis());
95  
96      HConnection connection = null;
97      CatalogTracker ct = null;
98      try {
99        // Mock an HRegionInterface. Our mock implementation will fail a few
100       // times when we go to open a scanner.
101       final HRegionInterface implementation = Mockito.mock(HRegionInterface.class);
102       // When openScanner called throw IOE 'Server not running' a few times
103       // before we return a scanner id.  Whats WEIRD is that these
104       // exceptions do not show in the log because they are caught and only
105       // printed if we FAIL.  We eventually succeed after retry so these don't
106       // show.  We will know if they happened or not because we will ask
107       // mockito at the end of this test to verify that openscanner was indeed
108       // called the wanted number of times.
109       final long scannerid = 123L;
110       Mockito.when(implementation.openScanner((byte [])Mockito.any(),
111           (Scan)Mockito.any())).
112         thenThrow(new IOException("Server not running (1 of 3)")).
113         thenThrow(new IOException("Server not running (2 of 3)")).
114         thenThrow(new IOException("Server not running (3 of 3)")).
115         thenReturn(scannerid);
116       // Make it so a verifiable answer comes back when next is called.  Return
117       // the verifiable answer and then a null so we stop scanning.  Our
118       // verifiable answer is something that looks like a row in META with
119       // a server and startcode that is that of the above defined servername.
120       List<KeyValue> kvs = new ArrayList<KeyValue>();
121       final byte [] rowToVerify = Bytes.toBytes("rowToVerify");
122       kvs.add(new KeyValue(rowToVerify,
123         HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER,
124         Writables.getBytes(HRegionInfo.FIRST_META_REGIONINFO)));
125       kvs.add(new KeyValue(rowToVerify,
126         HConstants.CATALOG_FAMILY, HConstants.SERVER_QUALIFIER,
127         Bytes.toBytes(sn.getHostAndPort())));
128       kvs.add(new KeyValue(rowToVerify,
129         HConstants.CATALOG_FAMILY, HConstants.STARTCODE_QUALIFIER,
130         Bytes.toBytes(sn.getStartcode())));
131       final Result [] result = new Result [] {new Result(kvs)};
132       Mockito.when(implementation.next(Mockito.anyLong(), Mockito.anyInt())).
133         thenReturn(result).
134         thenReturn(null);
135 
136       // Associate a spied-upon HConnection with UTIL.getConfiguration.  Need
137       // to shove this in here first so it gets picked up all over; e.g. by
138       // HTable.
139       connection = HConnectionTestingUtility.getSpiedConnection(UTIL.getConfiguration());
140       // Fix the location lookup so it 'works' though no network.  First
141       // make an 'any location' object.
142       final HRegionLocation anyLocation =
143         new HRegionLocation(HRegionInfo.FIRST_META_REGIONINFO, sn.getHostname(),
144           sn.getPort());
145       // Return the any location object when locateRegion is called in HTable
146       // constructor and when its called by ServerCallable (it uses getRegionLocation).
147       // The ugly format below comes of 'Important gotcha on spying real objects!' from
148       // http://mockito.googlecode.com/svn/branches/1.6/javadoc/org/mockito/Mockito.html
149       Mockito.doReturn(anyLocation).
150         when(connection).locateRegion((byte[]) Mockito.any(), (byte[]) Mockito.any());
151       Mockito.doReturn(anyLocation).
152         when(connection).getRegionLocation((byte[]) Mockito.any(),
153           (byte[]) Mockito.any(), Mockito.anyBoolean());
154 
155       // Now shove our HRI implementation into the spied-upon connection.
156       Mockito.doReturn(implementation).
157         when(connection).getHRegionConnection(Mockito.anyString(), Mockito.anyInt());
158 
159       // Now start up the catalogtracker with our doctored Connection.
160       ct = new CatalogTracker(zkw, null, connection, ABORTABLE, 0);
161       ct.start();
162       // Scan meta for user tables and verify we got back expected answer.
163       NavigableMap<HRegionInfo, Result> hris = MetaReader.getServerUserRegions(ct, sn);
164       assertTrue(hris.size() == 1);
165       assertTrue(hris.firstEntry().getKey().equals(HRegionInfo.FIRST_META_REGIONINFO));
166       assertTrue(Bytes.equals(rowToVerify, hris.firstEntry().getValue().getRow()));
167       // Finally verify that openscanner was called four times -- three times
168       // with exception and then on 4th attempt we succeed.
169       Mockito.verify(implementation, Mockito.times(4)).
170         openScanner((byte [])Mockito.any(), (Scan)Mockito.any());
171     } finally {
172       if (ct != null) ct.stop();
173       HConnectionManager.deleteConnection(UTIL.getConfiguration(), true);
174       zkw.close();
175     }
176   }
177 }