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  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    return settings;
172  }
173
174  static QuotaSettings fromSpace(TableName table, String namespace, SpaceQuota protoQuota) {
175    if (protoQuota == null) {
176      return null;
177    }
178    if ((table == null && namespace == null) || (table != null && namespace != null)) {
179      throw new IllegalArgumentException(
180          "Can only construct SpaceLimitSettings for a table or namespace.");
181    }
182    if (table != null) {
183      if (protoQuota.getRemove()) {
184        return new SpaceLimitSettings(table);
185      }
186      return SpaceLimitSettings.fromSpaceQuota(table, protoQuota);
187    } else {
188      if (protoQuota.getRemove()) {
189        return new SpaceLimitSettings(namespace);
190      }
191      // namespace must be non-null
192      return SpaceLimitSettings.fromSpaceQuota(namespace, protoQuota);
193    }
194  }
195
196  /* ==========================================================================
197   *  RPC Throttle
198   */
199
200  /**
201   * Throttle the specified user.
202   *
203   * @param userName the user to throttle
204   * @param type the type of throttling
205   * @param limit the allowed number of request/data per timeUnit
206   * @param timeUnit the limit time unit
207   * @return the quota settings
208   */
209  public static QuotaSettings throttleUser(final String userName, final ThrottleType type,
210      final long limit, final TimeUnit timeUnit) {
211    return throttleUser(userName, type, limit, timeUnit, QuotaScope.MACHINE);
212  }
213
214  /**
215   * Throttle the specified user.
216   * @param userName the user to throttle
217   * @param type the type of throttling
218   * @param limit the allowed number of request/data per timeUnit
219   * @param timeUnit the limit time unit
220   * @param scope the scope of throttling
221   * @return the quota settings
222   */
223  public static QuotaSettings throttleUser(final String userName, final ThrottleType type,
224      final long limit, final TimeUnit timeUnit, QuotaScope scope) {
225    return throttle(userName, null, null, null, type, limit, timeUnit, scope);
226  }
227
228  /**
229   * Throttle the specified user on the specified table.
230   *
231   * @param userName the user to throttle
232   * @param tableName the table to throttle
233   * @param type the type of throttling
234   * @param limit the allowed number of request/data per timeUnit
235   * @param timeUnit the limit time unit
236   * @return the quota settings
237   */
238  public static QuotaSettings throttleUser(final String userName, final TableName tableName,
239      final ThrottleType type, final long limit, final TimeUnit timeUnit) {
240    return throttleUser(userName, tableName, type, limit, timeUnit, QuotaScope.MACHINE);
241  }
242
243  /**
244   * Throttle the specified user on the specified table.
245   * @param userName the user to throttle
246   * @param tableName the table to throttle
247   * @param type the type of throttling
248   * @param limit the allowed number of request/data per timeUnit
249   * @param timeUnit the limit time unit
250   * @param scope the scope of throttling
251   * @return the quota settings
252   */
253  public static QuotaSettings throttleUser(final String userName, final TableName tableName,
254      final ThrottleType type, final long limit, final TimeUnit timeUnit, QuotaScope scope) {
255    return throttle(userName, tableName, null, null, type, limit, timeUnit, scope);
256  }
257
258  /**
259   * Throttle the specified user on the specified namespace.
260   *
261   * @param userName the user to throttle
262   * @param namespace the namespace to throttle
263   * @param type the type of throttling
264   * @param limit the allowed number of request/data per timeUnit
265   * @param timeUnit the limit time unit
266   * @return the quota settings
267   */
268  public static QuotaSettings throttleUser(final String userName, final String namespace,
269      final ThrottleType type, final long limit, final TimeUnit timeUnit) {
270    return throttleUser(userName, namespace, type, limit, timeUnit, QuotaScope.MACHINE);
271  }
272
273  /**
274   * Throttle the specified user on the specified namespace.
275   * @param userName the user to throttle
276   * @param namespace the namespace to throttle
277   * @param type the type of throttling
278   * @param limit the allowed number of request/data per timeUnit
279   * @param timeUnit the limit time unit
280   * @param scope the scope of throttling
281   * @return the quota settings
282   */
283  public static QuotaSettings throttleUser(final String userName, final String namespace,
284      final ThrottleType type, final long limit, final TimeUnit timeUnit, QuotaScope scope) {
285    return throttle(userName, null, namespace, null, type, limit, timeUnit, scope);
286  }
287
288  /**
289   * Remove the throttling for the specified user.
290   *
291   * @param userName the user
292   * @return the quota settings
293   */
294  public static QuotaSettings unthrottleUser(final String userName) {
295    return throttle(userName, null, null, null, null, 0, null, QuotaScope.MACHINE);
296  }
297
298  /**
299   * Remove the throttling for the specified user.
300   *
301   * @param userName the user
302   * @param type the type of throttling
303   * @return the quota settings
304   */
305  public static QuotaSettings unthrottleUserByThrottleType(final String userName,
306      final ThrottleType type) {
307    return throttle(userName, null, null, null, type, 0, null, QuotaScope.MACHINE);
308  }
309
310  /**
311   * Remove the throttling for the specified user on the specified table.
312   *
313   * @param userName the user
314   * @param tableName the table
315   * @return the quota settings
316   */
317  public static QuotaSettings unthrottleUser(final String userName, final TableName tableName) {
318    return throttle(userName, tableName, null, null, null, 0, null, QuotaScope.MACHINE);
319  }
320
321  /**
322   * Remove the throttling for the specified user on the specified table.
323   *
324   * @param userName the user
325   * @param tableName the table
326   * @param type the type of throttling
327   * @return the quota settings
328   */
329  public static QuotaSettings unthrottleUserByThrottleType(final String userName,
330      final TableName tableName, final ThrottleType type) {
331    return throttle(userName, tableName, null, null, type, 0, null, QuotaScope.MACHINE);
332  }
333
334  /**
335   * Remove the throttling for the specified user on the specified namespace.
336   *
337   * @param userName the user
338   * @param namespace the namespace
339   * @return the quota settings
340   */
341  public static QuotaSettings unthrottleUser(final String userName, final String namespace) {
342    return throttle(userName, null, namespace, null, null, 0, null, QuotaScope.MACHINE);
343  }
344
345  /**
346   * Remove the throttling for the specified user on the specified namespace.
347   *
348   * @param userName the user
349   * @param namespace the namespace
350   * @param type the type of throttling
351   * @return the quota settings
352   */
353  public static QuotaSettings unthrottleUserByThrottleType(final String userName,
354      final String namespace, final ThrottleType type) {
355    return throttle(userName, null, namespace, null, type, 0, null, QuotaScope.MACHINE);
356  }
357
358  /**
359   * Throttle the specified table.
360   *
361   * @param tableName the table to throttle
362   * @param type the type of throttling
363   * @param limit the allowed number of request/data per timeUnit
364   * @param timeUnit the limit time unit
365   * @return the quota settings
366   */
367  public static QuotaSettings throttleTable(final TableName tableName, final ThrottleType type,
368      final long limit, final TimeUnit timeUnit) {
369    return throttleTable(tableName, type, limit, timeUnit, QuotaScope.MACHINE);
370  }
371
372  /**
373   * Throttle the specified table.
374   * @param tableName the table to throttle
375   * @param type the type of throttling
376   * @param limit the allowed number of request/data per timeUnit
377   * @param timeUnit the limit time unit
378   * @param scope the scope of throttling
379   * @return the quota settings
380   */
381  public static QuotaSettings throttleTable(final TableName tableName, final ThrottleType type,
382      final long limit, final TimeUnit timeUnit, QuotaScope scope) {
383    return throttle(null, tableName, null, null, type, limit, timeUnit, scope);
384  }
385
386  /**
387   * Remove the throttling for the specified table.
388   *
389   * @param tableName the table
390   * @return the quota settings
391   */
392  public static QuotaSettings unthrottleTable(final TableName tableName) {
393    return throttle(null, tableName, null, null, null, 0, null, QuotaScope.MACHINE);
394  }
395
396  /**
397   * Remove the throttling for the specified table.
398   *
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   *
411   * @param namespace the namespace to throttle
412   * @param type the type of throttling
413   * @param limit the allowed number of request/data per timeUnit
414   * @param timeUnit the limit time unit
415   * @return the quota settings
416   */
417  public static QuotaSettings throttleNamespace(final String namespace, final ThrottleType type,
418      final long limit, final TimeUnit timeUnit) {
419    return throttleNamespace(namespace, type, limit, timeUnit, QuotaScope.MACHINE);
420  }
421
422  /**
423   * Throttle the specified namespace.
424   * @param namespace the namespace to throttle
425   * @param type the type of throttling
426   * @param limit the allowed number of request/data per timeUnit
427   * @param timeUnit the limit time unit
428   * @param scope the scope of throttling
429   * @return the quota settings
430   */
431  public static QuotaSettings throttleNamespace(final String namespace, final ThrottleType type,
432      final long limit, final TimeUnit timeUnit, QuotaScope scope) {
433    return throttle(null, null, namespace, null, type, limit, timeUnit, scope);
434  }
435
436  /**
437   * Remove the throttling for the specified namespace.
438   *
439   * @param namespace the namespace
440   * @return the quota settings
441   */
442  public static QuotaSettings unthrottleNamespace(final String namespace) {
443    return throttle(null, null, namespace, null, null, 0, null, QuotaScope.MACHINE);
444  }
445
446  /**
447   * Remove the throttling for the specified namespace by throttle type.
448   *
449   * @param namespace the namespace
450   * @param type the type of throttling
451   * @return the quota settings
452   */
453  public static QuotaSettings unthrottleNamespaceByThrottleType(final String namespace,
454      final ThrottleType type) {
455    return throttle(null, null, namespace, null, type, 0, null, QuotaScope.MACHINE);
456  }
457
458  /**
459   * Throttle the specified region server.
460   *
461   * @param regionServer the region server to throttle
462   * @param type the type of throttling
463   * @param limit the allowed number of request/data per timeUnit
464   * @param timeUnit the limit time unit
465   * @return the quota settings
466   */
467  public static QuotaSettings throttleRegionServer(final String regionServer,
468      final ThrottleType type, final long limit, final TimeUnit timeUnit) {
469    return throttle(null, null, null, regionServer, type, limit, timeUnit, QuotaScope.MACHINE);
470  }
471
472  /**
473   * Remove the throttling for the specified region server.
474   *
475   * @param regionServer the region Server
476   * @return the quota settings
477   */
478  public static QuotaSettings unthrottleRegionServer(final String regionServer) {
479    return throttle(null, null, null, regionServer, null, 0, null, QuotaScope.MACHINE);
480  }
481
482  /**
483   * Remove the throttling for the specified region server by throttle type.
484   *
485   * @param regionServer  the region Server
486   * @param type the type of throttling
487   * @return the quota settings
488   */
489  public static QuotaSettings unthrottleRegionServerByThrottleType(final String regionServer,
490      final ThrottleType type) {
491    return throttle(null, null, null, regionServer, type, 0, null, QuotaScope.MACHINE);
492  }
493
494  /* Throttle helper */
495  private static QuotaSettings throttle(final String userName, final TableName tableName,
496      final String namespace, final String regionServer, final ThrottleType type, final long limit,
497      final TimeUnit timeUnit, QuotaScope scope) {
498    QuotaProtos.ThrottleRequest.Builder builder = QuotaProtos.ThrottleRequest.newBuilder();
499    if (type != null) {
500      builder.setType(ProtobufUtil.toProtoThrottleType(type));
501    }
502    if (timeUnit != null) {
503      builder.setTimedQuota(ProtobufUtil.toTimedQuota(limit, timeUnit, scope));
504    }
505    return new ThrottleSettings(userName, tableName, namespace, regionServer, builder.build());
506  }
507
508  /* ==========================================================================
509   *  Global Settings
510   */
511
512  /**
513   * Set the "bypass global settings" for the specified user
514   *
515   * @param userName the user to throttle
516   * @param bypassGlobals true if the global settings should be bypassed
517   * @return the quota settings
518   */
519  public static QuotaSettings bypassGlobals(final String userName, final boolean bypassGlobals) {
520    return new QuotaGlobalsSettingsBypass(userName, null, null, null,  bypassGlobals);
521  }
522
523  /* ==========================================================================
524   *  FileSystem Space Settings
525   */
526
527  /**
528   * Creates a {@link QuotaSettings} object to limit the FileSystem space usage for the given table
529   * to the given size in bytes. When the space usage is exceeded by the table, the provided
530   * {@link SpaceViolationPolicy} is enacted on the table.
531   *
532   * @param tableName The name of the table on which the quota should be applied.
533   * @param sizeLimit The limit of a table's size in bytes.
534   * @param violationPolicy The action to take when the quota is exceeded.
535   * @return An {@link QuotaSettings} object.
536   */
537  public static QuotaSettings limitTableSpace(
538      final TableName tableName, long sizeLimit, final SpaceViolationPolicy violationPolicy) {
539    return new SpaceLimitSettings(tableName, sizeLimit, violationPolicy);
540  }
541
542  /**
543   * Creates a {@link QuotaSettings} object to remove the FileSystem space quota for the given
544   * table.
545   *
546   * @param tableName The name of the table to remove the quota for.
547   * @return A {@link QuotaSettings} object.
548   */
549  public static QuotaSettings removeTableSpaceLimit(TableName tableName) {
550    return new SpaceLimitSettings(tableName);
551  }
552
553  /**
554   * Creates a {@link QuotaSettings} object to limit the FileSystem space usage for the given
555   * namespace to the given size in bytes. When the space usage is exceeded by all tables in the
556   * namespace, the provided {@link SpaceViolationPolicy} is enacted on all tables in the namespace.
557   *
558   * @param namespace The namespace on which the quota should be applied.
559   * @param sizeLimit The limit of the namespace's size in bytes.
560   * @param violationPolicy The action to take when the the quota is exceeded.
561   * @return An {@link QuotaSettings} object.
562   */
563  public static QuotaSettings limitNamespaceSpace(
564      final String namespace, long sizeLimit, final SpaceViolationPolicy violationPolicy) {
565    return new SpaceLimitSettings(namespace, sizeLimit, violationPolicy);
566  }
567
568  /**
569   * Creates a {@link QuotaSettings} object to remove the FileSystem space quota for the given
570   * namespace.
571   *
572   * @param namespace The namespace to remove the quota on.
573   * @return A {@link QuotaSettings} object.
574   */
575  public static QuotaSettings removeNamespaceSpaceLimit(String namespace) {
576    return new SpaceLimitSettings(namespace);
577  }
578}