HBASE-21713 Support set region server throttle quota
Signed-off-by: Guanghao Zhang <zghao@apache.org>
This commit is contained in:
parent
54093b0d1f
commit
281558a3ab
|
@ -33,6 +33,7 @@ public class QuotaFilter {
|
||||||
private String namespaceRegex;
|
private String namespaceRegex;
|
||||||
private String tableRegex;
|
private String tableRegex;
|
||||||
private String userRegex;
|
private String userRegex;
|
||||||
|
private String regionServerRegex;
|
||||||
|
|
||||||
public QuotaFilter() {
|
public QuotaFilter() {
|
||||||
}
|
}
|
||||||
|
@ -70,6 +71,17 @@ public class QuotaFilter {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the region server filter regex
|
||||||
|
* @param regex the region server filter
|
||||||
|
* @return the quota filter object
|
||||||
|
*/
|
||||||
|
public QuotaFilter setRegionServerFilter(final String regex) {
|
||||||
|
this.regionServerRegex = regex;
|
||||||
|
hasFilters |= StringUtils.isNotEmpty(regex);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a type to the filter list
|
* Add a type to the filter list
|
||||||
* @param type the type to filter on
|
* @param type the type to filter on
|
||||||
|
@ -105,4 +117,9 @@ public class QuotaFilter {
|
||||||
public String getUserFilter() {
|
public String getUserFilter() {
|
||||||
return userRegex;
|
return userRegex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return the RegionServer filter regex */
|
||||||
|
public String getRegionServerFilter() {
|
||||||
|
return regionServerRegex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,24 +22,26 @@ import java.util.Objects;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.apache.hadoop.hbase.TableName;
|
import org.apache.hadoop.hbase.TableName;
|
||||||
|
import org.apache.hadoop.hbase.quotas.QuotaSettingsFactory.QuotaGlobalsSettingsBypass;
|
||||||
import org.apache.yetus.audience.InterfaceAudience;
|
import org.apache.yetus.audience.InterfaceAudience;
|
||||||
|
|
||||||
import org.apache.hbase.thirdparty.com.google.protobuf.TextFormat;
|
import org.apache.hbase.thirdparty.com.google.protobuf.TextFormat;
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
|
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetQuotaRequest;
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetQuotaRequest;
|
||||||
import org.apache.hadoop.hbase.quotas.QuotaSettingsFactory.QuotaGlobalsSettingsBypass;
|
|
||||||
|
|
||||||
@InterfaceAudience.Public
|
@InterfaceAudience.Public
|
||||||
public abstract class QuotaSettings {
|
public abstract class QuotaSettings {
|
||||||
private final String userName;
|
private final String userName;
|
||||||
private final String namespace;
|
private final String namespace;
|
||||||
private final TableName tableName;
|
private final TableName tableName;
|
||||||
|
private final String regionServer;
|
||||||
|
|
||||||
protected QuotaSettings(final String userName, final TableName tableName,
|
protected QuotaSettings(final String userName, final TableName tableName, final String namespace,
|
||||||
final String namespace) {
|
final String regionServer) {
|
||||||
this.userName = userName;
|
this.userName = userName;
|
||||||
this.namespace = namespace;
|
this.namespace = namespace;
|
||||||
this.tableName = tableName;
|
this.tableName = tableName;
|
||||||
|
this.regionServer = regionServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract QuotaType getQuotaType();
|
public abstract QuotaType getQuotaType();
|
||||||
|
@ -56,6 +58,10 @@ public abstract class QuotaSettings {
|
||||||
return namespace;
|
return namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getRegionServer() {
|
||||||
|
return regionServer;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the protocol buffer request into a QuotaSetting POJO. Arbitrarily
|
* Converts the protocol buffer request into a QuotaSetting POJO. Arbitrarily
|
||||||
* enforces that the request only contain one "limit", despite the message
|
* enforces that the request only contain one "limit", despite the message
|
||||||
|
@ -78,6 +84,10 @@ public abstract class QuotaSettings {
|
||||||
if (request.hasNamespace()) {
|
if (request.hasNamespace()) {
|
||||||
namespace = request.getNamespace();
|
namespace = request.getNamespace();
|
||||||
}
|
}
|
||||||
|
String regionServer = null;
|
||||||
|
if (request.hasRegionServer()) {
|
||||||
|
regionServer = request.getRegionServer();
|
||||||
|
}
|
||||||
if (request.hasBypassGlobals()) {
|
if (request.hasBypassGlobals()) {
|
||||||
// Make sure we don't have either of the two below limits also included
|
// Make sure we don't have either of the two below limits also included
|
||||||
if (request.hasSpaceLimit() || request.hasThrottle()) {
|
if (request.hasSpaceLimit() || request.hasThrottle()) {
|
||||||
|
@ -85,7 +95,7 @@ public abstract class QuotaSettings {
|
||||||
"SetQuotaRequest has multiple limits: " + TextFormat.shortDebugString(request));
|
"SetQuotaRequest has multiple limits: " + TextFormat.shortDebugString(request));
|
||||||
}
|
}
|
||||||
return new QuotaGlobalsSettingsBypass(
|
return new QuotaGlobalsSettingsBypass(
|
||||||
username, tableName, namespace, request.getBypassGlobals());
|
username, tableName, namespace, regionServer, request.getBypassGlobals());
|
||||||
} else if (request.hasSpaceLimit()) {
|
} else if (request.hasSpaceLimit()) {
|
||||||
// Make sure we don't have the below limit as well
|
// Make sure we don't have the below limit as well
|
||||||
if (request.hasThrottle()) {
|
if (request.hasThrottle()) {
|
||||||
|
@ -100,7 +110,8 @@ public abstract class QuotaSettings {
|
||||||
return QuotaSettingsFactory.fromSpace(
|
return QuotaSettingsFactory.fromSpace(
|
||||||
tableName, namespace, request.getSpaceLimit().getQuota());
|
tableName, namespace, request.getSpaceLimit().getQuota());
|
||||||
} else if (request.hasThrottle()) {
|
} else if (request.hasThrottle()) {
|
||||||
return new ThrottleSettings(username, tableName, namespace, request.getThrottle());
|
return new ThrottleSettings(username, tableName, namespace, regionServer,
|
||||||
|
request.getThrottle());
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Unhandled SetRequestRequest state");
|
throw new IllegalStateException("Unhandled SetRequestRequest state");
|
||||||
}
|
}
|
||||||
|
@ -123,6 +134,9 @@ public abstract class QuotaSettings {
|
||||||
if (settings.getNamespace() != null) {
|
if (settings.getNamespace() != null) {
|
||||||
builder.setNamespace(settings.getNamespace());
|
builder.setNamespace(settings.getNamespace());
|
||||||
}
|
}
|
||||||
|
if (settings.getRegionServer() != null) {
|
||||||
|
builder.setRegionServer(settings.getRegionServer());
|
||||||
|
}
|
||||||
settings.setupSetQuotaRequest(builder);
|
settings.setupSetQuotaRequest(builder);
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
@ -152,6 +166,9 @@ public abstract class QuotaSettings {
|
||||||
builder.append(namespace);
|
builder.append(namespace);
|
||||||
builder.append("', ");
|
builder.append("', ");
|
||||||
}
|
}
|
||||||
|
if (regionServer != null) {
|
||||||
|
builder.append("REGIONSERVER => ").append(regionServer).append(", ");
|
||||||
|
}
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,5 +220,8 @@ public abstract class QuotaSettings {
|
||||||
if (!Objects.equals(getNamespace(), mergee.getNamespace())) {
|
if (!Objects.equals(getNamespace(), mergee.getNamespace())) {
|
||||||
throw new IllegalArgumentException("Mismatched namespace on settings to merge");
|
throw new IllegalArgumentException("Mismatched namespace on settings to merge");
|
||||||
}
|
}
|
||||||
|
if (!Objects.equals(getRegionServer(), mergee.getRegionServer())) {
|
||||||
|
throw new IllegalArgumentException("Mismatched region server on settings to merge");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,8 @@ import java.util.concurrent.TimeUnit;
|
||||||
import org.apache.hadoop.hbase.TableName;
|
import org.apache.hadoop.hbase.TableName;
|
||||||
import org.apache.yetus.audience.InterfaceAudience;
|
import org.apache.yetus.audience.InterfaceAudience;
|
||||||
|
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetQuotaRequest;
|
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
|
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
|
||||||
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetQuotaRequest;
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos;
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos;
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Quotas;
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Quotas;
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.SpaceQuota;
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.SpaceQuota;
|
||||||
|
@ -37,8 +37,8 @@ public class QuotaSettingsFactory {
|
||||||
private final boolean bypassGlobals;
|
private final boolean bypassGlobals;
|
||||||
|
|
||||||
QuotaGlobalsSettingsBypass(final String userName, final TableName tableName,
|
QuotaGlobalsSettingsBypass(final String userName, final TableName tableName,
|
||||||
final String namespace, final boolean bypassGlobals) {
|
final String namespace, final String regionServer, final boolean bypassGlobals) {
|
||||||
super(userName, tableName, namespace);
|
super(userName, tableName, namespace, regionServer);
|
||||||
this.bypassGlobals = bypassGlobals;
|
this.bypassGlobals = bypassGlobals;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,35 +80,42 @@ public class QuotaSettingsFactory {
|
||||||
* QuotaSettings from the Quotas object
|
* QuotaSettings from the Quotas object
|
||||||
*/
|
*/
|
||||||
static List<QuotaSettings> fromUserQuotas(final String userName, final Quotas quotas) {
|
static List<QuotaSettings> fromUserQuotas(final String userName, final Quotas quotas) {
|
||||||
return fromQuotas(userName, null, null, quotas);
|
return fromQuotas(userName, null, null, null, quotas);
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<QuotaSettings> fromUserQuotas(final String userName, final TableName tableName,
|
static List<QuotaSettings> fromUserQuotas(final String userName, final TableName tableName,
|
||||||
final Quotas quotas) {
|
final Quotas quotas) {
|
||||||
return fromQuotas(userName, tableName, null, quotas);
|
return fromQuotas(userName, tableName, null, null, quotas);
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<QuotaSettings> fromUserQuotas(final String userName, final String namespace,
|
static List<QuotaSettings> fromUserQuotas(final String userName, final String namespace,
|
||||||
final Quotas quotas) {
|
final Quotas quotas) {
|
||||||
return fromQuotas(userName, null, namespace, quotas);
|
return fromQuotas(userName, null, namespace, null, quotas);
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<QuotaSettings> fromTableQuotas(final TableName tableName, final Quotas quotas) {
|
static List<QuotaSettings> fromTableQuotas(final TableName tableName, final Quotas quotas) {
|
||||||
return fromQuotas(null, tableName, null, quotas);
|
return fromQuotas(null, tableName, null, null, quotas);
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<QuotaSettings> fromNamespaceQuotas(final String namespace, final Quotas quotas) {
|
static List<QuotaSettings> fromNamespaceQuotas(final String namespace, final Quotas quotas) {
|
||||||
return fromQuotas(null, null, namespace, quotas);
|
return fromQuotas(null, null, namespace, null, quotas);
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<QuotaSettings> fromRegionServerQuotas(final String regionServer,
|
||||||
|
final Quotas quotas) {
|
||||||
|
return fromQuotas(null, null, null, regionServer, quotas);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<QuotaSettings> fromQuotas(final String userName, final TableName tableName,
|
private static List<QuotaSettings> fromQuotas(final String userName, final TableName tableName,
|
||||||
final String namespace, final Quotas quotas) {
|
final String namespace, final String regionServer, final Quotas quotas) {
|
||||||
List<QuotaSettings> settings = new ArrayList<>();
|
List<QuotaSettings> settings = new ArrayList<>();
|
||||||
if (quotas.hasThrottle()) {
|
if (quotas.hasThrottle()) {
|
||||||
settings.addAll(fromThrottle(userName, tableName, namespace, quotas.getThrottle()));
|
settings
|
||||||
|
.addAll(fromThrottle(userName, tableName, namespace, regionServer, quotas.getThrottle()));
|
||||||
}
|
}
|
||||||
if (quotas.getBypassGlobals() == true) {
|
if (quotas.getBypassGlobals() == true) {
|
||||||
settings.add(new QuotaGlobalsSettingsBypass(userName, tableName, namespace, true));
|
settings
|
||||||
|
.add(new QuotaGlobalsSettingsBypass(userName, tableName, namespace, regionServer, true));
|
||||||
}
|
}
|
||||||
if (quotas.hasSpace()) {
|
if (quotas.hasSpace()) {
|
||||||
settings.add(fromSpace(tableName, namespace, quotas.getSpace()));
|
settings.add(fromSpace(tableName, namespace, quotas.getSpace()));
|
||||||
|
@ -116,43 +123,44 @@ public class QuotaSettingsFactory {
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static List<QuotaSettings> fromThrottle(final String userName, final TableName tableName,
|
protected static List<QuotaSettings> fromThrottle(final String userName,
|
||||||
final String namespace, final QuotaProtos.Throttle throttle) {
|
final TableName tableName, final String namespace, final String regionServer,
|
||||||
|
final QuotaProtos.Throttle throttle) {
|
||||||
List<QuotaSettings> settings = new ArrayList<>();
|
List<QuotaSettings> settings = new ArrayList<>();
|
||||||
if (throttle.hasReqNum()) {
|
if (throttle.hasReqNum()) {
|
||||||
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace,
|
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
|
||||||
ThrottleType.REQUEST_NUMBER, throttle.getReqNum()));
|
ThrottleType.REQUEST_NUMBER, throttle.getReqNum()));
|
||||||
}
|
}
|
||||||
if (throttle.hasReqSize()) {
|
if (throttle.hasReqSize()) {
|
||||||
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace,
|
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
|
||||||
ThrottleType.REQUEST_SIZE, throttle.getReqSize()));
|
ThrottleType.REQUEST_SIZE, throttle.getReqSize()));
|
||||||
}
|
}
|
||||||
if (throttle.hasWriteNum()) {
|
if (throttle.hasWriteNum()) {
|
||||||
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace,
|
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
|
||||||
ThrottleType.WRITE_NUMBER, throttle.getWriteNum()));
|
ThrottleType.WRITE_NUMBER, throttle.getWriteNum()));
|
||||||
}
|
}
|
||||||
if (throttle.hasWriteSize()) {
|
if (throttle.hasWriteSize()) {
|
||||||
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace,
|
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
|
||||||
ThrottleType.WRITE_SIZE, throttle.getWriteSize()));
|
ThrottleType.WRITE_SIZE, throttle.getWriteSize()));
|
||||||
}
|
}
|
||||||
if (throttle.hasReadNum()) {
|
if (throttle.hasReadNum()) {
|
||||||
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace,
|
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
|
||||||
ThrottleType.READ_NUMBER, throttle.getReadNum()));
|
ThrottleType.READ_NUMBER, throttle.getReadNum()));
|
||||||
}
|
}
|
||||||
if (throttle.hasReadSize()) {
|
if (throttle.hasReadSize()) {
|
||||||
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace,
|
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
|
||||||
ThrottleType.READ_SIZE, throttle.getReadSize()));
|
ThrottleType.READ_SIZE, throttle.getReadSize()));
|
||||||
}
|
}
|
||||||
if (throttle.hasReqCapacityUnit()) {
|
if (throttle.hasReqCapacityUnit()) {
|
||||||
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace,
|
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
|
||||||
ThrottleType.REQUEST_CAPACITY_UNIT, throttle.getReqCapacityUnit()));
|
ThrottleType.REQUEST_CAPACITY_UNIT, throttle.getReqCapacityUnit()));
|
||||||
}
|
}
|
||||||
if (throttle.hasReadCapacityUnit()) {
|
if (throttle.hasReadCapacityUnit()) {
|
||||||
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace,
|
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
|
||||||
ThrottleType.READ_CAPACITY_UNIT, throttle.getReadCapacityUnit()));
|
ThrottleType.READ_CAPACITY_UNIT, throttle.getReadCapacityUnit()));
|
||||||
}
|
}
|
||||||
if (throttle.hasWriteCapacityUnit()) {
|
if (throttle.hasWriteCapacityUnit()) {
|
||||||
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace,
|
settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
|
||||||
ThrottleType.WRITE_CAPACITY_UNIT, throttle.getWriteCapacityUnit()));
|
ThrottleType.WRITE_CAPACITY_UNIT, throttle.getWriteCapacityUnit()));
|
||||||
}
|
}
|
||||||
return settings;
|
return settings;
|
||||||
|
@ -195,7 +203,7 @@ public class QuotaSettingsFactory {
|
||||||
*/
|
*/
|
||||||
public static QuotaSettings throttleUser(final String userName, final ThrottleType type,
|
public static QuotaSettings throttleUser(final String userName, final ThrottleType type,
|
||||||
final long limit, final TimeUnit timeUnit) {
|
final long limit, final TimeUnit timeUnit) {
|
||||||
return throttle(userName, null, null, type, limit, timeUnit);
|
return throttle(userName, null, null, null, type, limit, timeUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -210,7 +218,7 @@ public class QuotaSettingsFactory {
|
||||||
*/
|
*/
|
||||||
public static QuotaSettings throttleUser(final String userName, final TableName tableName,
|
public static QuotaSettings throttleUser(final String userName, final TableName tableName,
|
||||||
final ThrottleType type, final long limit, final TimeUnit timeUnit) {
|
final ThrottleType type, final long limit, final TimeUnit timeUnit) {
|
||||||
return throttle(userName, tableName, null, type, limit, timeUnit);
|
return throttle(userName, tableName, null, null, type, limit, timeUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -225,7 +233,7 @@ public class QuotaSettingsFactory {
|
||||||
*/
|
*/
|
||||||
public static QuotaSettings throttleUser(final String userName, final String namespace,
|
public static QuotaSettings throttleUser(final String userName, final String namespace,
|
||||||
final ThrottleType type, final long limit, final TimeUnit timeUnit) {
|
final ThrottleType type, final long limit, final TimeUnit timeUnit) {
|
||||||
return throttle(userName, null, namespace, type, limit, timeUnit);
|
return throttle(userName, null, namespace, null, type, limit, timeUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -235,7 +243,7 @@ public class QuotaSettingsFactory {
|
||||||
* @return the quota settings
|
* @return the quota settings
|
||||||
*/
|
*/
|
||||||
public static QuotaSettings unthrottleUser(final String userName) {
|
public static QuotaSettings unthrottleUser(final String userName) {
|
||||||
return throttle(userName, null, null, null, 0, null);
|
return throttle(userName, null, null, null, null, 0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -246,7 +254,7 @@ public class QuotaSettingsFactory {
|
||||||
* @return the quota settings
|
* @return the quota settings
|
||||||
*/
|
*/
|
||||||
public static QuotaSettings unthrottleUser(final String userName, final TableName tableName) {
|
public static QuotaSettings unthrottleUser(final String userName, final TableName tableName) {
|
||||||
return throttle(userName, tableName, null, null, 0, null);
|
return throttle(userName, tableName, null, null, null, 0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -257,7 +265,7 @@ public class QuotaSettingsFactory {
|
||||||
* @return the quota settings
|
* @return the quota settings
|
||||||
*/
|
*/
|
||||||
public static QuotaSettings unthrottleUser(final String userName, final String namespace) {
|
public static QuotaSettings unthrottleUser(final String userName, final String namespace) {
|
||||||
return throttle(userName, null, namespace, null, 0, null);
|
return throttle(userName, null, namespace, null, null, 0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -271,7 +279,7 @@ public class QuotaSettingsFactory {
|
||||||
*/
|
*/
|
||||||
public static QuotaSettings throttleTable(final TableName tableName, final ThrottleType type,
|
public static QuotaSettings throttleTable(final TableName tableName, final ThrottleType type,
|
||||||
final long limit, final TimeUnit timeUnit) {
|
final long limit, final TimeUnit timeUnit) {
|
||||||
return throttle(null, tableName, null, type, limit, timeUnit);
|
return throttle(null, tableName, null, null, type, limit, timeUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -281,7 +289,7 @@ public class QuotaSettingsFactory {
|
||||||
* @return the quota settings
|
* @return the quota settings
|
||||||
*/
|
*/
|
||||||
public static QuotaSettings unthrottleTable(final TableName tableName) {
|
public static QuotaSettings unthrottleTable(final TableName tableName) {
|
||||||
return throttle(null, tableName, null, null, 0, null);
|
return throttle(null, tableName, null, null, null, 0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -295,7 +303,7 @@ public class QuotaSettingsFactory {
|
||||||
*/
|
*/
|
||||||
public static QuotaSettings throttleNamespace(final String namespace, final ThrottleType type,
|
public static QuotaSettings throttleNamespace(final String namespace, final ThrottleType type,
|
||||||
final long limit, final TimeUnit timeUnit) {
|
final long limit, final TimeUnit timeUnit) {
|
||||||
return throttle(null, null, namespace, type, limit, timeUnit);
|
return throttle(null, null, namespace, null, type, limit, timeUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -305,12 +313,36 @@ public class QuotaSettingsFactory {
|
||||||
* @return the quota settings
|
* @return the quota settings
|
||||||
*/
|
*/
|
||||||
public static QuotaSettings unthrottleNamespace(final String namespace) {
|
public static QuotaSettings unthrottleNamespace(final String namespace) {
|
||||||
return throttle(null, null, namespace, null, 0, null);
|
return throttle(null, null, namespace, null, null, 0, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throttle the specified region server.
|
||||||
|
*
|
||||||
|
* @param regionServer the region server to throttle
|
||||||
|
* @param type the type of throttling
|
||||||
|
* @param limit the allowed number of request/data per timeUnit
|
||||||
|
* @param timeUnit the limit time unit
|
||||||
|
* @return the quota settings
|
||||||
|
*/
|
||||||
|
public static QuotaSettings throttleRegionServer(final String regionServer,
|
||||||
|
final ThrottleType type, final long limit, final TimeUnit timeUnit) {
|
||||||
|
return throttle(null, null, null, regionServer, type, limit, timeUnit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the throttling for the specified region server.
|
||||||
|
*
|
||||||
|
* @param regionServer the region Server
|
||||||
|
* @return the quota settings
|
||||||
|
*/
|
||||||
|
public static QuotaSettings unthrottleRegionServer(final String regionServer) {
|
||||||
|
return throttle(null, null, null, regionServer, null, 0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Throttle helper */
|
/* Throttle helper */
|
||||||
private static QuotaSettings throttle(final String userName, final TableName tableName,
|
private static QuotaSettings throttle(final String userName, final TableName tableName,
|
||||||
final String namespace, final ThrottleType type, final long limit,
|
final String namespace, final String regionServer, final ThrottleType type, final long limit,
|
||||||
final TimeUnit timeUnit) {
|
final TimeUnit timeUnit) {
|
||||||
QuotaProtos.ThrottleRequest.Builder builder = QuotaProtos.ThrottleRequest.newBuilder();
|
QuotaProtos.ThrottleRequest.Builder builder = QuotaProtos.ThrottleRequest.newBuilder();
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
|
@ -319,7 +351,7 @@ public class QuotaSettingsFactory {
|
||||||
if (timeUnit != null) {
|
if (timeUnit != null) {
|
||||||
builder.setTimedQuota(ProtobufUtil.toTimedQuota(limit, timeUnit, QuotaScope.MACHINE));
|
builder.setTimedQuota(ProtobufUtil.toTimedQuota(limit, timeUnit, QuotaScope.MACHINE));
|
||||||
}
|
}
|
||||||
return new ThrottleSettings(userName, tableName, namespace, builder.build());
|
return new ThrottleSettings(userName, tableName, namespace, regionServer, builder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
|
@ -334,7 +366,7 @@ public class QuotaSettingsFactory {
|
||||||
* @return the quota settings
|
* @return the quota settings
|
||||||
*/
|
*/
|
||||||
public static QuotaSettings bypassGlobals(final String userName, final boolean bypassGlobals) {
|
public static QuotaSettings bypassGlobals(final String userName, final boolean bypassGlobals) {
|
||||||
return new QuotaGlobalsSettingsBypass(userName, null, null, bypassGlobals);
|
return new QuotaGlobalsSettingsBypass(userName, null, null, null, bypassGlobals);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
|
|
|
@ -99,6 +99,13 @@ public class QuotaTableUtil {
|
||||||
protected static final byte[] QUOTA_USER_ROW_KEY_PREFIX = Bytes.toBytes("u.");
|
protected static final byte[] QUOTA_USER_ROW_KEY_PREFIX = Bytes.toBytes("u.");
|
||||||
protected static final byte[] QUOTA_TABLE_ROW_KEY_PREFIX = Bytes.toBytes("t.");
|
protected static final byte[] QUOTA_TABLE_ROW_KEY_PREFIX = Bytes.toBytes("t.");
|
||||||
protected static final byte[] QUOTA_NAMESPACE_ROW_KEY_PREFIX = Bytes.toBytes("n.");
|
protected static final byte[] QUOTA_NAMESPACE_ROW_KEY_PREFIX = Bytes.toBytes("n.");
|
||||||
|
protected static final byte[] QUOTA_REGION_SERVER_ROW_KEY_PREFIX = Bytes.toBytes("r.");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Setting specified region server quota isn't supported currently and the row key "r.all"
|
||||||
|
* represents the throttle quota of all region servers
|
||||||
|
*/
|
||||||
|
public static final String QUOTA_REGION_SERVER_ROW_KEY = "all";
|
||||||
|
|
||||||
/* =========================================================================
|
/* =========================================================================
|
||||||
* Quota "settings" helpers
|
* Quota "settings" helpers
|
||||||
|
@ -134,6 +141,11 @@ public class QuotaTableUtil {
|
||||||
return getQuotas(connection, rowKey, QUOTA_QUALIFIER_SETTINGS);
|
return getQuotas(connection, rowKey, QUOTA_QUALIFIER_SETTINGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Quotas getRegionServerQuota(final Connection connection, final String regionServer)
|
||||||
|
throws IOException {
|
||||||
|
return getQuotas(connection, getRegionServerRowKey(regionServer));
|
||||||
|
}
|
||||||
|
|
||||||
private static Quotas getQuotas(final Connection connection, final byte[] rowKey,
|
private static Quotas getQuotas(final Connection connection, final byte[] rowKey,
|
||||||
final byte[] qualifier) throws IOException {
|
final byte[] qualifier) throws IOException {
|
||||||
Get get = new Get(rowKey);
|
Get get = new Get(rowKey);
|
||||||
|
@ -157,6 +169,12 @@ public class QuotaTableUtil {
|
||||||
return get;
|
return get;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Get makeGetForRegionServerQuotas(final String regionServer) {
|
||||||
|
Get get = new Get(getRegionServerRowKey(regionServer));
|
||||||
|
get.addFamily(QUOTA_FAMILY_INFO);
|
||||||
|
return get;
|
||||||
|
}
|
||||||
|
|
||||||
public static Get makeGetForUserQuotas(final String user, final Iterable<TableName> tables,
|
public static Get makeGetForUserQuotas(final String user, final Iterable<TableName> tables,
|
||||||
final Iterable<String> namespaces) {
|
final Iterable<String> namespaces) {
|
||||||
Get get = new Get(getUserRowKey(user));
|
Get get = new Get(getUserRowKey(user));
|
||||||
|
@ -220,6 +238,9 @@ public class QuotaTableUtil {
|
||||||
} else if (StringUtils.isNotEmpty(filter.getNamespaceFilter())) {
|
} else if (StringUtils.isNotEmpty(filter.getNamespaceFilter())) {
|
||||||
filterList.addFilter(new RowFilter(CompareOperator.EQUAL,
|
filterList.addFilter(new RowFilter(CompareOperator.EQUAL,
|
||||||
new RegexStringComparator(getNamespaceRowKeyRegex(filter.getNamespaceFilter()), 0)));
|
new RegexStringComparator(getNamespaceRowKeyRegex(filter.getNamespaceFilter()), 0)));
|
||||||
|
} else if (StringUtils.isNotEmpty(filter.getRegionServerFilter())) {
|
||||||
|
filterList.addFilter(new RowFilter(CompareOperator.EQUAL, new RegexStringComparator(
|
||||||
|
getRegionServerRowKeyRegex(filter.getRegionServerFilter()), 0)));
|
||||||
}
|
}
|
||||||
return filterList;
|
return filterList;
|
||||||
}
|
}
|
||||||
|
@ -318,8 +339,13 @@ public class QuotaTableUtil {
|
||||||
throws IOException;
|
throws IOException;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static interface QuotasVisitor extends UserQuotasVisitor,
|
private static interface RegionServerQuotasVisitor {
|
||||||
TableQuotasVisitor, NamespaceQuotasVisitor {
|
void visitRegionServerQuotas(final String regionServer, final Quotas quotas)
|
||||||
|
throws IOException;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface QuotasVisitor extends UserQuotasVisitor, TableQuotasVisitor,
|
||||||
|
NamespaceQuotasVisitor, RegionServerQuotasVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void parseResult(final Result result, final QuotasVisitor visitor)
|
public static void parseResult(final Result result, final QuotasVisitor visitor)
|
||||||
|
@ -331,6 +357,8 @@ public class QuotaTableUtil {
|
||||||
parseTableResult(result, visitor);
|
parseTableResult(result, visitor);
|
||||||
} else if (isUserRowKey(row)) {
|
} else if (isUserRowKey(row)) {
|
||||||
parseUserResult(result, visitor);
|
parseUserResult(result, visitor);
|
||||||
|
} else if (isRegionServerRowKey(row)) {
|
||||||
|
parseRegionServerResult(result, visitor);
|
||||||
} else {
|
} else {
|
||||||
LOG.warn("unexpected row-key: " + Bytes.toString(row));
|
LOG.warn("unexpected row-key: " + Bytes.toString(row));
|
||||||
}
|
}
|
||||||
|
@ -364,6 +392,11 @@ public class QuotaTableUtil {
|
||||||
public void visitNamespaceQuotas(String namespace, Quotas quotas) {
|
public void visitNamespaceQuotas(String namespace, Quotas quotas) {
|
||||||
quotaSettings.addAll(QuotaSettingsFactory.fromNamespaceQuotas(namespace, quotas));
|
quotaSettings.addAll(QuotaSettingsFactory.fromNamespaceQuotas(namespace, quotas));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitRegionServerQuotas(String regionServer, Quotas quotas) {
|
||||||
|
quotaSettings.addAll(QuotaSettingsFactory.fromRegionServerQuotas(regionServer, quotas));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,6 +415,21 @@ public class QuotaTableUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void parseRegionServerResult(final Result result,
|
||||||
|
final RegionServerQuotasVisitor visitor) throws IOException {
|
||||||
|
String rs = getRegionServerFromRowKey(result.getRow());
|
||||||
|
parseRegionServerResult(rs, result, visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parseRegionServerResult(final String regionServer, final Result result,
|
||||||
|
final RegionServerQuotasVisitor visitor) throws IOException {
|
||||||
|
byte[] data = result.getValue(QUOTA_FAMILY_INFO, QUOTA_QUALIFIER_SETTINGS);
|
||||||
|
if (data != null) {
|
||||||
|
Quotas quotas = quotasFromData(data);
|
||||||
|
visitor.visitRegionServerQuotas(regionServer, quotas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void parseTableResult(final Result result, final TableQuotasVisitor visitor)
|
public static void parseTableResult(final Result result, final TableQuotasVisitor visitor)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
TableName table = getTableFromRowKey(result.getRow());
|
TableName table = getTableFromRowKey(result.getRow());
|
||||||
|
@ -621,6 +669,10 @@ public class QuotaTableUtil {
|
||||||
return Bytes.add(QUOTA_NAMESPACE_ROW_KEY_PREFIX, Bytes.toBytes(namespace));
|
return Bytes.add(QUOTA_NAMESPACE_ROW_KEY_PREFIX, Bytes.toBytes(namespace));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static byte[] getRegionServerRowKey(final String regionServer) {
|
||||||
|
return Bytes.add(QUOTA_REGION_SERVER_ROW_KEY_PREFIX, Bytes.toBytes(regionServer));
|
||||||
|
}
|
||||||
|
|
||||||
protected static byte[] getSettingsQualifierForUserTable(final TableName tableName) {
|
protected static byte[] getSettingsQualifierForUserTable(final TableName tableName) {
|
||||||
return Bytes.add(QUOTA_QUALIFIER_SETTINGS_PREFIX, tableName.getName());
|
return Bytes.add(QUOTA_QUALIFIER_SETTINGS_PREFIX, tableName.getName());
|
||||||
}
|
}
|
||||||
|
@ -642,6 +694,10 @@ public class QuotaTableUtil {
|
||||||
return getRowKeyRegEx(QUOTA_NAMESPACE_ROW_KEY_PREFIX, namespace);
|
return getRowKeyRegEx(QUOTA_NAMESPACE_ROW_KEY_PREFIX, namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getRegionServerRowKeyRegex(final String regionServer) {
|
||||||
|
return getRowKeyRegEx(QUOTA_REGION_SERVER_ROW_KEY_PREFIX, regionServer);
|
||||||
|
}
|
||||||
|
|
||||||
private static String getRowKeyRegEx(final byte[] prefix, final String regex) {
|
private static String getRowKeyRegEx(final byte[] prefix, final String regex) {
|
||||||
return '^' + Pattern.quote(Bytes.toString(prefix)) + regex + '$';
|
return '^' + Pattern.quote(Bytes.toString(prefix)) + regex + '$';
|
||||||
}
|
}
|
||||||
|
@ -664,6 +720,14 @@ public class QuotaTableUtil {
|
||||||
return Bytes.toString(key, QUOTA_NAMESPACE_ROW_KEY_PREFIX.length);
|
return Bytes.toString(key, QUOTA_NAMESPACE_ROW_KEY_PREFIX.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static boolean isRegionServerRowKey(final byte[] key) {
|
||||||
|
return Bytes.startsWith(key, QUOTA_REGION_SERVER_ROW_KEY_PREFIX);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String getRegionServerFromRowKey(final byte[] key) {
|
||||||
|
return Bytes.toString(key, QUOTA_REGION_SERVER_ROW_KEY_PREFIX.length);
|
||||||
|
}
|
||||||
|
|
||||||
protected static boolean isTableRowKey(final byte[] key) {
|
protected static boolean isTableRowKey(final byte[] key) {
|
||||||
return Bytes.startsWith(key, QUOTA_TABLE_ROW_KEY_PREFIX);
|
return Bytes.startsWith(key, QUOTA_TABLE_ROW_KEY_PREFIX);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ class SpaceLimitSettings extends QuotaSettings {
|
||||||
private final SpaceLimitRequest proto;
|
private final SpaceLimitRequest proto;
|
||||||
|
|
||||||
SpaceLimitSettings(TableName tableName, long sizeLimit, SpaceViolationPolicy violationPolicy) {
|
SpaceLimitSettings(TableName tableName, long sizeLimit, SpaceViolationPolicy violationPolicy) {
|
||||||
super(null, Objects.requireNonNull(tableName), null);
|
super(null, Objects.requireNonNull(tableName), null, null);
|
||||||
validateSizeLimit(sizeLimit);
|
validateSizeLimit(sizeLimit);
|
||||||
proto = buildProtoAddQuota(sizeLimit, Objects.requireNonNull(violationPolicy));
|
proto = buildProtoAddQuota(sizeLimit, Objects.requireNonNull(violationPolicy));
|
||||||
}
|
}
|
||||||
|
@ -46,12 +46,12 @@ class SpaceLimitSettings extends QuotaSettings {
|
||||||
* Constructs a {@code SpaceLimitSettings} to remove a space quota on the given {@code tableName}.
|
* Constructs a {@code SpaceLimitSettings} to remove a space quota on the given {@code tableName}.
|
||||||
*/
|
*/
|
||||||
SpaceLimitSettings(TableName tableName) {
|
SpaceLimitSettings(TableName tableName) {
|
||||||
super(null, Objects.requireNonNull(tableName), null);
|
super(null, Objects.requireNonNull(tableName), null, null);
|
||||||
proto = buildProtoRemoveQuota();
|
proto = buildProtoRemoveQuota();
|
||||||
}
|
}
|
||||||
|
|
||||||
SpaceLimitSettings(String namespace, long sizeLimit, SpaceViolationPolicy violationPolicy) {
|
SpaceLimitSettings(String namespace, long sizeLimit, SpaceViolationPolicy violationPolicy) {
|
||||||
super(null, null, Objects.requireNonNull(namespace));
|
super(null, null, Objects.requireNonNull(namespace), null);
|
||||||
validateSizeLimit(sizeLimit);
|
validateSizeLimit(sizeLimit);
|
||||||
proto = buildProtoAddQuota(sizeLimit, Objects.requireNonNull(violationPolicy));
|
proto = buildProtoAddQuota(sizeLimit, Objects.requireNonNull(violationPolicy));
|
||||||
}
|
}
|
||||||
|
@ -60,12 +60,12 @@ class SpaceLimitSettings extends QuotaSettings {
|
||||||
* Constructs a {@code SpaceLimitSettings} to remove a space quota on the given {@code namespace}.
|
* Constructs a {@code SpaceLimitSettings} to remove a space quota on the given {@code namespace}.
|
||||||
*/
|
*/
|
||||||
SpaceLimitSettings(String namespace) {
|
SpaceLimitSettings(String namespace) {
|
||||||
super(null, null, Objects.requireNonNull(namespace));
|
super(null, null, Objects.requireNonNull(namespace), null);
|
||||||
proto = buildProtoRemoveQuota();
|
proto = buildProtoRemoveQuota();
|
||||||
}
|
}
|
||||||
|
|
||||||
SpaceLimitSettings(TableName tableName, String namespace, SpaceLimitRequest req) {
|
SpaceLimitSettings(TableName tableName, String namespace, SpaceLimitRequest req) {
|
||||||
super(null, tableName, namespace);
|
super(null, tableName, namespace, null);
|
||||||
proto = req;
|
proto = req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,19 +25,19 @@ import org.apache.hadoop.hbase.TableName;
|
||||||
import org.apache.yetus.audience.InterfaceAudience;
|
import org.apache.yetus.audience.InterfaceAudience;
|
||||||
import org.apache.yetus.audience.InterfaceStability;
|
import org.apache.yetus.audience.InterfaceStability;
|
||||||
import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
|
import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetQuotaRequest;
|
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.TimedQuota;
|
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
|
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
|
||||||
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetQuotaRequest;
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos;
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos;
|
||||||
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.TimedQuota;
|
||||||
|
|
||||||
@InterfaceAudience.Private
|
@InterfaceAudience.Private
|
||||||
@InterfaceStability.Evolving
|
@InterfaceStability.Evolving
|
||||||
class ThrottleSettings extends QuotaSettings {
|
class ThrottleSettings extends QuotaSettings {
|
||||||
final QuotaProtos.ThrottleRequest proto;
|
final QuotaProtos.ThrottleRequest proto;
|
||||||
|
|
||||||
ThrottleSettings(final String userName, final TableName tableName,
|
ThrottleSettings(final String userName, final TableName tableName, final String namespace,
|
||||||
final String namespace, final QuotaProtos.ThrottleRequest proto) {
|
final String regionServer, final QuotaProtos.ThrottleRequest proto) {
|
||||||
super(userName, tableName, namespace);
|
super(userName, tableName, namespace, regionServer);
|
||||||
this.proto = proto;
|
this.proto = proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +146,8 @@ class ThrottleSettings extends QuotaSettings {
|
||||||
|
|
||||||
QuotaProtos.ThrottleRequest mergedReq = builder.setTimedQuota(
|
QuotaProtos.ThrottleRequest mergedReq = builder.setTimedQuota(
|
||||||
timedQuotaBuilder.build()).build();
|
timedQuotaBuilder.build()).build();
|
||||||
return new ThrottleSettings(getUserName(), getTableName(), getNamespace(), mergedReq);
|
return new ThrottleSettings(getUserName(), getTableName(), getNamespace(),
|
||||||
|
getRegionServer(), mergedReq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
@ -159,12 +160,12 @@ class ThrottleSettings extends QuotaSettings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ThrottleSettings fromTimedQuota(final String userName,
|
static ThrottleSettings fromTimedQuota(final String userName, final TableName tableName,
|
||||||
final TableName tableName, final String namespace,
|
final String namespace, final String regionServer, ThrottleType type,
|
||||||
ThrottleType type, QuotaProtos.TimedQuota timedQuota) {
|
QuotaProtos.TimedQuota timedQuota) {
|
||||||
QuotaProtos.ThrottleRequest.Builder builder = QuotaProtos.ThrottleRequest.newBuilder();
|
QuotaProtos.ThrottleRequest.Builder builder = QuotaProtos.ThrottleRequest.newBuilder();
|
||||||
builder.setType(ProtobufUtil.toProtoThrottleType(type));
|
builder.setType(ProtobufUtil.toProtoThrottleType(type));
|
||||||
builder.setTimedQuota(timedQuota);
|
builder.setTimedQuota(timedQuota);
|
||||||
return new ThrottleSettings(userName, tableName, namespace, builder.build());
|
return new ThrottleSettings(userName, tableName, namespace, regionServer, builder.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,67 +39,103 @@ public class TestQuotaGlobalsSettingsBypass {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMerge() throws IOException {
|
public void testMerge() throws IOException {
|
||||||
QuotaGlobalsSettingsBypass orig = new QuotaGlobalsSettingsBypass("joe", null, null, true);
|
QuotaGlobalsSettingsBypass orig = new QuotaGlobalsSettingsBypass("joe", null, null, null, true);
|
||||||
assertFalse(orig.merge(new QuotaGlobalsSettingsBypass(
|
assertFalse(
|
||||||
"joe", null, null, false)).getBypass());
|
orig.merge(new QuotaGlobalsSettingsBypass("joe", null, null, null, false)).getBypass());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInvalidMerges() throws IOException {
|
public void testInvalidMerges() throws IOException {
|
||||||
QuotaGlobalsSettingsBypass userBypass = new QuotaGlobalsSettingsBypass(
|
QuotaGlobalsSettingsBypass userBypass =
|
||||||
"joe", null, null, true);
|
new QuotaGlobalsSettingsBypass("joe", null, null, null, true);
|
||||||
QuotaGlobalsSettingsBypass tableBypass = new QuotaGlobalsSettingsBypass(
|
QuotaGlobalsSettingsBypass tableBypass =
|
||||||
null, TableName.valueOf("table"), null, true);
|
new QuotaGlobalsSettingsBypass(null, TableName.valueOf("table"), null, null, true);
|
||||||
QuotaGlobalsSettingsBypass namespaceBypass = new QuotaGlobalsSettingsBypass(
|
QuotaGlobalsSettingsBypass namespaceBypass =
|
||||||
null, null, "ns", true);
|
new QuotaGlobalsSettingsBypass(null, null, "ns", null, true);
|
||||||
QuotaGlobalsSettingsBypass userOnTableBypass = new QuotaGlobalsSettingsBypass(
|
QuotaGlobalsSettingsBypass regionServerBypass =
|
||||||
"joe", TableName.valueOf("table"), null, true);
|
new QuotaGlobalsSettingsBypass(null, null, null, "all", true);
|
||||||
QuotaGlobalsSettingsBypass userOnNamespaceBypass = new QuotaGlobalsSettingsBypass(
|
QuotaGlobalsSettingsBypass userOnTableBypass =
|
||||||
"joe", null, "ns", true);
|
new QuotaGlobalsSettingsBypass("joe", TableName.valueOf("table"), null, null, true);
|
||||||
|
QuotaGlobalsSettingsBypass userOnNamespaceBypass =
|
||||||
|
new QuotaGlobalsSettingsBypass("joe", null, "ns", null, true);
|
||||||
|
QuotaGlobalsSettingsBypass userOnRegionServerBypass =
|
||||||
|
new QuotaGlobalsSettingsBypass("joe", null, null, "all", true);
|
||||||
|
|
||||||
assertTrue(userBypass.merge(userBypass).getBypass());
|
assertTrue(userBypass.merge(userBypass).getBypass());
|
||||||
expectFailure(userBypass, new QuotaGlobalsSettingsBypass("frank", null, null, false));
|
expectFailure(userBypass, new QuotaGlobalsSettingsBypass("frank", null, null, null, false));
|
||||||
expectFailure(userBypass, tableBypass);
|
expectFailure(userBypass, tableBypass);
|
||||||
expectFailure(userBypass, namespaceBypass);
|
expectFailure(userBypass, namespaceBypass);
|
||||||
|
expectFailure(userBypass, regionServerBypass);
|
||||||
expectFailure(userBypass, userOnTableBypass);
|
expectFailure(userBypass, userOnTableBypass);
|
||||||
expectFailure(userBypass, userOnNamespaceBypass);
|
expectFailure(userBypass, userOnNamespaceBypass);
|
||||||
|
expectFailure(userBypass, userOnRegionServerBypass);
|
||||||
|
|
||||||
assertTrue(tableBypass.merge(tableBypass).getBypass());
|
assertTrue(tableBypass.merge(tableBypass).getBypass());
|
||||||
expectFailure(tableBypass, userBypass);
|
expectFailure(tableBypass, userBypass);
|
||||||
expectFailure(tableBypass, new QuotaGlobalsSettingsBypass(
|
expectFailure(tableBypass,
|
||||||
null, TableName.valueOf("foo"), null, false));
|
new QuotaGlobalsSettingsBypass(null, TableName.valueOf("foo"), null, null, false));
|
||||||
expectFailure(tableBypass, namespaceBypass);
|
expectFailure(tableBypass, namespaceBypass);
|
||||||
|
expectFailure(tableBypass, regionServerBypass);
|
||||||
expectFailure(tableBypass, userOnTableBypass);
|
expectFailure(tableBypass, userOnTableBypass);
|
||||||
expectFailure(tableBypass, userOnNamespaceBypass);
|
expectFailure(tableBypass, userOnNamespaceBypass);
|
||||||
|
expectFailure(tableBypass, userOnRegionServerBypass);
|
||||||
|
|
||||||
assertTrue(namespaceBypass.merge(namespaceBypass).getBypass());
|
assertTrue(namespaceBypass.merge(namespaceBypass).getBypass());
|
||||||
expectFailure(namespaceBypass, userBypass);
|
expectFailure(namespaceBypass, userBypass);
|
||||||
expectFailure(namespaceBypass, tableBypass);
|
expectFailure(namespaceBypass, tableBypass);
|
||||||
expectFailure(namespaceBypass, new QuotaGlobalsSettingsBypass(null, null, "sn", false));
|
expectFailure(namespaceBypass, regionServerBypass);
|
||||||
|
expectFailure(namespaceBypass, new QuotaGlobalsSettingsBypass(null, null, "sn", null, false));
|
||||||
expectFailure(namespaceBypass, userOnTableBypass);
|
expectFailure(namespaceBypass, userOnTableBypass);
|
||||||
expectFailure(namespaceBypass, userOnNamespaceBypass);
|
expectFailure(namespaceBypass, userOnNamespaceBypass);
|
||||||
|
expectFailure(namespaceBypass, userOnNamespaceBypass);
|
||||||
|
|
||||||
|
assertTrue(regionServerBypass.merge(regionServerBypass).getBypass());
|
||||||
|
expectFailure(regionServerBypass, userBypass);
|
||||||
|
expectFailure(regionServerBypass, tableBypass);
|
||||||
|
expectFailure(regionServerBypass, namespaceBypass);
|
||||||
|
expectFailure(regionServerBypass,
|
||||||
|
new QuotaGlobalsSettingsBypass(null, null, null, "rs", false));
|
||||||
|
expectFailure(regionServerBypass, userOnTableBypass);
|
||||||
|
expectFailure(regionServerBypass, userOnNamespaceBypass);
|
||||||
|
expectFailure(regionServerBypass, userOnRegionServerBypass);
|
||||||
|
|
||||||
assertTrue(userOnTableBypass.merge(userOnTableBypass).getBypass());
|
assertTrue(userOnTableBypass.merge(userOnTableBypass).getBypass());
|
||||||
expectFailure(userOnTableBypass, userBypass);
|
expectFailure(userOnTableBypass, userBypass);
|
||||||
expectFailure(userOnTableBypass, tableBypass);
|
expectFailure(userOnTableBypass, tableBypass);
|
||||||
expectFailure(userOnTableBypass, namespaceBypass);
|
expectFailure(userOnTableBypass, namespaceBypass);
|
||||||
|
expectFailure(userOnTableBypass, regionServerBypass);
|
||||||
// Incorrect user
|
// Incorrect user
|
||||||
expectFailure(userOnTableBypass, new QuotaGlobalsSettingsBypass(
|
expectFailure(userOnTableBypass,
|
||||||
"frank", TableName.valueOf("foo"), null, false));
|
new QuotaGlobalsSettingsBypass("frank", TableName.valueOf("foo"), null, null, false));
|
||||||
// Incorrect tablename
|
// Incorrect tablename
|
||||||
expectFailure(userOnTableBypass, new QuotaGlobalsSettingsBypass(
|
expectFailure(userOnTableBypass,
|
||||||
"joe", TableName.valueOf("bar"), null, false));
|
new QuotaGlobalsSettingsBypass("joe", TableName.valueOf("bar"), null, null, false));
|
||||||
expectFailure(userOnTableBypass, userOnNamespaceBypass);
|
expectFailure(userOnTableBypass, userOnNamespaceBypass);
|
||||||
|
expectFailure(userOnTableBypass, userOnRegionServerBypass);
|
||||||
|
|
||||||
assertTrue(userOnNamespaceBypass.merge(userOnNamespaceBypass).getBypass());
|
assertTrue(userOnNamespaceBypass.merge(userOnNamespaceBypass).getBypass());
|
||||||
expectFailure(userOnNamespaceBypass, userBypass);
|
expectFailure(userOnNamespaceBypass, userBypass);
|
||||||
expectFailure(userOnNamespaceBypass, tableBypass);
|
expectFailure(userOnNamespaceBypass, tableBypass);
|
||||||
expectFailure(userOnNamespaceBypass, namespaceBypass);
|
expectFailure(userOnNamespaceBypass, namespaceBypass);
|
||||||
|
expectFailure(userOnNamespaceBypass, regionServerBypass);
|
||||||
expectFailure(userOnNamespaceBypass, userOnTableBypass);
|
expectFailure(userOnNamespaceBypass, userOnTableBypass);
|
||||||
expectFailure(userOnNamespaceBypass, new QuotaGlobalsSettingsBypass(
|
expectFailure(userOnNamespaceBypass,
|
||||||
"frank", null, "ns", false));
|
new QuotaGlobalsSettingsBypass("frank", null, "ns", null, false));
|
||||||
expectFailure(userOnNamespaceBypass, new QuotaGlobalsSettingsBypass(
|
expectFailure(userOnNamespaceBypass,
|
||||||
"joe", null, "sn", false));
|
new QuotaGlobalsSettingsBypass("joe", null, "sn", null, false));
|
||||||
|
expectFailure(userOnNamespaceBypass, userOnRegionServerBypass);
|
||||||
|
|
||||||
|
assertTrue(userOnRegionServerBypass.merge(userOnRegionServerBypass).getBypass());
|
||||||
|
expectFailure(userOnRegionServerBypass, userBypass);
|
||||||
|
expectFailure(userOnRegionServerBypass, tableBypass);
|
||||||
|
expectFailure(userOnRegionServerBypass, namespaceBypass);
|
||||||
|
expectFailure(userOnRegionServerBypass, regionServerBypass);
|
||||||
|
expectFailure(userOnRegionServerBypass, userOnTableBypass);
|
||||||
|
expectFailure(userOnRegionServerBypass, userOnNamespaceBypass);
|
||||||
|
expectFailure(userOnRegionServerBypass,
|
||||||
|
new QuotaGlobalsSettingsBypass("frank", null, null, "all", false));
|
||||||
|
expectFailure(userOnRegionServerBypass,
|
||||||
|
new QuotaGlobalsSettingsBypass("joe", null, null, "rs", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
void expectFailure(QuotaSettings one, QuotaSettings two) throws IOException {
|
void expectFailure(QuotaSettings one, QuotaSettings two) throws IOException {
|
||||||
|
|
|
@ -87,6 +87,7 @@ public class TestQuotaSettingsFactory {
|
||||||
assertEquals(tn, throttleSettings.getTableName());
|
assertEquals(tn, throttleSettings.getTableName());
|
||||||
assertNull("Username should be null", throttleSettings.getUserName());
|
assertNull("Username should be null", throttleSettings.getUserName());
|
||||||
assertNull("Namespace should be null", throttleSettings.getNamespace());
|
assertNull("Namespace should be null", throttleSettings.getNamespace());
|
||||||
|
assertNull("RegionServer should be null", throttleSettings.getRegionServer());
|
||||||
seenRead = true;
|
seenRead = true;
|
||||||
break;
|
break;
|
||||||
case WRITE_NUMBER:
|
case WRITE_NUMBER:
|
||||||
|
@ -96,6 +97,7 @@ public class TestQuotaSettingsFactory {
|
||||||
assertEquals(tn, throttleSettings.getTableName());
|
assertEquals(tn, throttleSettings.getTableName());
|
||||||
assertNull("Username should be null", throttleSettings.getUserName());
|
assertNull("Username should be null", throttleSettings.getUserName());
|
||||||
assertNull("Namespace should be null", throttleSettings.getNamespace());
|
assertNull("Namespace should be null", throttleSettings.getNamespace());
|
||||||
|
assertNull("RegionServer should be null", throttleSettings.getRegionServer());
|
||||||
seenWrite = true;
|
seenWrite = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -107,6 +109,7 @@ public class TestQuotaSettingsFactory {
|
||||||
assertEquals(tn, spaceLimit.getTableName());
|
assertEquals(tn, spaceLimit.getTableName());
|
||||||
assertNull("Username should be null", spaceLimit.getUserName());
|
assertNull("Username should be null", spaceLimit.getUserName());
|
||||||
assertNull("Namespace should be null", spaceLimit.getNamespace());
|
assertNull("Namespace should be null", spaceLimit.getNamespace());
|
||||||
|
assertNull("RegionServer should be null", spaceLimit.getRegionServer());
|
||||||
assertTrue("SpaceLimitSettings should have a SpaceQuota", spaceLimit.getProto().hasQuota());
|
assertTrue("SpaceLimitSettings should have a SpaceQuota", spaceLimit.getProto().hasQuota());
|
||||||
assertEquals(spaceQuota, spaceLimit.getProto().getQuota());
|
assertEquals(spaceQuota, spaceLimit.getProto().getQuota());
|
||||||
seenSpace = true;
|
seenSpace = true;
|
||||||
|
|
|
@ -48,7 +48,7 @@ public class TestThrottleSettings {
|
||||||
.setTimeUnit(HBaseProtos.TimeUnit.MINUTES).build();
|
.setTimeUnit(HBaseProtos.TimeUnit.MINUTES).build();
|
||||||
ThrottleRequest tr1 = ThrottleRequest.newBuilder().setTimedQuota(tq1)
|
ThrottleRequest tr1 = ThrottleRequest.newBuilder().setTimedQuota(tq1)
|
||||||
.setType(QuotaProtos.ThrottleType.REQUEST_NUMBER).build();
|
.setType(QuotaProtos.ThrottleType.REQUEST_NUMBER).build();
|
||||||
ThrottleSettings orig = new ThrottleSettings("joe", null, null, tr1);
|
ThrottleSettings orig = new ThrottleSettings("joe", null, null, null, tr1);
|
||||||
|
|
||||||
TimedQuota tq2 = TimedQuota.newBuilder().setSoftLimit(10)
|
TimedQuota tq2 = TimedQuota.newBuilder().setSoftLimit(10)
|
||||||
.setScope(QuotaProtos.QuotaScope.MACHINE)
|
.setScope(QuotaProtos.QuotaScope.MACHINE)
|
||||||
|
@ -56,7 +56,7 @@ public class TestThrottleSettings {
|
||||||
ThrottleRequest tr2 = ThrottleRequest.newBuilder().setTimedQuota(tq2)
|
ThrottleRequest tr2 = ThrottleRequest.newBuilder().setTimedQuota(tq2)
|
||||||
.setType(QuotaProtos.ThrottleType.REQUEST_NUMBER).build();
|
.setType(QuotaProtos.ThrottleType.REQUEST_NUMBER).build();
|
||||||
|
|
||||||
ThrottleSettings merged = orig.merge(new ThrottleSettings("joe", null, null, tr2));
|
ThrottleSettings merged = orig.merge(new ThrottleSettings("joe", null, null, null, tr2));
|
||||||
|
|
||||||
assertEquals(10, merged.getSoftLimit());
|
assertEquals(10, merged.getSoftLimit());
|
||||||
assertEquals(ThrottleType.REQUEST_NUMBER, merged.getThrottleType());
|
assertEquals(ThrottleType.REQUEST_NUMBER, merged.getThrottleType());
|
||||||
|
@ -70,7 +70,7 @@ public class TestThrottleSettings {
|
||||||
.setTimeUnit(HBaseProtos.TimeUnit.MINUTES).build();
|
.setTimeUnit(HBaseProtos.TimeUnit.MINUTES).build();
|
||||||
ThrottleRequest requestsQuotaReq = ThrottleRequest.newBuilder().setTimedQuota(requestsQuota)
|
ThrottleRequest requestsQuotaReq = ThrottleRequest.newBuilder().setTimedQuota(requestsQuota)
|
||||||
.setType(QuotaProtos.ThrottleType.REQUEST_NUMBER).build();
|
.setType(QuotaProtos.ThrottleType.REQUEST_NUMBER).build();
|
||||||
ThrottleSettings orig = new ThrottleSettings("joe", null, null, requestsQuotaReq);
|
ThrottleSettings orig = new ThrottleSettings("joe", null, null, null, requestsQuotaReq);
|
||||||
|
|
||||||
TimedQuota readsQuota = TimedQuota.newBuilder().setSoftLimit(10)
|
TimedQuota readsQuota = TimedQuota.newBuilder().setSoftLimit(10)
|
||||||
.setScope(QuotaProtos.QuotaScope.MACHINE)
|
.setScope(QuotaProtos.QuotaScope.MACHINE)
|
||||||
|
@ -79,7 +79,7 @@ public class TestThrottleSettings {
|
||||||
.setType(QuotaProtos.ThrottleType.READ_NUMBER).build();
|
.setType(QuotaProtos.ThrottleType.READ_NUMBER).build();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
orig.merge(new ThrottleSettings("joe", null, null, readsQuotaReq));
|
orig.merge(new ThrottleSettings("joe", null, null, null, readsQuotaReq));
|
||||||
fail("A read throttle should not be capable of being merged with a request quota");
|
fail("A read throttle should not be capable of being merged with a request quota");
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
// Pass
|
// Pass
|
||||||
|
@ -93,13 +93,13 @@ public class TestThrottleSettings {
|
||||||
.setTimeUnit(HBaseProtos.TimeUnit.MINUTES).build();
|
.setTimeUnit(HBaseProtos.TimeUnit.MINUTES).build();
|
||||||
ThrottleRequest tr1 = ThrottleRequest.newBuilder().setTimedQuota(tq1)
|
ThrottleRequest tr1 = ThrottleRequest.newBuilder().setTimedQuota(tq1)
|
||||||
.setType(QuotaProtos.ThrottleType.REQUEST_NUMBER).build();
|
.setType(QuotaProtos.ThrottleType.REQUEST_NUMBER).build();
|
||||||
ThrottleSettings orig = new ThrottleSettings("joe", null, null, tr1);
|
ThrottleSettings orig = new ThrottleSettings("joe", null, null, null, tr1);
|
||||||
|
|
||||||
ThrottleRequest tr2 = ThrottleRequest.newBuilder()
|
ThrottleRequest tr2 = ThrottleRequest.newBuilder()
|
||||||
.setType(QuotaProtos.ThrottleType.REQUEST_NUMBER).build();
|
.setType(QuotaProtos.ThrottleType.REQUEST_NUMBER).build();
|
||||||
|
|
||||||
assertTrue(
|
assertTrue(
|
||||||
"The same object should be returned by merge, but it wasn't",
|
"The same object should be returned by merge, but it wasn't",
|
||||||
orig == orig.merge(new ThrottleSettings("joe", null, null, tr2)));
|
orig == orig.merge(new ThrottleSettings("joe", null, null, null, tr2)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -572,6 +572,7 @@ message SetQuotaRequest {
|
||||||
optional ThrottleRequest throttle = 7;
|
optional ThrottleRequest throttle = 7;
|
||||||
|
|
||||||
optional SpaceLimitRequest space_limit = 8;
|
optional SpaceLimitRequest space_limit = 8;
|
||||||
|
optional string region_server = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SetQuotaResponse {
|
message SetQuotaResponse {
|
||||||
|
|
|
@ -1092,6 +1092,24 @@ public interface MasterObserver {
|
||||||
default void postSetNamespaceQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx,
|
default void postSetNamespaceQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx,
|
||||||
final String namespace, final GlobalQuotaSettings quotas) throws IOException {}
|
final String namespace, final GlobalQuotaSettings quotas) throws IOException {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called before the quota for the region server is stored.
|
||||||
|
* @param ctx the environment to interact with the framework and master
|
||||||
|
* @param regionServer the name of the region server
|
||||||
|
* @param quotas the current quota for the region server
|
||||||
|
*/
|
||||||
|
default void preSetRegionServerQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx,
|
||||||
|
final String regionServer, final GlobalQuotaSettings quotas) throws IOException {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after the quota for the region server is stored.
|
||||||
|
* @param ctx the environment to interact with the framework and master
|
||||||
|
* @param regionServer the name of the region server
|
||||||
|
* @param quotas the resulting quota for the region server
|
||||||
|
*/
|
||||||
|
default void postSetRegionServerQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx,
|
||||||
|
final String regionServer, final GlobalQuotaSettings quotas) throws IOException {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called before merge regions request.
|
* Called before merge regions request.
|
||||||
* @param ctx coprocessor environment
|
* @param ctx coprocessor environment
|
||||||
|
|
|
@ -1285,6 +1285,26 @@ public class MasterCoprocessorHost
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void preSetRegionServerQuota(final String regionServer, final GlobalQuotaSettings quotas)
|
||||||
|
throws IOException {
|
||||||
|
execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {
|
||||||
|
@Override
|
||||||
|
public void call(MasterObserver observer) throws IOException {
|
||||||
|
observer.preSetRegionServerQuota(this, regionServer, quotas);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postSetRegionServerQuota(final String regionServer, final GlobalQuotaSettings quotas)
|
||||||
|
throws IOException {
|
||||||
|
execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {
|
||||||
|
@Override
|
||||||
|
public void call(MasterObserver observer) throws IOException {
|
||||||
|
observer.postSetRegionServerQuota(this, regionServer, quotas);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void preMoveServersAndTables(final Set<Address> servers, final Set<TableName> tables,
|
public void preMoveServersAndTables(final Set<Address> servers, final Set<TableName> tables,
|
||||||
final String targetGroup) throws IOException {
|
final String targetGroup) throws IOException {
|
||||||
execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {
|
execOperation(coprocEnvironments.isEmpty() ? null : new MasterObserverOperation() {
|
||||||
|
|
|
@ -35,8 +35,9 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Quotas;
|
||||||
@InterfaceStability.Evolving
|
@InterfaceStability.Evolving
|
||||||
public abstract class GlobalQuotaSettings extends QuotaSettings {
|
public abstract class GlobalQuotaSettings extends QuotaSettings {
|
||||||
|
|
||||||
protected GlobalQuotaSettings(String userName, TableName tableName, String namespace) {
|
protected GlobalQuotaSettings(String userName, TableName tableName, String namespace,
|
||||||
super(userName, tableName, namespace);
|
String regionServer) {
|
||||||
|
super(userName, tableName, namespace, regionServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -27,13 +27,14 @@ import java.util.Map.Entry;
|
||||||
import org.apache.hadoop.hbase.DoNotRetryIOException;
|
import org.apache.hadoop.hbase.DoNotRetryIOException;
|
||||||
import org.apache.hadoop.hbase.TableName;
|
import org.apache.hadoop.hbase.TableName;
|
||||||
import org.apache.hadoop.hbase.quotas.QuotaSettingsFactory.QuotaGlobalsSettingsBypass;
|
import org.apache.hadoop.hbase.quotas.QuotaSettingsFactory.QuotaGlobalsSettingsBypass;
|
||||||
|
import org.apache.yetus.audience.InterfaceAudience;
|
||||||
|
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
|
import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos;
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos;
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Quotas;
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Quotas;
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.SpaceQuota;
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.SpaceQuota;
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Throttle;
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Throttle;
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.TimedQuota;
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.TimedQuota;
|
||||||
import org.apache.yetus.audience.InterfaceAudience;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of {@link GlobalQuotaSettings} to hide the Protobuf messages we use internally.
|
* Implementation of {@link GlobalQuotaSettings} to hide the Protobuf messages we use internally.
|
||||||
|
@ -45,18 +46,18 @@ public class GlobalQuotaSettingsImpl extends GlobalQuotaSettings {
|
||||||
private final Boolean bypassGlobals;
|
private final Boolean bypassGlobals;
|
||||||
private final QuotaProtos.SpaceQuota spaceProto;
|
private final QuotaProtos.SpaceQuota spaceProto;
|
||||||
|
|
||||||
protected GlobalQuotaSettingsImpl(
|
protected GlobalQuotaSettingsImpl(String username, TableName tableName, String namespace,
|
||||||
String username, TableName tableName, String namespace, QuotaProtos.Quotas quotas) {
|
String regionServer, QuotaProtos.Quotas quotas) {
|
||||||
this(username, tableName, namespace,
|
this(username, tableName, namespace, regionServer,
|
||||||
(quotas != null && quotas.hasThrottle() ? quotas.getThrottle() : null),
|
(quotas != null && quotas.hasThrottle() ? quotas.getThrottle() : null),
|
||||||
(quotas != null && quotas.hasBypassGlobals() ? quotas.getBypassGlobals() : null),
|
(quotas != null && quotas.hasBypassGlobals() ? quotas.getBypassGlobals() : null),
|
||||||
(quotas != null && quotas.hasSpace() ? quotas.getSpace() : null));
|
(quotas != null && quotas.hasSpace() ? quotas.getSpace() : null));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected GlobalQuotaSettingsImpl(
|
protected GlobalQuotaSettingsImpl(String userName, TableName tableName, String namespace,
|
||||||
String userName, TableName tableName, String namespace, QuotaProtos.Throttle throttleProto,
|
String regionServer, QuotaProtos.Throttle throttleProto, Boolean bypassGlobals,
|
||||||
Boolean bypassGlobals, QuotaProtos.SpaceQuota spaceProto) {
|
QuotaProtos.SpaceQuota spaceProto) {
|
||||||
super(userName, tableName, namespace);
|
super(userName, tableName, namespace, regionServer);
|
||||||
this.throttleProto = throttleProto;
|
this.throttleProto = throttleProto;
|
||||||
this.bypassGlobals = bypassGlobals;
|
this.bypassGlobals = bypassGlobals;
|
||||||
this.spaceProto = spaceProto;
|
this.spaceProto = spaceProto;
|
||||||
|
@ -67,12 +68,12 @@ public class GlobalQuotaSettingsImpl extends GlobalQuotaSettings {
|
||||||
// Very similar to QuotaSettingsFactory
|
// Very similar to QuotaSettingsFactory
|
||||||
List<QuotaSettings> settings = new ArrayList<>();
|
List<QuotaSettings> settings = new ArrayList<>();
|
||||||
if (throttleProto != null) {
|
if (throttleProto != null) {
|
||||||
settings.addAll(QuotaSettingsFactory.fromThrottle(
|
settings.addAll(QuotaSettingsFactory.fromThrottle(getUserName(), getTableName(),
|
||||||
getUserName(), getTableName(), getNamespace(), throttleProto));
|
getNamespace(), getRegionServer(), throttleProto));
|
||||||
}
|
}
|
||||||
if (bypassGlobals != null && bypassGlobals.booleanValue()) {
|
if (bypassGlobals != null && bypassGlobals.booleanValue()) {
|
||||||
settings.add(new QuotaGlobalsSettingsBypass(
|
settings.add(new QuotaGlobalsSettingsBypass(getUserName(), getTableName(), getNamespace(),
|
||||||
getUserName(), getTableName(), getNamespace(), true));
|
getRegionServer(), true));
|
||||||
}
|
}
|
||||||
if (spaceProto != null) {
|
if (spaceProto != null) {
|
||||||
settings.add(QuotaSettingsFactory.fromSpace(getTableName(), getNamespace(), spaceProto));
|
settings.add(QuotaSettingsFactory.fromSpace(getTableName(), getNamespace(), spaceProto));
|
||||||
|
@ -210,7 +211,7 @@ public class GlobalQuotaSettingsImpl extends GlobalQuotaSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
return new GlobalQuotaSettingsImpl(
|
return new GlobalQuotaSettingsImpl(
|
||||||
getUserName(), getTableName(), getNamespace(),
|
getUserName(), getTableName(), getNamespace(), getRegionServer(),
|
||||||
(throttleBuilder == null ? null : throttleBuilder.build()), bypassGlobals,
|
(throttleBuilder == null ? null : throttleBuilder.build()), bypassGlobals,
|
||||||
(removeSpaceBuilder ? null : spaceBuilder.build()));
|
(removeSpaceBuilder ? null : spaceBuilder.build()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,7 @@ public class MasterQuotaManager implements RegionStateListener {
|
||||||
private NamedLock<String> namespaceLocks;
|
private NamedLock<String> namespaceLocks;
|
||||||
private NamedLock<TableName> tableLocks;
|
private NamedLock<TableName> tableLocks;
|
||||||
private NamedLock<String> userLocks;
|
private NamedLock<String> userLocks;
|
||||||
|
private NamedLock<String> regionServerLocks;
|
||||||
private boolean initialized = false;
|
private boolean initialized = false;
|
||||||
private NamespaceAuditor namespaceQuotaManager;
|
private NamespaceAuditor namespaceQuotaManager;
|
||||||
private ConcurrentHashMap<RegionInfo, SizeSnapshotWithTimestamp> regionSizes;
|
private ConcurrentHashMap<RegionInfo, SizeSnapshotWithTimestamp> regionSizes;
|
||||||
|
@ -110,6 +111,7 @@ public class MasterQuotaManager implements RegionStateListener {
|
||||||
namespaceLocks = new NamedLock<>();
|
namespaceLocks = new NamedLock<>();
|
||||||
tableLocks = new NamedLock<>();
|
tableLocks = new NamedLock<>();
|
||||||
userLocks = new NamedLock<>();
|
userLocks = new NamedLock<>();
|
||||||
|
regionServerLocks = new NamedLock<>();
|
||||||
regionSizes = new ConcurrentHashMap<>();
|
regionSizes = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
namespaceQuotaManager = new NamespaceAuditor(masterServices);
|
namespaceQuotaManager = new NamespaceAuditor(masterServices);
|
||||||
|
@ -162,9 +164,16 @@ public class MasterQuotaManager implements RegionStateListener {
|
||||||
} finally {
|
} finally {
|
||||||
namespaceLocks.unlock(req.getNamespace());
|
namespaceLocks.unlock(req.getNamespace());
|
||||||
}
|
}
|
||||||
|
} else if (req.hasRegionServer()) {
|
||||||
|
regionServerLocks.lock(req.getRegionServer());
|
||||||
|
try {
|
||||||
|
setRegionServerQuota(req.getRegionServer(), req);
|
||||||
|
} finally {
|
||||||
|
regionServerLocks.unlock(req.getRegionServer());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new DoNotRetryIOException(
|
throw new DoNotRetryIOException(new UnsupportedOperationException(
|
||||||
new UnsupportedOperationException("a user, a table or a namespace must be specified"));
|
"a user, a table, a namespace or region server must be specified"));
|
||||||
}
|
}
|
||||||
return SetQuotaResponse.newBuilder().build();
|
return SetQuotaResponse.newBuilder().build();
|
||||||
}
|
}
|
||||||
|
@ -174,8 +183,8 @@ public class MasterQuotaManager implements RegionStateListener {
|
||||||
setQuota(req, new SetQuotaOperations() {
|
setQuota(req, new SetQuotaOperations() {
|
||||||
@Override
|
@Override
|
||||||
public GlobalQuotaSettingsImpl fetch() throws IOException {
|
public GlobalQuotaSettingsImpl fetch() throws IOException {
|
||||||
return new GlobalQuotaSettingsImpl(req.getUserName(), null, null, QuotaUtil.getUserQuota(
|
return new GlobalQuotaSettingsImpl(req.getUserName(), null, null, null,
|
||||||
masterServices.getConnection(), userName));
|
QuotaUtil.getUserQuota(masterServices.getConnection(), userName));
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void update(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
public void update(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||||
|
@ -201,8 +210,8 @@ public class MasterQuotaManager implements RegionStateListener {
|
||||||
setQuota(req, new SetQuotaOperations() {
|
setQuota(req, new SetQuotaOperations() {
|
||||||
@Override
|
@Override
|
||||||
public GlobalQuotaSettingsImpl fetch() throws IOException {
|
public GlobalQuotaSettingsImpl fetch() throws IOException {
|
||||||
return new GlobalQuotaSettingsImpl(userName, table, null, QuotaUtil.getUserQuota(
|
return new GlobalQuotaSettingsImpl(userName, table, null, null,
|
||||||
masterServices.getConnection(), userName, table));
|
QuotaUtil.getUserQuota(masterServices.getConnection(), userName, table));
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void update(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
public void update(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||||
|
@ -229,8 +238,8 @@ public class MasterQuotaManager implements RegionStateListener {
|
||||||
setQuota(req, new SetQuotaOperations() {
|
setQuota(req, new SetQuotaOperations() {
|
||||||
@Override
|
@Override
|
||||||
public GlobalQuotaSettingsImpl fetch() throws IOException {
|
public GlobalQuotaSettingsImpl fetch() throws IOException {
|
||||||
return new GlobalQuotaSettingsImpl(userName, null, namespace, QuotaUtil.getUserQuota(
|
return new GlobalQuotaSettingsImpl(userName, null, namespace, null,
|
||||||
masterServices.getConnection(), userName, namespace));
|
QuotaUtil.getUserQuota(masterServices.getConnection(), userName, namespace));
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void update(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
public void update(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||||
|
@ -259,8 +268,8 @@ public class MasterQuotaManager implements RegionStateListener {
|
||||||
setQuota(req, new SetQuotaOperations() {
|
setQuota(req, new SetQuotaOperations() {
|
||||||
@Override
|
@Override
|
||||||
public GlobalQuotaSettingsImpl fetch() throws IOException {
|
public GlobalQuotaSettingsImpl fetch() throws IOException {
|
||||||
return new GlobalQuotaSettingsImpl(null, table, null, QuotaUtil.getTableQuota(
|
return new GlobalQuotaSettingsImpl(null, table, null, null,
|
||||||
masterServices.getConnection(), table));
|
QuotaUtil.getTableQuota(masterServices.getConnection(), table));
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void update(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
public void update(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||||
|
@ -286,8 +295,8 @@ public class MasterQuotaManager implements RegionStateListener {
|
||||||
setQuota(req, new SetQuotaOperations() {
|
setQuota(req, new SetQuotaOperations() {
|
||||||
@Override
|
@Override
|
||||||
public GlobalQuotaSettingsImpl fetch() throws IOException {
|
public GlobalQuotaSettingsImpl fetch() throws IOException {
|
||||||
return new GlobalQuotaSettingsImpl(null, null, namespace, QuotaUtil.getNamespaceQuota(
|
return new GlobalQuotaSettingsImpl(null, null, namespace, null,
|
||||||
masterServices.getConnection(), namespace));
|
QuotaUtil.getNamespaceQuota(masterServices.getConnection(), namespace));
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void update(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
public void update(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||||
|
@ -309,6 +318,38 @@ public class MasterQuotaManager implements RegionStateListener {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setRegionServerQuota(final String regionServer, final SetQuotaRequest req)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
setQuota(req, new SetQuotaOperations() {
|
||||||
|
@Override
|
||||||
|
public GlobalQuotaSettingsImpl fetch() throws IOException {
|
||||||
|
return new GlobalQuotaSettingsImpl(null, null, null, regionServer,
|
||||||
|
QuotaUtil.getRegionServerQuota(masterServices.getConnection(), regionServer));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||||
|
QuotaUtil.addRegionServerQuota(masterServices.getConnection(), regionServer,
|
||||||
|
((GlobalQuotaSettingsImpl) quotaPojo).toQuotas());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete() throws IOException {
|
||||||
|
QuotaUtil.deleteRegionServerQuota(masterServices.getConnection(), regionServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preApply(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||||
|
masterServices.getMasterCoprocessorHost().preSetRegionServerQuota(regionServer, quotaPojo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postApply(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||||
|
masterServices.getMasterCoprocessorHost().postSetRegionServerQuota(regionServer, quotaPojo);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void setNamespaceQuota(NamespaceDescriptor desc) throws IOException {
|
public void setNamespaceQuota(NamespaceDescriptor desc) throws IOException {
|
||||||
if (initialized) {
|
if (initialized) {
|
||||||
this.namespaceQuotaManager.addNamespace(desc);
|
this.namespaceQuotaManager.addNamespace(desc);
|
||||||
|
|
|
@ -34,14 +34,14 @@ import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.hbase.ScheduledChore;
|
import org.apache.hadoop.hbase.ScheduledChore;
|
||||||
import org.apache.hadoop.hbase.Stoppable;
|
import org.apache.hadoop.hbase.Stoppable;
|
||||||
import org.apache.hadoop.hbase.TableName;
|
import org.apache.hadoop.hbase.TableName;
|
||||||
import org.apache.yetus.audience.InterfaceAudience;
|
|
||||||
import org.apache.yetus.audience.InterfaceStability;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.apache.hadoop.hbase.client.Get;
|
import org.apache.hadoop.hbase.client.Get;
|
||||||
import org.apache.hadoop.hbase.regionserver.RegionServerServices;
|
import org.apache.hadoop.hbase.regionserver.RegionServerServices;
|
||||||
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
|
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
|
||||||
import org.apache.hadoop.security.UserGroupInformation;
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
|
import org.apache.yetus.audience.InterfaceAudience;
|
||||||
|
import org.apache.yetus.audience.InterfaceStability;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache that keeps track of the quota settings for the users and tables that
|
* Cache that keeps track of the quota settings for the users and tables that
|
||||||
|
@ -69,6 +69,8 @@ public class QuotaCache implements Stoppable {
|
||||||
private final ConcurrentHashMap<String, QuotaState> namespaceQuotaCache = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<String, QuotaState> namespaceQuotaCache = new ConcurrentHashMap<>();
|
||||||
private final ConcurrentHashMap<TableName, QuotaState> tableQuotaCache = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<TableName, QuotaState> tableQuotaCache = new ConcurrentHashMap<>();
|
||||||
private final ConcurrentHashMap<String, UserQuotaState> userQuotaCache = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<String, UserQuotaState> userQuotaCache = new ConcurrentHashMap<>();
|
||||||
|
private final ConcurrentHashMap<String, QuotaState> regionServerQuotaCache =
|
||||||
|
new ConcurrentHashMap<>();
|
||||||
private final RegionServerServices rsServices;
|
private final RegionServerServices rsServices;
|
||||||
|
|
||||||
private QuotaRefresherChore refreshChore;
|
private QuotaRefresherChore refreshChore;
|
||||||
|
@ -146,6 +148,16 @@ public class QuotaCache implements Stoppable {
|
||||||
return getQuotaState(this.namespaceQuotaCache, namespace).getGlobalLimiter();
|
return getQuotaState(this.namespaceQuotaCache, namespace).getGlobalLimiter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the limiter associated to the specified region server.
|
||||||
|
*
|
||||||
|
* @param regionServer the region server to limit
|
||||||
|
* @return the limiter associated to the specified region server
|
||||||
|
*/
|
||||||
|
public QuotaLimiter getRegionServerQuotaLimiter(final String regionServer) {
|
||||||
|
return getQuotaState(this.regionServerQuotaCache, regionServer).getGlobalLimiter();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the QuotaState requested. If the quota info is not in cache an empty one will be
|
* Returns the QuotaState requested. If the quota info is not in cache an empty one will be
|
||||||
* returned and the quota request will be enqueued for the next cache refresh.
|
* returned and the quota request will be enqueued for the next cache refresh.
|
||||||
|
@ -170,6 +182,11 @@ public class QuotaCache implements Stoppable {
|
||||||
return namespaceQuotaCache;
|
return namespaceQuotaCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
Map<String, QuotaState> getRegionServerQuotaCache() {
|
||||||
|
return regionServerQuotaCache;
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
Map<TableName, QuotaState> getTableQuotaCache() {
|
Map<TableName, QuotaState> getTableQuotaCache() {
|
||||||
return tableQuotaCache;
|
return tableQuotaCache;
|
||||||
|
@ -203,10 +220,13 @@ public class QuotaCache implements Stoppable {
|
||||||
QuotaCache.this.namespaceQuotaCache.putIfAbsent(ns, new QuotaState());
|
QuotaCache.this.namespaceQuotaCache.putIfAbsent(ns, new QuotaState());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
QuotaCache.this.regionServerQuotaCache.putIfAbsent(QuotaTableUtil.QUOTA_REGION_SERVER_ROW_KEY,
|
||||||
|
new QuotaState());
|
||||||
|
|
||||||
fetchNamespaceQuotaState();
|
fetchNamespaceQuotaState();
|
||||||
fetchTableQuotaState();
|
fetchTableQuotaState();
|
||||||
fetchUserQuotaState();
|
fetchUserQuotaState();
|
||||||
|
fetchRegionServerQuotaState();
|
||||||
lastUpdate = EnvironmentEdgeManager.currentTime();
|
lastUpdate = EnvironmentEdgeManager.currentTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,6 +277,21 @@ public class QuotaCache implements Stoppable {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fetchRegionServerQuotaState() {
|
||||||
|
fetch("regionServer", QuotaCache.this.regionServerQuotaCache,
|
||||||
|
new Fetcher<String, QuotaState>() {
|
||||||
|
@Override
|
||||||
|
public Get makeGet(final Map.Entry<String, QuotaState> entry) {
|
||||||
|
return QuotaUtil.makeGetForRegionServerQuotas(entry.getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, QuotaState> fetchEntries(final List<Get> gets) throws IOException {
|
||||||
|
return QuotaUtil.fetchRegionServerQuotas(rsServices.getConnection(), gets);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private <K, V extends QuotaState> void fetch(final String type,
|
private <K, V extends QuotaState> void fetch(final String type,
|
||||||
final ConcurrentHashMap<K, V> quotasMap, final Fetcher<K, V> fetcher) {
|
final ConcurrentHashMap<K, V> quotasMap, final Fetcher<K, V> fetcher) {
|
||||||
long now = EnvironmentEdgeManager.currentTime();
|
long now = EnvironmentEdgeManager.currentTime();
|
||||||
|
|
|
@ -29,10 +29,6 @@ import org.apache.hadoop.hbase.HColumnDescriptor;
|
||||||
import org.apache.hadoop.hbase.HConstants;
|
import org.apache.hadoop.hbase.HConstants;
|
||||||
import org.apache.hadoop.hbase.HTableDescriptor;
|
import org.apache.hadoop.hbase.HTableDescriptor;
|
||||||
import org.apache.hadoop.hbase.TableName;
|
import org.apache.hadoop.hbase.TableName;
|
||||||
import org.apache.yetus.audience.InterfaceAudience;
|
|
||||||
import org.apache.yetus.audience.InterfaceStability;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.apache.hadoop.hbase.client.Connection;
|
import org.apache.hadoop.hbase.client.Connection;
|
||||||
import org.apache.hadoop.hbase.client.Delete;
|
import org.apache.hadoop.hbase.client.Delete;
|
||||||
import org.apache.hadoop.hbase.client.Get;
|
import org.apache.hadoop.hbase.client.Get;
|
||||||
|
@ -40,10 +36,15 @@ import org.apache.hadoop.hbase.client.Mutation;
|
||||||
import org.apache.hadoop.hbase.client.Put;
|
import org.apache.hadoop.hbase.client.Put;
|
||||||
import org.apache.hadoop.hbase.client.Result;
|
import org.apache.hadoop.hbase.client.Result;
|
||||||
import org.apache.hadoop.hbase.client.Table;
|
import org.apache.hadoop.hbase.client.Table;
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Quotas;
|
|
||||||
import org.apache.hadoop.hbase.regionserver.BloomType;
|
import org.apache.hadoop.hbase.regionserver.BloomType;
|
||||||
import org.apache.hadoop.hbase.util.Bytes;
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
|
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
|
||||||
|
import org.apache.yetus.audience.InterfaceAudience;
|
||||||
|
import org.apache.yetus.audience.InterfaceStability;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Quotas;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class to interact with the quota table
|
* Helper class to interact with the quota table
|
||||||
|
@ -142,6 +143,16 @@ public class QuotaUtil extends QuotaTableUtil {
|
||||||
getSettingsQualifierForUserNamespace(namespace));
|
getSettingsQualifierForUserNamespace(namespace));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void addRegionServerQuota(final Connection connection, final String regionServer,
|
||||||
|
final Quotas data) throws IOException {
|
||||||
|
addQuotas(connection, getRegionServerRowKey(regionServer), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void deleteRegionServerQuota(final Connection connection, final String regionServer)
|
||||||
|
throws IOException {
|
||||||
|
deleteQuotas(connection, getRegionServerRowKey(regionServer));
|
||||||
|
}
|
||||||
|
|
||||||
private static void addQuotas(final Connection connection, final byte[] rowKey,
|
private static void addQuotas(final Connection connection, final byte[] rowKey,
|
||||||
final Quotas data) throws IOException {
|
final Quotas data) throws IOException {
|
||||||
addQuotas(connection, rowKey, QUOTA_QUALIFIER_SETTINGS, data);
|
addQuotas(connection, rowKey, QUOTA_QUALIFIER_SETTINGS, data);
|
||||||
|
@ -232,6 +243,17 @@ public class QuotaUtil extends QuotaTableUtil {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Map<String, QuotaState> fetchRegionServerQuotas(final Connection connection,
|
||||||
|
final List<Get> gets) throws IOException {
|
||||||
|
return fetchGlobalQuotas("regionServer", connection, gets, new KeyFromRow<String>() {
|
||||||
|
@Override
|
||||||
|
public String getKeyFromRow(final byte[] row) {
|
||||||
|
assert isRegionServerRowKey(row);
|
||||||
|
return getRegionServerFromRowKey(row);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static <K> Map<K, QuotaState> fetchGlobalQuotas(final String type,
|
public static <K> Map<K, QuotaState> fetchGlobalQuotas(final String type,
|
||||||
final Connection connection, final List<Get> gets, final KeyFromRow<K> kfr)
|
final Connection connection, final List<Get> gets, final KeyFromRow<K> kfr)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
|
@ -22,19 +22,19 @@ import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.apache.yetus.audience.InterfaceAudience;
|
|
||||||
import org.apache.yetus.audience.InterfaceStability;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.apache.hadoop.hbase.TableName;
|
import org.apache.hadoop.hbase.TableName;
|
||||||
import org.apache.hadoop.hbase.ipc.RpcScheduler;
|
import org.apache.hadoop.hbase.ipc.RpcScheduler;
|
||||||
import org.apache.hadoop.hbase.ipc.RpcServer;
|
import org.apache.hadoop.hbase.ipc.RpcServer;
|
||||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos;
|
|
||||||
import org.apache.hadoop.hbase.regionserver.Region;
|
import org.apache.hadoop.hbase.regionserver.Region;
|
||||||
import org.apache.hadoop.hbase.regionserver.RegionServerServices;
|
import org.apache.hadoop.hbase.regionserver.RegionServerServices;
|
||||||
import org.apache.hadoop.hbase.security.User;
|
import org.apache.hadoop.hbase.security.User;
|
||||||
import org.apache.hadoop.security.UserGroupInformation;
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
|
import org.apache.yetus.audience.InterfaceAudience;
|
||||||
|
import org.apache.yetus.audience.InterfaceStability;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
|
import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
|
||||||
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Region Server Quota Manager.
|
* Region Server Quota Manager.
|
||||||
|
@ -135,14 +135,17 @@ public class RegionServerRpcQuotaManager {
|
||||||
} else {
|
} else {
|
||||||
QuotaLimiter nsLimiter = quotaCache.getNamespaceLimiter(table.getNamespaceAsString());
|
QuotaLimiter nsLimiter = quotaCache.getNamespaceLimiter(table.getNamespaceAsString());
|
||||||
QuotaLimiter tableLimiter = quotaCache.getTableLimiter(table);
|
QuotaLimiter tableLimiter = quotaCache.getTableLimiter(table);
|
||||||
useNoop &= tableLimiter.isBypass() && nsLimiter.isBypass();
|
QuotaLimiter rsLimiter = quotaCache
|
||||||
|
.getRegionServerQuotaLimiter(QuotaTableUtil.QUOTA_REGION_SERVER_ROW_KEY);
|
||||||
|
useNoop &= tableLimiter.isBypass() && nsLimiter.isBypass() && rsLimiter.isBypass();
|
||||||
if (LOG.isTraceEnabled()) {
|
if (LOG.isTraceEnabled()) {
|
||||||
LOG.trace("get quota for ugi=" + ugi + " table=" + table + " userLimiter=" +
|
LOG.trace("get quota for ugi=" + ugi + " table=" + table + " userLimiter=" + userLimiter
|
||||||
userLimiter + " tableLimiter=" + tableLimiter + " nsLimiter=" + nsLimiter);
|
+ " tableLimiter=" + tableLimiter + " nsLimiter=" + nsLimiter + " rsLimiter="
|
||||||
|
+ rsLimiter);
|
||||||
}
|
}
|
||||||
if (!useNoop) {
|
if (!useNoop) {
|
||||||
return new DefaultOperationQuota(this.rsServices.getConfiguration(), userLimiter,
|
return new DefaultOperationQuota(this.rsServices.getConfiguration(), userLimiter,
|
||||||
tableLimiter, nsLimiter);
|
tableLimiter, nsLimiter, rsLimiter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2513,6 +2513,12 @@ public class AccessController implements MasterCoprocessor, RegionCoprocessor,
|
||||||
requirePermission(ctx, "setNamespaceQuota", Action.ADMIN);
|
requirePermission(ctx, "setNamespaceQuota", Action.ADMIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preSetRegionServerQuota(ObserverContext<MasterCoprocessorEnvironment> ctx,
|
||||||
|
final String regionServer, GlobalQuotaSettings quotas) throws IOException {
|
||||||
|
requirePermission(ctx, "setRegionServerQuota", Action.ADMIN);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ReplicationEndpoint postCreateReplicationEndPoint(
|
public ReplicationEndpoint postCreateReplicationEndPoint(
|
||||||
ObserverContext<RegionServerCoprocessorEnvironment> ctx, ReplicationEndpoint endpoint) {
|
ObserverContext<RegionServerCoprocessorEnvironment> ctx, ReplicationEndpoint endpoint) {
|
||||||
|
|
|
@ -58,9 +58,9 @@ public class TestGlobalQuotaSettingsImpl {
|
||||||
QuotaProtos.ThrottleRequest writeThrottle = QuotaProtos.ThrottleRequest.newBuilder()
|
QuotaProtos.ThrottleRequest writeThrottle = QuotaProtos.ThrottleRequest.newBuilder()
|
||||||
.setTimedQuota(writeQuota).setType(QuotaProtos.ThrottleType.WRITE_NUMBER).build();
|
.setTimedQuota(writeQuota).setType(QuotaProtos.ThrottleType.WRITE_NUMBER).build();
|
||||||
|
|
||||||
GlobalQuotaSettingsImpl settings = new GlobalQuotaSettingsImpl("joe", null, null, quota);
|
GlobalQuotaSettingsImpl settings = new GlobalQuotaSettingsImpl("joe", null, null, null, quota);
|
||||||
GlobalQuotaSettingsImpl merged = settings.merge(
|
GlobalQuotaSettingsImpl merged = settings.merge(
|
||||||
new ThrottleSettings("joe", null, null, writeThrottle));
|
new ThrottleSettings("joe", null, null, null, writeThrottle));
|
||||||
|
|
||||||
QuotaProtos.Throttle mergedThrottle = merged.getThrottleProto();
|
QuotaProtos.Throttle mergedThrottle = merged.getThrottleProto();
|
||||||
// Verify the request throttle is in place
|
// Verify the request throttle is in place
|
||||||
|
@ -80,7 +80,7 @@ public class TestGlobalQuotaSettingsImpl {
|
||||||
QuotaProtos.Quotas quota = QuotaProtos.Quotas.newBuilder()
|
QuotaProtos.Quotas quota = QuotaProtos.Quotas.newBuilder()
|
||||||
.setSpace(SPACE_QUOTA).build();
|
.setSpace(SPACE_QUOTA).build();
|
||||||
|
|
||||||
GlobalQuotaSettingsImpl settings = new GlobalQuotaSettingsImpl(null, tn, null, quota);
|
GlobalQuotaSettingsImpl settings = new GlobalQuotaSettingsImpl(null, tn, null, null, quota);
|
||||||
// Switch the violation policy to DISABLE
|
// Switch the violation policy to DISABLE
|
||||||
GlobalQuotaSettingsImpl merged = settings.merge(
|
GlobalQuotaSettingsImpl merged = settings.merge(
|
||||||
new SpaceLimitSettings(tn, SPACE_QUOTA.getSoftLimit(), SpaceViolationPolicy.DISABLE));
|
new SpaceLimitSettings(tn, SPACE_QUOTA.getSoftLimit(), SpaceViolationPolicy.DISABLE));
|
||||||
|
@ -96,7 +96,7 @@ public class TestGlobalQuotaSettingsImpl {
|
||||||
final String ns = "org1";
|
final String ns = "org1";
|
||||||
QuotaProtos.Quotas quota = QuotaProtos.Quotas.newBuilder()
|
QuotaProtos.Quotas quota = QuotaProtos.Quotas.newBuilder()
|
||||||
.setThrottle(THROTTLE).setSpace(SPACE_QUOTA).build();
|
.setThrottle(THROTTLE).setSpace(SPACE_QUOTA).build();
|
||||||
GlobalQuotaSettingsImpl settings = new GlobalQuotaSettingsImpl(null, null, ns, quota);
|
GlobalQuotaSettingsImpl settings = new GlobalQuotaSettingsImpl(null, null, ns, null, quota);
|
||||||
|
|
||||||
QuotaProtos.TimedQuota writeQuota = REQUEST_THROTTLE.toBuilder()
|
QuotaProtos.TimedQuota writeQuota = REQUEST_THROTTLE.toBuilder()
|
||||||
.setSoftLimit(500).build();
|
.setSoftLimit(500).build();
|
||||||
|
@ -105,7 +105,7 @@ public class TestGlobalQuotaSettingsImpl {
|
||||||
.setTimedQuota(writeQuota).setType(QuotaProtos.ThrottleType.WRITE_NUMBER).build();
|
.setTimedQuota(writeQuota).setType(QuotaProtos.ThrottleType.WRITE_NUMBER).build();
|
||||||
|
|
||||||
GlobalQuotaSettingsImpl merged = settings.merge(
|
GlobalQuotaSettingsImpl merged = settings.merge(
|
||||||
new ThrottleSettings(null, null, ns, writeThrottle));
|
new ThrottleSettings(null, null, ns, null, writeThrottle));
|
||||||
GlobalQuotaSettingsImpl finalQuota = merged.merge(new SpaceLimitSettings(
|
GlobalQuotaSettingsImpl finalQuota = merged.merge(new SpaceLimitSettings(
|
||||||
ns, SPACE_QUOTA.getSoftLimit(), SpaceViolationPolicy.NO_WRITES_COMPACTIONS));
|
ns, SPACE_QUOTA.getSoftLimit(), SpaceViolationPolicy.NO_WRITES_COMPACTIONS));
|
||||||
|
|
||||||
|
|
|
@ -174,6 +174,7 @@ public class TestQuotaAdmin {
|
||||||
assertEquals(userName, throttle.getUserName());
|
assertEquals(userName, throttle.getUserName());
|
||||||
assertEquals(null, throttle.getTableName());
|
assertEquals(null, throttle.getTableName());
|
||||||
assertEquals(null, throttle.getNamespace());
|
assertEquals(null, throttle.getNamespace());
|
||||||
|
assertEquals(null, throttle.getRegionServer());
|
||||||
assertEquals(6, throttle.getSoftLimit());
|
assertEquals(6, throttle.getSoftLimit());
|
||||||
assertEquals(TimeUnit.MINUTES, throttle.getTimeUnit());
|
assertEquals(TimeUnit.MINUTES, throttle.getTimeUnit());
|
||||||
countThrottle++;
|
countThrottle++;
|
||||||
|
@ -523,6 +524,51 @@ public class TestQuotaAdmin {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetAndRemoveRegionServerQuota() throws Exception {
|
||||||
|
Admin admin = TEST_UTIL.getAdmin();
|
||||||
|
String regionServer = QuotaTableUtil.QUOTA_REGION_SERVER_ROW_KEY;
|
||||||
|
QuotaFilter rsFilter = new QuotaFilter().setRegionServerFilter(regionServer);
|
||||||
|
|
||||||
|
admin.setQuota(QuotaSettingsFactory.throttleRegionServer(regionServer,
|
||||||
|
ThrottleType.REQUEST_NUMBER, 10, TimeUnit.MINUTES));
|
||||||
|
assertNumResults(1, rsFilter);
|
||||||
|
// Verify the Quota in the table
|
||||||
|
verifyRecordPresentInQuotaTable(ThrottleType.REQUEST_NUMBER, 10, TimeUnit.MINUTES);
|
||||||
|
|
||||||
|
admin.setQuota(QuotaSettingsFactory.throttleRegionServer(regionServer,
|
||||||
|
ThrottleType.REQUEST_NUMBER, 20, TimeUnit.MINUTES));
|
||||||
|
assertNumResults(1, rsFilter);
|
||||||
|
// Verify the Quota in the table
|
||||||
|
verifyRecordPresentInQuotaTable(ThrottleType.REQUEST_NUMBER, 20, TimeUnit.MINUTES);
|
||||||
|
|
||||||
|
admin.setQuota(QuotaSettingsFactory.throttleRegionServer(regionServer, ThrottleType.READ_NUMBER,
|
||||||
|
30, TimeUnit.SECONDS));
|
||||||
|
int count = 0;
|
||||||
|
QuotaRetriever scanner = QuotaRetriever.open(TEST_UTIL.getConfiguration(), rsFilter);
|
||||||
|
try {
|
||||||
|
for (QuotaSettings settings : scanner) {
|
||||||
|
assertTrue(settings.getQuotaType() == QuotaType.THROTTLE);
|
||||||
|
ThrottleSettings throttleSettings = (ThrottleSettings) settings;
|
||||||
|
assertEquals(regionServer, throttleSettings.getRegionServer());
|
||||||
|
count++;
|
||||||
|
if (throttleSettings.getThrottleType() == ThrottleType.REQUEST_NUMBER) {
|
||||||
|
assertEquals(20, throttleSettings.getSoftLimit());
|
||||||
|
assertEquals(TimeUnit.MINUTES, throttleSettings.getTimeUnit());
|
||||||
|
} else if (throttleSettings.getThrottleType() == ThrottleType.READ_NUMBER) {
|
||||||
|
assertEquals(30, throttleSettings.getSoftLimit());
|
||||||
|
assertEquals(TimeUnit.SECONDS, throttleSettings.getTimeUnit());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
scanner.close();
|
||||||
|
}
|
||||||
|
assertEquals(2, count);
|
||||||
|
|
||||||
|
admin.setQuota(QuotaSettingsFactory.unthrottleRegionServer(regionServer));
|
||||||
|
assertNumResults(0, new QuotaFilter().setRegionServerFilter(regionServer));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRpcThrottleWhenStartup() throws IOException, InterruptedException {
|
public void testRpcThrottleWhenStartup() throws IOException, InterruptedException {
|
||||||
TEST_UTIL.getAdmin().switchRpcThrottle(false);
|
TEST_UTIL.getAdmin().switchRpcThrottle(false);
|
||||||
|
|
|
@ -570,6 +570,31 @@ public class TestQuotaThrottle {
|
||||||
triggerTableCacheRefresh(true, TABLE_NAMES[0]);
|
triggerTableCacheRefresh(true, TABLE_NAMES[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegionServerThrottle() throws Exception {
|
||||||
|
final Admin admin = TEST_UTIL.getAdmin();
|
||||||
|
admin.setQuota(QuotaSettingsFactory.throttleTable(TABLE_NAMES[0], ThrottleType.WRITE_NUMBER, 5,
|
||||||
|
TimeUnit.MINUTES));
|
||||||
|
|
||||||
|
// requests are throttled by table quota
|
||||||
|
admin.setQuota(QuotaSettingsFactory.throttleRegionServer(
|
||||||
|
QuotaTableUtil.QUOTA_REGION_SERVER_ROW_KEY, ThrottleType.WRITE_NUMBER, 7, TimeUnit.MINUTES));
|
||||||
|
triggerCacheRefresh(false, false, true, false, true, TABLE_NAMES[0]);
|
||||||
|
assertEquals(5, doPuts(10, tables[0]));
|
||||||
|
|
||||||
|
// requests are throttled by region server quota
|
||||||
|
admin.setQuota(QuotaSettingsFactory.throttleRegionServer(
|
||||||
|
QuotaTableUtil.QUOTA_REGION_SERVER_ROW_KEY, ThrottleType.WRITE_NUMBER, 4, TimeUnit.MINUTES));
|
||||||
|
triggerCacheRefresh(false, false, false, false, true, TABLE_NAMES[0]);
|
||||||
|
assertEquals(4, doPuts(10, tables[0]));
|
||||||
|
|
||||||
|
// unthrottle
|
||||||
|
admin.setQuota(
|
||||||
|
QuotaSettingsFactory.unthrottleRegionServer(QuotaTableUtil.QUOTA_REGION_SERVER_ROW_KEY));
|
||||||
|
admin.setQuota(QuotaSettingsFactory.unthrottleTable(TABLE_NAMES[0]));
|
||||||
|
triggerCacheRefresh(true, false, true, false, true, TABLE_NAMES[0]);
|
||||||
|
}
|
||||||
|
|
||||||
private int doPuts(int maxOps, final Table... tables) throws Exception {
|
private int doPuts(int maxOps, final Table... tables) throws Exception {
|
||||||
return doPuts(maxOps, -1, tables);
|
return doPuts(maxOps, -1, tables);
|
||||||
}
|
}
|
||||||
|
@ -622,19 +647,19 @@ public class TestQuotaThrottle {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void triggerUserCacheRefresh(boolean bypass, TableName... tables) throws Exception {
|
private void triggerUserCacheRefresh(boolean bypass, TableName... tables) throws Exception {
|
||||||
triggerCacheRefresh(bypass, true, false, false, tables);
|
triggerCacheRefresh(bypass, true, false, false, false, tables);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void triggerTableCacheRefresh(boolean bypass, TableName... tables) throws Exception {
|
private void triggerTableCacheRefresh(boolean bypass, TableName... tables) throws Exception {
|
||||||
triggerCacheRefresh(bypass, false, true, false, tables);
|
triggerCacheRefresh(bypass, false, true, false, false, tables);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void triggerNamespaceCacheRefresh(boolean bypass, TableName... tables) throws Exception {
|
private void triggerNamespaceCacheRefresh(boolean bypass, TableName... tables) throws Exception {
|
||||||
triggerCacheRefresh(bypass, false, false, true, tables);
|
triggerCacheRefresh(bypass, false, false, true, false, tables);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void triggerCacheRefresh(boolean bypass, boolean userLimiter, boolean tableLimiter,
|
private void triggerCacheRefresh(boolean bypass, boolean userLimiter, boolean tableLimiter,
|
||||||
boolean nsLimiter, final TableName... tables) throws Exception {
|
boolean nsLimiter, boolean rsLimiter, final TableName... tables) throws Exception {
|
||||||
envEdge.incValue(2 * REFRESH_TIME);
|
envEdge.incValue(2 * REFRESH_TIME);
|
||||||
for (RegionServerThread rst: TEST_UTIL.getMiniHBaseCluster().getRegionServerThreads()) {
|
for (RegionServerThread rst: TEST_UTIL.getMiniHBaseCluster().getRegionServerThreads()) {
|
||||||
RegionServerRpcQuotaManager quotaManager = rst.getRegionServer().getRegionServerRpcQuotaManager();
|
RegionServerRpcQuotaManager quotaManager = rst.getRegionServer().getRegionServerRpcQuotaManager();
|
||||||
|
@ -663,6 +688,11 @@ public class TestQuotaThrottle {
|
||||||
if (nsLimiter) {
|
if (nsLimiter) {
|
||||||
isBypass &= quotaCache.getNamespaceLimiter(table.getNamespaceAsString()).isBypass();
|
isBypass &= quotaCache.getNamespaceLimiter(table.getNamespaceAsString()).isBypass();
|
||||||
}
|
}
|
||||||
|
if (rsLimiter) {
|
||||||
|
isBypass &= quotaCache
|
||||||
|
.getRegionServerQuotaLimiter(QuotaTableUtil.QUOTA_REGION_SERVER_ROW_KEY)
|
||||||
|
.isBypass();
|
||||||
|
}
|
||||||
if (isBypass != bypass) {
|
if (isBypass != bypass) {
|
||||||
envEdge.incValue(100);
|
envEdge.incValue(100);
|
||||||
isUpdated = false;
|
isUpdated = false;
|
||||||
|
@ -675,6 +705,7 @@ public class TestQuotaThrottle {
|
||||||
LOG.debug(Objects.toString(quotaCache.getNamespaceQuotaCache()));
|
LOG.debug(Objects.toString(quotaCache.getNamespaceQuotaCache()));
|
||||||
LOG.debug(Objects.toString(quotaCache.getTableQuotaCache()));
|
LOG.debug(Objects.toString(quotaCache.getTableQuotaCache()));
|
||||||
LOG.debug(Objects.toString(quotaCache.getUserQuotaCache()));
|
LOG.debug(Objects.toString(quotaCache.getUserQuotaCache()));
|
||||||
|
LOG.debug(Objects.toString(quotaCache.getRegionServerQuotaCache()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2700,6 +2700,15 @@ public class TestAccessController extends SecureTestUtil {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AccessTestAction setRegionServerQuotaAction = new AccessTestAction() {
|
||||||
|
@Override
|
||||||
|
public Object run() throws Exception {
|
||||||
|
ACCESS_CONTROLLER.preSetRegionServerQuota(ObserverContextImpl.createAndPrepare(CP_ENV),
|
||||||
|
null, null);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
verifyAllowed(setUserQuotaAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
|
verifyAllowed(setUserQuotaAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
|
||||||
verifyDenied(setUserQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
|
verifyDenied(setUserQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
|
||||||
USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
|
USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
|
||||||
|
@ -2718,6 +2727,10 @@ public class TestAccessController extends SecureTestUtil {
|
||||||
verifyAllowed(setNamespaceQuotaAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
|
verifyAllowed(setNamespaceQuotaAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
|
||||||
verifyDenied(setNamespaceQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
|
verifyDenied(setNamespaceQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
|
||||||
USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
|
USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
|
||||||
|
|
||||||
|
verifyAllowed(setRegionServerQuotaAction, SUPERUSER, USER_ADMIN, USER_GROUP_ADMIN);
|
||||||
|
verifyDenied(setRegionServerQuotaAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER,
|
||||||
|
USER_GROUP_READ, USER_GROUP_WRITE, USER_GROUP_CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -82,8 +82,11 @@ module Hbase
|
||||||
namespace = args.delete(NAMESPACE)
|
namespace = args.delete(NAMESPACE)
|
||||||
raise(ArgumentError, 'Unexpected arguments: ' + args.inspect) unless args.empty?
|
raise(ArgumentError, 'Unexpected arguments: ' + args.inspect) unless args.empty?
|
||||||
settings = QuotaSettingsFactory.throttleNamespace(namespace, type, limit, time_unit)
|
settings = QuotaSettingsFactory.throttleNamespace(namespace, type, limit, time_unit)
|
||||||
|
elsif args.key?(REGIONSERVER)
|
||||||
|
# TODO: Setting specified region server quota isn't supported currently and using 'all' for all RS
|
||||||
|
settings = QuotaSettingsFactory.throttleRegionServer('all', type, limit, time_unit)
|
||||||
else
|
else
|
||||||
raise 'One of USER, TABLE or NAMESPACE must be specified'
|
raise 'One of USER, TABLE, NAMESPACE or REGIONSERVER must be specified'
|
||||||
end
|
end
|
||||||
@admin.setQuota(settings)
|
@admin.setQuota(settings)
|
||||||
end
|
end
|
||||||
|
@ -112,8 +115,13 @@ module Hbase
|
||||||
namespace = args.delete(NAMESPACE)
|
namespace = args.delete(NAMESPACE)
|
||||||
raise(ArgumentError, 'Unexpected arguments: ' + args.inspect) unless args.empty?
|
raise(ArgumentError, 'Unexpected arguments: ' + args.inspect) unless args.empty?
|
||||||
settings = QuotaSettingsFactory.unthrottleNamespace(namespace)
|
settings = QuotaSettingsFactory.unthrottleNamespace(namespace)
|
||||||
|
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')
|
||||||
else
|
else
|
||||||
raise 'One of USER, TABLE or NAMESPACE must be specified'
|
raise 'One of USER, TABLE, NAMESPACE or REGIONSERVER must be specified'
|
||||||
end
|
end
|
||||||
@admin.setQuota(settings)
|
@admin.setQuota(settings)
|
||||||
end
|
end
|
||||||
|
@ -233,7 +241,8 @@ module Hbase
|
||||||
owner = {
|
owner = {
|
||||||
USER => settings.getUserName,
|
USER => settings.getUserName,
|
||||||
TABLE => settings.getTableName,
|
TABLE => settings.getTableName,
|
||||||
NAMESPACE => settings.getNamespace
|
NAMESPACE => settings.getNamespace,
|
||||||
|
REGIONSERVER => settings.getRegionServer
|
||||||
}.delete_if { |_k, v| v.nil? }.map { |k, v| k.to_s + ' => ' + v.to_s } * ', '
|
}.delete_if { |_k, v| v.nil? }.map { |k, v| k.to_s + ' => ' + v.to_s } * ', '
|
||||||
|
|
||||||
yield owner, settings.to_s
|
yield owner, settings.to_s
|
||||||
|
|
|
@ -22,7 +22,7 @@ module Shell
|
||||||
class SetQuota < Command
|
class SetQuota < Command
|
||||||
def help
|
def help
|
||||||
<<-EOF
|
<<-EOF
|
||||||
Set a quota for a user, table, or namespace.
|
Set a quota for a user, table, namespace or region server.
|
||||||
Syntax : set_quota TYPE => <type>, <args>
|
Syntax : set_quota TYPE => <type>, <args>
|
||||||
|
|
||||||
TYPE => THROTTLE
|
TYPE => THROTTLE
|
||||||
|
@ -55,6 +55,10 @@ For example:
|
||||||
hbase> set_quota TYPE => THROTTLE, USER => 'u1', LIMIT => NONE
|
hbase> set_quota TYPE => THROTTLE, USER => 'u1', LIMIT => NONE
|
||||||
hbase> set_quota TYPE => THROTTLE, THROTTLE_TYPE => WRITE, USER => 'u1', LIMIT => NONE
|
hbase> set_quota TYPE => THROTTLE, THROTTLE_TYPE => WRITE, USER => 'u1', LIMIT => NONE
|
||||||
|
|
||||||
|
hbase> set_quota TYPE => THROTTLE, REGIONSERVER => 'all', LIMIT => '30000req/sec'
|
||||||
|
hbase> set_quota TYPE => THROTTLE, REGIONSERVER => 'all', THROTTLE_TYPE => WRITE, LIMIT => '20000req/sec'
|
||||||
|
hbase> set_quota TYPE => THROTTLE, REGIONSERVER => 'all', LIMIT => NONE
|
||||||
|
|
||||||
hbase> set_quota USER => 'u1', GLOBAL_BYPASS => true
|
hbase> set_quota USER => 'u1', GLOBAL_BYPASS => true
|
||||||
|
|
||||||
TYPE => SPACE
|
TYPE => SPACE
|
||||||
|
|
|
@ -251,6 +251,27 @@ module Hbase
|
||||||
output = capture_stdout { command(:enable_rpc_throttle) }
|
output = capture_stdout { command(:enable_rpc_throttle) }
|
||||||
assert(output.include?('Previous rpc throttle state : false'))
|
assert(output.include?('Previous rpc throttle state : false'))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
define_test 'can set and remove region server quota' do
|
||||||
|
command(:set_quota, TYPE => THROTTLE, REGIONSERVER => 'all', LIMIT => '1CU/sec')
|
||||||
|
output = capture_stdout{ command(:list_quotas) }
|
||||||
|
assert(output.include?('REGIONSERVER => all'))
|
||||||
|
assert(output.include?('TYPE => THROTTLE'))
|
||||||
|
assert(output.include?('THROTTLE_TYPE => REQUEST_CAPACITY_UNIT'))
|
||||||
|
assert(output.include?('LIMIT => 1CU/sec'))
|
||||||
|
|
||||||
|
command(:set_quota, TYPE => THROTTLE, REGIONSERVER => 'all', THROTTLE_TYPE => WRITE, LIMIT => '2req/sec')
|
||||||
|
output = capture_stdout{ command(:list_quotas) }
|
||||||
|
assert(output.include?('REGIONSERVER => all'))
|
||||||
|
assert(output.include?('TYPE => THROTTLE'))
|
||||||
|
assert(output.include?('THROTTLE_TYPE => WRITE'))
|
||||||
|
assert(output.include?('THROTTLE_TYPE => REQUEST_CAPACITY_UNIT'))
|
||||||
|
assert(output.include?('LIMIT => 2req/sec'))
|
||||||
|
|
||||||
|
command(:set_quota, TYPE => THROTTLE, REGIONSERVER => 'all', LIMIT => NONE)
|
||||||
|
output = capture_stdout{ command(:list_quotas) }
|
||||||
|
assert(output.include?('0 row(s)'))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics/ClassLength
|
# rubocop:enable Metrics/ClassLength
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue