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 org.apache.hadoop.hbase.HBaseClassTestRule;
024import org.apache.hadoop.hbase.testclassification.RegionServerTests;
025import org.apache.hadoop.hbase.testclassification.SmallTests;
026import org.junit.ClassRule;
027import org.junit.Test;
028import org.junit.experimental.categories.Category;
029
030@Category({ RegionServerTests.class, SmallTests.class })
031public class TestDefaultOperationQuota {
032  @ClassRule
033  public static final HBaseClassTestRule CLASS_RULE =
034    HBaseClassTestRule.forClass(TestDefaultOperationQuota.class);
035
036  @Test
037  public void testScanEstimateNewScanner() {
038    long blockSize = 64 * 1024;
039    long nextCallSeq = 0;
040    long maxScannerResultSize = 100 * 1024 * 1024;
041    long maxBlockBytesScanned = 0;
042    long prevBBSDifference = 0;
043    long estimate = DefaultOperationQuota.getScanReadConsumeEstimate(blockSize, nextCallSeq,
044      maxScannerResultSize, maxBlockBytesScanned, prevBBSDifference);
045
046    // new scanner should estimate scan read as 1 block
047    assertEquals(blockSize, estimate);
048  }
049
050  @Test
051  public void testScanEstimateSecondNextCall() {
052    long blockSize = 64 * 1024;
053    long nextCallSeq = 1;
054    long maxScannerResultSize = 100 * 1024 * 1024;
055    long maxBlockBytesScanned = 10 * blockSize;
056    long prevBBSDifference = 10 * blockSize;
057    long estimate = DefaultOperationQuota.getScanReadConsumeEstimate(blockSize, nextCallSeq,
058      maxScannerResultSize, maxBlockBytesScanned, prevBBSDifference);
059
060    // 2nd next call should be estimated at maxBBS
061    assertEquals(maxBlockBytesScanned, estimate);
062  }
063
064  @Test
065  public void testScanEstimateFlatWorkload() {
066    long blockSize = 64 * 1024;
067    long nextCallSeq = 100;
068    long maxScannerResultSize = 100 * 1024 * 1024;
069    long maxBlockBytesScanned = 10 * blockSize;
070    long prevBBSDifference = 0;
071    long estimate = DefaultOperationQuota.getScanReadConsumeEstimate(blockSize, nextCallSeq,
072      maxScannerResultSize, maxBlockBytesScanned, prevBBSDifference);
073
074    // flat workload should not overestimate
075    assertEquals(maxBlockBytesScanned, estimate);
076  }
077
078  @Test
079  public void testScanEstimateVariableFlatWorkload() {
080    long blockSize = 64 * 1024;
081    long nextCallSeq = 1;
082    long maxScannerResultSize = 100 * 1024 * 1024;
083    long maxBlockBytesScanned = 10 * blockSize;
084    long prevBBSDifference = 0;
085    for (int i = 0; i < 100; i++) {
086      long variation = Math.round(Math.random() * blockSize);
087      if (variation % 2 == 0) {
088        variation *= -1;
089      }
090      // despite +/- <1 block variation, we consider this workload flat
091      prevBBSDifference = variation;
092
093      long estimate = DefaultOperationQuota.getScanReadConsumeEstimate(blockSize, nextCallSeq + i,
094        maxScannerResultSize, maxBlockBytesScanned, prevBBSDifference);
095
096      // flat workload should not overestimate
097      assertEquals(maxBlockBytesScanned, estimate);
098    }
099  }
100
101  @Test
102  public void testScanEstimateGrowingWorkload() {
103    long blockSize = 64 * 1024;
104    long nextCallSeq = 100;
105    long maxScannerResultSize = 100 * 1024 * 1024;
106    long maxBlockBytesScanned = 20 * blockSize;
107    long prevBBSDifference = 10 * blockSize;
108    long estimate = DefaultOperationQuota.getScanReadConsumeEstimate(blockSize, nextCallSeq,
109      maxScannerResultSize, maxBlockBytesScanned, prevBBSDifference);
110
111    // growing workload should overestimate
112    assertTrue(nextCallSeq * maxBlockBytesScanned == estimate || maxScannerResultSize == estimate);
113  }
114
115  @Test
116  public void testScanEstimateShrinkingWorkload() {
117    long blockSize = 64 * 1024;
118    long nextCallSeq = 100;
119    long maxScannerResultSize = 100 * 1024 * 1024;
120    long maxBlockBytesScanned = 20 * blockSize;
121    long prevBBSDifference = -10 * blockSize;
122    long estimate = DefaultOperationQuota.getScanReadConsumeEstimate(blockSize, nextCallSeq,
123      maxScannerResultSize, maxBlockBytesScanned, prevBBSDifference);
124
125    // shrinking workload should only shrink estimate to maxBBS
126    assertEquals(maxBlockBytesScanned, estimate);
127  }
128}