HBASE-20706 Prevent MTP from trying to reopen non-OPEN regions ModifyTableProcedure is using MoveRegionProcedure in a way that was unintended from the original implementation. As such, we have to guard against certain usages of it. We know we can re-open OPEN regions, but regions in OPENING will similarly soon be OPEN (thus, we want to reopen those regions too).
Signed-off-by: Michael Stack <st...@apache.org> Signed-off-by: zhangduo <zhang...@apache.org> Project: http://git-wip-us.apache.org/repos/asf/hbase/repo Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/e989a992 Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/e989a992 Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/e989a992 Branch: refs/heads/HBASE-19064 Commit: e989a9927e4938ab64be9d82324e8a00a5768032 Parents: d1cad1a Author: Josh Elser <els...@apache.org> Authored: Wed Jun 13 16:30:33 2018 -0400 Committer: Josh Elser <els...@apache.org> Committed: Wed Jun 20 14:19:28 2018 -0700 ---------------------------------------------------------------------- .../hbase/master/assignment/RegionStates.java | 27 ++++++++++++++++++-- .../master/procedure/ModifyTableProcedure.java | 23 +++++++++++------ .../procedure/TestModifyTableProcedure.java | 24 +++++++++-------- 3 files changed, 54 insertions(+), 20 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hbase/blob/e989a992/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/RegionStates.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/RegionStates.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/RegionStates.java index 26b340f..d4951f7 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/RegionStates.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/RegionStates.java @@ -34,6 +34,7 @@ import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Predicate; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.ServerName; @@ -570,6 +571,18 @@ public class RegionStates { } /** + * @return Returns regions for a table which are open or about to be open (OPEN or OPENING) + */ + public List<RegionInfo> getOpenRegionsOfTable(final TableName table) { + // We want to get regions which are already open on the cluster or are about to be open. + // The use-case is for identifying regions which need to be re-opened to ensure they see some + // new configuration. Regions in OPENING now are presently being opened by a RS, so we can + // assume that they will imminently be OPEN but may not see our configuration change + return getRegionsOfTable( + table, (state) -> state.isInState(State.OPEN) || state.isInState(State.OPENING)); + } + + /** * @return Return online regions of table; does not include OFFLINE or SPLITTING regions. */ public List<RegionInfo> getRegionsOfTable(final TableName table) { @@ -577,15 +590,25 @@ public class RegionStates { } /** + * @return Return online regions of table; does not include OFFLINE or SPLITTING regions. + */ + public List<RegionInfo> getRegionsOfTable(final TableName table, boolean offline) { + return getRegionsOfTable(table, (state) -> include(state, offline)); + } + + /** * @return Return the regions of the table; does not include OFFLINE unless you set * <code>offline</code> to true. Does not include regions that are in the * {@link State#SPLIT} state. */ - public List<RegionInfo> getRegionsOfTable(final TableName table, final boolean offline) { + public List<RegionInfo> getRegionsOfTable( + final TableName table, Predicate<RegionStateNode> filter) { final ArrayList<RegionStateNode> nodes = getTableRegionStateNodes(table); final ArrayList<RegionInfo> hris = new ArrayList<RegionInfo>(nodes.size()); for (RegionStateNode node: nodes) { - if (include(node, offline)) hris.add(node.getRegionInfo()); + if (filter.test(node)) { + hris.add(node.getRegionInfo()); + } } return hris; } http://git-wip-us.apache.org/repos/asf/hbase/blob/e989a992/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ModifyTableProcedure.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ModifyTableProcedure.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ModifyTableProcedure.java index 6fb9caa..bcf41ac 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ModifyTableProcedure.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ModifyTableProcedure.java @@ -56,7 +56,6 @@ public class ModifyTableProcedure private TableDescriptor modifiedTableDescriptor; private boolean deleteColumnFamilyInModify; - private List<RegionInfo> regionInfoList; private Boolean traceEnabled = null; public ModifyTableProcedure() { @@ -80,7 +79,6 @@ public class ModifyTableProcedure private void initilize() { this.unmodifiedTableDescriptor = null; - this.regionInfoList = null; this.traceEnabled = null; this.deleteColumnFamilyInModify = false; } @@ -125,7 +123,7 @@ public class ModifyTableProcedure case MODIFY_TABLE_REOPEN_ALL_REGIONS: if (env.getAssignmentManager().isTableEnabled(getTableName())) { addChildProcedure(env.getAssignmentManager() - .createReopenProcedures(getRegionInfoList(env))); + .createReopenProcedures(getOpenRegionInfoList(env))); } return Flow.NO_MORE_STATE; default: @@ -433,11 +431,20 @@ public class ModifyTableProcedure } } + /** + * Fetches all Regions for a table. Cache the result of this method if you need to use it multiple + * times. Be aware that it may change over in between calls to this procedure. + */ private List<RegionInfo> getRegionInfoList(final MasterProcedureEnv env) throws IOException { - if (regionInfoList == null) { - regionInfoList = env.getAssignmentManager().getRegionStates() - .getRegionsOfTable(getTableName()); - } - return regionInfoList; + return env.getAssignmentManager().getRegionStates().getRegionsOfTable(getTableName()); + } + + /** + * Fetches all open or soon to be open Regions for a table. Cache the result of this method if + * you need to use it multiple times. Be aware that it may change over in between calls to this + * procedure. + */ + private List<RegionInfo> getOpenRegionInfoList(final MasterProcedureEnv env) throws IOException { + return env.getAssignmentManager().getRegionStates().getOpenRegionsOfTable(getTableName()); } } http://git-wip-us.apache.org/repos/asf/hbase/blob/e989a992/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyTableProcedure.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyTableProcedure.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyTableProcedure.java index c519835..51d7d2b 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyTableProcedure.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestModifyTableProcedure.java @@ -26,7 +26,10 @@ import org.apache.hadoop.hbase.HBaseClassTestRule; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; import org.apache.hadoop.hbase.client.RegionInfo; +import org.apache.hadoop.hbase.client.TableDescriptor; +import org.apache.hadoop.hbase.client.TableDescriptorBuilder; import org.apache.hadoop.hbase.procedure2.Procedure; import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility; @@ -201,24 +204,25 @@ public class TestModifyTableProcedure extends TestTableDDLProcedureBase { ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true); // Modify multiple properties of the table. - HTableDescriptor htd = new HTableDescriptor(UTIL.getAdmin().getTableDescriptor(tableName)); - boolean newCompactionEnableOption = htd.isCompactionEnabled() ? false : true; - htd.setCompactionEnabled(newCompactionEnableOption); - htd.addFamily(new HColumnDescriptor(cf2)); - htd.removeFamily(Bytes.toBytes(cf3)); - htd.setRegionReplication(3); + TableDescriptor oldDescriptor = UTIL.getAdmin().getDescriptor(tableName); + TableDescriptor newDescriptor = TableDescriptorBuilder.newBuilder(oldDescriptor) + .setCompactionEnabled(!oldDescriptor.isCompactionEnabled()) + .setColumnFamily(ColumnFamilyDescriptorBuilder.of(cf2)) + .removeColumnFamily(Bytes.toBytes(cf3)) + .setRegionReplication(3) + .build(); // Start the Modify procedure && kill the executor long procId = procExec.submitProcedure( - new ModifyTableProcedure(procExec.getEnvironment(), htd)); + new ModifyTableProcedure(procExec.getEnvironment(), newDescriptor)); // Restart the executor and execute the step twice MasterProcedureTestingUtility.testRecoveryAndDoubleExecution(procExec, procId); // Validate descriptor - HTableDescriptor currentHtd = UTIL.getAdmin().getTableDescriptor(tableName); - assertEquals(newCompactionEnableOption, currentHtd.isCompactionEnabled()); - assertEquals(2, currentHtd.getFamiliesKeys().size()); + TableDescriptor currentDescriptor = UTIL.getAdmin().getDescriptor(tableName); + assertEquals(newDescriptor.isCompactionEnabled(), currentDescriptor.isCompactionEnabled()); + assertEquals(2, newDescriptor.getColumnFamilyNames().size()); // cf2 should be added cf3 should be removed MasterProcedureTestingUtility.validateTableCreation(UTIL.getHBaseCluster().getMaster(),