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 } catch (IOException e) {
110 LOG.error("Error manipulating table " + Bytes.toString(tableName), e);
111 } catch (KeeperException e) {
112 LOG.error("Error manipulating table " + Bytes.toString(tableName), e);
113 } finally {
114 notifyEventBeingHandled();
115 }
116 }
117
118 public boolean reOpenAllRegions(List<HRegionInfo> regions) throws IOException {
119 boolean done = false;
120 HTable table = null;
121 TreeMap<ServerName, List<HRegionInfo>> serverToRegions = Maps.newTreeMap();
122 NavigableMap<HRegionInfo, ServerName> hriHserverMapping;
123
124 LOG.info("Bucketing regions by region server...");
125
126 try {
127 table = new HTable(masterServices.getConfiguration(), tableName);
128 hriHserverMapping = table.getRegionLocations();
129 } finally {
130 if (table != null) {
131 table.close();
132 }
133 }
134 List<HRegionInfo> reRegions = new ArrayList<HRegionInfo>();
135 for (HRegionInfo hri : regions) {
136 ServerName rsLocation = hriHserverMapping.get(hri);
137
138
139
140 if (null == rsLocation) {
141 LOG.info("Skip " + hri);
142 continue;
143 }
144 if (!serverToRegions.containsKey(rsLocation)) {
145 LinkedList<HRegionInfo> hriList = Lists.newLinkedList();
146 serverToRegions.put(rsLocation, hriList);
147 }
148 reRegions.add(hri);
149 serverToRegions.get(rsLocation).add(hri);
150 }
151
152 LOG.info("Reopening " + reRegions.size() + " regions on "
153 + serverToRegions.size() + " region servers.");
154 this.masterServices.getAssignmentManager().setRegionsToReopen(reRegions);
155 notifyEventBeingHandled();
156 BulkReOpen bulkReopen = new BulkReOpen(this.server, serverToRegions,
157 this.masterServices.getAssignmentManager());
158 while (true) {
159 try {
160 if (bulkReopen.bulkReOpen()) {
161 done = true;
162 break;
163 } else {
164 LOG.warn("Timeout before reopening all regions");
165 }
166 } catch (InterruptedException e) {
167 LOG.warn("Reopen was interrupted");
168
169 Thread.currentThread().interrupt();
170 break;
171 }
172 }
173 return done;
174 }
175
176
177
178
179
180
181
182
183
184 public HTableDescriptor getTableDescriptor()
185 throws FileNotFoundException, IOException {
186 final String name = Bytes.toString(tableName);
187 HTableDescriptor htd =
188 this.masterServices.getTableDescriptors().get(name);
189 if (htd == null) {
190 throw new IOException("HTableDescriptor missing for " + name);
191 }
192 return htd;
193 }
194
195 byte [] hasColumnFamily(final HTableDescriptor htd, final byte [] cf)
196 throws InvalidFamilyOperationException {
197 if (!htd.hasFamily(cf)) {
198 throw new InvalidFamilyOperationException("Column family '" +
199 Bytes.toString(cf) + "' does not exist");
200 }
201 return cf;
202 }
203
204 protected abstract void handleTableOperation(List<HRegionInfo> regions)
205 throws IOException, KeeperException;
206
207
208
209
210
211
212 public synchronized void waitForEventBeingHandled() throws IOException {
213 if (!this.isEventBeingHandled) {
214 try {
215 wait();
216 } catch (InterruptedException ie) {
217 throw (IOException) new InterruptedIOException().initCause(ie);
218 }
219 }
220 }
221
222 private synchronized void notifyEventBeingHandled() {
223 if (!this.isEventBeingHandled) {
224 isEventBeingHandled = true;
225 notify();
226 }
227 }
228 }