HBASE-18873 Move protobufs to private implementation on GlobalQuotaSettings
A hack to "hide" the protobufs, but it's not going to be a trivial change to remove use of protobufs entirely as they're serialized into the hbase:quota table.
This commit is contained in:
parent
b7db62c702
commit
81133f89fc
|
@ -116,7 +116,7 @@ public class QuotaSettingsFactory {
|
|||
return settings;
|
||||
}
|
||||
|
||||
private static List<QuotaSettings> fromThrottle(final String userName, final TableName tableName,
|
||||
protected static List<QuotaSettings> fromThrottle(final String userName, final TableName tableName,
|
||||
final String namespace, final QuotaProtos.Throttle throttle) {
|
||||
List<QuotaSettings> settings = new ArrayList<>();
|
||||
if (throttle.hasReqNum()) {
|
||||
|
|
|
@ -16,23 +16,12 @@
|
|||
*/
|
||||
package org.apache.hadoop.hbase.quotas;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.hadoop.hbase.DoNotRetryIOException;
|
||||
import org.apache.hadoop.hbase.HBaseInterfaceAudience;
|
||||
import org.apache.hadoop.hbase.TableName;
|
||||
import org.apache.hadoop.hbase.quotas.QuotaSettingsFactory.QuotaGlobalsSettingsBypass;
|
||||
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetQuotaRequest.Builder;
|
||||
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.Throttle;
|
||||
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.generated.QuotaProtos;
|
||||
import org.apache.yetus.audience.InterfaceAudience;
|
||||
import org.apache.yetus.audience.InterfaceStability;
|
||||
|
||||
|
@ -43,28 +32,19 @@ import org.apache.yetus.audience.InterfaceStability;
|
|||
*/
|
||||
@InterfaceAudience.LimitedPrivate({HBaseInterfaceAudience.COPROC})
|
||||
@InterfaceStability.Evolving
|
||||
public class GlobalQuotaSettings extends QuotaSettings {
|
||||
private final QuotaProtos.Throttle throttleProto;
|
||||
private final Boolean bypassGlobals;
|
||||
private final QuotaProtos.SpaceQuota spaceProto;
|
||||
public abstract class GlobalQuotaSettings extends QuotaSettings {
|
||||
|
||||
protected GlobalQuotaSettings(
|
||||
String username, TableName tableName, String namespace, QuotaProtos.Quotas quotas) {
|
||||
this(username, tableName, namespace,
|
||||
(quotas != null && quotas.hasThrottle() ? quotas.getThrottle() : null),
|
||||
(quotas != null && quotas.hasBypassGlobals() ? quotas.getBypassGlobals() : null),
|
||||
(quotas != null && quotas.hasSpace() ? quotas.getSpace() : null));
|
||||
}
|
||||
|
||||
protected GlobalQuotaSettings(
|
||||
String userName, TableName tableName, String namespace, QuotaProtos.Throttle throttleProto,
|
||||
Boolean bypassGlobals, QuotaProtos.SpaceQuota spaceProto) {
|
||||
protected GlobalQuotaSettings(String userName, TableName tableName, String namespace) {
|
||||
super(userName, tableName, namespace);
|
||||
this.throttleProto = throttleProto;
|
||||
this.bypassGlobals = bypassGlobals;
|
||||
this.spaceProto = spaceProto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a list of QuotaSettings that present the complete quota state of the combination of
|
||||
* this user, table, and/or namespace. Beware in calling this method repeatedly as the
|
||||
* implementation of it may be costly.
|
||||
*/
|
||||
public abstract List<QuotaSettings> getQuotaSettings();
|
||||
|
||||
@Override
|
||||
public QuotaType getQuotaType() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -76,254 +56,4 @@ public class GlobalQuotaSettings extends QuotaSettings {
|
|||
throw new UnsupportedOperationException(
|
||||
"This class should not be used to generate a SetQuotaRequest.");
|
||||
}
|
||||
|
||||
protected QuotaProtos.Throttle getThrottleProto() {
|
||||
return this.throttleProto;
|
||||
}
|
||||
|
||||
protected Boolean getGlobalBypass() {
|
||||
return this.bypassGlobals;
|
||||
}
|
||||
|
||||
protected QuotaProtos.SpaceQuota getSpaceProto() {
|
||||
return this.spaceProto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link Quotas} message from {@code this}.
|
||||
*/
|
||||
protected Quotas toQuotas() {
|
||||
QuotaProtos.Quotas.Builder builder = QuotaProtos.Quotas.newBuilder();
|
||||
if (getThrottleProto() != null) {
|
||||
builder.setThrottle(getThrottleProto());
|
||||
}
|
||||
if (getGlobalBypass() != null) {
|
||||
builder.setBypassGlobals(getGlobalBypass());
|
||||
}
|
||||
if (getSpaceProto() != null) {
|
||||
builder.setSpace(getSpaceProto());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GlobalQuotaSettings merge(QuotaSettings other) throws IOException {
|
||||
// Validate the quota subject
|
||||
validateQuotaTarget(other);
|
||||
|
||||
// Propagate the Throttle
|
||||
QuotaProtos.Throttle.Builder throttleBuilder = (throttleProto == null
|
||||
? null : throttleProto.toBuilder());
|
||||
if (other instanceof ThrottleSettings) {
|
||||
if (throttleBuilder == null) {
|
||||
throttleBuilder = QuotaProtos.Throttle.newBuilder();
|
||||
}
|
||||
ThrottleSettings otherThrottle = (ThrottleSettings) other;
|
||||
|
||||
if (otherThrottle.proto.hasType()) {
|
||||
QuotaProtos.ThrottleRequest otherProto = otherThrottle.proto;
|
||||
if (otherProto.hasTimedQuota()) {
|
||||
if (otherProto.hasTimedQuota()) {
|
||||
validateTimedQuota(otherProto.getTimedQuota());
|
||||
}
|
||||
|
||||
switch (otherProto.getType()) {
|
||||
case REQUEST_NUMBER:
|
||||
if (otherProto.hasTimedQuota()) {
|
||||
throttleBuilder.setReqNum(otherProto.getTimedQuota());
|
||||
} else {
|
||||
throttleBuilder.clearReqNum();
|
||||
}
|
||||
break;
|
||||
case REQUEST_SIZE:
|
||||
if (otherProto.hasTimedQuota()) {
|
||||
throttleBuilder.setReqSize(otherProto.getTimedQuota());
|
||||
} else {
|
||||
throttleBuilder.clearReqSize();
|
||||
}
|
||||
break;
|
||||
case WRITE_NUMBER:
|
||||
if (otherProto.hasTimedQuota()) {
|
||||
throttleBuilder.setWriteNum(otherProto.getTimedQuota());
|
||||
} else {
|
||||
throttleBuilder.clearWriteNum();
|
||||
}
|
||||
break;
|
||||
case WRITE_SIZE:
|
||||
if (otherProto.hasTimedQuota()) {
|
||||
throttleBuilder.setWriteSize(otherProto.getTimedQuota());
|
||||
} else {
|
||||
throttleBuilder.clearWriteSize();
|
||||
}
|
||||
break;
|
||||
case READ_NUMBER:
|
||||
if (otherProto.hasTimedQuota()) {
|
||||
throttleBuilder.setReadNum(otherProto.getTimedQuota());
|
||||
} else {
|
||||
throttleBuilder.clearReqNum();
|
||||
}
|
||||
break;
|
||||
case READ_SIZE:
|
||||
if (otherProto.hasTimedQuota()) {
|
||||
throttleBuilder.setReadSize(otherProto.getTimedQuota());
|
||||
} else {
|
||||
throttleBuilder.clearReadSize();
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
clearThrottleBuilder(throttleBuilder);
|
||||
}
|
||||
} else {
|
||||
clearThrottleBuilder(throttleBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
// Propagate the space quota portion
|
||||
QuotaProtos.SpaceQuota.Builder spaceBuilder = (spaceProto == null
|
||||
? null : spaceProto.toBuilder());
|
||||
if (other instanceof SpaceLimitSettings) {
|
||||
if (spaceBuilder == null) {
|
||||
spaceBuilder = QuotaProtos.SpaceQuota.newBuilder();
|
||||
}
|
||||
SpaceLimitSettings settingsToMerge = (SpaceLimitSettings) other;
|
||||
|
||||
QuotaProtos.SpaceLimitRequest spaceRequest = settingsToMerge.getProto();
|
||||
|
||||
// The message contained the expect SpaceQuota object
|
||||
if (spaceRequest.hasQuota()) {
|
||||
SpaceQuota quotaToMerge = spaceRequest.getQuota();
|
||||
// Validate that the two settings are for the same target.
|
||||
// SpaceQuotas either apply to a table or a namespace (no user spacequota).
|
||||
if (!Objects.equals(getTableName(), settingsToMerge.getTableName())
|
||||
&& !Objects.equals(getNamespace(), settingsToMerge.getNamespace())) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot merge " + settingsToMerge + " into " + this);
|
||||
}
|
||||
|
||||
if (quotaToMerge.getRemove()) {
|
||||
// Update the builder to propagate the removal
|
||||
spaceBuilder.setRemove(true).clearSoftLimit().clearViolationPolicy();
|
||||
} else {
|
||||
// Add the new settings to the existing settings
|
||||
spaceBuilder.mergeFrom(quotaToMerge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Boolean bypassGlobals = this.bypassGlobals;
|
||||
if (other instanceof QuotaGlobalsSettingsBypass) {
|
||||
bypassGlobals = ((QuotaGlobalsSettingsBypass) other).getBypass();
|
||||
}
|
||||
|
||||
if (throttleBuilder == null &&
|
||||
(spaceBuilder == null || (spaceBuilder.hasRemove() && spaceBuilder.getRemove()))
|
||||
&& bypassGlobals == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new GlobalQuotaSettings(
|
||||
getUserName(), getTableName(), getNamespace(),
|
||||
(throttleBuilder == null ? null : throttleBuilder.build()), bypassGlobals,
|
||||
(spaceBuilder == null ? null : spaceBuilder.build()));
|
||||
}
|
||||
|
||||
private void validateTimedQuota(final TimedQuota timedQuota) throws IOException {
|
||||
if (timedQuota.getSoftLimit() < 1) {
|
||||
throw new DoNotRetryIOException(new UnsupportedOperationException(
|
||||
"The throttle limit must be greater then 0, got " + timedQuota.getSoftLimit()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("GlobalQuota: ");
|
||||
if (throttleProto != null) {
|
||||
Map<ThrottleType,TimedQuota> throttleQuotas = buildThrottleQuotas(throttleProto);
|
||||
builder.append(" { TYPE => THROTTLE ");
|
||||
for (Entry<ThrottleType,TimedQuota> entry : throttleQuotas.entrySet()) {
|
||||
final ThrottleType type = entry.getKey();
|
||||
final TimedQuota timedQuota = entry.getValue();
|
||||
builder.append("{THROTTLE_TYPE => ").append(type.name()).append(", LIMIT => ");
|
||||
if (timedQuota.hasSoftLimit()) {
|
||||
switch (type) {
|
||||
case REQUEST_NUMBER:
|
||||
case WRITE_NUMBER:
|
||||
case READ_NUMBER:
|
||||
builder.append(String.format("%dreq", timedQuota.getSoftLimit()));
|
||||
break;
|
||||
case REQUEST_SIZE:
|
||||
case WRITE_SIZE:
|
||||
case READ_SIZE:
|
||||
builder.append(sizeToString(timedQuota.getSoftLimit()));
|
||||
break;
|
||||
}
|
||||
} else if (timedQuota.hasShare()) {
|
||||
builder.append(String.format("%.2f%%", timedQuota.getShare()));
|
||||
}
|
||||
builder.append('/');
|
||||
builder.append(timeToString(ProtobufUtil.toTimeUnit(timedQuota.getTimeUnit())));
|
||||
if (timedQuota.hasScope()) {
|
||||
builder.append(", SCOPE => ");
|
||||
builder.append(timedQuota.getScope().toString());
|
||||
}
|
||||
}
|
||||
builder.append( "} } ");
|
||||
} else {
|
||||
builder.append(" {} ");
|
||||
}
|
||||
if (bypassGlobals != null) {
|
||||
builder.append(" { GLOBAL_BYPASS => " + bypassGlobals + " } ");
|
||||
}
|
||||
if (spaceProto != null) {
|
||||
builder.append(" { TYPE => SPACE");
|
||||
if (getTableName() != null) {
|
||||
builder.append(", TABLE => ").append(getTableName());
|
||||
}
|
||||
if (getNamespace() != null) {
|
||||
builder.append(", NAMESPACE => ").append(getNamespace());
|
||||
}
|
||||
if (spaceProto.getRemove()) {
|
||||
builder.append(", REMOVE => ").append(spaceProto.getRemove());
|
||||
} else {
|
||||
builder.append(", LIMIT => ").append(spaceProto.getSoftLimit());
|
||||
builder.append(", VIOLATION_POLICY => ").append(spaceProto.getViolationPolicy());
|
||||
}
|
||||
builder.append(" } ");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private Map<ThrottleType,TimedQuota> buildThrottleQuotas(Throttle proto) {
|
||||
HashMap<ThrottleType,TimedQuota> quotas = new HashMap<>();
|
||||
if (proto.hasReadNum()) {
|
||||
quotas.put(ThrottleType.READ_NUMBER, proto.getReadNum());
|
||||
}
|
||||
if (proto.hasReadSize()) {
|
||||
quotas.put(ThrottleType.READ_SIZE, proto.getReadSize());
|
||||
}
|
||||
if (proto.hasReqNum()) {
|
||||
quotas.put(ThrottleType.REQUEST_NUMBER, proto.getReqNum());
|
||||
}
|
||||
if (proto.hasReqSize()) {
|
||||
quotas.put(ThrottleType.REQUEST_SIZE, proto.getReqSize());
|
||||
}
|
||||
if (proto.hasWriteNum()) {
|
||||
quotas.put(ThrottleType.WRITE_NUMBER, proto.getWriteNum());
|
||||
}
|
||||
if (proto.hasWriteSize()) {
|
||||
quotas.put(ThrottleType.WRITE_SIZE, proto.getWriteSize());
|
||||
}
|
||||
return quotas;
|
||||
}
|
||||
|
||||
private void clearThrottleBuilder(QuotaProtos.Throttle.Builder builder) {
|
||||
builder.clearReadNum();
|
||||
builder.clearReadSize();
|
||||
builder.clearReqNum();
|
||||
builder.clearReqSize();
|
||||
builder.clearWriteNum();
|
||||
builder.clearWriteSize();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,332 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to you under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.hadoop.hbase.quotas;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.hadoop.hbase.DoNotRetryIOException;
|
||||
import org.apache.hadoop.hbase.TableName;
|
||||
import org.apache.hadoop.hbase.quotas.QuotaSettingsFactory.QuotaGlobalsSettingsBypass;
|
||||
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.Quotas;
|
||||
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.TimedQuota;
|
||||
import org.apache.yetus.audience.InterfaceAudience;
|
||||
|
||||
/**
|
||||
* Implementation of {@link GlobalQuotaSettings} to hide the Protobuf messages we use internally.
|
||||
*/
|
||||
@InterfaceAudience.Private
|
||||
public class GlobalQuotaSettingsImpl extends GlobalQuotaSettings {
|
||||
|
||||
private final QuotaProtos.Throttle throttleProto;
|
||||
private final Boolean bypassGlobals;
|
||||
private final QuotaProtos.SpaceQuota spaceProto;
|
||||
|
||||
protected GlobalQuotaSettingsImpl(
|
||||
String username, TableName tableName, String namespace, QuotaProtos.Quotas quotas) {
|
||||
this(username, tableName, namespace,
|
||||
(quotas != null && quotas.hasThrottle() ? quotas.getThrottle() : null),
|
||||
(quotas != null && quotas.hasBypassGlobals() ? quotas.getBypassGlobals() : null),
|
||||
(quotas != null && quotas.hasSpace() ? quotas.getSpace() : null));
|
||||
}
|
||||
|
||||
protected GlobalQuotaSettingsImpl(
|
||||
String userName, TableName tableName, String namespace, QuotaProtos.Throttle throttleProto,
|
||||
Boolean bypassGlobals, QuotaProtos.SpaceQuota spaceProto) {
|
||||
super(userName, tableName, namespace);
|
||||
this.throttleProto = throttleProto;
|
||||
this.bypassGlobals = bypassGlobals;
|
||||
this.spaceProto = spaceProto;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<QuotaSettings> getQuotaSettings() {
|
||||
// Very similar to QuotaSettingsFactory
|
||||
List<QuotaSettings> settings = new ArrayList<>();
|
||||
if (throttleProto != null) {
|
||||
settings.addAll(QuotaSettingsFactory.fromThrottle(
|
||||
getUserName(), getTableName(), getNamespace(), throttleProto));
|
||||
}
|
||||
if (bypassGlobals != null && bypassGlobals.booleanValue()) {
|
||||
settings.add(new QuotaGlobalsSettingsBypass(
|
||||
getUserName(), getTableName(), getNamespace(), true));
|
||||
}
|
||||
if (spaceProto != null) {
|
||||
settings.add(QuotaSettingsFactory.fromSpace(getTableName(), getNamespace(), spaceProto));
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
protected QuotaProtos.Throttle getThrottleProto() {
|
||||
return this.throttleProto;
|
||||
}
|
||||
|
||||
protected Boolean getBypassGlobals() {
|
||||
return this.bypassGlobals;
|
||||
}
|
||||
|
||||
protected QuotaProtos.SpaceQuota getSpaceProto() {
|
||||
return this.spaceProto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link Quotas} message from {@code this}.
|
||||
*/
|
||||
protected Quotas toQuotas() {
|
||||
QuotaProtos.Quotas.Builder builder = QuotaProtos.Quotas.newBuilder();
|
||||
if (getThrottleProto() != null) {
|
||||
builder.setThrottle(getThrottleProto());
|
||||
}
|
||||
if (getBypassGlobals() != null) {
|
||||
builder.setBypassGlobals(getBypassGlobals());
|
||||
}
|
||||
if (getSpaceProto() != null) {
|
||||
builder.setSpace(getSpaceProto());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GlobalQuotaSettingsImpl merge(QuotaSettings other) throws IOException {
|
||||
// Validate the quota subject
|
||||
validateQuotaTarget(other);
|
||||
|
||||
// Propagate the Throttle
|
||||
QuotaProtos.Throttle.Builder throttleBuilder = (throttleProto == null
|
||||
? null : throttleProto.toBuilder());
|
||||
if (other instanceof ThrottleSettings) {
|
||||
if (throttleBuilder == null) {
|
||||
throttleBuilder = QuotaProtos.Throttle.newBuilder();
|
||||
}
|
||||
ThrottleSettings otherThrottle = (ThrottleSettings) other;
|
||||
|
||||
if (otherThrottle.proto.hasType()) {
|
||||
QuotaProtos.ThrottleRequest otherProto = otherThrottle.proto;
|
||||
if (otherProto.hasTimedQuota()) {
|
||||
if (otherProto.hasTimedQuota()) {
|
||||
validateTimedQuota(otherProto.getTimedQuota());
|
||||
}
|
||||
|
||||
switch (otherProto.getType()) {
|
||||
case REQUEST_NUMBER:
|
||||
if (otherProto.hasTimedQuota()) {
|
||||
throttleBuilder.setReqNum(otherProto.getTimedQuota());
|
||||
} else {
|
||||
throttleBuilder.clearReqNum();
|
||||
}
|
||||
break;
|
||||
case REQUEST_SIZE:
|
||||
if (otherProto.hasTimedQuota()) {
|
||||
throttleBuilder.setReqSize(otherProto.getTimedQuota());
|
||||
} else {
|
||||
throttleBuilder.clearReqSize();
|
||||
}
|
||||
break;
|
||||
case WRITE_NUMBER:
|
||||
if (otherProto.hasTimedQuota()) {
|
||||
throttleBuilder.setWriteNum(otherProto.getTimedQuota());
|
||||
} else {
|
||||
throttleBuilder.clearWriteNum();
|
||||
}
|
||||
break;
|
||||
case WRITE_SIZE:
|
||||
if (otherProto.hasTimedQuota()) {
|
||||
throttleBuilder.setWriteSize(otherProto.getTimedQuota());
|
||||
} else {
|
||||
throttleBuilder.clearWriteSize();
|
||||
}
|
||||
break;
|
||||
case READ_NUMBER:
|
||||
if (otherProto.hasTimedQuota()) {
|
||||
throttleBuilder.setReadNum(otherProto.getTimedQuota());
|
||||
} else {
|
||||
throttleBuilder.clearReqNum();
|
||||
}
|
||||
break;
|
||||
case READ_SIZE:
|
||||
if (otherProto.hasTimedQuota()) {
|
||||
throttleBuilder.setReadSize(otherProto.getTimedQuota());
|
||||
} else {
|
||||
throttleBuilder.clearReadSize();
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
clearThrottleBuilder(throttleBuilder);
|
||||
}
|
||||
} else {
|
||||
clearThrottleBuilder(throttleBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
// Propagate the space quota portion
|
||||
QuotaProtos.SpaceQuota.Builder spaceBuilder = (spaceProto == null
|
||||
? null : spaceProto.toBuilder());
|
||||
if (other instanceof SpaceLimitSettings) {
|
||||
if (spaceBuilder == null) {
|
||||
spaceBuilder = QuotaProtos.SpaceQuota.newBuilder();
|
||||
}
|
||||
SpaceLimitSettings settingsToMerge = (SpaceLimitSettings) other;
|
||||
|
||||
QuotaProtos.SpaceLimitRequest spaceRequest = settingsToMerge.getProto();
|
||||
|
||||
// The message contained the expect SpaceQuota object
|
||||
if (spaceRequest.hasQuota()) {
|
||||
SpaceQuota quotaToMerge = spaceRequest.getQuota();
|
||||
// Validate that the two settings are for the same target.
|
||||
// SpaceQuotas either apply to a table or a namespace (no user spacequota).
|
||||
if (!Objects.equals(getTableName(), settingsToMerge.getTableName())
|
||||
&& !Objects.equals(getNamespace(), settingsToMerge.getNamespace())) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot merge " + settingsToMerge + " into " + this);
|
||||
}
|
||||
|
||||
if (quotaToMerge.getRemove()) {
|
||||
// Update the builder to propagate the removal
|
||||
spaceBuilder.setRemove(true).clearSoftLimit().clearViolationPolicy();
|
||||
} else {
|
||||
// Add the new settings to the existing settings
|
||||
spaceBuilder.mergeFrom(quotaToMerge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Boolean bypassGlobals = this.bypassGlobals;
|
||||
if (other instanceof QuotaGlobalsSettingsBypass) {
|
||||
bypassGlobals = ((QuotaGlobalsSettingsBypass) other).getBypass();
|
||||
}
|
||||
|
||||
if (throttleBuilder == null &&
|
||||
(spaceBuilder == null || (spaceBuilder.hasRemove() && spaceBuilder.getRemove()))
|
||||
&& bypassGlobals == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new GlobalQuotaSettingsImpl(
|
||||
getUserName(), getTableName(), getNamespace(),
|
||||
(throttleBuilder == null ? null : throttleBuilder.build()), bypassGlobals,
|
||||
(spaceBuilder == null ? null : spaceBuilder.build()));
|
||||
}
|
||||
|
||||
private void validateTimedQuota(final TimedQuota timedQuota) throws IOException {
|
||||
if (timedQuota.getSoftLimit() < 1) {
|
||||
throw new DoNotRetryIOException(new UnsupportedOperationException(
|
||||
"The throttle limit must be greater then 0, got " + timedQuota.getSoftLimit()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("GlobalQuota: ");
|
||||
if (throttleProto != null) {
|
||||
Map<ThrottleType,TimedQuota> throttleQuotas = buildThrottleQuotas(throttleProto);
|
||||
builder.append(" { TYPE => THROTTLE ");
|
||||
for (Entry<ThrottleType,TimedQuota> entry : throttleQuotas.entrySet()) {
|
||||
final ThrottleType type = entry.getKey();
|
||||
final TimedQuota timedQuota = entry.getValue();
|
||||
builder.append("{THROTTLE_TYPE => ").append(type.name()).append(", LIMIT => ");
|
||||
if (timedQuota.hasSoftLimit()) {
|
||||
switch (type) {
|
||||
case REQUEST_NUMBER:
|
||||
case WRITE_NUMBER:
|
||||
case READ_NUMBER:
|
||||
builder.append(String.format("%dreq", timedQuota.getSoftLimit()));
|
||||
break;
|
||||
case REQUEST_SIZE:
|
||||
case WRITE_SIZE:
|
||||
case READ_SIZE:
|
||||
builder.append(sizeToString(timedQuota.getSoftLimit()));
|
||||
break;
|
||||
}
|
||||
} else if (timedQuota.hasShare()) {
|
||||
builder.append(String.format("%.2f%%", timedQuota.getShare()));
|
||||
}
|
||||
builder.append('/');
|
||||
builder.append(timeToString(ProtobufUtil.toTimeUnit(timedQuota.getTimeUnit())));
|
||||
if (timedQuota.hasScope()) {
|
||||
builder.append(", SCOPE => ");
|
||||
builder.append(timedQuota.getScope().toString());
|
||||
}
|
||||
}
|
||||
builder.append( "} } ");
|
||||
} else {
|
||||
builder.append(" {} ");
|
||||
}
|
||||
if (bypassGlobals != null) {
|
||||
builder.append(" { GLOBAL_BYPASS => " + bypassGlobals + " } ");
|
||||
}
|
||||
if (spaceProto != null) {
|
||||
builder.append(" { TYPE => SPACE");
|
||||
if (getTableName() != null) {
|
||||
builder.append(", TABLE => ").append(getTableName());
|
||||
}
|
||||
if (getNamespace() != null) {
|
||||
builder.append(", NAMESPACE => ").append(getNamespace());
|
||||
}
|
||||
if (spaceProto.getRemove()) {
|
||||
builder.append(", REMOVE => ").append(spaceProto.getRemove());
|
||||
} else {
|
||||
builder.append(", LIMIT => ").append(spaceProto.getSoftLimit());
|
||||
builder.append(", VIOLATION_POLICY => ").append(spaceProto.getViolationPolicy());
|
||||
}
|
||||
builder.append(" } ");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private Map<ThrottleType,TimedQuota> buildThrottleQuotas(Throttle proto) {
|
||||
HashMap<ThrottleType,TimedQuota> quotas = new HashMap<>();
|
||||
if (proto.hasReadNum()) {
|
||||
quotas.put(ThrottleType.READ_NUMBER, proto.getReadNum());
|
||||
}
|
||||
if (proto.hasReadSize()) {
|
||||
quotas.put(ThrottleType.READ_SIZE, proto.getReadSize());
|
||||
}
|
||||
if (proto.hasReqNum()) {
|
||||
quotas.put(ThrottleType.REQUEST_NUMBER, proto.getReqNum());
|
||||
}
|
||||
if (proto.hasReqSize()) {
|
||||
quotas.put(ThrottleType.REQUEST_SIZE, proto.getReqSize());
|
||||
}
|
||||
if (proto.hasWriteNum()) {
|
||||
quotas.put(ThrottleType.WRITE_NUMBER, proto.getWriteNum());
|
||||
}
|
||||
if (proto.hasWriteSize()) {
|
||||
quotas.put(ThrottleType.WRITE_SIZE, proto.getWriteSize());
|
||||
}
|
||||
return quotas;
|
||||
}
|
||||
|
||||
private void clearThrottleBuilder(QuotaProtos.Throttle.Builder builder) {
|
||||
builder.clearReadNum();
|
||||
builder.clearReadSize();
|
||||
builder.clearReqNum();
|
||||
builder.clearReqSize();
|
||||
builder.clearWriteNum();
|
||||
builder.clearWriteSize();
|
||||
}
|
||||
}
|
|
@ -153,12 +153,12 @@ public class MasterQuotaManager implements RegionStateListener {
|
|||
throws IOException, InterruptedException {
|
||||
setQuota(req, new SetQuotaOperations() {
|
||||
@Override
|
||||
public GlobalQuotaSettings fetch() throws IOException {
|
||||
return new GlobalQuotaSettings(req.getUserName(), null, null, QuotaUtil.getUserQuota(
|
||||
public GlobalQuotaSettingsImpl fetch() throws IOException {
|
||||
return new GlobalQuotaSettingsImpl(req.getUserName(), null, null, QuotaUtil.getUserQuota(
|
||||
masterServices.getConnection(), userName));
|
||||
}
|
||||
@Override
|
||||
public void update(GlobalQuotaSettings quotaPojo) throws IOException {
|
||||
public void update(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||
QuotaUtil.addUserQuota(masterServices.getConnection(), userName, quotaPojo.toQuotas());
|
||||
}
|
||||
@Override
|
||||
|
@ -166,11 +166,11 @@ public class MasterQuotaManager implements RegionStateListener {
|
|||
QuotaUtil.deleteUserQuota(masterServices.getConnection(), userName);
|
||||
}
|
||||
@Override
|
||||
public void preApply(GlobalQuotaSettings quotaPojo) throws IOException {
|
||||
public void preApply(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||
masterServices.getMasterCoprocessorHost().preSetUserQuota(userName, quotaPojo);
|
||||
}
|
||||
@Override
|
||||
public void postApply(GlobalQuotaSettings quotaPojo) throws IOException {
|
||||
public void postApply(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||
masterServices.getMasterCoprocessorHost().postSetUserQuota(userName, quotaPojo);
|
||||
}
|
||||
});
|
||||
|
@ -180,12 +180,12 @@ public class MasterQuotaManager implements RegionStateListener {
|
|||
final SetQuotaRequest req) throws IOException, InterruptedException {
|
||||
setQuota(req, new SetQuotaOperations() {
|
||||
@Override
|
||||
public GlobalQuotaSettings fetch() throws IOException {
|
||||
return new GlobalQuotaSettings(userName, table, null, QuotaUtil.getUserQuota(
|
||||
public GlobalQuotaSettingsImpl fetch() throws IOException {
|
||||
return new GlobalQuotaSettingsImpl(userName, table, null, QuotaUtil.getUserQuota(
|
||||
masterServices.getConnection(), userName, table));
|
||||
}
|
||||
@Override
|
||||
public void update(GlobalQuotaSettings quotaPojo) throws IOException {
|
||||
public void update(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||
QuotaUtil.addUserQuota(masterServices.getConnection(), userName, table,
|
||||
quotaPojo.toQuotas());
|
||||
}
|
||||
|
@ -194,11 +194,11 @@ public class MasterQuotaManager implements RegionStateListener {
|
|||
QuotaUtil.deleteUserQuota(masterServices.getConnection(), userName, table);
|
||||
}
|
||||
@Override
|
||||
public void preApply(GlobalQuotaSettings quotaPojo) throws IOException {
|
||||
public void preApply(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||
masterServices.getMasterCoprocessorHost().preSetUserQuota(userName, table, quotaPojo);
|
||||
}
|
||||
@Override
|
||||
public void postApply(GlobalQuotaSettings quotaPojo) throws IOException {
|
||||
public void postApply(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||
masterServices.getMasterCoprocessorHost().postSetUserQuota(userName, table, quotaPojo);
|
||||
}
|
||||
});
|
||||
|
@ -208,12 +208,12 @@ public class MasterQuotaManager implements RegionStateListener {
|
|||
final SetQuotaRequest req) throws IOException, InterruptedException {
|
||||
setQuota(req, new SetQuotaOperations() {
|
||||
@Override
|
||||
public GlobalQuotaSettings fetch() throws IOException {
|
||||
return new GlobalQuotaSettings(userName, null, namespace, QuotaUtil.getUserQuota(
|
||||
public GlobalQuotaSettingsImpl fetch() throws IOException {
|
||||
return new GlobalQuotaSettingsImpl(userName, null, namespace, QuotaUtil.getUserQuota(
|
||||
masterServices.getConnection(), userName, namespace));
|
||||
}
|
||||
@Override
|
||||
public void update(GlobalQuotaSettings quotaPojo) throws IOException {
|
||||
public void update(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||
QuotaUtil.addUserQuota(masterServices.getConnection(), userName, namespace,
|
||||
quotaPojo.toQuotas());
|
||||
}
|
||||
|
@ -222,12 +222,12 @@ public class MasterQuotaManager implements RegionStateListener {
|
|||
QuotaUtil.deleteUserQuota(masterServices.getConnection(), userName, namespace);
|
||||
}
|
||||
@Override
|
||||
public void preApply(GlobalQuotaSettings quotaPojo) throws IOException {
|
||||
public void preApply(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||
masterServices.getMasterCoprocessorHost().preSetUserQuota(
|
||||
userName, namespace, quotaPojo);
|
||||
}
|
||||
@Override
|
||||
public void postApply(GlobalQuotaSettings quotaPojo) throws IOException {
|
||||
public void postApply(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||
masterServices.getMasterCoprocessorHost().postSetUserQuota(
|
||||
userName, namespace, quotaPojo);
|
||||
}
|
||||
|
@ -238,12 +238,12 @@ public class MasterQuotaManager implements RegionStateListener {
|
|||
throws IOException, InterruptedException {
|
||||
setQuota(req, new SetQuotaOperations() {
|
||||
@Override
|
||||
public GlobalQuotaSettings fetch() throws IOException {
|
||||
return new GlobalQuotaSettings(null, table, null, QuotaUtil.getTableQuota(
|
||||
public GlobalQuotaSettingsImpl fetch() throws IOException {
|
||||
return new GlobalQuotaSettingsImpl(null, table, null, QuotaUtil.getTableQuota(
|
||||
masterServices.getConnection(), table));
|
||||
}
|
||||
@Override
|
||||
public void update(GlobalQuotaSettings quotaPojo) throws IOException {
|
||||
public void update(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||
QuotaUtil.addTableQuota(masterServices.getConnection(), table, quotaPojo.toQuotas());
|
||||
}
|
||||
@Override
|
||||
|
@ -251,11 +251,11 @@ public class MasterQuotaManager implements RegionStateListener {
|
|||
QuotaUtil.deleteTableQuota(masterServices.getConnection(), table);
|
||||
}
|
||||
@Override
|
||||
public void preApply(GlobalQuotaSettings quotaPojo) throws IOException {
|
||||
public void preApply(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||
masterServices.getMasterCoprocessorHost().preSetTableQuota(table, quotaPojo);
|
||||
}
|
||||
@Override
|
||||
public void postApply(GlobalQuotaSettings quotaPojo) throws IOException {
|
||||
public void postApply(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||
masterServices.getMasterCoprocessorHost().postSetTableQuota(table, quotaPojo);
|
||||
}
|
||||
});
|
||||
|
@ -265,25 +265,25 @@ public class MasterQuotaManager implements RegionStateListener {
|
|||
throws IOException, InterruptedException {
|
||||
setQuota(req, new SetQuotaOperations() {
|
||||
@Override
|
||||
public GlobalQuotaSettings fetch() throws IOException {
|
||||
return new GlobalQuotaSettings(null, null, namespace, QuotaUtil.getNamespaceQuota(
|
||||
public GlobalQuotaSettingsImpl fetch() throws IOException {
|
||||
return new GlobalQuotaSettingsImpl(null, null, namespace, QuotaUtil.getNamespaceQuota(
|
||||
masterServices.getConnection(), namespace));
|
||||
}
|
||||
@Override
|
||||
public void update(GlobalQuotaSettings quotaPojo) throws IOException {
|
||||
public void update(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||
QuotaUtil.addNamespaceQuota(masterServices.getConnection(), namespace,
|
||||
((GlobalQuotaSettings) quotaPojo).toQuotas());
|
||||
((GlobalQuotaSettingsImpl) quotaPojo).toQuotas());
|
||||
}
|
||||
@Override
|
||||
public void delete() throws IOException {
|
||||
QuotaUtil.deleteNamespaceQuota(masterServices.getConnection(), namespace);
|
||||
}
|
||||
@Override
|
||||
public void preApply(GlobalQuotaSettings quotaPojo) throws IOException {
|
||||
public void preApply(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||
masterServices.getMasterCoprocessorHost().preSetNamespaceQuota(namespace, quotaPojo);
|
||||
}
|
||||
@Override
|
||||
public void postApply(GlobalQuotaSettings quotaPojo) throws IOException {
|
||||
public void postApply(GlobalQuotaSettingsImpl quotaPojo) throws IOException {
|
||||
masterServices.getMasterCoprocessorHost().postSetNamespaceQuota(namespace, quotaPojo);
|
||||
}
|
||||
});
|
||||
|
@ -311,7 +311,7 @@ public class MasterQuotaManager implements RegionStateListener {
|
|||
}
|
||||
|
||||
// Apply quota changes
|
||||
GlobalQuotaSettings currentQuota = quotaOps.fetch();
|
||||
GlobalQuotaSettingsImpl currentQuota = quotaOps.fetch();
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace(
|
||||
"Current quota for request(" + TextFormat.shortDebugString(req)
|
||||
|
@ -329,7 +329,7 @@ public class MasterQuotaManager implements RegionStateListener {
|
|||
//
|
||||
// NB: while SetQuotaRequest technically allows for multi types of quotas to be set in one
|
||||
// message, the Java API (in Admin/AsyncAdmin) does not. Assume there is only one type.
|
||||
GlobalQuotaSettings mergedQuota = currentQuota.merge(newQuota);
|
||||
GlobalQuotaSettingsImpl mergedQuota = currentQuota.merge(newQuota);
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Computed merged quota from current quota and user request: " + mergedQuota);
|
||||
}
|
||||
|
@ -403,7 +403,7 @@ public class MasterQuotaManager implements RegionStateListener {
|
|||
/**
|
||||
* Fetches the current quota settings for the subject.
|
||||
*/
|
||||
GlobalQuotaSettings fetch() throws IOException;
|
||||
GlobalQuotaSettingsImpl fetch() throws IOException;
|
||||
/**
|
||||
* Deletes the quota for the subject.
|
||||
*/
|
||||
|
@ -411,17 +411,17 @@ public class MasterQuotaManager implements RegionStateListener {
|
|||
/**
|
||||
* Persist the given quota for the subject.
|
||||
*/
|
||||
void update(GlobalQuotaSettings quotaPojo) throws IOException;
|
||||
void update(GlobalQuotaSettingsImpl quotaPojo) throws IOException;
|
||||
/**
|
||||
* Performs some action before {@link #update(GlobalQuotaSettings)} with the current quota
|
||||
* for the subject.
|
||||
* Performs some action before {@link #update(GlobalQuotaSettingsImpl)} with the current
|
||||
* quota for the subject.
|
||||
*/
|
||||
void preApply(GlobalQuotaSettings quotaPojo) throws IOException;
|
||||
void preApply(GlobalQuotaSettingsImpl quotaPojo) throws IOException;
|
||||
/**
|
||||
* Performs some action after {@link #update(GlobalQuotaSettings)} with the resulting quota
|
||||
* from the request action for the subject.
|
||||
* Performs some action after {@link #update(GlobalQuotaSettingsImpl)} with the resulting
|
||||
* quota from the request action for the subject.
|
||||
*/
|
||||
void postApply(GlobalQuotaSettings quotaPojo) throws IOException;
|
||||
void postApply(GlobalQuotaSettingsImpl quotaPojo) throws IOException;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.junit.Test;
|
|||
import org.junit.experimental.categories.Category;
|
||||
|
||||
@Category(SmallTests.class)
|
||||
public class TestGlobalQuotaSettings {
|
||||
public class TestGlobalQuotaSettingsImpl {
|
||||
|
||||
QuotaProtos.TimedQuota REQUEST_THROTTLE = QuotaProtos.TimedQuota.newBuilder()
|
||||
.setScope(QuotaProtos.QuotaScope.MACHINE).setSoftLimit(100)
|
||||
|
@ -51,8 +51,8 @@ public class TestGlobalQuotaSettings {
|
|||
QuotaProtos.ThrottleRequest writeThrottle = QuotaProtos.ThrottleRequest.newBuilder()
|
||||
.setTimedQuota(writeQuota).setType(QuotaProtos.ThrottleType.WRITE_NUMBER).build();
|
||||
|
||||
GlobalQuotaSettings settings = new GlobalQuotaSettings("joe", null, null, quota);
|
||||
GlobalQuotaSettings merged = settings.merge(
|
||||
GlobalQuotaSettingsImpl settings = new GlobalQuotaSettingsImpl("joe", null, null, quota);
|
||||
GlobalQuotaSettingsImpl merged = settings.merge(
|
||||
new ThrottleSettings("joe", null, null, writeThrottle));
|
||||
|
||||
QuotaProtos.Throttle mergedThrottle = merged.getThrottleProto();
|
||||
|
@ -73,9 +73,9 @@ public class TestGlobalQuotaSettings {
|
|||
QuotaProtos.Quotas quota = QuotaProtos.Quotas.newBuilder()
|
||||
.setSpace(SPACE_QUOTA).build();
|
||||
|
||||
GlobalQuotaSettings settings = new GlobalQuotaSettings(null, tn, null, quota);
|
||||
GlobalQuotaSettingsImpl settings = new GlobalQuotaSettingsImpl(null, tn, null, quota);
|
||||
// Switch the violation policy to DISABLE
|
||||
GlobalQuotaSettings merged = settings.merge(
|
||||
GlobalQuotaSettingsImpl merged = settings.merge(
|
||||
new SpaceLimitSettings(tn, SPACE_QUOTA.getSoftLimit(), SpaceViolationPolicy.DISABLE));
|
||||
|
||||
QuotaProtos.SpaceQuota mergedSpaceQuota = merged.getSpaceProto();
|
||||
|
@ -89,7 +89,7 @@ public class TestGlobalQuotaSettings {
|
|||
final String ns = "org1";
|
||||
QuotaProtos.Quotas quota = QuotaProtos.Quotas.newBuilder()
|
||||
.setThrottle(THROTTLE).setSpace(SPACE_QUOTA).build();
|
||||
GlobalQuotaSettings settings = new GlobalQuotaSettings(null, null, ns, quota);
|
||||
GlobalQuotaSettingsImpl settings = new GlobalQuotaSettingsImpl(null, null, ns, quota);
|
||||
|
||||
QuotaProtos.TimedQuota writeQuota = REQUEST_THROTTLE.toBuilder()
|
||||
.setSoftLimit(500).build();
|
||||
|
@ -97,9 +97,9 @@ public class TestGlobalQuotaSettings {
|
|||
QuotaProtos.ThrottleRequest writeThrottle = QuotaProtos.ThrottleRequest.newBuilder()
|
||||
.setTimedQuota(writeQuota).setType(QuotaProtos.ThrottleType.WRITE_NUMBER).build();
|
||||
|
||||
GlobalQuotaSettings merged = settings.merge(
|
||||
GlobalQuotaSettingsImpl merged = settings.merge(
|
||||
new ThrottleSettings(null, null, ns, writeThrottle));
|
||||
GlobalQuotaSettings finalQuota = merged.merge(new SpaceLimitSettings(
|
||||
GlobalQuotaSettingsImpl finalQuota = merged.merge(new SpaceLimitSettings(
|
||||
ns, SPACE_QUOTA.getSoftLimit(), SpaceViolationPolicy.NO_WRITES_COMPACTIONS));
|
||||
|
||||
// Verify both throttle quotas
|
Loading…
Reference in New Issue