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.coprocessor;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.apache.hadoop.conf.Configuration;
25 import org.apache.hadoop.fs.FileSystem;
26 import org.apache.hadoop.fs.Path;
27 import org.apache.hadoop.hbase.*;
28 import org.apache.hadoop.hbase.regionserver.HRegion;
29 import org.apache.hadoop.hbase.client.Put;
30 import org.apache.hadoop.hbase.regionserver.wal.HLog;
31 import org.apache.hadoop.hbase.regionserver.wal.HLogFactory;
32 import org.apache.hadoop.hbase.regionserver.wal.HLogSplitter;
33 import org.apache.hadoop.hbase.regionserver.wal.WALCoprocessorHost;
34 import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
35 import org.apache.hadoop.hbase.security.User;
36 import org.apache.hadoop.hbase.util.Bytes;
37 import org.apache.hadoop.hbase.util.FSUtils;
38 import org.apache.hadoop.hbase.util.EnvironmentEdge;
39 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
40 import org.junit.After;
41 import org.junit.AfterClass;
42 import org.junit.Before;
43 import org.junit.BeforeClass;
44 import org.junit.Test;
45 import org.junit.experimental.categories.Category;
46
47 import java.io.IOException;
48 import java.security.PrivilegedExceptionAction;
49 import java.util.Arrays;
50 import java.util.List;
51 import java.util.Map;
52
53 import static org.junit.Assert.*;
54
55
56
57
58
59
60 @Category(MediumTests.class)
61 public class TestWALObserver {
62 private static final Log LOG = LogFactory.getLog(TestWALObserver.class);
63 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
64
65 private static byte[] TEST_TABLE = Bytes.toBytes("observedTable");
66 private static byte[][] TEST_FAMILY = { Bytes.toBytes("fam1"),
67 Bytes.toBytes("fam2"), Bytes.toBytes("fam3"), };
68 private static byte[][] TEST_QUALIFIER = { Bytes.toBytes("q1"),
69 Bytes.toBytes("q2"), Bytes.toBytes("q3"), };
70 private static byte[][] TEST_VALUE = { Bytes.toBytes("v1"),
71 Bytes.toBytes("v2"), Bytes.toBytes("v3"), };
72 private static byte[] TEST_ROW = Bytes.toBytes("testRow");
73
74 private Configuration conf;
75 private FileSystem fs;
76 private Path dir;
77 private Path hbaseRootDir;
78 private String logName;
79 private Path oldLogDir;
80 private Path logDir;
81
82 @BeforeClass
83 public static void setupBeforeClass() throws Exception {
84 Configuration conf = TEST_UTIL.getConfiguration();
85 conf.set(CoprocessorHost.WAL_COPROCESSOR_CONF_KEY,
86 SampleRegionWALObserver.class.getName());
87 conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,
88 SampleRegionWALObserver.class.getName());
89 conf.setBoolean("dfs.support.append", true);
90 conf.setInt("dfs.client.block.recovery.retries", 2);
91
92 TEST_UTIL.startMiniCluster(1);
93 Path hbaseRootDir = TEST_UTIL.getDFSCluster().getFileSystem()
94 .makeQualified(new Path("/hbase"));
95 LOG.info("hbase.rootdir=" + hbaseRootDir);
96 FSUtils.setRootDir(conf, hbaseRootDir);
97 }
98
99 @AfterClass
100 public static void teardownAfterClass() throws Exception {
101 TEST_UTIL.shutdownMiniCluster();
102 }
103
104 @Before
105 public void setUp() throws Exception {
106 this.conf = HBaseConfiguration.create(TEST_UTIL.getConfiguration());
107
108 this.fs = TEST_UTIL.getDFSCluster().getFileSystem();
109 this.hbaseRootDir = FSUtils.getRootDir(conf);
110 this.dir = new Path(this.hbaseRootDir, TestWALObserver.class.getName());
111 this.oldLogDir = new Path(this.hbaseRootDir,
112 HConstants.HREGION_OLDLOGDIR_NAME);
113 this.logDir = new Path(this.hbaseRootDir, HConstants.HREGION_LOGDIR_NAME);
114 this.logName = HConstants.HREGION_LOGDIR_NAME;
115
116 if (TEST_UTIL.getDFSCluster().getFileSystem().exists(this.hbaseRootDir)) {
117 TEST_UTIL.getDFSCluster().getFileSystem().delete(this.hbaseRootDir, true);
118 }
119 }
120
121 @After
122 public void tearDown() throws Exception {
123 TEST_UTIL.getDFSCluster().getFileSystem().delete(this.hbaseRootDir, true);
124 }
125
126
127
128
129
130
131 @Test
132 public void testWALObserverWriteToWAL() throws Exception {
133
134 HRegionInfo hri = createBasic3FamilyHRegionInfo(Bytes.toString(TEST_TABLE));
135 final HTableDescriptor htd = createBasic3FamilyHTD(Bytes
136 .toString(TEST_TABLE));
137
138 Path basedir = new Path(this.hbaseRootDir, Bytes.toString(TEST_TABLE));
139 deleteDir(basedir);
140 fs.mkdirs(new Path(basedir, hri.getEncodedName()));
141
142 HLog log = HLogFactory.createHLog(this.fs, hbaseRootDir,
143 TestWALObserver.class.getName(), this.conf);
144 SampleRegionWALObserver cp = getCoprocessor(log);
145
146
147
148
149 cp.setTestValues(TEST_TABLE, TEST_ROW, TEST_FAMILY[0], TEST_QUALIFIER[0],
150 TEST_FAMILY[1], TEST_QUALIFIER[1], TEST_FAMILY[2], TEST_QUALIFIER[2]);
151
152 assertFalse(cp.isPreWALWriteCalled());
153 assertFalse(cp.isPostWALWriteCalled());
154
155
156
157
158 Put p = creatPutWith2Families(TEST_ROW);
159
160 Map<byte[], List<Cell>> familyMap = p.getFamilyCellMap();
161 WALEdit edit = new WALEdit();
162 addFamilyMapToWALEdit(familyMap, edit);
163
164 boolean foundFamily0 = false;
165 boolean foundFamily2 = false;
166 boolean modifiedFamily1 = false;
167
168 List<KeyValue> kvs = edit.getKeyValues();
169
170 for (KeyValue kv : kvs) {
171 if (Arrays.equals(kv.getFamily(), TEST_FAMILY[0])) {
172 foundFamily0 = true;
173 }
174 if (Arrays.equals(kv.getFamily(), TEST_FAMILY[2])) {
175 foundFamily2 = true;
176 }
177 if (Arrays.equals(kv.getFamily(), TEST_FAMILY[1])) {
178 if (!Arrays.equals(kv.getValue(), TEST_VALUE[1])) {
179 modifiedFamily1 = true;
180 }
181 }
182 }
183 assertTrue(foundFamily0);
184 assertFalse(foundFamily2);
185 assertFalse(modifiedFamily1);
186
187
188 long now = EnvironmentEdgeManager.currentTimeMillis();
189 log.append(hri, hri.getTableName(), edit, now, htd);
190
191
192 foundFamily0 = false;
193 foundFamily2 = false;
194 modifiedFamily1 = false;
195 for (KeyValue kv : kvs) {
196 if (Arrays.equals(kv.getFamily(), TEST_FAMILY[0])) {
197 foundFamily0 = true;
198 }
199 if (Arrays.equals(kv.getFamily(), TEST_FAMILY[2])) {
200 foundFamily2 = true;
201 }
202 if (Arrays.equals(kv.getFamily(), TEST_FAMILY[1])) {
203 if (!Arrays.equals(kv.getValue(), TEST_VALUE[1])) {
204 modifiedFamily1 = true;
205 }
206 }
207 }
208 assertFalse(foundFamily0);
209 assertTrue(foundFamily2);
210 assertTrue(modifiedFamily1);
211
212 assertTrue(cp.isPreWALWriteCalled());
213 assertTrue(cp.isPostWALWriteCalled());
214 }
215
216
217
218
219 @Test
220 public void testWALCoprocessorReplay() throws Exception {
221
222
223 TableName tableName = TableName.valueOf("testWALCoprocessorReplay");
224 final HTableDescriptor htd = getBasic3FamilyHTableDescriptor(tableName);
225
226
227
228
229 final HRegionInfo hri = new HRegionInfo(tableName, null, null);
230
231 final Path basedir =
232 FSUtils.getTableDir(this.hbaseRootDir, tableName);
233 deleteDir(basedir);
234 fs.mkdirs(new Path(basedir, hri.getEncodedName()));
235
236 final Configuration newConf = HBaseConfiguration.create(this.conf);
237
238
239 HLog wal = createWAL(this.conf);
240
241 WALEdit edit = new WALEdit();
242 long now = EnvironmentEdgeManager.currentTimeMillis();
243
244 final int countPerFamily = 1000;
245
246 for (HColumnDescriptor hcd : htd.getFamilies()) {
247
248
249 addWALEdits(tableName, hri, TEST_ROW, hcd.getName(), countPerFamily,
250 EnvironmentEdgeManager.getDelegate(), wal, htd);
251 }
252 wal.append(hri, tableName, edit, now, htd);
253
254 wal.sync();
255
256 User user = HBaseTestingUtility.getDifferentUser(newConf,
257 ".replay.wal.secondtime");
258 user.runAs(new PrivilegedExceptionAction() {
259 public Object run() throws Exception {
260 Path p = runWALSplit(newConf);
261 LOG.info("WALSplit path == " + p);
262 FileSystem newFS = FileSystem.get(newConf);
263
264 HLog wal2 = createWAL(newConf);
265 HRegion region = HRegion.openHRegion(newConf, FileSystem.get(newConf), hbaseRootDir,
266 hri, htd, wal2, TEST_UTIL.getHBaseCluster().getRegionServer(0), null);
267 long seqid2 = region.getOpenSeqNum();
268
269 SampleRegionWALObserver cp2 =
270 (SampleRegionWALObserver)region.getCoprocessorHost().findCoprocessor(
271 SampleRegionWALObserver.class.getName());
272
273 assertNotNull(cp2);
274 assertTrue(cp2.isPreWALRestoreCalled());
275 assertTrue(cp2.isPostWALRestoreCalled());
276 region.close();
277 wal2.closeAndDelete();
278 return null;
279 }
280 });
281 }
282
283
284
285
286
287
288 @Test
289 public void testWALObserverLoaded() throws Exception {
290 HLog log = HLogFactory.createHLog(fs, hbaseRootDir,
291 TestWALObserver.class.getName(), conf);
292 assertNotNull(getCoprocessor(log));
293 }
294
295 private SampleRegionWALObserver getCoprocessor(HLog wal) throws Exception {
296 WALCoprocessorHost host = wal.getCoprocessorHost();
297 Coprocessor c = host.findCoprocessor(SampleRegionWALObserver.class
298 .getName());
299 return (SampleRegionWALObserver) c;
300 }
301
302
303
304
305
306
307
308 private HRegionInfo createBasic3FamilyHRegionInfo(final String tableName) {
309 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(tableName));
310
311 for (int i = 0; i < TEST_FAMILY.length; i++) {
312 HColumnDescriptor a = new HColumnDescriptor(TEST_FAMILY[i]);
313 htd.addFamily(a);
314 }
315 return new HRegionInfo(htd.getTableName(), null, null, false);
316 }
317
318
319
320
321 private void deleteDir(final Path p) throws IOException {
322 if (this.fs.exists(p)) {
323 if (!this.fs.delete(p, true)) {
324 throw new IOException("Failed remove of " + p);
325 }
326 }
327 }
328
329 private Put creatPutWith2Families(byte[] row) throws IOException {
330 Put p = new Put(row);
331 for (int i = 0; i < TEST_FAMILY.length - 1; i++) {
332 p.add(TEST_FAMILY[i], TEST_QUALIFIER[i], TEST_VALUE[i]);
333 }
334 return p;
335 }
336
337
338
339
340
341
342
343
344
345 private void addFamilyMapToWALEdit(Map<byte[], List<Cell>> familyMap,
346 WALEdit walEdit) {
347 for (List<Cell> edits : familyMap.values()) {
348 for (Cell cell : edits) {
349
350 walEdit.add((KeyValue)cell);
351 }
352 }
353 }
354
355 private Path runWALSplit(final Configuration c) throws IOException {
356 List<Path> splits = HLogSplitter.split(
357 hbaseRootDir, logDir, oldLogDir, FileSystem.get(c), c);
358
359 assertEquals(1, splits.size());
360
361 assertTrue(fs.exists(splits.get(0)));
362 LOG.info("Split file=" + splits.get(0));
363 return splits.get(0);
364 }
365
366 private HLog createWAL(final Configuration c) throws IOException {
367 return HLogFactory.createHLog(FileSystem.get(c), hbaseRootDir, logName, c);
368 }
369
370 private void addWALEdits(final TableName tableName, final HRegionInfo hri,
371 final byte[] rowName, final byte[] family, final int count,
372 EnvironmentEdge ee, final HLog wal, final HTableDescriptor htd)
373 throws IOException {
374 String familyStr = Bytes.toString(family);
375 for (int j = 0; j < count; j++) {
376 byte[] qualifierBytes = Bytes.toBytes(Integer.toString(j));
377 byte[] columnBytes = Bytes.toBytes(familyStr + ":" + Integer.toString(j));
378 WALEdit edit = new WALEdit();
379 edit.add(new KeyValue(rowName, family, qualifierBytes, ee
380 .currentTimeMillis(), columnBytes));
381 wal.append(hri, tableName, edit, ee.currentTimeMillis(), htd);
382 }
383 }
384
385 private HTableDescriptor getBasic3FamilyHTableDescriptor(
386 final TableName tableName) {
387 HTableDescriptor htd = new HTableDescriptor(tableName);
388
389 for (int i = 0; i < TEST_FAMILY.length; i++) {
390 HColumnDescriptor a = new HColumnDescriptor(TEST_FAMILY[i]);
391 htd.addFamily(a);
392 }
393 return htd;
394 }
395
396 private HTableDescriptor createBasic3FamilyHTD(final String tableName) {
397 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(tableName));
398 HColumnDescriptor a = new HColumnDescriptor(Bytes.toBytes("a"));
399 htd.addFamily(a);
400 HColumnDescriptor b = new HColumnDescriptor(Bytes.toBytes("b"));
401 htd.addFamily(b);
402 HColumnDescriptor c = new HColumnDescriptor(Bytes.toBytes("c"));
403 htd.addFamily(c);
404 return htd;
405 }
406
407 }