1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.rest;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.apache.hadoop.conf.Configuration;
24 import org.apache.hadoop.conf.Configured;
25 import org.apache.hadoop.fs.FSDataInputStream;
26 import org.apache.hadoop.fs.FileStatus;
27 import org.apache.hadoop.fs.FileSystem;
28 import org.apache.hadoop.fs.Path;
29 import org.apache.hadoop.hbase.HBaseConfiguration;
30 import org.apache.hadoop.hbase.HColumnDescriptor;
31 import org.apache.hadoop.hbase.HConstants;
32 import org.apache.hadoop.hbase.HTableDescriptor;
33 import org.apache.hadoop.hbase.KeyValue;
34 import org.apache.hadoop.hbase.TableName;
35 import org.apache.hadoop.hbase.Tag;
36 import org.apache.hadoop.hbase.client.BufferedMutator;
37 import org.apache.hadoop.hbase.client.Connection;
38 import org.apache.hadoop.hbase.client.ConnectionFactory;
39 import org.apache.hadoop.hbase.client.Durability;
40 import org.apache.hadoop.hbase.client.Get;
41 import org.apache.hadoop.hbase.client.Put;
42 import org.apache.hadoop.hbase.client.Result;
43 import org.apache.hadoop.hbase.client.ResultScanner;
44 import org.apache.hadoop.hbase.client.Scan;
45 import org.apache.hadoop.hbase.client.Table;
46 import org.apache.hadoop.hbase.filter.BinaryComparator;
47 import org.apache.hadoop.hbase.filter.CompareFilter;
48 import org.apache.hadoop.hbase.filter.Filter;
49 import org.apache.hadoop.hbase.filter.PageFilter;
50 import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
51 import org.apache.hadoop.hbase.filter.WhileMatchFilter;
52 import org.apache.hadoop.hbase.io.compress.Compression;
53 import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
54 import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
55 import org.apache.hadoop.hbase.rest.client.Client;
56 import org.apache.hadoop.hbase.rest.client.Cluster;
57 import org.apache.hadoop.hbase.rest.client.RemoteAdmin;
58 import org.apache.hadoop.hbase.util.Bytes;
59 import org.apache.hadoop.hbase.util.Hash;
60 import org.apache.hadoop.hbase.util.MurmurHash;
61 import org.apache.hadoop.hbase.util.Pair;
62 import org.apache.hadoop.io.LongWritable;
63 import org.apache.hadoop.io.NullWritable;
64 import org.apache.hadoop.io.Text;
65 import org.apache.hadoop.io.Writable;
66 import org.apache.hadoop.mapreduce.InputSplit;
67 import org.apache.hadoop.mapreduce.Job;
68 import org.apache.hadoop.mapreduce.JobContext;
69 import org.apache.hadoop.mapreduce.Mapper;
70 import org.apache.hadoop.mapreduce.RecordReader;
71 import org.apache.hadoop.mapreduce.TaskAttemptContext;
72 import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
73 import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
74 import org.apache.hadoop.mapreduce.lib.reduce.LongSumReducer;
75 import org.apache.hadoop.util.LineReader;
76 import org.apache.hadoop.util.Tool;
77 import org.apache.hadoop.util.ToolRunner;
78
79 import java.io.DataInput;
80 import java.io.DataOutput;
81 import java.io.IOException;
82 import java.io.PrintStream;
83 import java.lang.reflect.Constructor;
84 import java.text.SimpleDateFormat;
85 import java.util.ArrayList;
86 import java.util.Arrays;
87 import java.util.Date;
88 import java.util.List;
89 import java.util.Map;
90 import java.util.Random;
91 import java.util.TreeMap;
92 import java.util.regex.Matcher;
93 import java.util.regex.Pattern;
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111 public class PerformanceEvaluation extends Configured implements Tool {
112 protected static final Log LOG = LogFactory.getLog(PerformanceEvaluation.class.getName());
113
114 private static final int DEFAULT_ROW_PREFIX_LENGTH = 16;
115 private static final int ROW_LENGTH = 1000;
116 private static final int TAG_LENGTH = 256;
117 private static final int ONE_GB = 1024 * 1024 * 1000;
118 private static final int ROWS_PER_GB = ONE_GB / ROW_LENGTH;
119
120 public static final TableName TABLE_NAME = TableName.valueOf("TestTable");
121 public static final byte [] FAMILY_NAME = Bytes.toBytes("info");
122 public static final byte [] QUALIFIER_NAME = Bytes.toBytes("data");
123 private TableName tableName = TABLE_NAME;
124
125 protected HTableDescriptor TABLE_DESCRIPTOR;
126 protected Map<String, CmdDescriptor> commands = new TreeMap<String, CmdDescriptor>();
127 protected static Cluster cluster = new Cluster();
128
129 volatile Configuration conf;
130 private boolean nomapred = false;
131 private int N = 1;
132 private int R = ROWS_PER_GB;
133 private Compression.Algorithm compression = Compression.Algorithm.NONE;
134 private DataBlockEncoding blockEncoding = DataBlockEncoding.NONE;
135 private boolean flushCommits = true;
136 private boolean writeToWAL = true;
137 private boolean inMemoryCF = false;
138 private int presplitRegions = 0;
139 private boolean useTags = false;
140 private int noOfTags = 1;
141 private Connection connection;
142
143 private static final Path PERF_EVAL_DIR = new Path("performance_evaluation");
144
145
146
147 public static final Pattern LINE_PATTERN =
148 Pattern.compile("tableName=(\\w+),\\s+" +
149 "startRow=(\\d+),\\s+" +
150 "perClientRunRows=(\\d+),\\s+" +
151 "totalRows=(\\d+),\\s+" +
152 "clients=(\\d+),\\s+" +
153 "flushCommits=(\\w+),\\s+" +
154 "writeToWAL=(\\w+),\\s+" +
155 "useTags=(\\w+),\\s+" +
156 "noOfTags=(\\d+)");
157
158
159
160
161
162 protected static enum Counter {
163
164 ELAPSED_TIME,
165
166 ROWS}
167
168
169
170
171
172 public PerformanceEvaluation(final Configuration c) {
173 this.conf = c;
174
175 addCommandDescriptor(RandomReadTest.class, "randomRead",
176 "Run random read test");
177 addCommandDescriptor(RandomSeekScanTest.class, "randomSeekScan",
178 "Run random seek and scan 100 test");
179 addCommandDescriptor(RandomScanWithRange10Test.class, "scanRange10",
180 "Run random seek scan with both start and stop row (max 10 rows)");
181 addCommandDescriptor(RandomScanWithRange100Test.class, "scanRange100",
182 "Run random seek scan with both start and stop row (max 100 rows)");
183 addCommandDescriptor(RandomScanWithRange1000Test.class, "scanRange1000",
184 "Run random seek scan with both start and stop row (max 1000 rows)");
185 addCommandDescriptor(RandomScanWithRange10000Test.class, "scanRange10000",
186 "Run random seek scan with both start and stop row (max 10000 rows)");
187 addCommandDescriptor(RandomWriteTest.class, "randomWrite",
188 "Run random write test");
189 addCommandDescriptor(SequentialReadTest.class, "sequentialRead",
190 "Run sequential read test");
191 addCommandDescriptor(SequentialWriteTest.class, "sequentialWrite",
192 "Run sequential write test");
193 addCommandDescriptor(ScanTest.class, "scan",
194 "Run scan test (read every row)");
195 addCommandDescriptor(FilteredScanTest.class, "filterScan",
196 "Run scan test using a filter to find a specific row based " +
197 "on it's value (make sure to use --rows=20)");
198 }
199
200 protected void addCommandDescriptor(Class<? extends Test> cmdClass,
201 String name, String description) {
202 CmdDescriptor cmdDescriptor =
203 new CmdDescriptor(cmdClass, name, description);
204 commands.put(name, cmdDescriptor);
205 }
206
207
208
209
210 interface Status {
211
212
213
214
215
216 void setStatus(final String msg) throws IOException;
217 }
218
219
220
221
222
223
224
225 public static class PeInputSplit extends InputSplit implements Writable {
226 private TableName tableName = TABLE_NAME;
227 private int startRow = 0;
228 private int rows = 0;
229 private int totalRows = 0;
230 private int clients = 0;
231 private boolean flushCommits = false;
232 private boolean writeToWAL = true;
233 private boolean useTags = false;
234 private int noOfTags = 0;
235
236 public PeInputSplit() {
237 }
238
239 public PeInputSplit(TableName tableName, int startRow, int rows, int totalRows, int clients,
240 boolean flushCommits, boolean writeToWAL, boolean useTags, int noOfTags) {
241 this.tableName = tableName;
242 this.startRow = startRow;
243 this.rows = rows;
244 this.totalRows = totalRows;
245 this.clients = clients;
246 this.flushCommits = flushCommits;
247 this.writeToWAL = writeToWAL;
248 this.useTags = useTags;
249 this.noOfTags = noOfTags;
250 }
251
252 @Override
253 public void readFields(DataInput in) throws IOException {
254 int tableNameLen = in.readInt();
255 byte[] name = new byte[tableNameLen];
256 in.readFully(name);
257 this.tableName = TableName.valueOf(name);
258 this.startRow = in.readInt();
259 this.rows = in.readInt();
260 this.totalRows = in.readInt();
261 this.clients = in.readInt();
262 this.flushCommits = in.readBoolean();
263 this.writeToWAL = in.readBoolean();
264 this.useTags = in.readBoolean();
265 this.noOfTags = in.readInt();
266 }
267
268 @Override
269 public void write(DataOutput out) throws IOException {
270 byte[] name = this.tableName.toBytes();
271 out.writeInt(name.length);
272 out.write(name);
273 out.writeInt(startRow);
274 out.writeInt(rows);
275 out.writeInt(totalRows);
276 out.writeInt(clients);
277 out.writeBoolean(flushCommits);
278 out.writeBoolean(writeToWAL);
279 out.writeBoolean(useTags);
280 out.writeInt(noOfTags);
281 }
282
283 @Override
284 public long getLength() throws IOException, InterruptedException {
285 return 0;
286 }
287
288 @Override
289 public String[] getLocations() throws IOException, InterruptedException {
290 return new String[0];
291 }
292
293 public int getStartRow() {
294 return startRow;
295 }
296
297 public TableName getTableName() {
298 return tableName;
299 }
300
301 public int getRows() {
302 return rows;
303 }
304
305 public int getTotalRows() {
306 return totalRows;
307 }
308
309 public int getClients() {
310 return clients;
311 }
312
313 public boolean isFlushCommits() {
314 return flushCommits;
315 }
316
317 public boolean isWriteToWAL() {
318 return writeToWAL;
319 }
320
321 public boolean isUseTags() {
322 return useTags;
323 }
324
325 public int getNoOfTags() {
326 return noOfTags;
327 }
328 }
329
330
331
332
333
334 public static class PeInputFormat extends FileInputFormat<NullWritable, PeInputSplit> {
335
336 @Override
337 public List<InputSplit> getSplits(JobContext job) throws IOException {
338
339 List<InputSplit> splitList = new ArrayList<InputSplit>();
340
341 for (FileStatus file: listStatus(job)) {
342 if (file.isDirectory()) {
343 continue;
344 }
345 Path path = file.getPath();
346 FileSystem fs = path.getFileSystem(job.getConfiguration());
347 FSDataInputStream fileIn = fs.open(path);
348 LineReader in = new LineReader(fileIn, job.getConfiguration());
349 int lineLen = 0;
350 while(true) {
351 Text lineText = new Text();
352 lineLen = in.readLine(lineText);
353 if(lineLen <= 0) {
354 break;
355 }
356 Matcher m = LINE_PATTERN.matcher(lineText.toString());
357 if((m != null) && m.matches()) {
358 TableName tableName = TableName.valueOf(m.group(1));
359 int startRow = Integer.parseInt(m.group(2));
360 int rows = Integer.parseInt(m.group(3));
361 int totalRows = Integer.parseInt(m.group(4));
362 int clients = Integer.parseInt(m.group(5));
363 boolean flushCommits = Boolean.parseBoolean(m.group(6));
364 boolean writeToWAL = Boolean.parseBoolean(m.group(7));
365 boolean useTags = Boolean.parseBoolean(m.group(8));
366 int noOfTags = Integer.parseInt(m.group(9));
367
368 LOG.debug("tableName=" + tableName +
369 " split["+ splitList.size() + "] " +
370 " startRow=" + startRow +
371 " rows=" + rows +
372 " totalRows=" + totalRows +
373 " clients=" + clients +
374 " flushCommits=" + flushCommits +
375 " writeToWAL=" + writeToWAL +
376 " useTags=" + useTags +
377 " noOfTags=" + noOfTags);
378
379 PeInputSplit newSplit =
380 new PeInputSplit(tableName, startRow, rows, totalRows, clients,
381 flushCommits, writeToWAL, useTags, noOfTags);
382 splitList.add(newSplit);
383 }
384 }
385 in.close();
386 }
387
388 LOG.info("Total # of splits: " + splitList.size());
389 return splitList;
390 }
391
392 @Override
393 public RecordReader<NullWritable, PeInputSplit> createRecordReader(InputSplit split,
394 TaskAttemptContext context) {
395 return new PeRecordReader();
396 }
397
398 public static class PeRecordReader extends RecordReader<NullWritable, PeInputSplit> {
399 private boolean readOver = false;
400 private PeInputSplit split = null;
401 private NullWritable key = null;
402 private PeInputSplit value = null;
403
404 @Override
405 public void initialize(InputSplit split, TaskAttemptContext context)
406 throws IOException, InterruptedException {
407 this.readOver = false;
408 this.split = (PeInputSplit)split;
409 }
410
411 @Override
412 public boolean nextKeyValue() throws IOException, InterruptedException {
413 if(readOver) {
414 return false;
415 }
416
417 key = NullWritable.get();
418 value = (PeInputSplit)split;
419
420 readOver = true;
421 return true;
422 }
423
424 @Override
425 public NullWritable getCurrentKey() throws IOException, InterruptedException {
426 return key;
427 }
428
429 @Override
430 public PeInputSplit getCurrentValue() throws IOException, InterruptedException {
431 return value;
432 }
433
434 @Override
435 public float getProgress() throws IOException, InterruptedException {
436 if(readOver) {
437 return 1.0f;
438 } else {
439 return 0.0f;
440 }
441 }
442
443 @Override
444 public void close() throws IOException {
445
446 }
447 }
448 }
449
450
451
452
453 public static class EvaluationMapTask
454 extends Mapper<NullWritable, PeInputSplit, LongWritable, LongWritable> {
455
456
457 public final static String CMD_KEY = "EvaluationMapTask.command";
458
459 public static final String PE_KEY = "EvaluationMapTask.performanceEvalImpl";
460
461 private Class<? extends Test> cmd;
462 private PerformanceEvaluation pe;
463
464 @Override
465 protected void setup(Context context) throws IOException, InterruptedException {
466 this.cmd = forName(context.getConfiguration().get(CMD_KEY), Test.class);
467
468
469
470 Class<? extends PerformanceEvaluation> peClass =
471 forName(context.getConfiguration().get(PE_KEY), PerformanceEvaluation.class);
472 try {
473 this.pe = peClass.getConstructor(Configuration.class)
474 .newInstance(context.getConfiguration());
475 } catch (Exception e) {
476 throw new IllegalStateException("Could not instantiate PE instance", e);
477 }
478 }
479
480 private <Type> Class<? extends Type> forName(String className, Class<Type> type) {
481 Class<? extends Type> clazz = null;
482 try {
483 clazz = Class.forName(className).asSubclass(type);
484 } catch (ClassNotFoundException e) {
485 throw new IllegalStateException("Could not find class for name: " + className, e);
486 }
487 return clazz;
488 }
489
490 @Override
491 protected void map(NullWritable key, PeInputSplit value, final Context context)
492 throws IOException, InterruptedException {
493 Status status = new Status() {
494 @Override
495 public void setStatus(String msg) {
496 context.setStatus(msg);
497 }
498 };
499
500
501 pe.tableName = value.getTableName();
502 long elapsedTime = this.pe.runOneClient(this.cmd, value.getStartRow(),
503 value.getRows(), value.getTotalRows(),
504 value.isFlushCommits(), value.isWriteToWAL(),
505 value.isUseTags(), value.getNoOfTags(),
506 ConnectionFactory.createConnection(context.getConfiguration()), status);
507
508
509 context.getCounter(Counter.ELAPSED_TIME).increment(elapsedTime);
510 context.getCounter(Counter.ROWS).increment(value.rows);
511 context.write(new LongWritable(value.startRow), new LongWritable(elapsedTime));
512 context.progress();
513 }
514 }
515
516
517
518
519
520
521
522 private boolean checkTable(RemoteAdmin admin) throws IOException {
523 HTableDescriptor tableDescriptor = getTableDescriptor();
524 if (this.presplitRegions > 0) {
525
526 if (admin.isTableAvailable(tableDescriptor.getTableName().getName())) {
527 admin.deleteTable(tableDescriptor.getTableName().getName());
528 }
529
530 byte[][] splits = getSplits();
531 for (int i=0; i < splits.length; i++) {
532 LOG.debug(" split " + i + ": " + Bytes.toStringBinary(splits[i]));
533 }
534 admin.createTable(tableDescriptor);
535 LOG.info ("Table created with " + this.presplitRegions + " splits");
536 } else {
537 boolean tableExists = admin.isTableAvailable(tableDescriptor.getTableName().getName());
538 if (!tableExists) {
539 admin.createTable(tableDescriptor);
540 LOG.info("Table " + tableDescriptor + " created");
541 }
542 }
543 boolean tableExists = admin.isTableAvailable(tableDescriptor.getTableName().getName());
544 return tableExists;
545 }
546
547 protected HTableDescriptor getTableDescriptor() {
548 if (TABLE_DESCRIPTOR == null) {
549 TABLE_DESCRIPTOR = new HTableDescriptor(tableName);
550 HColumnDescriptor family = new HColumnDescriptor(FAMILY_NAME);
551 family.setDataBlockEncoding(blockEncoding);
552 family.setCompressionType(compression);
553 if (inMemoryCF) {
554 family.setInMemory(true);
555 }
556 TABLE_DESCRIPTOR.addFamily(family);
557 }
558 return TABLE_DESCRIPTOR;
559 }
560
561
562
563
564
565
566 protected byte[][] getSplits() {
567 if (this.presplitRegions == 0)
568 return new byte [0][];
569
570 int numSplitPoints = presplitRegions - 1;
571 byte[][] splits = new byte[numSplitPoints][];
572 int jump = this.R / this.presplitRegions;
573 for (int i=0; i < numSplitPoints; i++) {
574 int rowkey = jump * (1 + i);
575 splits[i] = format(rowkey);
576 }
577 return splits;
578 }
579
580
581
582
583
584
585
586 private void runNIsMoreThanOne(final Class<? extends Test> cmd)
587 throws IOException, InterruptedException, ClassNotFoundException {
588 RemoteAdmin remoteAdmin = new RemoteAdmin(new Client(cluster), getConf());
589 checkTable(remoteAdmin);
590 if (nomapred) {
591 doMultipleClients(cmd);
592 } else {
593 doMapReduce(cmd);
594 }
595 }
596
597
598
599
600
601
602 private void doMultipleClients(final Class<? extends Test> cmd) throws IOException {
603 final List<Thread> threads = new ArrayList<Thread>(this.N);
604 final long[] timings = new long[this.N];
605 final int perClientRows = R/N;
606 final TableName tableName = this.tableName;
607 final DataBlockEncoding encoding = this.blockEncoding;
608 final boolean flushCommits = this.flushCommits;
609 final Compression.Algorithm compression = this.compression;
610 final boolean writeToWal = this.writeToWAL;
611 final int preSplitRegions = this.presplitRegions;
612 final boolean useTags = this.useTags;
613 final int numTags = this.noOfTags;
614 final Connection connection = ConnectionFactory.createConnection(getConf());
615 for (int i = 0; i < this.N; i++) {
616 final int index = i;
617 Thread t = new Thread ("TestClient-" + i) {
618 @Override
619 public void run() {
620 super.run();
621 PerformanceEvaluation pe = new PerformanceEvaluation(getConf());
622 pe.tableName = tableName;
623 pe.blockEncoding = encoding;
624 pe.flushCommits = flushCommits;
625 pe.compression = compression;
626 pe.writeToWAL = writeToWal;
627 pe.presplitRegions = preSplitRegions;
628 pe.N = N;
629 pe.connection = connection;
630 pe.useTags = useTags;
631 pe.noOfTags = numTags;
632 try {
633 long elapsedTime = pe.runOneClient(cmd, index * perClientRows,
634 perClientRows, R,
635 flushCommits, writeToWAL, useTags, noOfTags, connection, new Status() {
636 @Override
637 public void setStatus(final String msg) throws IOException {
638 LOG.info("client-" + getName() + " " + msg);
639 }
640 });
641 timings[index] = elapsedTime;
642 LOG.info("Finished " + getName() + " in " + elapsedTime +
643 "ms writing " + perClientRows + " rows");
644 } catch (IOException e) {
645 throw new RuntimeException(e);
646 }
647 }
648 };
649 threads.add(t);
650 }
651 for (Thread t: threads) {
652 t.start();
653 }
654 for (Thread t: threads) {
655 while(t.isAlive()) {
656 try {
657 t.join();
658 } catch (InterruptedException e) {
659 LOG.debug("Interrupted, continuing" + e.toString());
660 }
661 }
662 }
663 final String test = cmd.getSimpleName();
664 LOG.info("[" + test + "] Summary of timings (ms): "
665 + Arrays.toString(timings));
666 Arrays.sort(timings);
667 long total = 0;
668 for (int i = 0; i < this.N; i++) {
669 total += timings[i];
670 }
671 LOG.info("[" + test + "]"
672 + "\tMin: " + timings[0] + "ms"
673 + "\tMax: " + timings[this.N - 1] + "ms"
674 + "\tAvg: " + (total / this.N) + "ms");
675 }
676
677
678
679
680
681
682
683
684 private void doMapReduce(final Class<? extends Test> cmd) throws IOException,
685 InterruptedException, ClassNotFoundException {
686 Configuration conf = getConf();
687 Path inputDir = writeInputFile(conf);
688 conf.set(EvaluationMapTask.CMD_KEY, cmd.getName());
689 conf.set(EvaluationMapTask.PE_KEY, getClass().getName());
690 Job job = Job.getInstance(conf);
691 job.setJarByClass(PerformanceEvaluation.class);
692 job.setJobName("HBase Performance Evaluation");
693
694 job.setInputFormatClass(PeInputFormat.class);
695 PeInputFormat.setInputPaths(job, inputDir);
696
697 job.setOutputKeyClass(LongWritable.class);
698 job.setOutputValueClass(LongWritable.class);
699
700 job.setMapperClass(EvaluationMapTask.class);
701 job.setReducerClass(LongSumReducer.class);
702 job.setNumReduceTasks(1);
703
704 job.setOutputFormatClass(TextOutputFormat.class);
705 TextOutputFormat.setOutputPath(job, new Path(inputDir.getParent(), "outputs"));
706 TableMapReduceUtil.addDependencyJars(job);
707 TableMapReduceUtil.initCredentials(job);
708 job.waitForCompletion(true);
709 }
710
711
712
713
714
715
716
717 private Path writeInputFile(final Configuration c) throws IOException {
718 SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
719 Path jobdir = new Path(PERF_EVAL_DIR, formatter.format(new Date()));
720 Path inputDir = new Path(jobdir, "inputs");
721
722 FileSystem fs = FileSystem.get(c);
723 fs.mkdirs(inputDir);
724 Path inputFile = new Path(inputDir, "input.txt");
725 PrintStream out = new PrintStream(fs.create(inputFile));
726
727 Map<Integer, String> m = new TreeMap<Integer, String>();
728 Hash h = MurmurHash.getInstance();
729 int perClientRows = (this.R / this.N);
730 try {
731 for (int i = 0; i < 10; i++) {
732 for (int j = 0; j < N; j++) {
733 String s = "tableName=" + this.tableName +
734 ", startRow=" + ((j * perClientRows) + (i * (perClientRows/10))) +
735 ", perClientRunRows=" + (perClientRows / 10) +
736 ", totalRows=" + this.R +
737 ", clients=" + this.N +
738 ", flushCommits=" + this.flushCommits +
739 ", writeToWAL=" + this.writeToWAL +
740 ", useTags=" + this.useTags +
741 ", noOfTags=" + this.noOfTags;
742 int hash = h.hash(Bytes.toBytes(s));
743 m.put(hash, s);
744 }
745 }
746 for (Map.Entry<Integer, String> e: m.entrySet()) {
747 out.println(e.getValue());
748 }
749 } finally {
750 out.close();
751 }
752 return inputDir;
753 }
754
755
756
757
758 static class CmdDescriptor {
759 private Class<? extends Test> cmdClass;
760 private String name;
761 private String description;
762
763 CmdDescriptor(Class<? extends Test> cmdClass, String name, String description) {
764 this.cmdClass = cmdClass;
765 this.name = name;
766 this.description = description;
767 }
768
769 public Class<? extends Test> getCmdClass() {
770 return cmdClass;
771 }
772
773 public String getName() {
774 return name;
775 }
776
777 public String getDescription() {
778 return description;
779 }
780 }
781
782
783
784
785
786 static class TestOptions {
787 private int startRow;
788 private int perClientRunRows;
789 private int totalRows;
790 private int numClientThreads;
791 private TableName tableName;
792 private boolean flushCommits;
793 private boolean writeToWAL = true;
794 private boolean useTags = false;
795 private int noOfTags = 0;
796 private Connection connection;
797
798 TestOptions() {
799 }
800
801 TestOptions(int startRow, int perClientRunRows, int totalRows, int numClientThreads,
802 TableName tableName, boolean flushCommits, boolean writeToWAL, boolean useTags,
803 int noOfTags, Connection connection) {
804 this.startRow = startRow;
805 this.perClientRunRows = perClientRunRows;
806 this.totalRows = totalRows;
807 this.numClientThreads = numClientThreads;
808 this.tableName = tableName;
809 this.flushCommits = flushCommits;
810 this.writeToWAL = writeToWAL;
811 this.useTags = useTags;
812 this.noOfTags = noOfTags;
813 this.connection = connection;
814 }
815
816 public int getStartRow() {
817 return startRow;
818 }
819
820 public int getPerClientRunRows() {
821 return perClientRunRows;
822 }
823
824 public int getTotalRows() {
825 return totalRows;
826 }
827
828 public int getNumClientThreads() {
829 return numClientThreads;
830 }
831
832 public TableName getTableName() {
833 return tableName;
834 }
835
836 public boolean isFlushCommits() {
837 return flushCommits;
838 }
839
840 public boolean isWriteToWAL() {
841 return writeToWAL;
842 }
843
844 public Connection getConnection() {
845 return connection;
846 }
847
848 public boolean isUseTags() {
849 return this.useTags;
850 }
851
852 public int getNumTags() {
853 return this.noOfTags;
854 }
855 }
856
857
858
859
860
861 static abstract class Test {
862
863
864 private static final Random randomSeed =
865 new Random(System.currentTimeMillis());
866 private static long nextRandomSeed() {
867 return randomSeed.nextLong();
868 }
869 protected final Random rand = new Random(nextRandomSeed());
870
871 protected final int startRow;
872 protected final int perClientRunRows;
873 protected final int totalRows;
874 private final Status status;
875 protected TableName tableName;
876 protected volatile Configuration conf;
877 protected boolean writeToWAL;
878 protected boolean useTags;
879 protected int noOfTags;
880 protected Connection connection;
881
882
883
884
885
886 Test(final Configuration conf, final TestOptions options, final Status status) {
887 super();
888 this.startRow = options.getStartRow();
889 this.perClientRunRows = options.getPerClientRunRows();
890 this.totalRows = options.getTotalRows();
891 this.status = status;
892 this.tableName = options.getTableName();
893 this.conf = conf;
894 this.writeToWAL = options.isWriteToWAL();
895 this.useTags = options.isUseTags();
896 this.noOfTags = options.getNumTags();
897 this.connection = options.getConnection();
898 }
899
900 protected String generateStatus(final int sr, final int i, final int lr) {
901 return sr + "/" + i + "/" + lr;
902 }
903
904 protected int getReportingPeriod() {
905 int period = this.perClientRunRows / 10;
906 return period == 0? this.perClientRunRows: period;
907 }
908
909 abstract void testTakedown() throws IOException;
910
911
912
913
914
915 long test() throws IOException {
916 testSetup();
917 LOG.info("Timed test starting in thread " + Thread.currentThread().getName());
918 final long startTime = System.nanoTime();
919 try {
920 testTimed();
921 } finally {
922 testTakedown();
923 }
924 return (System.nanoTime() - startTime) / 1000000;
925 }
926
927 abstract void testSetup() throws IOException;
928
929
930
931
932 void testTimed() throws IOException {
933 int lastRow = this.startRow + this.perClientRunRows;
934
935 for (int i = this.startRow; i < lastRow; i++) {
936 testRow(i);
937 if (status != null && i > 0 && (i % getReportingPeriod()) == 0) {
938 status.setStatus(generateStatus(this.startRow, i, lastRow));
939 }
940 }
941 }
942
943
944
945
946
947 abstract void testRow(final int i) throws IOException;
948 }
949
950 static abstract class TableTest extends Test {
951 protected Table table;
952
953 public TableTest(Configuration conf, TestOptions options, Status status) {
954 super(conf, options, status);
955 }
956
957 @Override
958 void testSetup() throws IOException {
959 this.table = connection.getTable(tableName);
960 }
961
962 @Override
963 void testTakedown() throws IOException {
964 table.close();
965 }
966 }
967
968 static abstract class BufferedMutatorTest extends Test {
969 protected BufferedMutator mutator;
970 protected boolean flushCommits;
971
972 public BufferedMutatorTest(Configuration conf, TestOptions options, Status status) {
973 super(conf, options, status);
974 this.flushCommits = options.isFlushCommits();
975 }
976
977 @Override
978 void testSetup() throws IOException {
979 this.mutator = connection.getBufferedMutator(tableName);
980 }
981
982 @Override
983 void testTakedown() throws IOException {
984 if (flushCommits) {
985 this.mutator.flush();
986 }
987 mutator.close();
988 }
989 }
990
991 static class RandomSeekScanTest extends TableTest {
992 RandomSeekScanTest(Configuration conf, TestOptions options, Status status) {
993 super(conf, options, status);
994 }
995
996 @Override
997 void testRow(final int i) throws IOException {
998 Scan scan = new Scan(getRandomRow(this.rand, this.totalRows));
999 scan.addColumn(FAMILY_NAME, QUALIFIER_NAME);
1000 scan.setFilter(new WhileMatchFilter(new PageFilter(120)));
1001 ResultScanner s = this.table.getScanner(scan);
1002 s.close();
1003 }
1004
1005 @Override
1006 protected int getReportingPeriod() {
1007 int period = this.perClientRunRows / 100;
1008 return period == 0? this.perClientRunRows: period;
1009 }
1010
1011 }
1012
1013 @SuppressWarnings("unused")
1014 static abstract class RandomScanWithRangeTest extends TableTest {
1015 RandomScanWithRangeTest(Configuration conf, TestOptions options, Status status) {
1016 super(conf, options, status);
1017 }
1018
1019 @Override
1020 void testRow(final int i) throws IOException {
1021 Pair<byte[], byte[]> startAndStopRow = getStartAndStopRow();
1022 Scan scan = new Scan(startAndStopRow.getFirst(), startAndStopRow.getSecond());
1023 scan.addColumn(FAMILY_NAME, QUALIFIER_NAME);
1024 ResultScanner s = this.table.getScanner(scan);
1025 int count = 0;
1026 for (Result rr = null; (rr = s.next()) != null;) {
1027 count++;
1028 }
1029
1030 if (i % 100 == 0) {
1031 LOG.info(String.format("Scan for key range %s - %s returned %s rows",
1032 Bytes.toString(startAndStopRow.getFirst()),
1033 Bytes.toString(startAndStopRow.getSecond()), count));
1034 }
1035
1036 s.close();
1037 }
1038
1039 protected abstract Pair<byte[],byte[]> getStartAndStopRow();
1040
1041 protected Pair<byte[], byte[]> generateStartAndStopRows(int maxRange) {
1042 int start = this.rand.nextInt(Integer.MAX_VALUE) % totalRows;
1043 int stop = start + maxRange;
1044 return new Pair<byte[],byte[]>(format(start), format(stop));
1045 }
1046
1047 @Override
1048 protected int getReportingPeriod() {
1049 int period = this.perClientRunRows / 100;
1050 return period == 0? this.perClientRunRows: period;
1051 }
1052 }
1053
1054 static class RandomScanWithRange10Test extends RandomScanWithRangeTest {
1055 RandomScanWithRange10Test(Configuration conf, TestOptions options, Status status) {
1056 super(conf, options, status);
1057 }
1058
1059 @Override
1060 protected Pair<byte[], byte[]> getStartAndStopRow() {
1061 return generateStartAndStopRows(10);
1062 }
1063 }
1064
1065 static class RandomScanWithRange100Test extends RandomScanWithRangeTest {
1066 RandomScanWithRange100Test(Configuration conf, TestOptions options, Status status) {
1067 super(conf, options, status);
1068 }
1069
1070 @Override
1071 protected Pair<byte[], byte[]> getStartAndStopRow() {
1072 return generateStartAndStopRows(100);
1073 }
1074 }
1075
1076 static class RandomScanWithRange1000Test extends RandomScanWithRangeTest {
1077 RandomScanWithRange1000Test(Configuration conf, TestOptions options, Status status) {
1078 super(conf, options, status);
1079 }
1080
1081 @Override
1082 protected Pair<byte[], byte[]> getStartAndStopRow() {
1083 return generateStartAndStopRows(1000);
1084 }
1085 }
1086
1087 static class RandomScanWithRange10000Test extends RandomScanWithRangeTest {
1088 RandomScanWithRange10000Test(Configuration conf, TestOptions options, Status status) {
1089 super(conf, options, status);
1090 }
1091
1092 @Override
1093 protected Pair<byte[], byte[]> getStartAndStopRow() {
1094 return generateStartAndStopRows(10000);
1095 }
1096 }
1097
1098 static class RandomReadTest extends TableTest {
1099 RandomReadTest(Configuration conf, TestOptions options, Status status) {
1100 super(conf, options, status);
1101 }
1102
1103 @Override
1104 void testRow(final int i) throws IOException {
1105 Get get = new Get(getRandomRow(this.rand, this.totalRows));
1106 get.addColumn(FAMILY_NAME, QUALIFIER_NAME);
1107 this.table.get(get);
1108 }
1109
1110 @Override
1111 protected int getReportingPeriod() {
1112 int period = this.perClientRunRows / 100;
1113 return period == 0? this.perClientRunRows: period;
1114 }
1115
1116 }
1117
1118 static class RandomWriteTest extends BufferedMutatorTest {
1119 RandomWriteTest(Configuration conf, TestOptions options, Status status) {
1120 super(conf, options, status);
1121 }
1122
1123 @Override
1124 void testRow(final int i) throws IOException {
1125 byte[] row = getRandomRow(this.rand, this.totalRows);
1126 Put put = new Put(row);
1127 byte[] value = generateData(this.rand, ROW_LENGTH);
1128 if (useTags) {
1129 byte[] tag = generateData(this.rand, TAG_LENGTH);
1130 Tag[] tags = new Tag[noOfTags];
1131 for (int n = 0; n < noOfTags; n++) {
1132 Tag t = new Tag((byte) n, tag);
1133 tags[n] = t;
1134 }
1135 KeyValue kv = new KeyValue(row, FAMILY_NAME, QUALIFIER_NAME, HConstants.LATEST_TIMESTAMP,
1136 value, tags);
1137 put.add(kv);
1138 } else {
1139 put.add(FAMILY_NAME, QUALIFIER_NAME, value);
1140 }
1141 put.setDurability(writeToWAL ? Durability.SYNC_WAL : Durability.SKIP_WAL);
1142 mutator.mutate(put);
1143 }
1144 }
1145
1146 static class ScanTest extends TableTest {
1147 private ResultScanner testScanner;
1148
1149 ScanTest(Configuration conf, TestOptions options, Status status) {
1150 super(conf, options, status);
1151 }
1152
1153 @Override
1154 void testTakedown() throws IOException {
1155 if (this.testScanner != null) {
1156 this.testScanner.close();
1157 }
1158 super.testTakedown();
1159 }
1160
1161
1162 @Override
1163 void testRow(final int i) throws IOException {
1164 if (this.testScanner == null) {
1165 Scan scan = new Scan(format(this.startRow));
1166 scan.addColumn(FAMILY_NAME, QUALIFIER_NAME);
1167 this.testScanner = table.getScanner(scan);
1168 }
1169 testScanner.next();
1170 }
1171
1172 }
1173
1174 static class SequentialReadTest extends TableTest {
1175 SequentialReadTest(Configuration conf, TestOptions options, Status status) {
1176 super(conf, options, status);
1177 }
1178
1179 @Override
1180 void testRow(final int i) throws IOException {
1181 Get get = new Get(format(i));
1182 get.addColumn(FAMILY_NAME, QUALIFIER_NAME);
1183 table.get(get);
1184 }
1185
1186 }
1187
1188 static class SequentialWriteTest extends BufferedMutatorTest {
1189
1190 SequentialWriteTest(Configuration conf, TestOptions options, Status status) {
1191 super(conf, options, status);
1192 }
1193
1194 @Override
1195 void testRow(final int i) throws IOException {
1196 byte[] row = format(i);
1197 Put put = new Put(row);
1198 byte[] value = generateData(this.rand, ROW_LENGTH);
1199 if (useTags) {
1200 byte[] tag = generateData(this.rand, TAG_LENGTH);
1201 Tag[] tags = new Tag[noOfTags];
1202 for (int n = 0; n < noOfTags; n++) {
1203 Tag t = new Tag((byte) n, tag);
1204 tags[n] = t;
1205 }
1206 KeyValue kv = new KeyValue(row, FAMILY_NAME, QUALIFIER_NAME, HConstants.LATEST_TIMESTAMP,
1207 value, tags);
1208 put.add(kv);
1209 } else {
1210 put.add(FAMILY_NAME, QUALIFIER_NAME, value);
1211 }
1212 put.setDurability(writeToWAL ? Durability.SYNC_WAL : Durability.SKIP_WAL);
1213 mutator.mutate(put);
1214 }
1215 }
1216
1217 static class FilteredScanTest extends TableTest {
1218 protected static final Log LOG = LogFactory.getLog(FilteredScanTest.class.getName());
1219
1220 FilteredScanTest(Configuration conf, TestOptions options, Status status) {
1221 super(conf, options, status);
1222 }
1223
1224 @Override
1225 void testRow(int i) throws IOException {
1226 byte[] value = generateValue(this.rand);
1227 Scan scan = constructScan(value);
1228 ResultScanner scanner = null;
1229 try {
1230 scanner = this.table.getScanner(scan);
1231 while (scanner.next() != null) {
1232 }
1233 } finally {
1234 if (scanner != null) scanner.close();
1235 }
1236 }
1237
1238 protected Scan constructScan(byte[] valuePrefix) throws IOException {
1239 Filter filter = new SingleColumnValueFilter(
1240 FAMILY_NAME, QUALIFIER_NAME, CompareFilter.CompareOp.EQUAL,
1241 new BinaryComparator(valuePrefix)
1242 );
1243 Scan scan = new Scan();
1244 scan.addColumn(FAMILY_NAME, QUALIFIER_NAME);
1245 scan.setFilter(filter);
1246 return scan;
1247 }
1248 }
1249
1250
1251
1252
1253
1254
1255
1256 public static byte [] format(final int number) {
1257 byte [] b = new byte[DEFAULT_ROW_PREFIX_LENGTH + 10];
1258 int d = Math.abs(number);
1259 for (int i = b.length - 1; i >= 0; i--) {
1260 b[i] = (byte)((d % 10) + '0');
1261 d /= 10;
1262 }
1263 return b;
1264 }
1265
1266 public static byte[] generateData(final Random r, int length) {
1267 byte [] b = new byte [length];
1268 int i = 0;
1269
1270 for(i = 0; i < (length-8); i += 8) {
1271 b[i] = (byte) (65 + r.nextInt(26));
1272 b[i+1] = b[i];
1273 b[i+2] = b[i];
1274 b[i+3] = b[i];
1275 b[i+4] = b[i];
1276 b[i+5] = b[i];
1277 b[i+6] = b[i];
1278 b[i+7] = b[i];
1279 }
1280
1281 byte a = (byte) (65 + r.nextInt(26));
1282 for(; i < length; i++) {
1283 b[i] = a;
1284 }
1285 return b;
1286 }
1287
1288 public static byte[] generateValue(final Random r) {
1289 byte [] b = new byte [ROW_LENGTH];
1290 r.nextBytes(b);
1291 return b;
1292 }
1293
1294 static byte [] getRandomRow(final Random random, final int totalRows) {
1295 return format(random.nextInt(Integer.MAX_VALUE) % totalRows);
1296 }
1297
1298 long runOneClient(final Class<? extends Test> cmd, final int startRow,
1299 final int perClientRunRows, final int totalRows,
1300 boolean flushCommits, boolean writeToWAL, boolean useTags, int noOfTags,
1301 Connection connection, final Status status)
1302 throws IOException {
1303 status.setStatus("Start " + cmd + " at offset " + startRow + " for " +
1304 perClientRunRows + " rows");
1305 long totalElapsedTime = 0;
1306
1307 TestOptions options = new TestOptions(startRow, perClientRunRows,
1308 totalRows, N, tableName, flushCommits, writeToWAL, useTags, noOfTags, connection);
1309 final Test t;
1310 try {
1311 Constructor<? extends Test> constructor = cmd.getDeclaredConstructor(
1312 Configuration.class, TestOptions.class, Status.class);
1313 t = constructor.newInstance(this.conf, options, status);
1314 } catch (NoSuchMethodException e) {
1315 throw new IllegalArgumentException("Invalid command class: " +
1316 cmd.getName() + ". It does not provide a constructor as described by" +
1317 "the javadoc comment. Available constructors are: " +
1318 Arrays.toString(cmd.getConstructors()));
1319 } catch (Exception e) {
1320 throw new IllegalStateException("Failed to construct command class", e);
1321 }
1322 totalElapsedTime = t.test();
1323
1324 status.setStatus("Finished " + cmd + " in " + totalElapsedTime +
1325 "ms at offset " + startRow + " for " + perClientRunRows + " rows");
1326 return totalElapsedTime;
1327 }
1328
1329 private void runNIsOne(final Class<? extends Test> cmd) {
1330 Status status = new Status() {
1331 @Override
1332 public void setStatus(String msg) throws IOException {
1333 LOG.info(msg);
1334 }
1335 };
1336
1337 RemoteAdmin admin = null;
1338 try {
1339 Client client = new Client(cluster);
1340 admin = new RemoteAdmin(client, getConf());
1341 checkTable(admin);
1342 runOneClient(cmd, 0, this.R, this.R, this.flushCommits, this.writeToWAL,
1343 this.useTags, this.noOfTags, this.connection, status);
1344 } catch (Exception e) {
1345 LOG.error("Failed", e);
1346 }
1347 }
1348
1349 private void runTest(final Class<? extends Test> cmd) throws IOException,
1350 InterruptedException, ClassNotFoundException {
1351 if (N == 1) {
1352
1353
1354 runNIsOne(cmd);
1355 } else {
1356
1357 runNIsMoreThanOne(cmd);
1358 }
1359 }
1360
1361 protected void printUsage() {
1362 printUsage(null);
1363 }
1364
1365 protected void printUsage(final String message) {
1366 if (message != null && message.length() > 0) {
1367 System.err.println(message);
1368 }
1369 System.err.println("Usage: java " + this.getClass().getName() + " \\");
1370 System.err.println(" [--nomapred] [--rows=ROWS] [--table=NAME] \\");
1371 System.err.println(" [--compress=TYPE] [--blockEncoding=TYPE] " +
1372 "[-D<property=value>]* <command> <nclients>");
1373 System.err.println();
1374 System.err.println("Options:");
1375 System.err.println(" nomapred Run multiple clients using threads " +
1376 "(rather than use mapreduce)");
1377 System.err.println(" rows Rows each client runs. Default: One million");
1378 System.err.println(" table Alternate table name. Default: 'TestTable'");
1379 System.err.println(" compress Compression type to use (GZ, LZO, ...). Default: 'NONE'");
1380 System.err.println(" flushCommits Used to determine if the test should flush the table. " +
1381 "Default: false");
1382 System.err.println(" writeToWAL Set writeToWAL on puts. Default: True");
1383 System.err.println(" presplit Create presplit table. Recommended for accurate perf " +
1384 "analysis (see guide). Default: disabled");
1385 System.err.println(" inmemory Tries to keep the HFiles of the CF inmemory as far as " +
1386 "possible. Not guaranteed that reads are always served from inmemory. Default: false");
1387 System.err.println(" usetags Writes tags along with KVs. Use with HFile V3. " +
1388 "Default : false");
1389 System.err.println(" numoftags Specify the no of tags that would be needed. " +
1390 "This works only if usetags is true.");
1391 System.err.println();
1392 System.err.println(" Note: -D properties will be applied to the conf used. ");
1393 System.err.println(" For example: ");
1394 System.err.println(" -Dmapreduce.output.fileoutputformat.compress=true");
1395 System.err.println(" -Dmapreduce.task.timeout=60000");
1396 System.err.println();
1397 System.err.println("Command:");
1398 for (CmdDescriptor command : commands.values()) {
1399 System.err.println(String.format(" %-15s %s", command.getName(), command.getDescription()));
1400 }
1401 System.err.println();
1402 System.err.println("Args:");
1403 System.err.println(" nclients Integer. Required. Total number of " +
1404 "clients (and HRegionServers)");
1405 System.err.println(" running: 1 <= value <= 500");
1406 System.err.println("Examples:");
1407 System.err.println(" To run a single evaluation client:");
1408 System.err.println(" $ bin/hbase " + this.getClass().getName()
1409 + " sequentialWrite 1");
1410 }
1411
1412 private void getArgs(final int start, final String[] args) {
1413 if(start + 1 > args.length) {
1414 throw new IllegalArgumentException("must supply the number of clients");
1415 }
1416 N = Integer.parseInt(args[start]);
1417 if (N < 1) {
1418 throw new IllegalArgumentException("Number of clients must be > 1");
1419 }
1420
1421 R = R * N;
1422 }
1423
1424 @Override
1425 public int run(String[] args) throws Exception {
1426
1427
1428 int errCode = -1;
1429 if (args.length < 1) {
1430 printUsage();
1431 return errCode;
1432 }
1433
1434 try {
1435 for (int i = 0; i < args.length; i++) {
1436 String cmd = args[i];
1437 if (cmd.equals("-h") || cmd.startsWith("--h")) {
1438 printUsage();
1439 errCode = 0;
1440 break;
1441 }
1442
1443 final String nmr = "--nomapred";
1444 if (cmd.startsWith(nmr)) {
1445 nomapred = true;
1446 continue;
1447 }
1448
1449 final String rows = "--rows=";
1450 if (cmd.startsWith(rows)) {
1451 R = Integer.parseInt(cmd.substring(rows.length()));
1452 continue;
1453 }
1454
1455 final String table = "--table=";
1456 if (cmd.startsWith(table)) {
1457 this.tableName = TableName.valueOf(cmd.substring(table.length()));
1458 continue;
1459 }
1460
1461 final String compress = "--compress=";
1462 if (cmd.startsWith(compress)) {
1463 this.compression = Compression.Algorithm.valueOf(cmd.substring(compress.length()));
1464 continue;
1465 }
1466
1467 final String blockEncoding = "--blockEncoding=";
1468 if (cmd.startsWith(blockEncoding)) {
1469 this.blockEncoding = DataBlockEncoding.valueOf(cmd.substring(blockEncoding.length()));
1470 continue;
1471 }
1472
1473 final String flushCommits = "--flushCommits=";
1474 if (cmd.startsWith(flushCommits)) {
1475 this.flushCommits = Boolean.parseBoolean(cmd.substring(flushCommits.length()));
1476 continue;
1477 }
1478
1479 final String writeToWAL = "--writeToWAL=";
1480 if (cmd.startsWith(writeToWAL)) {
1481 this.writeToWAL = Boolean.parseBoolean(cmd.substring(writeToWAL.length()));
1482 continue;
1483 }
1484
1485 final String presplit = "--presplit=";
1486 if (cmd.startsWith(presplit)) {
1487 this.presplitRegions = Integer.parseInt(cmd.substring(presplit.length()));
1488 continue;
1489 }
1490
1491 final String inMemory = "--inmemory=";
1492 if (cmd.startsWith(inMemory)) {
1493 this.inMemoryCF = Boolean.parseBoolean(cmd.substring(inMemory.length()));
1494 continue;
1495 }
1496
1497 this.connection = ConnectionFactory.createConnection(getConf());
1498
1499 final String useTags = "--usetags=";
1500 if (cmd.startsWith(useTags)) {
1501 this.useTags = Boolean.parseBoolean(cmd.substring(useTags.length()));
1502 continue;
1503 }
1504
1505 final String noOfTags = "--nooftags=";
1506 if (cmd.startsWith(noOfTags)) {
1507 this.noOfTags = Integer.parseInt(cmd.substring(noOfTags.length()));
1508 continue;
1509 }
1510
1511 final String host = "--host=";
1512 if (cmd.startsWith(host)) {
1513 cluster.add(cmd.substring(host.length()));
1514 continue;
1515 }
1516
1517 Class<? extends Test> cmdClass = determineCommandClass(cmd);
1518 if (cmdClass != null) {
1519 getArgs(i + 1, args);
1520 if (cluster.isEmpty()) {
1521 String s = conf.get("stargate.hostname", "localhost");
1522 if (s.contains(":")) {
1523 cluster.add(s);
1524 } else {
1525 cluster.add(s, conf.getInt("stargate.port", 8080));
1526 }
1527 }
1528 runTest(cmdClass);
1529 errCode = 0;
1530 break;
1531 }
1532
1533 printUsage();
1534 break;
1535 }
1536 } catch (Exception e) {
1537 LOG.error("Failed", e);
1538 }
1539
1540 return errCode;
1541 }
1542
1543 private Class<? extends Test> determineCommandClass(String cmd) {
1544 CmdDescriptor descriptor = commands.get(cmd);
1545 return descriptor != null ? descriptor.getCmdClass() : null;
1546 }
1547
1548
1549
1550
1551 public static void main(final String[] args) throws Exception {
1552 int res = ToolRunner.run(new PerformanceEvaluation(HBaseConfiguration.create()), args);
1553 System.exit(res);
1554 }
1555 }