1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.regionserver.handler;
21
22 import java.io.IOException;
23 import java.util.concurrent.atomic.AtomicBoolean;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.apache.hadoop.hbase.HRegionInfo;
28 import org.apache.hadoop.hbase.Server;
29 import org.apache.hadoop.hbase.executor.EventHandler;
30 import org.apache.hadoop.hbase.regionserver.HRegion;
31 import org.apache.hadoop.hbase.regionserver.RegionServerServices;
32 import org.apache.hadoop.hbase.util.CancelableProgressable;
33 import org.apache.hadoop.hbase.zookeeper.ZKAssign;
34 import org.apache.zookeeper.KeeperException;
35
36
37
38
39
40
41 public class OpenRegionHandler extends EventHandler {
42 private static final Log LOG = LogFactory.getLog(OpenRegionHandler.class);
43
44 private final RegionServerServices rsServices;
45
46 private final HRegionInfo regionInfo;
47
48
49
50
51 private volatile int version = -1;
52
53 public OpenRegionHandler(final Server server,
54 final RegionServerServices rsServices, HRegionInfo regionInfo) {
55 this(server, rsServices, regionInfo, EventType.M_RS_OPEN_REGION);
56 }
57
58 protected OpenRegionHandler(final Server server,
59 final RegionServerServices rsServices, final HRegionInfo regionInfo,
60 EventType eventType) {
61 super(server, eventType);
62 this.rsServices = rsServices;
63 this.regionInfo = regionInfo;
64 }
65
66 public HRegionInfo getRegionInfo() {
67 return regionInfo;
68 }
69
70 @Override
71 public void process() throws IOException {
72 final String name = regionInfo.getRegionNameAsString();
73 LOG.debug("Processing open of " + name);
74 if (this.server.isStopped() || this.rsServices.isStopping()) {
75 LOG.info("Server stopping or stopped, skipping open of " + name);
76 return;
77 }
78 final String encodedName = regionInfo.getEncodedName();
79
80
81 HRegion region = this.rsServices.getFromOnlineRegions(encodedName);
82 if (region != null) {
83 LOG.warn("Attempted open of " + name +
84 " but already online on this server");
85 return;
86 }
87
88
89
90 if (!transitionZookeeperOfflineToOpening(encodedName)) {
91 LOG.warn("Region was hijacked? It no longer exists, encodedName=" +
92 encodedName);
93 return;
94 }
95
96
97
98 region = openRegion();
99 if (region == null) return;
100 boolean failed = true;
101 if (tickleOpening("post_region_open")) {
102 if (updateMeta(region)) failed = false;
103 }
104
105 if (failed || this.server.isStopped() || this.rsServices.isStopping()) {
106 cleanupFailedOpen(region);
107 return;
108 }
109
110 if (!transitionToOpened(region)) {
111 cleanupFailedOpen(region);
112 return;
113 }
114
115
116 LOG.debug("Opened " + name);
117 }
118
119
120
121
122
123
124
125
126 private boolean updateMeta(final HRegion r) {
127 if (this.server.isStopped() || this.rsServices.isStopping()) {
128 return false;
129 }
130
131
132 final AtomicBoolean signaller = new AtomicBoolean(false);
133 PostOpenDeployTasksThread t = new PostOpenDeployTasksThread(r,
134 this.server, this.rsServices, signaller);
135 t.start();
136 int assignmentTimeout = this.server.getConfiguration().
137 getInt("hbase.master.assignment.timeoutmonitor.period", 10000);
138
139
140 long timeout = assignmentTimeout * 10;
141 long now = System.currentTimeMillis();
142 long endTime = now + timeout;
143
144
145 long period = Math.max(1, assignmentTimeout/ 3);
146 long lastUpdate = now;
147 while (!signaller.get() && t.isAlive() && !this.server.isStopped() &&
148 !this.rsServices.isStopping() && (endTime > now)) {
149 long elapsed = now - lastUpdate;
150 if (elapsed > period) {
151
152 lastUpdate = now;
153 tickleOpening("post_open_deploy");
154 }
155 synchronized (signaller) {
156 try {
157 signaller.wait(period);
158 } catch (InterruptedException e) {
159
160 }
161 }
162 now = System.currentTimeMillis();
163 }
164
165
166 if (t.isAlive()) {
167 if (!signaller.get()) {
168
169 LOG.debug("Interrupting thread " + t);
170 t.interrupt();
171 }
172 try {
173 t.join();
174 } catch (InterruptedException ie) {
175 LOG.warn("Interrupted joining " +
176 r.getRegionInfo().getRegionNameAsString(), ie);
177 Thread.currentThread().interrupt();
178 }
179 }
180
181
182 return !t.interrupted() && t.getException() == null;
183 }
184
185
186
187
188
189
190 static class PostOpenDeployTasksThread extends Thread {
191 private Exception exception = null;
192 private final Server server;
193 private final RegionServerServices services;
194 private final HRegion region;
195 private final AtomicBoolean signaller;
196
197 PostOpenDeployTasksThread(final HRegion region, final Server server,
198 final RegionServerServices services, final AtomicBoolean signaller) {
199 super("PostOpenDeployTasks:" + region.getRegionInfo().getEncodedName());
200 this.setDaemon(true);
201 this.server = server;
202 this.services = services;
203 this.region = region;
204 this.signaller = signaller;
205 }
206
207 public void run() {
208 try {
209 this.services.postOpenDeployTasks(this.region,
210 this.server.getCatalogTracker(), false);
211 } catch (Exception e) {
212 LOG.warn("Exception running postOpenDeployTasks; region=" +
213 this.region.getRegionInfo().getEncodedName(), e);
214 this.exception = e;
215 }
216
217 this.signaller.set(true);
218 synchronized (this.signaller) {
219 this.signaller.notify();
220 }
221 }
222
223
224
225
226 Exception getException() {
227 return this.exception;
228 }
229 }
230
231
232
233
234
235
236 private boolean transitionToOpened(final HRegion r) throws IOException {
237 boolean result = false;
238 HRegionInfo hri = r.getRegionInfo();
239 final String name = hri.getRegionNameAsString();
240
241 try {
242 if (ZKAssign.transitionNodeOpened(this.server.getZooKeeper(), hri,
243 this.server.getServerName(), this.version) == -1) {
244 LOG.warn("Completed the OPEN of region " + name +
245 " but when transitioning from " +
246 " OPENING to OPENED got a version mismatch, someone else clashed " +
247 "so now unassigning -- closing region");
248 } else {
249 result = true;
250 }
251 } catch (KeeperException e) {
252 LOG.error("Failed transitioning node " + name +
253 " from OPENING to OPENED -- closing region", e);
254 }
255 return result;
256 }
257
258
259
260
261 HRegion openRegion() {
262 HRegion region = null;
263 try {
264
265
266 region = HRegion.openHRegion(this.regionInfo, this.rsServices.getWAL(),
267 this.server.getConfiguration(), this.rsServices.getFlushRequester(),
268 new CancelableProgressable() {
269 public boolean progress() {
270
271
272
273 return tickleOpening("open_region_progress");
274 }
275 });
276 } catch (IOException e) {
277
278
279 LOG.error("Failed open of region=" +
280 this.regionInfo.getRegionNameAsString(), e);
281 }
282 return region;
283 }
284
285 private void cleanupFailedOpen(final HRegion region) throws IOException {
286 if (region != null) region.close();
287 this.rsServices.removeFromOnlineRegions(regionInfo.getEncodedName());
288 }
289
290
291
292
293
294
295
296 boolean transitionZookeeperOfflineToOpening(final String encodedName) {
297
298 try {
299
300 this.version =
301 ZKAssign.transitionNodeOpening(server.getZooKeeper(),
302 regionInfo, server.getServerName());
303 } catch (KeeperException e) {
304 LOG.error("Error transition from OFFLINE to OPENING for region=" +
305 encodedName, e);
306 }
307 boolean b = isGoodVersion();
308 if (!b) {
309 LOG.warn("Failed transition from OFFLINE to OPENING for region=" +
310 encodedName);
311 }
312 return b;
313 }
314
315
316
317
318
319
320
321 boolean tickleOpening(final String context) {
322
323 if (!isGoodVersion()) return false;
324 String encodedName = this.regionInfo.getEncodedName();
325 try {
326 this.version =
327 ZKAssign.retransitionNodeOpening(server.getZooKeeper(),
328 this.regionInfo, this.server.getServerName(), this.version);
329 } catch (KeeperException e) {
330 server.abort("Exception refreshing OPENING; region=" + encodedName +
331 ", context=" + context, e);
332 this.version = -1;
333 }
334 boolean b = isGoodVersion();
335 if (!b) {
336 LOG.warn("Failed refreshing OPENING; region=" + encodedName +
337 ", context=" + context);
338 }
339 return b;
340 }
341
342 private boolean isGoodVersion() {
343 return this.version != -1;
344 }
345 }