HBASE-21843 RegionGroupingProvider breaks the meta wal file name pattern which may...
[hbase.git] / hbase-server / src / main / java / org / apache / hadoop / hbase / quotas / GlobalQuotaSettingsImpl.java
blobc7df789c20094aa4355d032325042be322201540
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to you under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 package org.apache.hadoop.hbase.quotas;
19 import java.io.IOException;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Objects;
25 import java.util.Map.Entry;
27 import org.apache.hadoop.hbase.DoNotRetryIOException;
28 import org.apache.hadoop.hbase.TableName;
29 import org.apache.hadoop.hbase.quotas.QuotaSettingsFactory.QuotaGlobalsSettingsBypass;
30 import org.apache.yetus.audience.InterfaceAudience;
32 import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
33 import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos;
34 import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Quotas;
35 import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.SpaceQuota;
36 import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Throttle;
37 import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.TimedQuota;
39 /**
40 * Implementation of {@link GlobalQuotaSettings} to hide the Protobuf messages we use internally.
42 @InterfaceAudience.Private
43 public class GlobalQuotaSettingsImpl extends GlobalQuotaSettings {
45 private final QuotaProtos.Throttle throttleProto;
46 private final Boolean bypassGlobals;
47 private final QuotaProtos.SpaceQuota spaceProto;
49 protected GlobalQuotaSettingsImpl(String username, TableName tableName, String namespace,
50 String regionServer, QuotaProtos.Quotas quotas) {
51 this(username, tableName, namespace, regionServer,
52 (quotas != null && quotas.hasThrottle() ? quotas.getThrottle() : null),
53 (quotas != null && quotas.hasBypassGlobals() ? quotas.getBypassGlobals() : null),
54 (quotas != null && quotas.hasSpace() ? quotas.getSpace() : null));
57 protected GlobalQuotaSettingsImpl(String userName, TableName tableName, String namespace,
58 String regionServer, QuotaProtos.Throttle throttleProto, Boolean bypassGlobals,
59 QuotaProtos.SpaceQuota spaceProto) {
60 super(userName, tableName, namespace, regionServer);
61 this.throttleProto = throttleProto;
62 this.bypassGlobals = bypassGlobals;
63 this.spaceProto = spaceProto;
66 @Override
67 public List<QuotaSettings> getQuotaSettings() {
68 // Very similar to QuotaSettingsFactory
69 List<QuotaSettings> settings = new ArrayList<>();
70 if (throttleProto != null) {
71 settings.addAll(QuotaSettingsFactory.fromThrottle(getUserName(), getTableName(),
72 getNamespace(), getRegionServer(), throttleProto));
74 if (bypassGlobals != null && bypassGlobals.booleanValue()) {
75 settings.add(new QuotaGlobalsSettingsBypass(getUserName(), getTableName(), getNamespace(),
76 getRegionServer(), true));
78 if (spaceProto != null) {
79 settings.add(QuotaSettingsFactory.fromSpace(getTableName(), getNamespace(), spaceProto));
81 return settings;
84 protected QuotaProtos.Throttle getThrottleProto() {
85 return this.throttleProto;
88 protected Boolean getBypassGlobals() {
89 return this.bypassGlobals;
92 protected QuotaProtos.SpaceQuota getSpaceProto() {
93 return this.spaceProto;
96 /**
97 * Constructs a new {@link Quotas} message from {@code this}.
99 protected Quotas toQuotas() {
100 QuotaProtos.Quotas.Builder builder = QuotaProtos.Quotas.newBuilder();
101 if (getThrottleProto() != null) {
102 builder.setThrottle(getThrottleProto());
104 if (getBypassGlobals() != null) {
105 builder.setBypassGlobals(getBypassGlobals());
107 if (getSpaceProto() != null) {
108 builder.setSpace(getSpaceProto());
110 return builder.build();
113 @Override
114 protected GlobalQuotaSettingsImpl merge(QuotaSettings other) throws IOException {
115 // Validate the quota subject
116 validateQuotaTarget(other);
118 // Propagate the Throttle
119 QuotaProtos.Throttle.Builder throttleBuilder =
120 throttleProto == null ? null : throttleProto.toBuilder();
122 if (other instanceof ThrottleSettings) {
123 ThrottleSettings otherThrottle = (ThrottleSettings) other;
124 if (!otherThrottle.proto.hasType() || !otherThrottle.proto.hasTimedQuota()) {
125 // It means it's a remove request
126 // To prevent the "empty" row in QuotaTableUtil.QUOTA_TABLE_NAME
127 throttleBuilder = null;
128 } else {
129 QuotaProtos.ThrottleRequest otherProto = otherThrottle.proto;
130 validateTimedQuota(otherProto.getTimedQuota());
131 if (throttleBuilder == null) {
132 throttleBuilder = QuotaProtos.Throttle.newBuilder();
135 switch (otherProto.getType()) {
136 case REQUEST_NUMBER:
137 throttleBuilder.setReqNum(otherProto.getTimedQuota());
138 break;
139 case REQUEST_SIZE:
140 throttleBuilder.setReqSize(otherProto.getTimedQuota());
141 break;
142 case WRITE_NUMBER:
143 throttleBuilder.setWriteNum(otherProto.getTimedQuota());
144 break;
145 case WRITE_SIZE:
146 throttleBuilder.setWriteSize(otherProto.getTimedQuota());
147 break;
148 case READ_NUMBER:
149 throttleBuilder.setReadNum(otherProto.getTimedQuota());
150 break;
151 case READ_SIZE:
152 throttleBuilder.setReadSize(otherProto.getTimedQuota());
153 break;
154 case REQUEST_CAPACITY_UNIT:
155 throttleBuilder.setReqCapacityUnit(otherProto.getTimedQuota());
156 break;
157 case READ_CAPACITY_UNIT:
158 throttleBuilder.setReadCapacityUnit(otherProto.getTimedQuota());
159 break;
160 case WRITE_CAPACITY_UNIT:
161 throttleBuilder.setWriteCapacityUnit(otherProto.getTimedQuota());
162 break;
163 default:
168 // Propagate the space quota portion
169 QuotaProtos.SpaceQuota.Builder spaceBuilder = (spaceProto == null
170 ? null : spaceProto.toBuilder());
171 if (other instanceof SpaceLimitSettings) {
172 if (spaceBuilder == null) {
173 spaceBuilder = QuotaProtos.SpaceQuota.newBuilder();
175 SpaceLimitSettings settingsToMerge = (SpaceLimitSettings) other;
177 QuotaProtos.SpaceLimitRequest spaceRequest = settingsToMerge.getProto();
179 // The message contained the expect SpaceQuota object
180 if (spaceRequest.hasQuota()) {
181 SpaceQuota quotaToMerge = spaceRequest.getQuota();
182 // Validate that the two settings are for the same target.
183 // SpaceQuotas either apply to a table or a namespace (no user spacequota).
184 if (!Objects.equals(getTableName(), settingsToMerge.getTableName())
185 && !Objects.equals(getNamespace(), settingsToMerge.getNamespace())) {
186 throw new IllegalArgumentException(
187 "Cannot merge " + settingsToMerge + " into " + this);
190 if (quotaToMerge.getRemove()) {
191 // It means it's a remove request
192 // Update the builder to propagate the removal
193 spaceBuilder.setRemove(true).clearSoftLimit().clearViolationPolicy();
194 } else {
195 // Add the new settings to the existing settings
196 spaceBuilder.mergeFrom(quotaToMerge);
201 boolean removeSpaceBuilder =
202 (spaceBuilder == null) || (spaceBuilder.hasRemove() && spaceBuilder.getRemove());
204 Boolean bypassGlobals = this.bypassGlobals;
205 if (other instanceof QuotaGlobalsSettingsBypass) {
206 bypassGlobals = ((QuotaGlobalsSettingsBypass) other).getBypass();
209 if (throttleBuilder == null && removeSpaceBuilder && bypassGlobals == null) {
210 return null;
213 return new GlobalQuotaSettingsImpl(
214 getUserName(), getTableName(), getNamespace(), getRegionServer(),
215 (throttleBuilder == null ? null : throttleBuilder.build()), bypassGlobals,
216 (removeSpaceBuilder ? null : spaceBuilder.build()));
219 private void validateTimedQuota(final TimedQuota timedQuota) throws IOException {
220 if (timedQuota.getSoftLimit() < 1) {
221 throw new DoNotRetryIOException(new UnsupportedOperationException(
222 "The throttle limit must be greater then 0, got " + timedQuota.getSoftLimit()));
226 @Override
227 public String toString() {
228 StringBuilder builder = new StringBuilder();
229 builder.append("GlobalQuota: ");
230 if (throttleProto != null) {
231 Map<ThrottleType,TimedQuota> throttleQuotas = buildThrottleQuotas(throttleProto);
232 builder.append(" { TYPE => THROTTLE ");
233 for (Entry<ThrottleType,TimedQuota> entry : throttleQuotas.entrySet()) {
234 final ThrottleType type = entry.getKey();
235 final TimedQuota timedQuota = entry.getValue();
236 builder.append("{THROTTLE_TYPE => ").append(type.name()).append(", LIMIT => ");
237 if (timedQuota.hasSoftLimit()) {
238 switch (type) {
239 case REQUEST_NUMBER:
240 case WRITE_NUMBER:
241 case READ_NUMBER:
242 builder.append(String.format("%dreq", timedQuota.getSoftLimit()));
243 break;
244 case REQUEST_SIZE:
245 case WRITE_SIZE:
246 case READ_SIZE:
247 builder.append(sizeToString(timedQuota.getSoftLimit()));
248 break;
249 case REQUEST_CAPACITY_UNIT:
250 case READ_CAPACITY_UNIT:
251 case WRITE_CAPACITY_UNIT:
252 builder.append(String.format("%dCU", timedQuota.getSoftLimit()));
253 default:
255 } else if (timedQuota.hasShare()) {
256 builder.append(String.format("%.2f%%", timedQuota.getShare()));
258 builder.append('/');
259 builder.append(timeToString(ProtobufUtil.toTimeUnit(timedQuota.getTimeUnit())));
260 if (timedQuota.hasScope()) {
261 builder.append(", SCOPE => ");
262 builder.append(timedQuota.getScope().toString());
265 builder.append( "} } ");
266 } else {
267 builder.append(" {} ");
269 if (bypassGlobals != null) {
270 builder.append(" { GLOBAL_BYPASS => " + bypassGlobals + " } ");
272 if (spaceProto != null) {
273 builder.append(" { TYPE => SPACE");
274 if (getTableName() != null) {
275 builder.append(", TABLE => ").append(getTableName());
277 if (getNamespace() != null) {
278 builder.append(", NAMESPACE => ").append(getNamespace());
280 if (spaceProto.getRemove()) {
281 builder.append(", REMOVE => ").append(spaceProto.getRemove());
282 } else {
283 builder.append(", LIMIT => ").append(sizeToString(spaceProto.getSoftLimit()));
284 builder.append(", VIOLATION_POLICY => ").append(spaceProto.getViolationPolicy());
286 builder.append(" } ");
288 return builder.toString();
291 private Map<ThrottleType,TimedQuota> buildThrottleQuotas(Throttle proto) {
292 HashMap<ThrottleType,TimedQuota> quotas = new HashMap<>();
293 if (proto.hasReadNum()) {
294 quotas.put(ThrottleType.READ_NUMBER, proto.getReadNum());
296 if (proto.hasReadSize()) {
297 quotas.put(ThrottleType.READ_SIZE, proto.getReadSize());
299 if (proto.hasReqNum()) {
300 quotas.put(ThrottleType.REQUEST_NUMBER, proto.getReqNum());
302 if (proto.hasReqSize()) {
303 quotas.put(ThrottleType.REQUEST_SIZE, proto.getReqSize());
305 if (proto.hasWriteNum()) {
306 quotas.put(ThrottleType.WRITE_NUMBER, proto.getWriteNum());
308 if (proto.hasWriteSize()) {
309 quotas.put(ThrottleType.WRITE_SIZE, proto.getWriteSize());
311 if (proto.hasReqCapacityUnit()) {
312 quotas.put(ThrottleType.REQUEST_CAPACITY_UNIT, proto.getReqCapacityUnit());
314 if (proto.hasReadCapacityUnit()) {
315 quotas.put(ThrottleType.READ_CAPACITY_UNIT, proto.getReqCapacityUnit());
317 if (proto.hasWriteCapacityUnit()) {
318 quotas.put(ThrottleType.WRITE_CAPACITY_UNIT, proto.getWriteCapacityUnit());
320 return quotas;