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.master.handler;
21
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.List;
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.HRegionInfo;
30 import org.apache.hadoop.hbase.Server;
31 import org.apache.hadoop.hbase.ServerName;
32 import org.apache.hadoop.hbase.TableNotDisabledException;
33 import org.apache.hadoop.hbase.TableNotFoundException;
34 import org.apache.hadoop.hbase.catalog.CatalogTracker;
35 import org.apache.hadoop.hbase.catalog.MetaReader;
36 import org.apache.hadoop.hbase.executor.EventHandler;
37 import org.apache.hadoop.hbase.master.AssignmentManager;
38 import org.apache.hadoop.hbase.master.BulkAssigner;
39 import org.apache.hadoop.hbase.master.HMaster;
40 import org.apache.hadoop.hbase.master.RegionPlan;
41 import org.apache.hadoop.hbase.master.ServerManager;
42 import org.apache.hadoop.hbase.util.Bytes;
43 import org.apache.hadoop.hbase.util.Pair;
44 import org.apache.zookeeper.KeeperException;
45
46
47
48
49 public class EnableTableHandler extends EventHandler {
50 private static final Log LOG = LogFactory.getLog(EnableTableHandler.class);
51 private final byte [] tableName;
52 private final String tableNameStr;
53 private final AssignmentManager assignmentManager;
54 private final CatalogTracker ct;
55 private boolean retainAssignment = false;
56
57 public EnableTableHandler(Server server, byte [] tableName,
58 CatalogTracker catalogTracker, AssignmentManager assignmentManager,
59 boolean skipTableStateCheck)
60 throws TableNotFoundException, TableNotDisabledException, IOException {
61 super(server, EventType.C_M_ENABLE_TABLE);
62 this.tableName = tableName;
63 this.tableNameStr = Bytes.toString(tableName);
64 this.ct = catalogTracker;
65 this.assignmentManager = assignmentManager;
66 this.retainAssignment = skipTableStateCheck;
67
68 if (!MetaReader.tableExists(catalogTracker, this.tableNameStr)) {
69
70
71 if (!this.retainAssignment) {
72 throw new TableNotFoundException(tableNameStr);
73 }
74 try {
75 this.assignmentManager.getZKTable().removeEnablingTable(tableNameStr, true);
76 } catch (KeeperException e) {
77
78 LOG.warn("Failed to delete the ENABLING node for the table " + tableNameStr
79 + ". The table will remain unusable. Run HBCK to manually fix the problem.");
80 }
81 }
82
83
84
85
86
87 if (!skipTableStateCheck)
88 {
89 try {
90 if (!this.assignmentManager.getZKTable().checkDisabledAndSetEnablingTable
91 (this.tableNameStr)) {
92 LOG.info("Table " + tableNameStr + " isn't disabled; skipping enable");
93 throw new TableNotDisabledException(this.tableNameStr);
94 }
95 } catch (KeeperException e) {
96 throw new IOException("Unable to ensure that the table will be" +
97 " enabling because of a ZooKeeper issue", e);
98 }
99 }
100 }
101
102 @Override
103 public String toString() {
104 String name = "UnknownServerName";
105 if(server != null && server.getServerName() != null) {
106 name = server.getServerName().toString();
107 }
108 return getClass().getSimpleName() + "-" + name + "-" + getSeqid() + "-" +
109 tableNameStr;
110 }
111
112 @Override
113 public void process() {
114 try {
115 LOG.info("Attemping to enable the table " + this.tableNameStr);
116 handleEnableTable();
117 } catch (IOException e) {
118 LOG.error("Error trying to enable the table " + this.tableNameStr, e);
119 } catch (KeeperException e) {
120 LOG.error("Error trying to enable the table " + this.tableNameStr, e);
121 } catch (InterruptedException e) {
122 LOG.error("Error trying to enable the table " + this.tableNameStr, e);
123 }
124 }
125
126 private void handleEnableTable() throws IOException, KeeperException, InterruptedException {
127
128
129
130
131 this.assignmentManager.getZKTable().setEnablingTable(this.tableNameStr);
132 boolean done = false;
133
134
135 List<Pair<HRegionInfo, ServerName>> tableRegionsAndLocations = MetaReader
136 .getTableRegionsAndLocations(this.ct, tableName, true);
137 int countOfRegionsInTable = tableRegionsAndLocations.size();
138 List<HRegionInfo> regions = regionsToAssignWithServerName(tableRegionsAndLocations);
139 int regionsCount = regions.size();
140 if (regionsCount == 0) {
141 done = true;
142 }
143 LOG.info("Table has " + countOfRegionsInTable + " regions of which " +
144 regionsCount + " are offline.");
145 BulkEnabler bd = new BulkEnabler(this.server, regions, countOfRegionsInTable,
146 this.retainAssignment);
147 try {
148 if (bd.bulkAssign()) {
149 done = true;
150 }
151 } catch (InterruptedException e) {
152 LOG.warn("Enable was interrupted");
153
154 Thread.currentThread().interrupt();
155 }
156
157 if (done) this.assignmentManager.getZKTable().setEnabledTable(
158 this.tableNameStr);
159 LOG.info("Enabled table is done=" + done);
160 }
161
162
163
164
165
166
167 private List<HRegionInfo> regionsToAssignWithServerName(
168 final List<Pair<HRegionInfo, ServerName>> regionsInMeta) throws IOException {
169 ServerManager serverManager = ((HMaster) this.server).getServerManager();
170 List<HRegionInfo> regions = new ArrayList<HRegionInfo>();
171 List<HRegionInfo> enablingTableRegions = this.assignmentManager
172 .getEnablingTableRegions(this.tableNameStr);
173 final List<HRegionInfo> onlineRegions = this.assignmentManager.getRegionsOfTable(tableName);
174 for (Pair<HRegionInfo, ServerName> regionLocation : regionsInMeta) {
175 HRegionInfo hri = regionLocation.getFirst();
176 ServerName sn = regionLocation.getSecond();
177 if (this.retainAssignment) {
178
179 if (enablingTableRegions != null && enablingTableRegions.contains(hri)) {
180 regions.add(hri);
181 if (sn != null && serverManager.isServerOnline(sn)) {
182 this.assignmentManager.addPlan(hri.getEncodedName(), new RegionPlan(hri, null, sn));
183 }
184 }
185 } else if (onlineRegions.contains(hri)) {
186 continue;
187 } else {
188 regions.add(hri);
189 }
190 }
191 return regions;
192 }
193
194
195
196
197 class BulkEnabler extends BulkAssigner {
198 private final List<HRegionInfo> regions;
199
200 private final int countOfRegionsInTable;
201 private final boolean retainAssignment;
202
203 BulkEnabler(final Server server, final List<HRegionInfo> regions,
204 final int countOfRegionsInTable,final boolean retainAssignment) {
205 super(server);
206 this.regions = regions;
207 this.countOfRegionsInTable = countOfRegionsInTable;
208 this.retainAssignment = retainAssignment;
209 }
210
211 @Override
212 protected void populatePool(ExecutorService pool) throws IOException {
213 boolean roundRobinAssignment = this.server.getConfiguration().getBoolean(
214 "hbase.master.enabletable.roundrobin", false);
215
216 if (retainAssignment || !roundRobinAssignment) {
217 for (HRegionInfo region : regions) {
218 if (assignmentManager.isRegionInTransition(region) != null) {
219 continue;
220 }
221 final HRegionInfo hri = region;
222 pool.execute(new Runnable() {
223 public void run() {
224 if (retainAssignment) {
225 assignmentManager.assign(hri, true, false, false);
226 } else {
227 assignmentManager.assign(hri, true);
228 }
229 }
230 });
231 }
232 } else {
233 try {
234 assignmentManager.assignUserRegionsToOnlineServers(regions);
235 } catch (InterruptedException e) {
236 LOG.warn("Assignment was interrupted");
237 Thread.currentThread().interrupt();
238 }
239 }
240 }
241
242 @Override
243 protected boolean waitUntilDone(long timeout)
244 throws InterruptedException {
245 long startTime = System.currentTimeMillis();
246 long remaining = timeout;
247 List<HRegionInfo> regions = null;
248 int lastNumberOfRegions = 0;
249 while (!server.isStopped() && remaining > 0) {
250 Thread.sleep(waitingTimeForEvents);
251 regions = assignmentManager.getRegionsOfTable(tableName);
252 if (isDone(regions)) break;
253
254
255 if (regions.size() > lastNumberOfRegions) {
256 lastNumberOfRegions = regions.size();
257 timeout += waitingTimeForEvents;
258 }
259 remaining = timeout - (System.currentTimeMillis() - startTime);
260 }
261 return isDone(regions);
262 }
263
264 private boolean isDone(final List<HRegionInfo> regions) {
265 return regions != null && regions.size() >= this.countOfRegionsInTable;
266 }
267 }
268 }