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