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.HashMap;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.concurrent.ExecutorService;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.hadoop.hbase.classification.InterfaceAudience;
30 import org.apache.hadoop.hbase.TableName;
31 import org.apache.hadoop.hbase.HRegionInfo;
32 import org.apache.hadoop.hbase.Server;
33 import org.apache.hadoop.hbase.ServerName;
34 import org.apache.hadoop.hbase.TableNotDisabledException;
35 import org.apache.hadoop.hbase.TableNotFoundException;
36 import org.apache.hadoop.hbase.catalog.CatalogTracker;
37 import org.apache.hadoop.hbase.catalog.MetaReader;
38 import org.apache.hadoop.hbase.executor.EventHandler;
39 import org.apache.hadoop.hbase.executor.EventType;
40 import org.apache.hadoop.hbase.master.AssignmentManager;
41 import org.apache.hadoop.hbase.master.BulkAssigner;
42 import org.apache.hadoop.hbase.master.GeneralBulkAssigner;
43 import org.apache.hadoop.hbase.master.HMaster;
44 import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
45 import org.apache.hadoop.hbase.master.RegionStates;
46 import org.apache.hadoop.hbase.master.ServerManager;
47 import org.apache.hadoop.hbase.master.TableLockManager;
48 import org.apache.hadoop.hbase.master.TableLockManager.TableLock;
49 import org.apache.hadoop.hbase.util.Pair;
50 import org.apache.zookeeper.KeeperException;
51 import org.cloudera.htrace.Trace;
52
53
54
55
56 @InterfaceAudience.Private
57 public class EnableTableHandler extends EventHandler {
58 private static final Log LOG = LogFactory.getLog(EnableTableHandler.class);
59 private final TableName tableName;
60 private final AssignmentManager assignmentManager;
61 private final TableLockManager tableLockManager;
62 private final CatalogTracker catalogTracker;
63 private boolean skipTableStateCheck = false;
64 private TableLock tableLock;
65
66 public EnableTableHandler(Server server, TableName tableName,
67 CatalogTracker catalogTracker, AssignmentManager assignmentManager,
68 TableLockManager tableLockManager, boolean skipTableStateCheck) {
69 super(server, EventType.C_M_ENABLE_TABLE);
70 this.tableName = tableName;
71 this.catalogTracker = catalogTracker;
72 this.assignmentManager = assignmentManager;
73 this.tableLockManager = tableLockManager;
74 this.skipTableStateCheck = skipTableStateCheck;
75 }
76
77 public EnableTableHandler prepare()
78 throws TableNotFoundException, TableNotDisabledException, IOException {
79
80 this.tableLock = this.tableLockManager.writeLock(tableName,
81 EventType.C_M_ENABLE_TABLE.toString());
82 this.tableLock.acquire();
83
84 boolean success = false;
85 try {
86
87 if (!MetaReader.tableExists(catalogTracker, tableName)) {
88
89 if (!this.skipTableStateCheck) {
90 throw new TableNotFoundException(tableName);
91 }
92 try {
93 this.assignmentManager.getZKTable().removeEnablingTable(tableName, true);
94 throw new TableNotFoundException(tableName);
95 } catch (KeeperException e) {
96
97 LOG.warn("Failed to delete the ENABLING node for the table " + tableName
98 + ". The table will remain unusable. Run HBCK to manually fix the problem.");
99 }
100 }
101
102
103
104
105
106 if (!skipTableStateCheck) {
107 try {
108 if (!this.assignmentManager.getZKTable().checkDisabledAndSetEnablingTable
109 (this.tableName)) {
110 LOG.info("Table " + tableName + " isn't disabled; skipping enable");
111 throw new TableNotDisabledException(this.tableName);
112 }
113 } catch (KeeperException e) {
114 throw new IOException("Unable to ensure that the table will be" +
115 " enabling because of a ZooKeeper issue", e);
116 }
117 }
118 success = true;
119 } finally {
120 if (!success) {
121 releaseTableLock();
122 }
123 }
124 return this;
125 }
126
127 @Override
128 public String toString() {
129 String name = "UnknownServerName";
130 if(server != null && server.getServerName() != null) {
131 name = server.getServerName().toString();
132 }
133 return getClass().getSimpleName() + "-" + name + "-" + getSeqid() + "-" +
134 tableName;
135 }
136
137 @Override
138 public void process() {
139 try {
140 LOG.info("Attempting to enable the table " + this.tableName);
141 MasterCoprocessorHost cpHost = ((HMaster) this.server)
142 .getCoprocessorHost();
143 if (cpHost != null) {
144 cpHost.preEnableTableHandler(this.tableName);
145 }
146 handleEnableTable();
147 if (cpHost != null) {
148 cpHost.postEnableTableHandler(this.tableName);
149 }
150 } catch (IOException e) {
151 LOG.error("Error trying to enable the table " + this.tableName, e);
152 } catch (KeeperException e) {
153 LOG.error("Error trying to enable the table " + this.tableName, e);
154 } catch (InterruptedException e) {
155 LOG.error("Error trying to enable the table " + this.tableName, e);
156 } finally {
157 releaseTableLock();
158 }
159 }
160
161 private void releaseTableLock() {
162 if (this.tableLock != null) {
163 try {
164 this.tableLock.release();
165 } catch (IOException ex) {
166 LOG.warn("Could not release the table lock", ex);
167 }
168 }
169 }
170
171 private void handleEnableTable() throws IOException, KeeperException, InterruptedException {
172
173
174
175
176 this.assignmentManager.getZKTable().setEnablingTable(this.tableName);
177 boolean done = false;
178 ServerManager serverManager = ((HMaster)this.server).getServerManager();
179
180
181 List<Pair<HRegionInfo, ServerName>> tableRegionsAndLocations = MetaReader
182 .getTableRegionsAndLocations(this.catalogTracker, tableName, true);
183 int countOfRegionsInTable = tableRegionsAndLocations.size();
184 Map<HRegionInfo, ServerName> regionsToAssign =
185 regionsToAssignWithServerName(tableRegionsAndLocations);
186 int regionsCount = regionsToAssign.size();
187 if (regionsCount == 0) {
188 done = true;
189 }
190 LOG.info("Table '" + this.tableName + "' has " + countOfRegionsInTable
191 + " regions, of which " + regionsCount + " are offline.");
192 List<ServerName> onlineServers = serverManager.createDestinationServersList();
193 Map<ServerName, List<HRegionInfo>> bulkPlan =
194 this.assignmentManager.getBalancer().retainAssignment(regionsToAssign, onlineServers);
195 LOG.info("Bulk assigning " + regionsCount + " region(s) across " + bulkPlan.size()
196 + " server(s), retainAssignment=true");
197
198 BulkAssigner ba = new GeneralBulkAssigner(this.server, bulkPlan, this.assignmentManager, true);
199 try {
200 if (ba.bulkAssign()) {
201 done = true;
202 }
203 } catch (InterruptedException e) {
204 LOG.warn("Enable operation was interrupted when enabling table '"
205 + this.tableName + "'");
206
207 Thread.currentThread().interrupt();
208 }
209 if (done) {
210
211 this.assignmentManager.getZKTable().setEnabledTable(
212 this.tableName);
213 LOG.info("Table '" + this.tableName
214 + "' was successfully enabled. Status: done=" + done);
215 } else {
216 LOG.warn("Table '" + this.tableName
217 + "' wasn't successfully enabled. Status: done=" + done);
218 }
219 }
220
221
222
223
224
225
226 private Map<HRegionInfo, ServerName> regionsToAssignWithServerName(
227 final List<Pair<HRegionInfo, ServerName>> regionsInMeta) throws IOException {
228 Map<HRegionInfo, ServerName> regionsToAssign =
229 new HashMap<HRegionInfo, ServerName>(regionsInMeta.size());
230 RegionStates regionStates = this.assignmentManager.getRegionStates();
231 for (Pair<HRegionInfo, ServerName> regionLocation : regionsInMeta) {
232 HRegionInfo hri = regionLocation.getFirst();
233 ServerName sn = regionLocation.getSecond();
234 if (regionStates.isRegionOffline(hri)) {
235 regionsToAssign.put(hri, sn);
236 } else {
237 if (LOG.isDebugEnabled()) {
238 LOG.debug("Skipping assign for the region " + hri + " during enable table "
239 + hri.getTable() + " because its already in tranition or assigned.");
240 }
241 }
242 }
243 return regionsToAssign;
244 }
245 }