1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.regionserver.handler;
20
21 import java.io.IOException;
22 import java.util.concurrent.atomic.AtomicBoolean;
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.HRegionInfo;
28 import org.apache.hadoop.hbase.HTableDescriptor;
29 import org.apache.hadoop.hbase.Server;
30 import org.apache.hadoop.hbase.coordination.OpenRegionCoordination;
31 import org.apache.hadoop.hbase.executor.EventHandler;
32 import org.apache.hadoop.hbase.executor.EventType;
33 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionStateTransition.TransitionCode;
34 import org.apache.hadoop.hbase.regionserver.HRegion;
35 import org.apache.hadoop.hbase.regionserver.RegionServerAccounting;
36 import org.apache.hadoop.hbase.regionserver.RegionServerServices;
37 import org.apache.hadoop.hbase.regionserver.RegionServerServices.PostOpenDeployContext;
38 import org.apache.hadoop.hbase.util.CancelableProgressable;
39 import org.apache.hadoop.hbase.util.ConfigUtil;
40
41
42
43
44
45 @InterfaceAudience.Private
46 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="JLM_JSR166_UTILCONCURRENT_MONITORENTER",
47 justification="Use of an atomic type both as monitor and condition variable is intended")
48 public class OpenRegionHandler extends EventHandler {
49 private static final Log LOG = LogFactory.getLog(OpenRegionHandler.class);
50
51 protected final RegionServerServices rsServices;
52
53 private final HRegionInfo regionInfo;
54 private final HTableDescriptor htd;
55 private final long masterSystemTime;
56
57 private OpenRegionCoordination coordination;
58 private OpenRegionCoordination.OpenRegionDetails ord;
59
60 private final boolean useZKForAssignment;
61
62 public OpenRegionHandler(final Server server,
63 final RegionServerServices rsServices, HRegionInfo regionInfo,
64 HTableDescriptor htd, long masterSystemTime, OpenRegionCoordination coordination,
65 OpenRegionCoordination.OpenRegionDetails ord) {
66 this(server, rsServices, regionInfo, htd, EventType.M_RS_OPEN_REGION,
67 masterSystemTime, coordination, ord);
68 }
69
70 protected OpenRegionHandler(final Server server,
71 final RegionServerServices rsServices, final HRegionInfo regionInfo,
72 final HTableDescriptor htd, EventType eventType, long masterSystemTime,
73 OpenRegionCoordination coordination, OpenRegionCoordination.OpenRegionDetails ord) {
74 super(server, eventType);
75 this.rsServices = rsServices;
76 this.regionInfo = regionInfo;
77 this.htd = htd;
78 this.coordination = coordination;
79 this.ord = ord;
80 useZKForAssignment = ConfigUtil.useZKForAssignment(server.getConfiguration());
81 this.masterSystemTime = masterSystemTime;
82 }
83
84 public HRegionInfo getRegionInfo() {
85 return regionInfo;
86 }
87
88 @Override
89 public void process() throws IOException {
90 boolean openSuccessful = false;
91 boolean transitionedToOpening = false;
92 final String regionName = regionInfo.getRegionNameAsString();
93 HRegion region = null;
94
95 try {
96 if (this.server.isStopped() || this.rsServices.isStopping()) {
97 return;
98 }
99 final String encodedName = regionInfo.getEncodedName();
100
101
102
103
104
105
106
107 if (this.rsServices.getFromOnlineRegions(encodedName) != null) {
108 LOG.error("Region " + encodedName +
109 " was already online when we started processing the opening. " +
110 "Marking this new attempt as failed");
111 return;
112 }
113
114
115
116
117 if (!isRegionStillOpening()){
118 LOG.error("Region " + encodedName + " opening cancelled");
119 return;
120 }
121
122 if (useZKForAssignment
123 && !coordination.transitionFromOfflineToOpening(regionInfo, ord)) {
124 LOG.warn("Region was hijacked? Opening cancelled for encodedName=" + encodedName);
125
126 return;
127 }
128 transitionedToOpening = true;
129
130
131 region = openRegion();
132 if (region == null) {
133 return;
134 }
135
136 boolean failed = true;
137 if (isRegionStillOpening() && (!useZKForAssignment ||
138 coordination.tickleOpening(ord, regionInfo, rsServices, "post_region_open"))) {
139 if (updateMeta(region, masterSystemTime)) {
140 failed = false;
141 }
142 }
143 if (failed || this.server.isStopped() ||
144 this.rsServices.isStopping()) {
145 return;
146 }
147
148 if (!isRegionStillOpening() ||
149 (useZKForAssignment && !coordination.transitionToOpened(region, ord))) {
150
151
152
153
154
155 return;
156 }
157
158
159
160
161
162
163
164
165
166
167
168 this.rsServices.addToOnlineRegions(region);
169 openSuccessful = true;
170
171
172 LOG.debug("Opened " + regionName + " on " +
173 this.server.getServerName());
174
175
176 } finally {
177
178 if (!openSuccessful) {
179 doCleanUpOnFailedOpen(region, transitionedToOpening, ord);
180 }
181 final Boolean current = this.rsServices.getRegionsInTransitionInRS().
182 remove(this.regionInfo.getEncodedNameAsBytes());
183
184
185
186
187
188
189
190
191 if (openSuccessful) {
192 if (current == null) {
193 LOG.error("Bad state: we've just opened a region that was NOT in transition. Region="
194 + regionName);
195 } else if (Boolean.FALSE.equals(current)) {
196
197 LOG.error("Race condition: we've finished to open a region, while a close was requested "
198 + " on region=" + regionName + ". It can be a critical error, as a region that"
199 + " should be closed is now opened. Closing it now");
200 cleanupFailedOpen(region);
201 }
202 }
203 }
204 }
205
206 private void doCleanUpOnFailedOpen(HRegion region, boolean transitionedToOpening,
207 OpenRegionCoordination.OpenRegionDetails ord)
208 throws IOException {
209 if (transitionedToOpening) {
210 try {
211 if (region != null) {
212 cleanupFailedOpen(region);
213 }
214 } finally {
215 if (!useZKForAssignment) {
216 rsServices.reportRegionStateTransition(TransitionCode.FAILED_OPEN, regionInfo);
217 } else {
218
219
220 coordination.tryTransitionFromOpeningToFailedOpen(regionInfo, ord);
221 }
222 }
223 } else if (!useZKForAssignment) {
224 rsServices.reportRegionStateTransition(TransitionCode.FAILED_OPEN, regionInfo);
225 } else {
226
227
228 coordination.tryTransitionFromOfflineToFailedOpen(this.rsServices, regionInfo, ord);
229 }
230 }
231
232
233
234
235
236
237
238
239 boolean updateMeta(final HRegion r, long masterSystemTime) {
240 if (this.server.isStopped() || this.rsServices.isStopping()) {
241 return false;
242 }
243
244
245 final AtomicBoolean signaller = new AtomicBoolean(false);
246 PostOpenDeployTasksThread t = new PostOpenDeployTasksThread(r,
247 this.server, this.rsServices, signaller, masterSystemTime);
248 t.start();
249
250
251
252
253
254 long now = System.currentTimeMillis();
255 long lastUpdate = now;
256 boolean tickleOpening = true;
257 while (!signaller.get() && t.isAlive() && !this.server.isStopped() &&
258 !this.rsServices.isStopping() && isRegionStillOpening()) {
259 long elapsed = now - lastUpdate;
260 if (elapsed > 120000) {
261
262 lastUpdate = now;
263 if (useZKForAssignment) {
264 tickleOpening = coordination.tickleOpening(
265 ord, regionInfo, rsServices, "post_open_deploy");
266 }
267 }
268 synchronized (signaller) {
269 try {
270
271
272 if (!signaller.get()) signaller.wait(10000);
273 } catch (InterruptedException e) {
274
275 }
276 }
277 now = System.currentTimeMillis();
278 }
279
280
281 if (t.isAlive()) {
282 if (!signaller.get()) {
283
284 LOG.debug("Interrupting thread " + t);
285 t.interrupt();
286 }
287 try {
288 t.join();
289 } catch (InterruptedException ie) {
290 LOG.warn("Interrupted joining " +
291 r.getRegionInfo().getRegionNameAsString(), ie);
292 Thread.currentThread().interrupt();
293 }
294 }
295
296
297
298
299 return ((!Thread.interrupted() && t.getException() == null) && tickleOpening);
300 }
301
302
303
304
305
306
307 static class PostOpenDeployTasksThread extends Thread {
308 private Throwable exception = null;
309 private final Server server;
310 private final RegionServerServices services;
311 private final HRegion region;
312 private final AtomicBoolean signaller;
313 private final long masterSystemTime;
314
315 PostOpenDeployTasksThread(final HRegion region, final Server server,
316 final RegionServerServices services, final AtomicBoolean signaller, long masterSystemTime) {
317 super("PostOpenDeployTasks:" + region.getRegionInfo().getEncodedName());
318 this.setDaemon(true);
319 this.server = server;
320 this.services = services;
321 this.region = region;
322 this.signaller = signaller;
323 this.masterSystemTime = masterSystemTime;
324 }
325
326 @Override
327 public void run() {
328 try {
329 this.services.postOpenDeployTasks(new PostOpenDeployContext(region, masterSystemTime));
330 } catch (Throwable e) {
331 String msg = "Exception running postOpenDeployTasks; region=" +
332 this.region.getRegionInfo().getEncodedName();
333 this.exception = e;
334 if (e instanceof IOException
335 && isRegionStillOpening(region.getRegionInfo(), services)) {
336 server.abort(msg, e);
337 } else {
338 LOG.warn(msg, e);
339 }
340 }
341
342 this.signaller.set(true);
343 synchronized (this.signaller) {
344 this.signaller.notify();
345 }
346 }
347
348
349
350
351 Throwable getException() {
352 return this.exception;
353 }
354 }
355
356
357
358
359 HRegion openRegion() {
360 HRegion region = null;
361 try {
362
363
364 region = HRegion.openHRegion(this.regionInfo, this.htd,
365 this.rsServices.getWAL(this.regionInfo),
366 this.server.getConfiguration(),
367 this.rsServices,
368 new CancelableProgressable() {
369 @Override
370 public boolean progress() {
371 if (useZKForAssignment) {
372
373 return coordination.tickleOpening(ord, regionInfo,
374 rsServices, "open_region_progress");
375 }
376 if (!isRegionStillOpening()) {
377 LOG.warn("Open region aborted since it isn't opening any more");
378 return false;
379 }
380 return true;
381 }
382 });
383 } catch (Throwable t) {
384
385
386
387 LOG.error(
388 "Failed open of region=" + this.regionInfo.getRegionNameAsString()
389 + ", starting to roll back the global memstore size.", t);
390
391 if (this.rsServices != null) {
392 RegionServerAccounting rsAccounting =
393 this.rsServices.getRegionServerAccounting();
394 if (rsAccounting != null) {
395 rsAccounting.rollbackRegionReplayEditsSize(this.regionInfo.getRegionName());
396 }
397 }
398 }
399 return region;
400 }
401
402 void cleanupFailedOpen(final HRegion region) throws IOException {
403 if (region != null) {
404 byte[] encodedName = regionInfo.getEncodedNameAsBytes();
405 try {
406 rsServices.getRegionsInTransitionInRS().put(encodedName,Boolean.FALSE);
407 this.rsServices.removeFromOnlineRegions(region, null);
408 region.close();
409 } finally {
410 rsServices.getRegionsInTransitionInRS().remove(encodedName);
411 }
412 }
413 }
414
415 private static boolean isRegionStillOpening(
416 HRegionInfo regionInfo, RegionServerServices rsServices) {
417 byte[] encodedName = regionInfo.getEncodedNameAsBytes();
418 Boolean action = rsServices.getRegionsInTransitionInRS().get(encodedName);
419 return Boolean.TRUE.equals(action);
420 }
421
422 private boolean isRegionStillOpening() {
423 return isRegionStillOpening(regionInfo, rsServices);
424 }
425 }