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