1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.client;
20
21 import java.util.List;
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.apache.hadoop.conf.Configuration;
26 import org.apache.hadoop.fs.FileSystem;
27 import org.apache.hadoop.fs.Path;
28 import org.apache.hadoop.hbase.Cell;
29 import org.apache.hadoop.hbase.CellUtil;
30 import org.apache.hadoop.hbase.TableName;
31 import org.apache.hadoop.hbase.HBaseTestingUtility;
32 import org.apache.hadoop.hbase.HColumnDescriptor;
33 import org.apache.hadoop.hbase.HConstants;
34 import org.apache.hadoop.hbase.HRegionInfo;
35 import org.apache.hadoop.hbase.HTableDescriptor;
36 import org.apache.hadoop.hbase.master.cleaner.HFileCleaner;
37 import org.apache.hadoop.hbase.master.cleaner.HFileLinkCleaner;
38 import org.apache.hadoop.hbase.master.snapshot.SnapshotHFileCleaner;
39 import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
40 import org.apache.hadoop.hbase.mob.MobConstants;
41 import org.apache.hadoop.hbase.regionserver.ConstantSizeRegionSplitPolicy;
42 import org.apache.hadoop.hbase.snapshot.MobSnapshotTestingUtils;
43 import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils;
44 import org.apache.hadoop.hbase.testclassification.LargeTests;
45 import org.apache.hadoop.hbase.util.Bytes;
46 import org.junit.After;
47 import org.junit.AfterClass;
48 import org.junit.Assert;
49 import org.junit.Before;
50 import org.junit.BeforeClass;
51 import org.junit.Test;
52 import org.junit.experimental.categories.Category;
53
54
55
56
57 @Category(LargeTests.class)
58 public class TestMobSnapshotCloneIndependence {
59 private static final Log LOG = LogFactory.getLog(TestMobSnapshotCloneIndependence.class);
60
61 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
62
63 private static final int NUM_RS = 2;
64 private static final String STRING_TABLE_NAME = "test";
65 private static final String TEST_FAM_STR = "fam";
66 private static final byte[] TEST_FAM = Bytes.toBytes(TEST_FAM_STR);
67 private static final byte[] TABLE_NAME = Bytes.toBytes(STRING_TABLE_NAME);
68
69
70
71
72
73 @BeforeClass
74 public static void setupCluster() throws Exception {
75 setupConf(UTIL.getConfiguration());
76 UTIL.startMiniCluster(NUM_RS);
77 }
78
79 private static void setupConf(Configuration conf) {
80
81 conf.setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
82
83 conf.setInt("hbase.regionsever.info.port", -1);
84
85 conf.setInt("hbase.hregion.memstore.flush.size", 25000);
86
87
88 conf.setInt("hbase.hstore.compaction.min", 10);
89 conf.setInt("hbase.hstore.compactionThreshold", 10);
90
91 conf.setInt("hbase.hstore.blockingStoreFiles", 12);
92 conf.setInt("hbase.regionserver.msginterval", 100);
93 conf.setBoolean("hbase.master.enabletable.roundrobin", true);
94
95 conf.set(HConstants.HBASE_REGION_SPLIT_POLICY_KEY,
96 ConstantSizeRegionSplitPolicy.class.getName());
97 conf.setInt(MobConstants.MOB_FILE_CACHE_SIZE_KEY, 0);
98 conf.setInt("hfile.format.version", 3);
99 conf.set(HFileCleaner.MASTER_HFILE_CLEANER_PLUGINS, SnapshotHFileCleaner.class.getName() + ","
100 + HFileLinkCleaner.class.getName());
101 }
102
103 @Before
104 public void setup() throws Exception {
105 MobSnapshotTestingUtils.createMobTable(UTIL, TableName.valueOf(STRING_TABLE_NAME), TEST_FAM);
106 }
107
108 @After
109 public void tearDown() throws Exception {
110 UTIL.deleteTable(TABLE_NAME);
111 SnapshotTestingUtils.deleteAllSnapshots(UTIL.getHBaseAdmin());
112 SnapshotTestingUtils.deleteArchiveDirectory(UTIL);
113 }
114
115 @AfterClass
116 public static void cleanupTest() throws Exception {
117 try {
118 UTIL.shutdownMiniCluster();
119 } catch (Exception e) {
120 LOG.warn("failure shutting down cluster", e);
121 }
122 }
123
124
125
126
127
128 @Test (timeout=300000)
129 public void testOnlineSnapshotAppendIndependent() throws Exception {
130 runTestSnapshotAppendIndependent(true);
131 }
132
133
134
135
136
137 @Test (timeout=300000)
138 public void testOfflineSnapshotAppendIndependent() throws Exception {
139 runTestSnapshotAppendIndependent(false);
140 }
141
142
143
144
145
146 @Test (timeout=300000)
147 public void testOnlineSnapshotMetadataChangesIndependent() throws Exception {
148 runTestSnapshotMetadataChangesIndependent(true);
149 }
150
151
152
153
154
155 @Test (timeout=300000)
156 public void testOfflineSnapshotMetadataChangesIndependent() throws Exception {
157 runTestSnapshotMetadataChangesIndependent(false);
158 }
159
160
161
162
163
164 @Test (timeout=300000)
165 public void testOfflineSnapshotRegionOperationsIndependent() throws Exception {
166 runTestRegionOperationsIndependent(false);
167 }
168
169
170
171
172
173 @Test (timeout=300000)
174 public void testOnlineSnapshotRegionOperationsIndependent() throws Exception {
175 runTestRegionOperationsIndependent(true);
176 }
177
178
179
180
181 @Test (timeout=300000)
182 public void testDeleteTableToBeCloned() throws Exception {
183 FileSystem fs = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getFileSystem();
184 Path rootDir = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();
185 TableName tn = TableName.valueOf("testDeleteTableToBeCloned");
186 byte[] qf = Bytes.toBytes("qf");
187 MobSnapshotTestingUtils.createMobTable(UTIL, tn, TEST_FAM);
188 String row = "row";
189 String value = "value";
190 Put put = new Put(Bytes.toBytes(row));
191 put.addColumn(TEST_FAM, qf, Bytes.toBytes(value));
192 Admin admin = UTIL.getHBaseAdmin();
193 BufferedMutator mutator = UTIL.getConnection().getBufferedMutator(tn);
194 mutator.mutate(put);
195 mutator.flush();
196 admin.flush(tn);
197
198 final String snapshotNameAsString = "snapshot_" + tn;
199 byte[] snapshotName = Bytes.toBytes(snapshotNameAsString);
200 Table table = ConnectionFactory.createConnection(UTIL.getConfiguration()).getTable(tn);
201 Table clonedTable = null;
202 try {
203 SnapshotTestingUtils.createSnapshotAndValidate(admin, tn, TEST_FAM_STR, snapshotNameAsString,
204 rootDir, fs, true);
205 TableName cloneTableName = TableName.valueOf("test-clone-" + tn);
206 admin.cloneSnapshot(snapshotName, cloneTableName);
207 clonedTable = ConnectionFactory.createConnection(UTIL.getConfiguration()).getTable(
208 cloneTableName);
209 admin.deleteSnapshot(snapshotName);
210 admin.disableTable(tn);
211 admin.deleteTable(tn);
212
213 UTIL.getHBaseCluster().getMaster().getHFileCleaner().choreForTesting();
214
215 Scan scan = new Scan();
216 ResultScanner scanner = clonedTable.getScanner(scan);
217 Result rs = scanner.next();
218 Cell cell = rs.getColumnLatestCell(TEST_FAM, qf);
219 Assert.assertEquals(value, Bytes.toString(CellUtil.cloneValue(cell)));
220 Assert.assertNull(scanner.next());
221 } finally {
222 table.close();
223 if (clonedTable != null) {
224 clonedTable.close();
225 }
226 }
227 }
228
229 private static void waitOnSplit(final HTable t, int originalCount) throws Exception {
230 for (int i = 0; i < 200; i++) {
231 try {
232 Thread.sleep(50);
233 } catch (InterruptedException e) {
234
235 Thread.currentThread().interrupt();
236 }
237 if (t.getRegionLocations().size() > originalCount) {
238 return;
239 }
240 }
241 throw new Exception("Split did not increase the number of regions");
242 }
243
244
245
246
247
248
249 private void runTestSnapshotAppendIndependent(boolean online) throws Exception {
250 FileSystem fs = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getFileSystem();
251 Path rootDir = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();
252
253 Admin admin = UTIL.getHBaseAdmin();
254 final long startTime = System.currentTimeMillis();
255 final TableName localTableName =
256 TableName.valueOf(STRING_TABLE_NAME + startTime);
257
258 HTable original = MobSnapshotTestingUtils.createMobTable(UTIL, localTableName, TEST_FAM);
259 try {
260
261 SnapshotTestingUtils.loadData(UTIL, localTableName, 500, TEST_FAM);
262 final int origTableRowCount = MobSnapshotTestingUtils.countMobRows(original);
263
264
265 final String snapshotNameAsString = "snapshot_" + localTableName;
266 byte[] snapshotName = Bytes.toBytes(snapshotNameAsString);
267
268 SnapshotTestingUtils.createSnapshotAndValidate(admin, localTableName, TEST_FAM_STR,
269 snapshotNameAsString, rootDir, fs, online);
270
271 if (!online) {
272 admin.enableTable(localTableName);
273 }
274 TableName cloneTableName = TableName.valueOf("test-clone-" + localTableName);
275 admin.cloneSnapshot(snapshotName, cloneTableName);
276
277 HTable clonedTable = new HTable(UTIL.getConfiguration(), cloneTableName);
278
279 try {
280 final int clonedTableRowCount = MobSnapshotTestingUtils.countMobRows(clonedTable);
281
282 Assert.assertEquals(
283 "The line counts of original and cloned tables do not match after clone. ",
284 origTableRowCount, clonedTableRowCount);
285
286
287 final String rowKey = "new-row-" + System.currentTimeMillis();
288
289 Put p = new Put(Bytes.toBytes(rowKey));
290 p.add(TEST_FAM, Bytes.toBytes("someQualifier"), Bytes.toBytes("someString"));
291 original.put(p);
292 original.flushCommits();
293
294
295 Assert.assertEquals("The row count of the original table was not modified by the put",
296 origTableRowCount + 1, MobSnapshotTestingUtils.countMobRows(original));
297 Assert.assertEquals(
298 "The row count of the cloned table changed as a result of addition to the original",
299 clonedTableRowCount, MobSnapshotTestingUtils.countMobRows(clonedTable));
300
301 p = new Put(Bytes.toBytes(rowKey));
302 p.add(TEST_FAM, Bytes.toBytes("someQualifier"), Bytes.toBytes("someString"));
303 clonedTable.put(p);
304 clonedTable.flushCommits();
305
306
307 Assert.assertEquals(
308 "The row count of the original table was modified by the put to the clone",
309 origTableRowCount + 1, MobSnapshotTestingUtils.countMobRows(original));
310 Assert.assertEquals("The row count of the cloned table was not modified by the put",
311 clonedTableRowCount + 1, MobSnapshotTestingUtils.countMobRows(clonedTable));
312 } finally {
313
314 clonedTable.close();
315 }
316 } finally {
317
318 original.close();
319 }
320 }
321
322
323
324
325
326 private void runTestRegionOperationsIndependent(boolean online) throws Exception {
327 FileSystem fs = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getFileSystem();
328 Path rootDir = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();
329
330
331 Admin admin = UTIL.getHBaseAdmin();
332 final long startTime = System.currentTimeMillis();
333 final TableName localTableName =
334 TableName.valueOf(STRING_TABLE_NAME + startTime);
335 HTable original = MobSnapshotTestingUtils.createMobTable(UTIL, localTableName, TEST_FAM);
336 SnapshotTestingUtils.loadData(UTIL, localTableName, 500, TEST_FAM);
337 final int loadedTableCount = MobSnapshotTestingUtils.countMobRows(original);
338 System.out.println("Original table has: " + loadedTableCount + " rows");
339
340 final String snapshotNameAsString = "snapshot_" + localTableName;
341
342
343 SnapshotTestingUtils.createSnapshotAndValidate(admin, localTableName, TEST_FAM_STR,
344 snapshotNameAsString, rootDir, fs, online);
345
346 if (!online) {
347 admin.enableTable(localTableName);
348 }
349
350 TableName cloneTableName = TableName.valueOf("test-clone-" + localTableName);
351
352
353 byte[] snapshotName = Bytes.toBytes(snapshotNameAsString);
354 admin.cloneSnapshot(snapshotName, cloneTableName);
355
356
357 original.clearRegionCache();
358 List<HRegionInfo> originalTableHRegions = admin.getTableRegions(localTableName);
359
360 final int originalRegionCount = originalTableHRegions.size();
361 final int cloneTableRegionCount = admin.getTableRegions(cloneTableName).size();
362 Assert.assertEquals(
363 "The number of regions in the cloned table is different than in the original table.",
364 originalRegionCount, cloneTableRegionCount);
365
366
367 admin.splitRegion(originalTableHRegions.get(0).getRegionName());
368 waitOnSplit(original, originalRegionCount);
369
370
371 final int cloneTableRegionCount2 = admin.getTableRegions(cloneTableName).size();
372 Assert.assertEquals(
373 "The number of regions in the cloned table changed though none of its regions were split.",
374 cloneTableRegionCount, cloneTableRegionCount2);
375 }
376
377
378
379
380
381
382 private void runTestSnapshotMetadataChangesIndependent(boolean online) throws Exception {
383 FileSystem fs = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getFileSystem();
384 Path rootDir = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();
385
386
387 Admin admin = UTIL.getHBaseAdmin();
388 final long startTime = System.currentTimeMillis();
389 final TableName localTableName =
390 TableName.valueOf(STRING_TABLE_NAME + startTime);
391 HTable original = MobSnapshotTestingUtils.createMobTable(UTIL, localTableName, TEST_FAM);
392 SnapshotTestingUtils.loadData(UTIL, localTableName, 500, TEST_FAM);
393
394 final String snapshotNameAsString = "snapshot_" + localTableName;
395
396
397 SnapshotTestingUtils.createSnapshotAndValidate(admin, localTableName, TEST_FAM_STR,
398 snapshotNameAsString, rootDir, fs, online);
399
400 if (!online) {
401 admin.enableTable(localTableName);
402 }
403 TableName cloneTableName = TableName.valueOf("test-clone-" + localTableName);
404
405
406 byte[] snapshotName = Bytes.toBytes(snapshotNameAsString);
407 admin.cloneSnapshot(snapshotName, cloneTableName);
408
409
410 byte[] TEST_FAM_2 = Bytes.toBytes("fam2");
411 HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAM_2);
412
413 admin.disableTable(localTableName);
414 admin.addColumn(localTableName, hcd);
415
416
417 admin.enableTable(localTableName);
418
419
420
421
422 HTableDescriptor originalTableDescriptor = original.getTableDescriptor();
423 HTableDescriptor clonedTableDescriptor = admin.getTableDescriptor(cloneTableName);
424
425 Assert.assertTrue("The original family was not found. There is something wrong. ",
426 originalTableDescriptor.hasFamily(TEST_FAM));
427 Assert.assertTrue("The original family was not found in the clone. There is something wrong. ",
428 clonedTableDescriptor.hasFamily(TEST_FAM));
429
430 Assert.assertTrue("The new family was not found. ",
431 originalTableDescriptor.hasFamily(TEST_FAM_2));
432 Assert.assertTrue("The new family was not found. ",
433 !clonedTableDescriptor.hasFamily(TEST_FAM_2));
434 }
435 }