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