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;
20
21 import java.io.IOException;
22 import java.io.InterruptedIOException;
23 import java.util.NavigableSet;
24
25 import org.apache.commons.lang.StringUtils;
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.apache.hadoop.hbase.classification.InterfaceAudience;
29 import org.apache.hadoop.conf.Configuration;
30 import org.apache.hadoop.hbase.CellUtil;
31 import org.apache.hadoop.hbase.DoNotRetryIOException;
32 import org.apache.hadoop.hbase.HConstants;
33 import org.apache.hadoop.hbase.HTableDescriptor;
34 import org.apache.hadoop.hbase.NamespaceDescriptor;
35 import org.apache.hadoop.hbase.TableName;
36 import org.apache.hadoop.hbase.ZKNamespaceManager;
37 import org.apache.hadoop.hbase.MetaTableAccessor;
38 import org.apache.hadoop.hbase.client.Delete;
39 import org.apache.hadoop.hbase.client.Get;
40 import org.apache.hadoop.hbase.client.Put;
41 import org.apache.hadoop.hbase.client.Result;
42 import org.apache.hadoop.hbase.client.ResultScanner;
43 import org.apache.hadoop.hbase.client.Table;
44 import org.apache.hadoop.hbase.constraint.ConstraintException;
45 import org.apache.hadoop.hbase.master.procedure.CreateNamespaceProcedure;
46 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
47 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
48 import org.apache.hadoop.hbase.util.Bytes;
49 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
50
51 import com.google.common.collect.Sets;
52
53
54
55
56
57
58
59 @InterfaceAudience.Private
60 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="IS2_INCONSISTENT_SYNC",
61 justification="TODO: synchronize access on nsTable but it is done in tiers above and this " +
62 "class is going away/shrinking")
63 public class TableNamespaceManager {
64 private static final Log LOG = LogFactory.getLog(TableNamespaceManager.class);
65
66 private Configuration conf;
67 private MasterServices masterServices;
68 private Table nsTable = null;
69 private ZKNamespaceManager zkNamespaceManager;
70 private boolean initialized;
71
72 public static final String KEY_MAX_REGIONS = "hbase.namespace.quota.maxregions";
73 public static final String KEY_MAX_TABLES = "hbase.namespace.quota.maxtables";
74 static final String NS_INIT_TIMEOUT = "hbase.master.namespace.init.timeout";
75 static final int DEFAULT_NS_INIT_TIMEOUT = 300000;
76
77 public TableNamespaceManager(MasterServices masterServices) {
78 this.masterServices = masterServices;
79 this.conf = masterServices.getConfiguration();
80 }
81
82 public void start() throws IOException {
83 if (!MetaTableAccessor.tableExists(masterServices.getConnection(),
84 TableName.NAMESPACE_TABLE_NAME)) {
85 LOG.info("Namespace table not found. Creating...");
86 createNamespaceTable(masterServices);
87 }
88
89 try {
90
91
92
93 long startTime = EnvironmentEdgeManager.currentTime();
94 int timeout = conf.getInt(NS_INIT_TIMEOUT, DEFAULT_NS_INIT_TIMEOUT);
95 while (!isTableAvailableAndInitialized(false)) {
96 if (EnvironmentEdgeManager.currentTime() - startTime + 100 > timeout) {
97
98 throw new IOException("Timedout " + timeout + "ms waiting for namespace table to " +
99 "be assigned");
100 }
101 Thread.sleep(100);
102 }
103 } catch (InterruptedException e) {
104 throw (InterruptedIOException) new InterruptedIOException().initCause(e);
105 }
106 }
107
108 private synchronized Table getNamespaceTable() throws IOException {
109 if (!isTableNamespaceManagerInitialized()) {
110 throw new IOException(this.getClass().getName() + " isn't ready to serve");
111 }
112 return nsTable;
113 }
114
115
116
117
118 public boolean doesNamespaceExist(final String namespaceName) throws IOException {
119 if (nsTable == null) {
120 throw new IOException(this.getClass().getName() + " isn't ready to serve");
121 }
122 return (get(nsTable, namespaceName) != null);
123 }
124
125 public synchronized NamespaceDescriptor get(String name) throws IOException {
126 if (!isTableNamespaceManagerInitialized()) {
127 return null;
128 }
129 return zkNamespaceManager.get(name);
130 }
131
132 private NamespaceDescriptor get(Table table, String name) throws IOException {
133 Result res = table.get(new Get(Bytes.toBytes(name)));
134 if (res.isEmpty()) {
135 return null;
136 }
137 byte[] val = CellUtil.cloneValue(res.getColumnLatestCell(
138 HTableDescriptor.NAMESPACE_FAMILY_INFO_BYTES, HTableDescriptor.NAMESPACE_COL_DESC_BYTES));
139 return
140 ProtobufUtil.toNamespaceDescriptor(
141 HBaseProtos.NamespaceDescriptor.parseFrom(val));
142 }
143
144 public void insertIntoNSTable(final NamespaceDescriptor ns) throws IOException {
145 if (nsTable == null) {
146 throw new IOException(this.getClass().getName() + " isn't ready to serve");
147 }
148 Put p = new Put(Bytes.toBytes(ns.getName()));
149 p.addImmutable(HTableDescriptor.NAMESPACE_FAMILY_INFO_BYTES,
150 HTableDescriptor.NAMESPACE_COL_DESC_BYTES,
151 ProtobufUtil.toProtoNamespaceDescriptor(ns).toByteArray());
152 nsTable.put(p);
153 }
154
155 public void updateZKNamespaceManager(final NamespaceDescriptor ns) throws IOException {
156 try {
157 zkNamespaceManager.update(ns);
158 } catch (IOException ex) {
159 String msg = "Failed to update namespace information in ZK.";
160 LOG.error(msg, ex);
161 throw new IOException(msg, ex);
162 }
163 }
164
165 public void removeFromNSTable(final String namespaceName) throws IOException {
166 if (nsTable == null) {
167 throw new IOException(this.getClass().getName() + " isn't ready to serve");
168 }
169 Delete d = new Delete(Bytes.toBytes(namespaceName));
170 nsTable.delete(d);
171 }
172
173 public void removeFromZKNamespaceManager(final String namespaceName) throws IOException {
174 zkNamespaceManager.remove(namespaceName);
175 }
176
177 public synchronized NavigableSet<NamespaceDescriptor> list() throws IOException {
178 NavigableSet<NamespaceDescriptor> ret =
179 Sets.newTreeSet(NamespaceDescriptor.NAMESPACE_DESCRIPTOR_COMPARATOR);
180 ResultScanner scanner =
181 getNamespaceTable().getScanner(HTableDescriptor.NAMESPACE_FAMILY_INFO_BYTES);
182 try {
183 for(Result r : scanner) {
184 byte[] val = CellUtil.cloneValue(r.getColumnLatestCell(
185 HTableDescriptor.NAMESPACE_FAMILY_INFO_BYTES,
186 HTableDescriptor.NAMESPACE_COL_DESC_BYTES));
187 ret.add(ProtobufUtil.toNamespaceDescriptor(
188 HBaseProtos.NamespaceDescriptor.parseFrom(val)));
189 }
190 } finally {
191 scanner.close();
192 }
193 return ret;
194 }
195
196 private void createNamespaceTable(MasterServices masterServices) throws IOException {
197 masterServices.createSystemTable(HTableDescriptor.NAMESPACE_TABLEDESC);
198 }
199
200 @SuppressWarnings("deprecation")
201 private boolean isTableNamespaceManagerInitialized() throws IOException {
202 if (initialized) {
203 this.nsTable = this.masterServices.getConnection().getTable(TableName.NAMESPACE_TABLE_NAME);
204 return true;
205 }
206 return false;
207 }
208
209
210
211
212
213
214
215
216
217 @SuppressWarnings("deprecation")
218 public synchronized boolean isTableAvailableAndInitialized(
219 final boolean createNamespaceAync) throws IOException {
220
221 if (isTableNamespaceManagerInitialized()) {
222 return true;
223 }
224
225 if (zkNamespaceManager == null) {
226 zkNamespaceManager = new ZKNamespaceManager(masterServices.getZooKeeper());
227 zkNamespaceManager.start();
228 }
229
230
231 if (isTableAssigned()) {
232 try {
233 boolean initGoodSofar = true;
234 nsTable = this.masterServices.getConnection().getTable(TableName.NAMESPACE_TABLE_NAME);
235 if (get(nsTable, NamespaceDescriptor.DEFAULT_NAMESPACE.getName()) == null) {
236 if (createNamespaceAync) {
237 masterServices.getMasterProcedureExecutor().submitProcedure(
238 new CreateNamespaceProcedure(
239 masterServices.getMasterProcedureExecutor().getEnvironment(),
240 NamespaceDescriptor.DEFAULT_NAMESPACE));
241 initGoodSofar = false;
242 }
243 else {
244 masterServices.createNamespaceSync(
245 NamespaceDescriptor.DEFAULT_NAMESPACE,
246 HConstants.NO_NONCE,
247 HConstants.NO_NONCE,
248 false);
249 }
250 }
251 if (get(nsTable, NamespaceDescriptor.SYSTEM_NAMESPACE.getName()) == null) {
252 if (createNamespaceAync) {
253 masterServices.getMasterProcedureExecutor().submitProcedure(
254 new CreateNamespaceProcedure(
255 masterServices.getMasterProcedureExecutor().getEnvironment(),
256 NamespaceDescriptor.SYSTEM_NAMESPACE));
257 initGoodSofar = false;
258 }
259 else {
260 masterServices.createNamespaceSync(
261 NamespaceDescriptor.SYSTEM_NAMESPACE,
262 HConstants.NO_NONCE,
263 HConstants.NO_NONCE,
264 false);
265 }
266 }
267
268 if (!initGoodSofar) {
269
270 return false;
271 }
272
273 ResultScanner scanner = nsTable.getScanner(HTableDescriptor.NAMESPACE_FAMILY_INFO_BYTES);
274 try {
275 for (Result result : scanner) {
276 byte[] val = CellUtil.cloneValue(result.getColumnLatestCell(
277 HTableDescriptor.NAMESPACE_FAMILY_INFO_BYTES,
278 HTableDescriptor.NAMESPACE_COL_DESC_BYTES));
279 NamespaceDescriptor ns =
280 ProtobufUtil.toNamespaceDescriptor(
281 HBaseProtos.NamespaceDescriptor.parseFrom(val));
282 zkNamespaceManager.update(ns);
283 }
284 } finally {
285 scanner.close();
286 }
287 initialized = true;
288 return true;
289 } catch (IOException ie) {
290 LOG.warn("Caught exception in initializing namespace table manager", ie);
291 if (nsTable != null) {
292 nsTable.close();
293 }
294 throw ie;
295 }
296 }
297 return false;
298 }
299
300 private boolean isTableAssigned() {
301 return !masterServices.getAssignmentManager().getRegionStates().
302 getRegionsOfTable(TableName.NAMESPACE_TABLE_NAME).isEmpty();
303 }
304
305 public void validateTableAndRegionCount(NamespaceDescriptor desc) throws IOException {
306 if (getMaxRegions(desc) <= 0) {
307 throw new ConstraintException("The max region quota for " + desc.getName()
308 + " is less than or equal to zero.");
309 }
310 if (getMaxTables(desc) <= 0) {
311 throw new ConstraintException("The max tables quota for " + desc.getName()
312 + " is less than or equal to zero.");
313 }
314 }
315
316 public static long getMaxTables(NamespaceDescriptor ns) throws IOException {
317 String value = ns.getConfigurationValue(KEY_MAX_TABLES);
318 long maxTables = 0;
319 if (StringUtils.isNotEmpty(value)) {
320 try {
321 maxTables = Long.parseLong(value);
322 } catch (NumberFormatException exp) {
323 throw new DoNotRetryIOException("NumberFormatException while getting max tables.", exp);
324 }
325 } else {
326
327 maxTables = Long.MAX_VALUE;
328 }
329 return maxTables;
330 }
331
332 public static long getMaxRegions(NamespaceDescriptor ns) throws IOException {
333 String value = ns.getConfigurationValue(KEY_MAX_REGIONS);
334 long maxRegions = 0;
335 if (StringUtils.isNotEmpty(value)) {
336 try {
337 maxRegions = Long.parseLong(value);
338 } catch (NumberFormatException exp) {
339 throw new DoNotRetryIOException("NumberFormatException while getting max regions.", exp);
340 }
341 } else {
342
343 maxRegions = Long.MAX_VALUE;
344 }
345 return maxRegions;
346 }
347 }