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
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.hadoop.classification.InterfaceAudience;
30 import org.apache.hadoop.conf.Configuration;
31 import org.apache.hadoop.fs.FileSystem;
32 import org.apache.hadoop.fs.Path;
33 import org.apache.hadoop.hbase.HRegionInfo;
34 import org.apache.hadoop.hbase.HTableDescriptor;
35 import org.apache.hadoop.hbase.ServerName;
36 import org.apache.hadoop.hbase.catalog.MetaReader;
37 import org.apache.hadoop.hbase.errorhandling.ForeignException;
38 import org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher;
39 import org.apache.hadoop.hbase.errorhandling.ForeignExceptionSnare;
40 import org.apache.hadoop.hbase.exceptions.SnapshotCreationException;
41 import org.apache.hadoop.hbase.executor.EventHandler;
42 import org.apache.hadoop.hbase.executor.EventType;
43 import org.apache.hadoop.hbase.master.MasterServices;
44 import org.apache.hadoop.hbase.master.SnapshotSentinel;
45 import org.apache.hadoop.hbase.master.TableLockManager;
46 import org.apache.hadoop.hbase.master.TableLockManager.TableLock;
47 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
48 import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils;
49 import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
50 import org.apache.hadoop.hbase.snapshot.TableInfoCopyTask;
51 import org.apache.hadoop.hbase.util.Bytes;
52 import org.apache.hadoop.hbase.util.Pair;
53 import org.apache.zookeeper.KeeperException;
54
55
56
57
58
59
60
61
62 @InterfaceAudience.Private
63 public abstract class TakeSnapshotHandler extends EventHandler implements SnapshotSentinel,
64 ForeignExceptionSnare {
65 private static final Log LOG = LogFactory.getLog(TakeSnapshotHandler.class);
66
67 private volatile boolean finished;
68
69
70 protected final MasterServices master;
71 protected final SnapshotDescription snapshot;
72 protected final Configuration conf;
73 protected final FileSystem fs;
74 protected final Path rootDir;
75 private final Path snapshotDir;
76 protected final Path workingDir;
77 private final MasterSnapshotVerifier verifier;
78 protected final ForeignExceptionDispatcher monitor;
79 protected final TableLockManager tableLockManager;
80 protected final TableLock tableLock;
81
82
83
84
85
86
87 public TakeSnapshotHandler(SnapshotDescription snapshot,
88 final MasterServices masterServices) throws IOException {
89 super(masterServices, EventType.C_M_SNAPSHOT_TABLE);
90 assert snapshot != null : "SnapshotDescription must not be nul1";
91 assert masterServices != null : "MasterServices must not be nul1";
92
93 this.master = masterServices;
94 this.snapshot = snapshot;
95 this.conf = this.master.getConfiguration();
96 this.fs = this.master.getMasterFileSystem().getFileSystem();
97 this.rootDir = this.master.getMasterFileSystem().getRootDir();
98 this.snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshot, rootDir);
99 this.workingDir = SnapshotDescriptionUtils.getWorkingSnapshotDir(snapshot, rootDir);
100 this.monitor = new ForeignExceptionDispatcher();
101
102 this.tableLockManager = master.getTableLockManager();
103 this.tableLock = this.tableLockManager.writeLock(Bytes.toBytes(snapshot.getTable())
104 , EventType.C_M_SNAPSHOT_TABLE.toString());
105
106
107 this.verifier = new MasterSnapshotVerifier(masterServices, snapshot, rootDir);
108 }
109
110 private HTableDescriptor loadTableDescriptor()
111 throws FileNotFoundException, IOException {
112 final String name = snapshot.getTable();
113 HTableDescriptor htd =
114 this.master.getTableDescriptors().get(name);
115 if (htd == null) {
116 throw new IOException("HTableDescriptor missing for " + name);
117 }
118 return htd;
119 }
120
121 public TakeSnapshotHandler prepare() throws Exception {
122 super.prepare();
123 loadTableDescriptor();
124
125 this.tableLock.acquire();
126
127 return this;
128 }
129
130
131
132
133
134 @Override
135 public void process() {
136 LOG.info("Running table snapshot operation " + eventType + " on table " + snapshot.getTable());
137 try {
138
139
140
141
142 SnapshotDescriptionUtils.writeSnapshotInfo(snapshot, workingDir, this.fs);
143 new TableInfoCopyTask(monitor, snapshot, fs, rootDir).call();
144 monitor.rethrowException();
145
146 List<Pair<HRegionInfo, ServerName>> regionsAndLocations =
147 MetaReader.getTableRegionsAndLocations(this.server.getCatalogTracker(),
148 Bytes.toBytes(snapshot.getTable()), true);
149
150
151 snapshotRegions(regionsAndLocations);
152
153
154 Set<String> serverNames = new HashSet<String>();
155 for (Pair<HRegionInfo, ServerName> p : regionsAndLocations) {
156 serverNames.add(p.getSecond().toString());
157 }
158
159
160 verifier.verifySnapshot(this.workingDir, serverNames);
161
162
163 completeSnapshot(this.snapshotDir, this.workingDir, this.fs);
164 } catch (Exception e) {
165 String reason = "Failed taking snapshot " + ClientSnapshotDescriptionUtils.toString(snapshot)
166 + " due to exception:" + e.getMessage();
167 LOG.error(reason, e);
168 ForeignException ee = new ForeignException(reason, e);
169 monitor.receive(ee);
170
171 cancel("Failed to take snapshot '" + ClientSnapshotDescriptionUtils.toString(snapshot)
172 + "' due to exception");
173 } finally {
174 LOG.debug("Launching cleanup of working dir:" + workingDir);
175 try {
176
177
178 if (fs.exists(workingDir) && !this.fs.delete(workingDir, true)) {
179 LOG.error("Couldn't delete snapshot working directory:" + workingDir);
180 }
181 } catch (IOException e) {
182 LOG.error("Couldn't delete snapshot working directory:" + workingDir);
183 }
184 releaseTableLock();
185 }
186 }
187
188 protected void releaseTableLock() {
189 if (this.tableLock != null) {
190 try {
191 this.tableLock.release();
192 } catch (IOException ex) {
193 LOG.warn("Could not release the table lock", ex);
194 }
195 }
196 }
197
198
199
200
201
202
203
204
205
206
207 public void completeSnapshot(Path snapshotDir, Path workingDir, FileSystem fs)
208 throws SnapshotCreationException, IOException {
209 LOG.debug("Sentinel is done, just moving the snapshot from " + workingDir + " to "
210 + snapshotDir);
211 if (!fs.rename(workingDir, snapshotDir)) {
212 throw new SnapshotCreationException("Failed to move working directory(" + workingDir
213 + ") to completed directory(" + snapshotDir + ").");
214 }
215 finished = true;
216 }
217
218
219
220
221 protected abstract void snapshotRegions(List<Pair<HRegionInfo, ServerName>> regions)
222 throws IOException, KeeperException;
223
224 @Override
225 public void cancel(String why) {
226 if (finished) return;
227
228 this.finished = true;
229 LOG.info("Stop taking snapshot=" + ClientSnapshotDescriptionUtils.toString(snapshot) + " because: "
230 + why);
231 CancellationException ce = new CancellationException(why);
232 monitor.receive(new ForeignException(master.getServerName().toString(), ce));
233 }
234
235 @Override
236 public boolean isFinished() {
237 return finished;
238 }
239
240 @Override
241 public SnapshotDescription getSnapshot() {
242 return snapshot;
243 }
244
245 @Override
246 public ForeignException getExceptionIfFailed() {
247 return monitor.getException();
248 }
249
250 @Override
251 public void rethrowException() throws ForeignException {
252 monitor.rethrowException();
253 }
254
255 @Override
256 public boolean hasException() {
257 return monitor.hasException();
258 }
259
260 @Override
261 public ForeignException getException() {
262 return monitor.getException();
263 }
264
265 }