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.assertTrue;
22
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.List;
28 import java.util.Set;
29 import java.util.TreeSet;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
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.fs.PathFilter;
37 import org.apache.hadoop.hbase.HBaseTestingUtility;
38 import org.apache.hadoop.hbase.HColumnDescriptor;
39 import org.apache.hadoop.hbase.HConstants;
40 import org.apache.hadoop.hbase.HRegionInfo;
41 import org.apache.hadoop.hbase.HTableDescriptor;
42 import org.apache.hadoop.hbase.client.Durability;
43 import org.apache.hadoop.hbase.client.HBaseAdmin;
44 import org.apache.hadoop.hbase.client.HTable;
45 import org.apache.hadoop.hbase.client.Put;
46 import org.apache.hadoop.hbase.master.HMaster;
47 import org.apache.hadoop.hbase.master.MasterFileSystem;
48 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
49 import org.apache.hadoop.hbase.regionserver.HRegion;
50 import org.apache.hadoop.hbase.regionserver.HRegionServer;
51 import org.apache.hadoop.hbase.snapshot.HBaseSnapshotException;
52 import org.apache.hadoop.hbase.snapshot.HSnapshotDescription;
53 import org.apache.hadoop.hbase.snapshot.TakeSnapshotUtils;
54 import org.apache.hadoop.hbase.util.Bytes;
55 import org.apache.hadoop.hbase.util.FSTableDescriptors;
56 import org.apache.hadoop.hbase.util.FSUtils;
57 import org.apache.hadoop.hbase.util.MD5Hash;
58 import org.junit.Assert;
59
60
61
62
63 public class SnapshotTestingUtils {
64
65 private static final Log LOG = LogFactory.getLog(SnapshotTestingUtils.class);
66
67
68
69
70
71 public static void assertNoSnapshots(HBaseAdmin admin) throws IOException {
72 assertEquals("Have some previous snapshots", 0, admin.listSnapshots().size());
73 }
74
75
76
77
78
79 public static void assertOneSnapshotThatMatches(HBaseAdmin admin, HSnapshotDescription snapshot)
80 throws IOException {
81 assertOneSnapshotThatMatches(admin, snapshot.getName(), snapshot.getTable());
82 }
83
84
85
86
87
88 public static void assertOneSnapshotThatMatches(HBaseAdmin admin, SnapshotDescription snapshot)
89 throws IOException {
90 assertOneSnapshotThatMatches(admin, snapshot.getName(), snapshot.getTable());
91 }
92
93
94
95
96
97 public static List<SnapshotDescription> assertOneSnapshotThatMatches(HBaseAdmin admin,
98 String snapshotName, String tableName) throws IOException {
99
100 List<SnapshotDescription> snapshots = admin.listSnapshots();
101
102 assertEquals("Should only have 1 snapshot", 1, snapshots.size());
103 assertEquals(snapshotName, snapshots.get(0).getName());
104 assertEquals(tableName, snapshots.get(0).getTable());
105
106 return snapshots;
107 }
108
109
110
111
112
113 public static List<SnapshotDescription> assertOneSnapshotThatMatches(HBaseAdmin admin,
114 byte[] snapshot, byte[] tableName) throws IOException {
115 return assertOneSnapshotThatMatches(admin, Bytes.toString(snapshot), Bytes.toString(tableName));
116 }
117
118
119
120
121 public static void confirmSnapshotValid(SnapshotDescription snapshotDescriptor,
122 byte[] tableName, byte[] testFamily, Path rootDir, HBaseAdmin admin, FileSystem fs,
123 boolean requireLogs, Path logsDir, Set<String> snapshotServers) throws IOException {
124 Path snapshotDir = SnapshotDescriptionUtils
125 .getCompletedSnapshotDir(snapshotDescriptor, rootDir);
126 assertTrue(fs.exists(snapshotDir));
127 Path snapshotinfo = new Path(snapshotDir, SnapshotDescriptionUtils.SNAPSHOTINFO_FILE);
128 assertTrue(fs.exists(snapshotinfo));
129
130 if (requireLogs) {
131 TakeSnapshotUtils.verifyAllLogsGotReferenced(fs, logsDir, snapshotServers,
132 snapshotDescriptor, new Path(snapshotDir, HConstants.HREGION_LOGDIR_NAME));
133 }
134
135 HTableDescriptor desc = FSTableDescriptors.getTableDescriptor(fs, rootDir, tableName);
136 HTableDescriptor snapshotDesc = FSTableDescriptors.getTableDescriptor(fs, snapshotDir);
137 assertEquals(desc, snapshotDesc);
138
139
140 List<HRegionInfo> regions = admin.getTableRegions(tableName);
141 for (HRegionInfo info : regions) {
142 String regionName = info.getEncodedName();
143 Path regionDir = new Path(snapshotDir, regionName);
144 HRegionInfo snapshotRegionInfo = HRegion.loadDotRegionInfoFileContent(fs, regionDir);
145 assertEquals(info, snapshotRegionInfo);
146
147 Path familyDir = new Path(regionDir, Bytes.toString(testFamily));
148 assertTrue("Expected to find: " + familyDir + ", but it doesn't exist", fs.exists(familyDir));
149
150 assertTrue(fs.listStatus(familyDir).length > 0);
151 }
152 }
153
154
155
156
157
158
159
160
161
162 public static void waitForSnapshotToComplete(HMaster master, HSnapshotDescription snapshot,
163 long sleep) throws IOException {
164 boolean done = false;
165 while (!done) {
166 done = master.isSnapshotDone(snapshot);
167 try {
168 Thread.sleep(sleep);
169 } catch (InterruptedException e) {
170 throw new IOException(e);
171 }
172 }
173 }
174
175 public static void cleanupSnapshot(HBaseAdmin admin, byte[] tableName) throws IOException {
176 SnapshotTestingUtils.cleanupSnapshot(admin, Bytes.toString(tableName));
177 }
178
179 public static void cleanupSnapshot(HBaseAdmin admin, String snapshotName) throws IOException {
180
181 admin.deleteSnapshot(snapshotName);
182 assertNoSnapshots(admin);
183 }
184
185
186
187
188
189
190
191 public static void expectSnapshotDoneException(HMaster master, HSnapshotDescription snapshot,
192 Class<? extends HBaseSnapshotException> clazz) {
193 try {
194 boolean res = master.isSnapshotDone(snapshot);
195 Assert.fail("didn't fail to lookup a snapshot: res=" + res);
196 } catch (HBaseSnapshotException e) {
197 assertEquals("Threw wrong snapshot exception!", clazz, e.getClass());
198 } catch (Throwable t) {
199 Assert.fail("Threw an unexpected exception:" + t);
200 }
201 }
202
203
204
205
206
207
208
209
210 public static FileStatus[] listHFiles(final FileSystem fs, Path tableDir) throws IOException {
211
212 PathFilter regionFilter = new FSUtils.RegionDirFilter(fs);
213 PathFilter familyFilter = new FSUtils.FamilyDirFilter(fs);
214 final PathFilter fileFilter = new PathFilter() {
215 @Override
216 public boolean accept(Path file) {
217 try {
218 return fs.isFile(file);
219 } catch (IOException e) {
220 return false;
221 }
222 }
223 };
224
225 FileStatus[] regionDirs = FSUtils.listStatus(fs, tableDir, regionFilter);
226
227 if (regionDirs == null || regionDirs.length == 0) return new FileStatus[0];
228
229
230 List<FileStatus> regionFiles = new ArrayList<FileStatus>(regionDirs.length);
231 for (FileStatus regionDir : regionDirs) {
232 FileStatus[] fams = FSUtils.listStatus(fs, regionDir.getPath(), familyFilter);
233
234 if (fams == null || fams.length == 0) continue;
235
236 regionFiles.addAll(SnapshotTestingUtils.getHFilesInRegion(fams, fs, fileFilter));
237 }
238 FileStatus[] files = new FileStatus[regionFiles.size()];
239 regionFiles.toArray(files);
240 return files;
241 }
242
243
244
245
246
247
248
249
250
251 public static Collection<FileStatus> getHFilesInRegion(FileStatus[] families, FileSystem fs,
252 PathFilter fileFilter) throws IOException {
253 Set<FileStatus> files = new TreeSet<FileStatus>();
254 for (FileStatus family : families) {
255
256 FileStatus[] hfiles = FSUtils.listStatus(fs, family.getPath(), fileFilter);
257
258 if (hfiles == null || hfiles.length == 0) continue;
259 files.addAll(Arrays.asList(hfiles));
260 }
261 return files;
262 }
263
264
265
266
267 public static void waitForTableToBeOnline(final HBaseTestingUtility util, final byte[] tableName)
268 throws IOException, InterruptedException {
269 HRegionServer rs = util.getRSForFirstRegionInTable(tableName);
270 List<HRegion> onlineRegions = rs.getOnlineRegions(tableName);
271 for (HRegion region : onlineRegions) {
272 region.waitForFlushesAndCompactions();
273 }
274 util.getHBaseAdmin().isTableAvailable(tableName);
275 }
276
277 public static void createTable(final HBaseTestingUtility util, final byte[] tableName,
278 final byte[]... families) throws IOException, InterruptedException {
279 HTableDescriptor htd = new HTableDescriptor(tableName);
280 for (byte[] family: families) {
281 HColumnDescriptor hcd = new HColumnDescriptor(family);
282 htd.addFamily(hcd);
283 }
284 byte[][] splitKeys = new byte[14][];
285 byte[] hex = Bytes.toBytes("123456789abcde");
286 for (int i = 0; i < splitKeys.length; ++i) {
287 splitKeys[i] = new byte[] { hex[i] };
288 }
289 util.getHBaseAdmin().createTable(htd, splitKeys);
290 waitForTableToBeOnline(util, tableName);
291 assertEquals(15, util.getHBaseAdmin().getTableRegions(tableName).size());
292 }
293
294 public static void loadData(final HBaseTestingUtility util, final byte[] tableName, int rows,
295 byte[]... families) throws IOException, InterruptedException {
296 loadData(util, new HTable(util.getConfiguration(), tableName), rows, families);
297 }
298
299 public static void loadData(final HBaseTestingUtility util, final HTable table, int rows,
300 byte[]... families) throws IOException, InterruptedException {
301 table.setAutoFlush(false);
302
303
304 assertTrue(rows >= 16);
305 for (byte k0: Bytes.toBytes("0123456789abcdef")) {
306 byte[] k = new byte[] { k0 };
307 byte[] value = Bytes.add(Bytes.toBytes(System.currentTimeMillis()), k);
308 byte[] key = Bytes.add(k, Bytes.toBytes(MD5Hash.getMD5AsHex(value)));
309 putData(table, families, key, value);
310 rows--;
311 }
312
313
314 while (rows-- > 0) {
315 byte[] value = Bytes.add(Bytes.toBytes(System.currentTimeMillis()), Bytes.toBytes(rows));
316 byte[] key = Bytes.toBytes(MD5Hash.getMD5AsHex(value));
317 putData(table, families, key, value);
318 }
319 table.flushCommits();
320
321 waitForTableToBeOnline(util, table.getTableName());
322 }
323
324 private static void putData(final HTable table, final byte[][] families,
325 final byte[] key, final byte[] value) throws IOException {
326 byte[] q = Bytes.toBytes("q");
327 Put put = new Put(key);
328 put.setDurability(Durability.SKIP_WAL);
329 for (byte[] family: families) {
330 put.add(family, q, value);
331 }
332 table.put(put);
333 }
334
335 public static void deleteAllSnapshots(final HBaseAdmin admin)
336 throws IOException {
337
338 for (SnapshotDescription snapshot: admin.listSnapshots()) {
339 admin.deleteSnapshot(snapshot.getName());
340 }
341 SnapshotTestingUtils.assertNoSnapshots(admin);
342 }
343
344 public static void deleteArchiveDirectory(final HBaseTestingUtility util)
345 throws IOException {
346
347 MasterFileSystem mfs = util.getMiniHBaseCluster().getMaster().getMasterFileSystem();
348 Path archiveDir = new Path(mfs.getRootDir(), HConstants.HFILE_ARCHIVE_DIRECTORY);
349 mfs.getFileSystem().delete(archiveDir, true);
350 }
351
352 public static void verifyRowCount(final HBaseTestingUtility util, final byte[] tableName,
353 long expectedRows) throws IOException {
354 HTable table = new HTable(util.getConfiguration(), tableName);
355 try {
356 assertEquals(expectedRows, util.countRows(table));
357 } finally {
358 table.close();
359 }
360 }
361 }