1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.regionserver.wal;
21
22 import java.io.IOException;
23 import java.util.Random;
24
25 import org.apache.commons.logging.impl.Log4JLogger;
26 import org.apache.hadoop.hbase.*;
27 import org.apache.log4j.Level;
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30
31 import org.apache.hadoop.util.Tool;
32 import org.apache.hadoop.util.ToolRunner;
33 import org.apache.hadoop.conf.Configuration;
34 import org.apache.hadoop.conf.Configured;
35 import org.apache.hadoop.fs.FileSystem;
36 import org.apache.hadoop.fs.Path;
37 import org.apache.hadoop.hbase.regionserver.HRegion;
38 import org.apache.hadoop.hbase.util.Bytes;
39 import org.apache.hadoop.hbase.ipc.HBaseRPC;
40
41 import org.junit.Test;
42 import org.junit.experimental.categories.Category;
43
44 @Category(MediumTests.class)
45 public class TestHLogBench extends Configured implements Tool {
46
47 static final Log LOG = LogFactory.getLog(TestHLogBench.class);
48 private static final Random r = new Random();
49
50 private static final byte [] FAMILY = Bytes.toBytes("hlogbenchFamily");
51
52
53 private static int totalTime = 0;
54 private static Object lock = new Object();
55
56
57 protected FileSystem fs;
58
59
60 private int numThreads = 300;
61 private int numIterationsPerThread = 10000;
62
63 private final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
64 private Path regionRootDir =TEST_UTIL.getDataTestDir("TestHLogBench") ;
65
66 private boolean appendNoSync = false;
67
68 public TestHLogBench() {
69 this(null);
70 }
71
72 private TestHLogBench(Configuration conf) {
73 super(conf);
74 fs = null;
75 }
76
77
78
79
80 public void init() throws IOException {
81 getConf().setQuietMode(true);
82 if (this.fs == null) {
83 this.fs = FileSystem.get(getConf());
84 }
85 }
86
87
88
89
90 public void close() throws IOException {
91 if (fs != null) {
92 fs.close();
93 fs = null;
94 }
95 }
96
97
98
99
100 public int run(String argv[]) throws Exception {
101
102 int exitCode = -1;
103 int i = 0;
104
105
106 if (argv.length < 4) {
107 printUsage("");
108 return exitCode;
109 }
110
111
112 try {
113 init();
114 } catch (HBaseRPC.VersionMismatch v) {
115 LOG.warn("Version Mismatch between client and server" +
116 "... command aborted.");
117 return exitCode;
118 } catch (IOException e) {
119 LOG.warn("Bad connection to FS. command aborted.");
120 return exitCode;
121 }
122
123 try {
124 for (; i < argv.length; i++) {
125 if ("-numThreads".equals(argv[i])) {
126 i++;
127 this.numThreads = Integer.parseInt(argv[i]);
128 } else if ("-numIterationsPerThread".equals(argv[i])) {
129 i++;
130 this.numIterationsPerThread = Integer.parseInt(argv[i]);
131 } else if ("-path".equals(argv[i])) {
132
133 i++;
134 this.regionRootDir = new Path(argv[i]);
135 this.regionRootDir = regionRootDir.makeQualified(this.fs);
136 } else if ("-nosync".equals(argv[i])) {
137 this.appendNoSync = true;
138 } else {
139 printUsage(argv[i]);
140 return exitCode;
141 }
142 }
143 } catch (NumberFormatException nfe) {
144 LOG.warn("Illegal numThreads or numIterationsPerThread, " +
145 " a positive integer expected");
146 throw nfe;
147 }
148 go();
149 return 0;
150 }
151
152 private void go() throws IOException, InterruptedException {
153
154 long start = System.currentTimeMillis();
155 log("Running TestHLogBench with " + numThreads + " threads each doing " +
156 numIterationsPerThread + " HLog appends " +
157 (appendNoSync ? "nosync" : "sync") +
158 " at rootDir " + regionRootDir);
159
160
161 byte [] tableName = Bytes.toBytes("table");
162 byte [][] familyNames = new byte [][] { FAMILY };
163 HTableDescriptor htd = new HTableDescriptor();
164 htd.addFamily(new HColumnDescriptor(Bytes.toBytes("f1")));
165 HRegion region = mockRegion(tableName, familyNames, regionRootDir);
166 HLog hlog = region.getLog();
167
168
169 LogWriter [] incrementors = new LogWriter[numThreads];
170 for (int i=0; i<numThreads; i++) {
171 incrementors[i] = new LogWriter(region, tableName, hlog, i,
172 numIterationsPerThread,
173 appendNoSync);
174 incrementors[i].start();
175 }
176
177
178 for (int i=0; i<numThreads; i++) {
179
180 incrementors[i].join();
181 }
182
183
184 long totalOps = numThreads * numIterationsPerThread;
185 log("Operations per second " + ((totalOps * 1000L)/totalTime));
186 log("Average latency in ms " + ((totalTime * 1000L)/totalOps));
187 }
188
189
190
191
192 private static void printUsage(String cmd) {
193 String prefix = "Usage: java " + TestHLogBench.class.getSimpleName();
194 System.err.println(prefix + cmd +
195 " [-numThreads <number>] " +
196 " [-numIterationsPerThread <number>] " +
197 " [-path <path where region's root directory is created>]" +
198 " [-nosync]");
199 }
200
201
202
203
204 public static class LogWriter extends Thread {
205
206 private final HRegion region;
207 private final int threadNumber;
208 private final int numIncrements;
209 private final HLog hlog;
210 private boolean appendNoSync;
211 private byte[] tableName;
212
213 private int count;
214
215 public LogWriter(HRegion region, byte[] tableName,
216 HLog log, int threadNumber,
217 int numIncrements, boolean appendNoSync) {
218 this.region = region;
219 this.threadNumber = threadNumber;
220 this.numIncrements = numIncrements;
221 this.hlog = log;
222 this.count = 0;
223 this.appendNoSync = appendNoSync;
224 this.tableName = tableName;
225 setDaemon(true);
226
227 }
228
229 @Override
230 public void run() {
231 long now = System.currentTimeMillis();
232 byte [] key = Bytes.toBytes("thisisakey");
233 KeyValue kv = new KeyValue(key, now);
234 WALEdit walEdit = new WALEdit();
235 walEdit.add(kv);
236 HRegionInfo hri = region.getRegionInfo();
237 HTableDescriptor htd = new HTableDescriptor();
238 htd.addFamily(new HColumnDescriptor(Bytes.toBytes("f1")));
239 boolean isMetaRegion = false;
240 long start = System.currentTimeMillis();
241 for (int i=0; i<numIncrements; i++) {
242 try {
243 if (appendNoSync) {
244 hlog.appendNoSync(hri, tableName, walEdit,
245 HConstants.DEFAULT_CLUSTER_ID, now, htd);
246 } else {
247 hlog.append(hri, tableName, walEdit, now, htd);
248 }
249 } catch (IOException e) {
250 log("Fatal exception: " + e);
251 e.printStackTrace();
252 }
253 count++;
254 }
255 long tot = System.currentTimeMillis() - start;
256 synchronized (lock) {
257 totalTime += tot;
258 }
259
260 }
261 }
262
263 private static void log(String string) {
264 LOG.info(string);
265 }
266
267 private byte[][] makeBytes(int numArrays, int arraySize) {
268 byte [][] bytes = new byte[numArrays][];
269 for (int i=0; i<numArrays; i++) {
270 bytes[i] = new byte[arraySize];
271 r.nextBytes(bytes[i]);
272 }
273 return bytes;
274 }
275
276
277
278
279 private HRegion mockRegion(byte[] tableName, byte[][] familyNames,
280 Path rootDir) throws IOException {
281
282 HBaseTestingUtility htu = new HBaseTestingUtility();
283 Configuration conf = htu.getConfiguration();
284 conf.setBoolean("hbase.rs.cacheblocksonwrite", true);
285 conf.setBoolean("hbase.hregion.use.incrementnew", true);
286 conf.setBoolean("dfs.support.append", true);
287 FileSystem fs = FileSystem.get(conf);
288 int numQualifiers = 10;
289 byte [][] qualifiers = new byte [numQualifiers][];
290 for (int i=0; i<numQualifiers; i++) qualifiers[i] = Bytes.toBytes("qf" + i);
291 int numRows = 10;
292 byte [][] rows = new byte [numRows][];
293 for (int i=0; i<numRows; i++) rows[i] = Bytes.toBytes("r" + i);
294
295
296 ((Log4JLogger)HRegion.LOG).getLogger().setLevel(Level.WARN);
297
298 HTableDescriptor htd = new HTableDescriptor(tableName);
299 for (byte [] family : familyNames)
300 htd.addFamily(new HColumnDescriptor(family));
301
302 HRegionInfo hri = new HRegionInfo(tableName, Bytes.toBytes(0L),
303 Bytes.toBytes(0xffffffffL));
304 if (fs.exists(rootDir)) {
305 if (!fs.delete(rootDir, true)) {
306 throw new IOException("Failed delete of " + rootDir);
307 }
308 }
309 return HRegion.createHRegion(hri, rootDir, conf, htd);
310 }
311
312 @Test
313 public void testLogPerformance() throws Exception {
314 TestHLogBench bench = new TestHLogBench();
315 int res;
316 String[] argv = new String[7];
317 argv[0] = "-numThreads";
318 argv[1] = Integer.toString(100);
319 argv[2] = "-numIterationsPerThread";
320 argv[3] = Integer.toString(1000);
321 argv[4] = "-path";
322 argv[5] = TEST_UTIL.getDataTestDir() + "/HlogPerformance";
323 argv[6] = "-nosync";
324 try {
325 res = ToolRunner.run(bench, argv);
326 } finally {
327 bench.close();
328 }
329 }
330
331 public static void main(String[] argv) throws Exception {
332 TestHLogBench bench = new TestHLogBench();
333 int res;
334 try {
335 res = ToolRunner.run(bench, argv);
336 } finally {
337 bench.close();
338 }
339 System.exit(res);
340 }
341
342 @org.junit.Rule
343 public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
344 new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
345 }
346