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