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 retainAssignment = 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.retainAssignment = 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.retainAssignment) {
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 (!retainAssignment) {
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 this.retainAssignment);
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.isRegionInTransition(hri) && !regionStates.isRegionAssigned(hri)) {
226 if (this.retainAssignment && 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.getTableName() + " 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 private final boolean retainAssignment;
248
249 BulkEnabler(final Server server, final List<HRegionInfo> regions,
250 final int countOfRegionsInTable, boolean retainAssignment) {
251 super(server);
252 this.regions = regions;
253 this.countOfRegionsInTable = countOfRegionsInTable;
254 this.retainAssignment = retainAssignment;
255 }
256
257 @Override
258 protected void populatePool(ExecutorService pool) throws IOException {
259 boolean roundRobinAssignment = this.server.getConfiguration().getBoolean(
260 "hbase.master.enabletable.roundrobin", false);
261
262
263
264 if (retainAssignment || !roundRobinAssignment) {
265 for (HRegionInfo region : regions) {
266 if (assignmentManager.getRegionStates()
267 .isRegionInTransition(region)) {
268 continue;
269 }
270 final HRegionInfo hri = region;
271 pool.execute(Trace.wrap("BulkEnabler.populatePool",new Runnable() {
272 public void run() {
273 assignmentManager.assign(hri, true);
274 }
275 }));
276 }
277 } else {
278 try {
279 assignmentManager.assign(regions);
280 } catch (InterruptedException e) {
281 LOG.warn("Assignment was interrupted");
282 Thread.currentThread().interrupt();
283 }
284 }
285 }
286
287 @Override
288 protected boolean waitUntilDone(long timeout)
289 throws InterruptedException {
290 long startTime = System.currentTimeMillis();
291 long remaining = timeout;
292 List<HRegionInfo> regions = null;
293 int lastNumberOfRegions = 0;
294 while (!server.isStopped() && remaining > 0) {
295 Thread.sleep(waitingTimeForEvents);
296 regions = assignmentManager.getRegionStates()
297 .getRegionsOfTable(tableName);
298 if (isDone(regions)) break;
299
300
301 if (regions.size() > lastNumberOfRegions) {
302 lastNumberOfRegions = regions.size();
303 timeout += waitingTimeForEvents;
304 }
305 remaining = timeout - (System.currentTimeMillis() - startTime);
306 }
307 return isDone(regions);
308 }
309
310 private boolean isDone(final List<HRegionInfo> regions) {
311 return regions != null && regions.size() >= this.countOfRegionsInTable;
312 }
313 }
314 }