1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.regionserver.snapshot;
19
20 import java.io.IOException;
21 import java.util.List;
22 import java.util.concurrent.Callable;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.apache.hadoop.hbase.classification.InterfaceAudience;
27 import org.apache.hadoop.hbase.classification.InterfaceStability;
28 import org.apache.hadoop.hbase.client.IsolationLevel;
29 import org.apache.hadoop.hbase.errorhandling.ForeignException;
30 import org.apache.hadoop.hbase.errorhandling.ForeignExceptionDispatcher;
31 import org.apache.hadoop.hbase.procedure.ProcedureMember;
32 import org.apache.hadoop.hbase.procedure.Subprocedure;
33 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
34 import org.apache.hadoop.hbase.regionserver.HRegion;
35 import org.apache.hadoop.hbase.regionserver.Region;
36 import org.apache.hadoop.hbase.regionserver.Region.FlushResult;
37 import org.apache.hadoop.hbase.regionserver.Region.Operation;
38 import org.apache.hadoop.hbase.regionserver.snapshot.RegionServerSnapshotManager.SnapshotSubprocedurePool;
39 import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils;
40
41
42
43
44
45
46
47
48 @InterfaceAudience.Private
49 @InterfaceStability.Unstable
50 public class FlushSnapshotSubprocedure extends Subprocedure {
51 private static final Log LOG = LogFactory.getLog(FlushSnapshotSubprocedure.class);
52
53 private final List<Region> regions;
54 private final SnapshotDescription snapshot;
55 private final SnapshotSubprocedurePool taskManager;
56 private boolean snapshotSkipFlush = false;
57
58
59 final static int MAX_RETRIES = 3;
60
61 public FlushSnapshotSubprocedure(ProcedureMember member,
62 ForeignExceptionDispatcher errorListener, long wakeFrequency, long timeout,
63 List<Region> regions, SnapshotDescription snapshot,
64 SnapshotSubprocedurePool taskManager) {
65 super(member, snapshot.getName(), errorListener, wakeFrequency, timeout);
66 this.snapshot = snapshot;
67
68 if (this.snapshot.getType() == SnapshotDescription.Type.SKIPFLUSH) {
69 snapshotSkipFlush = true;
70 }
71 this.regions = regions;
72 this.taskManager = taskManager;
73 }
74
75
76
77
78 public static class RegionSnapshotTask implements Callable<Void> {
79 private Region region;
80 private boolean skipFlush;
81 private ForeignExceptionDispatcher monitor;
82 private SnapshotDescription snapshotDesc;
83
84 public RegionSnapshotTask(Region region, SnapshotDescription snapshotDesc,
85 boolean skipFlush, ForeignExceptionDispatcher monitor) {
86 this.region = region;
87 this.skipFlush = skipFlush;
88 this.monitor = monitor;
89 this.snapshotDesc = snapshotDesc;
90 }
91
92 @Override
93 public Void call() throws Exception {
94
95
96
97
98
99 LOG.debug("Starting snapshot operation on " + region);
100 region.startRegionOperation(Operation.SNAPSHOT);
101 try {
102 if (skipFlush) {
103
104
105
106
107
108
109
110 LOG.debug("take snapshot without flush memstore first");
111 } else {
112 LOG.debug("Flush Snapshotting region " + region.toString() + " started...");
113 boolean succeeded = false;
114 long readPt = region.getReadpoint(IsolationLevel.READ_COMMITTED);
115 for (int i = 0; i < MAX_RETRIES; i++) {
116 FlushResult res = region.flush(true);
117 if (res.getResult() == FlushResult.Result.CANNOT_FLUSH) {
118 if (region instanceof HRegion) {
119 HRegion hreg = (HRegion) region;
120
121
122 hreg.waitForFlushes();
123 }
124 if (region.getMaxFlushedSeqId() >= readPt) {
125
126 succeeded = true;
127 break;
128 }
129 } else {
130 succeeded = true;
131 break;
132 }
133 }
134 if (!succeeded) {
135 throw new IOException("Unable to complete flush after " + MAX_RETRIES + " attempts");
136 }
137 }
138 ((HRegion)region).addRegionToSnapshot(snapshotDesc, monitor);
139 if (skipFlush) {
140 LOG.debug("... SkipFlush Snapshotting region " + region.toString() + " completed.");
141 } else {
142 LOG.debug("... Flush Snapshotting region " + region.toString() + " completed.");
143 }
144 } finally {
145 LOG.debug("Closing snapshot operation on " + region);
146 ((HRegion)region).closeRegionOperation(Operation.SNAPSHOT);
147 }
148 return null;
149 }
150 }
151
152 private void flushSnapshot() throws ForeignException {
153 if (regions.isEmpty()) {
154
155 return;
156 }
157
158 monitor.rethrowException();
159
160
161 if (taskManager.hasTasks()) {
162 throw new IllegalStateException("Attempting to take snapshot "
163 + ClientSnapshotDescriptionUtils.toString(snapshot)
164 + " but we currently have outstanding tasks");
165 }
166
167
168 for (Region region : regions) {
169
170 taskManager.submitTask(new RegionSnapshotTask(region, snapshot, snapshotSkipFlush, monitor));
171 monitor.rethrowException();
172 }
173
174
175 LOG.debug("Flush Snapshot Tasks submitted for " + regions.size() + " regions");
176 try {
177 taskManager.waitForOutstandingTasks();
178 } catch (InterruptedException e) {
179 LOG.error("got interrupted exception for " + getMemberName());
180 throw new ForeignException(getMemberName(), e);
181 }
182 }
183
184
185
186
187 @Override
188 public void acquireBarrier() throws ForeignException {
189
190 }
191
192
193
194
195 @Override
196 public byte[] insideBarrier() throws ForeignException {
197 flushSnapshot();
198 return new byte[0];
199 }
200
201
202
203
204 @Override
205 public void cleanup(Exception e) {
206 LOG.info("Aborting all online FLUSH snapshot subprocedure task threads for '"
207 + snapshot.getName() + "' due to error", e);
208 try {
209 taskManager.cancelTasks();
210 } catch (InterruptedException e1) {
211 Thread.currentThread().interrupt();
212 }
213 }
214
215
216
217
218 public void releaseBarrier() {
219
220 }
221
222 }