diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java index 1880a0d7c0..fc5ef8063b 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java @@ -834,6 +834,30 @@ public class MetaTableAccessor { return HConstants.STATE_QUALIFIER; } + /** + * Returns the column qualifier for serialized region state + * @param replicaId the replicaId of the region + * @return a byte[] for state qualifier + */ + @VisibleForTesting + public static byte[] getRegionStateColumn(int replicaId) { + return replicaId == 0 ? HConstants.STATE_QUALIFIER + : Bytes.toBytes(HConstants.STATE_QUALIFIER_STR + META_REPLICA_ID_DELIMITER + + String.format(RegionInfo.REPLICA_ID_FORMAT, replicaId)); + } + + /** + * Returns the column qualifier for serialized region state + * @param replicaId the replicaId of the region + * @return a byte[] for sn column qualifier + */ + @VisibleForTesting + public static byte[] getServerNameColumn(int replicaId) { + return replicaId == 0 ? HConstants.SERVERNAME_QUALIFIER + : Bytes.toBytes(HConstants.SERVERNAME_QUALIFIER_STR + META_REPLICA_ID_DELIMITER + + String.format(RegionInfo.REPLICA_ID_FORMAT, replicaId)); + } + /** * Returns the column qualifier for server column for replicaId * @param replicaId the replicaId of the region @@ -1386,7 +1410,10 @@ public class MetaTableAccessor { getSeqNumColumn(i), now); deleteReplicaLocations.addColumns(getCatalogFamily(), getStartCodeColumn(i), now); + deleteReplicaLocations.addColumns(getCatalogFamily(), getServerNameColumn(i), now); + deleteReplicaLocations.addColumns(getCatalogFamily(), getRegionStateColumn(i), now); } + deleteFromMetaTable(connection, deleteReplicaLocations); } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/EnableTableProcedure.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/EnableTableProcedure.java index c46070cd58..4c1b20c08b 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/EnableTableProcedure.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/EnableTableProcedure.java @@ -124,56 +124,52 @@ public class EnableTableProcedure List regionsOfTable = env.getAssignmentManager().getRegionStates().getRegionsOfTable(tableName, true); - if (regionReplicaCount > 1) { - int currentMaxReplica = 0; - // Check if the regions in memory have replica regions as marked in META table - for (RegionInfo regionInfo : regionsOfTable) { - if (regionInfo.getReplicaId() > currentMaxReplica) { - // Iterating through all the list to identify the highest replicaID region. - // We can stop after checking with the first set of regions?? - currentMaxReplica = regionInfo.getReplicaId(); - } + int currentMaxReplica = 0; + // Check if the regions in memory have replica regions as marked in META table + for (RegionInfo regionInfo : regionsOfTable) { + if (regionInfo.getReplicaId() > currentMaxReplica) { + // Iterating through all the list to identify the highest replicaID region. + // We can stop after checking with the first set of regions?? + currentMaxReplica = regionInfo.getReplicaId(); } + } - // read the META table to know the actual number of replicas for the table - if there - // was a table modification on region replica then this will reflect the new entries also - int replicasFound = - getNumberOfReplicasFromMeta(connection, regionReplicaCount, regionsOfTable); - assert regionReplicaCount - 1 == replicasFound; - LOG.info(replicasFound + " META entries added for the given regionReplicaCount " - + regionReplicaCount + " for the table " + tableName.getNameAsString()); - if (currentMaxReplica == (regionReplicaCount - 1)) { - if (LOG.isDebugEnabled()) { - LOG.debug("There is no change to the number of region replicas." - + " Assigning the available regions." + " Current and previous" - + "replica count is " + regionReplicaCount); - } - } else if (currentMaxReplica > (regionReplicaCount - 1)) { - // we have additional regions as the replica count has been decreased. Delete - // those regions because already the table is in the unassigned state - LOG.info("The number of replicas " + (currentMaxReplica + 1) - + " is more than the region replica count " + regionReplicaCount); - List copyOfRegions = new ArrayList(regionsOfTable); - for (RegionInfo regionInfo : copyOfRegions) { - if (regionInfo.getReplicaId() > (regionReplicaCount - 1)) { - // delete the region from the regionStates - env.getAssignmentManager().getRegionStates().deleteRegion(regionInfo); - // remove it from the list of regions of the table - LOG.info("The regioninfo being removed is " + regionInfo + " " - + regionInfo.getReplicaId()); - regionsOfTable.remove(regionInfo); - } + // read the META table to know the actual number of replicas for the table - if there + // was a table modification on region replica then this will reflect the new entries also + int replicasFound = + getNumberOfReplicasFromMeta(connection, regionReplicaCount, regionsOfTable); + assert regionReplicaCount - 1 == replicasFound; + LOG.info(replicasFound + " META entries added for the given regionReplicaCount " + + regionReplicaCount + " for the table " + tableName.getNameAsString()); + if (currentMaxReplica == (regionReplicaCount - 1)) { + if (LOG.isDebugEnabled()) { + LOG.debug("There is no change to the number of region replicas." + + " Assigning the available regions." + " Current and previous" + + "replica count is " + regionReplicaCount); + } + } else if (currentMaxReplica > (regionReplicaCount - 1)) { + // we have additional regions as the replica count has been decreased. Delete + // those regions because already the table is in the unassigned state + LOG.info("The number of replicas " + (currentMaxReplica + 1) + + " is more than the region replica count " + regionReplicaCount); + List copyOfRegions = new ArrayList(regionsOfTable); + for (RegionInfo regionInfo : copyOfRegions) { + if (regionInfo.getReplicaId() > (regionReplicaCount - 1)) { + // delete the region from the regionStates + env.getAssignmentManager().getRegionStates().deleteRegion(regionInfo); + // remove it from the list of regions of the table + LOG.info( + "The regioninfo being removed is " + regionInfo + " " + regionInfo.getReplicaId()); + regionsOfTable.remove(regionInfo); } - } else { - // the replicasFound is less than the regionReplication - LOG.info( - "The number of replicas has been changed(increased)." - + " Lets assign the new region replicas. The previous replica count was " - + (currentMaxReplica + 1) + ". The current replica count is " - + regionReplicaCount); - regionsOfTable = RegionReplicaUtil.addReplicas(hTableDescriptor, regionsOfTable, - currentMaxReplica + 1, regionReplicaCount); } + } else { + // the replicasFound is less than the regionReplication + LOG.info("The number of replicas has been changed(increased)." + + " Lets assign the new region replicas. The previous replica count was " + + (currentMaxReplica + 1) + ". The current replica count is " + regionReplicaCount); + regionsOfTable = RegionReplicaUtil.addReplicas(hTableDescriptor, regionsOfTable, + currentMaxReplica + 1, regionReplicaCount); } // Assign all the table regions. (including region replicas if added). // createAssignProcedure will try to retain old assignments if possible. diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/TestMetaTableAccessor.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestMetaTableAccessor.java index ec93207656..bce700a851 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/TestMetaTableAccessor.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestMetaTableAccessor.java @@ -22,7 +22,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyObject; +import static org.mockito.ArgumentMatchers.anyObject; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; @@ -68,6 +68,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.hbase.thirdparty.com.google.common.collect.Lists; +import org.apache.hbase.thirdparty.com.google.common.collect.Sets; /** * Test {@link org.apache.hadoop.hbase.MetaTableAccessor}. @@ -440,6 +441,44 @@ public class TestMetaTableAccessor { assertEquals(0, startCodeCell.getValueLength()); } + @Test + public void testMetaLocationForRegionReplicasIsRemovedAtTableDeletion() throws IOException { + long regionId = System.currentTimeMillis(); + RegionInfo primary = RegionInfoBuilder.newBuilder(TableName.valueOf(name.getMethodName())) + .setStartKey(HConstants.EMPTY_START_ROW).setEndKey(HConstants.EMPTY_END_ROW).setSplit(false) + .setRegionId(regionId).setReplicaId(0).build(); + + Table meta = MetaTableAccessor.getMetaHTable(connection); + try { + List regionInfos = Lists.newArrayList(primary); + MetaTableAccessor.addRegionsToMeta(connection, regionInfos, 3); + MetaTableAccessor.removeRegionReplicasFromMeta(Sets.newHashSet(primary.getRegionName()), 1, 2, + connection); + Get get = new Get(primary.getRegionName()); + Result result = meta.get(get); + for (int replicaId = 0; replicaId < 3; replicaId++) { + Cell serverCell = result.getColumnLatestCell(HConstants.CATALOG_FAMILY, + MetaTableAccessor.getServerColumn(replicaId)); + Cell startCodeCell = result.getColumnLatestCell(HConstants.CATALOG_FAMILY, + MetaTableAccessor.getStartCodeColumn(replicaId)); + Cell stateCell = result.getColumnLatestCell(HConstants.CATALOG_FAMILY, + MetaTableAccessor.getRegionStateColumn(replicaId)); + Cell snCell = result.getColumnLatestCell(HConstants.CATALOG_FAMILY, + MetaTableAccessor.getServerNameColumn(replicaId)); + if (replicaId == 0) { + assertNotNull(stateCell); + } else { + assertNull(serverCell); + assertNull(startCodeCell); + assertNull(stateCell); + assertNull(snCell); + } + } + } finally { + meta.close(); + } + } + @Test public void testMetaLocationForRegionReplicasIsAddedAtTableCreation() throws IOException { long regionId = System.currentTimeMillis();