1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.master.handler;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.concurrent.ExecutorService;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.apache.hadoop.classification.InterfaceAudience;
29 import org.apache.hadoop.hbase.TableName;
30 import org.apache.hadoop.hbase.HRegionInfo;
31 import org.apache.hadoop.hbase.Server;
32 import org.apache.hadoop.hbase.ServerName;
33 import org.apache.hadoop.hbase.TableNotDisabledException;
34 import org.apache.hadoop.hbase.TableNotFoundException;
35 import org.apache.hadoop.hbase.catalog.CatalogTracker;
36 import org.apache.hadoop.hbase.catalog.MetaReader;
37 import org.apache.hadoop.hbase.executor.EventHandler;
38 import org.apache.hadoop.hbase.executor.EventType;
39 import org.apache.hadoop.hbase.master.AssignmentManager;
40 import org.apache.hadoop.hbase.master.BulkAssigner;
41 import org.apache.hadoop.hbase.master.HMaster;
42 import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
43 import org.apache.hadoop.hbase.master.RegionPlan;
44 import org.apache.hadoop.hbase.master.RegionStates;
45 import org.apache.hadoop.hbase.master.ServerManager;
46 import org.apache.hadoop.hbase.master.TableLockManager;
47 import org.apache.hadoop.hbase.master.TableLockManager.TableLock;
48 import org.apache.hadoop.hbase.util.Pair;
49 import org.apache.zookeeper.KeeperException;
50 import org.cloudera.htrace.Trace;
51
52
53
54
55 @InterfaceAudience.Private
56 public class EnableTableHandler extends EventHandler {
57 private static final Log LOG = LogFactory.getLog(EnableTableHandler.class);
58 private final TableName tableName;
59 private final AssignmentManager assignmentManager;
60 private final TableLockManager tableLockManager;
61 private final CatalogTracker catalogTracker;
62 private boolean skipTableStateCheck = false;
63 private TableLock tableLock;
64
65 public EnableTableHandler(Server server, TableName tableName,
66 CatalogTracker catalogTracker, AssignmentManager assignmentManager,
67 TableLockManager tableLockManager, boolean skipTableStateCheck) {
68 super(server, EventType.C_M_ENABLE_TABLE);
69 this.tableName = tableName;
70 this.catalogTracker = catalogTracker;
71 this.assignmentManager = assignmentManager;
72 this.tableLockManager = tableLockManager;
73 this.skipTableStateCheck = skipTableStateCheck;
74 }
75
76 public EnableTableHandler prepare()
77 throws TableNotFoundException, TableNotDisabledException, IOException {
78
79 this.tableLock = this.tableLockManager.writeLock(tableName,
80 EventType.C_M_ENABLE_TABLE.toString());
81 this.tableLock.acquire();
82
83 boolean success = false;
84 try {
85
86 if (!MetaReader.tableExists(catalogTracker, tableName)) {
87
88 if (!this.skipTableStateCheck) {
89 throw new TableNotFoundException(tableName);
90 }
91 try {
92 this.assignmentManager.getZKTable().removeEnablingTable(tableName, true);
93 } catch (KeeperException e) {
94
95 LOG.warn("Failed to delete the ENABLING node for the table " + tableName
96 + ". The table will remain unusable. Run HBCK to manually fix the problem.");
97 }
98 }
99
100
101
102
103
104 if (!skipTableStateCheck) {
105 try {
106 if (!this.assignmentManager.getZKTable().checkDisabledAndSetEnablingTable
107 (this.tableName)) {
108 LOG.info("Table " + tableName + " isn't disabled; skipping enable");
109 throw new TableNotDisabledException(this.tableName);
110 }
111 } catch (KeeperException e) {
112 throw new IOException("Unable to ensure that the table will be" +
113 " enabling because of a ZooKeeper issue", e);
114 }
115 }
116 success = true;
117 } finally {
118 if (!success) {
119 releaseTableLock();
120 }
121 }
122 return this;
123 }
124
125 @Override
126 public String toString() {
127 String name = "UnknownServerName";
128 if(server != null && server.getServerName() != null) {
129 name = server.getServerName().toString();
130 }
131 return getClass().getSimpleName() + "-" + name + "-" + getSeqid() + "-" +
132 tableName;
133 }
134
135 @Override
136 public void process() {
137 try {
138 LOG.info("Attempting to enable the table " + this.tableName);
139 MasterCoprocessorHost cpHost = ((HMaster) this.server)
140 .getCoprocessorHost();
141 if (cpHost != null) {
142 cpHost.preEnableTableHandler(this.tableName);
143 }
144 handleEnableTable();
145 if (cpHost != null) {
146 cpHost.postEnableTableHandler(this.tableName);
147 }
148 } catch (IOException e) {
149 LOG.error("Error trying to enable the table " + this.tableName, e);
150 } catch (KeeperException e) {
151 LOG.error("Error trying to enable the table " + this.tableName, e);
152 } catch (InterruptedException e) {
153 LOG.error("Error trying to enable the table " + this.tableName, e);
154 } finally {
155 releaseTableLock();
156 }
157 }
158
159 private void releaseTableLock() {
160 if (this.tableLock != null) {
161 try {
162 this.tableLock.release();
163 } catch (IOException ex) {
164 LOG.warn("Could not release the table lock", ex);
165 }
166 }
167 }
168
169 private void handleEnableTable() throws IOException, KeeperException, InterruptedException {
170
171
172
173
174 this.assignmentManager.getZKTable().setEnablingTable(this.tableName);
175 boolean done = false;
176
177
178 List<Pair<HRegionInfo, ServerName>> tableRegionsAndLocations = MetaReader
179 .getTableRegionsAndLocations(this.catalogTracker, tableName, true);
180 int countOfRegionsInTable = tableRegionsAndLocations.size();
181 List<HRegionInfo> regions = regionsToAssignWithServerName(tableRegionsAndLocations);
182 int regionsCount = regions.size();
183 if (regionsCount == 0) {
184 done = true;
185 }
186 LOG.info("Table '" + this.tableName + "' has " + countOfRegionsInTable
187 + " regions, of which " + regionsCount + " are offline.");
188 BulkEnabler bd = new BulkEnabler(this.server, regions, countOfRegionsInTable,
189 true);
190 try {
191 if (bd.bulkAssign()) {
192 done = true;
193 }
194 } catch (InterruptedException e) {
195 LOG.warn("Enable operation was interrupted when enabling table '"
196 + this.tableName + "'");
197
198 Thread.currentThread().interrupt();
199 }
200 if (done) {
201
202 this.assignmentManager.getZKTable().setEnabledTable(
203 this.tableName);
204 LOG.info("Table '" + this.tableName
205 + "' was successfully enabled. Status: done=" + done);
206 } else {
207 LOG.warn("Table '" + this.tableName
208 + "' wasn't successfully enabled. Status: done=" + done);
209 }
210 }
211
212
213
214
215
216
217 private List<HRegionInfo> regionsToAssignWithServerName(
218 final List<Pair<HRegionInfo, ServerName>> regionsInMeta) throws IOException {
219 ServerManager serverManager = ((HMaster) this.server).getServerManager();
220 List<HRegionInfo> regions = new ArrayList<HRegionInfo>();
221 RegionStates regionStates = this.assignmentManager.getRegionStates();
222 for (Pair<HRegionInfo, ServerName> regionLocation : regionsInMeta) {
223 HRegionInfo hri = regionLocation.getFirst();
224 ServerName sn = regionLocation.getSecond();
225 if (regionStates.isRegionOffline(hri)) {
226 if (sn != null && serverManager.isServerOnline(sn)) {
227 this.assignmentManager.addPlan(hri.getEncodedName(), new RegionPlan(hri, null, sn));
228 }
229 regions.add(hri);
230 } else {
231 if (LOG.isDebugEnabled()) {
232 LOG.debug("Skipping assign for the region " + hri + " during enable table "
233 + hri.getTable() + " because its already in tranition or assigned.");
234 }
235 }
236 }
237 return regions;
238 }
239
240
241
242
243 class BulkEnabler extends BulkAssigner {
244 private final List<HRegionInfo> regions;
245
246 private final int countOfRegionsInTable;
247
248 BulkEnabler(final Server server, final List<HRegionInfo> regions,
249 final int countOfRegionsInTable, boolean retainAssignment) {
250 super(server);
251 this.regions = regions;
252 this.countOfRegionsInTable = countOfRegionsInTable;
253 }
254
255 @Override
256 protected void populatePool(ExecutorService pool) throws IOException {
257
258
259 for (HRegionInfo region : regions) {
260 if (assignmentManager.getRegionStates()
261 .isRegionInTransition(region)) {
262 continue;
263 }
264 final HRegionInfo hri = region;
265 pool.execute(Trace.wrap("BulkEnabler.populatePool",new Runnable() {
266 public void run() {
267 assignmentManager.assign(hri, true);
268 }
269 }));
270 }
271 }
272
273 @Override
274 protected boolean waitUntilDone(long timeout)
275 throws InterruptedException {
276 long startTime = System.currentTimeMillis();
277 long remaining = timeout;
278 List<HRegionInfo> regions = null;
279 int lastNumberOfRegions = 0;
280 while (!server.isStopped() && remaining > 0) {
281 Thread.sleep(waitingTimeForEvents);
282 regions = assignmentManager.getRegionStates()
283 .getRegionsOfTable(tableName);
284 if (isDone(regions)) break;
285
286
287 if (regions.size() > lastNumberOfRegions) {
288 lastNumberOfRegions = regions.size();
289 timeout += waitingTimeForEvents;
290 }
291 remaining = timeout - (System.currentTimeMillis() - startTime);
292 }
293 return isDone(regions);
294 }
295
296 private boolean isDone(final List<HRegionInfo> regions) {
297 return regions != null && regions.size() >= this.countOfRegionsInTable;
298 }
299 }
300 }