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