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