You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by en...@apache.org on 2014/06/28 02:30:59 UTC
[13/49] HBASE-10350. Master/AM/RegionStates changes to create and
assign region replicas (ddas)
http://git-wip-us.apache.org/repos/asf/hbase/blob/3d8ee3a0/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterOperationsForRegionReplicas.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterOperationsForRegionReplicas.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterOperationsForRegionReplicas.java
new file mode 100644
index 0000000..5ffedf7
--- /dev/null
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterOperationsForRegionReplicas.java
@@ -0,0 +1,323 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.master;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseTestingUtility;
+import org.apache.hadoop.hbase.HColumnDescriptor;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.HRegionInfo;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.MediumTests;
+import org.apache.hadoop.hbase.ServerName;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.catalog.CatalogTracker;
+import org.apache.hadoop.hbase.catalog.MetaReader;
+import org.apache.hadoop.hbase.catalog.MetaReader.Visitor;
+import org.apache.hadoop.hbase.client.Delete;
+import org.apache.hadoop.hbase.client.HBaseAdmin;
+import org.apache.hadoop.hbase.client.HTable;
+import org.apache.hadoop.hbase.client.RegionReplicaUtil;
+import org.apache.hadoop.hbase.client.Result;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category(MediumTests.class)
+public class TestMasterOperationsForRegionReplicas {
+ final static Log LOG = LogFactory.getLog(TestRegionPlacement.class);
+ private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
+ private static HBaseAdmin admin;
+ private static int numSlaves = 2;
+
+ @BeforeClass
+ public static void setupBeforeClass() throws Exception {
+ Configuration conf = TEST_UTIL.getConfiguration();
+ conf.setBoolean("hbase.tests.use.shortcircuit.reads", false);
+ TEST_UTIL.startMiniCluster(numSlaves);
+ admin = new HBaseAdmin(conf);
+ while(admin.getClusterStatus().getServers().size() < numSlaves) {
+ Thread.sleep(100);
+ }
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ TEST_UTIL.shutdownMiniCluster();
+ }
+
+ @Test
+ public void testCreateTableWithSingleReplica() throws Exception {
+ final int numRegions = 3;
+ final int numReplica = 1;
+ final TableName table = TableName.valueOf("singleReplicaTable");
+ try {
+ HTableDescriptor desc = new HTableDescriptor(table);
+ desc.setRegionReplication(numReplica);
+ desc.addFamily(new HColumnDescriptor("family"));
+ admin.createTable(desc, Bytes.toBytes("A"), Bytes.toBytes("Z"), numRegions);
+
+ CatalogTracker ct = new CatalogTracker(TEST_UTIL.getConfiguration());
+ validateNumberOfRowsInMeta(table, numRegions, ct);
+ List<HRegionInfo> hris = MetaReader.getTableRegions(ct, table);
+ assert(hris.size() == numRegions * numReplica);
+ } finally {
+ admin.disableTable(table);
+ admin.deleteTable(table);
+ }
+ }
+
+ @Test
+ public void testCreateTableWithMultipleReplicas() throws Exception {
+ final TableName table = TableName.valueOf("fooTable");
+ final int numRegions = 3;
+ final int numReplica = 2;
+ try {
+ HTableDescriptor desc = new HTableDescriptor(table);
+ desc.setRegionReplication(numReplica);
+ desc.addFamily(new HColumnDescriptor("family"));
+ admin.createTable(desc, Bytes.toBytes("A"), Bytes.toBytes("Z"), numRegions);
+ TEST_UTIL.waitTableEnabled(table.getName());
+ CatalogTracker ct = new CatalogTracker(TEST_UTIL.getConfiguration());
+ validateNumberOfRowsInMeta(table, numRegions, ct);
+
+ List<HRegionInfo> hris = MetaReader.getTableRegions(ct, table);
+ assert(hris.size() == numRegions * numReplica);
+ // check that the master created expected number of RegionState objects
+ for (int i = 0; i < numRegions; i++) {
+ for (int j = 0; j < numReplica; j++) {
+ HRegionInfo replica = RegionReplicaUtil.getRegionInfoForReplica(hris.get(i), j);
+ RegionState state = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager()
+ .getRegionStates().getRegionState(replica);
+ assert (state != null);
+ }
+ }
+ // TODO: HBASE-10351 should uncomment the following tests (since the tests assume region placements are handled)
+// List<Result> metaRows = MetaReader.fullScan(ct);
+// int numRows = 0;
+// for (Result result : metaRows) {
+// RegionLocations locations = MetaReader.getRegionLocations(result);
+// HRegionInfo hri = locations.getRegionLocation().getRegionInfo();
+// if (!hri.getTable().equals(table)) continue;
+// numRows += 1;
+// HRegionLocation[] servers = locations.getRegionLocations();
+// // have two locations for the replicas of a region, and the locations should be different
+// assert(servers.length == 2);
+// assert(!servers[0].equals(servers[1]));
+// }
+// assert(numRows == numRegions);
+//
+// // The same verification of the meta as above but with the SnapshotOfRegionAssignmentFromMeta
+// // class
+// validateFromSnapshotFromMeta(table, numRegions, numReplica, ct);
+//
+// // Now kill the master, restart it and see if the assignments are kept
+// ServerName master = TEST_UTIL.getHBaseClusterInterface().getClusterStatus().getMaster();
+// TEST_UTIL.getHBaseClusterInterface().stopMaster(master);
+// TEST_UTIL.getHBaseClusterInterface().waitForMasterToStop(master, 30000);
+// TEST_UTIL.getHBaseClusterInterface().startMaster(master.getHostname());
+// TEST_UTIL.getHBaseClusterInterface().waitForActiveAndReadyMaster();
+// for (int i = 0; i < numRegions; i++) {
+// for (int j = 0; j < numReplica; j++) {
+// HRegionInfo replica = RegionReplicaUtil.getRegionInfoForReplica(hris.get(i), j);
+// RegionState state = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager()
+// .getRegionStates().getRegionState(replica);
+// assert (state != null);
+// }
+// }
+// validateFromSnapshotFromMeta(table, numRegions, numReplica, ct);
+//
+// // Now shut the whole cluster down, and verify the assignments are kept so that the
+// // availability constraints are met.
+// TEST_UTIL.getConfiguration().setBoolean("hbase.master.startup.retainassign", true);
+// TEST_UTIL.shutdownMiniHBaseCluster();
+// TEST_UTIL.startMiniHBaseCluster(1, numSlaves);
+// TEST_UTIL.waitTableEnabled(table.getName());
+// ct = new CatalogTracker(TEST_UTIL.getConfiguration());
+// validateFromSnapshotFromMeta(table, numRegions, numReplica, ct);
+//
+// // Now shut the whole cluster down, and verify regions are assigned even if there is only
+// // one server running
+// TEST_UTIL.shutdownMiniHBaseCluster();
+// TEST_UTIL.startMiniHBaseCluster(1, 1);
+// TEST_UTIL.waitTableEnabled(table.getName());
+// ct = new CatalogTracker(TEST_UTIL.getConfiguration());
+// validateSingleRegionServerAssignment(ct, numRegions, numReplica);
+// for (int i = 1; i < numSlaves; i++) { //restore the cluster
+// TEST_UTIL.getMiniHBaseCluster().startRegionServer();
+// }
+
+ //TODO: HBASE-10361 patch should uncomment the test below
+// //check on alter table
+// admin.disableTable(table);
+// assert(admin.isTableDisabled(table));
+// //increase the replica
+// desc.setRegionReplication(numReplica + 1);
+// admin.modifyTable(table, desc);
+// admin.enableTable(table);
+// assert(admin.isTableEnabled(table));
+// List<HRegionInfo> regions = TEST_UTIL.getMiniHBaseCluster().getMaster()
+// .getAssignmentManager().getRegionStates().getRegionsOfTable(table);
+// assert(regions.size() == numRegions * (numReplica + 1));
+//
+// //decrease the replica(earlier, table was modified to have a replica count of numReplica + 1)
+// admin.disableTable(table);
+// desc.setRegionReplication(numReplica);
+// admin.modifyTable(table, desc);
+// admin.enableTable(table);
+// assert(admin.isTableEnabled(table));
+// regions = TEST_UTIL.getMiniHBaseCluster().getMaster()
+// .getAssignmentManager().getRegionStates().getRegionsOfTable(table);
+// assert(regions.size() == numRegions * numReplica);
+// //also make sure the meta table has the replica locations removed
+// hris = MetaReader.getTableRegions(ct, table);
+// assert(hris.size() == numRegions * numReplica);
+// //just check that the number of default replica regions in the meta table are the same
+// //as the number of regions the table was created with, and the count of the
+// //replicas is numReplica for each region
+// Map<HRegionInfo, Integer> defaultReplicas = new HashMap<HRegionInfo, Integer>();
+// for (HRegionInfo hri : hris) {
+// Integer i;
+// HRegionInfo regionReplica0 = hri.getRegionInfoForReplica(0);
+// defaultReplicas.put(regionReplica0,
+// (i = defaultReplicas.get(regionReplica0)) == null ? 1 : i + 1);
+// }
+// assert(defaultReplicas.size() == numRegions);
+// Collection<Integer> counts = new HashSet<Integer>(defaultReplicas.values());
+// assert(counts.size() == 1 && counts.contains(new Integer(numReplica)));
+ } finally {
+ admin.disableTable(table);
+ admin.deleteTable(table);
+ }
+ }
+
+ //@Test (TODO: enable when we have support for alter_table- HBASE-10361).
+ public void testIncompleteMetaTableReplicaInformation() throws Exception {
+ final TableName table = TableName.valueOf("fooTableTest1");
+ final int numRegions = 3;
+ final int numReplica = 2;
+ try {
+ // Create a table and let the meta table be updated with the location of the
+ // region locations.
+ HTableDescriptor desc = new HTableDescriptor(table);
+ desc.setRegionReplication(numReplica);
+ desc.addFamily(new HColumnDescriptor("family"));
+ admin.createTable(desc, Bytes.toBytes("A"), Bytes.toBytes("Z"), numRegions);
+ TEST_UTIL.waitTableEnabled(table.getName());
+ CatalogTracker ct = new CatalogTracker(TEST_UTIL.getConfiguration());
+ Set<byte[]> tableRows = new HashSet<byte[]>();
+ List<HRegionInfo> hris = MetaReader.getTableRegions(ct, table);
+ for (HRegionInfo hri : hris) {
+ tableRows.add(hri.getRegionName());
+ }
+ admin.disableTable(table);
+ // now delete one replica info from all the rows
+ // this is to make the meta appear to be only partially updated
+ HTable metaTable = new HTable(TableName.META_TABLE_NAME, ct.getConnection());
+ for (byte[] row : tableRows) {
+ Delete deleteOneReplicaLocation = new Delete(row);
+ deleteOneReplicaLocation.deleteColumns(HConstants.CATALOG_FAMILY, MetaReader.getServerColumn(1));
+ deleteOneReplicaLocation.deleteColumns(HConstants.CATALOG_FAMILY, MetaReader.getSeqNumColumn(1));
+ deleteOneReplicaLocation.deleteColumns(HConstants.CATALOG_FAMILY, MetaReader.getStartCodeColumn(1));
+ metaTable.delete(deleteOneReplicaLocation);
+ }
+ metaTable.close();
+ // even if the meta table is partly updated, when we re-enable the table, we should
+ // get back the desired number of replicas for the regions
+ admin.enableTable(table);
+ assert(admin.isTableEnabled(table));
+ List<HRegionInfo> regions = TEST_UTIL.getMiniHBaseCluster().getMaster()
+ .getAssignmentManager().getRegionStates().getRegionsOfTable(table);
+ assert(regions.size() == numRegions * numReplica);
+ } finally {
+ admin.disableTable(table);
+ admin.deleteTable(table);
+ }
+ }
+
+ private String printRegions(List<HRegionInfo> regions) {
+ StringBuffer strBuf = new StringBuffer();
+ for (HRegionInfo r : regions) {
+ strBuf.append(" ____ " + r.toString());
+ }
+ return strBuf.toString();
+ }
+
+ private void validateNumberOfRowsInMeta(final TableName table, int numRegions, CatalogTracker ct)
+ throws IOException {
+ assert(admin.tableExists(table));
+ final AtomicInteger count = new AtomicInteger();
+ Visitor visitor = new Visitor() {
+ @Override
+ public boolean visit(Result r) throws IOException {
+ if (HRegionInfo.getHRegionInfo(r).getTable().equals(table)) count.incrementAndGet();
+ return true;
+ }
+ };
+ MetaReader.fullScan(ct, visitor);
+ assert(count.get() == numRegions);
+ }
+
+ private void validateFromSnapshotFromMeta(TableName table, int numRegions,
+ int numReplica, CatalogTracker ct) throws IOException {
+ SnapshotOfRegionAssignmentFromMeta snapshot = new SnapshotOfRegionAssignmentFromMeta(ct);
+ snapshot.initialize();
+ Map<HRegionInfo, ServerName> regionToServerMap = snapshot.getRegionToRegionServerMap();
+ assert(regionToServerMap.size() == numRegions * numReplica + 1); //'1' for the namespace
+ Map<ServerName, List<HRegionInfo>> serverToRegionMap = snapshot.getRegionServerToRegionMap();
+ for (Map.Entry<ServerName, List<HRegionInfo>> entry : serverToRegionMap.entrySet()) {
+ List<HRegionInfo> regions = entry.getValue();
+ Set<byte[]> setOfStartKeys = new HashSet<byte[]>();
+ for (HRegionInfo region : regions) {
+ byte[] startKey = region.getStartKey();
+ if (region.getTable().equals(table)) {
+ setOfStartKeys.add(startKey); //ignore other tables
+ LOG.info("--STARTKEY " + new String(startKey)+"--");
+ }
+ }
+ // the number of startkeys will be equal to the number of regions hosted in each server
+ // (each server will be hosting one replica of a region)
+ assertEquals(setOfStartKeys.size() , numRegions);
+ }
+ }
+
+ private void validateSingleRegionServerAssignment(CatalogTracker ct, int numRegions,
+ int numReplica) throws IOException {
+ SnapshotOfRegionAssignmentFromMeta snapshot = new SnapshotOfRegionAssignmentFromMeta(ct);
+ snapshot.initialize();
+ Map<HRegionInfo, ServerName> regionToServerMap = snapshot.getRegionToRegionServerMap();
+ assert(regionToServerMap.size() == numRegions * numReplica + 1); //'1' for the namespace
+ Map<ServerName, List<HRegionInfo>> serverToRegionMap = snapshot.getRegionServerToRegionMap();
+ assert(serverToRegionMap.keySet().size() == 1);
+ assert(serverToRegionMap.values().iterator().next().size() == numRegions * numReplica + 1);
+ }
+}