| 
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