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 static org.junit.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertTrue;
022
023import java.io.IOException;
024import org.apache.hadoop.hbase.TableName;
025import org.apache.hadoop.hbase.testclassification.SmallTests;
026import org.junit.jupiter.api.Tag;
027import org.junit.jupiter.api.Test;
028
029import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
030import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos;
031
032@Tag(SmallTests.TAG)
033public class TestGlobalQuotaSettingsImpl {
034
035  QuotaProtos.TimedQuota REQUEST_THROTTLE =
036    QuotaProtos.TimedQuota.newBuilder().setScope(QuotaProtos.QuotaScope.MACHINE).setSoftLimit(100)
037      .setTimeUnit(HBaseProtos.TimeUnit.MINUTES).build();
038  QuotaProtos.Throttle THROTTLE =
039    QuotaProtos.Throttle.newBuilder().setReqNum(REQUEST_THROTTLE).build();
040
041  QuotaProtos.SpaceQuota SPACE_QUOTA =
042    QuotaProtos.SpaceQuota.newBuilder().setSoftLimit(1024L * 1024L)
043      .setViolationPolicy(QuotaProtos.SpaceViolationPolicy.NO_WRITES).build();
044
045  @Test
046  public void testMergeThrottle() throws IOException {
047    QuotaProtos.Quotas quota = QuotaProtos.Quotas.newBuilder().setThrottle(THROTTLE).build();
048    QuotaProtos.TimedQuota writeQuota = REQUEST_THROTTLE.toBuilder().setSoftLimit(500).build();
049    // Unset the req throttle, set a write throttle
050    QuotaProtos.ThrottleRequest writeThrottle = QuotaProtos.ThrottleRequest.newBuilder()
051      .setTimedQuota(writeQuota).setType(QuotaProtos.ThrottleType.WRITE_NUMBER).build();
052
053    GlobalQuotaSettingsImpl settings = new GlobalQuotaSettingsImpl("joe", null, null, null, quota);
054    GlobalQuotaSettingsImpl merged =
055      settings.merge(new ThrottleSettings("joe", null, null, null, writeThrottle));
056
057    QuotaProtos.Throttle mergedThrottle = merged.getThrottleProto();
058    // Verify the request throttle is in place
059    assertTrue(mergedThrottle.hasReqNum());
060    QuotaProtos.TimedQuota actualReqNum = mergedThrottle.getReqNum();
061    assertEquals(REQUEST_THROTTLE.getSoftLimit(), actualReqNum.getSoftLimit());
062
063    // Verify the write throttle is in place
064    assertTrue(mergedThrottle.hasWriteNum());
065    QuotaProtos.TimedQuota actualWriteNum = mergedThrottle.getWriteNum();
066    assertEquals(writeQuota.getSoftLimit(), actualWriteNum.getSoftLimit());
067  }
068
069  @Test
070  public void testMergeSpace() throws IOException {
071    TableName tn = TableName.valueOf("foo");
072    QuotaProtos.Quotas quota = QuotaProtos.Quotas.newBuilder().setSpace(SPACE_QUOTA).build();
073
074    GlobalQuotaSettingsImpl settings = new GlobalQuotaSettingsImpl(null, tn, null, null, quota);
075    // Switch the violation policy to DISABLE
076    GlobalQuotaSettingsImpl merged = settings
077      .merge(new SpaceLimitSettings(tn, SPACE_QUOTA.getSoftLimit(), SpaceViolationPolicy.DISABLE));
078
079    QuotaProtos.SpaceQuota mergedSpaceQuota = merged.getSpaceProto();
080    assertEquals(SPACE_QUOTA.getSoftLimit(), mergedSpaceQuota.getSoftLimit());
081    assertEquals(QuotaProtos.SpaceViolationPolicy.DISABLE, mergedSpaceQuota.getViolationPolicy());
082  }
083
084  @Test
085  public void testMergeThrottleAndSpace() throws IOException {
086    final String ns = "org1";
087    QuotaProtos.Quotas quota =
088      QuotaProtos.Quotas.newBuilder().setThrottle(THROTTLE).setSpace(SPACE_QUOTA).build();
089    GlobalQuotaSettingsImpl settings = new GlobalQuotaSettingsImpl(null, null, ns, null, quota);
090
091    QuotaProtos.TimedQuota writeQuota = REQUEST_THROTTLE.toBuilder().setSoftLimit(500).build();
092    // Add a write throttle
093    QuotaProtos.ThrottleRequest writeThrottle = QuotaProtos.ThrottleRequest.newBuilder()
094      .setTimedQuota(writeQuota).setType(QuotaProtos.ThrottleType.WRITE_NUMBER).build();
095
096    GlobalQuotaSettingsImpl merged =
097      settings.merge(new ThrottleSettings(null, null, ns, null, writeThrottle));
098    GlobalQuotaSettingsImpl finalQuota = merged.merge(new SpaceLimitSettings(ns,
099      SPACE_QUOTA.getSoftLimit(), SpaceViolationPolicy.NO_WRITES_COMPACTIONS));
100
101    // Verify both throttle quotas
102    QuotaProtos.Throttle throttle = finalQuota.getThrottleProto();
103    assertTrue(throttle.hasReqNum());
104    QuotaProtos.TimedQuota reqNumQuota = throttle.getReqNum();
105    assertEquals(REQUEST_THROTTLE.getSoftLimit(), reqNumQuota.getSoftLimit());
106
107    assertTrue(throttle.hasWriteNum());
108    QuotaProtos.TimedQuota writeNumQuota = throttle.getWriteNum();
109    assertEquals(writeQuota.getSoftLimit(), writeNumQuota.getSoftLimit());
110
111    // Verify space quota
112    QuotaProtos.SpaceQuota finalSpaceQuota = finalQuota.getSpaceProto();
113    assertEquals(SPACE_QUOTA.getSoftLimit(), finalSpaceQuota.getSoftLimit());
114    assertEquals(QuotaProtos.SpaceViolationPolicy.NO_WRITES_COMPACTIONS,
115      finalSpaceQuota.getViolationPolicy());
116  }
117}