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.exceptions.InvalidFamilyOperationException;
35 import org.apache.hadoop.hbase.Server;
36 import org.apache.hadoop.hbase.ServerName;
37 import org.apache.hadoop.hbase.exceptions.TableExistsException;
38 import org.apache.hadoop.hbase.exceptions.TableNotDisabledException;
39 import org.apache.hadoop.hbase.catalog.MetaReader;
40 import org.apache.hadoop.hbase.client.HTable;
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
67 public TableEventHandler(EventType eventType, byte [] tableName, Server server,
68 MasterServices masterServices) {
69 super(server, eventType);
70 this.masterServices = masterServices;
71 this.tableName = tableName;
72 this.tableNameStr = Bytes.toString(this.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 return this;
101 }
102
103
104
105
106 protected void prepareWithTableLock() throws IOException {
107 }
108
109 private boolean isOnlineSchemaChangeAllowed() {
110 return this.server.getConfiguration().getBoolean(
111 "hbase.online.schema.update.enable", false);
112 }
113
114 @Override
115 public void process() {
116 try {
117 LOG.info("Handling table operation " + eventType + " on table " +
118 Bytes.toString(tableName));
119
120 List<HRegionInfo> hris =
121 MetaReader.getTableRegions(this.server.getCatalogTracker(),
122 tableName);
123 handleTableOperation(hris);
124 if (eventType.isOnlineSchemaChangeSupported() && this.masterServices.
125 getAssignmentManager().getZKTable().
126 isEnabledTable(Bytes.toString(tableName))) {
127 if (reOpenAllRegions(hris)) {
128 LOG.info("Completed table operation " + eventType + " on table " +
129 Bytes.toString(tableName));
130 } else {
131 LOG.warn("Error on reopening the regions");
132 }
133 }
134 } catch (IOException e) {
135 LOG.error("Error manipulating table " + Bytes.toString(tableName), e);
136 } catch (KeeperException e) {
137 LOG.error("Error manipulating table " + Bytes.toString(tableName), e);
138 } finally {
139 releaseTableLock();
140 }
141 }
142
143 protected void releaseTableLock() {
144 if (this.tableLock != null) {
145 try {
146 this.tableLock.release();
147 } catch (IOException ex) {
148 LOG.warn("Could not release the table lock", ex);
149 }
150 }
151 }
152
153 public boolean reOpenAllRegions(List<HRegionInfo> regions) throws IOException {
154 boolean done = false;
155 LOG.info("Bucketing regions by region server...");
156 HTable table = new HTable(masterServices.getConfiguration(), tableName);
157 TreeMap<ServerName, List<HRegionInfo>> serverToRegions = Maps
158 .newTreeMap();
159 NavigableMap<HRegionInfo, ServerName> hriHserverMapping = table.getRegionLocations();
160 List<HRegionInfo> reRegions = new ArrayList<HRegionInfo>();
161 for (HRegionInfo hri : regions) {
162 ServerName rsLocation = hriHserverMapping.get(hri);
163
164
165
166 if (null == rsLocation) {
167 LOG.info("Skip " + hri);
168 continue;
169 }
170 if (!serverToRegions.containsKey(rsLocation)) {
171 LinkedList<HRegionInfo> hriList = Lists.newLinkedList();
172 serverToRegions.put(rsLocation, hriList);
173 }
174 reRegions.add(hri);
175 serverToRegions.get(rsLocation).add(hri);
176 }
177
178 LOG.info("Reopening " + reRegions.size() + " regions on "
179 + serverToRegions.size() + " region servers.");
180 this.masterServices.getAssignmentManager().setRegionsToReopen(reRegions);
181 BulkReOpen bulkReopen = new BulkReOpen(this.server, serverToRegions,
182 this.masterServices.getAssignmentManager());
183 while (true) {
184 try {
185 if (bulkReopen.bulkReOpen()) {
186 done = true;
187 break;
188 } else {
189 LOG.warn("Timeout before reopening all regions");
190 }
191 } catch (InterruptedException e) {
192 LOG.warn("Reopen was interrupted");
193
194 Thread.currentThread().interrupt();
195 break;
196 }
197 }
198 return done;
199 }
200
201
202
203
204
205
206
207
208
209
210 public HTableDescriptor getTableDescriptor()
211 throws FileNotFoundException, IOException {
212 final String name = Bytes.toString(tableName);
213 HTableDescriptor htd =
214 this.masterServices.getTableDescriptors().get(name);
215 if (htd == null) {
216 throw new IOException("HTableDescriptor missing for " + name);
217 }
218 return htd;
219 }
220
221 byte [] hasColumnFamily(final HTableDescriptor htd, final byte [] cf)
222 throws InvalidFamilyOperationException {
223 if (!htd.hasFamily(cf)) {
224 throw new InvalidFamilyOperationException("Column family '" +
225 Bytes.toString(cf) + "' does not exist");
226 }
227 return cf;
228 }
229
230 protected abstract void handleTableOperation(List<HRegionInfo> regions)
231 throws IOException, KeeperException;
232 }