001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.quotas;
019
020import java.io.IOException;
021import java.util.ArrayList;
022import java.util.List;
023import java.util.concurrent.TimeUnit;
024
025import org.apache.hadoop.hbase.TableName;
026import org.apache.yetus.audience.InterfaceAudience;
027
028import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
029import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetQuotaRequest;
030import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos;
031import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Quotas;
032import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.SpaceQuota;
033
034@InterfaceAudience.Public
035public class QuotaSettingsFactory {
036  static class QuotaGlobalsSettingsBypass extends QuotaSettings {
037    private final boolean bypassGlobals;
038
039    QuotaGlobalsSettingsBypass(final String userName, final TableName tableName,
040        final String namespace, final String regionServer, final boolean bypassGlobals) {
041      super(userName, tableName, namespace, regionServer);
042      this.bypassGlobals = bypassGlobals;
043    }
044
045    @Override
046    public QuotaType getQuotaType() {
047      return QuotaType.GLOBAL_BYPASS;
048    }
049
050    @Override
051    protected void setupSetQuotaRequest(SetQuotaRequest.Builder builder) {
052      builder.setBypassGlobals(bypassGlobals);
053    }
054
055    @Override
056    public String toString() {
057      return "GLOBAL_BYPASS => " + bypassGlobals;
058    }
059
060    protected boolean getBypass() {
061      return bypassGlobals;
062    }
063
064    @Override
065    protected QuotaGlobalsSettingsBypass merge(QuotaSettings newSettings) throws IOException {
066      if (newSettings instanceof QuotaGlobalsSettingsBypass) {
067        QuotaGlobalsSettingsBypass other = (QuotaGlobalsSettingsBypass) newSettings;
068
069        validateQuotaTarget(other);
070
071        if (getBypass() != other.getBypass()) {
072          return other;
073        }
074      }
075      return this;
076    }
077  }
078
079  /* ==========================================================================
080   *  QuotaSettings from the Quotas object
081   */
082  static List<QuotaSettings> fromUserQuotas(final String userName, final Quotas quotas) {
083    return fromQuotas(userName, null, null, null, quotas);
084  }
085
086  static List<QuotaSettings> fromUserQuotas(final String userName, final TableName tableName,
087      final Quotas quotas) {
088    return fromQuotas(userName, tableName, null, null, quotas);
089  }
090
091  static List<QuotaSettings> fromUserQuotas(final String userName, final String namespace,
092      final Quotas quotas) {
093    return fromQuotas(userName, null, namespace, null, quotas);
094  }
095
096  static List<QuotaSettings> fromTableQuotas(final TableName tableName, final Quotas quotas) {
097    return fromQuotas(null, tableName, null, null, quotas);
098  }
099
100  static List<QuotaSettings> fromNamespaceQuotas(final String namespace, final Quotas quotas) {
101    return fromQuotas(null, null, namespace, null, quotas);
102  }
103
104  static List<QuotaSettings> fromRegionServerQuotas(final String regionServer,
105      final Quotas quotas) {
106    return fromQuotas(null, null, null, regionServer, quotas);
107  }
108
109  private static List<QuotaSettings> fromQuotas(final String userName, final TableName tableName,
110      final String namespace, final String regionServer, final Quotas quotas) {
111    List<QuotaSettings> settings = new ArrayList<>();
112    if (quotas.hasThrottle()) {
113      settings
114          .addAll(fromThrottle(userName, tableName, namespace, regionServer, quotas.getThrottle()));
115    }
116    if (quotas.getBypassGlobals() == true) {
117      settings
118          .add(new QuotaGlobalsSettingsBypass(userName, tableName, namespace, regionServer, true));
119    }
120    if (quotas.hasSpace()) {
121      settings.add(fromSpace(tableName, namespace, quotas.getSpace()));
122    }
123    return settings;
124  }
125
126  protected static List<QuotaSettings> fromThrottle(final String userName,
127      final TableName tableName, final String namespace, final String regionServer,
128      final QuotaProtos.Throttle throttle) {
129    List<QuotaSettings> settings = new ArrayList<>();
130    if (throttle.hasReqNum()) {
131      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
132        ThrottleType.REQUEST_NUMBER, throttle.getReqNum()));
133    }
134    if (throttle.hasReqSize()) {
135      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
136        ThrottleType.REQUEST_SIZE, throttle.getReqSize()));
137    }
138    if (throttle.hasWriteNum()) {
139      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
140        ThrottleType.WRITE_NUMBER, throttle.getWriteNum()));
141    }
142    if (throttle.hasWriteSize()) {
143      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
144        ThrottleType.WRITE_SIZE, throttle.getWriteSize()));
145    }
146    if (throttle.hasReadNum()) {
147      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
148        ThrottleType.READ_NUMBER, throttle.getReadNum()));
149    }
150    if (throttle.hasReadSize()) {
151      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
152        ThrottleType.READ_SIZE, throttle.getReadSize()));
153    }
154    if (throttle.hasReqCapacityUnit()) {
155      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
156        ThrottleType.REQUEST_CAPACITY_UNIT, throttle.getReqCapacityUnit()));
157    }
158    if (throttle.hasReadCapacityUnit()) {
159      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
160        ThrottleType.READ_CAPACITY_UNIT, throttle.getReadCapacityUnit()));
161    }
162    if (throttle.hasWriteCapacityUnit()) {
163      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
164        ThrottleType.WRITE_CAPACITY_UNIT, throttle.getWriteCapacityUnit()));
165    }
166    return settings;
167  }
168
169  static QuotaSettings fromSpace(TableName table, String namespace, SpaceQuota protoQuota) {
170    if (protoQuota == null) {
171      return null;
172    }
173    if ((table == null && namespace == null) || (table != null && namespace != null)) {
174      throw new IllegalArgumentException(
175          "Can only construct SpaceLimitSettings for a table or namespace.");
176    }
177    if (table != null) {
178      if (protoQuota.getRemove()) {
179        return new SpaceLimitSettings(table);
180      }
181      return SpaceLimitSettings.fromSpaceQuota(table, protoQuota);
182    } else {
183      if (protoQuota.getRemove()) {
184        return new SpaceLimitSettings(namespace);
185      }
186      // namespace must be non-null
187      return SpaceLimitSettings.fromSpaceQuota(namespace, protoQuota);
188    }
189  }
190
191  /* ==========================================================================
192   *  RPC Throttle
193   */
194
195  /**
196   * Throttle the specified user.
197   *
198   * @param userName the user to throttle
199   * @param type the type of throttling
200   * @param limit the allowed number of request/data per timeUnit
201   * @param timeUnit the limit time unit
202   * @return the quota settings
203   */
204  public static QuotaSettings throttleUser(final String userName, final ThrottleType type,
205      final long limit, final TimeUnit timeUnit) {
206    return throttleUser(userName, type, limit, timeUnit, QuotaScope.MACHINE);
207  }
208
209  /**
210   * Throttle the specified user.
211   * @param userName the user to throttle
212   * @param type the type of throttling
213   * @param limit the allowed number of request/data per timeUnit
214   * @param timeUnit the limit time unit
215   * @param scope the scope of throttling
216   * @return the quota settings
217   */
218  public static QuotaSettings throttleUser(final String userName, final ThrottleType type,
219      final long limit, final TimeUnit timeUnit, QuotaScope scope) {
220    return throttle(userName, null, null, null, type, limit, timeUnit, scope);
221  }
222
223  /**
224   * Throttle the specified user on the specified table.
225   *
226   * @param userName the user to throttle
227   * @param tableName the table to throttle
228   * @param type the type of throttling
229   * @param limit the allowed number of request/data per timeUnit
230   * @param timeUnit the limit time unit
231   * @return the quota settings
232   */
233  public static QuotaSettings throttleUser(final String userName, final TableName tableName,
234      final ThrottleType type, final long limit, final TimeUnit timeUnit) {
235    return throttleUser(userName, tableName, type, limit, timeUnit, QuotaScope.MACHINE);
236  }
237
238  /**
239   * Throttle the specified user on the specified table.
240   * @param userName the user to throttle
241   * @param tableName the table to throttle
242   * @param type the type of throttling
243   * @param limit the allowed number of request/data per timeUnit
244   * @param timeUnit the limit time unit
245   * @param scope the scope of throttling
246   * @return the quota settings
247   */
248  public static QuotaSettings throttleUser(final String userName, final TableName tableName,
249      final ThrottleType type, final long limit, final TimeUnit timeUnit, QuotaScope scope) {
250    return throttle(userName, tableName, null, null, type, limit, timeUnit, scope);
251  }
252
253  /**
254   * Throttle the specified user on the specified namespace.
255   *
256   * @param userName the user to throttle
257   * @param namespace the namespace to throttle
258   * @param type the type of throttling
259   * @param limit the allowed number of request/data per timeUnit
260   * @param timeUnit the limit time unit
261   * @return the quota settings
262   */
263  public static QuotaSettings throttleUser(final String userName, final String namespace,
264      final ThrottleType type, final long limit, final TimeUnit timeUnit) {
265    return throttleUser(userName, namespace, type, limit, timeUnit, QuotaScope.MACHINE);
266  }
267
268  /**
269   * Throttle the specified user on the specified namespace.
270   * @param userName the user to throttle
271   * @param namespace the namespace to throttle
272   * @param type the type of throttling
273   * @param limit the allowed number of request/data per timeUnit
274   * @param timeUnit the limit time unit
275   * @param scope the scope of throttling
276   * @return the quota settings
277   */
278  public static QuotaSettings throttleUser(final String userName, final String namespace,
279      final ThrottleType type, final long limit, final TimeUnit timeUnit, QuotaScope scope) {
280    return throttle(userName, null, namespace, null, type, limit, timeUnit, scope);
281  }
282
283  /**
284   * Remove the throttling for the specified user.
285   *
286   * @param userName the user
287   * @return the quota settings
288   */
289  public static QuotaSettings unthrottleUser(final String userName) {
290    return throttle(userName, null, null, null, null, 0, null, QuotaScope.MACHINE);
291  }
292
293  /**
294   * Remove the throttling for the specified user.
295   *
296   * @param userName the user
297   * @param type the type of throttling
298   * @return the quota settings
299   */
300  public static QuotaSettings unthrottleUserByThrottleType(final String userName,
301      final ThrottleType type) {
302    return throttle(userName, null, null, null, type, 0, null, QuotaScope.MACHINE);
303  }
304
305  /**
306   * Remove the throttling for the specified user on the specified table.
307   *
308   * @param userName the user
309   * @param tableName the table
310   * @return the quota settings
311   */
312  public static QuotaSettings unthrottleUser(final String userName, final TableName tableName) {
313    return throttle(userName, tableName, null, null, null, 0, null, QuotaScope.MACHINE);
314  }
315
316  /**
317   * Remove the throttling for the specified user on the specified table.
318   *
319   * @param userName the user
320   * @param tableName the table
321   * @param type the type of throttling
322   * @return the quota settings
323   */
324  public static QuotaSettings unthrottleUserByThrottleType(final String userName,
325      final TableName tableName, final ThrottleType type) {
326    return throttle(userName, tableName, null, null, type, 0, null, QuotaScope.MACHINE);
327  }
328
329  /**
330   * Remove the throttling for the specified user on the specified namespace.
331   *
332   * @param userName the user
333   * @param namespace the namespace
334   * @return the quota settings
335   */
336  public static QuotaSettings unthrottleUser(final String userName, final String namespace) {
337    return throttle(userName, null, namespace, null, null, 0, null, QuotaScope.MACHINE);
338  }
339
340  /**
341   * Remove the throttling for the specified user on the specified namespace.
342   *
343   * @param userName the user
344   * @param namespace the namespace
345   * @param type the type of throttling
346   * @return the quota settings
347   */
348  public static QuotaSettings unthrottleUserByThrottleType(final String userName,
349      final String namespace, final ThrottleType type) {
350    return throttle(userName, null, namespace, null, type, 0, null, QuotaScope.MACHINE);
351  }
352
353  /**
354   * Throttle the specified table.
355   *
356   * @param tableName the table to throttle
357   * @param type the type of throttling
358   * @param limit the allowed number of request/data per timeUnit
359   * @param timeUnit the limit time unit
360   * @return the quota settings
361   */
362  public static QuotaSettings throttleTable(final TableName tableName, final ThrottleType type,
363      final long limit, final TimeUnit timeUnit) {
364    return throttleTable(tableName, type, limit, timeUnit, QuotaScope.MACHINE);
365  }
366
367  /**
368   * Throttle the specified table.
369   * @param tableName the table to throttle
370   * @param type the type of throttling
371   * @param limit the allowed number of request/data per timeUnit
372   * @param timeUnit the limit time unit
373   * @param scope the scope of throttling
374   * @return the quota settings
375   */
376  public static QuotaSettings throttleTable(final TableName tableName, final ThrottleType type,
377      final long limit, final TimeUnit timeUnit, QuotaScope scope) {
378    return throttle(null, tableName, null, null, type, limit, timeUnit, scope);
379  }
380
381  /**
382   * Remove the throttling for the specified table.
383   *
384   * @param tableName the table
385   * @return the quota settings
386   */
387  public static QuotaSettings unthrottleTable(final TableName tableName) {
388    return throttle(null, tableName, null, null, null, 0, null, QuotaScope.MACHINE);
389  }
390
391  /**
392   * Remove the throttling for the specified table.
393   *
394   * @param tableName the table
395   * @param type the type of throttling
396   * @return the quota settings
397   */
398  public static QuotaSettings unthrottleTableByThrottleType(final TableName tableName,
399      final ThrottleType type) {
400    return throttle(null, tableName, null, null, type, 0, null, QuotaScope.MACHINE);
401  }
402
403  /**
404   * Throttle the specified namespace.
405   *
406   * @param namespace the namespace to throttle
407   * @param type the type of throttling
408   * @param limit the allowed number of request/data per timeUnit
409   * @param timeUnit the limit time unit
410   * @return the quota settings
411   */
412  public static QuotaSettings throttleNamespace(final String namespace, final ThrottleType type,
413      final long limit, final TimeUnit timeUnit) {
414    return throttleNamespace(namespace, type, limit, timeUnit, QuotaScope.MACHINE);
415  }
416
417  /**
418   * Throttle the specified namespace.
419   * @param namespace the namespace to throttle
420   * @param type the type of throttling
421   * @param limit the allowed number of request/data per timeUnit
422   * @param timeUnit the limit time unit
423   * @param scope the scope of throttling
424   * @return the quota settings
425   */
426  public static QuotaSettings throttleNamespace(final String namespace, final ThrottleType type,
427      final long limit, final TimeUnit timeUnit, QuotaScope scope) {
428    return throttle(null, null, namespace, null, type, limit, timeUnit, scope);
429  }
430
431  /**
432   * Remove the throttling for the specified namespace.
433   *
434   * @param namespace the namespace
435   * @return the quota settings
436   */
437  public static QuotaSettings unthrottleNamespace(final String namespace) {
438    return throttle(null, null, namespace, null, null, 0, null, QuotaScope.MACHINE);
439  }
440
441  /**
442   * Remove the throttling for the specified namespace by throttle type.
443   *
444   * @param namespace the namespace
445   * @param type the type of throttling
446   * @return the quota settings
447   */
448  public static QuotaSettings unthrottleNamespaceByThrottleType(final String namespace,
449      final ThrottleType type) {
450    return throttle(null, null, namespace, null, type, 0, null, QuotaScope.MACHINE);
451  }
452
453  /**
454   * Throttle the specified region server.
455   *
456   * @param regionServer the region server to throttle
457   * @param type the type of throttling
458   * @param limit the allowed number of request/data per timeUnit
459   * @param timeUnit the limit time unit
460   * @return the quota settings
461   */
462  public static QuotaSettings throttleRegionServer(final String regionServer,
463      final ThrottleType type, final long limit, final TimeUnit timeUnit) {
464    return throttle(null, null, null, regionServer, type, limit, timeUnit, QuotaScope.MACHINE);
465  }
466
467  /**
468   * Remove the throttling for the specified region server.
469   *
470   * @param regionServer the region Server
471   * @return the quota settings
472   */
473  public static QuotaSettings unthrottleRegionServer(final String regionServer) {
474    return throttle(null, null, null, regionServer, null, 0, null, QuotaScope.MACHINE);
475  }
476
477  /**
478   * Remove the throttling for the specified region server by throttle type.
479   *
480   * @param regionServer  the region Server
481   * @param type the type of throttling
482   * @return the quota settings
483   */
484  public static QuotaSettings unthrottleRegionServerByThrottleType(final String regionServer,
485      final ThrottleType type) {
486    return throttle(null, null, null, regionServer, type, 0, null, QuotaScope.MACHINE);
487  }
488
489  /* Throttle helper */
490  private static QuotaSettings throttle(final String userName, final TableName tableName,
491      final String namespace, final String regionServer, final ThrottleType type, final long limit,
492      final TimeUnit timeUnit, QuotaScope scope) {
493    QuotaProtos.ThrottleRequest.Builder builder = QuotaProtos.ThrottleRequest.newBuilder();
494    if (type != null) {
495      builder.setType(ProtobufUtil.toProtoThrottleType(type));
496    }
497    if (timeUnit != null) {
498      builder.setTimedQuota(ProtobufUtil.toTimedQuota(limit, timeUnit, scope));
499    }
500    return new ThrottleSettings(userName, tableName, namespace, regionServer, builder.build());
501  }
502
503  /* ==========================================================================
504   *  Global Settings
505   */
506
507  /**
508   * Set the "bypass global settings" for the specified user
509   *
510   * @param userName the user to throttle
511   * @param bypassGlobals true if the global settings should be bypassed
512   * @return the quota settings
513   */
514  public static QuotaSettings bypassGlobals(final String userName, final boolean bypassGlobals) {
515    return new QuotaGlobalsSettingsBypass(userName, null, null, null,  bypassGlobals);
516  }
517
518  /* ==========================================================================
519   *  FileSystem Space Settings
520   */
521
522  /**
523   * Creates a {@link QuotaSettings} object to limit the FileSystem space usage for the given table
524   * to the given size in bytes. When the space usage is exceeded by the table, the provided
525   * {@link SpaceViolationPolicy} is enacted on the table.
526   *
527   * @param tableName The name of the table on which the quota should be applied.
528   * @param sizeLimit The limit of a table's size in bytes.
529   * @param violationPolicy The action to take when the quota is exceeded.
530   * @return An {@link QuotaSettings} object.
531   */
532  public static QuotaSettings limitTableSpace(
533      final TableName tableName, long sizeLimit, final SpaceViolationPolicy violationPolicy) {
534    return new SpaceLimitSettings(tableName, sizeLimit, violationPolicy);
535  }
536
537  /**
538   * Creates a {@link QuotaSettings} object to remove the FileSystem space quota for the given
539   * table.
540   *
541   * @param tableName The name of the table to remove the quota for.
542   * @return A {@link QuotaSettings} object.
543   */
544  public static QuotaSettings removeTableSpaceLimit(TableName tableName) {
545    return new SpaceLimitSettings(tableName);
546  }
547
548  /**
549   * Creates a {@link QuotaSettings} object to limit the FileSystem space usage for the given
550   * namespace to the given size in bytes. When the space usage is exceeded by all tables in the
551   * namespace, the provided {@link SpaceViolationPolicy} is enacted on all tables in the namespace.
552   *
553   * @param namespace The namespace on which the quota should be applied.
554   * @param sizeLimit The limit of the namespace's size in bytes.
555   * @param violationPolicy The action to take when the the quota is exceeded.
556   * @return An {@link QuotaSettings} object.
557   */
558  public static QuotaSettings limitNamespaceSpace(
559      final String namespace, long sizeLimit, final SpaceViolationPolicy violationPolicy) {
560    return new SpaceLimitSettings(namespace, sizeLimit, violationPolicy);
561  }
562
563  /**
564   * Creates a {@link QuotaSettings} object to remove the FileSystem space quota for the given
565   * namespace.
566   *
567   * @param namespace The namespace to remove the quota on.
568   * @return A {@link QuotaSettings} object.
569   */
570  public static QuotaSettings removeNamespaceSpaceLimit(String namespace) {
571    return new SpaceLimitSettings(namespace);
572  }
573}