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