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.List;
23 import java.util.concurrent.ExecutorService;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.apache.hadoop.classification.InterfaceAudience;
28 import org.apache.hadoop.hbase.HRegionInfo;
29 import org.apache.hadoop.hbase.Server;
30 import org.apache.hadoop.hbase.exceptions.TableNotEnabledException;
31 import org.apache.hadoop.hbase.exceptions.TableNotFoundException;
32 import org.apache.hadoop.hbase.catalog.CatalogTracker;
33 import org.apache.hadoop.hbase.catalog.MetaReader;
34 import org.apache.hadoop.hbase.executor.EventHandler;
35 import org.apache.hadoop.hbase.executor.EventType;
36 import org.apache.hadoop.hbase.master.AssignmentManager;
37 import org.apache.hadoop.hbase.master.BulkAssigner;
38 import org.apache.hadoop.hbase.master.HMaster;
39 import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
40 import org.apache.hadoop.hbase.master.RegionStates;
41 import org.apache.hadoop.hbase.master.TableLockManager;
42 import org.apache.hadoop.hbase.master.TableLockManager.TableLock;
43 import org.apache.hadoop.hbase.util.Bytes;
44 import org.apache.zookeeper.KeeperException;
45 import org.cloudera.htrace.Trace;
46
47
48
49
50 @InterfaceAudience.Private
51 public class DisableTableHandler extends EventHandler {
52 private static final Log LOG = LogFactory.getLog(DisableTableHandler.class);
53 private final byte [] tableName;
54 private final String tableNameStr;
55 private final AssignmentManager assignmentManager;
56 private final TableLockManager tableLockManager;
57 private final CatalogTracker catalogTracker;
58 private final boolean skipTableStateCheck;
59 private TableLock tableLock;
60
61 public DisableTableHandler(Server server, byte [] tableName,
62 CatalogTracker catalogTracker, AssignmentManager assignmentManager,
63 TableLockManager tableLockManager, boolean skipTableStateCheck) {
64 super(server, EventType.C_M_DISABLE_TABLE);
65 this.tableName = tableName;
66 this.tableNameStr = Bytes.toString(this.tableName);
67 this.assignmentManager = assignmentManager;
68 this.catalogTracker = catalogTracker;
69 this.tableLockManager = tableLockManager;
70 this.skipTableStateCheck = skipTableStateCheck;
71 }
72
73 public DisableTableHandler prepare()
74 throws TableNotFoundException, TableNotEnabledException, IOException {
75
76 this.tableLock = this.tableLockManager.writeLock(tableName,
77 EventType.C_M_DISABLE_TABLE.toString());
78 this.tableLock.acquire();
79
80 boolean success = false;
81 try {
82
83 if (!MetaReader.tableExists(catalogTracker, this.tableNameStr)) {
84 throw new TableNotFoundException(this.tableNameStr);
85 }
86
87
88
89
90
91
92 if (!skipTableStateCheck) {
93 try {
94 if (!this.assignmentManager.getZKTable().checkEnabledAndSetDisablingTable
95 (this.tableNameStr)) {
96 LOG.info("Table " + tableNameStr + " isn't enabled; skipping disable");
97 throw new TableNotEnabledException(this.tableNameStr);
98 }
99 } catch (KeeperException e) {
100 throw new IOException("Unable to ensure that the table will be" +
101 " disabling because of a ZooKeeper issue", e);
102 }
103 }
104 success = true;
105 } finally {
106 if (!success) {
107 releaseTableLock();
108 }
109 }
110
111 return this;
112 }
113
114 @Override
115 public String toString() {
116 String name = "UnknownServerName";
117 if(server != null && server.getServerName() != null) {
118 name = server.getServerName().toString();
119 }
120 return getClass().getSimpleName() + "-" + name + "-" + getSeqid() + "-" +
121 tableNameStr;
122 }
123
124 @Override
125 public void process() {
126 try {
127 LOG.info("Attempting to disable table " + this.tableNameStr);
128 MasterCoprocessorHost cpHost = ((HMaster) this.server)
129 .getCoprocessorHost();
130 if (cpHost != null) {
131 cpHost.preDisableTableHandler(this.tableName);
132 }
133 handleDisableTable();
134 if (cpHost != null) {
135 cpHost.postDisableTableHandler(this.tableName);
136 }
137 } catch (IOException e) {
138 LOG.error("Error trying to disable table " + this.tableNameStr, e);
139 } catch (KeeperException e) {
140 LOG.error("Error trying to disable table " + this.tableNameStr, e);
141 } finally {
142 releaseTableLock();
143 }
144 }
145
146 private void releaseTableLock() {
147 if (this.tableLock != null) {
148 try {
149 this.tableLock.release();
150 } catch (IOException ex) {
151 LOG.warn("Could not release the table lock", ex);
152 }
153 }
154 }
155
156 private void handleDisableTable() throws IOException, KeeperException {
157
158 this.assignmentManager.getZKTable().setDisablingTable(this.tableNameStr);
159 boolean done = false;
160 while (true) {
161
162
163
164
165 final List<HRegionInfo> regions = this.assignmentManager
166 .getRegionStates().getRegionsOfTable(tableName);
167 if (regions.size() == 0) {
168 done = true;
169 break;
170 }
171 LOG.info("Offlining " + regions.size() + " regions.");
172 BulkDisabler bd = new BulkDisabler(this.server, regions);
173 try {
174 if (bd.bulkAssign()) {
175 done = true;
176 break;
177 }
178 } catch (InterruptedException e) {
179 LOG.warn("Disable was interrupted");
180
181 Thread.currentThread().interrupt();
182 break;
183 }
184 }
185
186 if (done) this.assignmentManager.getZKTable().setDisabledTable(this.tableNameStr);
187 LOG.info("Disabled table is done=" + done);
188 }
189
190
191
192
193 class BulkDisabler extends BulkAssigner {
194 private final List<HRegionInfo> regions;
195
196 BulkDisabler(final Server server, final List<HRegionInfo> regions) {
197 super(server);
198 this.regions = regions;
199 }
200
201 @Override
202 protected void populatePool(ExecutorService pool) {
203 RegionStates regionStates = assignmentManager.getRegionStates();
204 for (HRegionInfo region: regions) {
205 if (regionStates.isRegionInTransition(region)
206 && !regionStates.isRegionFailedToClose(region)) continue;
207 final HRegionInfo hri = region;
208 pool.execute(Trace.wrap(new Runnable() {
209 public void run() {
210 assignmentManager.unassign(hri, true);
211 }
212 }));
213 }
214 }
215
216 @Override
217 protected boolean waitUntilDone(long timeout)
218 throws InterruptedException {
219 long startTime = System.currentTimeMillis();
220 long remaining = timeout;
221 List<HRegionInfo> regions = null;
222 while (!server.isStopped() && remaining > 0) {
223 Thread.sleep(waitingTimeForEvents);
224 regions = assignmentManager.getRegionStates().getRegionsOfTable(tableName);
225 LOG.debug("Disable waiting until done; " + remaining + " ms remaining; " + regions);
226 if (regions.isEmpty()) break;
227 remaining = timeout - (System.currentTimeMillis() - startTime);
228 }
229 return regions != null && regions.isEmpty();
230 }
231 }
232 }