001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertNull;
022import static org.junit.Assert.assertTrue;
023
024import java.io.IOException;
025import org.apache.hadoop.hbase.master.RegionState;
026import org.apache.hadoop.hbase.testclassification.MediumTests;
027import org.apache.hadoop.hbase.testclassification.MiscTests;
028import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
029import org.apache.hadoop.hbase.util.Threads;
030import org.apache.hadoop.hbase.zookeeper.MetaTableLocator;
031import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
032import org.apache.zookeeper.KeeperException;
033import org.junit.After;
034import org.junit.AfterClass;
035import org.junit.Before;
036import org.junit.BeforeClass;
037import org.junit.ClassRule;
038import org.junit.Test;
039import org.junit.experimental.categories.Category;
040import org.mockito.Mockito;
041import org.slf4j.Logger;
042import org.slf4j.LoggerFactory;
043
044import org.apache.hbase.thirdparty.com.google.protobuf.RpcController;
045import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException;
046
047import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos;
048import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.GetRequest;
049import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.GetResponse;
050
051/**
052 * Test {@link org.apache.hadoop.hbase.zookeeper.MetaTableLocator}
053 */
054@Category({ MiscTests.class, MediumTests.class })
055public class TestMetaTableLocator {
056
057  @ClassRule
058  public static final HBaseClassTestRule CLASS_RULE =
059    HBaseClassTestRule.forClass(TestMetaTableLocator.class);
060
061  private static final Logger LOG = LoggerFactory.getLogger(TestMetaTableLocator.class);
062  private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
063  private static final ServerName SN =
064    ServerName.valueOf("example.org", 1234, EnvironmentEdgeManager.currentTime());
065  private ZKWatcher watcher;
066  private Abortable abortable;
067
068  @BeforeClass
069  public static void beforeClass() throws Exception {
070    // Set this down so tests run quicker
071    UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 3);
072    UTIL.startMiniZKCluster();
073  }
074
075  @AfterClass
076  public static void afterClass() throws IOException {
077    UTIL.getZkCluster().shutdown();
078  }
079
080  @Before
081  public void before() throws IOException {
082    this.abortable = new Abortable() {
083      @Override
084      public void abort(String why, Throwable e) {
085        LOG.info(why, e);
086      }
087
088      @Override
089      public boolean isAborted() {
090        return false;
091      }
092    };
093    this.watcher =
094      new ZKWatcher(UTIL.getConfiguration(), this.getClass().getSimpleName(), this.abortable, true);
095  }
096
097  @After
098  public void after() {
099    try {
100      // Clean out meta location or later tests will be confused... they presume
101      // start fresh in zk.
102      MetaTableLocator.deleteMetaLocation(this.watcher);
103    } catch (KeeperException e) {
104      LOG.warn("Unable to delete hbase:meta location", e);
105    }
106
107    this.watcher.close();
108  }
109
110  /**
111   * Test normal operations
112   */
113  @Test
114  public void testMetaLookup()
115    throws IOException, InterruptedException, ServiceException, KeeperException {
116    final ClientProtos.ClientService.BlockingInterface client =
117      Mockito.mock(ClientProtos.ClientService.BlockingInterface.class);
118
119    Mockito.when(client.get((RpcController) Mockito.any(), (GetRequest) Mockito.any()))
120      .thenReturn(GetResponse.newBuilder().build());
121
122    assertNull(MetaTableLocator.getMetaRegionLocation(this.watcher));
123    for (RegionState.State state : RegionState.State.values()) {
124      if (state.equals(RegionState.State.OPEN)) {
125        continue;
126      }
127      MetaTableLocator.setMetaLocation(this.watcher, SN, state);
128      assertNull(MetaTableLocator.getMetaRegionLocation(this.watcher));
129      assertEquals(state, MetaTableLocator.getMetaRegionState(this.watcher).getState());
130    }
131    MetaTableLocator.setMetaLocation(this.watcher, SN, RegionState.State.OPEN);
132    assertEquals(SN, MetaTableLocator.getMetaRegionLocation(this.watcher));
133    assertEquals(RegionState.State.OPEN,
134      MetaTableLocator.getMetaRegionState(this.watcher).getState());
135
136    MetaTableLocator.deleteMetaLocation(this.watcher);
137    assertNull(MetaTableLocator.getMetaRegionState(this.watcher).getServerName());
138    assertEquals(RegionState.State.OFFLINE,
139      MetaTableLocator.getMetaRegionState(this.watcher).getState());
140    assertNull(MetaTableLocator.getMetaRegionLocation(this.watcher));
141  }
142
143  @Test(expected = NotAllMetaRegionsOnlineException.class)
144  public void testTimeoutWaitForMeta() throws IOException, InterruptedException {
145    MetaTableLocator.waitMetaRegionLocation(watcher, 100);
146  }
147
148  /**
149   * Test waiting on meat w/ no timeout specified.
150   */
151  @Test
152  public void testNoTimeoutWaitForMeta() throws IOException, InterruptedException, KeeperException {
153    ServerName hsa = MetaTableLocator.getMetaRegionLocation(watcher);
154    assertNull(hsa);
155
156    // Now test waiting on meta location getting set.
157    Thread t = new WaitOnMetaThread();
158    startWaitAliveThenWaitItLives(t, 1);
159    // Set a meta location.
160    MetaTableLocator.setMetaLocation(this.watcher, SN, RegionState.State.OPEN);
161    hsa = SN;
162    // Join the thread... should exit shortly.
163    t.join();
164    // Now meta is available.
165    assertTrue(MetaTableLocator.getMetaRegionLocation(watcher).equals(hsa));
166  }
167
168  private void startWaitAliveThenWaitItLives(final Thread t, final int ms) {
169    t.start();
170    UTIL.waitFor(2000, t::isAlive);
171    // Wait one second.
172    Threads.sleep(ms);
173    assertTrue("Assert " + t.getName() + " still waiting", t.isAlive());
174  }
175
176  /**
177   * Wait on META.
178   */
179  class WaitOnMetaThread extends Thread {
180
181    WaitOnMetaThread() {
182      super("WaitOnMeta");
183    }
184
185    @Override
186    public void run() {
187      try {
188        doWaiting();
189      } catch (InterruptedException e) {
190        throw new RuntimeException("Failed wait", e);
191      }
192      LOG.info("Exiting " + getName());
193    }
194
195    void doWaiting() throws InterruptedException {
196      try {
197        for (;;) {
198          if (MetaTableLocator.waitMetaRegionLocation(watcher, 10000) != null) {
199            break;
200          }
201        }
202      } catch (NotAllMetaRegionsOnlineException e) {
203        // Ignore
204      }
205    }
206  }
207}