1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.snapshot;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.fail;
22
23 import java.io.IOException;
24 import java.util.Collections;
25 import java.util.Comparator;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.hadoop.conf.Configuration;
33 import org.apache.hadoop.fs.FileSystem;
34 import org.apache.hadoop.fs.Path;
35 import org.apache.hadoop.hbase.HBaseTestingUtility;
36 import org.apache.hadoop.hbase.HConstants;
37 import org.apache.hadoop.hbase.HRegionInfo;
38 import org.apache.hadoop.hbase.TableName;
39 import org.apache.hadoop.hbase.TableNotFoundException;
40 import org.apache.hadoop.hbase.client.Admin;
41 import org.apache.hadoop.hbase.client.Table;
42 import org.apache.hadoop.hbase.master.HMaster;
43 import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
44 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
45 import org.apache.hadoop.hbase.regionserver.ConstantSizeRegionSplitPolicy;
46 import org.apache.hadoop.hbase.testclassification.LargeTests;
47 import org.apache.hadoop.hbase.util.Bytes;
48 import org.junit.After;
49 import org.junit.AfterClass;
50 import org.junit.Before;
51 import org.junit.BeforeClass;
52 import org.junit.Test;
53 import org.junit.experimental.categories.Category;
54
55
56
57
58
59
60
61
62
63 @Category(LargeTests.class)
64 public class TestFlushSnapshotFromClient {
65 private static final Log LOG = LogFactory.getLog(TestFlushSnapshotFromClient.class);
66 protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
67 private static final int NUM_RS = 2;
68 private static final byte[] TEST_FAM = Bytes.toBytes("fam");
69 private static final TableName TABLE_NAME = TableName.valueOf("test");
70 private final int DEFAULT_NUM_ROWS = 100;
71
72
73
74
75
76 @BeforeClass
77 public static void setupCluster() throws Exception {
78
79
80
81
82
83 setupConf(UTIL.getConfiguration());
84 UTIL.startMiniCluster(NUM_RS);
85 }
86
87 protected static void setupConf(Configuration conf) {
88
89 conf.setInt("hbase.regionsever.info.port", -1);
90
91 conf.setInt("hbase.hregion.memstore.flush.size", 25000);
92
93
94 conf.setInt("hbase.hstore.compaction.min", 10);
95 conf.setInt("hbase.hstore.compactionThreshold", 10);
96
97 conf.setInt("hbase.hstore.blockingStoreFiles", 12);
98
99 conf.setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
100 conf.set(HConstants.HBASE_REGION_SPLIT_POLICY_KEY,
101 ConstantSizeRegionSplitPolicy.class.getName());
102 }
103
104 @Before
105 public void setup() throws Exception {
106 SnapshotTestingUtils.createTable(UTIL, TABLE_NAME, TEST_FAM);
107 }
108
109 @After
110 public void tearDown() throws Exception {
111 UTIL.deleteTable(TABLE_NAME);
112
113 SnapshotTestingUtils.deleteAllSnapshots(UTIL.getHBaseAdmin());
114 SnapshotTestingUtils.deleteArchiveDirectory(UTIL);
115 }
116
117 @AfterClass
118 public static void cleanupTest() throws Exception {
119 try {
120 UTIL.shutdownMiniCluster();
121 } catch (Exception e) {
122 LOG.warn("failure shutting down cluster", e);
123 }
124 }
125
126
127
128
129
130 @Test (timeout=300000)
131 public void testFlushTableSnapshot() throws Exception {
132 Admin admin = UTIL.getHBaseAdmin();
133
134 SnapshotTestingUtils.assertNoSnapshots(admin);
135
136
137 SnapshotTestingUtils.loadData(UTIL, TABLE_NAME, DEFAULT_NUM_ROWS, TEST_FAM);
138
139 LOG.debug("FS state before snapshot:");
140 UTIL.getHBaseCluster().getMaster().getMasterFileSystem().logFileSystemState(LOG);
141
142
143 String snapshotString = "offlineTableSnapshot";
144 byte[] snapshot = Bytes.toBytes(snapshotString);
145 admin.snapshot(snapshotString, TABLE_NAME, SnapshotDescription.Type.FLUSH);
146 LOG.debug("Snapshot completed.");
147
148
149 List<SnapshotDescription> snapshots = SnapshotTestingUtils.assertOneSnapshotThatMatches(admin,
150 snapshot, TABLE_NAME);
151
152
153 LOG.debug("FS state after snapshot:");
154 UTIL.getHBaseCluster().getMaster().getMasterFileSystem().logFileSystemState(LOG);
155
156 SnapshotTestingUtils.confirmSnapshotValid(UTIL, snapshots.get(0), TABLE_NAME, TEST_FAM);
157 }
158
159
160
161
162
163 @Test(timeout=30000)
164 public void testSkipFlushTableSnapshot() throws Exception {
165 Admin admin = UTIL.getHBaseAdmin();
166
167 SnapshotTestingUtils.assertNoSnapshots(admin);
168
169
170 try (Table table = UTIL.getConnection().getTable(TABLE_NAME)) {
171 UTIL.loadTable(table, TEST_FAM);
172 }
173
174 LOG.debug("FS state before snapshot:");
175 UTIL.getHBaseCluster().getMaster().getMasterFileSystem().logFileSystemState(LOG);
176
177
178 String snapshotString = "skipFlushTableSnapshot";
179 byte[] snapshot = Bytes.toBytes(snapshotString);
180 admin.snapshot(snapshotString, TABLE_NAME, SnapshotDescription.Type.SKIPFLUSH);
181 LOG.debug("Snapshot completed.");
182
183
184 List<SnapshotDescription> snapshots = SnapshotTestingUtils.assertOneSnapshotThatMatches(admin,
185 snapshot, TABLE_NAME);
186
187
188 LOG.debug("FS state after snapshot:");
189 UTIL.getHBaseCluster().getMaster().getMasterFileSystem().logFileSystemState(LOG);
190
191 SnapshotTestingUtils.confirmSnapshotValid(UTIL, snapshots.get(0), TABLE_NAME, TEST_FAM);
192
193 admin.deleteSnapshot(snapshot);
194 snapshots = admin.listSnapshots();
195 SnapshotTestingUtils.assertNoSnapshots(admin);
196 }
197
198
199
200
201
202
203 @Test (timeout=300000)
204 public void testFlushTableSnapshotWithProcedure() throws Exception {
205 Admin admin = UTIL.getHBaseAdmin();
206
207 SnapshotTestingUtils.assertNoSnapshots(admin);
208
209
210 SnapshotTestingUtils.loadData(UTIL, TABLE_NAME, DEFAULT_NUM_ROWS, TEST_FAM);
211
212 LOG.debug("FS state before snapshot:");
213 UTIL.getHBaseCluster().getMaster().getMasterFileSystem().logFileSystemState(LOG);
214
215
216 String snapshotString = "offlineTableSnapshot";
217 byte[] snapshot = Bytes.toBytes(snapshotString);
218 Map<String, String> props = new HashMap<String, String>();
219 props.put("table", TABLE_NAME.getNameAsString());
220 admin.execProcedure(SnapshotManager.ONLINE_SNAPSHOT_CONTROLLER_DESCRIPTION,
221 snapshotString, props);
222
223
224 LOG.debug("Snapshot completed.");
225
226
227 List<SnapshotDescription> snapshots = SnapshotTestingUtils.assertOneSnapshotThatMatches(admin,
228 snapshot, TABLE_NAME);
229
230
231 LOG.debug("FS state after snapshot:");
232 UTIL.getHBaseCluster().getMaster().getMasterFileSystem().logFileSystemState(LOG);
233
234 SnapshotTestingUtils.confirmSnapshotValid(UTIL, snapshots.get(0), TABLE_NAME, TEST_FAM);
235 }
236
237 @Test (timeout=300000)
238 public void testSnapshotFailsOnNonExistantTable() throws Exception {
239 Admin admin = UTIL.getHBaseAdmin();
240
241 SnapshotTestingUtils.assertNoSnapshots(admin);
242 TableName tableName = TableName.valueOf("_not_a_table");
243
244
245 boolean fail = false;
246 do {
247 try {
248 admin.getTableDescriptor(tableName);
249 fail = true;
250 LOG.error("Table:" + tableName + " already exists, checking a new name");
251 tableName = TableName.valueOf(tableName+"!");
252 } catch (TableNotFoundException e) {
253 fail = false;
254 }
255 } while (fail);
256
257
258 try {
259 admin.snapshot("fail", tableName, SnapshotDescription.Type.FLUSH);
260 fail("Snapshot succeeded even though there is not table.");
261 } catch (SnapshotCreationException e) {
262 LOG.info("Correctly failed to snapshot a non-existant table:" + e.getMessage());
263 }
264 }
265
266 @Test(timeout = 300000)
267 public void testAsyncFlushSnapshot() throws Exception {
268 Admin admin = UTIL.getHBaseAdmin();
269 SnapshotDescription snapshot = SnapshotDescription.newBuilder().setName("asyncSnapshot")
270 .setTable(TABLE_NAME.getNameAsString())
271 .setType(SnapshotDescription.Type.FLUSH)
272 .build();
273
274
275 admin.takeSnapshotAsync(snapshot);
276
277
278 HMaster master = UTIL.getMiniHBaseCluster().getMaster();
279 SnapshotTestingUtils.waitForSnapshotToComplete(master, snapshot, 200);
280 LOG.info(" === Async Snapshot Completed ===");
281 UTIL.getHBaseCluster().getMaster().getMasterFileSystem().logFileSystemState(LOG);
282
283
284 SnapshotTestingUtils.assertOneSnapshotThatMatches(admin, snapshot);
285 }
286
287 @Test (timeout=300000)
288 public void testSnapshotStateAfterMerge() throws Exception {
289 int numRows = DEFAULT_NUM_ROWS;
290 Admin admin = UTIL.getHBaseAdmin();
291
292 SnapshotTestingUtils.assertNoSnapshots(admin);
293
294 SnapshotTestingUtils.loadData(UTIL, TABLE_NAME, numRows, TEST_FAM);
295
296
297 String snapshotBeforeMergeName = "snapshotBeforeMerge";
298 admin.snapshot(snapshotBeforeMergeName, TABLE_NAME, SnapshotDescription.Type.FLUSH);
299
300
301 TableName cloneBeforeMergeName = TableName.valueOf("cloneBeforeMerge");
302 admin.cloneSnapshot(snapshotBeforeMergeName, cloneBeforeMergeName);
303 SnapshotTestingUtils.waitForTableToBeOnline(UTIL, cloneBeforeMergeName);
304
305
306 List<HRegionInfo> regions = admin.getTableRegions(TABLE_NAME);
307 Collections.sort(regions, new Comparator<HRegionInfo>() {
308 public int compare(HRegionInfo r1, HRegionInfo r2) {
309 return Bytes.compareTo(r1.getStartKey(), r2.getStartKey());
310 }
311 });
312
313 int numRegions = admin.getTableRegions(TABLE_NAME).size();
314 int numRegionsAfterMerge = numRegions - 2;
315 admin.mergeRegions(regions.get(1).getEncodedNameAsBytes(),
316 regions.get(2).getEncodedNameAsBytes(), true);
317 admin.mergeRegions(regions.get(5).getEncodedNameAsBytes(),
318 regions.get(6).getEncodedNameAsBytes(), true);
319
320
321 waitRegionsAfterMerge(numRegionsAfterMerge);
322 assertEquals(numRegionsAfterMerge, admin.getTableRegions(TABLE_NAME).size());
323
324
325 TableName cloneAfterMergeName = TableName.valueOf("cloneAfterMerge");
326 admin.cloneSnapshot(snapshotBeforeMergeName, cloneAfterMergeName);
327 SnapshotTestingUtils.waitForTableToBeOnline(UTIL, cloneAfterMergeName);
328
329 SnapshotTestingUtils.verifyRowCount(UTIL, TABLE_NAME, numRows);
330 SnapshotTestingUtils.verifyRowCount(UTIL, cloneBeforeMergeName, numRows);
331 SnapshotTestingUtils.verifyRowCount(UTIL, cloneAfterMergeName, numRows);
332
333
334 UTIL.deleteTable(cloneAfterMergeName);
335 UTIL.deleteTable(cloneBeforeMergeName);
336 }
337
338 @Test (timeout=300000)
339 public void testTakeSnapshotAfterMerge() throws Exception {
340 int numRows = DEFAULT_NUM_ROWS;
341 Admin admin = UTIL.getHBaseAdmin();
342
343 SnapshotTestingUtils.assertNoSnapshots(admin);
344
345 SnapshotTestingUtils.loadData(UTIL, TABLE_NAME, numRows, TEST_FAM);
346
347
348 List<HRegionInfo> regions = admin.getTableRegions(TABLE_NAME);
349 Collections.sort(regions, new Comparator<HRegionInfo>() {
350 public int compare(HRegionInfo r1, HRegionInfo r2) {
351 return Bytes.compareTo(r1.getStartKey(), r2.getStartKey());
352 }
353 });
354
355 int numRegions = admin.getTableRegions(TABLE_NAME).size();
356 int numRegionsAfterMerge = numRegions - 2;
357 admin.mergeRegions(regions.get(1).getEncodedNameAsBytes(),
358 regions.get(2).getEncodedNameAsBytes(), true);
359 admin.mergeRegions(regions.get(5).getEncodedNameAsBytes(),
360 regions.get(6).getEncodedNameAsBytes(), true);
361
362 waitRegionsAfterMerge(numRegionsAfterMerge);
363 assertEquals(numRegionsAfterMerge, admin.getTableRegions(TABLE_NAME).size());
364
365
366 String snapshotName = "snapshotAfterMerge";
367 SnapshotTestingUtils.snapshot(admin, snapshotName, TABLE_NAME.getNameAsString(),
368 SnapshotDescription.Type.FLUSH, 3);
369
370
371 TableName cloneName = TableName.valueOf("cloneMerge");
372 admin.cloneSnapshot(snapshotName, cloneName);
373 SnapshotTestingUtils.waitForTableToBeOnline(UTIL, cloneName);
374
375 SnapshotTestingUtils.verifyRowCount(UTIL, TABLE_NAME, numRows);
376 SnapshotTestingUtils.verifyRowCount(UTIL, cloneName, numRows);
377
378
379 UTIL.deleteTable(cloneName);
380 }
381
382
383
384
385 @Test (timeout=300000)
386 public void testFlushCreateListDestroy() throws Exception {
387 LOG.debug("------- Starting Snapshot test -------------");
388 Admin admin = UTIL.getHBaseAdmin();
389
390 SnapshotTestingUtils.assertNoSnapshots(admin);
391
392 SnapshotTestingUtils.loadData(UTIL, TABLE_NAME, DEFAULT_NUM_ROWS, TEST_FAM);
393
394 String snapshotName = "flushSnapshotCreateListDestroy";
395 FileSystem fs = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getFileSystem();
396 Path rootDir = UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();
397 SnapshotTestingUtils.createSnapshotAndValidate(admin, TABLE_NAME, Bytes.toString(TEST_FAM),
398 snapshotName, rootDir, fs, true);
399 }
400
401 private void waitRegionsAfterMerge(final long numRegionsAfterMerge)
402 throws IOException, InterruptedException {
403 Admin admin = UTIL.getHBaseAdmin();
404
405 long startTime = System.currentTimeMillis();
406 while (admin.getTableRegions(TABLE_NAME).size() != numRegionsAfterMerge) {
407
408
409 if ((System.currentTimeMillis() - startTime) > 15000)
410 break;
411 Thread.sleep(100);
412 }
413 SnapshotTestingUtils.waitForTableToBeOnline(UTIL, TABLE_NAME);
414 }
415 }