1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.master.cleaner;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.List;
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.FileStatus;
34 import org.apache.hadoop.fs.FileSystem;
35 import org.apache.hadoop.fs.Path;
36 import org.apache.hadoop.hbase.HBaseTestingUtility;
37 import org.apache.hadoop.hbase.HConstants;
38 import org.apache.hadoop.hbase.MediumTests;
39 import org.apache.hadoop.hbase.client.HBaseAdmin;
40 import org.apache.hadoop.hbase.client.HTable;
41 import org.apache.hadoop.hbase.master.HMaster;
42 import org.apache.hadoop.hbase.master.snapshot.DisabledTableSnapshotHandler;
43 import org.apache.hadoop.hbase.master.snapshot.SnapshotHFileCleaner;
44 import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
45 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
46 import org.apache.hadoop.hbase.regionserver.ConstantSizeRegionSplitPolicy;
47 import org.apache.hadoop.hbase.regionserver.HRegion;
48 import org.apache.hadoop.hbase.snapshot.HSnapshotDescription;
49 import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
50 import org.apache.hadoop.hbase.snapshot.SnapshotTestingUtils;
51 import org.apache.hadoop.hbase.snapshot.UnknownSnapshotException;
52 import org.apache.hadoop.hbase.util.Bytes;
53 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
54 import org.apache.hadoop.hbase.util.FSUtils;
55 import org.apache.hadoop.hbase.util.HFileArchiveUtil;
56 import org.junit.After;
57 import org.junit.AfterClass;
58 import org.junit.Before;
59 import org.junit.BeforeClass;
60 import org.junit.Test;
61 import org.junit.experimental.categories.Category;
62 import org.mockito.Mockito;
63
64 import com.google.common.collect.Lists;
65
66
67
68
69 @Category(MediumTests.class)
70 public class TestSnapshotFromMaster {
71
72 private static final Log LOG = LogFactory.getLog(TestSnapshotFromMaster.class);
73 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
74 private static final int NUM_RS = 2;
75 private static Path rootDir;
76 private static Path snapshots;
77 private static FileSystem fs;
78 private static HMaster master;
79
80
81 private static Path archiveDir;
82 private static final String STRING_TABLE_NAME = "test";
83 private static final byte[] TEST_FAM = Bytes.toBytes("fam");
84 private static final byte[] TABLE_NAME = Bytes.toBytes(STRING_TABLE_NAME);
85
86 private static final long cacheRefreshPeriod = 500;
87
88
89
90
91 @BeforeClass
92 public static void setupCluster() throws Exception {
93 setupConf(UTIL.getConfiguration());
94 UTIL.startMiniCluster(NUM_RS);
95 fs = UTIL.getDFSCluster().getFileSystem();
96 master = UTIL.getMiniHBaseCluster().getMaster();
97 rootDir = master.getMasterFileSystem().getRootDir();
98 snapshots = SnapshotDescriptionUtils.getSnapshotsDir(rootDir);
99 archiveDir = new Path(rootDir, HConstants.HFILE_ARCHIVE_DIRECTORY);
100 }
101
102 private static void setupConf(Configuration conf) {
103
104 conf.setInt("hbase.regionsever.info.port", -1);
105
106 conf.setInt("hbase.hregion.memstore.flush.size", 25000);
107
108
109 conf.setInt("hbase.hstore.compaction.min", 3);
110 conf.setInt("hbase.hstore.compactionThreshold", 5);
111
112 conf.setInt("hbase.hstore.blockingStoreFiles", 12);
113
114 conf.setInt("hbase.client.retries.number", 1);
115
116 conf.set(HFileCleaner.MASTER_HFILE_CLEANER_PLUGINS, "");
117 conf.set(HConstants.HBASE_MASTER_LOGCLEANER_PLUGINS, "");
118
119 conf.setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
120 conf.setLong(SnapshotHFileCleaner.HFILE_CACHE_REFRESH_PERIOD_CONF_KEY, cacheRefreshPeriod);
121
122
123 conf.set(HConstants.HBASE_REGION_SPLIT_POLICY_KEY,
124 ConstantSizeRegionSplitPolicy.class.getName());
125 }
126
127 @Before
128 public void setup() throws Exception {
129 UTIL.createTable(TABLE_NAME, TEST_FAM);
130 master.getSnapshotManagerForTesting().setSnapshotHandlerForTesting(STRING_TABLE_NAME, null);
131 }
132
133 @After
134 public void tearDown() throws Exception {
135 UTIL.deleteTable(TABLE_NAME);
136
137
138 if (fs.exists(archiveDir)) {
139 if (!fs.delete(archiveDir, true)) {
140 throw new IOException("Couldn't delete archive directory (" + archiveDir
141 + " for an unknown reason");
142 }
143 }
144
145
146 if (fs.exists(snapshots)) {
147 if (!fs.delete(snapshots, true)) {
148 throw new IOException("Couldn't delete snapshots directory (" + snapshots
149 + " for an unknown reason");
150 }
151 }
152 }
153
154 @AfterClass
155 public static void cleanupTest() throws Exception {
156 try {
157 UTIL.shutdownMiniCluster();
158 } catch (Exception e) {
159
160 }
161 }
162
163
164
165
166
167
168
169
170
171
172 @Test(timeout = 60000)
173 public void testIsDoneContract() throws Exception {
174
175 String snapshotName = "asyncExpectedFailureTest";
176
177
178 SnapshotTestingUtils.expectSnapshotDoneException(master, new HSnapshotDescription(),
179 UnknownSnapshotException.class);
180
181
182 SnapshotDescription desc = SnapshotDescription.newBuilder()
183 .setName(snapshotName).setTable(STRING_TABLE_NAME).build();
184 SnapshotTestingUtils.expectSnapshotDoneException(master, new HSnapshotDescription(desc),
185 UnknownSnapshotException.class);
186
187
188 DisabledTableSnapshotHandler mockHandler = Mockito.mock(DisabledTableSnapshotHandler.class);
189 Mockito.when(mockHandler.getException()).thenReturn(null);
190 Mockito.when(mockHandler.getSnapshot()).thenReturn(desc);
191 Mockito.when(mockHandler.isFinished()).thenReturn(new Boolean(true));
192 Mockito.when(mockHandler.getCompletionTimestamp())
193 .thenReturn(EnvironmentEdgeManager.currentTimeMillis());
194
195 master.getSnapshotManagerForTesting()
196 .setSnapshotHandlerForTesting(STRING_TABLE_NAME, mockHandler);
197
198
199 SnapshotTestingUtils.expectSnapshotDoneException(master, new HSnapshotDescription(),
200 UnknownSnapshotException.class);
201
202
203 boolean isDone = master.isSnapshotDone(new HSnapshotDescription(desc));
204 assertTrue("Snapshot didn't complete when it should have.", isDone);
205
206
207 desc = SnapshotDescription.newBuilder().setName("Not A Snapshot").build();
208 SnapshotTestingUtils.expectSnapshotDoneException(master, new HSnapshotDescription(desc),
209 UnknownSnapshotException.class);
210
211
212 snapshotName = "completed";
213 Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName, rootDir);
214 desc = desc.toBuilder().setName(snapshotName).build();
215 SnapshotDescriptionUtils.writeSnapshotInfo(desc, snapshotDir, fs);
216
217 isDone = master.isSnapshotDone(new HSnapshotDescription(desc));
218 assertTrue("Completed, on-disk snapshot not found", isDone);
219 }
220
221 @Test
222 public void testGetCompletedSnapshots() throws Exception {
223
224 List<HSnapshotDescription> snapshots = master.getCompletedSnapshots();
225 assertEquals("Found unexpected number of snapshots", 0, snapshots.size());
226
227
228 String snapshotName = "completed";
229 Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName, rootDir);
230 SnapshotDescription snapshot = SnapshotDescription.newBuilder().setName(snapshotName).build();
231 SnapshotDescriptionUtils.writeSnapshotInfo(snapshot, snapshotDir, fs);
232
233
234 snapshots = master.getCompletedSnapshots();
235 assertEquals("Found unexpected number of snapshots", 1, snapshots.size());
236 List<HSnapshotDescription> expected = Lists.newArrayList(new HSnapshotDescription(snapshot));
237 assertEquals("Returned snapshots don't match created snapshots", expected, snapshots);
238
239
240 snapshotName = "completed_two";
241 snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName, rootDir);
242 snapshot = SnapshotDescription.newBuilder().setName(snapshotName).build();
243 SnapshotDescriptionUtils.writeSnapshotInfo(snapshot, snapshotDir, fs);
244 expected.add(new HSnapshotDescription(snapshot));
245
246
247 snapshots = master.getCompletedSnapshots();
248 assertEquals("Found unexpected number of snapshots", 2, snapshots.size());
249 assertEquals("Returned snapshots don't match created snapshots", expected, snapshots);
250 }
251
252 @Test
253 public void testDeleteSnapshot() throws Exception {
254
255 String snapshotName = "completed";
256 SnapshotDescription snapshot = SnapshotDescription.newBuilder().setName(snapshotName).build();
257
258 try {
259 master.deleteSnapshot(new HSnapshotDescription(snapshot));
260 fail("Master didn't throw exception when attempting to delete snapshot that doesn't exist");
261 } catch (IOException e) {
262 LOG.debug("Correctly failed delete of non-existant snapshot:" + e.getMessage());
263 }
264
265
266 Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName, rootDir);
267 SnapshotDescriptionUtils.writeSnapshotInfo(snapshot, snapshotDir, fs);
268
269
270 master.deleteSnapshot(new HSnapshotDescription(snapshot));
271 }
272
273
274
275
276
277
278 @Test
279 public void testSnapshotHFileArchiving() throws Exception {
280 HBaseAdmin admin = UTIL.getHBaseAdmin();
281
282 SnapshotTestingUtils.assertNoSnapshots(admin);
283
284 UTIL.loadTable(new HTable(UTIL.getConfiguration(), TABLE_NAME), TEST_FAM);
285
286
287 admin.disableTable(TABLE_NAME);
288
289
290 String snapshotName = "snapshot";
291 byte[] snapshotNameBytes = Bytes.toBytes(snapshotName);
292 admin.snapshot(snapshotNameBytes, TABLE_NAME);
293
294 Configuration conf = master.getConfiguration();
295 LOG.info("After snapshot File-System state");
296 FSUtils.logFileSystemState(fs, rootDir, LOG);
297
298
299 SnapshotTestingUtils.assertOneSnapshotThatMatches(admin, snapshotNameBytes, TABLE_NAME);
300
301
302 admin.enableTable(TABLE_NAME);
303
304
305 List<HRegion> regions = UTIL.getHBaseCluster().getRegions(TABLE_NAME);
306 for (HRegion region : regions) {
307 region.waitForFlushesAndCompactions();
308 region.compactStores();
309 }
310 LOG.info("After compaction File-System state");
311 FSUtils.logFileSystemState(fs, rootDir, LOG);
312
313
314 LOG.debug("Running hfile cleaners");
315 ensureHFileCleanersRun();
316 LOG.info("After cleaners File-System state: " + rootDir);
317 FSUtils.logFileSystemState(fs, rootDir, LOG);
318
319
320 Path snapshotTable = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName, rootDir);
321 FileStatus[] snapshotHFiles = SnapshotTestingUtils.listHFiles(fs, snapshotTable);
322
323 LOG.debug("Have snapshot hfiles:");
324 for (FileStatus file : snapshotHFiles) {
325 LOG.debug(file.getPath());
326 }
327
328 Collection<String> files = getArchivedHFiles(archiveDir, rootDir, fs, STRING_TABLE_NAME);
329
330
331 for (FileStatus file : snapshotHFiles) {
332 assertTrue("Archived hfiles " + files + " is missing snapshot file:" + file.getPath(),
333 files.contains(file.getPath().getName()));
334 }
335
336
337 admin.deleteSnapshot(snapshotNameBytes);
338 SnapshotTestingUtils.assertNoSnapshots(admin);
339
340
341
342 List<BaseHFileCleanerDelegate> delegates = UTIL.getMiniHBaseCluster().getMaster()
343 .getHFileCleaner().cleanersChain;
344 for (BaseHFileCleanerDelegate delegate: delegates) {
345 if (delegate instanceof SnapshotHFileCleaner) {
346 ((SnapshotHFileCleaner)delegate).getFileCacheForTesting().triggerCacheRefreshForTesting();
347 }
348 }
349
350 LOG.debug("Running hfile cleaners");
351 ensureHFileCleanersRun();
352 LOG.info("After delete snapshot cleaners run File-System state");
353 FSUtils.logFileSystemState(fs, rootDir, LOG);
354
355 files = getArchivedHFiles(archiveDir, rootDir, fs, STRING_TABLE_NAME);
356 assertEquals("Still have some hfiles in the archive, when their snapshot has been deleted.", 0,
357 files.size());
358 }
359
360
361
362
363
364 private final Collection<String> getArchivedHFiles(Path archiveDir, Path rootDir,
365 FileSystem fs, String tableName) throws IOException {
366 Path tableArchive = new Path(archiveDir, tableName);
367 FileStatus[] archivedHFiles = SnapshotTestingUtils.listHFiles(fs, tableArchive);
368 List<String> files = new ArrayList<String>(archivedHFiles.length);
369 LOG.debug("Have archived hfiles: " + tableArchive);
370 for (FileStatus file : archivedHFiles) {
371 LOG.debug(file.getPath());
372 files.add(file.getPath().getName());
373 }
374
375
376 Collections.sort(files);
377 return files;
378 }
379
380
381
382
383 private static void ensureHFileCleanersRun() {
384 UTIL.getHBaseCluster().getMaster().getHFileCleaner().chore();
385 }
386 }