1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.snapshot;
20
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertTrue;
23
24 import java.io.IOException;
25 import java.net.URI;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Set;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.hadoop.conf.Configuration;
35 import org.apache.hadoop.fs.FSDataOutputStream;
36 import org.apache.hadoop.fs.FileStatus;
37 import org.apache.hadoop.fs.FileSystem;
38 import org.apache.hadoop.fs.FileUtil;
39 import org.apache.hadoop.fs.Path;
40 import org.apache.hadoop.hbase.TableName;
41 import org.apache.hadoop.hbase.HBaseTestingUtility;
42 import org.apache.hadoop.hbase.HColumnDescriptor;
43 import org.apache.hadoop.hbase.HConstants;
44 import org.apache.hadoop.hbase.HRegionInfo;
45 import org.apache.hadoop.hbase.HTableDescriptor;
46 import org.apache.hadoop.hbase.MediumTests;
47 import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
48 import org.apache.hadoop.hbase.client.HBaseAdmin;
49 import org.apache.hadoop.hbase.client.HTable;
50 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
51 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
52 import org.apache.hadoop.hbase.regionserver.HRegionFileSystem;
53 import org.apache.hadoop.hbase.util.Bytes;
54 import org.apache.hadoop.hbase.util.FSUtils;
55 import org.apache.hadoop.hbase.util.Pair;
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
63
64
65
66 @Category(MediumTests.class)
67 public class TestExportSnapshot {
68 private final Log LOG = LogFactory.getLog(getClass());
69
70 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
71
72 private final static byte[] FAMILY = Bytes.toBytes("cf");
73
74 private byte[] emptySnapshotName;
75 private byte[] snapshotName;
76 private TableName tableName;
77 private HBaseAdmin admin;
78
79 @BeforeClass
80 public static void setUpBeforeClass() throws Exception {
81 TEST_UTIL.getConfiguration().setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
82 TEST_UTIL.getConfiguration().setInt("hbase.regionserver.msginterval", 100);
83 TEST_UTIL.getConfiguration().setInt("hbase.client.pause", 250);
84 TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 6);
85 TEST_UTIL.getConfiguration().setBoolean("hbase.master.enabletable.roundrobin", true);
86 TEST_UTIL.startMiniCluster(3);
87 }
88
89 @AfterClass
90 public static void tearDownAfterClass() throws Exception {
91 TEST_UTIL.shutdownMiniCluster();
92 }
93
94
95
96
97 @Before
98 public void setUp() throws Exception {
99 this.admin = TEST_UTIL.getHBaseAdmin();
100
101 long tid = System.currentTimeMillis();
102 tableName = TableName.valueOf("testtb-" + tid);
103 snapshotName = Bytes.toBytes("snaptb0-" + tid);
104 emptySnapshotName = Bytes.toBytes("emptySnaptb0-" + tid);
105
106
107 HTableDescriptor htd = new HTableDescriptor(tableName);
108 htd.addFamily(new HColumnDescriptor(FAMILY));
109 admin.createTable(htd, null);
110
111
112 admin.snapshot(emptySnapshotName, tableName);
113
114
115 HTable table = new HTable(TEST_UTIL.getConfiguration(), tableName);
116 TEST_UTIL.loadTable(table, FAMILY);
117
118
119 admin.snapshot(snapshotName, tableName);
120 }
121
122 @After
123 public void tearDown() throws Exception {
124 TEST_UTIL.deleteTable(tableName);
125 SnapshotTestingUtils.deleteAllSnapshots(TEST_UTIL.getHBaseAdmin());
126 SnapshotTestingUtils.deleteArchiveDirectory(TEST_UTIL);
127 admin.close();
128 }
129
130
131
132
133
134
135
136
137
138
139 @Test
140 public void testBalanceSplit() throws Exception {
141
142 List<Pair<Path, Long>> files = new ArrayList<Pair<Path, Long>>();
143 for (long i = 0; i <= 20; i++) {
144 files.add(new Pair<Path, Long>(new Path("file-" + i), i));
145 }
146
147
148
149
150
151
152
153 List<List<Path>> splits = ExportSnapshot.getBalancedSplits(files, 5);
154 assertEquals(5, splits.size());
155 assertEquals(Arrays.asList(new Path("file-20"), new Path("file-11"),
156 new Path("file-10"), new Path("file-1"), new Path("file-0")), splits.get(0));
157 assertEquals(Arrays.asList(new Path("file-19"), new Path("file-12"),
158 new Path("file-9"), new Path("file-2")), splits.get(1));
159 assertEquals(Arrays.asList(new Path("file-18"), new Path("file-13"),
160 new Path("file-8"), new Path("file-3")), splits.get(2));
161 assertEquals(Arrays.asList(new Path("file-17"), new Path("file-14"),
162 new Path("file-7"), new Path("file-4")), splits.get(3));
163 assertEquals(Arrays.asList(new Path("file-16"), new Path("file-15"),
164 new Path("file-6"), new Path("file-5")), splits.get(4));
165 }
166
167
168
169
170 @Test
171 public void testExportFileSystemState() throws Exception {
172 testExportFileSystemState(tableName, snapshotName, 2);
173 }
174
175 @Test
176 public void testEmptyExportFileSystemState() throws Exception {
177 testExportFileSystemState(tableName, emptySnapshotName, 1);
178 }
179
180
181
182
183
184 @Test
185 public void testSnapshotWithRefsExportFileSystemState() throws Exception {
186 Configuration conf = TEST_UTIL.getConfiguration();
187
188 final TableName tableWithRefsName =
189 TableName.valueOf("tableWithRefs");
190 final String snapshotName = "tableWithRefs";
191 final String TEST_FAMILY = Bytes.toString(FAMILY);
192 final String TEST_HFILE = "abc";
193
194 final SnapshotDescription sd = SnapshotDescription.newBuilder()
195 .setName(snapshotName)
196 .setTable(tableWithRefsName.getNameAsString()).build();
197
198 FileSystem fs = TEST_UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getFileSystem();
199 Path rootDir = TEST_UTIL.getHBaseCluster().getMaster().getMasterFileSystem().getRootDir();
200 Path archiveDir = new Path(rootDir, HConstants.HFILE_ARCHIVE_DIRECTORY);
201
202
203 HRegionInfo hri = new HRegionInfo(tableWithRefsName);
204 HRegionFileSystem r0fs = HRegionFileSystem.createRegionOnFileSystem(conf,
205 fs, FSUtils.getTableDir(archiveDir, hri.getTableName()), hri);
206 Path storeFile = new Path(rootDir, TEST_HFILE);
207 FSDataOutputStream out = fs.create(storeFile);
208 out.write(Bytes.toBytes("Test Data"));
209 out.close();
210 r0fs.commitStoreFile(TEST_FAMILY, storeFile);
211
212
213
214 hri = new HRegionInfo(tableWithRefsName);
215 HRegionFileSystem r1fs = HRegionFileSystem.createRegionOnFileSystem(conf,
216 fs, new Path(archiveDir, hri.getTableName().getNameAsString()), hri);
217 storeFile = new Path(rootDir, TEST_HFILE + '.' + r0fs.getRegionInfo().getEncodedName());
218 out = fs.create(storeFile);
219 out.write(Bytes.toBytes("Test Data"));
220 out.close();
221 r1fs.commitStoreFile(TEST_FAMILY, storeFile);
222
223 Path tableDir = FSUtils.getTableDir(archiveDir, tableWithRefsName);
224 Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName, rootDir);
225 FileUtil.copy(fs, tableDir, fs, snapshotDir, false, conf);
226 SnapshotDescriptionUtils.writeSnapshotInfo(sd, snapshotDir, fs);
227
228 testExportFileSystemState(tableWithRefsName, Bytes.toBytes(snapshotName), 2);
229 }
230
231
232
233
234 private void testExportFileSystemState(final TableName tableName, final byte[] snapshotName,
235 int filesExpected) throws Exception {
236 Path copyDir = TEST_UTIL.getDataTestDir("export-" + System.currentTimeMillis());
237 URI hdfsUri = FileSystem.get(TEST_UTIL.getConfiguration()).getUri();
238 FileSystem fs = FileSystem.get(copyDir.toUri(), new Configuration());
239 copyDir = copyDir.makeQualified(fs);
240
241
242 int res = ExportSnapshot.innerMain(TEST_UTIL.getConfiguration(), new String[] {
243 "-snapshot", Bytes.toString(snapshotName),
244 "-copy-to", copyDir.toString()
245 });
246 assertEquals(0, res);
247
248
249 FileStatus[] rootFiles = fs.listStatus(copyDir);
250 assertEquals(filesExpected, rootFiles.length);
251 for (FileStatus fileStatus: rootFiles) {
252 String name = fileStatus.getPath().getName();
253 assertTrue(fileStatus.isDir());
254 assertTrue(name.equals(HConstants.SNAPSHOT_DIR_NAME) ||
255 name.equals(HConstants.HFILE_ARCHIVE_DIRECTORY));
256 }
257
258
259 final FileSystem hdfs = FileSystem.get(hdfsUri, TEST_UTIL.getConfiguration());
260 final Path snapshotDir = new Path(HConstants.SNAPSHOT_DIR_NAME, Bytes.toString(snapshotName));
261 verifySnapshot(hdfs, new Path(TEST_UTIL.getDefaultRootDirPath(), snapshotDir),
262 fs, new Path(copyDir, snapshotDir));
263 verifyArchive(fs, copyDir, tableName, Bytes.toString(snapshotName));
264 FSUtils.logFileSystemState(hdfs, snapshotDir, LOG);
265
266
267 fs.delete(copyDir, true);
268 }
269
270
271
272
273 private void verifySnapshot(final FileSystem fs1, final Path root1,
274 final FileSystem fs2, final Path root2) throws IOException {
275 Set<String> s = new HashSet<String>();
276 assertEquals(listFiles(fs1, root1, root1), listFiles(fs2, root2, root2));
277 }
278
279
280
281
282 private void verifyArchive(final FileSystem fs, final Path rootDir,
283 final TableName tableName, final String snapshotName) throws IOException {
284 final Path exportedSnapshot = new Path(rootDir,
285 new Path(HConstants.SNAPSHOT_DIR_NAME, snapshotName));
286 final Path exportedArchive = new Path(rootDir, HConstants.HFILE_ARCHIVE_DIRECTORY);
287 LOG.debug(listFiles(fs, exportedArchive, exportedArchive));
288 SnapshotReferenceUtil.visitReferencedFiles(fs, exportedSnapshot,
289 new SnapshotReferenceUtil.FileVisitor() {
290 public void storeFile (final String region, final String family, final String hfile)
291 throws IOException {
292 verifyNonEmptyFile(new Path(exportedArchive,
293 new Path(FSUtils.getTableDir(new Path("./"), tableName),
294 new Path(region, new Path(family, hfile)))));
295 }
296
297 public void recoveredEdits (final String region, final String logfile)
298 throws IOException {
299 verifyNonEmptyFile(new Path(exportedSnapshot,
300 new Path(tableName.getNameAsString(), new Path(region, logfile))));
301 }
302
303 public void logFile (final String server, final String logfile)
304 throws IOException {
305 verifyNonEmptyFile(new Path(exportedSnapshot, new Path(server, logfile)));
306 }
307
308 private void verifyNonEmptyFile(final Path path) throws IOException {
309 assertTrue(path + " should exists", fs.exists(path));
310 assertTrue(path + " should not be empty", fs.getFileStatus(path).getLen() > 0);
311 }
312 });
313 }
314
315 private Set<String> listFiles(final FileSystem fs, final Path root, final Path dir)
316 throws IOException {
317 Set<String> files = new HashSet<String>();
318 int rootPrefix = root.toString().length();
319 FileStatus[] list = FSUtils.listStatus(fs, dir);
320 if (list != null) {
321 for (FileStatus fstat: list) {
322 LOG.debug(fstat.getPath());
323 if (fstat.isDir()) {
324 files.addAll(listFiles(fs, root, fstat.getPath()));
325 } else {
326 files.add(fstat.getPath().toString().substring(rootPrefix));
327 }
328 }
329 }
330 return files;
331 }
332 }