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