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.assertEquals;
21  import static org.junit.Assert.assertNotNull;
22  import static org.junit.Assert.assertTrue;
23  import com.google.common.base.Preconditions;
24  import java.io.IOException;
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.List;
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.hadoop.conf.Configuration;
31  import org.apache.hadoop.hbase.HBaseTestingUtility;
32  import org.apache.hadoop.hbase.HConstants;
33  import org.apache.hadoop.hbase.HRegionLocation;
34  import org.apache.hadoop.hbase.MultithreadedTestUtil;
35  import org.apache.hadoop.hbase.RegionLocations;
36  import org.apache.hadoop.hbase.ServerName;
37  import org.apache.hadoop.hbase.Waiter;
38  import org.apache.hadoop.hbase.master.HMaster;
39  import org.apache.hadoop.hbase.master.MetaRegionLocationCache;
40  import org.apache.hadoop.hbase.master.RegionState;
41  import org.apache.hadoop.hbase.testclassification.MasterTests;
42  import org.apache.hadoop.hbase.testclassification.SmallTests;
43  import org.apache.hadoop.hbase.util.JVMClusterUtil;
44  import org.apache.hadoop.hbase.zookeeper.MetaTableLocator;
45  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
46  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
47  import org.junit.AfterClass;
48  import org.junit.BeforeClass;
49  import org.junit.Test;
50  import org.junit.experimental.categories.Category;
51  
52  @Category({SmallTests.class, MasterTests.class })
53  public class TestMetaRegionLocationCache {
54  
55    private static final Log LOG = LogFactory.getLog(TestMetaRegionLocationCache.class.getName());
56  
57    private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
58    private static ConnectionRegistry REGISTRY;
59  
60    // waits for all replicas to have region location
61    static void waitUntilAllMetaReplicasHavingRegionLocation(Configuration conf,
62                                                             final ConnectionRegistry registry, final int regionReplication) throws IOException {
63      Waiter.waitFor(conf, conf.getLong(
64          "hbase.client.sync.wait.timeout.msec", 60000), 200, true,
65          new Waiter.ExplainingPredicate<IOException>() {
66            @Override
67            public String explainFailure() throws IOException {
68              return "Not all meta replicas get assigned";
69            }
70  
71            @Override
72            public boolean evaluate() throws IOException {
73              try {
74                RegionLocations locs = registry.getMetaRegionLocations();
75                if (locs == null || locs.size() < regionReplication) {
76                  return false;
77                }
78                for (int i = 0; i < regionReplication; i++) {
79                  if (locs.getRegionLocation(i) == null) {
80                    return false;
81                  }
82                }
83                return true;
84              } catch (Exception e) {
85                LOG.warn("Failed to get meta region locations", e);
86                return false;
87              }
88            }
89          });
90    }
91  
92    @BeforeClass
93    public static void setUp() throws Exception {
94      TEST_UTIL.getConfiguration().setInt(HConstants.META_REPLICAS_NUM, 3);
95      TEST_UTIL.startMiniCluster(3);
96      REGISTRY = ConnectionRegistryFactory.getRegistry(TEST_UTIL.getConnection());
97      waitUntilAllMetaReplicasHavingRegionLocation(
98          TEST_UTIL.getConfiguration(), REGISTRY, 3);
99      TEST_UTIL.getConnection().getAdmin().setBalancerRunning(false, true);
100   }
101 
102   @AfterClass
103   public static void cleanUp() throws Exception {
104     TEST_UTIL.shutdownMiniCluster();
105   }
106 
107   private List<HRegionLocation> getCurrentMetaLocations(ZooKeeperWatcher zk) throws Exception {
108     List<HRegionLocation> result = new ArrayList<>();
109     for (String znode: zk.getMetaReplicaNodes()) {
110       String path = ZKUtil.joinZNode(zk.baseZNode, znode);
111       int replicaId = zk.getMetaReplicaIdFromPath(path);
112       RegionState state = MetaTableLocator.getMetaRegionState(zk, replicaId);
113       result.add(new HRegionLocation(state.getRegion(), state.getServerName()));
114     }
115     return result;
116   }
117 
118   // Verifies that the cached meta locations in the given master are in sync with what is in ZK.
119   private void verifyCachedMetaLocations(final HMaster master) throws Exception {
120     // Wait until initial meta locations are loaded.
121     ZooKeeperWatcher zk = master.getZooKeeper();
122     final List<String> metaZnodes = zk.getMetaReplicaNodes();
123     assertEquals(3, metaZnodes.size());
124     TEST_UTIL.waitFor(10000, new Waiter.Predicate<Exception>() {
125       @Override
126       public boolean evaluate() throws Exception {
127         return master.getMetaRegionLocationCache().getMetaRegionLocations().size()
128             == metaZnodes.size();
129       }
130     });
131     List<HRegionLocation> metaHRLs = master.getMetaRegionLocationCache().getMetaRegionLocations();
132     List<HRegionLocation> actualHRLs = getCurrentMetaLocations(zk);
133     Collections.sort(metaHRLs);
134     Collections.sort(actualHRLs);
135     assertEquals(actualHRLs, metaHRLs);
136   }
137 
138   @Test public void testInitialMetaLocations() throws Exception {
139     verifyCachedMetaLocations(TEST_UTIL.getMiniHBaseCluster().getMaster());
140   }
141 
142   @Test public void testStandByMetaLocations() throws Exception {
143     HMaster standBy = TEST_UTIL.getMiniHBaseCluster().startMaster().getMaster();
144     verifyCachedMetaLocations(standBy);
145   }
146 
147   private static ServerName getOtherRS(List<ServerName> allServers, ServerName except) {
148     Preconditions.checkArgument(allServers.size() > 0);
149     allServers.remove(except);
150     ServerName ret;
151     try {
152       Collections.shuffle(allServers);
153       ret = allServers.get(0);
154     } finally {
155       allServers.add(except);
156     }
157     return ret;
158   }
159 
160   /*
161    * Shuffles the meta region replicas around the cluster and makes sure the cache is not stale.
162    */
163   @Test public void testMetaLocationsChange() throws Exception {
164     List<HRegionLocation> currentMetaLocs =
165         getCurrentMetaLocations(TEST_UTIL.getMiniHBaseCluster().getMaster().getZooKeeper());
166     List<ServerName> allServers = new ArrayList<>();
167     for (JVMClusterUtil.RegionServerThread rs:
168         TEST_UTIL.getMiniHBaseCluster().getRegionServerThreads()) {
169       allServers.add(rs.getRegionServer().getServerName());
170     }
171     // Move these replicas to random servers.
172     for (HRegionLocation location: currentMetaLocs) {
173       TEST_UTIL.moveRegionAndWait(
174           location.getRegionInfo(), getOtherRS(allServers, location.getServerName()));
175     }
176     waitUntilAllMetaReplicasHavingRegionLocation(
177         TEST_UTIL.getConfiguration(), REGISTRY, 3);
178     for (JVMClusterUtil.MasterThread masterThread:
179         TEST_UTIL.getMiniHBaseCluster().getMasterThreads()) {
180       verifyCachedMetaLocations(masterThread.getMaster());
181     }
182   }
183 
184   /**
185    * Tests MetaRegionLocationCache's init procedure to make sure that it correctly watches the base
186    * znode for notifications.
187    */
188   @Test public void testMetaRegionLocationCache() throws Exception {
189     final String parentZnodeName = "/randomznodename";
190     Configuration conf = new Configuration(TEST_UTIL.getConfiguration());
191     conf.set(HConstants.ZOOKEEPER_ZNODE_PARENT, parentZnodeName);
192     ServerName sn = ServerName.valueOf("localhost", 1234, 5678);
193     try (ZooKeeperWatcher zkWatcher = new ZooKeeperWatcher(conf, null, null, true)) {
194       // A thread that repeatedly creates and drops an unrelated child znode. This is to simulate
195       // some ZK activity in the background.
196       MultithreadedTestUtil.TestContext ctx = new MultithreadedTestUtil.TestContext(conf);
197       ctx.addThread(new MultithreadedTestUtil.RepeatingTestThread(ctx) {
198         @Override public void doAnAction() throws Exception {
199           final String testZnode = parentZnodeName + "/child";
200           ZKUtil.createNodeIfNotExistsAndWatch(zkWatcher, testZnode, testZnode.getBytes());
201           ZKUtil.deleteNode(zkWatcher, testZnode);
202         }
203       });
204       ctx.startThreads();
205       try {
206         MetaRegionLocationCache metaCache = new MetaRegionLocationCache(zkWatcher);
207         // meta znodes do not exist at this point, cache should be empty.
208         assertTrue(metaCache.getMetaRegionLocations().isEmpty());
209         // Set the meta locations for a random meta replicas, simulating an active hmaster meta
210         // assignment.
211         for (int i = 0; i < 3; i++) {
212           // Updates the meta znodes.
213           MetaTableLocator.setMetaLocation(zkWatcher, sn, i, RegionState.State.OPEN);
214         }
215         // Wait until the meta cache is populated.
216         int iters = 0;
217         while (iters++ < 10) {
218           if (metaCache.getMetaRegionLocations().size() == 3) {
219             break;
220           }
221           Thread.sleep(1000);
222         }
223         List<HRegionLocation> metaLocations = metaCache.getMetaRegionLocations();
224         assertNotNull(metaLocations);
225         assertEquals(3, metaLocations.size());
226         for (HRegionLocation location : metaLocations) {
227           assertEquals(sn, location.getServerName());
228         }
229       } finally {
230         // clean up.
231         ctx.stop();
232         ZKUtil.deleteChildrenRecursively(zkWatcher, parentZnodeName);
233       }
234     }
235   }
236 }