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.assertFalse;
23 import static org.junit.Assert.assertTrue;
24
25 import java.io.IOException;
26 import java.net.URI;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.List;
30 import java.util.HashSet;
31 import java.util.Set;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35
36 import org.apache.hadoop.conf.Configuration;
37 import org.apache.hadoop.fs.FileSystem;
38 import org.apache.hadoop.fs.FileStatus;
39 import org.apache.hadoop.fs.Path;
40 import org.apache.hadoop.hbase.HBaseTestingUtility;
41 import org.apache.hadoop.hbase.HColumnDescriptor;
42 import org.apache.hadoop.hbase.HConstants;
43 import org.apache.hadoop.hbase.HRegionInfo;
44 import org.apache.hadoop.hbase.HTableDescriptor;
45 import org.apache.hadoop.hbase.KeyValue;
46 import org.apache.hadoop.hbase.MediumTests;
47 import org.apache.hadoop.hbase.MiniHBaseCluster;
48 import org.apache.hadoop.hbase.master.snapshot.SnapshotManager;
49 import org.apache.hadoop.hbase.client.HBaseAdmin;
50 import org.apache.hadoop.hbase.client.HTable;
51 import org.apache.hadoop.hbase.util.Bytes;
52 import org.apache.hadoop.hbase.util.FSUtils;
53 import org.apache.hadoop.hbase.util.Pair;
54 import org.apache.hadoop.hbase.snapshot.ExportSnapshot;
55 import org.apache.hadoop.hbase.snapshot.SnapshotReferenceUtil;
56 import org.apache.hadoop.mapreduce.Job;
57 import org.junit.After;
58 import org.junit.AfterClass;
59 import org.junit.Before;
60 import org.junit.BeforeClass;
61 import org.junit.Test;
62 import org.junit.experimental.categories.Category;
63
64
65
66
67 @Category(MediumTests.class)
68 public class TestExportSnapshot {
69 private final Log LOG = LogFactory.getLog(getClass());
70
71 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
72
73 private final static byte[] FAMILY = Bytes.toBytes("cf");
74
75 private byte[] emptySnapshotName;
76 private byte[] snapshotName;
77 private byte[] tableName;
78 private HBaseAdmin admin;
79
80 @BeforeClass
81 public static void setUpBeforeClass() throws Exception {
82 TEST_UTIL.getConfiguration().setBoolean(SnapshotManager.HBASE_SNAPSHOT_ENABLED, true);
83 TEST_UTIL.getConfiguration().setInt("hbase.regionserver.msginterval", 100);
84 TEST_UTIL.getConfiguration().setInt("hbase.client.pause", 250);
85 TEST_UTIL.getConfiguration().setInt("hbase.client.retries.number", 6);
86 TEST_UTIL.getConfiguration().setBoolean("hbase.master.enabletable.roundrobin", true);
87 TEST_UTIL.startMiniCluster(3);
88 }
89
90 @AfterClass
91 public static void tearDownAfterClass() throws Exception {
92 TEST_UTIL.shutdownMiniCluster();
93 }
94
95
96
97
98 @Before
99 public void setUp() throws Exception {
100 this.admin = TEST_UTIL.getHBaseAdmin();
101
102 long tid = System.currentTimeMillis();
103 tableName = Bytes.toBytes("testtb-" + tid);
104 snapshotName = Bytes.toBytes("snaptb0-" + tid);
105 emptySnapshotName = Bytes.toBytes("emptySnaptb0-" + tid);
106
107
108 HTableDescriptor htd = new HTableDescriptor(tableName);
109 htd.addFamily(new HColumnDescriptor(FAMILY));
110 admin.createTable(htd, null);
111
112
113 admin.disableTable(tableName);
114 admin.snapshot(emptySnapshotName, tableName);
115 admin.enableTable(tableName);
116
117
118 HTable table = new HTable(TEST_UTIL.getConfiguration(), tableName);
119 TEST_UTIL.loadTable(table, FAMILY);
120
121
122 admin.disableTable(tableName);
123 admin.snapshot(snapshotName, tableName);
124 admin.enableTable(tableName);
125 }
126
127 @After
128 public void tearDown() throws Exception {
129 admin.disableTable(tableName);
130 admin.deleteSnapshot(snapshotName);
131 admin.deleteSnapshot(emptySnapshotName);
132 admin.deleteTable(tableName);
133 admin.close();
134 }
135
136
137
138
139
140
141
142
143
144
145 @Test
146 public void testBalanceSplit() throws Exception {
147
148 List<Pair<Path, Long>> files = new ArrayList<Pair<Path, Long>>();
149 for (long i = 0; i <= 20; i++) {
150 files.add(new Pair<Path, Long>(new Path("file-" + i), i));
151 }
152
153
154
155
156
157
158
159 List<List<Path>> splits = ExportSnapshot.getBalancedSplits(files, 5);
160 assertEquals(5, splits.size());
161 assertEquals(Arrays.asList(new Path("file-20"), new Path("file-11"),
162 new Path("file-10"), new Path("file-1"), new Path("file-0")), splits.get(0));
163 assertEquals(Arrays.asList(new Path("file-19"), new Path("file-12"),
164 new Path("file-9"), new Path("file-2")), splits.get(1));
165 assertEquals(Arrays.asList(new Path("file-18"), new Path("file-13"),
166 new Path("file-8"), new Path("file-3")), splits.get(2));
167 assertEquals(Arrays.asList(new Path("file-17"), new Path("file-14"),
168 new Path("file-7"), new Path("file-4")), splits.get(3));
169 assertEquals(Arrays.asList(new Path("file-16"), new Path("file-15"),
170 new Path("file-6"), new Path("file-5")), splits.get(4));
171 }
172
173
174
175
176 @Test
177 public void testExportFileSystemState() throws Exception {
178 testExportFileSystemState(tableName, snapshotName, 2);
179 }
180
181 @Test
182 public void testEmptyExportFileSystemState() throws Exception {
183 testExportFileSystemState(tableName, emptySnapshotName, 1);
184 }
185
186
187
188
189 private void testExportFileSystemState(final byte[] tableName, final byte[] snapshotName,
190 int filesExpected) throws Exception {
191 Path copyDir = TEST_UTIL.getDataTestDir("export-" + System.currentTimeMillis());
192 URI hdfsUri = FileSystem.get(TEST_UTIL.getConfiguration()).getUri();
193 FileSystem fs = FileSystem.get(copyDir.toUri(), new Configuration());
194 copyDir = copyDir.makeQualified(fs);
195
196
197 int res = ExportSnapshot.innerMain(TEST_UTIL.getConfiguration(), new String[] {
198 "-snapshot", Bytes.toString(snapshotName),
199 "-copy-to", copyDir.toString()
200 });
201 assertEquals(0, res);
202
203
204 FileStatus[] rootFiles = fs.listStatus(copyDir);
205 assertEquals(filesExpected, rootFiles.length);
206 for (FileStatus fileStatus: rootFiles) {
207 String name = fileStatus.getPath().getName();
208 assertTrue(fileStatus.isDir());
209 assertTrue(name.equals(HConstants.SNAPSHOT_DIR_NAME) || name.equals(".archive"));
210 }
211
212
213 final FileSystem hdfs = FileSystem.get(hdfsUri, TEST_UTIL.getConfiguration());
214 final Path snapshotDir = new Path(HConstants.SNAPSHOT_DIR_NAME, Bytes.toString(snapshotName));
215 verifySnapshot(hdfs, new Path(TEST_UTIL.getDefaultRootDirPath(), snapshotDir),
216 fs, new Path(copyDir, snapshotDir));
217 verifyArchive(fs, copyDir, Bytes.toString(snapshotName));
218
219
220 fs.delete(copyDir, true);
221 }
222
223
224
225
226 private void verifySnapshot(final FileSystem fs1, final Path root1,
227 final FileSystem fs2, final Path root2) throws IOException {
228 Set<String> s = new HashSet<String>();
229 assertEquals(listFiles(fs1, root1, root1), listFiles(fs2, root2, root2));
230 }
231
232
233
234
235 private void verifyArchive(final FileSystem fs, final Path rootDir, final String snapshotName)
236 throws IOException {
237 final Path exportedSnapshot = new Path(rootDir,
238 new Path(HConstants.SNAPSHOT_DIR_NAME, snapshotName));
239 final Path exportedArchive = new Path(rootDir, ".archive");
240 LOG.debug(listFiles(fs, exportedArchive, exportedArchive));
241 SnapshotReferenceUtil.visitReferencedFiles(fs, exportedSnapshot,
242 new SnapshotReferenceUtil.FileVisitor() {
243 public void storeFile (final String region, final String family, final String hfile)
244 throws IOException {
245 verifyNonEmptyFile(new Path(exportedArchive,
246 new Path(Bytes.toString(tableName), new Path(region, new Path(family, hfile)))));
247 }
248
249 public void recoveredEdits (final String region, final String logfile)
250 throws IOException {
251 verifyNonEmptyFile(new Path(exportedSnapshot,
252 new Path(Bytes.toString(tableName), new Path(region, logfile))));
253 }
254
255 public void logFile (final String server, final String logfile)
256 throws IOException {
257 verifyNonEmptyFile(new Path(exportedSnapshot, new Path(server, logfile)));
258 }
259
260 private void verifyNonEmptyFile(final Path path) throws IOException {
261 LOG.debug(path);
262 assertTrue(fs.exists(path));
263 assertTrue(fs.getFileStatus(path).getLen() > 0);
264 }
265 });
266 }
267
268 private Set<String> listFiles(final FileSystem fs, final Path root, final Path dir)
269 throws IOException {
270 Set<String> files = new HashSet<String>();
271 int rootPrefix = root.toString().length();
272 FileStatus[] list = FSUtils.listStatus(fs, dir);
273 if (list != null) {
274 for (FileStatus fstat: list) {
275 LOG.debug(fstat.getPath());
276 if (fstat.isDir()) {
277 files.addAll(listFiles(fs, root, fstat.getPath()));
278 } else {
279 files.add(fstat.getPath().toString().substring(rootPrefix));
280 }
281 }
282 }
283 return files;
284 }
285 }