1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.test;
20
21 import java.io.DataInput;
22 import java.io.DataOutput;
23 import java.io.FileNotFoundException;
24 import java.io.IOException;
25 import java.io.InterruptedIOException;
26 import java.security.SecureRandom;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Random;
32 import java.util.Set;
33 import java.util.SortedSet;
34 import java.util.TreeSet;
35 import java.util.UUID;
36 import java.util.concurrent.ThreadLocalRandom;
37 import java.util.concurrent.atomic.AtomicInteger;
38
39 import org.apache.commons.cli.CommandLine;
40 import org.apache.commons.cli.GnuParser;
41 import org.apache.commons.cli.HelpFormatter;
42 import org.apache.commons.cli.Options;
43 import org.apache.commons.cli.ParseException;
44 import org.apache.commons.logging.Log;
45 import org.apache.commons.logging.LogFactory;
46 import org.apache.hadoop.conf.Configuration;
47 import org.apache.hadoop.conf.Configured;
48 import org.apache.hadoop.fs.FileSystem;
49 import org.apache.hadoop.fs.LocatedFileStatus;
50 import org.apache.hadoop.fs.Path;
51 import org.apache.hadoop.fs.RemoteIterator;
52 import org.apache.hadoop.hbase.Cell;
53 import org.apache.hadoop.hbase.HBaseConfiguration;
54 import org.apache.hadoop.hbase.HBaseTestingUtility;
55 import org.apache.hadoop.hbase.HColumnDescriptor;
56 import org.apache.hadoop.hbase.HConstants;
57 import org.apache.hadoop.hbase.HRegionLocation;
58 import org.apache.hadoop.hbase.HTableDescriptor;
59 import org.apache.hadoop.hbase.client.HTable;
60 import org.apache.hadoop.hbase.client.Table;
61 import org.apache.hadoop.hbase.IntegrationTestBase;
62 import org.apache.hadoop.hbase.IntegrationTestingUtility;
63 import org.apache.hadoop.hbase.testclassification.IntegrationTests;
64 import org.apache.hadoop.hbase.fs.HFileSystem;
65 import org.apache.hadoop.hbase.MasterNotRunningException;
66 import org.apache.hadoop.hbase.TableName;
67 import org.apache.hadoop.hbase.client.Admin;
68 import org.apache.hadoop.hbase.client.BufferedMutator;
69 import org.apache.hadoop.hbase.client.BufferedMutatorParams;
70 import org.apache.hadoop.hbase.client.Connection;
71 import org.apache.hadoop.hbase.client.ConnectionFactory;
72 import org.apache.hadoop.hbase.client.Get;
73 import org.apache.hadoop.hbase.client.Mutation;
74 import org.apache.hadoop.hbase.client.Put;
75 import org.apache.hadoop.hbase.client.RegionLocator;
76 import org.apache.hadoop.hbase.client.Result;
77 import org.apache.hadoop.hbase.client.ResultScanner;
78 import org.apache.hadoop.hbase.client.Scan;
79 import org.apache.hadoop.hbase.client.ScannerCallable;
80 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
81 import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
82 import org.apache.hadoop.hbase.mapreduce.TableMapper;
83 import org.apache.hadoop.hbase.mapreduce.TableRecordReaderImpl;
84 import org.apache.hadoop.hbase.mapreduce.WALPlayer;
85 import org.apache.hadoop.hbase.regionserver.FlushLargeStoresPolicy;
86 import org.apache.hadoop.hbase.regionserver.FlushPolicyFactory;
87 import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
88 import org.apache.hadoop.hbase.util.AbstractHBaseTool;
89 import org.apache.hadoop.hbase.util.Bytes;
90 import org.apache.hadoop.hbase.util.RegionSplitter;
91 import org.apache.hadoop.hbase.wal.WALKey;
92 import org.apache.hadoop.io.BytesWritable;
93 import org.apache.hadoop.io.NullWritable;
94 import org.apache.hadoop.io.Writable;
95 import org.apache.hadoop.mapreduce.Counter;
96 import org.apache.hadoop.mapreduce.CounterGroup;
97 import org.apache.hadoop.mapreduce.Counters;
98 import org.apache.hadoop.mapreduce.InputFormat;
99 import org.apache.hadoop.mapreduce.InputSplit;
100 import org.apache.hadoop.mapreduce.Job;
101 import org.apache.hadoop.mapreduce.JobContext;
102 import org.apache.hadoop.mapreduce.Mapper;
103 import org.apache.hadoop.mapreduce.RecordReader;
104 import org.apache.hadoop.mapreduce.Reducer;
105 import org.apache.hadoop.mapreduce.TaskAttemptContext;
106 import org.apache.hadoop.mapreduce.TaskAttemptID;
107 import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
108 import org.apache.hadoop.mapreduce.lib.input.FileSplit;
109 import org.apache.hadoop.mapreduce.lib.input.SequenceFileAsBinaryInputFormat;
110 import org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat;
111 import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
112 import org.apache.hadoop.mapreduce.lib.output.NullOutputFormat;
113 import org.apache.hadoop.mapreduce.lib.output.SequenceFileAsBinaryOutputFormat;
114 import org.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat;
115 import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
116 import org.apache.hadoop.mapreduce.task.TaskAttemptContextImpl;
117 import org.apache.hadoop.util.Tool;
118 import org.apache.hadoop.util.ToolRunner;
119 import org.junit.Test;
120 import org.junit.experimental.categories.Category;
121
122 import com.google.common.collect.Sets;
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187 @Category(IntegrationTests.class)
188 public class IntegrationTestBigLinkedList extends IntegrationTestBase {
189 protected static final byte[] NO_KEY = new byte[1];
190
191 protected static String TABLE_NAME_KEY = "IntegrationTestBigLinkedList.table";
192
193 protected static String DEFAULT_TABLE_NAME = "IntegrationTestBigLinkedList";
194
195 protected static byte[] FAMILY_NAME = Bytes.toBytes("meta");
196 private static byte[] BIG_FAMILY_NAME = Bytes.toBytes("big");
197 private static byte[] TINY_FAMILY_NAME = Bytes.toBytes("tiny");
198
199
200 protected static final byte[] COLUMN_PREV = Bytes.toBytes("prev");
201
202
203 protected static final byte[] COLUMN_CLIENT = Bytes.toBytes("client");
204
205
206 protected static final byte[] COLUMN_COUNT = Bytes.toBytes("count");
207
208
209 private static final String GENERATOR_NUM_ROWS_PER_MAP_KEY
210 = "IntegrationTestBigLinkedList.generator.num_rows";
211
212 private static final String GENERATOR_NUM_MAPPERS_KEY
213 = "IntegrationTestBigLinkedList.generator.map.tasks";
214
215 private static final String GENERATOR_WIDTH_KEY
216 = "IntegrationTestBigLinkedList.generator.width";
217
218 private static final String GENERATOR_WRAP_KEY
219 = "IntegrationTestBigLinkedList.generator.wrap";
220
221 protected int NUM_SLAVES_BASE = 3;
222
223 private static final int MISSING_ROWS_TO_LOG = 10;
224
225 private static final int WIDTH_DEFAULT = 1000000;
226 private static final int WRAP_DEFAULT = 25;
227 private static final int ROWKEY_LENGTH = 16;
228
229 protected String toRun;
230 protected String[] otherArgs;
231
232 static class CINode {
233 byte[] key;
234 byte[] prev;
235 String client;
236 long count;
237 }
238
239
240
241
242 static class Generator extends Configured implements Tool {
243
244 private static final Log LOG = LogFactory.getLog(Generator.class);
245
246
247
248
249
250
251
252
253
254
255
256
257 public static final String MULTIPLE_UNEVEN_COLUMNFAMILIES_KEY =
258 "generator.multiple.columnfamilies";
259
260 static class GeneratorInputFormat extends InputFormat<BytesWritable,NullWritable> {
261 static class GeneratorInputSplit extends InputSplit implements Writable {
262 @Override
263 public long getLength() throws IOException, InterruptedException {
264 return 1;
265 }
266 @Override
267 public String[] getLocations() throws IOException, InterruptedException {
268 return new String[0];
269 }
270 @Override
271 public void readFields(DataInput arg0) throws IOException {
272 }
273 @Override
274 public void write(DataOutput arg0) throws IOException {
275 }
276 }
277
278 static class GeneratorRecordReader extends RecordReader<BytesWritable,NullWritable> {
279 private long count;
280 private long numNodes;
281 private Random rand;
282
283 @Override
284 public void close() throws IOException {
285 }
286
287 @Override
288 public BytesWritable getCurrentKey() throws IOException, InterruptedException {
289 byte[] bytes = new byte[ROWKEY_LENGTH];
290 rand.nextBytes(bytes);
291 return new BytesWritable(bytes);
292 }
293
294 @Override
295 public NullWritable getCurrentValue() throws IOException, InterruptedException {
296 return NullWritable.get();
297 }
298
299 @Override
300 public float getProgress() throws IOException, InterruptedException {
301 return (float)(count / (double)numNodes);
302 }
303
304 @Override
305 public void initialize(InputSplit arg0, TaskAttemptContext context)
306 throws IOException, InterruptedException {
307 numNodes = context.getConfiguration().getLong(GENERATOR_NUM_ROWS_PER_MAP_KEY, 25000000);
308
309 rand = new SecureRandom();
310 }
311
312 @Override
313 public boolean nextKeyValue() throws IOException, InterruptedException {
314 return count++ < numNodes;
315 }
316
317 }
318
319 @Override
320 public RecordReader<BytesWritable,NullWritable> createRecordReader(
321 InputSplit split, TaskAttemptContext context) throws IOException, InterruptedException {
322 GeneratorRecordReader rr = new GeneratorRecordReader();
323 rr.initialize(split, context);
324 return rr;
325 }
326
327 @Override
328 public List<InputSplit> getSplits(JobContext job) throws IOException, InterruptedException {
329 int numMappers = job.getConfiguration().getInt(GENERATOR_NUM_MAPPERS_KEY, 1);
330
331 ArrayList<InputSplit> splits = new ArrayList<InputSplit>(numMappers);
332
333 for (int i = 0; i < numMappers; i++) {
334 splits.add(new GeneratorInputSplit());
335 }
336
337 return splits;
338 }
339 }
340
341
342 static class OneFilePerMapperSFIF<K, V> extends SequenceFileInputFormat<K, V> {
343 @Override
344 protected boolean isSplitable(JobContext context, Path filename) {
345 return false;
346 }
347 }
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375 static class GeneratorMapper
376 extends Mapper<BytesWritable, NullWritable, NullWritable, NullWritable> {
377
378 byte[][] first = null;
379 byte[][] prev = null;
380 byte[][] current = null;
381 byte[] id;
382 long count = 0;
383 int i;
384 BufferedMutator mutator;
385 Connection connection;
386 long numNodes;
387 long wrap;
388 int width;
389 boolean multipleUnevenColumnFamilies;
390 byte[] tinyValue = new byte[] { 't' };
391 byte[] bigValue = null;
392
393 @Override
394 protected void setup(Context context) throws IOException, InterruptedException {
395 id = Bytes.toBytes("Job: "+context.getJobID() + " Task: " + context.getTaskAttemptID());
396 Configuration conf = context.getConfiguration();
397 connection = ConnectionFactory.createConnection(conf);
398 instantiateHTable();
399 this.width = context.getConfiguration().getInt(GENERATOR_WIDTH_KEY, WIDTH_DEFAULT);
400 current = new byte[this.width][];
401 int wrapMultiplier = context.getConfiguration().getInt(GENERATOR_WRAP_KEY, WRAP_DEFAULT);
402 this.wrap = (long)wrapMultiplier * width;
403 this.numNodes = context.getConfiguration().getLong(
404 GENERATOR_NUM_ROWS_PER_MAP_KEY, (long)WIDTH_DEFAULT * WRAP_DEFAULT);
405 if (this.numNodes < this.wrap) {
406 this.wrap = this.numNodes;
407 }
408 this.multipleUnevenColumnFamilies =
409 context.getConfiguration().getBoolean(MULTIPLE_UNEVEN_COLUMNFAMILIES_KEY, false);
410 }
411
412 protected void instantiateHTable() throws IOException {
413 mutator = connection.getBufferedMutator(
414 new BufferedMutatorParams(getTableName(connection.getConfiguration()))
415 .writeBufferSize(4 * 1024 * 1024));
416 }
417
418 @Override
419 protected void cleanup(Context context) throws IOException ,InterruptedException {
420 mutator.close();
421 connection.close();
422 }
423
424 @Override
425 protected void map(BytesWritable key, NullWritable value, Context output) throws IOException {
426 current[i] = new byte[key.getLength()];
427 System.arraycopy(key.getBytes(), 0, current[i], 0, key.getLength());
428 if (++i == current.length) {
429 LOG.info("Persisting current.length=" + current.length + ", count=" + count + ", id=" +
430 Bytes.toStringBinary(id) + ", current=" + Bytes.toStringBinary(current[0]) +
431 ", i=" + i);
432 persist(output, count, prev, current, id);
433 i = 0;
434
435 if (first == null) {
436 first = current;
437 }
438 prev = current;
439 current = new byte[this.width][];
440
441 count += current.length;
442 output.setStatus("Count " + count);
443
444 if (count % wrap == 0) {
445
446
447 circularLeftShift(first);
448
449 persist(output, -1, prev, first, null);
450
451 first = null;
452 prev = null;
453 }
454 }
455 }
456
457 private static <T> void circularLeftShift(T[] first) {
458 T ez = first[0];
459 System.arraycopy(first, 1, first, 0, first.length - 1);
460 first[first.length - 1] = ez;
461 }
462
463 protected void persist(Context output, long count, byte[][] prev, byte[][] current, byte[] id)
464 throws IOException {
465 for (int i = 0; i < current.length; i++) {
466 Put put = new Put(current[i]);
467 put.addColumn(FAMILY_NAME, COLUMN_PREV, prev == null ? NO_KEY : prev[i]);
468
469 if (count >= 0) {
470 put.addColumn(FAMILY_NAME, COLUMN_COUNT, Bytes.toBytes(count + i));
471 }
472 if (id != null) {
473 put.addColumn(FAMILY_NAME, COLUMN_CLIENT, id);
474 }
475
476 if (this.multipleUnevenColumnFamilies) {
477
478 put.addColumn(TINY_FAMILY_NAME, TINY_FAMILY_NAME, this.tinyValue);
479
480 if (this.bigValue == null) {
481 this.bigValue = new byte[current[i].length * 10];
482 ThreadLocalRandom.current().nextBytes(this.bigValue);
483 }
484
485 put.addColumn(BIG_FAMILY_NAME, BIG_FAMILY_NAME, this.bigValue);
486 }
487 mutator.mutate(put);
488
489 if (i % 1000 == 0) {
490
491 output.progress();
492 }
493 }
494
495 mutator.flush();
496 }
497 }
498
499 @Override
500 public int run(String[] args) throws Exception {
501 if (args.length < 3) {
502 System.out.println("Usage : " + Generator.class.getSimpleName() +
503 " <num mappers> <num nodes per map> <tmp output dir> [<width> <wrap multiplier>]");
504 System.out.println(" where <num nodes per map> should be a multiple of " +
505 " width*wrap multiplier, 25M by default");
506 return 0;
507 }
508
509 int numMappers = Integer.parseInt(args[0]);
510 long numNodes = Long.parseLong(args[1]);
511 Path tmpOutput = new Path(args[2]);
512 Integer width = (args.length < 4) ? null : Integer.parseInt(args[3]);
513 Integer wrapMuplitplier = (args.length < 5) ? null : Integer.parseInt(args[4]);
514 return run(numMappers, numNodes, tmpOutput, width, wrapMuplitplier);
515 }
516
517 protected void createSchema() throws IOException {
518 Configuration conf = getConf();
519 TableName tableName = getTableName(conf);
520 try (Connection conn = ConnectionFactory.createConnection(conf);
521 Admin admin = conn.getAdmin()) {
522 if (!admin.tableExists(tableName)) {
523 HTableDescriptor htd = new HTableDescriptor(getTableName(getConf()));
524 htd.addFamily(new HColumnDescriptor(FAMILY_NAME));
525
526 htd.addFamily(new HColumnDescriptor(BIG_FAMILY_NAME));
527 htd.addFamily(new HColumnDescriptor(TINY_FAMILY_NAME));
528 int numberOfServers = admin.getClusterStatus().getServers().size();
529 if (numberOfServers == 0) {
530 throw new IllegalStateException("No live regionservers");
531 }
532 int regionsPerServer = conf.getInt(HBaseTestingUtility.REGIONS_PER_SERVER_KEY,
533 HBaseTestingUtility.DEFAULT_REGIONS_PER_SERVER);
534 int totalNumberOfRegions = numberOfServers * regionsPerServer;
535 LOG.info("Number of live regionservers: " + numberOfServers + ", " +
536 "pre-splitting table into " + totalNumberOfRegions + " regions " +
537 "(default regions per server: " + regionsPerServer + ")");
538
539 byte[][] splits = new RegionSplitter.UniformSplit().split(totalNumberOfRegions);
540
541 admin.createTable(htd, splits);
542 }
543 } catch (MasterNotRunningException e) {
544 LOG.error("Master not running", e);
545 throw new IOException(e);
546 }
547 }
548
549 public int runRandomInputGenerator(int numMappers, long numNodes, Path tmpOutput,
550 Integer width, Integer wrapMuplitplier) throws Exception {
551 LOG.info("Running RandomInputGenerator with numMappers=" + numMappers
552 + ", numNodes=" + numNodes);
553 Job job = Job.getInstance(getConf());
554
555 job.setJobName("Random Input Generator");
556 job.setNumReduceTasks(0);
557 job.setJarByClass(getClass());
558
559 job.setInputFormatClass(GeneratorInputFormat.class);
560 job.setOutputKeyClass(BytesWritable.class);
561 job.setOutputValueClass(NullWritable.class);
562
563 setJobConf(job, numMappers, numNodes, width, wrapMuplitplier);
564
565 job.setMapperClass(Mapper.class);
566
567 FileOutputFormat.setOutputPath(job, tmpOutput);
568 job.setOutputFormatClass(SequenceFileOutputFormat.class);
569
570 boolean success = jobCompletion(job);
571
572 return success ? 0 : 1;
573 }
574
575 public int runGenerator(int numMappers, long numNodes, Path tmpOutput,
576 Integer width, Integer wrapMuplitplier) throws Exception {
577 LOG.info("Running Generator with numMappers=" + numMappers +", numNodes=" + numNodes);
578 createSchema();
579 Job job = Job.getInstance(getConf());
580
581 job.setJobName("Link Generator");
582 job.setNumReduceTasks(0);
583 job.setJarByClass(getClass());
584
585 FileInputFormat.setInputPaths(job, tmpOutput);
586 job.setInputFormatClass(OneFilePerMapperSFIF.class);
587 job.setOutputKeyClass(NullWritable.class);
588 job.setOutputValueClass(NullWritable.class);
589
590 setJobConf(job, numMappers, numNodes, width, wrapMuplitplier);
591
592 setMapperForGenerator(job);
593
594 job.setOutputFormatClass(NullOutputFormat.class);
595
596 job.getConfiguration().setBoolean("mapreduce.map.speculative", false);
597 String multipleUnevenColumnFamiliesStr = System.getProperty(MULTIPLE_UNEVEN_COLUMNFAMILIES_KEY);
598 if (multipleUnevenColumnFamiliesStr != null) {
599 job.getConfiguration().setBoolean(MULTIPLE_UNEVEN_COLUMNFAMILIES_KEY,
600 Boolean.parseBoolean(multipleUnevenColumnFamiliesStr));
601 }
602 TableMapReduceUtil.addDependencyJars(job);
603 TableMapReduceUtil.addDependencyJars(job.getConfiguration(), AbstractHBaseTool.class);
604 TableMapReduceUtil.initCredentials(job);
605
606 boolean success = jobCompletion(job);
607
608 return success ? 0 : 1;
609 }
610
611 protected boolean jobCompletion(Job job) throws IOException, InterruptedException,
612 ClassNotFoundException {
613 boolean success = job.waitForCompletion(true);
614 return success;
615 }
616
617 protected void setMapperForGenerator(Job job) {
618 job.setMapperClass(GeneratorMapper.class);
619 }
620
621 public int run(int numMappers, long numNodes, Path tmpOutput,
622 Integer width, Integer wrapMuplitplier) throws Exception {
623 int ret = runRandomInputGenerator(numMappers, numNodes, tmpOutput, width, wrapMuplitplier);
624 if (ret > 0) {
625 return ret;
626 }
627 return runGenerator(numMappers, numNodes, tmpOutput, width, wrapMuplitplier);
628 }
629 }
630
631
632
633
634
635
636
637 static class Search extends Configured implements Tool {
638 private static final Log LOG = LogFactory.getLog(Search.class);
639 protected Job job;
640
641 private static void printUsage(final String error) {
642 if (error != null && error.length() > 0) System.out.println("ERROR: " + error);
643 System.err.println("Usage: search <KEYS_DIR> [<MAPPERS_COUNT>]");
644 }
645
646 @Override
647 public int run(String[] args) throws Exception {
648 if (args.length < 1 || args.length > 2) {
649 printUsage(null);
650 return 1;
651 }
652 Path inputDir = new Path(args[0]);
653 int numMappers = 1;
654 if (args.length > 1) {
655 numMappers = Integer.parseInt(args[1]);
656 }
657 return run(inputDir, numMappers);
658 }
659
660
661
662
663 public static class WALSearcher extends WALPlayer {
664 public WALSearcher(Configuration conf) {
665 super(conf);
666 }
667
668
669
670
671 public static class WALMapperSearcher extends WALMapper {
672 private SortedSet<byte []> keysToFind;
673 private AtomicInteger rows = new AtomicInteger(0);
674
675 @Override
676 public void setup(Mapper<WALKey, WALEdit, ImmutableBytesWritable, Mutation>.Context context)
677 throws IOException {
678 super.setup(context);
679 try {
680 this.keysToFind = readKeysToSearch(context.getConfiguration());
681 LOG.info("Loaded keys to find: count=" + this.keysToFind.size());
682 } catch (InterruptedException e) {
683 throw new InterruptedIOException(e.toString());
684 }
685 }
686
687 @Override
688 protected boolean filter(Context context, Cell cell) {
689
690 byte [] row = new byte [cell.getRowLength()];
691 System.arraycopy(cell.getRowArray(), cell.getRowOffset(), row, 0, cell.getRowLength());
692 boolean b = this.keysToFind.contains(row);
693 if (b) {
694 String keyStr = Bytes.toStringBinary(row);
695 try {
696 LOG.info("Found cell=" + cell + " , walKey=" + context.getCurrentKey());
697 } catch (IOException|InterruptedException e) {
698 LOG.warn(e);
699 }
700 if (rows.addAndGet(1) < MISSING_ROWS_TO_LOG) {
701 context.getCounter(FOUND_GROUP_KEY, keyStr).increment(1);
702 }
703 context.getCounter(FOUND_GROUP_KEY, "CELL_WITH_MISSING_ROW").increment(1);
704 }
705 return b;
706 }
707 }
708
709
710 @Override
711 public Job createSubmittableJob(String[] args) throws IOException {
712 Job job = super.createSubmittableJob(args);
713
714 job.setJarByClass(WALMapperSearcher.class);
715 job.setMapperClass(WALMapperSearcher.class);
716 job.setOutputFormatClass(NullOutputFormat.class);
717 return job;
718 }
719 }
720
721 static final String FOUND_GROUP_KEY = "Found";
722 static final String SEARCHER_INPUTDIR_KEY = "searcher.keys.inputdir";
723
724 public int run(Path inputDir, int numMappers) throws Exception {
725 getConf().set(SEARCHER_INPUTDIR_KEY, inputDir.toString());
726 SortedSet<byte []> keys = readKeysToSearch(getConf());
727 if (keys.isEmpty()) throw new RuntimeException("No keys to find");
728 LOG.info("Count of keys to find: " + keys.size());
729 for(byte [] key: keys) LOG.info("Key: " + Bytes.toStringBinary(key));
730 Path hbaseDir = new Path(getConf().get(HConstants.HBASE_DIR));
731
732 Path walsDir = new Path(hbaseDir, HConstants.HREGION_LOGDIR_NAME);
733 Path oldWalsDir = new Path(hbaseDir, HConstants.HREGION_OLDLOGDIR_NAME);
734 LOG.info("Running Search with keys inputDir=" + inputDir +", numMappers=" + numMappers +
735 " against " + getConf().get(HConstants.HBASE_DIR));
736 int ret = ToolRunner.run(new WALSearcher(getConf()), new String [] {walsDir.toString(), ""});
737 if (ret != 0) return ret;
738 return ToolRunner.run(new WALSearcher(getConf()), new String [] {oldWalsDir.toString(), ""});
739 }
740
741 static SortedSet<byte []> readKeysToSearch(final Configuration conf)
742 throws IOException, InterruptedException {
743 Path keysInputDir = new Path(conf.get(SEARCHER_INPUTDIR_KEY));
744 FileSystem fs = FileSystem.get(conf);
745 SortedSet<byte []> result = new TreeSet<byte []>(Bytes.BYTES_COMPARATOR);
746 if (!fs.exists(keysInputDir)) {
747 throw new FileNotFoundException(keysInputDir.toString());
748 }
749 if (!fs.isDirectory(keysInputDir)) {
750 throw new UnsupportedOperationException("TODO");
751 } else {
752 RemoteIterator<LocatedFileStatus> iterator = fs.listFiles(keysInputDir, false);
753 while(iterator.hasNext()) {
754 LocatedFileStatus keyFileStatus = iterator.next();
755
756 if (keyFileStatus.getPath().getName().startsWith("_")) continue;
757 result.addAll(readFileToSearch(conf, fs, keyFileStatus));
758 }
759 }
760 return result;
761 }
762
763 private static SortedSet<byte[]> readFileToSearch(final Configuration conf,
764 final FileSystem fs, final LocatedFileStatus keyFileStatus) throws IOException,
765 InterruptedException {
766 SortedSet<byte []> result = new TreeSet<byte []>(Bytes.BYTES_COMPARATOR);
767
768
769 TaskAttemptContext context = new TaskAttemptContextImpl(conf, new TaskAttemptID());
770 try (SequenceFileAsBinaryInputFormat.SequenceFileAsBinaryRecordReader rr =
771 new SequenceFileAsBinaryInputFormat.SequenceFileAsBinaryRecordReader()) {
772 InputSplit is =
773 new FileSplit(keyFileStatus.getPath(), 0, keyFileStatus.getLen(), new String [] {});
774 rr.initialize(is, context);
775 while (rr.nextKeyValue()) {
776 rr.getCurrentKey();
777 BytesWritable bw = rr.getCurrentValue();
778 if (Verify.VerifyReducer.whichType(bw.getBytes()) == Verify.Counts.UNDEFINED) {
779 byte[] key = new byte[rr.getCurrentKey().getLength()];
780 System.arraycopy(rr.getCurrentKey().getBytes(), 0, key, 0, rr.getCurrentKey()
781 .getLength());
782 result.add(key);
783 }
784 }
785 }
786 return result;
787 }
788 }
789
790
791
792
793
794 static class Verify extends Configured implements Tool {
795
796 private static final Log LOG = LogFactory.getLog(Verify.class);
797 protected static final BytesWritable DEF = new BytesWritable(new byte[] { 0 });
798 protected static final BytesWritable DEF_LOST_FAMILIES = new BytesWritable(new byte[] { 1 });
799
800 protected Job job;
801
802 public static class VerifyMapper extends TableMapper<BytesWritable, BytesWritable> {
803 private BytesWritable row = new BytesWritable();
804 private BytesWritable ref = new BytesWritable();
805
806 private boolean multipleUnevenColumnFamilies;
807
808 @Override
809 protected void setup(
810 Mapper<ImmutableBytesWritable, Result, BytesWritable, BytesWritable>.Context context)
811 throws IOException, InterruptedException {
812 this.multipleUnevenColumnFamilies =
813 context.getConfiguration().getBoolean(Generator.MULTIPLE_UNEVEN_COLUMNFAMILIES_KEY,
814 false);
815 }
816
817 @Override
818 protected void map(ImmutableBytesWritable key, Result value, Context context)
819 throws IOException ,InterruptedException {
820 byte[] rowKey = key.get();
821 row.set(rowKey, 0, rowKey.length);
822 if (multipleUnevenColumnFamilies
823 && (!value.containsColumn(BIG_FAMILY_NAME, BIG_FAMILY_NAME) || !value.containsColumn(
824 TINY_FAMILY_NAME, TINY_FAMILY_NAME))) {
825 context.write(row, DEF_LOST_FAMILIES);
826 } else {
827 context.write(row, DEF);
828 }
829 byte[] prev = value.getValue(FAMILY_NAME, COLUMN_PREV);
830 if (prev != null && prev.length > 0) {
831 ref.set(prev, 0, prev.length);
832 context.write(ref, row);
833 } else {
834 LOG.warn(String.format("Prev is not set for: %s", Bytes.toStringBinary(rowKey)));
835 }
836 }
837 }
838
839
840
841
842
843 public static enum Counts {
844 UNREFERENCED, UNDEFINED, REFERENCED, CORRUPT, EXTRAREFERENCES, EXTRA_UNDEF_REFERENCES,
845 LOST_FAMILIES
846 }
847
848
849
850
851
852
853 public static class VerifyReducer extends
854 Reducer<BytesWritable, BytesWritable, BytesWritable, BytesWritable> {
855 private ArrayList<byte[]> refs = new ArrayList<byte[]>();
856 private final BytesWritable UNREF = new BytesWritable(addPrefixFlag(
857 Counts.UNREFERENCED.ordinal(), new byte[] {}));
858 private final BytesWritable LOSTFAM = new BytesWritable(addPrefixFlag(
859 Counts.LOST_FAMILIES.ordinal(), new byte[] {}));
860
861 private AtomicInteger rows = new AtomicInteger(0);
862 private Connection connection;
863
864 @Override
865 protected void setup(Reducer<BytesWritable, BytesWritable, BytesWritable, BytesWritable>.Context context)
866 throws IOException, InterruptedException {
867 super.setup(context);
868 this.connection = ConnectionFactory.createConnection(context.getConfiguration());
869 }
870
871 @Override
872 protected void cleanup(
873 Reducer<BytesWritable, BytesWritable, BytesWritable, BytesWritable>.Context context)
874 throws IOException, InterruptedException {
875 if (this.connection != null) {
876 this.connection.close();
877 }
878 super.cleanup(context);
879 }
880
881
882
883
884
885
886
887 public static byte[] addPrefixFlag(final int ordinal, final byte [] r) {
888 byte[] prefix = Bytes.toBytes((short)ordinal);
889 if (prefix.length != Bytes.SIZEOF_SHORT) {
890 throw new RuntimeException("Unexpected size: " + prefix.length);
891 }
892 byte[] result = new byte[prefix.length + r.length];
893 System.arraycopy(prefix, 0, result, 0, prefix.length);
894 System.arraycopy(r, 0, result, prefix.length, r.length);
895 return result;
896 }
897
898
899
900
901
902
903 public static Counts whichType(final byte [] bs) {
904 int ordinal = Bytes.toShort(bs, 0, Bytes.SIZEOF_SHORT);
905 return Counts.values()[ordinal];
906 }
907
908
909
910
911
912 public static byte[] getRowOnly(BytesWritable bw) {
913 byte[] bytes = new byte [bw.getLength() - Bytes.SIZEOF_SHORT];
914 System.arraycopy(bw.getBytes(), Bytes.SIZEOF_SHORT, bytes, 0, bytes.length);
915 return bytes;
916 }
917
918 @Override
919 public void reduce(BytesWritable key, Iterable<BytesWritable> values, Context context)
920 throws IOException, InterruptedException {
921 int defCount = 0;
922 boolean lostFamilies = false;
923 refs.clear();
924 for (BytesWritable type : values) {
925 if (type.getLength() == DEF.getLength()) {
926 defCount++;
927 if (type.getBytes()[0] == 1) {
928 lostFamilies = true;
929 }
930 } else {
931 byte[] bytes = new byte[type.getLength()];
932 System.arraycopy(type.getBytes(), 0, bytes, 0, type.getLength());
933 refs.add(bytes);
934 }
935 }
936
937
938 StringBuilder refsSb = null;
939 String keyString = Bytes.toStringBinary(key.getBytes(), 0, key.getLength());
940 if (defCount == 0 || refs.size() != 1) {
941 refsSb = dumpExtraInfoOnRefs(key, context, refs);
942 LOG.error("LinkedListError: key=" + keyString + ", reference(s)=" +
943 (refsSb != null? refsSb.toString(): ""));
944 }
945 if (lostFamilies) {
946 LOG.error("LinkedListError: key=" + keyString + ", lost big or tiny families");
947 context.getCounter(Counts.LOST_FAMILIES).increment(1);
948 context.write(key, LOSTFAM);
949 }
950
951 if (defCount == 0 && refs.size() > 0) {
952
953
954
955 for (int i = 0; i < refs.size(); i++) {
956 byte[] bs = refs.get(i);
957 int ordinal;
958 if (i <= 0) {
959 ordinal = Counts.UNDEFINED.ordinal();
960 context.write(key, new BytesWritable(addPrefixFlag(ordinal, bs)));
961 context.getCounter(Counts.UNDEFINED).increment(1);
962 } else {
963 ordinal = Counts.EXTRA_UNDEF_REFERENCES.ordinal();
964 context.write(key, new BytesWritable(addPrefixFlag(ordinal, bs)));
965 }
966 }
967 if (rows.addAndGet(1) < MISSING_ROWS_TO_LOG) {
968
969
970
971
972 context.getCounter("undef", keyString).increment(1);
973 }
974 } else if (defCount > 0 && refs.size() == 0) {
975
976 context.write(key, UNREF);
977 context.getCounter(Counts.UNREFERENCED).increment(1);
978 if (rows.addAndGet(1) < MISSING_ROWS_TO_LOG) {
979 context.getCounter("unref", keyString).increment(1);
980 }
981 } else {
982 if (refs.size() > 1) {
983
984 for (int i = 1; i < refs.size(); i++) {
985 context.write(key,
986 new BytesWritable(addPrefixFlag(Counts.EXTRAREFERENCES.ordinal(), refs.get(i))));
987 }
988 context.getCounter(Counts.EXTRAREFERENCES).increment(refs.size() - 1);
989 }
990
991 context.getCounter(Counts.REFERENCED).increment(1);
992 }
993 }
994
995
996
997
998
999
1000 private StringBuilder dumpExtraInfoOnRefs(final BytesWritable key, final Context context,
1001 final List<byte []> refs)
1002 throws IOException {
1003 StringBuilder refsSb = null;
1004 if (refs.isEmpty()) return refsSb;
1005 refsSb = new StringBuilder();
1006 String comma = "";
1007
1008
1009
1010 TableName tn = getTableName(context.getConfiguration());
1011 try (Table t = this.connection.getTable(tn)) {
1012 for (byte [] ref : refs) {
1013 Result r = t.get(new Get(ref));
1014 List<Cell> cells = r.listCells();
1015 String ts = (cells != null && !cells.isEmpty())?
1016 new java.util.Date(cells.get(0).getTimestamp()).toString(): "";
1017 byte [] b = r.getValue(FAMILY_NAME, COLUMN_CLIENT);
1018 String jobStr = (b != null && b.length > 0)? Bytes.toString(b): "";
1019 b = r.getValue(FAMILY_NAME, COLUMN_COUNT);
1020 long count = (b != null && b.length > 0)? Bytes.toLong(b): -1;
1021 b = r.getValue(FAMILY_NAME, COLUMN_PREV);
1022 String refRegionLocation = "";
1023 String keyRegionLocation = "";
1024 if (b != null && b.length > 0) {
1025 try (RegionLocator rl = this.connection.getRegionLocator(tn)) {
1026 HRegionLocation hrl = rl.getRegionLocation(b);
1027 if (hrl != null) refRegionLocation = hrl.toString();
1028
1029 hrl = rl.getRegionLocation(key.getBytes());
1030 if (hrl != null) keyRegionLocation = hrl.toString();
1031 }
1032 }
1033 LOG.error("Extras on ref without a def, ref=" + Bytes.toStringBinary(ref) +
1034 ", refPrevEqualsKey=" +
1035 (Bytes.compareTo(key.getBytes(), 0, key.getLength(), b, 0, b.length) == 0) +
1036 ", key=" + Bytes.toStringBinary(key.getBytes(), 0, key.getLength()) +
1037 ", ref row date=" + ts + ", jobStr=" + jobStr +
1038 ", ref row count=" + count +
1039 ", ref row regionLocation=" + refRegionLocation +
1040 ", key row regionLocation=" + keyRegionLocation);
1041 refsSb.append(comma);
1042 comma = ",";
1043 refsSb.append(Bytes.toStringBinary(ref));
1044 }
1045 }
1046 return refsSb;
1047 }
1048 }
1049
1050 @Override
1051 public int run(String[] args) throws Exception {
1052 if (args.length != 2) {
1053 System.out.println("Usage : " + Verify.class.getSimpleName()
1054 + " <output dir> <num reducers>");
1055 return 0;
1056 }
1057
1058 String outputDir = args[0];
1059 int numReducers = Integer.parseInt(args[1]);
1060
1061 return run(outputDir, numReducers);
1062 }
1063
1064 public int run(String outputDir, int numReducers) throws Exception {
1065 return run(new Path(outputDir), numReducers);
1066 }
1067
1068 public int run(Path outputDir, int numReducers) throws Exception {
1069 LOG.info("Running Verify with outputDir=" + outputDir +", numReducers=" + numReducers);
1070
1071 job = Job.getInstance(getConf());
1072
1073 job.setJobName("Link Verifier");
1074 job.setNumReduceTasks(numReducers);
1075 job.setJarByClass(getClass());
1076
1077 setJobScannerConf(job);
1078
1079 Scan scan = new Scan();
1080 scan.addColumn(FAMILY_NAME, COLUMN_PREV);
1081 scan.setCaching(10000);
1082 scan.setCacheBlocks(false);
1083 if (isMultiUnevenColumnFamilies()) {
1084 scan.addColumn(BIG_FAMILY_NAME, BIG_FAMILY_NAME);
1085 scan.addColumn(TINY_FAMILY_NAME, TINY_FAMILY_NAME);
1086 job.getConfiguration().setBoolean(Generator.MULTIPLE_UNEVEN_COLUMNFAMILIES_KEY, true);
1087 }
1088
1089 TableMapReduceUtil.initTableMapperJob(getTableName(getConf()).getName(), scan,
1090 VerifyMapper.class, BytesWritable.class, BytesWritable.class, job);
1091 TableMapReduceUtil.addDependencyJars(job.getConfiguration(), AbstractHBaseTool.class);
1092
1093 job.getConfiguration().setBoolean("mapreduce.map.speculative", false);
1094
1095 job.setReducerClass(VerifyReducer.class);
1096 job.setOutputFormatClass(SequenceFileAsBinaryOutputFormat.class);
1097 job.setOutputKeyClass(BytesWritable.class);
1098 job.setOutputValueClass(BytesWritable.class);
1099 TextOutputFormat.setOutputPath(job, outputDir);
1100
1101 boolean success = job.waitForCompletion(true);
1102
1103 if (success) {
1104 Counters counters = job.getCounters();
1105 if (null == counters) {
1106 LOG.warn("Counters were null, cannot verify Job completion");
1107
1108 return 0;
1109 }
1110
1111
1112 if (verifyUnexpectedValues(counters)) {
1113
1114 return 0;
1115 }
1116 }
1117
1118
1119 return 1;
1120 }
1121
1122 public boolean verify(long expectedReferenced) throws Exception {
1123 if (job == null) {
1124 throw new IllegalStateException("You should call run() first");
1125 }
1126
1127 Counters counters = job.getCounters();
1128
1129
1130 boolean success = verifyExpectedValues(expectedReferenced, counters);
1131
1132 if (!verifyUnexpectedValues(counters)) {
1133
1134 success = false;
1135 }
1136
1137 if (!success) {
1138 handleFailure(counters);
1139 }
1140 return success;
1141 }
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152 protected boolean verifyExpectedValues(long expectedReferenced, Counters counters) {
1153 final Counter referenced = counters.findCounter(Counts.REFERENCED);
1154 final Counter unreferenced = counters.findCounter(Counts.UNREFERENCED);
1155 boolean success = true;
1156
1157 if (expectedReferenced != referenced.getValue()) {
1158 LOG.error("Expected referenced count does not match with actual referenced count. " +
1159 "expected referenced=" + expectedReferenced + " ,actual=" + referenced.getValue());
1160 success = false;
1161 }
1162
1163 if (unreferenced.getValue() > 0) {
1164 final Counter multiref = counters.findCounter(Counts.EXTRAREFERENCES);
1165 boolean couldBeMultiRef = (multiref.getValue() == unreferenced.getValue());
1166 LOG.error("Unreferenced nodes were not expected. Unreferenced count=" + unreferenced.getValue()
1167 + (couldBeMultiRef ? "; could be due to duplicate random numbers" : ""));
1168 success = false;
1169 }
1170
1171 return success;
1172 }
1173
1174
1175
1176
1177
1178
1179
1180
1181 protected boolean verifyUnexpectedValues(Counters counters) {
1182 final Counter undefined = counters.findCounter(Counts.UNDEFINED);
1183 final Counter lostfamilies = counters.findCounter(Counts.LOST_FAMILIES);
1184 boolean success = true;
1185
1186 if (undefined.getValue() > 0) {
1187 LOG.error("Found an undefined node. Undefined count=" + undefined.getValue());
1188 success = false;
1189 }
1190
1191 if (lostfamilies.getValue() > 0) {
1192 LOG.error("Found nodes which lost big or tiny families, count=" + lostfamilies.getValue());
1193 success = false;
1194 }
1195
1196 return success;
1197 }
1198
1199 protected void handleFailure(Counters counters) throws IOException {
1200 Configuration conf = job.getConfiguration();
1201 TableName tableName = getTableName(conf);
1202 try (Connection conn = ConnectionFactory.createConnection(conf)) {
1203 try (RegionLocator rl = conn.getRegionLocator(tableName)) {
1204 CounterGroup g = counters.getGroup("undef");
1205 Iterator<Counter> it = g.iterator();
1206 while (it.hasNext()) {
1207 String keyString = it.next().getName();
1208 byte[] key = Bytes.toBytes(keyString);
1209 HRegionLocation loc = rl.getRegionLocation(key, true);
1210 LOG.error("undefined row " + keyString + ", " + loc);
1211 }
1212 g = counters.getGroup("unref");
1213 it = g.iterator();
1214 while (it.hasNext()) {
1215 String keyString = it.next().getName();
1216 byte[] key = Bytes.toBytes(keyString);
1217 HRegionLocation loc = rl.getRegionLocation(key, true);
1218 LOG.error("unreferred row " + keyString + ", " + loc);
1219 }
1220 }
1221 }
1222 }
1223 }
1224
1225
1226
1227
1228
1229 static class Loop extends Configured implements Tool {
1230
1231 private static final Log LOG = LogFactory.getLog(Loop.class);
1232
1233 IntegrationTestBigLinkedList it;
1234
1235 protected void runGenerator(int numMappers, long numNodes,
1236 String outputDir, Integer width, Integer wrapMuplitplier) throws Exception {
1237 Path outputPath = new Path(outputDir);
1238 UUID uuid = UUID.randomUUID();
1239 Path generatorOutput = new Path(outputPath, uuid.toString());
1240
1241 Generator generator = new Generator();
1242 generator.setConf(getConf());
1243 int retCode = generator.run(numMappers, numNodes, generatorOutput, width, wrapMuplitplier);
1244 if (retCode > 0) {
1245 throw new RuntimeException("Generator failed with return code: " + retCode);
1246 }
1247 }
1248
1249 protected void runVerify(String outputDir,
1250 int numReducers, long expectedNumNodes) throws Exception {
1251 Path outputPath = new Path(outputDir);
1252 UUID uuid = UUID.randomUUID();
1253 Path iterationOutput = new Path(outputPath, uuid.toString());
1254
1255 Verify verify = new Verify();
1256 verify.setConf(getConf());
1257 int retCode = verify.run(iterationOutput, numReducers);
1258 if (retCode > 0) {
1259 throw new RuntimeException("Verify.run failed with return code: " + retCode);
1260 }
1261
1262 if (!verify.verify(expectedNumNodes)) {
1263 throw new RuntimeException("Verify.verify failed");
1264 }
1265
1266 LOG.info("Verify finished with succees. Total nodes=" + expectedNumNodes);
1267 }
1268
1269 @Override
1270 public int run(String[] args) throws Exception {
1271 if (args.length < 5) {
1272 System.err.println("Usage: Loop <num iterations> <num mappers> <num nodes per mapper> <output dir> <num reducers> [<width> <wrap multiplier>]");
1273 return 1;
1274 }
1275 LOG.info("Running Loop with args:" + Arrays.deepToString(args));
1276
1277 int numIterations = Integer.parseInt(args[0]);
1278 int numMappers = Integer.parseInt(args[1]);
1279 long numNodes = Long.parseLong(args[2]);
1280 String outputDir = args[3];
1281 int numReducers = Integer.parseInt(args[4]);
1282 Integer width = (args.length < 6) ? null : Integer.parseInt(args[5]);
1283 Integer wrapMuplitplier = (args.length < 7) ? null : Integer.parseInt(args[6]);
1284
1285 long expectedNumNodes = 0;
1286
1287 if (numIterations < 0) {
1288 numIterations = Integer.MAX_VALUE;
1289 }
1290
1291 for (int i = 0; i < numIterations; i++) {
1292 LOG.info("Starting iteration = " + i);
1293 runGenerator(numMappers, numNodes, outputDir, width, wrapMuplitplier);
1294 expectedNumNodes += numMappers * numNodes;
1295
1296 runVerify(outputDir, numReducers, expectedNumNodes);
1297 }
1298
1299 return 0;
1300 }
1301 }
1302
1303
1304
1305
1306 private static class Print extends Configured implements Tool {
1307 @Override
1308 public int run(String[] args) throws Exception {
1309 Options options = new Options();
1310 options.addOption("s", "start", true, "start key");
1311 options.addOption("e", "end", true, "end key");
1312 options.addOption("l", "limit", true, "number to print");
1313
1314 GnuParser parser = new GnuParser();
1315 CommandLine cmd = null;
1316 try {
1317 cmd = parser.parse(options, args);
1318 if (cmd.getArgs().length != 0) {
1319 throw new ParseException("Command takes no arguments");
1320 }
1321 } catch (ParseException e) {
1322 System.err.println("Failed to parse command line " + e.getMessage());
1323 System.err.println();
1324 HelpFormatter formatter = new HelpFormatter();
1325 formatter.printHelp(getClass().getSimpleName(), options);
1326 System.exit(-1);
1327 }
1328
1329 Table table = new HTable(getConf(), getTableName(getConf()));
1330
1331 Scan scan = new Scan();
1332 scan.setBatch(10000);
1333
1334 if (cmd.hasOption("s"))
1335 scan.setStartRow(Bytes.toBytesBinary(cmd.getOptionValue("s")));
1336
1337 if (cmd.hasOption("e"))
1338 scan.setStopRow(Bytes.toBytesBinary(cmd.getOptionValue("e")));
1339
1340 int limit = 0;
1341 if (cmd.hasOption("l"))
1342 limit = Integer.parseInt(cmd.getOptionValue("l"));
1343 else
1344 limit = 100;
1345
1346 ResultScanner scanner = table.getScanner(scan);
1347
1348 CINode node = new CINode();
1349 Result result = scanner.next();
1350 int count = 0;
1351 while (result != null && count++ < limit) {
1352 node = getCINode(result, node);
1353 System.out.printf("%s:%s:%012d:%s\n", Bytes.toStringBinary(node.key),
1354 Bytes.toStringBinary(node.prev), node.count, node.client);
1355 result = scanner.next();
1356 }
1357 scanner.close();
1358 table.close();
1359
1360 return 0;
1361 }
1362 }
1363
1364
1365
1366
1367 private static class Delete extends Configured implements Tool {
1368 @Override
1369 public int run(String[] args) throws Exception {
1370 if (args.length != 1) {
1371 System.out.println("Usage : " + Delete.class.getSimpleName() + " <node to delete>");
1372 return 0;
1373 }
1374 byte[] val = Bytes.toBytesBinary(args[0]);
1375
1376 org.apache.hadoop.hbase.client.Delete delete
1377 = new org.apache.hadoop.hbase.client.Delete(val);
1378
1379 Table table = new HTable(getConf(), getTableName(getConf()));
1380 table.delete(delete);
1381 table.close();
1382
1383 System.out.println("Delete successful");
1384 return 0;
1385 }
1386 }
1387
1388
1389
1390
1391
1392 private static class Walker extends Configured implements Tool {
1393 @Override
1394 public int run(String[] args) throws IOException {
1395 Options options = new Options();
1396 options.addOption("n", "num", true, "number of queries");
1397 options.addOption("s", "start", true, "key to start at, binary string");
1398 options.addOption("l", "logevery", true, "log every N queries");
1399
1400 GnuParser parser = new GnuParser();
1401 CommandLine cmd = null;
1402 try {
1403 cmd = parser.parse(options, args);
1404 if (cmd.getArgs().length != 0) {
1405 throw new ParseException("Command takes no arguments");
1406 }
1407 } catch (ParseException e) {
1408 System.err.println("Failed to parse command line " + e.getMessage());
1409 System.err.println();
1410 HelpFormatter formatter = new HelpFormatter();
1411 formatter.printHelp(getClass().getSimpleName(), options);
1412 System.exit(-1);
1413 }
1414
1415 long maxQueries = Long.MAX_VALUE;
1416 if (cmd.hasOption('n')) {
1417 maxQueries = Long.parseLong(cmd.getOptionValue("n"));
1418 }
1419 Random rand = new SecureRandom();
1420 boolean isSpecificStart = cmd.hasOption('s');
1421 byte[] startKey = isSpecificStart ? Bytes.toBytesBinary(cmd.getOptionValue('s')) : null;
1422 int logEvery = cmd.hasOption('l') ? Integer.parseInt(cmd.getOptionValue('l')) : 1;
1423
1424 Table table = new HTable(getConf(), getTableName(getConf()));
1425 long numQueries = 0;
1426
1427
1428
1429 while (numQueries < maxQueries && (numQueries == 0 || !isSpecificStart)) {
1430 if (!isSpecificStart) {
1431 startKey = new byte[ROWKEY_LENGTH];
1432 rand.nextBytes(startKey);
1433 }
1434 CINode node = findStartNode(table, startKey);
1435 if (node == null && isSpecificStart) {
1436 System.err.printf("Start node not found: %s \n", Bytes.toStringBinary(startKey));
1437 }
1438 numQueries++;
1439 while (node != null && node.prev.length != NO_KEY.length && numQueries < maxQueries) {
1440 byte[] prev = node.prev;
1441 long t1 = System.currentTimeMillis();
1442 node = getNode(prev, table, node);
1443 long t2 = System.currentTimeMillis();
1444 if (numQueries % logEvery == 0) {
1445 System.out.printf("CQ %d: %d %s \n", numQueries, t2 - t1, Bytes.toStringBinary(prev));
1446 }
1447 numQueries++;
1448 if (node == null) {
1449 System.err.printf("UNDEFINED NODE %s \n", Bytes.toStringBinary(prev));
1450 } else if (node.prev.length == NO_KEY.length) {
1451 System.err.printf("TERMINATING NODE %s \n", Bytes.toStringBinary(node.key));
1452 }
1453 }
1454 }
1455
1456 table.close();
1457 return 0;
1458 }
1459
1460 private static CINode findStartNode(Table table, byte[] startKey) throws IOException {
1461 Scan scan = new Scan();
1462 scan.setStartRow(startKey);
1463 scan.setBatch(1);
1464 scan.addColumn(FAMILY_NAME, COLUMN_PREV);
1465
1466 long t1 = System.currentTimeMillis();
1467 ResultScanner scanner = table.getScanner(scan);
1468 Result result = scanner.next();
1469 long t2 = System.currentTimeMillis();
1470 scanner.close();
1471
1472 if ( result != null) {
1473 CINode node = getCINode(result, new CINode());
1474 System.out.printf("FSR %d %s\n", t2 - t1, Bytes.toStringBinary(node.key));
1475 return node;
1476 }
1477
1478 System.out.println("FSR " + (t2 - t1));
1479
1480 return null;
1481 }
1482
1483 private CINode getNode(byte[] row, Table table, CINode node) throws IOException {
1484 Get get = new Get(row);
1485 get.addColumn(FAMILY_NAME, COLUMN_PREV);
1486 Result result = table.get(get);
1487 return getCINode(result, node);
1488 }
1489 }
1490
1491 private static class Clean extends Configured implements Tool {
1492 @Override public int run(String[] args) throws Exception {
1493 if (args.length < 1) {
1494 System.err.println("Usage: Clean <output dir>");
1495 return -1;
1496 }
1497
1498 Path p = new Path(args[0]);
1499 Configuration conf = getConf();
1500 TableName tableName = getTableName(conf);
1501 try (FileSystem fs = HFileSystem.get(conf);
1502 Connection conn = ConnectionFactory.createConnection(conf);
1503 Admin admin = conn.getAdmin()) {
1504 if (admin.tableExists(tableName)) {
1505 admin.disableTable(tableName);
1506 admin.deleteTable(tableName);
1507 }
1508
1509 if (fs.exists(p)) {
1510 fs.delete(p, true);
1511 }
1512 }
1513
1514 return 0;
1515 }
1516 }
1517
1518 static TableName getTableName(Configuration conf) {
1519 return TableName.valueOf(conf.get(TABLE_NAME_KEY, DEFAULT_TABLE_NAME));
1520 }
1521
1522 private static CINode getCINode(Result result, CINode node) {
1523 node.key = Bytes.copy(result.getRow());
1524 if (result.containsColumn(FAMILY_NAME, COLUMN_PREV)) {
1525 node.prev = Bytes.copy(result.getValue(FAMILY_NAME, COLUMN_PREV));
1526 } else {
1527 node.prev = NO_KEY;
1528 }
1529 if (result.containsColumn(FAMILY_NAME, COLUMN_COUNT)) {
1530 node.count = Bytes.toLong(result.getValue(FAMILY_NAME, COLUMN_COUNT));
1531 } else {
1532 node.count = -1;
1533 }
1534 if (result.containsColumn(FAMILY_NAME, COLUMN_CLIENT)) {
1535 node.client = Bytes.toString(result.getValue(FAMILY_NAME, COLUMN_CLIENT));
1536 } else {
1537 node.client = "";
1538 }
1539 return node;
1540 }
1541
1542 protected IntegrationTestingUtility util;
1543
1544 @Override
1545 public void setUpCluster() throws Exception {
1546 util = getTestingUtil(getConf());
1547 boolean isDistributed = util.isDistributedCluster();
1548 util.initializeCluster(isDistributed ? 1 : this.NUM_SLAVES_BASE);
1549 if (!isDistributed) {
1550 util.startMiniMapReduceCluster();
1551 }
1552 this.setConf(util.getConfiguration());
1553 }
1554
1555 @Override
1556 public void cleanUpCluster() throws Exception {
1557 super.cleanUpCluster();
1558 if (util.isDistributedCluster()) {
1559 util.shutdownMiniMapReduceCluster();
1560 }
1561 }
1562
1563 private static boolean isMultiUnevenColumnFamilies() {
1564 return Boolean.TRUE.toString().equalsIgnoreCase(
1565 System.getProperty(Generator.MULTIPLE_UNEVEN_COLUMNFAMILIES_KEY));
1566 }
1567
1568 @Test
1569 public void testContinuousIngest() throws IOException, Exception {
1570
1571 Configuration conf = getTestingUtil(getConf()).getConfiguration();
1572 if (isMultiUnevenColumnFamilies()) {
1573
1574 conf.set(FlushPolicyFactory.HBASE_FLUSH_POLICY_KEY, FlushLargeStoresPolicy.class.getName());
1575 }
1576 int ret =
1577 ToolRunner.run(conf, new Loop(), new String[] { "1", "1", "2000000",
1578 util.getDataTestDirOnTestFS("IntegrationTestBigLinkedList").toString(), "1" });
1579 org.junit.Assert.assertEquals(0, ret);
1580 }
1581
1582 private void usage() {
1583 System.err.println("Usage: " + this.getClass().getSimpleName() + " COMMAND [COMMAND options]");
1584 printCommands();
1585 }
1586
1587 private void printCommands() {
1588 System.err.println("Commands:");
1589 System.err.println(" generator Map only job that generates data.");
1590 System.err.println(" verify A map reduce job that looks for holes. Check return code and");
1591 System.err.println(" look at the counts after running. See REFERENCED and");
1592 System.err.println(" UNREFERENCED are ok. Any UNDEFINED counts are bad. Do not run");
1593 System.err.println(" with the Generator.");
1594 System.err.println(" walker " +
1595 "Standalone program that starts following a linked list & emits timing info.");
1596 System.err.println(" print Standalone program that prints nodes in the linked list.");
1597 System.err.println(" delete Standalone program that deletes a·single node.");
1598 System.err.println(" loop Program to Loop through Generator and Verify steps");
1599 System.err.println(" clean Program to clean all left over detritus.");
1600 System.err.println(" search Search for missing keys.");
1601 System.err.flush();
1602 }
1603
1604 @Override
1605 protected void processOptions(CommandLine cmd) {
1606 super.processOptions(cmd);
1607 String[] args = cmd.getArgs();
1608
1609 if (args.length < 1) {
1610 printUsage(this.getClass().getSimpleName() +
1611 " <general options> COMMAND [<COMMAND options>]", "General options:", "");
1612 printCommands();
1613
1614 throw new RuntimeException("Incorrect Number of args.");
1615 }
1616 toRun = args[0];
1617 otherArgs = Arrays.copyOfRange(args, 1, args.length);
1618 }
1619
1620 @Override
1621 public int runTestFromCommandLine() throws Exception {
1622 Tool tool = null;
1623 if (toRun.equalsIgnoreCase("Generator")) {
1624 tool = new Generator();
1625 } else if (toRun.equalsIgnoreCase("Verify")) {
1626 tool = new Verify();
1627 } else if (toRun.equalsIgnoreCase("Loop")) {
1628 Loop loop = new Loop();
1629 loop.it = this;
1630 tool = loop;
1631 } else if (toRun.equalsIgnoreCase("Walker")) {
1632 tool = new Walker();
1633 } else if (toRun.equalsIgnoreCase("Print")) {
1634 tool = new Print();
1635 } else if (toRun.equalsIgnoreCase("Delete")) {
1636 tool = new Delete();
1637 } else if (toRun.equalsIgnoreCase("Clean")) {
1638 tool = new Clean();
1639 } else if (toRun.equalsIgnoreCase("Search")) {
1640 tool = new Search();
1641 } else {
1642 usage();
1643 throw new RuntimeException("Unknown arg");
1644 }
1645
1646 return ToolRunner.run(getConf(), tool, otherArgs);
1647 }
1648
1649 @Override
1650 public TableName getTablename() {
1651 Configuration c = getConf();
1652 return TableName.valueOf(c.get(TABLE_NAME_KEY, DEFAULT_TABLE_NAME));
1653 }
1654
1655 @Override
1656 protected Set<String> getColumnFamilies() {
1657 if (isMultiUnevenColumnFamilies()) {
1658 return Sets.newHashSet(Bytes.toString(FAMILY_NAME), Bytes.toString(BIG_FAMILY_NAME),
1659 Bytes.toString(TINY_FAMILY_NAME));
1660 } else {
1661 return Sets.newHashSet(Bytes.toString(FAMILY_NAME));
1662 }
1663 }
1664
1665 private static void setJobConf(Job job, int numMappers, long numNodes,
1666 Integer width, Integer wrapMultiplier) {
1667 job.getConfiguration().setInt(GENERATOR_NUM_MAPPERS_KEY, numMappers);
1668 job.getConfiguration().setLong(GENERATOR_NUM_ROWS_PER_MAP_KEY, numNodes);
1669 if (width != null) {
1670 job.getConfiguration().setInt(GENERATOR_WIDTH_KEY, width);
1671 }
1672 if (wrapMultiplier != null) {
1673 job.getConfiguration().setInt(GENERATOR_WRAP_KEY, wrapMultiplier);
1674 }
1675 }
1676
1677 public static void setJobScannerConf(Job job) {
1678
1679 job.getConfiguration().setBoolean(ScannerCallable.LOG_SCANNER_ACTIVITY, true);
1680 job.getConfiguration().setInt(TableRecordReaderImpl.LOG_PER_ROW_COUNT, 100000);
1681 }
1682
1683 public static void main(String[] args) throws Exception {
1684 Configuration conf = HBaseConfiguration.create();
1685 IntegrationTestingUtility.setUseDistributedCluster(conf);
1686 int ret = ToolRunner.run(conf, new IntegrationTestBigLinkedList(), args);
1687 System.exit(ret);
1688 }
1689 }