/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.client;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.client.backoff.ExponentialClientBackoffPolicy;
import org.apache.hadoop.hbase.client.backoff.ServerStatistics;
import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Test;
import org.mockito.Mockito;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class TestClientExponentialBackoff {
ServerName server = Mockito.mock(ServerName.class);
byte[] regionname = Bytes.toBytes("region");
@Test
public void testNulls() {
Configuration conf = new Configuration(false);
ExponentialClientBackoffPolicy backoff = new ExponentialClientBackoffPolicy(conf);
assertEquals(0, backoff.getBackoffTime(null, null, null));
// server name doesn't matter to calculation, but check it now anyways
assertEquals(0, backoff.getBackoffTime(server, null, null));
assertEquals(0, backoff.getBackoffTime(server, regionname, null));
// check when no stats for the region yet
ServerStatistics stats = new ServerStatistics();
assertEquals(0, backoff.getBackoffTime(server, regionname, stats));
}
@Test
public void testMaxLoad() {
Configuration conf = new Configuration(false);
ExponentialClientBackoffPolicy backoff = new ExponentialClientBackoffPolicy(conf);
ServerStatistics stats = new ServerStatistics();
update(stats, 100);
assertEquals(ExponentialClientBackoffPolicy.DEFAULT_MAX_BACKOFF, backoff.getBackoffTime(server,
regionname, stats));
// another policy with a different max timeout
long max = 100;
conf.setLong(ExponentialClientBackoffPolicy.MAX_BACKOFF_KEY, max);
ExponentialClientBackoffPolicy backoffShortTimeout = new ExponentialClientBackoffPolicy(conf);
assertEquals(max, backoffShortTimeout.getBackoffTime(server, regionname, stats));
// test beyond 100 still doesn't exceed the max
update(stats, 101);
assertEquals(ExponentialClientBackoffPolicy.DEFAULT_MAX_BACKOFF, backoff.getBackoffTime(server,
regionname, stats));
assertEquals(max, backoffShortTimeout.getBackoffTime(server, regionname, stats));
// and that when we are below 100, its less than the max timeout
update(stats, 99);
assertTrue(backoff.getBackoffTime(server,
regionname, stats) < ExponentialClientBackoffPolicy.DEFAULT_MAX_BACKOFF);
assertTrue(backoffShortTimeout.getBackoffTime(server, regionname, stats) < max);
}
/**
* Make sure that we get results in the order that we expect - backoff for a load of 1 should
* less than backoff for 10, which should be less than that for 50.
*/
@Test
public void testResultOrdering() {
Configuration conf = new Configuration(false);
// make the max timeout really high so we get differentiation between load factors
conf.setLong(ExponentialClientBackoffPolicy.MAX_BACKOFF_KEY, Integer.MAX_VALUE);
ExponentialClientBackoffPolicy backoff = new ExponentialClientBackoffPolicy(conf);
ServerStatistics stats = new ServerStatistics();
long previous = backoff.getBackoffTime(server, regionname, stats);
for (int i = 1; i <= 100; i++) {
update(stats, i);
long next = backoff.getBackoffTime(server, regionname, stats);
assertTrue(
"Previous backoff time" + previous + " >= " + next + ", the next backoff time for " +
"load " + i, previous < next);
previous = next;
}
}
@Test
public void testHeapOccupancyPolicy() {
Configuration conf = new Configuration(false);
ExponentialClientBackoffPolicy backoff = new ExponentialClientBackoffPolicy(conf);
ServerStatistics stats = new ServerStatistics();
long backoffTime;
update(stats, 0, 95);
backoffTime = backoff.getBackoffTime(server, regionname, stats);
assertTrue("Heap occupancy at low watermark had no effect", backoffTime > 0);
long previous = backoffTime;
update(stats, 0, 96);
backoffTime = backoff.getBackoffTime(server, regionname, stats);
assertTrue("Increase above low watermark should have increased backoff",
backoffTime > previous);
update(stats, 0, 98);
backoffTime = backoff.getBackoffTime(server, regionname, stats);
assertEquals("We should be using max backoff when at high watermark", backoffTime,
ExponentialClientBackoffPolicy.DEFAULT_MAX_BACKOFF);
}
private void update(ServerStatistics stats, int load) {
ClientProtos.RegionLoadStats stat = ClientProtos.RegionLoadStats.newBuilder()
.setMemstoreLoad
(load).build();
stats.update(regionname, stat);
}
private void update(ServerStatistics stats, int memstoreLoad, int heapOccupancy) {
ClientProtos.RegionLoadStats stat = ClientProtos.RegionLoadStats.newBuilder()
.setMemstoreLoad(memstoreLoad)
.setHeapOccupancy(heapOccupancy)
.build();
stats.update(regionname, stat);
}
}