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, backoff.getBackoffTime(server, 071 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, backoff.getBackoffTime(server, 082 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, 088 regionname, stats) < 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 094 * less 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( 109 "Previous backoff time" + previous + " >= " + next + ", the next backoff time for " + 110 "load " + i, previous < next); 111 previous = next; 112 } 113 } 114 115 @Test 116 public void testHeapOccupancyPolicy() { 117 Configuration conf = new Configuration(false); 118 ExponentialClientBackoffPolicy backoff = new ExponentialClientBackoffPolicy(conf); 119 120 ServerStatistics stats = new ServerStatistics(); 121 long backoffTime; 122 123 update(stats, 0, 95, 0); 124 backoffTime = backoff.getBackoffTime(server, regionname, stats); 125 assertTrue("Heap occupancy at low watermark had no effect", backoffTime > 0); 126 127 long previous = backoffTime; 128 update(stats, 0, 96, 0); 129 backoffTime = backoff.getBackoffTime(server, regionname, stats); 130 assertTrue("Increase above low watermark should have increased backoff", 131 backoffTime > previous); 132 133 update(stats, 0, 98, 0); 134 backoffTime = backoff.getBackoffTime(server, regionname, stats); 135 assertEquals("We should be using max backoff when at high watermark", 136 ExponentialClientBackoffPolicy.DEFAULT_MAX_BACKOFF, backoffTime); 137 } 138 139 @Test 140 public void testCompactionPressurePolicy() { 141 Configuration conf = new Configuration(false); 142 ExponentialClientBackoffPolicy backoff = new ExponentialClientBackoffPolicy(conf); 143 144 ServerStatistics stats = new ServerStatistics(); 145 long backoffTime; 146 147 update(stats, 0, 0, 0); 148 backoffTime = backoff.getBackoffTime(server, regionname, stats); 149 assertTrue("Compaction pressure has no effect", backoffTime == 0); 150 151 long previous = backoffTime; 152 update(stats, 0, 0, 50); 153 backoffTime = backoff.getBackoffTime(server, regionname, stats); 154 assertTrue("Compaction pressure should be bigger", 155 backoffTime > previous); 156 157 update(stats, 0, 0, 100); 158 backoffTime = backoff.getBackoffTime(server, regionname, stats); 159 assertEquals("under heavy compaction pressure", 160 ExponentialClientBackoffPolicy.DEFAULT_MAX_BACKOFF, backoffTime); 161 } 162 163 private void update(ServerStatistics stats, int load) { 164 ClientProtos.RegionLoadStats stat = ClientProtos.RegionLoadStats.newBuilder() 165 .setMemStoreLoad(load).build(); 166 stats.update(regionname, ProtobufUtil.createRegionLoadStats(stat)); 167 } 168 169 private void update(ServerStatistics stats, int memstoreLoad, int heapOccupancy, 170 int compactionPressure) { 171 ClientProtos.RegionLoadStats stat = ClientProtos.RegionLoadStats.newBuilder() 172 .setMemStoreLoad(memstoreLoad) 173 .setHeapOccupancy(heapOccupancy) 174 .setCompactionPressure(compactionPressure) 175 .build(); 176 stats.update(regionname, ProtobufUtil.createRegionLoadStats(stat)); 177 } 178}