1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.master.snapshot;
19
20 import java.io.IOException;
21 import java.util.List;
22 import java.util.Set;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.apache.hadoop.classification.InterfaceAudience;
27 import org.apache.hadoop.classification.InterfaceStability;
28 import org.apache.hadoop.fs.FSDataInputStream;
29 import org.apache.hadoop.fs.FileStatus;
30 import org.apache.hadoop.fs.FileSystem;
31 import org.apache.hadoop.fs.Path;
32 import org.apache.hadoop.fs.PathFilter;
33 import org.apache.hadoop.hbase.HConstants;
34 import org.apache.hadoop.hbase.HRegionInfo;
35 import org.apache.hadoop.hbase.ServerName;
36 import org.apache.hadoop.hbase.catalog.MetaReader;
37 import org.apache.hadoop.hbase.io.HFileLink;
38 import org.apache.hadoop.hbase.master.MasterServices;
39 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
40 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription.Type;
41 import org.apache.hadoop.hbase.regionserver.HRegion;
42 import org.apache.hadoop.hbase.regionserver.StoreFile;
43 import org.apache.hadoop.hbase.snapshot.CorruptedSnapshotException;
44 import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
45 import org.apache.hadoop.hbase.snapshot.SnapshotReferenceUtil;
46 import org.apache.hadoop.hbase.snapshot.TakeSnapshotUtils;
47 import org.apache.hadoop.hbase.util.Bytes;
48 import org.apache.hadoop.hbase.util.FSTableDescriptors;
49 import org.apache.hadoop.hbase.util.FSUtils;
50 import org.apache.hadoop.hbase.util.FSVisitor;
51 import org.apache.hadoop.hbase.util.HFileArchiveUtil;
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 @InterfaceAudience.Private
82 @InterfaceStability.Unstable
83 public final class MasterSnapshotVerifier {
84 private static final Log LOG = LogFactory.getLog(MasterSnapshotVerifier.class);
85
86 private SnapshotDescription snapshot;
87 private FileSystem fs;
88 private Path rootDir;
89 private String tableName;
90 private MasterServices services;
91
92
93
94
95
96
97 public MasterSnapshotVerifier(MasterServices services, SnapshotDescription snapshot, Path rootDir) {
98 this.fs = services.getMasterFileSystem().getFileSystem();
99 this.services = services;
100 this.snapshot = snapshot;
101 this.rootDir = rootDir;
102 this.tableName = snapshot.getTable();
103 }
104
105
106
107
108
109
110
111
112 public void verifySnapshot(Path snapshotDir, Set<String> snapshotServers)
113 throws CorruptedSnapshotException, IOException {
114
115 verifySnapshotDescription(snapshotDir);
116
117
118 verifyTableInfo(snapshotDir);
119
120
121 verifyRegions(snapshotDir);
122 }
123
124
125
126
127
128 private void verifySnapshotDescription(Path snapshotDir) throws CorruptedSnapshotException {
129 SnapshotDescription found = SnapshotDescriptionUtils.readSnapshotInfo(fs, snapshotDir);
130 if (!this.snapshot.equals(found)) {
131 throw new CorruptedSnapshotException("Snapshot read (" + found
132 + ") doesn't equal snapshot we ran (" + snapshot + ").", snapshot);
133 }
134 }
135
136
137
138
139
140 private void verifyTableInfo(Path snapshotDir) throws IOException {
141 FSTableDescriptors.getTableDescriptor(fs, snapshotDir);
142 }
143
144
145
146
147
148
149 private void verifyRegions(Path snapshotDir) throws IOException {
150 List<HRegionInfo> regions = MetaReader.getTableRegions(this.services.getCatalogTracker(),
151 Bytes.toBytes(tableName));
152
153 Set<String> snapshotRegions = SnapshotReferenceUtil.getSnapshotRegionNames(fs, snapshotDir);
154 if (snapshotRegions == null) {
155 String msg = "Snapshot " + SnapshotDescriptionUtils.toString(snapshot) + " looks empty";
156 LOG.error(msg);
157 throw new CorruptedSnapshotException(msg);
158 }
159
160 if (snapshotRegions.size() != regions.size()) {
161 String msg = "Regions moved during the snapshot '" +
162 SnapshotDescriptionUtils.toString(snapshot) + "'. expected=" +
163 regions.size() + " snapshotted=" + snapshotRegions.size();
164 LOG.error(msg);
165 throw new CorruptedSnapshotException(msg);
166 }
167
168 for (HRegionInfo region : regions) {
169 if (!snapshotRegions.contains(region.getEncodedName())) {
170
171 String msg = "No region directory found for region:" + region;
172 LOG.error(msg);
173 throw new CorruptedSnapshotException(msg, snapshot);
174 }
175
176 verifyRegion(fs, snapshotDir, region);
177 }
178 }
179
180
181
182
183
184
185
186 private void verifyRegion(final FileSystem fs, final Path snapshotDir, final HRegionInfo region)
187 throws IOException {
188
189 Path regionDir = new Path(snapshotDir, region.getEncodedName());
190
191
192 Path regionInfo = new Path(regionDir, HRegion.REGIONINFO_FILE);
193
194 if (!fs.exists(regionInfo)) {
195 throw new CorruptedSnapshotException("No region info found for region:" + region, snapshot);
196 }
197
198 FSDataInputStream in = fs.open(regionInfo);
199 HRegionInfo found = new HRegionInfo();
200 try {
201 found.readFields(in);
202 if (!region.equals(found)) {
203 throw new CorruptedSnapshotException("Found region info (" + found
204 + ") doesn't match expected region:" + region, snapshot);
205 }
206 } finally {
207 in.close();
208 }
209
210
211 TakeSnapshotUtils.verifyRecoveredEdits(fs, snapshotDir, found, snapshot);
212
213
214 SnapshotReferenceUtil.visitRegionStoreFiles(fs, regionDir, new FSVisitor.StoreFileVisitor() {
215 public void storeFile(final String regionNameSuffix, final String family,
216 final String hfileName) throws IOException {
217 verifyStoreFile(snapshotDir, region, family, hfileName);
218 }
219 });
220 }
221
222 private void verifyStoreFile(final Path snapshotDir, final HRegionInfo regionInfo,
223 final String family, final String fileName) throws IOException {
224 Path refPath = null;
225 if (StoreFile.isReference(fileName)) {
226
227 Path snapshotHFilePath = new Path(new Path(
228 new Path(snapshotDir, regionInfo.getEncodedName()), family), fileName);
229 refPath = StoreFile.getReferredToFile(snapshotHFilePath);
230 if (!fs.exists(refPath)) {
231 throw new CorruptedSnapshotException("Missing parent hfile for: " + fileName, snapshot);
232 }
233 }
234
235 Path linkPath;
236 if (refPath != null && HFileLink.isHFileLink(refPath)) {
237 linkPath = new Path(family, refPath.getName());
238 } else if (HFileLink.isHFileLink(fileName)) {
239 linkPath = new Path(family, fileName);
240 } else {
241 linkPath = new Path(family, HFileLink.createHFileLinkName(tableName,
242 regionInfo.getEncodedName(), fileName));
243 }
244
245
246 HFileLink link = new HFileLink(services.getConfiguration(), linkPath);
247 if (!link.exists(fs)) {
248 throw new CorruptedSnapshotException("Can't find hfile: " + fileName
249 + " in the real (" + link.getOriginPath() + ") or archive (" + link.getArchivePath()
250 + ") directory for the primary table.", snapshot);
251 }
252 }
253
254
255
256
257
258
259
260
261
262 private void verifyLogs(Path snapshotDir, Set<String> snapshotServers)
263 throws CorruptedSnapshotException, IOException {
264 Path snapshotLogDir = new Path(snapshotDir, HConstants.HREGION_LOGDIR_NAME);
265 Path logsDir = new Path(rootDir, HConstants.HREGION_LOGDIR_NAME);
266 TakeSnapshotUtils.verifyAllLogsGotReferenced(fs, logsDir, snapshotServers, snapshot,
267 snapshotLogDir);
268 }
269 }