1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.mapreduce;
20
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertTrue;
23 import static org.junit.Assert.fail;
24
25 import java.io.ByteArrayOutputStream;
26 import java.io.IOException;
27 import java.io.PrintStream;
28 import java.util.ArrayList;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.hadoop.conf.Configuration;
33 import org.apache.hadoop.hbase.CategoryBasedTimeout;
34 import org.apache.hadoop.hbase.HBaseTestingUtility;
35 import org.apache.hadoop.hbase.testclassification.LargeTests;
36 import org.apache.hadoop.hbase.TableName;
37 import org.apache.hadoop.hbase.client.HTable;
38 import org.apache.hadoop.hbase.client.Put;
39 import org.apache.hadoop.hbase.client.Table;
40 import org.apache.hadoop.hbase.mapreduce.RowCounter.RowCounterMapper;
41 import org.apache.hadoop.hbase.util.Bytes;
42 import org.apache.hadoop.hbase.util.LauncherSecurityManager;
43 import org.apache.hadoop.mapreduce.Counter;
44 import org.apache.hadoop.mapreduce.Job;
45 import org.apache.hadoop.util.GenericOptionsParser;
46 import org.junit.AfterClass;
47 import org.junit.BeforeClass;
48 import org.junit.Rule;
49 import org.junit.Test;
50 import org.junit.experimental.categories.Category;
51 import org.junit.rules.TestRule;
52
53
54
55
56 @Category(LargeTests.class)
57 public class TestRowCounter {
58 @Rule public final TestRule timeout = CategoryBasedTimeout.builder().
59 withTimeout(this.getClass()).withLookingForStuckThread(true).build();
60 private static final Log LOG = LogFactory.getLog(TestRowCounter.class);
61 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
62
63 private final static String TABLE_NAME = "testRowCounter";
64
65 private final static String COL_FAM = "col_fam";
66
67 private final static String COL1 = "c1";
68
69 private final static String COL2 = "c2";
70
71 private final static String COMPOSITE_COLUMN = "C:A:A";
72
73 private final static int TOTAL_ROWS = 10;
74
75 private final static int ROWS_WITH_ONE_COL = 2;
76
77
78
79
80 @BeforeClass
81 public static void setUpBeforeClass()
82 throws Exception {
83 TEST_UTIL.setJobWithoutMRCluster();
84 TEST_UTIL.startMiniCluster();
85 Table table = TEST_UTIL.createTable(TableName.valueOf(TABLE_NAME), Bytes.toBytes(COL_FAM));
86 writeRows(table, TOTAL_ROWS, ROWS_WITH_ONE_COL);
87 table.close();
88 }
89
90
91
92
93 @AfterClass
94 public static void tearDownAfterClass()
95 throws Exception {
96 TEST_UTIL.shutdownMiniCluster();
97 }
98
99
100
101
102
103
104 @Test
105 public void testRowCounterNoColumn()
106 throws Exception {
107 String[] args = new String[] {TABLE_NAME};
108 runRowCount(args, 10);
109 }
110
111
112
113
114
115
116
117 @Test
118 public void testRowCounterExclusiveColumn()
119 throws Exception {
120 String[] args = new String[] {TABLE_NAME, COL_FAM + ":" + COL1};
121 runRowCount(args, 8);
122 }
123
124
125
126
127
128
129
130 @Test
131 public void testRowCounterColumnWithColonInQualifier()
132 throws Exception {
133 String[] args = new String[] {TABLE_NAME, COL_FAM + ":" + COMPOSITE_COLUMN};
134 runRowCount(args, 8);
135 }
136
137
138
139
140
141
142
143 @Test
144 public void testRowCounterHiddenColumn()
145 throws Exception {
146 String[] args = new String[] {TABLE_NAME, COL_FAM + ":" + COL2};
147 runRowCount(args, 10);
148 }
149
150
151
152
153
154 @Test
155 public void testRowCounterRowSingleRange() throws Exception {
156 String[] args = new String[] {
157 TABLE_NAME, "--range=row1,row3"
158 };
159 runRowCount(args, 2);
160 }
161
162
163
164
165
166 @Test
167 public void testRowCounterRowSingleRangeUpperBound() throws Exception {
168 String[] args = new String[] {
169 TABLE_NAME, "--range=,row3"
170 };
171 runRowCount(args, 3);
172 }
173
174
175
176
177
178 @Test
179 public void testRowCounterRowMultiRangeUpperBound() throws Exception {
180 String[] args = new String[] {
181 TABLE_NAME, "--range=,row3;row5,row7"
182 };
183 runRowCount(args, 5);
184 }
185
186
187
188
189 @Test
190 public void testRowCounterRowMultiRange() throws Exception {
191 String[] args = new String[] {
192 TABLE_NAME, "--range=row1,row3;row5,row8"
193 };
194 runRowCount(args, 5);
195 }
196
197
198
199
200
201
202 @Test
203 public void testRowCounterRowMultiEmptyRange() throws Exception {
204 String[] args = new String[] {
205 TABLE_NAME, "--range=row1,row3;;"
206 };
207 runRowCount(args, 2);
208 }
209
210 @Test
211 public void testRowCounter10kRowRange() throws Exception {
212 String tableName = TABLE_NAME + "10k";
213
214 try (Table table = TEST_UTIL.createTable(
215 TableName.valueOf(tableName), Bytes.toBytes(COL_FAM))) {
216 writeRows(table, 10000, 0);
217 }
218 String[] args = new String[] {
219 tableName, "--range=row9872,row9875"
220 };
221 runRowCount(args, 3);
222 }
223
224
225
226
227
228 @Test
229 public void testRowCounterRowRangeBinary() throws Exception {
230 String tableName = TABLE_NAME + "Binary";
231 try (Table table = TEST_UTIL.createTable(
232 TableName.valueOf(tableName), Bytes.toBytes(COL_FAM))) {
233 writeRows(table, 10, 0, true);
234 }
235 String[] args = new String[] {
236 tableName, "--range=\\x00row5,\\x00row8"
237 };
238 runRowCount(args, 3);
239 }
240
241
242
243
244
245
246 @Test
247 public void testRowCounterTimeRange()
248 throws Exception {
249 final String tableName = TABLE_NAME + "TimeRange";
250 final byte[] family = Bytes.toBytes(COL_FAM);
251 final byte[] col1 = Bytes.toBytes(COL1);
252 Put put1 = new Put(Bytes.toBytes("row_timerange_" + 1));
253 Put put2 = new Put(Bytes.toBytes("row_timerange_" + 2));
254 Put put3 = new Put(Bytes.toBytes("row_timerange_" + 3));
255
256 long ts;
257
258
259
260 try (Table table = TEST_UTIL.createTable(
261 TableName.valueOf(tableName), Bytes.toBytes(COL_FAM))) {
262
263 ts = System.currentTimeMillis();
264 put1.add(family, col1, ts, Bytes.toBytes("val1"));
265 table.put(put1);
266 Thread.sleep(100);
267
268 ts = System.currentTimeMillis();
269 put2.add(family, col1, ts, Bytes.toBytes("val2"));
270 put3.add(family, col1, ts, Bytes.toBytes("val3"));
271 table.put(put2);
272 table.put(put3);
273 }
274
275 String[] args = new String[] {tableName, COL_FAM + ":" + COL1, "--starttime=" + 0,
276 "--endtime=" + ts};
277 runRowCount(args, 1);
278
279 args = new String[] {tableName, COL_FAM + ":" + COL1, "--starttime=" + 0,
280 "--endtime=" + (ts - 10)};
281 runRowCount(args, 1);
282
283 args = new String[] {tableName, COL_FAM + ":" + COL1, "--starttime=" + ts,
284 "--endtime=" + (ts + 1000)};
285 runRowCount(args, 2);
286
287 args = new String[] {tableName, COL_FAM + ":" + COL1, "--starttime=" + (ts - 30 * 1000),
288 "--endtime=" + (ts + 30 * 1000),};
289 runRowCount(args, 3);
290 }
291
292
293
294
295
296
297
298
299 private void runRowCount(String[] args, int expectedCount)
300 throws Exception {
301 GenericOptionsParser opts = new GenericOptionsParser(TEST_UTIL.getConfiguration(), args);
302 Configuration conf = opts.getConfiguration();
303 args = opts.getRemainingArgs();
304 Job job = RowCounter.createSubmittableJob(conf, args);
305 long start = System.currentTimeMillis();
306 job.waitForCompletion(true);
307 long duration = System.currentTimeMillis() - start;
308 LOG.debug("row count duration (ms): " + duration);
309 assertTrue(job.isSuccessful());
310 Counter counter = job.getCounters().findCounter(RowCounterMapper.Counters.ROWS);
311 assertEquals(expectedCount, counter.getValue());
312 }
313
314 private static void writeRows(Table table, int totalRows, int rowsWithOneCol)
315 throws IOException {
316 writeRows(table, totalRows, rowsWithOneCol, false);
317 }
318
319
320
321
322
323
324
325
326
327
328 private static void writeRows(Table table, int totalRows, int rowsWithOneCol, boolean writeBinary)
329 throws IOException {
330 final String rowPrefix = writeBinary ? "\\x00row" : "row";
331 final byte[] family = Bytes.toBytes(COL_FAM);
332 final byte[] value = Bytes.toBytes("abcd");
333 final byte[] col1 = Bytes.toBytes(COL1);
334 final byte[] col2 = Bytes.toBytes(COL2);
335 final byte[] col3 = Bytes.toBytes(COMPOSITE_COLUMN);
336 ArrayList<Put> rowsUpdate = new ArrayList<Put>();
337
338 int i = 0;
339 for (; i < totalRows - rowsWithOneCol; i++) {
340 byte[] row = Bytes.toBytesBinary(rowPrefix + i);
341 Put put = new Put(row);
342 put.add(family, col1, value);
343 put.add(family, col2, value);
344 put.add(family, col3, value);
345 rowsUpdate.add(put);
346 }
347
348
349 for (; i < totalRows; i++) {
350 byte[] row = Bytes.toBytesBinary(rowPrefix + i);
351 Put put = new Put(row);
352 put.add(family, col2, value);
353 rowsUpdate.add(put);
354 }
355 table.put(rowsUpdate);
356 }
357
358
359
360
361 @Test
362 public void testImportMain()
363 throws Exception {
364 PrintStream oldPrintStream = System.err;
365 SecurityManager SECURITY_MANAGER = System.getSecurityManager();
366 LauncherSecurityManager newSecurityManager = new LauncherSecurityManager();
367 System.setSecurityManager(newSecurityManager);
368 ByteArrayOutputStream data = new ByteArrayOutputStream();
369 String[] args = {};
370 System.setErr(new PrintStream(data));
371 try {
372 System.setErr(new PrintStream(data));
373
374 try {
375 RowCounter.main(args);
376 fail("should be SecurityException");
377 } catch (SecurityException e) {
378 assertEquals(-1, newSecurityManager.getExitCode());
379 assertTrue(data.toString().contains("Wrong number of parameters:"));
380 assertTrue(data.toString().contains("Usage: RowCounter [options] <tablename> " +
381 "[--starttime=[start] --endtime=[end] " +
382 "[--range=[startKey],[endKey]" +
383 "[;[startKey],[endKey]...]] " +
384 "[<column1> <column2>...]"));
385 assertTrue(data.toString().contains("-Dhbase.client.scanner.caching=100"));
386 assertTrue(data.toString().contains("-Dmapreduce.map.speculative=false"));
387 }
388 data.reset();
389 try {
390 args = new String[2];
391 args[0] = "table";
392 args[1] = "--range=1";
393 RowCounter.main(args);
394 fail("should be SecurityException");
395 } catch (SecurityException e) {
396 assertEquals(-1, newSecurityManager.getExitCode());
397 assertTrue(data.toString().contains("Please specify range in such format as \"--range=a,b\" or, with only one boundary," +
398
399 " \"--range=,b\" or \"--range=a,\""));
400 assertTrue(data.toString().contains("Usage: RowCounter [options] <tablename> " +
401 "[--starttime=[start] --endtime=[end] " +
402 "[--range=[startKey],[endKey]" +
403 "[;[startKey],[endKey]...]] " +
404 "[<column1> <column2>...]"));
405 }
406
407 } finally {
408 System.setErr(oldPrintStream);
409 System.setSecurityManager(SECURITY_MANAGER);
410 }
411
412 }
413 }