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