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 com.google.common.base.Preconditions;
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Set;
26 import java.util.concurrent.CancellationException;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.hadoop.hbase.classification.InterfaceAudience;
31 import org.apache.hadoop.conf.Configuration;
32 import org.apache.hadoop.fs.FileSystem;
33 import org.apache.hadoop.fs.Path;
34 import org.apache.hadoop.hbase.TableName;
35 import org.apache.hadoop.hbase.HRegionInfo;
36 import org.apache.hadoop.hbase.HTableDescriptor;
37 import org.apache.hadoop.hbase.ServerName;
38 import org.apache.hadoop.hbase.MetaTableAccessor;
39 import org.apache.hadoop.hbase.errorhandling.ForeignException;
40 import org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher;
41 import org.apache.hadoop.hbase.errorhandling.ForeignExceptionSnare;
42 import org.apache.hadoop.hbase.executor.EventHandler;
43 import org.apache.hadoop.hbase.executor.EventType;
44 import org.apache.hadoop.hbase.master.MasterServices;
45 import org.apache.hadoop.hbase.master.MetricsSnapshot;
46 import org.apache.hadoop.hbase.master.SnapshotSentinel;
47 import org.apache.hadoop.hbase.master.TableLockManager;
48 import org.apache.hadoop.hbase.master.TableLockManager.TableLock;
49 import org.apache.hadoop.hbase.monitoring.MonitoredTask;
50 import org.apache.hadoop.hbase.monitoring.TaskMonitor;
51 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
52 import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils;
53 import org.apache.hadoop.hbase.snapshot.SnapshotCreationException;
54 import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
55 import org.apache.hadoop.hbase.snapshot.SnapshotManifest;
56 import org.apache.hadoop.hbase.util.FSUtils;
57 import org.apache.hadoop.hbase.util.Pair;
58 import org.apache.hadoop.hbase.zookeeper.MetaTableLocator;
59 import org.apache.zookeeper.KeeperException;
60
61
62
63
64
65
66
67
68 @InterfaceAudience.Private
69 public abstract class TakeSnapshotHandler extends EventHandler implements SnapshotSentinel,
70 ForeignExceptionSnare {
71 private static final Log LOG = LogFactory.getLog(TakeSnapshotHandler.class);
72
73 private volatile boolean finished;
74
75
76 protected final MasterServices master;
77 protected final MetricsSnapshot metricsSnapshot = new MetricsSnapshot();
78 protected final SnapshotDescription snapshot;
79 protected final Configuration conf;
80 protected final FileSystem rootFs;
81 protected final FileSystem workingDirFs;
82 protected final Path rootDir;
83 private final Path snapshotDir;
84 protected final Path workingDir;
85 private final MasterSnapshotVerifier verifier;
86 protected final ForeignExceptionDispatcher monitor;
87 protected final TableLockManager tableLockManager;
88 protected final TableLock tableLock;
89 protected final MonitoredTask status;
90 protected final TableName snapshotTable;
91 protected final SnapshotManifest snapshotManifest;
92 protected final SnapshotManager snapshotManager;
93
94 protected HTableDescriptor htd;
95
96
97
98
99
100
101
102
103
104 public TakeSnapshotHandler(SnapshotDescription snapshot, final MasterServices masterServices,
105 final SnapshotManager snapshotManager) throws IOException {
106 super(masterServices, EventType.C_M_SNAPSHOT_TABLE);
107 assert snapshot != null : "SnapshotDescription must not be nul1";
108 assert masterServices != null : "MasterServices must not be nul1";
109 this.master = masterServices;
110 this.conf = this.master.getConfiguration();
111 this.rootDir = this.master.getMasterFileSystem().getRootDir();
112 this.workingDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(snapshot, rootDir, conf);
113 Preconditions.checkArgument(!SnapshotDescriptionUtils.isSubDirectoryOf(workingDir, rootDir) ||
114 SnapshotDescriptionUtils.isWithinDefaultWorkingDir(workingDir, conf),
115 "The working directory " + workingDir + " cannot be in the root directory unless it is "
116 + "within the default working directory");
117
118 this.snapshot = snapshot;
119 this.snapshotManager = snapshotManager;
120 this.snapshotTable = TableName.valueOf(snapshot.getTable());
121 this.rootFs = this.master.getMasterFileSystem().getFileSystem();
122 this.snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshot, rootDir);
123 this.workingDirFs = this.workingDir.getFileSystem(this.conf);
124 this.monitor = new ForeignExceptionDispatcher(snapshot.getName());
125 this.snapshotManifest = SnapshotManifest.create(conf, rootFs, workingDir, snapshot, monitor);
126
127 this.tableLockManager = master.getTableLockManager();
128 this.tableLock = this.tableLockManager.writeLock(
129 snapshotTable,
130 EventType.C_M_SNAPSHOT_TABLE.toString());
131
132
133 this.verifier = new MasterSnapshotVerifier(masterServices, snapshot, workingDirFs);
134
135 this.status = TaskMonitor.get().createStatus(
136 "Taking " + snapshot.getType() + " snapshot on table: " + snapshotTable);
137 }
138
139 private HTableDescriptor loadTableDescriptor()
140 throws FileNotFoundException, IOException {
141 HTableDescriptor htd =
142 this.master.getTableDescriptors().get(snapshotTable);
143 if (htd == null) {
144 throw new IOException("HTableDescriptor missing for " + snapshotTable);
145 }
146 return htd;
147 }
148
149 @Override
150 public TakeSnapshotHandler prepare() throws Exception {
151 super.prepare();
152 this.tableLock.acquire();
153
154 boolean success = false;
155 try {
156 this.htd = loadTableDescriptor();
157 success = true;
158 } finally {
159 if (!success) {
160 releaseTableLock();
161 }
162 }
163
164 return this;
165 }
166
167
168
169
170
171 @Override
172 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="REC_CATCH_EXCEPTION",
173 justification="Intentional")
174 public void process() {
175 String msg = "Running " + snapshot.getType() + " table snapshot " + snapshot.getName() + " "
176 + eventType + " on table " + snapshotTable;
177 LOG.info(msg);
178 status.setStatus(msg);
179 try {
180
181
182
183
184 SnapshotDescriptionUtils.writeSnapshotInfo(snapshot, workingDir, workingDirFs);
185 snapshotManifest.addTableDescriptor(this.htd);
186 monitor.rethrowException();
187
188 List<Pair<HRegionInfo, ServerName>> regionsAndLocations;
189 if (TableName.META_TABLE_NAME.equals(snapshotTable)) {
190 regionsAndLocations = new MetaTableLocator().getMetaRegionsAndLocations(
191 server.getZooKeeper());
192 } else {
193 regionsAndLocations = MetaTableAccessor.getTableRegionsAndLocations(
194 server.getZooKeeper(), server.getConnection(), snapshotTable, false);
195 }
196
197
198 snapshotRegions(regionsAndLocations);
199 monitor.rethrowException();
200
201
202 Set<String> serverNames = new HashSet<String>();
203 for (Pair<HRegionInfo, ServerName> p : regionsAndLocations) {
204 if (p != null && p.getFirst() != null && p.getSecond() != null) {
205 HRegionInfo hri = p.getFirst();
206 if (hri.isOffline() && (hri.isSplit() || hri.isSplitParent())) continue;
207 serverNames.add(p.getSecond().toString());
208 }
209 }
210
211
212 status.setStatus("Consolidate snapshot: " + snapshot.getName());
213 snapshotManifest.consolidate();
214
215
216 status.setStatus("Verifying snapshot: " + snapshot.getName());
217 verifier.verifySnapshot(this.workingDir, serverNames);
218
219
220 completeSnapshot(this.snapshotDir, this.workingDir, this.rootFs, this.workingDirFs);
221 msg = "Snapshot " + snapshot.getName() + " of table " + snapshotTable + " completed";
222 status.markComplete(msg);
223 LOG.info(msg);
224 metricsSnapshot.addSnapshot(status.getCompletionTimestamp() - status.getStartTime());
225 } catch (Exception e) {
226 status.abort("Failed to complete snapshot " + snapshot.getName() + " on table " +
227 snapshotTable + " because " + e.getMessage());
228 String reason = "Failed taking snapshot " + ClientSnapshotDescriptionUtils.toString(snapshot)
229 + " due to exception:" + e.getMessage();
230 LOG.error(reason, e);
231 ForeignException ee = new ForeignException(reason, e);
232 monitor.receive(ee);
233
234 cancel(reason);
235 } finally {
236 LOG.debug("Launching cleanup of working dir:" + workingDir);
237 try {
238
239
240 if (!workingDirFs.delete(workingDir, true)) {
241 LOG.error("Couldn't delete snapshot working directory:" + workingDir);
242 }
243 } catch (IOException e) {
244 LOG.error("Couldn't delete snapshot working directory:" + workingDir);
245 }
246 releaseTableLock();
247 }
248 }
249
250 protected void releaseTableLock() {
251 if (this.tableLock != null) {
252 try {
253 this.tableLock.release();
254 } catch (IOException ex) {
255 LOG.warn("Could not release the table lock", ex);
256 }
257 }
258 }
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273 public void completeSnapshot(Path snapshotDir, Path workingDir, FileSystem fs,
274 FileSystem workingDirFs) throws SnapshotCreationException, IOException {
275 SnapshotDescriptionUtils.completeSnapshot(snapshotDir, workingDir, fs, workingDirFs, conf);
276 finished = true;
277 }
278
279
280
281
282 protected abstract void snapshotRegions(List<Pair<HRegionInfo, ServerName>> regions)
283 throws IOException, KeeperException;
284
285
286
287
288 protected void snapshotDisabledRegion(final HRegionInfo regionInfo)
289 throws IOException {
290 snapshotManifest.addRegion(FSUtils.getTableDir(rootDir, snapshotTable), regionInfo);
291 monitor.rethrowException();
292 status.setStatus("Completed referencing HFiles for offline region " + regionInfo.toString() +
293 " of table: " + snapshotTable);
294 }
295
296 @Override
297 public void cancel(String why) {
298 if (finished) return;
299
300 this.finished = true;
301 LOG.info("Stop taking snapshot=" + ClientSnapshotDescriptionUtils.toString(snapshot) +
302 " because: " + why);
303 CancellationException ce = new CancellationException(why);
304 monitor.receive(new ForeignException(master.getServerName().toString(), ce));
305 }
306
307 @Override
308 public boolean isFinished() {
309 return finished;
310 }
311
312 @Override
313 public long getCompletionTimestamp() {
314 return this.status.getCompletionTimestamp();
315 }
316
317 @Override
318 public SnapshotDescription getSnapshot() {
319 return snapshot;
320 }
321
322 @Override
323 public ForeignException getExceptionIfFailed() {
324 return monitor.getException();
325 }
326
327 @Override
328 public void rethrowExceptionIfFailed() throws ForeignException {
329 monitor.rethrowException();
330 }
331
332 @Override
333 public void rethrowException() throws ForeignException {
334 monitor.rethrowException();
335 }
336
337 @Override
338 public boolean hasException() {
339 return monitor.hasException();
340 }
341
342 @Override
343 public ForeignException getException() {
344 return monitor.getException();
345 }
346
347 }