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.util.ArrayList;
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.NavigableMap;
28 import java.util.TreeMap;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.hadoop.hbase.HRegionInfo;
33 import org.apache.hadoop.hbase.HTableDescriptor;
34 import org.apache.hadoop.hbase.InvalidFamilyOperationException;
35 import org.apache.hadoop.hbase.Server;
36 import org.apache.hadoop.hbase.ServerName;
37 import org.apache.hadoop.hbase.TableExistsException;
38 import org.apache.hadoop.hbase.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.master.BulkReOpen;
43 import org.apache.hadoop.hbase.master.MasterServices;
44 import org.apache.hadoop.hbase.util.Bytes;
45 import org.apache.zookeeper.KeeperException;
46
47 import com.google.common.collect.Lists;
48 import com.google.common.collect.Maps;
49
50
51
52
53
54
55
56
57 public abstract class TableEventHandler extends EventHandler {
58 private static final Log LOG = LogFactory.getLog(TableEventHandler.class);
59 protected final MasterServices masterServices;
60 protected final byte [] tableName;
61 protected final String tableNameStr;
62
63 public TableEventHandler(EventType eventType, byte [] tableName, Server server,
64 MasterServices masterServices)
65 throws IOException {
66 super(server, eventType);
67 this.masterServices = masterServices;
68 this.tableName = tableName;
69 try {
70 this.masterServices.checkTableModifiable(tableName);
71 } catch (TableNotDisabledException ex) {
72 if (isOnlineSchemaChangeAllowed()
73 && eventType.isOnlineSchemaChangeSupported()) {
74 LOG.debug("Ignoring table not disabled exception " +
75 "for supporting online schema changes.");
76 } else {
77 throw ex;
78 }
79 }
80 this.tableNameStr = Bytes.toString(this.tableName);
81 }
82
83 private boolean isOnlineSchemaChangeAllowed() {
84 return this.server.getConfiguration().getBoolean(
85 "hbase.online.schema.update.enable", false);
86 }
87
88 @Override
89 public void process() {
90 try {
91 LOG.info("Handling table operation " + eventType + " on table " +
92 Bytes.toString(tableName));
93 List<HRegionInfo> hris =
94 MetaReader.getTableRegions(this.server.getCatalogTracker(),
95 tableName);
96 handleTableOperation(hris);
97 if (eventType.isOnlineSchemaChangeSupported() && this.masterServices.
98 getAssignmentManager().getZKTable().
99 isEnabledTable(Bytes.toString(tableName))) {
100 if (reOpenAllRegions(hris)) {
101 LOG.info("Completed table operation " + eventType + " on table " +
102 Bytes.toString(tableName));
103 } else {
104 LOG.warn("Error on reopening the regions");
105 }
106 }
107 } catch (IOException e) {
108 LOG.error("Error manipulating table " + Bytes.toString(tableName), e);
109 } catch (KeeperException e) {
110 LOG.error("Error manipulating table " + Bytes.toString(tableName), e);
111 }
112 }
113
114 public boolean reOpenAllRegions(List<HRegionInfo> regions) throws IOException {
115 boolean done = false;
116 LOG.info("Bucketing regions by region server...");
117 HTable table = new HTable(masterServices.getConfiguration(), tableName);
118 TreeMap<ServerName, List<HRegionInfo>> serverToRegions = Maps
119 .newTreeMap();
120 NavigableMap<HRegionInfo, ServerName> hriHserverMapping = table.getRegionLocations();
121 List<HRegionInfo> reRegions = new ArrayList<HRegionInfo>();
122 for (HRegionInfo hri : regions) {
123 ServerName rsLocation = hriHserverMapping.get(hri);
124
125
126
127 if (null == rsLocation) {
128 LOG.info("Skip " + hri);
129 continue;
130 }
131 if (!serverToRegions.containsKey(rsLocation)) {
132 LinkedList<HRegionInfo> hriList = Lists.newLinkedList();
133 serverToRegions.put(rsLocation, hriList);
134 }
135 reRegions.add(hri);
136 serverToRegions.get(rsLocation).add(hri);
137 }
138
139 LOG.info("Reopening " + reRegions.size() + " regions on "
140 + serverToRegions.size() + " region servers.");
141 this.masterServices.getAssignmentManager().setRegionsToReopen(reRegions);
142 BulkReOpen bulkReopen = new BulkReOpen(this.server, serverToRegions,
143 this.masterServices.getAssignmentManager());
144 while (true) {
145 try {
146 if (bulkReopen.bulkReOpen()) {
147 done = true;
148 break;
149 } else {
150 LOG.warn("Timeout before reopening all regions");
151 }
152 } catch (InterruptedException e) {
153 LOG.warn("Reopen was interrupted");
154
155 Thread.currentThread().interrupt();
156 break;
157 }
158 }
159 return done;
160 }
161
162
163
164
165
166
167
168 HTableDescriptor getTableDescriptor()
169 throws TableExistsException, FileNotFoundException, IOException {
170 final String name = Bytes.toString(tableName);
171 HTableDescriptor htd =
172 this.masterServices.getTableDescriptors().get(name);
173 if (htd == null) {
174 throw new IOException("HTableDescriptor missing for " + name);
175 }
176 return htd;
177 }
178
179 byte [] hasColumnFamily(final HTableDescriptor htd, final byte [] cf)
180 throws InvalidFamilyOperationException {
181 if (!htd.hasFamily(cf)) {
182 throw new InvalidFamilyOperationException("Column family '" +
183 Bytes.toString(cf) + "' does not exist");
184 }
185 return cf;
186 }
187
188 protected abstract void handleTableOperation(List<HRegionInfo> regions)
189 throws IOException, KeeperException;
190 }