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;
024import org.apache.hadoop.hbase.TableName;
025import org.apache.yetus.audience.InterfaceAudience;
026
027import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
028import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetQuotaRequest;
029import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos;
030import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Quotas;
031import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.SpaceQuota;
032
033@InterfaceAudience.Public
034public class QuotaSettingsFactory {
035  static class QuotaGlobalsSettingsBypass extends QuotaSettings {
036    private final boolean bypassGlobals;
037
038    QuotaGlobalsSettingsBypass(final String userName, final TableName tableName,
039      final String namespace, final String regionServer, final boolean bypassGlobals) {
040      super(userName, tableName, namespace, regionServer);
041      this.bypassGlobals = bypassGlobals;
042    }
043
044    @Override
045    public QuotaType getQuotaType() {
046      return QuotaType.GLOBAL_BYPASS;
047    }
048
049    @Override
050    protected void setupSetQuotaRequest(SetQuotaRequest.Builder builder) {
051      builder.setBypassGlobals(bypassGlobals);
052    }
053
054    @Override
055    public String toString() {
056      return "GLOBAL_BYPASS => " + bypassGlobals;
057    }
058
059    protected boolean getBypass() {
060      return bypassGlobals;
061    }
062
063    @Override
064    protected QuotaGlobalsSettingsBypass merge(QuotaSettings newSettings) throws IOException {
065      if (newSettings instanceof QuotaGlobalsSettingsBypass) {
066        QuotaGlobalsSettingsBypass other = (QuotaGlobalsSettingsBypass) newSettings;
067
068        validateQuotaTarget(other);
069
070        if (getBypass() != other.getBypass()) {
071          return other;
072        }
073      }
074      return this;
075    }
076  }
077
078  /*
079   * ========================================================================== QuotaSettings from
080   * 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  public static List<ThrottleSettings> fromTableThrottles(final TableName tableName,
127    final QuotaProtos.Throttle throttle) {
128    return fromThrottle(null, tableName, null, null, throttle);
129  }
130
131  protected static List<ThrottleSettings> fromThrottle(final String userName,
132    final TableName tableName, final String namespace, final String regionServer,
133    final QuotaProtos.Throttle throttle) {
134    List<ThrottleSettings> settings = new ArrayList<>();
135    if (throttle.hasReqNum()) {
136      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
137        ThrottleType.REQUEST_NUMBER, throttle.getReqNum()));
138    }
139    if (throttle.hasReqSize()) {
140      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
141        ThrottleType.REQUEST_SIZE, throttle.getReqSize()));
142    }
143    if (throttle.hasWriteNum()) {
144      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
145        ThrottleType.WRITE_NUMBER, throttle.getWriteNum()));
146    }
147    if (throttle.hasWriteSize()) {
148      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
149        ThrottleType.WRITE_SIZE, throttle.getWriteSize()));
150    }
151    if (throttle.hasReadNum()) {
152      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
153        ThrottleType.READ_NUMBER, throttle.getReadNum()));
154    }
155    if (throttle.hasReadSize()) {
156      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
157        ThrottleType.READ_SIZE, throttle.getReadSize()));
158    }
159    if (throttle.hasReqCapacityUnit()) {
160      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
161        ThrottleType.REQUEST_CAPACITY_UNIT, throttle.getReqCapacityUnit()));
162    }
163    if (throttle.hasReadCapacityUnit()) {
164      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
165        ThrottleType.READ_CAPACITY_UNIT, throttle.getReadCapacityUnit()));
166    }
167    if (throttle.hasWriteCapacityUnit()) {
168      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
169        ThrottleType.WRITE_CAPACITY_UNIT, throttle.getWriteCapacityUnit()));
170    }
171    if (throttle.hasAtomicReadSize()) {
172      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
173        ThrottleType.ATOMIC_READ_SIZE, throttle.getAtomicReadSize()));
174    }
175    if (throttle.hasAtomicWriteSize()) {
176      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
177        ThrottleType.ATOMIC_WRITE_SIZE, throttle.getAtomicWriteSize()));
178    }
179    if (throttle.hasAtomicReqNum()) {
180      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace, regionServer,
181        ThrottleType.ATOMIC_REQUEST_NUMBER, throttle.getAtomicReqNum()));
182    }
183    return settings;
184  }
185
186  static QuotaSettings fromSpace(TableName table, String namespace, SpaceQuota protoQuota) {
187    if (protoQuota == null) {
188      return null;
189    }
190    if ((table == null && namespace == null) || (table != null && namespace != null)) {
191      throw new IllegalArgumentException(
192        "Can only construct SpaceLimitSettings for a table or namespace.");
193    }
194    if (table != null) {
195      if (protoQuota.getRemove()) {
196        return new SpaceLimitSettings(table);
197      }
198      return SpaceLimitSettings.fromSpaceQuota(table, protoQuota);
199    } else {
200      if (protoQuota.getRemove()) {
201        return new SpaceLimitSettings(namespace);
202      }
203      // namespace must be non-null
204      return SpaceLimitSettings.fromSpaceQuota(namespace, protoQuota);
205    }
206  }
207
208  /*
209   * ========================================================================== RPC Throttle
210   */
211
212  /**
213   * Throttle the specified user.
214   * @param userName the user to throttle
215   * @param type     the type of throttling
216   * @param limit    the allowed number of request/data per timeUnit
217   * @param timeUnit the limit time unit
218   * @return the quota settings
219   */
220  public static QuotaSettings throttleUser(final String userName, final ThrottleType type,
221    final long limit, final TimeUnit timeUnit) {
222    return throttleUser(userName, type, limit, timeUnit, QuotaScope.MACHINE);
223  }
224
225  /**
226   * Throttle the specified user.
227   * @param userName the user 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   * @param scope    the scope of throttling
232   * @return the quota settings
233   */
234  public static QuotaSettings throttleUser(final String userName, final ThrottleType type,
235    final long limit, final TimeUnit timeUnit, QuotaScope scope) {
236    return throttle(userName, null, null, null, type, limit, timeUnit, scope);
237  }
238
239  /**
240   * Throttle the specified user on the specified table.
241   * @param userName  the user to throttle
242   * @param tableName the table to throttle
243   * @param type      the type of throttling
244   * @param limit     the allowed number of request/data per timeUnit
245   * @param timeUnit  the limit time unit
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) {
250    return throttleUser(userName, tableName, type, limit, timeUnit, QuotaScope.MACHINE);
251  }
252
253  /**
254   * Throttle the specified user on the specified table.
255   * @param userName  the user to throttle
256   * @param tableName the table to throttle
257   * @param type      the type of throttling
258   * @param limit     the allowed number of request/data per timeUnit
259   * @param timeUnit  the limit time unit
260   * @param scope     the scope of throttling
261   * @return the quota settings
262   */
263  public static QuotaSettings throttleUser(final String userName, final TableName tableName,
264    final ThrottleType type, final long limit, final TimeUnit timeUnit, QuotaScope scope) {
265    return throttle(userName, tableName, null, null, type, limit, timeUnit, scope);
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   * @return the quota settings
276   */
277  public static QuotaSettings throttleUser(final String userName, final String namespace,
278    final ThrottleType type, final long limit, final TimeUnit timeUnit) {
279    return throttleUser(userName, namespace, type, limit, timeUnit, QuotaScope.MACHINE);
280  }
281
282  /**
283   * Throttle the specified user on the specified namespace.
284   * @param userName  the user to throttle
285   * @param namespace the namespace to throttle
286   * @param type      the type of throttling
287   * @param limit     the allowed number of request/data per timeUnit
288   * @param timeUnit  the limit time unit
289   * @param scope     the scope of throttling
290   * @return the quota settings
291   */
292  public static QuotaSettings throttleUser(final String userName, final String namespace,
293    final ThrottleType type, final long limit, final TimeUnit timeUnit, QuotaScope scope) {
294    return throttle(userName, null, namespace, null, type, limit, timeUnit, scope);
295  }
296
297  /**
298   * Remove the throttling for the specified user.
299   * @param userName the user
300   * @return the quota settings
301   */
302  public static QuotaSettings unthrottleUser(final String userName) {
303    return throttle(userName, null, null, null, null, 0, null, QuotaScope.MACHINE);
304  }
305
306  /**
307   * Remove the throttling for the specified user.
308   * @param userName the user
309   * @param type     the type of throttling
310   * @return the quota settings
311   */
312  public static QuotaSettings unthrottleUserByThrottleType(final String userName,
313    final ThrottleType type) {
314    return throttle(userName, null, null, null, type, 0, null, QuotaScope.MACHINE);
315  }
316
317  /**
318   * Remove the throttling for the specified user on the specified table.
319   * @param userName  the user
320   * @param tableName the table
321   * @return the quota settings
322   */
323  public static QuotaSettings unthrottleUser(final String userName, final TableName tableName) {
324    return throttle(userName, tableName, null, null, null, 0, null, QuotaScope.MACHINE);
325  }
326
327  /**
328   * Remove the throttling for the specified user on the specified table.
329   * @param userName  the user
330   * @param tableName the table
331   * @param type      the type of throttling
332   * @return the quota settings
333   */
334  public static QuotaSettings unthrottleUserByThrottleType(final String userName,
335    final TableName tableName, final ThrottleType type) {
336    return throttle(userName, tableName, null, null, type, 0, null, QuotaScope.MACHINE);
337  }
338
339  /**
340   * Remove the throttling for the specified user on the specified namespace.
341   * @param userName  the user
342   * @param namespace the namespace
343   * @return the quota settings
344   */
345  public static QuotaSettings unthrottleUser(final String userName, final String namespace) {
346    return throttle(userName, null, namespace, null, null, 0, null, QuotaScope.MACHINE);
347  }
348
349  /**
350   * Remove the throttling for the specified user on the specified namespace.
351   * @param userName  the user
352   * @param namespace the namespace
353   * @param type      the type of throttling
354   * @return the quota settings
355   */
356  public static QuotaSettings unthrottleUserByThrottleType(final String userName,
357    final String namespace, final ThrottleType type) {
358    return throttle(userName, null, namespace, null, type, 0, null, QuotaScope.MACHINE);
359  }
360
361  /**
362   * Throttle the specified table.
363   * @param tableName the table to throttle
364   * @param type      the type of throttling
365   * @param limit     the allowed number of request/data per timeUnit
366   * @param timeUnit  the limit time unit
367   * @return the quota settings
368   */
369  public static QuotaSettings throttleTable(final TableName tableName, final ThrottleType type,
370    final long limit, final TimeUnit timeUnit) {
371    return throttleTable(tableName, type, limit, timeUnit, QuotaScope.MACHINE);
372  }
373
374  /**
375   * Throttle the specified table.
376   * @param tableName the table to throttle
377   * @param type      the type of throttling
378   * @param limit     the allowed number of request/data per timeUnit
379   * @param timeUnit  the limit time unit
380   * @param scope     the scope of throttling
381   * @return the quota settings
382   */
383  public static QuotaSettings throttleTable(final TableName tableName, final ThrottleType type,
384    final long limit, final TimeUnit timeUnit, QuotaScope scope) {
385    return throttle(null, tableName, null, null, type, limit, timeUnit, scope);
386  }
387
388  /**
389   * Remove the throttling for the specified table.
390   * @param tableName the table
391   * @return the quota settings
392   */
393  public static QuotaSettings unthrottleTable(final TableName tableName) {
394    return throttle(null, tableName, null, null, null, 0, null, QuotaScope.MACHINE);
395  }
396
397  /**
398   * Remove the throttling for the specified table.
399   * @param tableName the table
400   * @param type      the type of throttling
401   * @return the quota settings
402   */
403  public static QuotaSettings unthrottleTableByThrottleType(final TableName tableName,
404    final ThrottleType type) {
405    return throttle(null, tableName, null, null, type, 0, null, QuotaScope.MACHINE);
406  }
407
408  /**
409   * Throttle the specified namespace.
410   * @param namespace the namespace to throttle
411   * @param type      the type of throttling
412   * @param limit     the allowed number of request/data per timeUnit
413   * @param timeUnit  the limit time unit
414   * @return the quota settings
415   */
416  public static QuotaSettings throttleNamespace(final String namespace, final ThrottleType type,
417    final long limit, final TimeUnit timeUnit) {
418    return throttleNamespace(namespace, type, limit, timeUnit, QuotaScope.MACHINE);
419  }
420
421  /**
422   * Throttle the specified namespace.
423   * @param namespace the namespace to throttle
424   * @param type      the type of throttling
425   * @param limit     the allowed number of request/data per timeUnit
426   * @param timeUnit  the limit time unit
427   * @param scope     the scope of throttling
428   * @return the quota settings
429   */
430  public static QuotaSettings throttleNamespace(final String namespace, final ThrottleType type,
431    final long limit, final TimeUnit timeUnit, QuotaScope scope) {
432    return throttle(null, null, namespace, null, type, limit, timeUnit, scope);
433  }
434
435  /**
436   * Remove the throttling for the specified namespace.
437   * @param namespace the namespace
438   * @return the quota settings
439   */
440  public static QuotaSettings unthrottleNamespace(final String namespace) {
441    return throttle(null, null, namespace, null, null, 0, null, QuotaScope.MACHINE);
442  }
443
444  /**
445   * Remove the throttling for the specified namespace by throttle type.
446   * @param namespace the namespace
447   * @param type      the type of throttling
448   * @return the quota settings
449   */
450  public static QuotaSettings unthrottleNamespaceByThrottleType(final String namespace,
451    final ThrottleType type) {
452    return throttle(null, null, namespace, null, type, 0, null, QuotaScope.MACHINE);
453  }
454
455  /**
456   * Throttle the specified region server.
457   * @param regionServer the region server to throttle
458   * @param type         the type of throttling
459   * @param limit        the allowed number of request/data per timeUnit
460   * @param timeUnit     the limit time unit
461   * @return the quota settings
462   */
463  public static QuotaSettings throttleRegionServer(final String regionServer,
464    final ThrottleType type, final long limit, final TimeUnit timeUnit) {
465    return throttle(null, null, null, regionServer, type, limit, timeUnit, QuotaScope.MACHINE);
466  }
467
468  /**
469   * Remove the throttling for the specified region server.
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   * @param regionServer the region Server
480   * @param type         the type of throttling
481   * @return the quota settings
482   */
483  public static QuotaSettings unthrottleRegionServerByThrottleType(final String regionServer,
484    final ThrottleType type) {
485    return throttle(null, null, null, regionServer, type, 0, null, QuotaScope.MACHINE);
486  }
487
488  /* Throttle helper */
489  private static QuotaSettings throttle(final String userName, final TableName tableName,
490    final String namespace, final String regionServer, final ThrottleType type, final long limit,
491    final TimeUnit timeUnit, QuotaScope scope) {
492    QuotaProtos.ThrottleRequest.Builder builder = QuotaProtos.ThrottleRequest.newBuilder();
493    if (type != null) {
494      builder.setType(ProtobufUtil.toProtoThrottleType(type));
495    }
496    if (timeUnit != null) {
497      builder.setTimedQuota(ProtobufUtil.toTimedQuota(limit, timeUnit, scope));
498    }
499    return new ThrottleSettings(userName, tableName, namespace, regionServer, builder.build());
500  }
501
502  /*
503   * ========================================================================== Global Settings
504   */
505
506  /**
507   * Set the "bypass global settings" for the specified user
508   * @param userName      the user to throttle
509   * @param bypassGlobals true if the global settings should be bypassed
510   * @return the quota settings
511   */
512  public static QuotaSettings bypassGlobals(final String userName, final boolean bypassGlobals) {
513    return new QuotaGlobalsSettingsBypass(userName, null, null, null, bypassGlobals);
514  }
515
516  /*
517   * ========================================================================== FileSystem Space
518   * Settings
519   */
520
521  /**
522   * Creates a {@link QuotaSettings} object to limit the FileSystem space usage for the given table
523   * to the given size in bytes. When the space usage is exceeded by the table, the provided
524   * {@link SpaceViolationPolicy} is enacted on the table.
525   * @param tableName       The name of the table on which the quota should be applied.
526   * @param sizeLimit       The limit of a table's size in bytes.
527   * @param violationPolicy The action to take when the quota is exceeded.
528   * @return An {@link QuotaSettings} object.
529   */
530  public static QuotaSettings limitTableSpace(final TableName tableName, long sizeLimit,
531    final SpaceViolationPolicy violationPolicy) {
532    return new SpaceLimitSettings(tableName, sizeLimit, violationPolicy);
533  }
534
535  /**
536   * Creates a {@link QuotaSettings} object to remove the FileSystem space quota for the given
537   * table.
538   * @param tableName The name of the table to remove the quota for.
539   * @return A {@link QuotaSettings} object.
540   */
541  public static QuotaSettings removeTableSpaceLimit(TableName tableName) {
542    return new SpaceLimitSettings(tableName);
543  }
544
545  /**
546   * Creates a {@link QuotaSettings} object to limit the FileSystem space usage for the given
547   * namespace to the given size in bytes. When the space usage is exceeded by all tables in the
548   * namespace, the provided {@link SpaceViolationPolicy} is enacted on all tables in the namespace.
549   * @param namespace       The namespace on which the quota should be applied.
550   * @param sizeLimit       The limit of the namespace's size in bytes.
551   * @param violationPolicy The action to take when the the quota is exceeded.
552   * @return An {@link QuotaSettings} object.
553   */
554  public static QuotaSettings limitNamespaceSpace(final String namespace, long sizeLimit,
555    final SpaceViolationPolicy violationPolicy) {
556    return new SpaceLimitSettings(namespace, sizeLimit, violationPolicy);
557  }
558
559  /**
560   * Creates a {@link QuotaSettings} object to remove the FileSystem space quota for the given
561   * namespace.
562   * @param namespace The namespace to remove the quota on.
563   * @return A {@link QuotaSettings} object.
564   */
565  public static QuotaSettings removeNamespaceSpaceLimit(String namespace) {
566    return new SpaceLimitSettings(namespace);
567  }
568}