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