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