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.generated.MasterProtos.SetQuotaRequest;
029import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
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 boolean bypassGlobals) {
041      super(userName, tableName, namespace);
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, quotas);
084  }
085
086  static List<QuotaSettings> fromUserQuotas(final String userName, final TableName tableName,
087      final Quotas quotas) {
088    return fromQuotas(userName, tableName, 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, quotas);
094  }
095
096  static List<QuotaSettings> fromTableQuotas(final TableName tableName, final Quotas quotas) {
097    return fromQuotas(null, tableName, null, quotas);
098  }
099
100  static List<QuotaSettings> fromNamespaceQuotas(final String namespace, final Quotas quotas) {
101    return fromQuotas(null, null, namespace, quotas);
102  }
103
104  private static List<QuotaSettings> fromQuotas(final String userName, final TableName tableName,
105      final String namespace, final Quotas quotas) {
106    List<QuotaSettings> settings = new ArrayList<>();
107    if (quotas.hasThrottle()) {
108      settings.addAll(fromThrottle(userName, tableName, namespace, quotas.getThrottle()));
109    }
110    if (quotas.getBypassGlobals() == true) {
111      settings.add(new QuotaGlobalsSettingsBypass(userName, tableName, namespace, true));
112    }
113    if (quotas.hasSpace()) {
114      settings.add(fromSpace(tableName, namespace, quotas.getSpace()));
115    }
116    return settings;
117  }
118
119  protected static List<QuotaSettings> fromThrottle(final String userName, final TableName tableName,
120      final String namespace, final QuotaProtos.Throttle throttle) {
121    List<QuotaSettings> settings = new ArrayList<>();
122    if (throttle.hasReqNum()) {
123      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace,
124          ThrottleType.REQUEST_NUMBER, throttle.getReqNum()));
125    }
126    if (throttle.hasReqSize()) {
127      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace,
128          ThrottleType.REQUEST_SIZE, throttle.getReqSize()));
129    }
130    if (throttle.hasWriteNum()) {
131      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace,
132          ThrottleType.WRITE_NUMBER, throttle.getWriteNum()));
133    }
134    if (throttle.hasWriteSize()) {
135      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace,
136          ThrottleType.WRITE_SIZE, throttle.getWriteSize()));
137    }
138    if (throttle.hasReadNum()) {
139      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace,
140          ThrottleType.READ_NUMBER, throttle.getReadNum()));
141    }
142    if (throttle.hasReadSize()) {
143      settings.add(ThrottleSettings.fromTimedQuota(userName, tableName, namespace,
144          ThrottleType.READ_SIZE, throttle.getReadSize()));
145    }
146    return settings;
147  }
148
149  static QuotaSettings fromSpace(TableName table, String namespace, SpaceQuota protoQuota) {
150    if (protoQuota == null) {
151      return null;
152    }
153    if ((table == null && namespace == null) || (table != null && namespace != null)) {
154      throw new IllegalArgumentException(
155          "Can only construct SpaceLimitSettings for a table or namespace.");
156    }
157    if (table != null) {
158      if (protoQuota.getRemove()) {
159        return new SpaceLimitSettings(table);
160      }
161      return SpaceLimitSettings.fromSpaceQuota(table, protoQuota);
162    } else {
163      if (protoQuota.getRemove()) {
164        return new SpaceLimitSettings(namespace);
165      }
166      // namespace must be non-null
167      return SpaceLimitSettings.fromSpaceQuota(namespace, protoQuota);
168    }
169  }
170
171  /* ==========================================================================
172   *  RPC Throttle
173   */
174
175  /**
176   * Throttle the specified user.
177   *
178   * @param userName the user to throttle
179   * @param type the type of throttling
180   * @param limit the allowed number of request/data per timeUnit
181   * @param timeUnit the limit time unit
182   * @return the quota settings
183   */
184  public static QuotaSettings throttleUser(final String userName, final ThrottleType type,
185      final long limit, final TimeUnit timeUnit) {
186    return throttle(userName, null, null, type, limit, timeUnit);
187  }
188
189  /**
190   * Throttle the specified user on the specified table.
191   *
192   * @param userName the user to throttle
193   * @param tableName the table to throttle
194   * @param type the type of throttling
195   * @param limit the allowed number of request/data per timeUnit
196   * @param timeUnit the limit time unit
197   * @return the quota settings
198   */
199  public static QuotaSettings throttleUser(final String userName, final TableName tableName,
200      final ThrottleType type, final long limit, final TimeUnit timeUnit) {
201    return throttle(userName, tableName, null, type, limit, timeUnit);
202  }
203
204  /**
205   * Throttle the specified user on the specified namespace.
206   *
207   * @param userName the user to throttle
208   * @param namespace the namespace to throttle
209   * @param type the type of throttling
210   * @param limit the allowed number of request/data per timeUnit
211   * @param timeUnit the limit time unit
212   * @return the quota settings
213   */
214  public static QuotaSettings throttleUser(final String userName, final String namespace,
215      final ThrottleType type, final long limit, final TimeUnit timeUnit) {
216    return throttle(userName, null, namespace, type, limit, timeUnit);
217  }
218
219  /**
220   * Remove the throttling for the specified user.
221   *
222   * @param userName the user
223   * @return the quota settings
224   */
225  public static QuotaSettings unthrottleUser(final String userName) {
226    return throttle(userName, null, null, null, 0, null);
227  }
228
229  /**
230   * Remove the throttling for the specified user on the specified table.
231   *
232   * @param userName the user
233   * @param tableName the table
234   * @return the quota settings
235   */
236  public static QuotaSettings unthrottleUser(final String userName, final TableName tableName) {
237    return throttle(userName, tableName, null, null, 0, null);
238  }
239
240  /**
241   * Remove the throttling for the specified user on the specified namespace.
242   *
243   * @param userName the user
244   * @param namespace the namespace
245   * @return the quota settings
246   */
247  public static QuotaSettings unthrottleUser(final String userName, final String namespace) {
248    return throttle(userName, null, namespace, null, 0, null);
249  }
250
251  /**
252   * Throttle the specified table.
253   *
254   * @param tableName the table to throttle
255   * @param type the type of throttling
256   * @param limit the allowed number of request/data per timeUnit
257   * @param timeUnit the limit time unit
258   * @return the quota settings
259   */
260  public static QuotaSettings throttleTable(final TableName tableName, final ThrottleType type,
261      final long limit, final TimeUnit timeUnit) {
262    return throttle(null, tableName, null, type, limit, timeUnit);
263  }
264
265  /**
266   * Remove the throttling for the specified table.
267   *
268   * @param tableName the table
269   * @return the quota settings
270   */
271  public static QuotaSettings unthrottleTable(final TableName tableName) {
272    return throttle(null, tableName, null, null, 0, null);
273  }
274
275  /**
276   * Throttle the specified namespace.
277   *
278   * @param namespace the namespace to throttle
279   * @param type the type of throttling
280   * @param limit the allowed number of request/data per timeUnit
281   * @param timeUnit the limit time unit
282   * @return the quota settings
283   */
284  public static QuotaSettings throttleNamespace(final String namespace, final ThrottleType type,
285      final long limit, final TimeUnit timeUnit) {
286    return throttle(null, null, namespace, type, limit, timeUnit);
287  }
288
289  /**
290   * Remove the throttling for the specified namespace.
291   *
292   * @param namespace the namespace
293   * @return the quota settings
294   */
295  public static QuotaSettings unthrottleNamespace(final String namespace) {
296    return throttle(null, null, namespace, null, 0, null);
297  }
298
299  /* Throttle helper */
300  private static QuotaSettings throttle(final String userName, final TableName tableName,
301      final String namespace, final ThrottleType type, final long limit,
302      final TimeUnit timeUnit) {
303    QuotaProtos.ThrottleRequest.Builder builder = QuotaProtos.ThrottleRequest.newBuilder();
304    if (type != null) {
305      builder.setType(ProtobufUtil.toProtoThrottleType(type));
306    }
307    if (timeUnit != null) {
308      builder.setTimedQuota(ProtobufUtil.toTimedQuota(limit, timeUnit, QuotaScope.MACHINE));
309    }
310    return new ThrottleSettings(userName, tableName, namespace, builder.build());
311  }
312
313  /* ==========================================================================
314   *  Global Settings
315   */
316
317  /**
318   * Set the "bypass global settings" for the specified user
319   *
320   * @param userName the user to throttle
321   * @param bypassGlobals true if the global settings should be bypassed
322   * @return the quota settings
323   */
324  public static QuotaSettings bypassGlobals(final String userName, final boolean bypassGlobals) {
325    return new QuotaGlobalsSettingsBypass(userName, null, null, bypassGlobals);
326  }
327
328  /* ==========================================================================
329   *  FileSystem Space Settings
330   */
331
332  /**
333   * Creates a {@link QuotaSettings} object to limit the FileSystem space usage for the given table
334   * to the given size in bytes. When the space usage is exceeded by the table, the provided
335   * {@link SpaceViolationPolicy} is enacted on the table.
336   *
337   * @param tableName The name of the table on which the quota should be applied.
338   * @param sizeLimit The limit of a table's size in bytes.
339   * @param violationPolicy The action to take when the quota is exceeded.
340   * @return An {@link QuotaSettings} object.
341   */
342  public static QuotaSettings limitTableSpace(
343      final TableName tableName, long sizeLimit, final SpaceViolationPolicy violationPolicy) {
344    return new SpaceLimitSettings(tableName, sizeLimit, violationPolicy);
345  }
346
347  /**
348   * Creates a {@link QuotaSettings} object to remove the FileSystem space quota for the given
349   * table.
350   *
351   * @param tableName The name of the table to remove the quota for.
352   * @return A {@link QuotaSettings} object.
353   */
354  public static QuotaSettings removeTableSpaceLimit(TableName tableName) {
355    return new SpaceLimitSettings(tableName);
356  }
357
358  /**
359   * Creates a {@link QuotaSettings} object to limit the FileSystem space usage for the given
360   * namespace to the given size in bytes. When the space usage is exceeded by all tables in the
361   * namespace, the provided {@link SpaceViolationPolicy} is enacted on all tables in the namespace.
362   *
363   * @param namespace The namespace on which the quota should be applied.
364   * @param sizeLimit The limit of the namespace's size in bytes.
365   * @param violationPolicy The action to take when the the quota is exceeded.
366   * @return An {@link QuotaSettings} object.
367   */
368  public static QuotaSettings limitNamespaceSpace(
369      final String namespace, long sizeLimit, final SpaceViolationPolicy violationPolicy) {
370    return new SpaceLimitSettings(namespace, sizeLimit, violationPolicy);
371  }
372
373  /**
374   * Creates a {@link QuotaSettings} object to remove the FileSystem space quota for the given
375   * namespace.
376   *
377   * @param namespace The namespace to remove the quota on.
378   * @return A {@link QuotaSettings} object.
379   */
380  public static QuotaSettings removeNamespaceSpaceLimit(String namespace) {
381    return new SpaceLimitSettings(namespace);
382  }
383}