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