|
21 | 21 | import java.io.IOException; |
22 | 22 | import java.util.Collections; |
23 | 23 | import java.util.List; |
| 24 | +import java.util.Objects; |
24 | 25 | import java.util.Optional; |
25 | 26 | import java.util.Set; |
| 27 | +import java.util.function.Supplier; |
26 | 28 | import java.util.stream.Collectors; |
27 | 29 | import org.apache.hadoop.hbase.CoprocessorEnvironment; |
28 | | -import org.apache.hadoop.hbase.HBaseIOException; |
29 | 30 | import org.apache.hadoop.hbase.HConstants; |
30 | 31 | import org.apache.hadoop.hbase.NamespaceDescriptor; |
31 | 32 | import org.apache.hadoop.hbase.ServerName; |
@@ -68,7 +69,7 @@ public void start(CoprocessorEnvironment env) throws IOException { |
68 | 69 | groupInfoManager = RSGroupInfoManagerImpl.getInstance(master); |
69 | 70 | groupAdminServer = new RSGroupAdminServer(master, groupInfoManager); |
70 | 71 | Class<?> clazz = |
71 | | - master.getConfiguration().getClass(HConstants.HBASE_MASTER_LOADBALANCER_CLASS, null); |
| 72 | + master.getConfiguration().getClass(HConstants.HBASE_MASTER_LOADBALANCER_CLASS, null); |
72 | 73 | if (!RSGroupableBalancer.class.isAssignableFrom(clazz)) { |
73 | 74 | throw new IOException("Configured balancer does not support RegionServer groups."); |
74 | 75 | } |
@@ -108,85 +109,101 @@ RSGroupAdminServiceImpl getGroupAdminService() { |
108 | 109 |
|
109 | 110 | @Override |
110 | 111 | public void postClearDeadServers(ObserverContext<MasterCoprocessorEnvironment> ctx, |
111 | | - List<ServerName> servers, List<ServerName> notClearedServers) throws IOException { |
| 112 | + List<ServerName> servers, List<ServerName> notClearedServers) throws IOException { |
112 | 113 | Set<Address> clearedServer = |
113 | | - servers.stream().filter(server -> !notClearedServers.contains(server)) |
114 | | - .map(ServerName::getAddress).collect(Collectors.toSet()); |
| 114 | + servers.stream().filter(server -> !notClearedServers.contains(server)) |
| 115 | + .map(ServerName::getAddress).collect(Collectors.toSet()); |
115 | 116 | if (!clearedServer.isEmpty()) { |
116 | 117 | groupAdminServer.removeServers(clearedServer); |
117 | 118 | } |
118 | 119 | } |
119 | 120 |
|
120 | | - private void checkGroupExists(Optional<String> optGroupName) throws IOException { |
| 121 | + private RSGroupInfo checkGroupExists(Optional<String> optGroupName, Supplier<String> forWhom) |
| 122 | + throws IOException { |
121 | 123 | if (optGroupName.isPresent()) { |
122 | 124 | String groupName = optGroupName.get(); |
123 | | - if (groupAdminServer.getRSGroupInfo(groupName) == null) { |
124 | | - throw new ConstraintException("Region server group " + groupName + " does not exit"); |
| 125 | + RSGroupInfo group = groupAdminServer.getRSGroupInfo(groupName); |
| 126 | + if (group == null) { |
| 127 | + throw new ConstraintException( |
| 128 | + "Region server group " + groupName + " for " + forWhom.get() + " does not exit"); |
125 | 129 | } |
| 130 | + return group; |
126 | 131 | } |
| 132 | + return null; |
127 | 133 | } |
128 | 134 |
|
129 | | - private boolean rsgroupHasServersOnline(TableDescriptor desc) throws IOException { |
130 | | - RSGroupInfo rsGroupInfo; |
131 | | - Optional<String> optGroupName = desc.getRegionServerGroup(); |
132 | | - if (optGroupName.isPresent()) { |
133 | | - String groupName = optGroupName.get(); |
134 | | - if (groupName.equals(RSGroupInfo.DEFAULT_GROUP)) { |
135 | | - // do not check for default group |
136 | | - return true; |
137 | | - } |
138 | | - rsGroupInfo = groupAdminServer.getRSGroupInfo(groupName); |
139 | | - if (rsGroupInfo == null) { |
140 | | - throw new ConstraintException( |
141 | | - "RSGroup " + groupName + " for table " + desc.getTableName() + " does not exist"); |
142 | | - } |
143 | | - } else { |
144 | | - NamespaceDescriptor nd = |
145 | | - master.getClusterSchema().getNamespace(desc.getTableName().getNamespaceAsString()); |
146 | | - String groupNameOfNs = nd.getConfigurationValue(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP); |
147 | | - if (groupNameOfNs == null || groupNameOfNs.equals(RSGroupInfo.DEFAULT_GROUP)) { |
148 | | - // do not check for default group |
149 | | - return true; |
150 | | - } |
151 | | - rsGroupInfo = groupAdminServer.getRSGroupInfo(groupNameOfNs); |
152 | | - if (rsGroupInfo == null) { |
153 | | - throw new ConstraintException("RSGroup " + groupNameOfNs + " for table " + |
154 | | - desc.getTableName() + "(inherit from namespace) does not exist"); |
155 | | - } |
| 135 | + private Optional<String> getNamespaceGroup(NamespaceDescriptor namespaceDesc) { |
| 136 | + return Optional |
| 137 | + .ofNullable(namespaceDesc.getConfigurationValue(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP)); |
| 138 | + } |
| 139 | + |
| 140 | + // Do not allow creating new tables/namespaces which has an empty rs group, expect the default rs |
| 141 | + // group. Notice that we do not check for online servers, as this is not stable because region |
| 142 | + // servers can die at any time. |
| 143 | + private void checkGroupNotEmpty(RSGroupInfo rsGroupInfo, Supplier<String> forWhom) |
| 144 | + throws ConstraintException { |
| 145 | + if (rsGroupInfo == null || rsGroupInfo.getName().equals(RSGroupInfo.DEFAULT_GROUP)) { |
| 146 | + // we do not have a rs group config or we explicitly set the rs group to default, then no need |
| 147 | + // to check. |
| 148 | + return; |
| 149 | + } |
| 150 | + if (rsGroupInfo.getServers().isEmpty()) { |
| 151 | + throw new ConstraintException( |
| 152 | + "No servers in the rsgroup " + rsGroupInfo.getName() + " for " + forWhom.get()); |
156 | 153 | } |
157 | | - return master.getServerManager().createDestinationServersList().stream() |
158 | | - .anyMatch(onlineServer -> rsGroupInfo.containsServer(onlineServer.getAddress())); |
159 | 154 | } |
160 | 155 |
|
161 | 156 | @Override |
162 | 157 | public void preCreateTableAction(ObserverContext<MasterCoprocessorEnvironment> ctx, |
163 | | - TableDescriptor desc, RegionInfo[] regions) throws IOException { |
164 | | - checkGroupExists(desc.getRegionServerGroup()); |
165 | | - if (!desc.getTableName().isSystemTable() && !rsgroupHasServersOnline(desc)) { |
166 | | - throw new HBaseIOException("No online servers in the rsgroup for " + desc); |
| 158 | + TableDescriptor desc, RegionInfo[] regions) throws IOException { |
| 159 | + if (desc.getTableName().isSystemTable()) { |
| 160 | + // do not check for system tables as we may block the bootstrap. |
| 161 | + return; |
| 162 | + } |
| 163 | + Supplier<String> forWhom = () -> "table " + desc.getTableName(); |
| 164 | + RSGroupInfo rsGroupInfo = checkGroupExists(desc.getRegionServerGroup(), forWhom); |
| 165 | + if (rsGroupInfo == null) { |
| 166 | + // we do not set rs group info on table, check if we have one on namespace |
| 167 | + String namespace = desc.getTableName().getNamespaceAsString(); |
| 168 | + NamespaceDescriptor nd = master.getClusterSchema().getNamespace(namespace); |
| 169 | + forWhom = () -> "table " + desc.getTableName() + "(inherit from namespace)"; |
| 170 | + rsGroupInfo = checkGroupExists(getNamespaceGroup(nd), forWhom); |
167 | 171 | } |
| 172 | + checkGroupNotEmpty(rsGroupInfo, forWhom); |
168 | 173 | } |
169 | 174 |
|
170 | 175 | @Override |
171 | 176 | public TableDescriptor preModifyTable(ObserverContext<MasterCoprocessorEnvironment> ctx, |
172 | | - TableName tableName, TableDescriptor currentDescriptor, TableDescriptor newDescriptor) |
173 | | - throws IOException { |
174 | | - checkGroupExists(newDescriptor.getRegionServerGroup()); |
| 177 | + TableName tableName, TableDescriptor currentDescriptor, TableDescriptor newDescriptor) |
| 178 | + throws IOException { |
| 179 | + if (!currentDescriptor.getRegionServerGroup().equals(newDescriptor.getRegionServerGroup())) { |
| 180 | + Supplier<String> forWhom = () -> "table " + newDescriptor.getTableName(); |
| 181 | + RSGroupInfo rsGroupInfo = checkGroupExists(newDescriptor.getRegionServerGroup(), forWhom); |
| 182 | + checkGroupNotEmpty(rsGroupInfo, forWhom); |
| 183 | + } |
175 | 184 | return MasterObserver.super.preModifyTable(ctx, tableName, currentDescriptor, newDescriptor); |
176 | 185 | } |
177 | 186 |
|
| 187 | + private void checkNamespaceGroup(NamespaceDescriptor nd) throws IOException { |
| 188 | + Supplier<String> forWhom = () -> "namespace " + nd.getName(); |
| 189 | + RSGroupInfo rsGroupInfo = checkGroupExists(getNamespaceGroup(nd), forWhom); |
| 190 | + checkGroupNotEmpty(rsGroupInfo, forWhom); |
| 191 | + } |
| 192 | + |
178 | 193 | @Override |
179 | 194 | public void preCreateNamespace(ObserverContext<MasterCoprocessorEnvironment> ctx, |
180 | | - NamespaceDescriptor ns) throws IOException { |
181 | | - checkGroupExists( |
182 | | - Optional.ofNullable(ns.getConfigurationValue(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP))); |
| 195 | + NamespaceDescriptor ns) throws IOException { |
| 196 | + checkNamespaceGroup(ns); |
183 | 197 | } |
184 | 198 |
|
185 | 199 | @Override |
186 | 200 | public void preModifyNamespace(ObserverContext<MasterCoprocessorEnvironment> ctx, |
187 | | - NamespaceDescriptor currentNsDescriptor, NamespaceDescriptor newNsDescriptor) |
188 | | - throws IOException { |
189 | | - checkGroupExists(Optional |
190 | | - .ofNullable(newNsDescriptor.getConfigurationValue(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP))); |
| 201 | + NamespaceDescriptor currentNsDescriptor, NamespaceDescriptor newNsDescriptor) |
| 202 | + throws IOException { |
| 203 | + if (!Objects.equals( |
| 204 | + currentNsDescriptor.getConfigurationValue(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP), |
| 205 | + newNsDescriptor.getConfigurationValue(RSGroupInfo.NAMESPACE_DESC_PROP_GROUP))) { |
| 206 | + checkNamespaceGroup(newNsDescriptor); |
| 207 | + } |
191 | 208 | } |
192 | 209 | } |
0 commit comments