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