2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 package org
.apache
.hadoop
.hbase
.master
;
21 import java
.io
.IOException
;
22 import java
.util
.List
;
23 import java
.util
.concurrent
.ConcurrentHashMap
;
24 import java
.util
.concurrent
.ConcurrentMap
;
25 import java
.util
.stream
.Collectors
;
26 import org
.apache
.commons
.lang3
.StringUtils
;
27 import org
.apache
.hadoop
.hbase
.Cell
;
28 import org
.apache
.hadoop
.hbase
.CellUtil
;
29 import org
.apache
.hadoop
.hbase
.DoNotRetryIOException
;
30 import org
.apache
.hadoop
.hbase
.HConstants
;
31 import org
.apache
.hadoop
.hbase
.MetaTableAccessor
;
32 import org
.apache
.hadoop
.hbase
.NamespaceDescriptor
;
33 import org
.apache
.hadoop
.hbase
.TableName
;
34 import org
.apache
.hadoop
.hbase
.client
.BufferedMutator
;
35 import org
.apache
.hadoop
.hbase
.client
.Connection
;
36 import org
.apache
.hadoop
.hbase
.client
.Delete
;
37 import org
.apache
.hadoop
.hbase
.client
.Put
;
38 import org
.apache
.hadoop
.hbase
.client
.Result
;
39 import org
.apache
.hadoop
.hbase
.client
.ResultScanner
;
40 import org
.apache
.hadoop
.hbase
.client
.Scan
;
41 import org
.apache
.hadoop
.hbase
.client
.Table
;
42 import org
.apache
.hadoop
.hbase
.client
.TableDescriptorBuilder
;
43 import org
.apache
.hadoop
.hbase
.client
.TableState
;
44 import org
.apache
.hadoop
.hbase
.constraint
.ConstraintException
;
45 import org
.apache
.hadoop
.hbase
.master
.procedure
.DisableTableProcedure
;
46 import org
.apache
.hadoop
.hbase
.util
.Bytes
;
47 import org
.apache
.yetus
.audience
.InterfaceAudience
;
49 import org
.apache
.hbase
.thirdparty
.com
.google
.protobuf
.CodedInputStream
;
51 import org
.apache
.hadoop
.hbase
.shaded
.protobuf
.ProtobufUtil
;
52 import org
.apache
.hadoop
.hbase
.shaded
.protobuf
.generated
.HBaseProtos
;
55 * This is a helper class used internally to manage the namespace metadata that is stored in the ns
56 * family in meta table.
58 @InterfaceAudience.Private
59 public class TableNamespaceManager
{
61 public static final String KEY_MAX_REGIONS
= "hbase.namespace.quota.maxregions";
62 public static final String KEY_MAX_TABLES
= "hbase.namespace.quota.maxtables";
63 static final String NS_INIT_TIMEOUT
= "hbase.master.namespace.init.timeout";
64 static final int DEFAULT_NS_INIT_TIMEOUT
= 300000;
66 private final ConcurrentMap
<String
, NamespaceDescriptor
> cache
= new ConcurrentHashMap
<>();
68 private final MasterServices masterServices
;
70 TableNamespaceManager(MasterServices masterServices
) {
71 this.masterServices
= masterServices
;
74 private void migrateNamespaceTable() throws IOException
{
75 try (Table nsTable
= masterServices
.getConnection().getTable(TableName
.NAMESPACE_TABLE_NAME
);
76 ResultScanner scanner
= nsTable
.getScanner(
77 new Scan().addFamily(TableDescriptorBuilder
.NAMESPACE_FAMILY_INFO_BYTES
).readAllVersions());
78 BufferedMutator mutator
=
79 masterServices
.getConnection().getBufferedMutator(TableName
.META_TABLE_NAME
)) {
80 for (Result result
;;) {
81 result
= scanner
.next();
85 Put put
= new Put(result
.getRow());
87 .getColumnCells(TableDescriptorBuilder
.NAMESPACE_FAMILY_INFO_BYTES
,
88 TableDescriptorBuilder
.NAMESPACE_COL_DESC_BYTES
)
89 .forEach(c
-> put
.addColumn(HConstants
.NAMESPACE_FAMILY
,
90 HConstants
.NAMESPACE_COL_DESC_QUALIFIER
, c
.getTimestamp(), CellUtil
.cloneValue(c
)));
94 // schedule a disable procedure instead of block waiting here, as when disabling a table we will
95 // wait until master is initialized, but we are part of the initialization...
96 masterServices
.getMasterProcedureExecutor().submitProcedure(
97 new DisableTableProcedure(masterServices
.getMasterProcedureExecutor().getEnvironment(),
98 TableName
.NAMESPACE_TABLE_NAME
, false));
101 private void loadNamespaceIntoCache() throws IOException
{
102 try (Table table
= masterServices
.getConnection().getTable(TableName
.META_TABLE_NAME
);
103 ResultScanner scanner
= table
.getScanner(HConstants
.NAMESPACE_FAMILY
)) {
104 for (Result result
;;) {
105 result
= scanner
.next();
106 if (result
== null) {
109 Cell cell
= result
.getColumnLatestCell(HConstants
.NAMESPACE_FAMILY
,
110 HConstants
.NAMESPACE_COL_DESC_QUALIFIER
);
111 NamespaceDescriptor ns
= ProtobufUtil
112 .toNamespaceDescriptor(HBaseProtos
.NamespaceDescriptor
.parseFrom(CodedInputStream
113 .newInstance(cell
.getValueArray(), cell
.getValueOffset(), cell
.getValueLength())));
114 cache
.put(ns
.getName(), ns
);
119 public void start() throws IOException
{
120 TableState nsTableState
= MetaTableAccessor
.getTableState(masterServices
.getConnection(),
121 TableName
.NAMESPACE_TABLE_NAME
);
122 if (nsTableState
!= null && nsTableState
.isEnabled()) {
123 migrateNamespaceTable();
125 loadNamespaceIntoCache();
129 * check whether a namespace has already existed.
131 public boolean doesNamespaceExist(String namespaceName
) throws IOException
{
132 return cache
.containsKey(namespaceName
);
135 public NamespaceDescriptor
get(String name
) throws IOException
{
136 return cache
.get(name
);
139 public void addOrUpdateNamespace(NamespaceDescriptor ns
) throws IOException
{
140 insertNamespaceToMeta(masterServices
.getConnection(), ns
);
141 cache
.put(ns
.getName(), ns
);
144 public static void insertNamespaceToMeta(Connection conn
, NamespaceDescriptor ns
)
146 byte[] row
= Bytes
.toBytes(ns
.getName());
147 Put put
= new Put(row
, true).addColumn(HConstants
.NAMESPACE_FAMILY
,
148 HConstants
.NAMESPACE_COL_DESC_QUALIFIER
,
149 ProtobufUtil
.toProtoNamespaceDescriptor(ns
).toByteArray());
150 try (Table table
= conn
.getTable(TableName
.META_TABLE_NAME
)) {
155 public void deleteNamespace(String namespaceName
) throws IOException
{
156 Delete d
= new Delete(Bytes
.toBytes(namespaceName
));
157 try (Table table
= masterServices
.getConnection().getTable(TableName
.META_TABLE_NAME
)) {
160 cache
.remove(namespaceName
);
163 public List
<NamespaceDescriptor
> list() throws IOException
{
164 return cache
.values().stream().collect(Collectors
.toList());
167 public void validateTableAndRegionCount(NamespaceDescriptor desc
) throws IOException
{
168 if (getMaxRegions(desc
) <= 0) {
169 throw new ConstraintException(
170 "The max region quota for " + desc
.getName() + " is less than or equal to zero.");
172 if (getMaxTables(desc
) <= 0) {
173 throw new ConstraintException(
174 "The max tables quota for " + desc
.getName() + " is less than or equal to zero.");
178 public static long getMaxTables(NamespaceDescriptor ns
) throws IOException
{
179 String value
= ns
.getConfigurationValue(KEY_MAX_TABLES
);
181 if (StringUtils
.isNotEmpty(value
)) {
183 maxTables
= Long
.parseLong(value
);
184 } catch (NumberFormatException exp
) {
185 throw new DoNotRetryIOException("NumberFormatException while getting max tables.", exp
);
188 // The property is not set, so assume its the max long value.
189 maxTables
= Long
.MAX_VALUE
;
194 public static long getMaxRegions(NamespaceDescriptor ns
) throws IOException
{
195 String value
= ns
.getConfigurationValue(KEY_MAX_REGIONS
);
197 if (StringUtils
.isNotEmpty(value
)) {
199 maxRegions
= Long
.parseLong(value
);
200 } catch (NumberFormatException exp
) {
201 throw new DoNotRetryIOException("NumberFormatException while getting max regions.", exp
);
204 // The property is not set, so assume its the max long value.
205 maxRegions
= Long
.MAX_VALUE
;