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