You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by zg...@apache.org on 2019/03/26 03:01:14 UTC

[hbase] branch branch-2 updated: HBASE-21964 unset Quota by Throttle Type

This is an automated email from the ASF dual-hosted git repository.

zghao pushed a commit to branch branch-2
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/branch-2 by this push:
     new 1926b86  HBASE-21964 unset Quota by Throttle Type
1926b86 is described below

commit 1926b86a8ca03e9086c776df5101caba05e8ca00
Author: yaojingyi <ya...@didichuxing.com>
AuthorDate: Fri Mar 22 10:55:03 2019 +0800

    HBASE-21964 unset Quota by Throttle Type
    
    Signed-off-by: Guanghao Zhang <zg...@apache.org>
---
 .../hadoop/hbase/quotas/QuotaSettingsFactory.java  |  74 ++++++++++
 .../hbase/quotas/GlobalQuotaSettingsImpl.java      | 122 +++++++++++++++--
 .../hadoop/hbase/quotas/TestQuotaThrottle.java     | 151 +++++++++++++++++++++
 hbase-shell/src/main/ruby/hbase/quotas.rb          | 146 ++++++++++++++++----
 4 files changed, 455 insertions(+), 38 deletions(-)

diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/quotas/QuotaSettingsFactory.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/quotas/QuotaSettingsFactory.java
index 3124591..4473b73 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/quotas/QuotaSettingsFactory.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/quotas/QuotaSettingsFactory.java
@@ -291,6 +291,18 @@ public class QuotaSettingsFactory {
   }
 
   /**
+   * Remove the throttling for the specified user.
+   *
+   * @param userName the user
+   * @param type the type of throttling
+   * @return the quota settings
+   */
+  public static QuotaSettings unthrottleUserByThrottleType(final String userName,
+      final ThrottleType type) {
+    return throttle(userName, null, null, null, type, 0, null, QuotaScope.MACHINE);
+  }
+
+  /**
    * Remove the throttling for the specified user on the specified table.
    *
    * @param userName the user
@@ -302,6 +314,19 @@ public class QuotaSettingsFactory {
   }
 
   /**
+   * Remove the throttling for the specified user on the specified table.
+   *
+   * @param userName the user
+   * @param tableName the table
+   * @param type the type of throttling
+   * @return the quota settings
+   */
+  public static QuotaSettings unthrottleUserByThrottleType(final String userName,
+      final TableName tableName, final ThrottleType type) {
+    return throttle(userName, tableName, null, null, type, 0, null, QuotaScope.MACHINE);
+  }
+
+  /**
    * Remove the throttling for the specified user on the specified namespace.
    *
    * @param userName the user
@@ -313,6 +338,19 @@ public class QuotaSettingsFactory {
   }
 
   /**
+   * Remove the throttling for the specified user on the specified namespace.
+   *
+   * @param userName the user
+   * @param namespace the namespace
+   * @param type the type of throttling
+   * @return the quota settings
+   */
+  public static QuotaSettings unthrottleUserByThrottleType(final String userName,
+      final String namespace, final ThrottleType type) {
+    return throttle(userName, null, namespace, null, type, 0, null, QuotaScope.MACHINE);
+  }
+
+  /**
    * Throttle the specified table.
    *
    * @param tableName the table to throttle
@@ -351,6 +389,18 @@ public class QuotaSettingsFactory {
   }
 
   /**
+   * Remove the throttling for the specified table.
+   *
+   * @param tableName the table
+   * @param type the type of throttling
+   * @return the quota settings
+   */
+  public static QuotaSettings unthrottleTableByThrottleType(final TableName tableName,
+      final ThrottleType type) {
+    return throttle(null, tableName, null, null, type, 0, null, QuotaScope.MACHINE);
+  }
+
+  /**
    * Throttle the specified namespace.
    *
    * @param namespace the namespace to throttle
@@ -389,6 +439,18 @@ public class QuotaSettingsFactory {
   }
 
   /**
+   * Remove the throttling for the specified namespace by throttle type.
+   *
+   * @param namespace the namespace
+   * @param type the type of throttling
+   * @return the quota settings
+   */
+  public static QuotaSettings unthrottleNamespaceByThrottleType(final String namespace,
+      final ThrottleType type) {
+    return throttle(null, null, namespace, null, type, 0, null, QuotaScope.MACHINE);
+  }
+
+  /**
    * Throttle the specified region server.
    *
    * @param regionServer the region server to throttle
@@ -412,6 +474,18 @@ public class QuotaSettingsFactory {
     return throttle(null, null, null, regionServer, null, 0, null, QuotaScope.MACHINE);
   }
 
+  /**
+   * Remove the throttling for the specified region server by throttle type.
+   *
+   * @param regionServer  the region Server
+   * @param type the type of throttling
+   * @return the quota settings
+   */
+  public static QuotaSettings unthrottleRegionServerByThrottleType(final String regionServer,
+      final ThrottleType type) {
+    return throttle(null, null, null, regionServer, type, 0, null, QuotaScope.MACHINE);
+  }
+
   /* Throttle helper */
   private static QuotaSettings throttle(final String userName, final TableName tableName,
       final String namespace, final String regionServer, final ThrottleType type, final long limit,
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/GlobalQuotaSettingsImpl.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/GlobalQuotaSettingsImpl.java
index c7df789..6bcbf7e 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/GlobalQuotaSettingsImpl.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/quotas/GlobalQuotaSettingsImpl.java
@@ -110,6 +110,60 @@ public class GlobalQuotaSettingsImpl extends GlobalQuotaSettings {
     return builder.build();
   }
 
+  private boolean hasThrottle(QuotaProtos.ThrottleType quotaType,
+      QuotaProtos.Throttle.Builder throttleBuilder) {
+    boolean hasThrottle = false;
+    switch (quotaType) {
+      case REQUEST_NUMBER:
+        if (throttleBuilder.hasReqNum()) {
+          hasThrottle = true;
+        }
+        break;
+      case REQUEST_SIZE:
+        if (throttleBuilder.hasReqSize()) {
+          hasThrottle = true;
+        }
+        break;
+      case WRITE_NUMBER:
+        if (throttleBuilder.hasWriteNum()) {
+          hasThrottle = true;
+        }
+        break;
+      case WRITE_SIZE:
+        if (throttleBuilder.hasWriteSize()) {
+          hasThrottle = true;
+        }
+        break;
+      case READ_NUMBER:
+        if (throttleBuilder.hasReadNum()) {
+          hasThrottle = true;
+        }
+        break;
+      case READ_SIZE:
+        if (throttleBuilder.hasReadSize()) {
+          hasThrottle = true;
+        }
+        break;
+      case REQUEST_CAPACITY_UNIT:
+        if (throttleBuilder.hasReqCapacityUnit()) {
+          hasThrottle = true;
+        }
+        break;
+      case READ_CAPACITY_UNIT:
+        if (throttleBuilder.hasReadCapacityUnit()) {
+          hasThrottle = true;
+        }
+        break;
+      case WRITE_CAPACITY_UNIT:
+        if (throttleBuilder.hasWriteCapacityUnit()) {
+          hasThrottle = true;
+        }
+        break;
+      default:
+    }
+    return hasThrottle;
+  }
+
   @Override
   protected GlobalQuotaSettingsImpl merge(QuotaSettings other) throws IOException {
     // Validate the quota subject
@@ -124,14 +178,60 @@ public class GlobalQuotaSettingsImpl extends GlobalQuotaSettings {
       if (!otherThrottle.proto.hasType() || !otherThrottle.proto.hasTimedQuota()) {
         // It means it's a remove request
         // To prevent the "empty" row in QuotaTableUtil.QUOTA_TABLE_NAME
-        throttleBuilder = null;
+
+        QuotaProtos.ThrottleRequest otherProto = otherThrottle.proto;
+        if (throttleBuilder != null && !otherThrottle.proto.hasTimedQuota() && otherThrottle.proto
+            .hasType()) {
+          switch (otherProto.getType()) {
+            case REQUEST_NUMBER:
+              throttleBuilder.clearReqNum();
+              break;
+            case REQUEST_SIZE:
+              throttleBuilder.clearReqSize();
+              break;
+            case WRITE_NUMBER:
+              throttleBuilder.clearWriteNum();
+              break;
+            case WRITE_SIZE:
+              throttleBuilder.clearWriteSize();
+              break;
+            case READ_NUMBER:
+              throttleBuilder.clearReadNum();
+              break;
+            case READ_SIZE:
+              throttleBuilder.clearReadSize();
+              break;
+            case REQUEST_CAPACITY_UNIT:
+              throttleBuilder.clearReqCapacityUnit();
+              break;
+            case READ_CAPACITY_UNIT:
+              throttleBuilder.clearReadCapacityUnit();
+              break;
+            case WRITE_CAPACITY_UNIT:
+              throttleBuilder.clearWriteCapacityUnit();
+              break;
+            default:
+          }
+          boolean hasThrottle = false;
+          for (QuotaProtos.ThrottleType quotaType : QuotaProtos.ThrottleType.values()) {
+            hasThrottle = hasThrottle(quotaType, throttleBuilder);
+            if (hasThrottle) {
+              break;
+            }
+          }
+          if (!hasThrottle) {
+            throttleBuilder = null;
+          }
+        } else {
+          throttleBuilder = null;
+        }
+
       } else {
         QuotaProtos.ThrottleRequest otherProto = otherThrottle.proto;
         validateTimedQuota(otherProto.getTimedQuota());
         if (throttleBuilder == null) {
           throttleBuilder = QuotaProtos.Throttle.newBuilder();
         }
-
         switch (otherProto.getType()) {
           case REQUEST_NUMBER:
             throttleBuilder.setReqNum(otherProto.getTimedQuota());
@@ -166,8 +266,8 @@ public class GlobalQuotaSettingsImpl extends GlobalQuotaSettings {
     }
 
     // Propagate the space quota portion
-    QuotaProtos.SpaceQuota.Builder spaceBuilder = (spaceProto == null
-        ? null : spaceProto.toBuilder());
+    QuotaProtos.SpaceQuota.Builder spaceBuilder =
+        (spaceProto == null ? null : spaceProto.toBuilder());
     if (other instanceof SpaceLimitSettings) {
       if (spaceBuilder == null) {
         spaceBuilder = QuotaProtos.SpaceQuota.newBuilder();
@@ -181,10 +281,9 @@ public class GlobalQuotaSettingsImpl extends GlobalQuotaSettings {
         SpaceQuota quotaToMerge = spaceRequest.getQuota();
         // Validate that the two settings are for the same target.
         // SpaceQuotas either apply to a table or a namespace (no user spacequota).
-        if (!Objects.equals(getTableName(), settingsToMerge.getTableName())
-            && !Objects.equals(getNamespace(), settingsToMerge.getNamespace())) {
-          throw new IllegalArgumentException(
-              "Cannot merge " + settingsToMerge + " into " + this);
+        if (!Objects.equals(getTableName(), settingsToMerge.getTableName()) && !Objects
+            .equals(getNamespace(), settingsToMerge.getNamespace())) {
+          throw new IllegalArgumentException("Cannot merge " + settingsToMerge + " into " + this);
         }
 
         if (quotaToMerge.getRemove()) {
@@ -210,10 +309,9 @@ public class GlobalQuotaSettingsImpl extends GlobalQuotaSettings {
       return null;
     }
 
-    return new GlobalQuotaSettingsImpl(
-        getUserName(), getTableName(), getNamespace(), getRegionServer(),
-        (throttleBuilder == null ? null : throttleBuilder.build()), bypassGlobals,
-        (removeSpaceBuilder ? null : spaceBuilder.build()));
+    return new GlobalQuotaSettingsImpl(getUserName(), getTableName(), getNamespace(),
+        getRegionServer(), (throttleBuilder == null ? null : throttleBuilder.build()),
+        bypassGlobals, (removeSpaceBuilder ? null : spaceBuilder.build()));
   }
 
   private void validateTimedQuota(final TimedQuota timedQuota) throws IOException {
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/quotas/TestQuotaThrottle.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/quotas/TestQuotaThrottle.java
index abc7b1d..993007df 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/quotas/TestQuotaThrottle.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/quotas/TestQuotaThrottle.java
@@ -27,7 +27,10 @@ import static org.apache.hadoop.hbase.quotas.ThrottleQuotaTestUtil.triggerUserCa
 import static org.apache.hadoop.hbase.quotas.ThrottleQuotaTestUtil.waitMinuteQuota;
 import static org.junit.Assert.assertEquals;
 
+import java.io.IOException;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
+
 import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseTestingUtility;
 import org.apache.hadoop.hbase.HConstants;
@@ -71,6 +74,13 @@ public class TestQuotaThrottle {
     TableName.valueOf("TestQuotaAdmin1"),
     TableName.valueOf("TestQuotaAdmin2")
   };
+
+  private final static String[] NAMESPACES = new String[] {
+    "NAMESPACE01",
+    "NAMESPACE02",
+    "NAMESPACE03"
+  };
+
   private static Table[] tables;
 
   @BeforeClass
@@ -192,6 +202,147 @@ public class TestQuotaThrottle {
   }
 
   @Test
+  public void testUserUnThrottleByType() throws Exception {
+    final Admin admin = TEST_UTIL.getAdmin();
+    final String userName = User.getCurrent().getShortName();
+    String userName01 = "user01";
+    // Add 6req/min limit
+    admin.setQuota(QuotaSettingsFactory
+        .throttleUser(userName, ThrottleType.REQUEST_NUMBER, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleUser(userName, ThrottleType.REQUEST_SIZE, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleUser(userName01, ThrottleType.REQUEST_NUMBER, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleUser(userName01, ThrottleType.REQUEST_SIZE, 6, TimeUnit.MINUTES));
+    admin.setQuota(
+        QuotaSettingsFactory.unthrottleUserByThrottleType(userName, ThrottleType.REQUEST_NUMBER));
+    assertEquals(3, getQuotaSettingCount(admin));
+    admin.setQuota(
+        QuotaSettingsFactory.unthrottleUserByThrottleType(userName, ThrottleType.REQUEST_SIZE));
+    assertEquals(2, getQuotaSettingCount(admin));
+  }
+
+  @Test
+  public void testUserTableUnThrottleByType() throws Exception {
+    final Admin admin = TEST_UTIL.getAdmin();
+    final String userName = User.getCurrent().getShortName();
+    String userName01 = "user01";
+    // Add 6req/min limit
+    admin.setQuota(QuotaSettingsFactory
+        .throttleUser(userName, TABLE_NAMES[0], ThrottleType.REQUEST_NUMBER, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleUser(userName, TABLE_NAMES[0], ThrottleType.REQUEST_SIZE, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleUser(userName01, TABLE_NAMES[1], ThrottleType.REQUEST_NUMBER, 6,
+            TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleUser(userName01, TABLE_NAMES[1], ThrottleType.REQUEST_SIZE, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .unthrottleUserByThrottleType(userName, TABLE_NAMES[0], ThrottleType.REQUEST_NUMBER));
+    assertEquals(3, getQuotaSettingCount(admin));
+    admin.setQuota(QuotaSettingsFactory
+        .unthrottleUserByThrottleType(userName, TABLE_NAMES[0], ThrottleType.REQUEST_SIZE));
+    assertEquals(2, getQuotaSettingCount(admin));
+  }
+
+  @Test
+  public void testUserNameSpaceUnThrottleByType() throws Exception {
+    final Admin admin = TEST_UTIL.getAdmin();
+    final String userName = User.getCurrent().getShortName();
+    String userName01 = "user01";
+    // Add 6req/min limit
+    admin.setQuota(QuotaSettingsFactory
+        .throttleUser(userName, NAMESPACES[0], ThrottleType.REQUEST_NUMBER, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleUser(userName, NAMESPACES[0], ThrottleType.REQUEST_SIZE, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleUser(userName01, NAMESPACES[1], ThrottleType.REQUEST_NUMBER, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleUser(userName01, NAMESPACES[1], ThrottleType.REQUEST_SIZE, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .unthrottleUserByThrottleType(userName, NAMESPACES[0], ThrottleType.REQUEST_NUMBER));
+    assertEquals(3, getQuotaSettingCount(admin));
+    admin.setQuota(QuotaSettingsFactory
+        .unthrottleUserByThrottleType(userName, NAMESPACES[0], ThrottleType.REQUEST_SIZE));
+    assertEquals(2, getQuotaSettingCount(admin));
+  }
+
+  @Test
+  public void testTableUnThrottleByType() throws Exception {
+    final Admin admin = TEST_UTIL.getAdmin();
+    final String userName = User.getCurrent().getShortName();
+    // Add 6req/min limit
+    admin.setQuota(QuotaSettingsFactory
+        .throttleTable(TABLE_NAMES[0], ThrottleType.REQUEST_NUMBER, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleTable(TABLE_NAMES[0], ThrottleType.REQUEST_SIZE, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleTable(TABLE_NAMES[1], ThrottleType.REQUEST_NUMBER, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleTable(TABLE_NAMES[1], ThrottleType.REQUEST_SIZE, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .unthrottleTableByThrottleType(TABLE_NAMES[0], ThrottleType.REQUEST_NUMBER));
+    assertEquals(3, getQuotaSettingCount(admin));
+    admin.setQuota(QuotaSettingsFactory
+        .unthrottleTableByThrottleType(TABLE_NAMES[0], ThrottleType.REQUEST_SIZE));
+    assertEquals(2, getQuotaSettingCount(admin));
+  }
+
+  @Test
+  public void testNameSpaceUnThrottleByType() throws Exception {
+    final Admin admin = TEST_UTIL.getAdmin();
+    final String userName = User.getCurrent().getShortName();
+    // Add 6req/min limit
+    admin.setQuota(QuotaSettingsFactory
+        .throttleNamespace(NAMESPACES[0], ThrottleType.REQUEST_NUMBER, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleNamespace(NAMESPACES[0], ThrottleType.REQUEST_SIZE, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleNamespace(NAMESPACES[1], ThrottleType.REQUEST_NUMBER, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleNamespace(NAMESPACES[1], ThrottleType.REQUEST_SIZE, 6, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .unthrottleNamespaceByThrottleType(NAMESPACES[0], ThrottleType.REQUEST_NUMBER));
+    assertEquals(3, getQuotaSettingCount(admin));
+    admin.setQuota(QuotaSettingsFactory
+        .unthrottleNamespaceByThrottleType(NAMESPACES[0], ThrottleType.REQUEST_SIZE));
+    assertEquals(2, getQuotaSettingCount(admin));
+  }
+
+  @Test
+  public void testRegionServerUnThrottleByType() throws Exception {
+    final Admin admin = TEST_UTIL.getAdmin();
+    final String[] REGIONSERVER = { "RS01", "RS02" };
+
+    admin.setQuota(QuotaSettingsFactory
+        .throttleRegionServer(REGIONSERVER[0], ThrottleType.READ_NUMBER, 4, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleRegionServer(REGIONSERVER[0], ThrottleType.WRITE_NUMBER, 4, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleRegionServer(REGIONSERVER[1], ThrottleType.READ_NUMBER, 4, TimeUnit.MINUTES));
+    admin.setQuota(QuotaSettingsFactory
+        .throttleRegionServer(REGIONSERVER[1], ThrottleType.WRITE_NUMBER, 4, TimeUnit.MINUTES));
+
+    admin.setQuota(QuotaSettingsFactory
+        .unthrottleRegionServerByThrottleType(REGIONSERVER[0], ThrottleType.READ_NUMBER));
+    assertEquals(3, getQuotaSettingCount(admin));
+    admin.setQuota(QuotaSettingsFactory
+        .unthrottleRegionServerByThrottleType(REGIONSERVER[0], ThrottleType.WRITE_NUMBER));
+    assertEquals(2, getQuotaSettingCount(admin));
+  }
+
+  public int getQuotaSettingCount(Admin admin) throws IOException {
+    List<QuotaSettings> list_quotas = admin.getQuota(new QuotaFilter());
+    int quotaSettingCount = 0;
+    for (QuotaSettings setting : list_quotas) {
+      quotaSettingCount++;
+      LOG.info("Quota Setting:" + setting);
+    }
+    return quotaSettingCount;
+  }
+
+  @Test
   public void testUserTableReadAndWriteThrottle() throws Exception {
     final Admin admin = TEST_UTIL.getAdmin();
     final String userName = User.getCurrent().getShortName();
diff --git a/hbase-shell/src/main/ruby/hbase/quotas.rb b/hbase-shell/src/main/ruby/hbase/quotas.rb
index 6fcf8bf..9243877 100644
--- a/hbase-shell/src/main/ruby/hbase/quotas.rb
+++ b/hbase-shell/src/main/ruby/hbase/quotas.rb
@@ -46,6 +46,15 @@ module HBaseQuotasConstants
   NO_WRITES = 'NO_WRITES'.freeze
   NO_WRITES_COMPACTIONS = 'NO_WRITES_COMPACTIONS'.freeze
   DISABLE = 'DISABLE'.freeze
+  READ_NUMBER = 'READ_NUMBER'.freeze
+  READ_SIZE = 'READ_SIZE'.freeze
+  WRITE_NUMBER = 'WRITE_NUMBER'.freeze
+  WRITE_SIZE = 'WRITE_SIZE'.freeze
+  REQUEST_NUMBER = 'REQUEST_NUMBER'.freeze
+  REQUEST_SIZE = 'REQUEST_SIZE'.freeze
+  REQUEST_CAPACITY_UNIT = 'REQUEST_CAPACITY_UNIT'.freeze
+  WRITE_CAPACITY_UNIT = 'WRITE_CAPACITY_UNIT'.freeze
+  READ_CAPACITY_UNIT = 'READ_CAPACITY_UNIT'.freeze
 end
 
 module Hbase
@@ -102,39 +111,124 @@ module Hbase
 
     def unthrottle(args)
       raise(ArgumentError, 'Arguments should be a Hash') unless args.is_a?(Hash)
-      if args.key?(USER)
-        user = args.delete(USER)
-        if args.key?(TABLE)
-          table = TableName.valueOf(args.delete(TABLE))
-          raise(ArgumentError, 'Unexpected arguments: ' + args.inspect) unless args.empty?
-          settings = QuotaSettingsFactory.unthrottleUser(user, table)
-        elsif args.key?(NAMESPACE)
-          namespace = args.delete(NAMESPACE)
-          raise(ArgumentError, 'Unexpected arguments: ' + args.inspect) unless args.empty?
-          settings = QuotaSettingsFactory.unthrottleUser(user, namespace)
-        else
-          raise(ArgumentError, 'Unexpected arguments: ' + args.inspect) unless args.empty?
-          settings = QuotaSettingsFactory.unthrottleUser(user)
-        end
-      elsif args.key?(TABLE)
-        table = TableName.valueOf(args.delete(TABLE))
-        raise(ArgumentError, 'Unexpected arguments: ' + args.inspect) unless args.empty?
-        settings = QuotaSettingsFactory.unthrottleTable(table)
-      elsif args.key?(NAMESPACE)
-        namespace = args.delete(NAMESPACE)
-        raise(ArgumentError, 'Unexpected arguments: ' + args.inspect) unless args.empty?
-        settings = QuotaSettingsFactory.unthrottleNamespace(namespace)
+
+      if args.key?(USER) then settings = unthrottle_user_table_namespace(args)
+      elsif args.key?(TABLE) then settings = unthrottle_table(args)
+      elsif args.key?(NAMESPACE) then settings = unthrottle_namespace(args)
       elsif args.key?(REGIONSERVER)
-        regionServer = args.delete(REGIONSERVER)
-        raise(ArgumentError, 'Unexpected arguments: ' + args.inspect) unless args.empty?
-        # TODO: Setting specified region server quota isn't supported currently and using 'all' for all RS
-        settings = QuotaSettingsFactory.unthrottleRegionServer('all')
+        settings = unthrottle_regionserver(args)
       else
         raise 'One of USER, TABLE, NAMESPACE or REGIONSERVER must be specified'
       end
       @admin.setQuota(settings)
     end
 
+    def _parse_throttle_type(type_cls, throttle_type)
+      type_cls.valueOf(throttle_type)
+    end
+
+    def get_throttle_type(args)
+      throttle_type_str = args.delete(THROTTLE_TYPE)
+      throttle_type = _parse_throttle_type(ThrottleType, throttle_type_str)
+      throttle_type
+    end
+
+    def unthrottle_user_table_namespace(args)
+      user = args.delete(USER)
+      settings = if args.key?(TABLE)
+                   unthrottle_user_table(args, user)
+                 elsif args.key?(NAMESPACE)
+                   unthrottle_user_namespace(args, user)
+                 else
+                   unthrottle_user(args, user)
+                 end
+      settings
+    end
+
+    def args_empty(args)
+      return if args.empty?
+
+      raise(ArgumentError,
+            'Unexpected arguments: ' + args.inspect)
+    end
+
+    def unthrottle_user_table(args, user)
+      table = TableName.valueOf(args.delete(TABLE))
+      if args.key?(THROTTLE_TYPE)
+        settings = QuotaSettingsFactory
+                   .unthrottleUserByThrottleType(user,
+                                                 table, get_throttle_type(args))
+      else
+        args_empty(args)
+        settings = QuotaSettingsFactory.unthrottleUser(user, table)
+      end
+      settings
+    end
+
+    def unthrottle_user_namespace(args, user)
+      namespace = args.delete(NAMESPACE)
+      if args.key?(THROTTLE_TYPE)
+        throttle_type = get_throttle_type(args)
+        settings = QuotaSettingsFactory
+                   .unthrottleUserByThrottleType(user, namespace, throttle_type)
+      else
+        args_empty(args)
+        settings = QuotaSettingsFactory.unthrottleUser(user, namespace)
+      end
+      settings
+    end
+
+    def unthrottle_user(args, user)
+      if args.key?(THROTTLE_TYPE)
+        throttle_type = get_throttle_type(args)
+        settings = QuotaSettingsFactory
+                   .unthrottleUserByThrottleType(user, throttle_type)
+      else
+        args_empty(args)
+        settings = QuotaSettingsFactory.unthrottleUser(user)
+      end
+      settings
+    end
+
+    def unthrottle_table(args)
+      table = TableName.valueOf(args.delete(TABLE))
+      if args.key?(THROTTLE_TYPE)
+        throttle_type = get_throttle_type(args)
+        settings = QuotaSettingsFactory
+                   .unthrottleTableByThrottleType(table, throttle_type)
+      else
+        args_empty(args)
+        settings = QuotaSettingsFactory.unthrottleTable(table)
+      end
+      settings
+    end
+
+    def unthrottle_namespace(args)
+      namespace = args.delete(NAMESPACE)
+      if args.key?(THROTTLE_TYPE)
+        throttle_type = get_throttle_type(args)
+        settings = QuotaSettingsFactory
+                   .unthrottleNamespaceByThrottleType(namespace, throttle_type)
+      else
+        args_empty(args)
+        settings = QuotaSettingsFactory.unthrottleNamespace(namespace)
+      end
+      settings
+    end
+
+    def unthrottle_regionserver(args)
+      _region_server = args.delete(REGIONSERVER)
+      if args.key?(THROTTLE_TYPE)
+        throttle_type = get_throttle_type(args)
+        settings = QuotaSettingsFactory
+                   .unthrottleRegionServerByThrottleType('all', throttle_type)
+      else
+        args_empty(args)
+        settings = QuotaSettingsFactory.unthrottleRegionServer('all')
+      end
+      settings
+    end
+
     # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
     # rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity
     def limit_space(args)