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