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 java.io.IOException;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.Map.Entry;
26 import java.util.Set;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.hadoop.conf.Configuration;
31 import org.apache.hadoop.fs.FileStatus;
32 import org.apache.hadoop.fs.FileSystem;
33 import org.apache.hadoop.fs.Path;
34 import org.apache.hadoop.fs.PathFilter;
35 import org.apache.hadoop.hbase.HRegionInfo;
36 import org.apache.hadoop.hbase.errorhandling.ForeignExceptionListener;
37 import org.apache.hadoop.hbase.errorhandling.TimeoutExceptionInjector;
38 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
39 import org.apache.hadoop.hbase.regionserver.HRegion;
40 import org.apache.hadoop.hbase.regionserver.Store;
41 import org.apache.hadoop.hbase.regionserver.wal.HLog;
42 import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
43 import org.apache.hadoop.hbase.util.Bytes;
44 import org.apache.hadoop.hbase.util.FSUtils;
45
46 import com.google.common.collect.HashMultimap;
47 import com.google.common.collect.Multimap;
48
49
50
51
52 public class TakeSnapshotUtils {
53
54 private static final Log LOG = LogFactory.getLog(TakeSnapshotUtils.class);
55
56 private TakeSnapshotUtils() {
57
58 }
59
60
61
62
63
64
65
66
67
68
69
70 public static Path getRegionSnapshotDirectory(SnapshotDescription desc, Path rootDir,
71 String regionName) {
72 Path snapshotDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(desc, rootDir);
73 return HRegion.getRegionDir(snapshotDir, regionName);
74 }
75
76
77
78
79
80
81
82
83
84
85 public static Path getStoreSnapshotDirectory(Path regionDir, String family) {
86 return Store.getStoreHomedir(regionDir, Bytes.toBytes(family));
87 }
88
89
90
91
92
93
94
95
96
97
98 public static List<Path> getFamilySnapshotDirectories(SnapshotDescription snapshot,
99 Path snapshotRegionDir, FileStatus[] families) {
100 if (families == null || families.length == 0) return Collections.emptyList();
101
102 List<Path> familyDirs = new ArrayList<Path>(families.length);
103 for (FileStatus family : families) {
104
105 familyDirs.add(getStoreSnapshotDirectory(snapshotRegionDir, family.getPath().getName()));
106 }
107 return familyDirs;
108 }
109
110
111
112
113
114
115
116
117 public static TimeoutExceptionInjector getMasterTimerAndBindToMonitor(SnapshotDescription snapshot,
118 Configuration conf, ForeignExceptionListener monitor) {
119 long maxTime = SnapshotDescriptionUtils.getMaxMasterTimeout(conf, snapshot.getType(),
120 SnapshotDescriptionUtils.DEFAULT_MAX_WAIT_TIME);
121 return new TimeoutExceptionInjector(monitor, maxTime);
122 }
123
124
125
126
127
128
129
130
131
132
133 public static void verifyAllLogsGotReferenced(FileSystem fs, Path logsDir,
134 Set<String> serverNames, SnapshotDescription snapshot, Path snapshotLogDir)
135 throws IOException {
136 assertTrue(snapshot, "Logs directory doesn't exist in snapshot", fs.exists(logsDir));
137
138 Multimap<String, String> snapshotLogs = getMapOfServersAndLogs(fs, snapshotLogDir, serverNames);
139 Multimap<String, String> realLogs = getMapOfServersAndLogs(fs, logsDir, serverNames);
140 if (realLogs != null) {
141 assertNotNull(snapshot, "No server logs added to snapshot", snapshotLogs);
142 } else {
143 assertNull(snapshot, "Snapshotted server logs that don't exist", snapshotLogs);
144 }
145
146
147 Set<Entry<String, Collection<String>>> serverEntries = realLogs.asMap().entrySet();
148 Set<Entry<String, Collection<String>>> snapshotEntries = snapshotLogs.asMap().entrySet();
149 assertEquals(snapshot, "Not the same number of snapshot and original server logs directories",
150 serverEntries.size(), snapshotEntries.size());
151
152
153 for (Entry<String, Collection<String>> serverLogs : serverEntries) {
154
155 if (!serverNames.contains(serverLogs.getKey())) continue;
156 Collection<String> snapshotServerLogs = snapshotLogs.get(serverLogs.getKey());
157 assertNotNull(snapshot, "Snapshots missing logs for server:" + serverLogs.getKey(),
158 snapshotServerLogs);
159
160
161 assertEquals(snapshot,
162 "Didn't reference all the log files for server:" + serverLogs.getKey(), serverLogs
163 .getValue().size(), snapshotServerLogs.size());
164 for (String log : serverLogs.getValue()) {
165 assertTrue(snapshot, "Snapshot logs didn't include " + log,
166 snapshotServerLogs.contains(log));
167 }
168 }
169 }
170
171
172
173
174
175
176
177
178
179
180 public static void verifyRecoveredEdits(FileSystem fs, Path rootDir, HRegionInfo regionInfo,
181 SnapshotDescription snapshot) throws IOException {
182 Path regionDir = HRegion.getRegionDir(rootDir, regionInfo);
183 Path editsDir = HLog.getRegionDirRecoveredEditsDir(regionDir);
184 Path snapshotRegionDir = TakeSnapshotUtils.getRegionSnapshotDirectory(snapshot, rootDir,
185 regionInfo.getEncodedName());
186 Path snapshotEditsDir = HLog.getRegionDirRecoveredEditsDir(snapshotRegionDir);
187
188 FileStatus[] edits = FSUtils.listStatus(fs, editsDir);
189 FileStatus[] snapshotEdits = FSUtils.listStatus(fs, snapshotEditsDir);
190 if (edits == null) {
191 assertNull(snapshot, "Snapshot has edits but table doesn't", snapshotEdits);
192 return;
193 }
194
195 assertNotNull(snapshot, "Table has edits, but snapshot doesn't", snapshotEdits);
196
197
198 assertEquals(snapshot, "Not same number of edits in snapshot as table", edits.length,
199 snapshotEdits.length);
200
201
202
203 for (FileStatus edit : edits) {
204 for (FileStatus sEdit : snapshotEdits) {
205 if (sEdit.getPath().equals(edit.getPath())) {
206 assertEquals(snapshot, "Snapshot file" + sEdit.getPath()
207 + " length not equal to the original: " + edit.getPath(), edit.getLen(),
208 sEdit.getLen());
209 break;
210 }
211 }
212 assertTrue(snapshot, "No edit in snapshot with name:" + edit.getPath(), false);
213 }
214 }
215
216 private static void assertNull(SnapshotDescription snapshot, String msg, Object isNull)
217 throws CorruptedSnapshotException {
218 if (isNull != null) {
219 throw new CorruptedSnapshotException(msg + ", Expected " + isNull + " to be null.", snapshot);
220 }
221 }
222
223 private static void assertNotNull(SnapshotDescription snapshot, String msg, Object notNull)
224 throws CorruptedSnapshotException {
225 if (notNull == null) {
226 throw new CorruptedSnapshotException(msg + ", Expected object to not be null, but was null.",
227 snapshot);
228 }
229 }
230
231 private static void assertTrue(SnapshotDescription snapshot, String msg, boolean isTrue)
232 throws CorruptedSnapshotException {
233 if (!isTrue) {
234 throw new CorruptedSnapshotException(msg + ", Expected true, but was false", snapshot);
235 }
236 }
237
238
239
240
241
242
243
244
245 private static void assertEquals(SnapshotDescription snapshot, String msg, int expected,
246 int gotten) throws CorruptedSnapshotException {
247 if (expected != gotten) {
248 throw new CorruptedSnapshotException(msg + ". Expected:" + expected + ", got:" + gotten,
249 snapshot);
250 }
251 }
252
253
254
255
256
257
258
259
260 private static void assertEquals(SnapshotDescription snapshot, String msg, long expected,
261 long gotten) throws CorruptedSnapshotException {
262 if (expected != gotten) {
263 throw new CorruptedSnapshotException(msg + ". Expected:" + expected + ", got:" + gotten,
264 snapshot);
265 }
266 }
267
268
269
270
271
272
273
274 private static Multimap<String, String> getMapOfServersAndLogs(FileSystem fs, Path logdir,
275 Collection<String> toInclude) throws IOException {
276
277 PathFilter filter = toInclude == null || toInclude.size() == 0 ? null
278 : new MatchesDirectoryNames(toInclude);
279
280
281 FileStatus[] serverLogDirs = FSUtils.listStatus(fs, logdir, filter);
282 if (serverLogDirs == null) return null;
283
284
285 Multimap<String, String> map = HashMultimap.create();
286 for (FileStatus server : serverLogDirs) {
287 FileStatus[] serverLogs = FSUtils.listStatus(fs, server.getPath(), null);
288 if (serverLogs == null) continue;
289 for (FileStatus log : serverLogs) {
290 map.put(server.getPath().getName(), log.getPath().getName());
291 }
292 }
293 return map;
294 }
295
296
297
298
299
300 private static class MatchesDirectoryNames implements PathFilter {
301
302 Collection<String> paths;
303
304 public MatchesDirectoryNames(Collection<String> dirNames) {
305 this.paths = dirNames;
306 }
307
308 @Override
309 public boolean accept(Path path) {
310 return paths.contains(path.getName());
311 }
312 }
313
314
315
316
317
318
319
320 public static Path getSnapshotHLogsDir(Path snapshotDir, String serverName) {
321 return new Path(snapshotDir, HLog.getHLogDirectoryName(serverName));
322 }
323 }