Skip to content

Commit

Permalink
[DistSQL]Support alter traffic rule syntax. (#15155)
Browse files Browse the repository at this point in the history
* Support `alter traffic rule` syntax.

* Rename variable.

* Add successful test.

* Add converter.
  • Loading branch information
lanchengx committed Jan 30, 2022
1 parent e915749 commit 0dcf5c6
Show file tree
Hide file tree
Showing 10 changed files with 340 additions and 41 deletions.
Expand Up @@ -83,6 +83,18 @@ createTrafficRule
: CREATE TRAFFIC RULE trafficRuleDefinition (COMMA trafficRuleDefinition)*
;

alterTrafficRule
: ALTER TRAFFIC RULE trafficRuleDefinition (COMMA trafficRuleDefinition)*
;

showTrafficRules
: SHOW TRAFFIC (RULES | RULE ruleName)
;

dropTrafficRule
: DROP TRAFFIC RULE ifExists? ruleName (COMMA ruleName)*
;

trafficRuleDefinition
: ruleName LP labelDefinition COMMA trafficAlgorithmDefinition COMMA loadBanlanceDefinition RP
;
Expand All @@ -107,14 +119,6 @@ typeName
: IDENTIFIER
;

showTrafficRules
: SHOW TRAFFIC (RULES | RULE ruleName)
;

dropTrafficRule
: DROP TRAFFIC RULE ifExists? ruleName (COMMA ruleName)*
;

exportSchemaConfiguration
: EXPORT SCHEMA (CONFIGURATION | CONFIG) (FROM schemaName)? (COMMA? FILE EQ filePath)?
;
Expand Down
Expand Up @@ -48,6 +48,7 @@ execute
| showTrafficRules
| dropTrafficRule
| createTrafficRule
| alterTrafficRule
| exportSchemaConfiguration
) SEMI?
;
Expand Up @@ -26,6 +26,7 @@
import org.apache.shardingsphere.distsql.parser.autogen.CommonDistSQLStatementParser.AlterDefaultSingleTableRuleContext;
import org.apache.shardingsphere.distsql.parser.autogen.CommonDistSQLStatementParser.AlterResourceContext;
import org.apache.shardingsphere.distsql.parser.autogen.CommonDistSQLStatementParser.AlterSQLParserRuleContext;
import org.apache.shardingsphere.distsql.parser.autogen.CommonDistSQLStatementParser.AlterTrafficRuleContext;
import org.apache.shardingsphere.distsql.parser.autogen.CommonDistSQLStatementParser.AlterTransactionRuleContext;
import org.apache.shardingsphere.distsql.parser.autogen.CommonDistSQLStatementParser.CacheOptionContext;
import org.apache.shardingsphere.distsql.parser.autogen.CommonDistSQLStatementParser.ClearHintContext;
Expand Down Expand Up @@ -89,6 +90,7 @@
import org.apache.shardingsphere.distsql.parser.statement.rdl.alter.AlterResourceStatement;
import org.apache.shardingsphere.distsql.parser.statement.rdl.create.AddResourceStatement;
import org.apache.shardingsphere.distsql.parser.statement.rdl.create.AlterDefaultSingleTableRuleStatement;
import org.apache.shardingsphere.distsql.parser.statement.rdl.create.AlterTrafficRuleStatement;
import org.apache.shardingsphere.distsql.parser.statement.rdl.create.CreateDefaultSingleTableRuleStatement;
import org.apache.shardingsphere.distsql.parser.statement.rdl.create.CreateTrafficRuleStatement;
import org.apache.shardingsphere.distsql.parser.statement.rdl.drop.DropDefaultSingleTableRuleStatement;
Expand Down Expand Up @@ -353,6 +355,11 @@ public ASTNode visitCreateTrafficRule(final CreateTrafficRuleContext ctx) {
return new CreateTrafficRuleStatement(ctx.trafficRuleDefinition().stream().map(each -> (TrafficRuleSegment) visit(each)).collect(Collectors.toCollection(LinkedList::new)));
}

