Skip to content

Commit

Permalink
Add ShadowRouteContextDecorator (#33518)
Browse files Browse the repository at this point in the history
* Add ShadowRouteContextDecorator

* Add ShadowRouteContextDecorator
  • Loading branch information
terrymanu authored Nov 3, 2024
1 parent f361c51 commit 96848f5
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 57 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* 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.shadow.route.engine;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.shardingsphere.infra.route.context.RouteContext;
import org.apache.shardingsphere.infra.route.context.RouteMapper;
import org.apache.shardingsphere.infra.route.context.RouteUnit;
import org.apache.shardingsphere.shadow.rule.ShadowRule;

import java.util.Collection;
import java.util.LinkedList;
import java.util.Map;
import java.util.Optional;

/**
* Shadow route context decorator.
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class ShadowRouteContextDecorator {

/**
* Decorate route context.
*
* @param routeContext route context to be decorated
* @param rule shadow rule
* @param shadowDataSourceMappings shadow data source mappings
*/
public static void decorate(final RouteContext routeContext, final ShadowRule rule, final Map<String, String> shadowDataSourceMappings) {
Collection<RouteUnit> toBeRemovedRouteUnit = new LinkedList<>();
Collection<RouteUnit> toBeAddedRouteUnit = new LinkedList<>();
for (RouteUnit each : routeContext.getRouteUnits()) {
String logicName = each.getDataSourceMapper().getLogicName();
String actualName = each.getDataSourceMapper().getActualName();
Optional<String> sourceDataSourceName = rule.getSourceDataSourceName(actualName);
if (sourceDataSourceName.isPresent()) {
String shadowDataSourceName = shadowDataSourceMappings.get(sourceDataSourceName.get());
toBeRemovedRouteUnit.add(each);
toBeAddedRouteUnit.add(null == shadowDataSourceName
? new RouteUnit(new RouteMapper(logicName, sourceDataSourceName.get()), each.getTableMappers())
: new RouteUnit(new RouteMapper(logicName, shadowDataSourceName), each.getTableMappers()));
}
}
routeContext.getRouteUnits().removeAll(toBeRemovedRouteUnit);
routeContext.getRouteUnits().addAll(toBeAddedRouteUnit);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,8 @@
package org.apache.shardingsphere.shadow.route.engine;

import org.apache.shardingsphere.infra.route.context.RouteContext;
import org.apache.shardingsphere.infra.route.context.RouteMapper;
import org.apache.shardingsphere.infra.route.context.RouteUnit;
import org.apache.shardingsphere.shadow.rule.ShadowRule;

import java.util.Collection;
import java.util.LinkedList;
import java.util.Map;
import java.util.Optional;

/**
* Shadow route engine.
*/
Expand All @@ -39,30 +32,4 @@ public interface ShadowRouteEngine {
* @param rule shadow rule
*/
void route(RouteContext routeContext, ShadowRule rule);

/**
* Decorate route context.
*
* @param routeContext route context to be decorated
* @param rule shadow rule
* @param shadowDataSourceMappings shadow data source mappings
*/
default void decorateRouteContext(final RouteContext routeContext, final ShadowRule rule, final Map<String, String> shadowDataSourceMappings) {
Collection<RouteUnit> toBeRemovedRouteUnit = new LinkedList<>();
Collection<RouteUnit> toBeAddedRouteUnit = new LinkedList<>();
for (RouteUnit each : routeContext.getRouteUnits()) {
String logicName = each.getDataSourceMapper().getLogicName();
String actualName = each.getDataSourceMapper().getActualName();
Optional<String> sourceDataSourceName = rule.getSourceDataSourceName(actualName);
if (sourceDataSourceName.isPresent()) {
String shadowDataSourceName = shadowDataSourceMappings.get(sourceDataSourceName.get());
toBeRemovedRouteUnit.add(each);
toBeAddedRouteUnit.add(null == shadowDataSourceName
? new RouteUnit(new RouteMapper(logicName, sourceDataSourceName.get()), each.getTableMappers())
: new RouteUnit(new RouteMapper(logicName, shadowDataSourceName), each.getTableMappers()));
}
}
routeContext.getRouteUnits().removeAll(toBeRemovedRouteUnit);
routeContext.getRouteUnits().addAll(toBeAddedRouteUnit);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@

package org.apache.shardingsphere.shadow.route.engine.dml;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.apache.shardingsphere.infra.annotation.HighFrequencyInvocation;
import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
import org.apache.shardingsphere.infra.binder.context.type.TableAvailable;
import org.apache.shardingsphere.infra.hint.HintValueContext;
import org.apache.shardingsphere.infra.route.context.RouteContext;
import org.apache.shardingsphere.shadow.condition.ShadowColumnCondition;
import org.apache.shardingsphere.shadow.condition.ShadowDetermineCondition;
import org.apache.shardingsphere.shadow.route.engine.ShadowRouteContextDecorator;
import org.apache.shardingsphere.shadow.route.engine.ShadowRouteEngine;
import org.apache.shardingsphere.shadow.route.engine.determiner.ColumnShadowAlgorithmDeterminer;
import org.apache.shardingsphere.shadow.route.engine.determiner.HintShadowAlgorithmDeterminer;
Expand All @@ -45,25 +45,23 @@
/**
* Abstract shadow DML statement route engine.
*/
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@HighFrequencyInvocation
public abstract class AbstractShadowDMLStatementRouteEngine implements ShadowRouteEngine {

private final SQLStatementContext sqlStatementContext;

private final HintValueContext hintValueContext;

private final ShadowOperationType operationType;

private final Map<String, String> tableAliasNameMappings = new LinkedHashMap<>();
private final boolean isShadow;

@Override
public final void route(final RouteContext routeContext, final ShadowRule rule) {
tableAliasNameMappings.putAll(getTableAliasNameMappings(((TableAvailable) sqlStatementContext).getTablesContext().getSimpleTables()));
decorateRouteContext(routeContext, rule, findShadowDataSourceMappings(rule));
@Getter
private final Map<String, String> tableAliasAndNameMappings;

protected AbstractShadowDMLStatementRouteEngine(final SQLStatementContext sqlStatementContext, final HintValueContext hintValueContext, final ShadowOperationType operationType) {
this.operationType = operationType;
isShadow = hintValueContext.isShadow();
tableAliasAndNameMappings = getTableAliasAndNameMappings(((TableAvailable) sqlStatementContext).getTablesContext().getSimpleTables());
}

private Map<String, String> getTableAliasNameMappings(final Collection<SimpleTableSegment> tableSegments) {
private Map<String, String> getTableAliasAndNameMappings(final Collection<SimpleTableSegment> tableSegments) {
Map<String, String> result = new LinkedHashMap<>(tableSegments.size(), 1F);
for (SimpleTableSegment each : tableSegments) {
String tableName = each.getTableName().getIdentifier().getValue();
Expand All @@ -73,12 +71,17 @@ private Map<String, String> getTableAliasNameMappings(final Collection<SimpleTab
return result;
}

@Override
public final void route(final RouteContext routeContext, final ShadowRule rule) {
ShadowRouteContextDecorator.decorate(routeContext, rule, findShadowDataSourceMappings(rule));
}

private Map<String, String> findShadowDataSourceMappings(final ShadowRule rule) {
Collection<String> relatedShadowTables = rule.getRelatedShadowTables(tableAliasNameMappings.values());
Collection<String> relatedShadowTables = rule.getRelatedShadowTables(tableAliasAndNameMappings.values());
if (relatedShadowTables.isEmpty() && isMatchDefaultAlgorithm(rule)) {
return rule.getAllShadowDataSourceMappings();
}
Map<String, String> result = findBySQLComments(rule, relatedShadowTables);
Map<String, String> result = findBySQLHints(rule, relatedShadowTables);
return result.isEmpty() ? findByShadowColumn(rule, relatedShadowTables) : result;
}

Expand All @@ -87,25 +90,25 @@ private boolean isMatchDefaultAlgorithm(final ShadowRule rule) {
Optional<ShadowAlgorithm> defaultAlgorithm = rule.getDefaultShadowAlgorithm();
if (defaultAlgorithm.isPresent() && defaultAlgorithm.get() instanceof HintShadowAlgorithm<?>) {
ShadowDetermineCondition determineCondition = new ShadowDetermineCondition("", ShadowOperationType.HINT_MATCH);
return HintShadowAlgorithmDeterminer.isShadow((HintShadowAlgorithm<Comparable<?>>) defaultAlgorithm.get(), determineCondition, rule, hintValueContext.isShadow());
return HintShadowAlgorithmDeterminer.isShadow((HintShadowAlgorithm<Comparable<?>>) defaultAlgorithm.get(), determineCondition, rule, isShadow);
}
return false;
}

private Map<String, String> findBySQLComments(final ShadowRule rule, final Collection<String> relatedShadowTables) {
private Map<String, String> findBySQLHints(final ShadowRule rule, final Collection<String> relatedShadowTables) {
Map<String, String> result = new LinkedHashMap<>();
for (String each : relatedShadowTables) {
if (isContainsShadowInSQLComments(rule, each, new ShadowDetermineCondition(each, operationType))) {
if (isContainsShadowInSQLHints(rule, each, new ShadowDetermineCondition(each, operationType))) {
result.putAll(rule.getRelatedShadowDataSourceMappings(each));
return result;
}
}
return result;
}

private boolean isContainsShadowInSQLComments(final ShadowRule rule, final String tableName, final ShadowDetermineCondition shadowCondition) {
private boolean isContainsShadowInSQLHints(final ShadowRule rule, final String tableName, final ShadowDetermineCondition shadowCondition) {
for (HintShadowAlgorithm<Comparable<?>> each : rule.getRelatedHintShadowAlgorithms(tableName)) {
if (HintShadowAlgorithmDeterminer.isShadow(each, shadowCondition, rule, hintValueContext.isShadow())) {
if (HintShadowAlgorithmDeterminer.isShadow(each, shadowCondition, rule, isShadow)) {
return true;
}
}
Expand Down Expand Up @@ -156,6 +159,6 @@ private boolean isMatchColumnShadowAlgorithm(final String shadowTable, final Col
protected abstract Collection<ShadowColumnCondition> getShadowColumnConditions(String shadowColumnName);

protected final String getSingleTableName() {
return tableAliasNameMappings.entrySet().iterator().next().getValue();
return tableAliasAndNameMappings.entrySet().iterator().next().getValue();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,6 @@ private Collection<ExpressionSegment> getWhereSegment() {

private String extractOwnerName(final ColumnSegment columnSegment) {
Optional<OwnerSegment> owner = columnSegment.getOwner();
return owner.isPresent() ? getTableAliasNameMappings().get(owner.get().getIdentifier().getValue()) : getTableAliasNameMappings().keySet().iterator().next();
return owner.isPresent() ? getTableAliasAndNameMappings().get(owner.get().getIdentifier().getValue()) : getTableAliasAndNameMappings().keySet().iterator().next();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.apache.shardingsphere.infra.hint.HintValueContext;
import org.apache.shardingsphere.infra.route.context.RouteContext;
import org.apache.shardingsphere.shadow.condition.ShadowDetermineCondition;
import org.apache.shardingsphere.shadow.route.engine.ShadowRouteContextDecorator;
import org.apache.shardingsphere.shadow.route.engine.ShadowRouteEngine;
import org.apache.shardingsphere.shadow.route.engine.determiner.HintShadowAlgorithmDeterminer;
import org.apache.shardingsphere.shadow.rule.ShadowRule;
Expand All @@ -40,7 +41,7 @@ public final class ShadowNonDMLStatementRouteEngine implements ShadowRouteEngine

@Override
public void route(final RouteContext routeContext, final ShadowRule rule) {
decorateRouteContext(routeContext, rule, findShadowDataSourceMappings(rule));
ShadowRouteContextDecorator.decorate(routeContext, rule, findShadowDataSourceMappings(rule));
}

private Map<String, String> findShadowDataSourceMappings(final ShadowRule rule) {
Expand Down

0 comments on commit 96848f5

Please sign in to comment.