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
226 if (isTableAssigned()) {
227 try {
228 boolean initGoodSofar = true;
229 nsTable = this.masterServices.getConnection().getTable(TableName.NAMESPACE_TABLE_NAME);
230 zkNamespaceManager = new ZKNamespaceManager(masterServices.getZooKeeper());
231 zkNamespaceManager.start();
232
233 if (get(nsTable, NamespaceDescriptor.DEFAULT_NAMESPACE.getName()) == null) {
234 if (createNamespaceAync) {
235 masterServices.getMasterProcedureExecutor().submitProcedure(
236 new CreateNamespaceProcedure(
237 masterServices.getMasterProcedureExecutor().getEnvironment(),
238 NamespaceDescriptor.DEFAULT_NAMESPACE));
239 initGoodSofar = false;
240 }
241 else {
242 masterServices.createNamespaceSync(
243 NamespaceDescriptor.DEFAULT_NAMESPACE,
244 HConstants.NO_NONCE,
245 HConstants.NO_NONCE,
246 false);
247 }
248 }
249 if (get(nsTable, NamespaceDescriptor.SYSTEM_NAMESPACE.getName()) == null) {
250 if (createNamespaceAync) {
251 masterServices.getMasterProcedureExecutor().submitProcedure(
252 new CreateNamespaceProcedure(
253 masterServices.getMasterProcedureExecutor().getEnvironment(),
254 NamespaceDescriptor.SYSTEM_NAMESPACE));
255 initGoodSofar = false;
256 }
257 else {
258 masterServices.createNamespaceSync(
259 NamespaceDescriptor.SYSTEM_NAMESPACE,
260 HConstants.NO_NONCE,
261 HConstants.NO_NONCE,
262 false);
263 }
264 }
265
266 if (!initGoodSofar) {
267
268 return false;
269 }
270
271 ResultScanner scanner = nsTable.getScanner(HTableDescriptor.NAMESPACE_FAMILY_INFO_BYTES);
272 try {
273 for (Result result : scanner) {
274 byte[] val = CellUtil.cloneValue(result.getColumnLatestCell(
275 HTableDescriptor.NAMESPACE_FAMILY_INFO_BYTES,
276 HTableDescriptor.NAMESPACE_COL_DESC_BYTES));
277 NamespaceDescriptor ns =
278 ProtobufUtil.toNamespaceDescriptor(
279 HBaseProtos.NamespaceDescriptor.parseFrom(val));
280 zkNamespaceManager.update(ns);
281 }
282 } finally {
283 scanner.close();
284 }
285 initialized = true;
286 return true;
287 } catch (IOException ie) {
288 LOG.warn("Caught exception in initializing namespace table manager", ie);
289 if (nsTable != null) {
290 nsTable.close();
291 }
292 throw ie;
293 }
294 }
295 return false;
296 }
297
298 private boolean isTableAssigned() {
299 return !masterServices.getAssignmentManager().getRegionStates().
300 getRegionsOfTable(TableName.NAMESPACE_TABLE_NAME).isEmpty();
301 }
302
303 public void validateTableAndRegionCount(NamespaceDescriptor desc) throws IOException {
304 if (getMaxRegions(desc) <= 0) {
305 throw new ConstraintException("The max region quota for " + desc.getName()
306 + " is less than or equal to zero.");
307 }
308 if (getMaxTables(desc) <= 0) {
309 throw new ConstraintException("The max tables quota for " + desc.getName()
310 + " is less than or equal to zero.");
311 }
312 }
313
314 public static long getMaxTables(NamespaceDescriptor ns) throws IOException {
315 String value = ns.getConfigurationValue(KEY_MAX_TABLES);
316 long maxTables = 0;
317 if (StringUtils.isNotEmpty(value)) {
318 try {
319 maxTables = Long.parseLong(value);
320 } catch (NumberFormatException exp) {
321 throw new DoNotRetryIOException("NumberFormatException while getting max tables.", exp);
322 }
323 } else {
324
325 maxTables = Long.MAX_VALUE;
326 }
327 return maxTables;
328 }
329
330 public static long getMaxRegions(NamespaceDescriptor ns) throws IOException {
331 String value = ns.getConfigurationValue(KEY_MAX_REGIONS);
332 long maxRegions = 0;
333 if (StringUtils.isNotEmpty(value)) {
334 try {
335 maxRegions = Long.parseLong(value);
336 } catch (NumberFormatException exp) {
337 throw new DoNotRetryIOException("NumberFormatException while getting max regions.", exp);
338 }
339 } else {
340
341 maxRegions = Long.MAX_VALUE;
342 }
343 return maxRegions;
344 }
345 }