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.HRegionServer;
39 import org.apache.hadoop.hbase.regionserver.Region;
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();
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 Connection conn = ConnectionFactory.createConnection(conf);
96 HTable table = (HTable) conn.getTable(tablename);
97
98 table.setAutoFlushTo(true);
99
100
101 Put p = new Put(Bytes.toBytes("row"));
102 p.add(family, qualifier, Bytes.toBytes("value1"));
103 table.put(p);
104
105
106 ClusterConnection connection = table.connection;
107 ClientBackoffPolicy backoffPolicy = connection.getBackoffPolicy();
108 assertTrue("Backoff policy is not correctly configured",
109 backoffPolicy instanceof ExponentialClientBackoffPolicy);
110
111 ServerStatisticTracker stats = connection.getStatisticsTracker();
112 assertNotNull( "No stats configured for the client!", stats);
113 Region region = UTIL.getHBaseCluster().getRegionServer(0).getOnlineRegions(tablename).get(0);
114
115 ServerName server = UTIL.getHBaseCluster().getRegionServer(0).getServerName();
116 byte[] regionName = region.getRegionInfo().getRegionName();
117
118
119 ServerStatistics serverStats = stats.getServerStatsForTesting(server);
120 ServerStatistics.RegionStatistics regionStats = serverStats.getStatsForRegion(regionName);
121 int load = regionStats.getMemstoreLoadPercent();
122 assertEquals("We did not find some load on the memstore", load,
123 regionStats.getMemstoreLoadPercent());
124
125
126 long backoffTime = backoffPolicy.getBackoffTime(server, regionName, serverStats);
127 assertNotEquals("Reported load does not produce a backoff", backoffTime, 0);
128 LOG.debug("Backoff calculated for " + region.getRegionInfo().getRegionNameAsString() + " @ " +
129 server + " is " + backoffTime);
130
131
132
133 List<Row> ops = new ArrayList<Row>(1);
134 ops.add(p);
135 final CountDownLatch latch = new CountDownLatch(1);
136 final AtomicLong endTime = new AtomicLong();
137 long startTime = EnvironmentEdgeManager.currentTime();
138 table.mutator.ap.submit(tablename, ops, true, new Batch.Callback<Result>() {
139 @Override
140 public void update(byte[] region, byte[] row, Result result) {
141 endTime.set(EnvironmentEdgeManager.currentTime());
142 latch.countDown();
143 }
144 }, true);
145
146
147
148
149 String name = server.getServerName() + "," + Bytes.toStringBinary(regionName);
150 MetricsConnection.RegionStats rsStats = connection.getConnectionMetrics().
151 serverStats.get(server).get(regionName);
152 assertEquals(name, rsStats.name);
153 assertEquals(rsStats.heapOccupancyHist.mean(),
154 (double)regionStats.getHeapOccupancyPercent(), 0.1 );
155 assertEquals(rsStats.memstoreLoadHist.mean(),
156 (double)regionStats.getMemstoreLoadPercent(), 0.1);
157
158 MetricsConnection.RunnerStats runnerStats = connection.getConnectionMetrics().runnerStats;
159
160 assertEquals(runnerStats.delayRunners.count(), 1);
161 assertEquals(runnerStats.normalRunners.count(), 1);
162 assertEquals("", runnerStats.delayIntevalHist.mean(), (double)backoffTime, 0.1);
163
164 latch.await(backoffTime * 2, TimeUnit.MILLISECONDS);
165 assertNotEquals("AsyncProcess did not submit the work time", endTime.get(), 0);
166 assertTrue("AsyncProcess did not delay long enough", endTime.get() - startTime >= backoffTime);
167 }
168
169 @Test
170 public void testMutateRowStats() throws IOException {
171 Configuration conf = UTIL.getConfiguration();
172 ClusterConnection conn = (ClusterConnection) ConnectionFactory.createConnection(conf);
173 HTable table = (HTable) conn.getTable(tableName);
174 HRegionServer rs = UTIL.getHBaseCluster().getRegionServer(0);
175 Region region = rs.getOnlineRegions(TableName.valueOf(tableName)).get(0);
176
177 RowMutations mutations = new RowMutations(Bytes.toBytes("row"));
178 Put p = new Put(Bytes.toBytes("row"));
179 p.addColumn(family, qualifier, Bytes.toBytes("value2"));
180 mutations.add(p);
181 table.mutateRow(mutations);
182
183 ServerStatisticTracker stats = conn.getStatisticsTracker();
184 assertNotNull( "No stats configured for the client!", stats);
185
186 ServerName server = rs.getServerName();
187 byte[] regionName = region.getRegionInfo().getRegionName();
188
189
190 ServerStatistics serverStats = stats.getServerStatsForTesting(server);
191 ServerStatistics.RegionStatistics regionStats = serverStats.getStatsForRegion(regionName);
192
193 assertNotNull(regionStats);
194 assertTrue(regionStats.getMemstoreLoadPercent() > 0);
195 }
196 }