You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by te...@apache.org on 2016/01/07 00:39:06 UTC

hbase git commit: HBASE-15073 Finer grained control over normalization actions for RegionNormalizer

Repository: hbase
Updated Branches:
  refs/heads/branch-1 c73b4f8df -> 53983f5b2


HBASE-15073 Finer grained control over normalization actions for RegionNormalizer


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/53983f5b
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/53983f5b
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/53983f5b

Branch: refs/heads/branch-1
Commit: 53983f5b2e88812ebb5a632ee363750194ed15cb
Parents: c73b4f8
Author: tedyu <yu...@gmail.com>
Authored: Wed Jan 6 15:38:46 2016 -0800
Committer: tedyu <yu...@gmail.com>
Committed: Wed Jan 6 15:38:46 2016 -0800

----------------------------------------------------------------------
 .../apache/hadoop/hbase/HTableDescriptor.java   | 60 +++++++++++++-------
 .../hbase/normalizer/NormalizationPlan.java     | 45 +++++++++++++++
 .../org/apache/hadoop/hbase/master/HMaster.java | 18 ++++--
 .../normalizer/EmptyNormalizationPlan.java      |  6 ++
 .../normalizer/MergeNormalizationPlan.java      |  6 ++
 .../master/normalizer/NormalizationPlan.java    | 35 ------------
 .../master/normalizer/RegionNormalizer.java     |  8 ++-
 .../normalizer/SimpleRegionNormalizer.java      | 11 +++-
 .../normalizer/SplitNormalizationPlan.java      |  6 ++
 .../normalizer/TestSimpleRegionNormalizer.java  | 47 +++++++++++----
 .../TestSimpleRegionNormalizerOnCluster.java    |  4 +-
 hbase-shell/src/main/ruby/hbase/admin.rb        |  5 +-
 .../src/main/ruby/shell/commands/normalize.rb   |  2 +-
 .../ruby/shell/commands/normalizer_switch.rb    |  3 +-
 14 files changed, 174 insertions(+), 82 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/53983f5b/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java
index a6c08c3..dfb56e4 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java
@@ -44,6 +44,8 @@ import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.hbase.client.Durability;
 import org.apache.hadoop.hbase.client.RegionReplicaUtil;
 import org.apache.hadoop.hbase.exceptions.DeserializationException;
