1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.client;
19
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.concurrent.CountDownLatch;
23 import java.util.concurrent.TimeUnit;
24 import java.util.concurrent.atomic.AtomicLong;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.apache.hadoop.conf.Configuration;
29 import org.apache.hadoop.hbase.HBaseTestingUtility;
30 import org.apache.hadoop.hbase.HConstants;
31 import org.apache.hadoop.hbase.ServerName;
32 import org.apache.hadoop.hbase.TableName;
33 import org.apache.hadoop.hbase.client.backoff.ClientBackoffPolicy;
34 import org.apache.hadoop.hbase.client.backoff.ExponentialClientBackoffPolicy;
35 import org.apache.hadoop.hbase.client.backoff.ServerStatistics;
36 import org.apache.hadoop.hbase.client.coprocessor.Batch;
37 import org.apache.hadoop.hbase.regionserver.HRegion;
38 import org.apache.hadoop.hbase.regionserver.HRegionServer;
39 import org.apache.hadoop.hbase.testclassification.MediumTests;
40 import org.apache.hadoop.hbase.util.Bytes;
41 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
42 import org.junit.AfterClass;
43 import org.junit.BeforeClass;
44 import org.junit.Test;
45 import org.junit.experimental.categories.Category;
46
47 import static org.apache.hadoop.hbase.client.MetricsConnection.CLIENT_SIDE_METRICS_ENABLED_KEY;
48 import static org.junit.Assert.assertEquals;
49 import static org.junit.Assert.assertNotEquals;
50 import static org.junit.Assert.assertNotNull;
51 import static org.junit.Assert.assertTrue;
52
53
54
55
56 @Category(MediumTests.class)
57 public class TestClientPushback {
58
59 private static final Log LOG = LogFactory.getLog(TestClientPushback.class);
60 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
61
62 private static final byte[] tableName = Bytes.toBytes("client-pushback");
63 private static final byte[] family = Bytes.toBytes("f");
64 private static final byte[] qualifier = Bytes.toBytes("q");
65 private static long flushSizeBytes = 1024;
66
67 @BeforeClass
68 public static void setupCluster() throws Exception{
69 Configuration conf = UTIL.getConfiguration();
70
71 conf.setBoolean(HConstants.ENABLE_CLIENT_BACKPRESSURE, true);
72
73 conf.setClass(ClientBackoffPolicy.BACKOFF_POLICY_CLASS, ExponentialClientBackoffPolicy.class,
74 ClientBackoffPolicy.class);
75
76
77 conf.setLong(HConstants.HREGION_MEMSTORE_FLUSH_SIZE, flushSizeBytes);
78
79 conf.setLong(HConstants.HREGION_MEMSTORE_BLOCK_MULTIPLIER, HConstants.DEFAULT_HREGION_MEMSTORE_BLOCK_MULTIPLIER);
80 conf.setBoolean(CLIENT_SIDE_METRICS_ENABLED_KEY, true);
81 UTIL.startMiniCluster(1);
82 UTIL.createTable(tableName, family);
83 }
84
85 @AfterClass
86 public static void teardownCluster() throws Exception{
87 UTIL.shutdownMiniCluster();
88 }
89
90 @Test(timeout=60000)
91 public void testClientTracksServerPushback() throws Exception{
92 Configuration conf = UTIL.getConfiguration();
93 TableName tablename = TableName.valueOf(tableName);
94
95
96 HConnection conn = HConnectionManager.createConnection(conf);
97 HTable table = (HTable) conn.getTable(tablename);
98
99 HRegionServer rs = UTIL.getHBaseCluster().getRegionServer(0);
100 HRegion region = rs.getOnlineRegions(tablename).get(0);
101
102 LOG.debug("Writing some data to "+tablename);
103
104 Put p = new Put(Bytes.toBytes("row"));
105 p.add(family, qualifier, Bytes.toBytes("value1"));
106 table.put(p);
107 table.flushCommits();
108
109
110 int load = (int)((region.addAndGetGlobalMemstoreSize(0) * 100) / flushSizeBytes);
111 LOG.debug("Done writing some data to "+tablename);
112
113
114 ClientBackoffPolicy backoffPolicy = conn.getBackoffPolicy();
115 assertTrue("Backoff policy is not correctly configured",
116 backoffPolicy instanceof ExponentialClientBackoffPolicy);
117
118 ServerStatisticTracker stats = conn.getStatisticsTracker();
119 assertNotNull( "No stats configured for the client!", stats);
120
121 ServerName server = rs.getServerName();
122 byte[] regionName = region.getRegionName();
123
124
125 ServerStatistics serverStats = stats.getServerStatsForTesting(server);
126 ServerStatistics.RegionStatistics regionStats = serverStats.getStatsForRegion(regionName);
127 assertEquals("We did not find some load on the memstore", load,
128 regionStats.getMemstoreLoadPercent());
129
130
131 long backoffTime = backoffPolicy.getBackoffTime(server, regionName, serverStats);
132 assertNotEquals("Reported load does not produce a backoff", backoffTime, 0);
133 LOG.debug("Backoff calculated for " + region.getRegionNameAsString() + " @ " + server +
134 " is " + backoffTime);
135
136
137
138 List<Row> ops = new ArrayList<Row>(1);
139 p = new Put(Bytes.toBytes("row"));
140 p.add(family, qualifier, Bytes.toBytes("value2"));
141 ops.add(p);
142 final CountDownLatch latch = new CountDownLatch(1);
143 final AtomicLong endTime = new AtomicLong();
144 long startTime = EnvironmentEdgeManager.currentTimeMillis();
145 table.ap.submit(ops, true, new Batch.Callback<Object>() {
146 @Override
147 public void update(byte[] region, byte[] row, Object result) {
148 endTime.set(EnvironmentEdgeManager.currentTimeMillis());
149 latch.countDown();
150 }
151 });
152
153
154
155
156
157 String name = server.getServerName() + "," + Bytes.toStringBinary(regionName);
158 MetricsConnection.RegionStats rsStats = conn.getConnectionMetrics().
159 serverStats.get(server).get(regionName);
160 assertEquals(name, rsStats.name);
161 assertEquals(rsStats.heapOccupancyHist.mean(),
162 (double)regionStats.getHeapOccupancyPercent(), 0.1 );
163 assertEquals(rsStats.memstoreLoadHist.mean(),
164 (double)regionStats.getMemstoreLoadPercent(), 0.1);
165
166 MetricsConnection.RunnerStats runnerStats = conn.getConnectionMetrics().runnerStats;
167
168 assertEquals(runnerStats.delayRunners.count(), 1);
169 assertEquals(runnerStats.normalRunners.count(), 1);
170 assertEquals("", runnerStats.delayIntevalHist.mean(), (double)backoffTime, 0.1);
171
172 latch.await(backoffTime * 2, TimeUnit.MILLISECONDS);
173 assertNotEquals("AsyncProcess did not submit the work in time", endTime.get(), 0);
174 assertTrue("AsyncProcess did not delay long enough", endTime.get() - startTime >= backoffTime);
175 }
176 }