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.client; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertTrue; 022 023import org.apache.hadoop.conf.Configuration; 024import org.apache.hadoop.hbase.HBaseClassTestRule; 025import org.apache.hadoop.hbase.ServerName; 026import org.apache.hadoop.hbase.client.backoff.ExponentialClientBackoffPolicy; 027import org.apache.hadoop.hbase.client.backoff.ServerStatistics; 028import org.apache.hadoop.hbase.testclassification.ClientTests; 029import org.apache.hadoop.hbase.testclassification.SmallTests; 030import org.apache.hadoop.hbase.util.Bytes; 031import org.junit.ClassRule; 032import org.junit.Test; 033import org.junit.experimental.categories.Category; 034import org.mockito.Mockito; 035 036import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 037import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos; 038 039@Category({ ClientTests.class, SmallTests.class }) 040public class TestClientExponentialBackoff { 041 @ClassRule 042 public static final HBaseClassTestRule CLASS_RULE = 043 HBaseClassTestRule.forClass(TestClientExponentialBackoff.class); 044 045 ServerName server = Mockito.mock(ServerName.class); 046 byte[] regionname = Bytes.toBytes("region"); 047 048 @Test 049 public void testNulls() { 050 Configuration conf = new Configuration(false); 051 ExponentialClientBackoffPolicy backoff = new ExponentialClientBackoffPolicy(conf); 052 assertEquals(0, backoff.getBackoffTime(null, null, null)); 053 054 // server name doesn't matter to calculation, but check it now anyways 055 assertEquals(0, backoff.getBackoffTime(server, null, null)); 056 assertEquals(0, backoff.getBackoffTime(server, regionname, null)); 057 058 // check when no stats for the region yet 059 ServerStatistics stats = new ServerStatistics(); 060 assertEquals(0, backoff.getBackoffTime(server, regionname, stats)); 061 } 062 063 @Test 064 public void testMaxLoad() { 065 Configuration conf = new Configuration(false); 066 ExponentialClientBackoffPolicy backoff = new ExponentialClientBackoffPolicy(conf); 067 068 ServerStatistics stats = new ServerStatistics(); 069 update(stats, 100); 070 assertEquals(ExponentialClientBackoffPolicy.DEFAULT_MAX_BACKOFF, 071 backoff.getBackoffTime(server, regionname, stats)); 072 073 // another policy with a different max timeout 074 long max = 100; 075 conf.setLong(ExponentialClientBackoffPolicy.MAX_BACKOFF_KEY, max); 076 ExponentialClientBackoffPolicy backoffShortTimeout = new ExponentialClientBackoffPolicy(conf); 077 assertEquals(max, backoffShortTimeout.getBackoffTime(server, regionname, stats)); 078 079 // test beyond 100 still doesn't exceed the max 080 update(stats, 101); 081 assertEquals(ExponentialClientBackoffPolicy.DEFAULT_MAX_BACKOFF, 082 backoff.getBackoffTime(server, regionname, stats)); 083 assertEquals(max, backoffShortTimeout.getBackoffTime(server, regionname, stats)); 084 085 // and that when we are below 100, its less than the max timeout 086 update(stats, 99); 087 assertTrue(backoff.getBackoffTime(server, regionname, stats) 088 < ExponentialClientBackoffPolicy.DEFAULT_MAX_BACKOFF); 089 assertTrue(backoffShortTimeout.getBackoffTime(server, regionname, stats) < max); 090 } 091 092 /** 093 * Make sure that we get results in the order that we expect - backoff for a load of 1 should less 094 * than backoff for 10, which should be less than that for 50. 095 */ 096 @Test 097 public void testResultOrdering() { 098 Configuration conf = new Configuration(false); 099 // make the max timeout really high so we get differentiation between load factors 100 conf.setLong(ExponentialClientBackoffPolicy.MAX_BACKOFF_KEY, Integer.MAX_VALUE); 101 ExponentialClientBackoffPolicy backoff = new ExponentialClientBackoffPolicy(conf); 102 103 ServerStatistics stats = new ServerStatistics(); 104 long previous = backoff.getBackoffTime(server, regionname, stats); 105 for (int i = 1; i <= 100; i++) { 106 update(stats, i); 107 long next = backoff.getBackoffTime(server, regionname, stats); 108 assertTrue("Previous backoff time" + previous + " >= " + next + ", the next backoff time for " 109 + "load " + i, previous < next); 110 previous = next; 111 } 112 } 113 114 @Test 115 public void testHeapOccupancyPolicy() { 116 Configuration conf = new Configuration(false); 117 ExponentialClientBackoffPolicy backoff = new ExponentialClientBackoffPolicy(conf); 118 119 ServerStatistics stats = new ServerStatistics(); 120 long backoffTime; 121 122 update(stats, 0, 95, 0); 123 backoffTime = backoff.getBackoffTime(server, regionname, stats); 124 assertTrue("Heap occupancy at low watermark had no effect", backoffTime > 0); 125 126 long previous = backoffTime; 127 update(stats, 0, 96, 0); 128 backoffTime = backoff.getBackoffTime(server, regionname, stats); 129 assertTrue("Increase above low watermark should have increased backoff", 130 backoffTime > previous); 131 132 update(stats, 0, 98, 0); 133 backoffTime = backoff.getBackoffTime(server, regionname, stats); 134 assertEquals("We should be using max backoff when at high watermark", 135 ExponentialClientBackoffPolicy.DEFAULT_MAX_BACKOFF, backoffTime); 136 } 137 138 @Test 139 public void testCompactionPressurePolicy() { 140 Configuration conf = new Configuration(false); 141 ExponentialClientBackoffPolicy backoff = new ExponentialClientBackoffPolicy(conf); 142 143 ServerStatistics stats = new ServerStatistics(); 144 long backoffTime; 145 146 update(stats, 0, 0, 0); 147 backoffTime = backoff.getBackoffTime(server, regionname, stats); 148 assertTrue("Compaction pressure has no effect", backoffTime == 0); 149 150 long previous = backoffTime; 151 update(stats, 0, 0, 50); 152 backoffTime = backoff.getBackoffTime(server, regionname, stats); 153 assertTrue("Compaction pressure should be bigger", backoffTime > previous); 154 155 update(stats, 0, 0, 100); 156 backoffTime = backoff.getBackoffTime(server, regionname, stats); 157 assertEquals("under heavy compaction pressure", 158 ExponentialClientBackoffPolicy.DEFAULT_MAX_BACKOFF, backoffTime); 159 } 160 161 private void update(ServerStatistics stats, int load) { 162 ClientProtos.RegionLoadStats stat = 163 ClientProtos.RegionLoadStats.newBuilder().setMemStoreLoad(load).build(); 164 stats.update(regionname, ProtobufUtil.createRegionLoadStats(stat)); 165 } 166 167 private void update(ServerStatistics stats, int memstoreLoad, int heapOccupancy, 168 int compactionPressure) { 169 ClientProtos.RegionLoadStats stat = 170 ClientProtos.RegionLoadStats.newBuilder().setMemStoreLoad(memstoreLoad) 171 .setHeapOccupancy(heapOccupancy).setCompactionPressure(compactionPressure).build(); 172 stats.update(regionname, ProtobufUtil.createRegionLoadStats(stat)); 173 } 174}