+import org.apache.hadoop.hbase.normalizer.NormalizationPlan;
+import org.apache.hadoop.hbase.normalizer.NormalizationPlan.PlanType;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BytesBytesPair;
@@ -201,13 +203,14 @@ public class HTableDescriptor implements WritableComparable<HTableDescriptor> {
 
   /**
    * <em>INTERNAL</em> Used by shell/rest interface to access this metadata
-   * attribute which denotes if the table should be treated by region normalizer.
+   * attribute which denotes the allowed types of action (split/merge) when the table is treated
+   * by region normalizer.
    *
-   * @see #isNormalizationEnabled()
+   * @see #getDesiredNormalizationTypes()
    */
-  public static final String NORMALIZATION_ENABLED = "NORMALIZATION_ENABLED";
-  private static final ImmutableBytesWritable NORMALIZATION_ENABLED_KEY =
-    new ImmutableBytesWritable(Bytes.toBytes(NORMALIZATION_ENABLED));
+  public static final String NORMALIZATION_MODE = "NORMALIZATION_MODE";
+  private static final ImmutableBytesWritable NORMALIZATION_MODE_KEY =
+      new ImmutableBytesWritable(Bytes.toBytes(NORMALIZATION_MODE));
 
   /** Default durability for HTD is USE_DEFAULT, which defaults to HBase-global default value */
   private static final Durability DEFAULT_DURABLITY = Durability.USE_DEFAULT;
@@ -236,11 +239,6 @@ public class HTableDescriptor implements WritableComparable<HTableDescriptor> {
   public static final boolean DEFAULT_COMPACTION_ENABLED = true;
 
   /**
-   * Constant that denotes whether the table is normalized by default.
-   */
-  public static final boolean DEFAULT_NORMALIZATION_ENABLED = false;
-
-  /**
    * Constant that denotes the maximum default size of the memstore after which
    * the contents are flushed to the store files
    */
@@ -264,7 +262,7 @@ public class HTableDescriptor implements WritableComparable<HTableDescriptor> {
         String.valueOf(DEFAULT_DEFERRED_LOG_FLUSH));
     DEFAULT_VALUES.put(DURABILITY, DEFAULT_DURABLITY.name()); //use the enum name
     DEFAULT_VALUES.put(REGION_REPLICATION, String.valueOf(DEFAULT_REGION_REPLICATION));
-    DEFAULT_VALUES.put(NORMALIZATION_ENABLED, String.valueOf(DEFAULT_NORMALIZATION_ENABLED));
+    DEFAULT_VALUES.put(NORMALIZATION_MODE, "");
     for (String s : DEFAULT_VALUES.keySet()) {
       RESERVED_KEYWORDS.add(new ImmutableBytesWritable(Bytes.toBytes(s)));
     }
@@ -657,22 +655,42 @@ public class HTableDescriptor implements WritableComparable<HTableDescriptor> {
   }
 
   /**
-   * Check if normalization enable flag of the table is true. If flag is
-   * false then no region normalizer won't attempt to normalize this table.
+   * Check if normalization flag of the table. If flag is
+   * empty then region normalizer won't attempt to normalize this table.
    *
-   * @return true if region normalization is enabled for this table
+   * @return List of PlanType if region normalization is enabled for this table
+   *         null means region normalization is disabled
    */
-  public boolean isNormalizationEnabled() {
-    return isSomething(NORMALIZATION_ENABLED_KEY, DEFAULT_NORMALIZATION_ENABLED);
+  public List<PlanType> getDesiredNormalizationTypes() {
+    byte [] value = getValue(NORMALIZATION_MODE_KEY);
+    if (value == null) {
+      return null;
+    }
+    String strValue = Bytes.toString(value);
+    if (strValue.isEmpty()) {
+      return null;
+    }
+    List<NormalizationPlan.PlanType> types = new ArrayList<>();
+    if (strValue.toUpperCase().contains("M")) {
+      types.add(PlanType.MERGE);
+    }
+    if (strValue.toUpperCase().contains("S")) {
+      types.add(PlanType.SPLIT);
+    }
+    return types;
   }
 
   /**
-   * Setting the table normalization enable flag.
+   * Setting the types of action for table normalization mode flag.
    *
-   * @param isEnable True if enable normalization.
-   */
-  public HTableDescriptor setNormalizationEnabled(final boolean isEnable) {
-    setValue(NORMALIZATION_ENABLED_KEY, isEnable ? TRUE : FALSE);
+   * @param types String containing desired types of action:
+   *        "M" for region merge
+   *        "S" for region split
+   *        "MS" for region merge / split
+   */
+  public HTableDescriptor setNormalizationMode(final String types) {
+    setValue(NORMALIZATION_MODE_KEY, types == null || types.isEmpty() ? null :
+      new ImmutableBytesWritable(Bytes.toBytes(types.toUpperCase())));
     return this;
   }
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/53983f5b/hbase-client/src/main/java/org/apache/hadoop/hbase/normalizer/NormalizationPlan.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/normalizer/NormalizationPlan.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/normalizer/NormalizationPlan.java
new file mode 100644
index 0000000..66481e6
--- /dev/null
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/normalizer/NormalizationPlan.java
@@ -0,0 +1,45 @@
+/**
+ *
+ * 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.normalizer;
+
+import org.apache.hadoop.hbase.classification.InterfaceAudience;
+import org.apache.hadoop.hbase.client.Admin;
+
+/**
+ * Interface for normalization plan.
+ */
+@InterfaceAudience.Private
+public interface NormalizationPlan {
+  enum PlanType {
+    SPLIT,
+    MERGE,
+    NONE
+  }
+
+  /**
+   * Executes normalization plan on cluster (does actual splitting/merging work).
+   * @param admin instance of Admin
+   */
+  void execute(Admin admin);
+
+  /**
+   * @return the type of this plan
+   */
+  PlanType getType();
+}

http://git-wip-us.apache.org/repos/asf/hbase/blob/53983f5b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
index d9e422b..4d554a6 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java
@@ -116,6 +116,7 @@ import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
 import org.apache.hadoop.hbase.monitoring.MemoryBoundedLogMessageBuffer;
 import org.apache.hadoop.hbase.monitoring.MonitoredTask;
 import org.apache.hadoop.hbase.monitoring.TaskMonitor;
+import org.apache.hadoop.hbase.normalizer.NormalizationPlan.PlanType;
 import org.apache.hadoop.hbase.procedure.MasterProcedureManagerHost;
 import org.apache.hadoop.hbase.procedure.flush.MasterFlushTableProcedureManager;
 import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
@@ -1356,13 +1357,20 @@ public class HMaster extends HRegionServer implements MasterServices, Server {
           LOG.debug("Skipping normalizing " + table + " since its namespace has quota");
           continue;
         }
-        if (table.isSystemTable() || (getTableDescriptors().get(table) != null &&
-          !getTableDescriptors().get(table).isNormalizationEnabled())) {
-          LOG.debug("Skipping normalization for table: " + table + ", as it's either system"
-            + " table or doesn't have auto normalization turned on");
+        if (table.isSystemTable()) {
+          LOG.debug("Skipping normalization for table: " + table + ", as it's system table");
           continue;
         }
-        this.normalizer.computePlanForTable(table).execute(clusterConnection.getAdmin());
+        List<PlanType> types = null;
+        if (getTableDescriptors().get(table) != null) {
+          types = getTableDescriptors().get(table).getDesiredNormalizationTypes();
+          if (types == null) {
+            LOG.debug("Skipping normalization for table: " + table + ", as it's either system"
+                + " table or doesn't have auto normalization turned on");
+            continue;
+          }
+        }
+        this.normalizer.computePlanForTable(table, types).execute(clusterConnection.getAdmin());
       }
     }
     // If Region did not generate any plans, it means the cluster is already balanced.

http://git-wip-us.apache.org/repos/asf/hbase/blob/53983f5b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/EmptyNormalizationPlan.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/EmptyNormalizationPlan.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/EmptyNormalizationPlan.java
index a36dd07..29cc0c3 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/EmptyNormalizationPlan.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/EmptyNormalizationPlan.java
@@ -20,6 +20,7 @@ package org.apache.hadoop.hbase.master.normalizer;
 
 import org.apache.hadoop.hbase.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.normalizer.NormalizationPlan;
 
 /**
  * Plan which signifies that no normalization is required,
@@ -45,4 +46,9 @@ public final class EmptyNormalizationPlan implements NormalizationPlan {
   @Override
   public void execute(Admin admin) {
   }
+
+  @Override
+  public PlanType getType() {
+    return PlanType.NONE;
+  }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/53983f5b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/MergeNormalizationPlan.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/MergeNormalizationPlan.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/MergeNormalizationPlan.java
index 08a58a5..f3ce1d5 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/MergeNormalizationPlan.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/MergeNormalizationPlan.java
@@ -23,6 +23,7 @@ import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.hbase.HRegionInfo;
 import org.apache.hadoop.hbase.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.normalizer.NormalizationPlan;
 
 import java.io.IOException;
 
@@ -41,6 +42,11 @@ public class MergeNormalizationPlan implements NormalizationPlan {
     this.secondRegion = secondRegion;
   }
 
+  @Override
+  public PlanType getType() {
+    return PlanType.MERGE;
+  }
+
   HRegionInfo getFirstRegion() {
     return firstRegion;
   }

http://git-wip-us.apache.org/repos/asf/hbase/blob/53983f5b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/NormalizationPlan.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/NormalizationPlan.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/NormalizationPlan.java
deleted file mode 100644
index 96eed8c..0000000
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/NormalizationPlan.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- *
- * 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.normalizer;
-
-import org.apache.hadoop.hbase.classification.InterfaceAudience;
-import org.apache.hadoop.hbase.client.Admin;
-
-/**
- * Interface for normalization plan.
- */
-@InterfaceAudience.Private
-public interface NormalizationPlan {
-
-  /**
-   * Executes normalization plan on cluster (does actual splitting/merging work).
-   * @param admin instance of Admin
-   */
-  void execute(Admin admin);
-}

http://git-wip-us.apache.org/repos/asf/hbase/blob/53983f5b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/RegionNormalizer.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/RegionNormalizer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/RegionNormalizer.java
index 19abcf2..9de376a 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/RegionNormalizer.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/RegionNormalizer.java
@@ -18,10 +18,14 @@
  */
 package org.apache.hadoop.hbase.master.normalizer;
 
+import java.util.List;
+
 import org.apache.hadoop.hbase.HBaseIOException;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.master.MasterServices;
+import org.apache.hadoop.hbase.normalizer.NormalizationPlan;
+import org.apache.hadoop.hbase.normalizer.NormalizationPlan.PlanType;
 
 /**
  * Performs "normalization" of regions on the cluster, making sure that suboptimal
@@ -45,7 +49,9 @@ public interface RegionNormalizer {
   /**
    * Computes next optimal normalization plan.
    * @param table table to normalize
+   * @param types desired types of NormalizationPlan
    * @return Next (perhaps most urgent) normalization action to perform
    */
-  NormalizationPlan computePlanForTable(TableName table) throws HBaseIOException;
+  NormalizationPlan computePlanForTable(TableName table, List<PlanType> types)
+      throws HBaseIOException;
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/53983f5b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SimpleRegionNormalizer.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SimpleRegionNormalizer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SimpleRegionNormalizer.java
index fe6034b..9f76f26 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SimpleRegionNormalizer.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SimpleRegionNormalizer.java
@@ -27,6 +27,8 @@ import org.apache.hadoop.hbase.ServerName;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.master.MasterServices;
+import org.apache.hadoop.hbase.normalizer.NormalizationPlan;
+import org.apache.hadoop.hbase.normalizer.NormalizationPlan.PlanType;
 import org.apache.hadoop.hbase.util.Triple;
 
 import java.util.ArrayList;
@@ -90,10 +92,12 @@ public class SimpleRegionNormalizer implements RegionNormalizer {
    * Action may be either a split, or a merge, or no action.
    *
    * @param table table to normalize
+   * @param types desired types of NormalizationPlan
    * @return normalization plan to execute
    */
   @Override
-  public NormalizationPlan computePlanForTable(TableName table) throws HBaseIOException {
+  public NormalizationPlan computePlanForTable(TableName table, List<PlanType> types)
+      throws HBaseIOException {
     if (table == null || table.isSystemTable()) {
       LOG.debug("Normalization of system table " + table + " isn't allowed");
       return EmptyNormalizationPlan.getInstance();
@@ -134,7 +138,7 @@ public class SimpleRegionNormalizer implements RegionNormalizer {
 
     // now; if the largest region is >2 times large than average, we split it, split
     // is more high priority normalization action than merge.
-    if (largestRegion.getSecond() > 2 * avgRegionSize) {
+    if (types.contains(PlanType.SPLIT) && largestRegion.getSecond() > 2 * avgRegionSize) {
       LOG.debug("Table " + table + ", largest region "
         + largestRegion.getFirst().getRegionNameAsString() + " has size "
         + largestRegion.getSecond() + ", more than 2 times than avg size, splitting");
@@ -155,7 +159,8 @@ public class SimpleRegionNormalizer implements RegionNormalizer {
     }
     Triple<HRegionInfo, Long, Integer> candidateRegion = regionsWithSize.get(candidateIdx);
     Triple<HRegionInfo, Long, Integer> candidateRegion2 = regionsWithSize.get(candidateIdx+1);
-    if (candidateRegion.getSecond() + candidateRegion2.getSecond() < avgRegionSize) {
+    if (types.contains(PlanType.MERGE) &&
+        candidateRegion.getSecond() + candidateRegion2.getSecond() < avgRegionSize) {
       LOG.debug("Table " + table + ", smallest region size: " + candidateRegion.getSecond()
         + " and its smallest neighbor size: " + candidateRegion2.getSecond()
         + ", less than the avg size, merging them");

http://git-wip-us.apache.org/repos/asf/hbase/blob/53983f5b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SplitNormalizationPlan.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SplitNormalizationPlan.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SplitNormalizationPlan.java
index c96988a..76b7cc2 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SplitNormalizationPlan.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/normalizer/SplitNormalizationPlan.java
@@ -23,6 +23,7 @@ import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.hbase.HRegionInfo;
 import org.apache.hadoop.hbase.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.normalizer.NormalizationPlan;
 
 import java.io.IOException;
 import java.util.Arrays;
@@ -42,6 +43,11 @@ public class SplitNormalizationPlan implements NormalizationPlan {
     this.splitPoint = splitPoint;
   }
 
+  @Override
+  public PlanType getType() {
+    return PlanType.SPLIT;
+  }
+
   public HRegionInfo getRegionInfo() {
     return regionInfo;
   }

http://git-wip-us.apache.org/repos/asf/hbase/blob/53983f5b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizer.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizer.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizer.java
index e22532c..2c302d5 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizer.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizer.java
@@ -26,6 +26,8 @@ import org.apache.hadoop.hbase.RegionLoad;
 import org.apache.hadoop.hbase.ServerName;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.master.MasterServices;
+import org.apache.hadoop.hbase.normalizer.NormalizationPlan;
+import org.apache.hadoop.hbase.normalizer.NormalizationPlan.PlanType;
 import org.apache.hadoop.hbase.testclassification.SmallTests;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.junit.BeforeClass;
@@ -52,6 +54,18 @@ public class TestSimpleRegionNormalizer {
   private static final Log LOG = LogFactory.getLog(TestSimpleRegionNormalizer.class);
 
   private static RegionNormalizer normalizer;
+  private static List<PlanType> bothTypes;
+  static {
+    bothTypes = new ArrayList<>();
+    bothTypes.add(PlanType.SPLIT);
+    bothTypes.add(PlanType.MERGE);
+  }
+
+  private static List<PlanType> splitType;
+  static {
+    splitType = new ArrayList<>();
+    splitType.add(PlanType.SPLIT);
+  }
 
   // mocks
   private static MasterServices masterServices;
@@ -68,7 +82,7 @@ public class TestSimpleRegionNormalizer {
     Map<byte[], Integer> regionSizes = new HashMap<>();
 
     setupMocksForNormalizer(regionSizes, hris);
-    NormalizationPlan plan = normalizer.computePlanForTable(testTable);
+    NormalizationPlan plan = normalizer.computePlanForTable(testTable, bothTypes);
     assertTrue(plan instanceof EmptyNormalizationPlan);
   }
 
@@ -87,7 +101,7 @@ public class TestSimpleRegionNormalizer {
     regionSizes.put(hri2.getRegionName(), 15);
 
     setupMocksForNormalizer(regionSizes, hris);
-    NormalizationPlan plan = normalizer.computePlanForTable(testTable);
+    NormalizationPlan plan = normalizer.computePlanForTable(testTable, bothTypes);
     assertTrue((plan instanceof EmptyNormalizationPlan));
   }
 
@@ -113,14 +127,18 @@ public class TestSimpleRegionNormalizer {
     hris.add(hri4);
     regionSizes.put(hri4.getRegionName(), 10);
 
-
     setupMocksForNormalizer(regionSizes, hris);
-    NormalizationPlan plan = normalizer.computePlanForTable(testTable);
+    NormalizationPlan plan = normalizer.computePlanForTable(testTable, bothTypes);
     assertTrue(plan instanceof EmptyNormalizationPlan);
   }
 
   @Test
   public void testMergeOfSmallRegions() throws HBaseIOException {
+    testMergeOfSmallRegions(true);
+    testMergeOfSmallRegions(false);
+  }
+
+  public void testMergeOfSmallRegions(boolean mergeDesired) throws HBaseIOException {
     TableName testTable = TableName.valueOf("testMergeOfSmallRegions");
     List<HRegionInfo> hris = new ArrayList<>();
     Map<byte[], Integer> regionSizes = new HashMap<>();
@@ -146,11 +164,16 @@ public class TestSimpleRegionNormalizer {
     regionSizes.put(hri5.getRegionName(), 16);
 
     setupMocksForNormalizer(regionSizes, hris);
-    NormalizationPlan plan = normalizer.computePlanForTable(testTable);
-
-    assertTrue(plan instanceof MergeNormalizationPlan);
-    assertEquals(hri2, ((MergeNormalizationPlan) plan).getFirstRegion());
-    assertEquals(hri3, ((MergeNormalizationPlan) plan).getSecondRegion());
+    NormalizationPlan plan = normalizer.computePlanForTable(testTable,
+      mergeDesired ? bothTypes : splitType);
+
+    if (mergeDesired) {
+      assertTrue(plan instanceof MergeNormalizationPlan);
+      assertEquals(hri2, ((MergeNormalizationPlan) plan).getFirstRegion());
+      assertEquals(hri3, ((MergeNormalizationPlan) plan).getSecondRegion());
+    } else {
+      assertTrue(plan instanceof EmptyNormalizationPlan);
+    }
   }
 
   // Test for situation illustrated in HBASE-14867
@@ -185,7 +208,7 @@ public class TestSimpleRegionNormalizer {
     regionSizes.put(hri6.getRegionName(), 2700);
 
     setupMocksForNormalizer(regionSizes, hris);
-    NormalizationPlan plan = normalizer.computePlanForTable(testTable);
+    NormalizationPlan plan = normalizer.computePlanForTable(testTable, bothTypes);
 
     assertTrue(plan instanceof MergeNormalizationPlan);
     assertEquals(hri5, ((MergeNormalizationPlan) plan).getFirstRegion());
@@ -219,7 +242,7 @@ public class TestSimpleRegionNormalizer {
     regionSizes.put(hri5.getRegionName(), 5);
 
     setupMocksForNormalizer(regionSizes, hris);
-    NormalizationPlan plan = normalizer.computePlanForTable(testTable);
+    NormalizationPlan plan = normalizer.computePlanForTable(testTable, bothTypes);
 
     assertTrue(plan instanceof EmptyNormalizationPlan);
   }
@@ -247,7 +270,7 @@ public class TestSimpleRegionNormalizer {
     regionSizes.put(hri4.getRegionName(), 30);
 
     setupMocksForNormalizer(regionSizes, hris);
-    NormalizationPlan plan = normalizer.computePlanForTable(testTable);
+    NormalizationPlan plan = normalizer.computePlanForTable(testTable, bothTypes);
 
     assertTrue(plan instanceof SplitNormalizationPlan);
     assertEquals(hri4, ((SplitNormalizationPlan) plan).getRegionInfo());

http://git-wip-us.apache.org/repos/asf/hbase/blob/53983f5b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizerOnCluster.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizerOnCluster.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizerOnCluster.java
index 07d09fe..b821b8a 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizerOnCluster.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/normalizer/TestSimpleRegionNormalizerOnCluster.java
@@ -113,7 +113,7 @@ public class TestSimpleRegionNormalizerOnCluster {
     }
 
     HTableDescriptor htd = admin.getTableDescriptor(TABLENAME);
-    htd.setNormalizationEnabled(true);
+    htd.setNormalizationMode("MS");
     admin.modifyTable(TABLENAME, htd);
 
     admin.flush(TABLENAME);
@@ -178,7 +178,7 @@ public class TestSimpleRegionNormalizerOnCluster {
     }
 
     HTableDescriptor htd = admin.getTableDescriptor(TABLENAME);
-    htd.setNormalizationEnabled(true);
+    htd.setNormalizationMode("MS");
     admin.modifyTable(TABLENAME, htd);
 
     admin.flush(TABLENAME);

http://git-wip-us.apache.org/repos/asf/hbase/blob/53983f5b/hbase-shell/src/main/ruby/hbase/admin.rb
----------------------------------------------------------------------
diff --git a/hbase-shell/src/main/ruby/hbase/admin.rb b/hbase-shell/src/main/ruby/hbase/admin.rb
index 7765ef0..0613918 100644
--- a/hbase-shell/src/main/ruby/hbase/admin.rb
+++ b/hbase-shell/src/main/ruby/hbase/admin.rb
@@ -246,7 +246,10 @@ module Hbase
     #----------------------------------------------------------------------------------------------
     # Parse arguments and update HTableDescriptor accordingly
     def parse_htd_args(htd, arg)
-      htd.setNormalizationEnabled(JBoolean.valueOf(arg.delete(NORMALIZATION_ENABLED))) if arg[NORMALIZATION_ENABLED]
+      if arg.has_key?(NORMALIZATION_MODE)
+        mode = arg.delete(NORMALIZATION_MODE)
+        htd.setValue(NORMALIZATION_MODE, mode)
+      end
     end
 
     #----------------------------------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/hbase/blob/53983f5b/hbase-shell/src/main/ruby/shell/commands/normalize.rb
----------------------------------------------------------------------
diff --git a/hbase-shell/src/main/ruby/shell/commands/normalize.rb b/hbase-shell/src/main/ruby/shell/commands/normalize.rb
index 7e6302c..e2b3d42 100644
--- a/hbase-shell/src/main/ruby/shell/commands/normalize.rb
+++ b/hbase-shell/src/main/ruby/shell/commands/normalize.rb
@@ -22,7 +22,7 @@ module Shell
     class Normalize < Command
       def help
         return <<-EOF
-Trigger region normalizer for all tables which have NORMALIZATION_ENABLED flag set. Returns true
+Trigger region normalizer for all tables which have NORMALIZATION_MODE flag set. Returns true
  if normalizer ran successfully, false otherwise. Note that this command has no effect
  if region normalizer is disabled (make sure it's turned on using 'normalizer_switch' command).
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/53983f5b/hbase-shell/src/main/ruby/shell/commands/normalizer_switch.rb
----------------------------------------------------------------------
diff --git a/hbase-shell/src/main/ruby/shell/commands/normalizer_switch.rb b/hbase-shell/src/main/ruby/shell/commands/normalizer_switch.rb
index 6d959c4..ee9e2d1 100644
--- a/hbase-shell/src/main/ruby/shell/commands/normalizer_switch.rb
+++ b/hbase-shell/src/main/ruby/shell/commands/normalizer_switch.rb
@@ -23,7 +23,8 @@ module Shell
       def help
         return <<-EOF
 Enable/Disable region normalizer. Returns previous normalizer state.
-When normalizer is enabled, it handles all tables with 'NORMALIZATION_ENABLED' => true.
+When normalizer is enabled, it handles all tables with 'NORMALIZATION_MODE' flag containing
+types of normalization actions.
 Examples:
 
   hbase> normalizer_switch true