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.FileNotFoundException;
23 import java.io.IOException;
24 import java.io.InterruptedIOException;
25 import java.util.ArrayList;
26 import java.util.LinkedList;
27 import java.util.List;
28 import java.util.NavigableMap;
29 import java.util.TreeMap;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.apache.hadoop.hbase.HRegionInfo;
34 import org.apache.hadoop.hbase.HTableDescriptor;
35 import org.apache.hadoop.hbase.InvalidFamilyOperationException;
36 import org.apache.hadoop.hbase.Server;
37 import org.apache.hadoop.hbase.ServerName;
38 import org.apache.hadoop.hbase.TableExistsException;
39 import org.apache.hadoop.hbase.TableNotDisabledException;
40 import org.apache.hadoop.hbase.catalog.MetaReader;
41 import org.apache.hadoop.hbase.client.HTable;
42 import org.apache.hadoop.hbase.executor.EventHandler;
43 import org.apache.hadoop.hbase.master.BulkReOpen;
44 import org.apache.hadoop.hbase.master.MasterServices;
45 import org.apache.hadoop.hbase.util.Bytes;
46 import org.apache.zookeeper.KeeperException;
47
48 import com.google.common.collect.Lists;
49 import com.google.common.collect.Maps;
50
51
52
53
54
55
56
57
58 public abstract class TableEventHandler extends EventHandler {
59 private static final Log LOG = LogFactory.getLog(TableEventHandler.class);
60 protected final MasterServices masterServices;
61 protected final byte [] tableName;
62 protected final String tableNameStr;
63 protected boolean isEventBeingHandled = false;
64
65 public TableEventHandler(EventType eventType, byte [] tableName, Server server,
66 MasterServices masterServices)
67 throws IOException {
68 super(server, eventType);
69 this.masterServices = masterServices;
70 this.tableName = tableName;
71 try {
72 this.masterServices.checkTableModifiable(tableName);
73 } catch (TableNotDisabledException ex) {
74 if (isOnlineSchemaChangeAllowed()
75 && eventType.isOnlineSchemaChangeSupported()) {
76 LOG.debug("Ignoring table not disabled exception " +
77 "for supporting online schema changes.");
78 } else {
79 throw ex;
80 }
81 }
82 this.tableNameStr = Bytes.toString(this.tableName);
83 }
84
85 private boolean isOnlineSchemaChangeAllowed() {
86 return this.server.getConfiguration().getBoolean(
87 "hbase.online.schema.update.enable", false);
88 }
89
90 @Override
91 public void process() {
92 try {
93 LOG.info("Handling table operation " + eventType + " on table " +
94 Bytes.toString(tableName));
95 List<HRegionInfo> hris =
96 MetaReader.getTableRegions(this.server.getCatalogTracker(),
97 tableName);
98 handleTableOperation(hris);
99 if (eventType.isOnlineSchemaChangeSupported() && this.masterServices.
100 getAssignmentManager().getZKTable().
101 isEnabledTable(Bytes.toString(tableName))) {
102 if (reOpenAllRegions(hris)) {
103 LOG.info("Completed table operation " + eventType + " on table " +
104 Bytes.toString(tableName));
105 } else {
106 LOG.warn("Error on reopening the regions");
107 }
108 }
109 completed(null);
110 } catch (IOException e) {
111 LOG.error("Error manipulating table " + Bytes.toString(tableName), e);
112 completed(e);
113 } catch (KeeperException e) {
114 LOG.error("Error manipulating table " + Bytes.toString(tableName), e);
115 completed(e);
116 } finally {
117 notifyEventBeingHandled();
118 }
119 }
120
121
122
123
124
125 protected void completed(final Throwable exception) {
126 }
127
128 public boolean reOpenAllRegions(List<HRegionInfo> regions) throws IOException {
129 boolean done = false;
130 HTable table = null;
131 TreeMap<ServerName, List<HRegionInfo>> serverToRegions = Maps.newTreeMap();
132 NavigableMap<HRegionInfo, ServerName> hriHserverMapping;
133
134 LOG.info("Bucketing regions by region server...");
135
136 try {
137 table = new HTable(masterServices.getConfiguration(), tableName);
138 hriHserverMapping = table.getRegionLocations();
139 } finally {
140 if (table != null) {
141 table.close();
142 }
143 }
144 List<HRegionInfo> reRegions = new ArrayList<HRegionInfo>();
145 for (HRegionInfo hri : regions) {
146 ServerName rsLocation = hriHserverMapping.get(hri);
147
148
149
150 if (null == rsLocation) {
151 LOG.info("Skip " + hri);
152 continue;
153 }
154 if (!serverToRegions.containsKey(rsLocation)) {
155 LinkedList<HRegionInfo> hriList = Lists.newLinkedList();
156 serverToRegions.put(rsLocation, hriList);
157 }
158 reRegions.add(hri);
159 serverToRegions.get(rsLocation).add(hri);
160 }
161
162 LOG.info("Reopening " + reRegions.size() + " regions on "
163 + serverToRegions.size() + " region servers.");
164 this.masterServices.getAssignmentManager().setRegionsToReopen(reRegions);
165 notifyEventBeingHandled();
166 BulkReOpen bulkReopen = new BulkReOpen(this.server, serverToRegions,
167 this.masterServices.getAssignmentManager());
168 while (true) {
169 try {
170 if (bulkReopen.bulkReOpen()) {
171 done = true;
172 break;
173 } else {
174 LOG.warn("Timeout before reopening all regions");
175 }
176 } catch (InterruptedException e) {
177 LOG.warn("Reopen was interrupted");
178
179 Thread.currentThread().interrupt();
180 break;
181 }
182 }
183 return done;
184 }
185
186
187
188
189
190
191
192
193
194 public HTableDescriptor getTableDescriptor()
195 throws FileNotFoundException, IOException {
196 final String name = Bytes.toString(tableName);
197 HTableDescriptor htd =
198 this.masterServices.getTableDescriptors().get(name);
199 if (htd == null) {
200 throw new IOException("HTableDescriptor missing for " + name);
201 }
202 return htd;
203 }
204
205 byte [] hasColumnFamily(final HTableDescriptor htd, final byte [] cf)
206 throws InvalidFamilyOperationException {
207 if (!htd.hasFamily(cf)) {
208 throw new InvalidFamilyOperationException("Column family '" +
209 Bytes.toString(cf) + "' does not exist");
210 }
211 return cf;
212 }
213
214 protected abstract void handleTableOperation(List<HRegionInfo> regions)
215 throws IOException, KeeperException;
216
217
218
219
220
221
222 public synchronized void waitForEventBeingHandled() throws IOException {
223 if (!this.isEventBeingHandled) {
224 try {
225 wait();
226 } catch (InterruptedException ie) {
227 throw (IOException) new InterruptedIOException().initCause(ie);
228 }
229 }
230 }
231
232 private synchronized void notifyEventBeingHandled() {
233 if (!this.isEventBeingHandled) {
234 isEventBeingHandled = true;
235 notify();
236 }
237 }
238 }