@Override
public ASTNode visitAlterTrafficRule(final AlterTrafficRuleContext ctx) {
return new AlterTrafficRuleStatement(ctx.trafficRuleDefinition().stream().map(each -> (TrafficRuleSegment) visit(each)).collect(Collectors.toCollection(LinkedList::new)));
}

@Override
public ASTNode visitShowTrafficRules(final ShowTrafficRulesContext ctx) {
ShowTrafficRulesStatement result = new ShowTrafficRulesStatement();
Expand All @@ -364,7 +371,7 @@ public ASTNode visitShowTrafficRules(final ShowTrafficRulesContext ctx) {

@Override
public ASTNode visitTrafficRuleDefinition(final TrafficRuleDefinitionContext ctx) {
return new TrafficRuleSegment(getIdentifierValue(ctx.ruleName()), buildLabels(ctx.labelDefinition()),
return new TrafficRuleSegment(getIdentifierValue(ctx.ruleName()), buildLabels(ctx.labelDefinition()),
(AlgorithmSegment) visit(ctx.trafficAlgorithmDefinition().algorithmDefinition()), (AlgorithmSegment) visit(ctx.loadBanlanceDefinition().algorithmDefinition()));
}

Expand Down
@@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.shardingsphere.distsql.parser.statement.rdl.create;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.apache.shardingsphere.distsql.parser.segment.TrafficRuleSegment;
import org.apache.shardingsphere.distsql.parser.statement.ral.common.AlterDistSQLStatement;

import java.util.Collection;

/**
* Alter traffic rule statement.
*/
@RequiredArgsConstructor
@Getter
public final class AlterTrafficRuleStatement extends AlterDistSQLStatement {

private final Collection<TrafficRuleSegment> segments;
}
Expand Up @@ -34,6 +34,10 @@ public RequiredRuleMissedException(final String ruleType, final String schemaNam
super(1112, String.format("%s rule does not exist in schema `%s`.", ruleType, schemaName));
}

public RequiredRuleMissedException(final String ruleType, final Collection<String> ruleNames) {
super(1112, String.format("%s rules `%s` do not exist.", ruleType, ruleNames));
}

public RequiredRuleMissedException(final String ruleType, final String schemaName, final String ruleName) {
super(1112, String.format("%s rule `%s` do not exist in schema `%s`.", ruleType, ruleName, schemaName));
}
Expand Down
Expand Up @@ -20,8 +20,10 @@
import org.apache.shardingsphere.distsql.parser.statement.ral.common.AlterDistSQLStatement;
import org.apache.shardingsphere.distsql.parser.statement.ral.common.alter.AlterSQLParserRuleStatement;
import org.apache.shardingsphere.distsql.parser.statement.ral.common.alter.AlterTransactionRuleStatement;
import org.apache.shardingsphere.distsql.parser.statement.rdl.create.AlterTrafficRuleStatement;
import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
import org.apache.shardingsphere.proxy.backend.text.distsql.ral.common.alter.excutor.AlterSQLParserRuleExecutor;
import org.apache.shardingsphere.proxy.backend.text.distsql.ral.common.alter.excutor.AlterTrafficRuleExecutor;
import org.apache.shardingsphere.proxy.backend.text.distsql.ral.common.alter.excutor.AlterTransactionRuleExecutor;

import java.sql.SQLException;
Expand All @@ -46,6 +48,9 @@ public static AlterStatementExecutor newInstance(final AlterDistSQLStatement sql
if (sqlStatement instanceof AlterSQLParserRuleStatement) {
return new AlterSQLParserRuleExecutor((AlterSQLParserRuleStatement) sqlStatement);
}
if (sqlStatement instanceof AlterTrafficRuleStatement) {
return new AlterTrafficRuleExecutor((AlterTrafficRuleStatement) sqlStatement);
}
throw new UnsupportedOperationException(sqlStatement.getClass().getCanonicalName());
}
}
@@ -0,0 +1,94 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.shardingsphere.proxy.backend.text.distsql.ral.common.alter.excutor;

import lombok.RequiredArgsConstructor;
import org.apache.shardingsphere.distsql.parser.segment.TrafficRuleSegment;
import org.apache.shardingsphere.distsql.parser.statement.rdl.create.AlterTrafficRuleStatement;
import org.apache.shardingsphere.infra.distsql.exception.DistSQLException;
import org.apache.shardingsphere.infra.distsql.exception.rule.InvalidAlgorithmConfigurationException;
import org.apache.shardingsphere.infra.distsql.exception.rule.RequiredRuleMissedException;
import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
import org.apache.shardingsphere.mode.metadata.persist.MetaDataPersistService;
import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
import org.apache.shardingsphere.proxy.backend.response.header.ResponseHeader;
import org.apache.shardingsphere.proxy.backend.response.header.update.UpdateResponseHeader;
import org.apache.shardingsphere.proxy.backend.text.distsql.ral.common.alter.AlterStatementExecutor;
import org.apache.shardingsphere.proxy.backend.text.distsql.ral.common.convert.TrafficRuleConverter;
import org.apache.shardingsphere.spi.typed.TypedSPIRegistry;
import org.apache.shardingsphere.traffic.api.config.TrafficRuleConfiguration;
import org.apache.shardingsphere.traffic.api.config.TrafficStrategyConfiguration;
import org.apache.shardingsphere.traffic.spi.TrafficAlgorithm;
import org.apache.shardingsphere.traffic.spi.TrafficLoadBalanceAlgorithm;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;

/**
* Alter traffic rule handler.
*/
@RequiredArgsConstructor
public final class AlterTrafficRuleExecutor implements AlterStatementExecutor {

private final AlterTrafficRuleStatement sqlStatement;

@Override
public ResponseHeader execute() throws DistSQLException {
Optional<TrafficRuleConfiguration> currentConfiguration = ProxyContext.getInstance().getContextManager().getMetaDataContexts().getGlobalRuleMetaData()
.findRuleConfiguration(TrafficRuleConfiguration.class).stream().findAny();
check(sqlStatement, currentConfiguration);
TrafficRuleConfiguration toBeAlteredConfiguration = TrafficRuleConverter.convert(sqlStatement.getSegments());
updateToRepository(toBeAlteredConfiguration, currentConfiguration.get());
return new UpdateResponseHeader(sqlStatement);
}

private void check(final AlterTrafficRuleStatement sqlStatement, final Optional<TrafficRuleConfiguration> currentConfiguration) throws DistSQLException {
DistSQLException.predictionThrow(currentConfiguration.isPresent(), new RequiredRuleMissedException("Traffic"));
Collection<String> currentRuleNames = currentConfiguration.get().getTrafficStrategies().stream().map(TrafficStrategyConfiguration::getName).collect(Collectors.toSet());
Set<String> notExistRuleNames = sqlStatement.getSegments().stream().map(TrafficRuleSegment::getName).filter(each -> !currentRuleNames.contains(each)).collect(Collectors.toSet());
DistSQLException.predictionThrow(notExistRuleNames.isEmpty(), new RequiredRuleMissedException("Traffic", notExistRuleNames));
Collection<String> invalidAlgorithmNames = getInvalidAlgorithmNames(sqlStatement.getSegments());
DistSQLException.predictionThrow(invalidAlgorithmNames.isEmpty(), new InvalidAlgorithmConfigurationException("traffic", invalidAlgorithmNames));
}

private Collection<String> getInvalidAlgorithmNames(final Collection<TrafficRuleSegment> segments) {
Collection<String> result = new ArrayList<>(segments.size());
sqlStatement.getSegments().forEach(each -> {
if (!TypedSPIRegistry.findRegisteredService(TrafficAlgorithm.class, each.getAlgorithm().getName(), new Properties()).isPresent()) {
result.add(each.getAlgorithm().getName());
}
if (!TypedSPIRegistry.findRegisteredService(TrafficLoadBalanceAlgorithm.class, each.getLoadBalancer().getName(), new Properties()).isPresent()) {
result.add(each.getLoadBalancer().getName());
}
});
return result;
}

private void updateToRepository(final TrafficRuleConfiguration toBeAlteredConfiguration, final TrafficRuleConfiguration currentConfiguration) {
currentConfiguration.getTrafficStrategies().addAll(toBeAlteredConfiguration.getTrafficStrategies());
currentConfiguration.getTrafficAlgorithms().putAll(toBeAlteredConfiguration.getTrafficAlgorithms());
currentConfiguration.getLoadBalancers().putAll(toBeAlteredConfiguration.getLoadBalancers());
MetaDataContexts metaDataContexts = ProxyContext.getInstance().getContextManager().getMetaDataContexts();
Optional<MetaDataPersistService> metaDataPersistService = metaDataContexts.getMetaDataPersistService();
metaDataPersistService.ifPresent(op -> op.getGlobalRuleService().persist(metaDataContexts.getGlobalRuleMetaData().getConfigurations(), true));
}
}
@@ -0,0 +1,67 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.shardingsphere.proxy.backend.text.distsql.ral.common.convert;

import org.apache.shardingsphere.distsql.parser.segment.AlgorithmSegment;
import org.apache.shardingsphere.distsql.parser.segment.TrafficRuleSegment;
import org.apache.shardingsphere.infra.config.algorithm.ShardingSphereAlgorithmConfiguration;
import org.apache.shardingsphere.traffic.api.config.TrafficRuleConfiguration;
import org.apache.shardingsphere.traffic.api.config.TrafficStrategyConfiguration;

import java.util.Collection;

/**
* Traffic rule converter.
*/
public final class TrafficRuleConverter {

/**
* Convert traffic rule segment to traffic rule configuration.
*
* @param segments traffic rule segments
* @return traffic rule configuration
*/
public static TrafficRuleConfiguration convert(final Collection<TrafficRuleSegment> segments) {
TrafficRuleConfiguration result = new TrafficRuleConfiguration();
segments.forEach(each -> setConfigurationData(result, each));
return result;
}

private static void setConfigurationData(final TrafficRuleConfiguration result, final TrafficRuleSegment each) {
ShardingSphereAlgorithmConfiguration trafficAlgorithm = createAlgorithmConfiguration(each.getAlgorithm());
ShardingSphereAlgorithmConfiguration loadBalancer = createAlgorithmConfiguration(each.getLoadBalancer());
String trafficAlgorithmName = createAlgorithmName(each.getName(), trafficAlgorithm);
String loadBalancerName = createAlgorithmName(each.getName(), loadBalancer);
TrafficStrategyConfiguration trafficStrategy = createTrafficStrategy(each, trafficAlgorithmName, loadBalancerName);
result.getTrafficStrategies().add(trafficStrategy);
result.getTrafficAlgorithms().put(trafficAlgorithmName, trafficAlgorithm);
result.getLoadBalancers().put(loadBalancerName, loadBalancer);
}

private static ShardingSphereAlgorithmConfiguration createAlgorithmConfiguration(final AlgorithmSegment segment) {
return new ShardingSphereAlgorithmConfiguration(segment.getName(), segment.getProps());
}

private static TrafficStrategyConfiguration createTrafficStrategy(final TrafficRuleSegment trafficRuleSegment, final String trafficAlgorithmName, final String loadBalancerName) {
return new TrafficStrategyConfiguration(trafficRuleSegment.getName(), trafficRuleSegment.getLabels(), trafficAlgorithmName, loadBalancerName);
}

private static String createAlgorithmName(final String ruleName, final ShardingSphereAlgorithmConfiguration algorithm) {
return String.format("%s_%s", ruleName, algorithm.getType()).toLowerCase();
}
}

0 comments on commit 0dcf5c6

Please sign in to comment.