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