View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shardingsphere.traffic.rule;
19  
20  import com.google.common.base.Preconditions;
21  import lombok.Getter;
22  import org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
23  import org.apache.shardingsphere.infra.algorithm.loadbalancer.core.LoadBalanceAlgorithm;
24  import org.apache.shardingsphere.infra.hint.HintValueContext;
25  import org.apache.shardingsphere.infra.rule.scope.GlobalRule;
26  import org.apache.shardingsphere.infra.rule.attribute.RuleAttributes;
27  import org.apache.shardingsphere.infra.session.query.QueryContext;
28  import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
29  import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
30  import org.apache.shardingsphere.traffic.api.config.TrafficRuleConfiguration;
31  import org.apache.shardingsphere.traffic.api.config.TrafficStrategyConfiguration;
32  import org.apache.shardingsphere.traffic.api.traffic.hint.HintTrafficAlgorithm;
33  import org.apache.shardingsphere.traffic.api.traffic.hint.HintTrafficValue;
34  import org.apache.shardingsphere.traffic.api.traffic.identifier.SimplifiedTrafficAlgorithm;
35  import org.apache.shardingsphere.traffic.api.traffic.segment.SegmentTrafficAlgorithm;
36  import org.apache.shardingsphere.traffic.api.traffic.segment.SegmentTrafficValue;
37  import org.apache.shardingsphere.traffic.api.traffic.transaction.TransactionTrafficAlgorithm;
38  import org.apache.shardingsphere.traffic.api.traffic.transaction.TransactionTrafficValue;
39  import org.apache.shardingsphere.traffic.spi.TrafficAlgorithm;
40  
41  import java.util.Collection;
42  import java.util.Collections;
43  import java.util.HashSet;
44  import java.util.LinkedHashMap;
45  import java.util.LinkedHashSet;
46  import java.util.LinkedList;
47  import java.util.Map;
48  import java.util.Optional;
49  
50  /**
51   * Traffic rule.
52   */
53  @Getter
54  public final class TrafficRule implements GlobalRule {
55      
56      private final TrafficRuleConfiguration configuration;
57      
58      private final Collection<TrafficStrategyRule> strategyRules;
59      
60      public TrafficRule(final TrafficRuleConfiguration ruleConfig) {
61          configuration = ruleConfig;
62          Map<String, TrafficAlgorithm> trafficAlgorithms = createTrafficAlgorithms(ruleConfig.getTrafficAlgorithms());
63          Map<String, LoadBalanceAlgorithm> loadBalancers = createLoadBalanceAlgorithms(ruleConfig.getLoadBalancers());
64          strategyRules = createTrafficStrategyRules(ruleConfig.getTrafficStrategies(), trafficAlgorithms, loadBalancers);
65      }
66      
67      private Map<String, TrafficAlgorithm> createTrafficAlgorithms(final Map<String, AlgorithmConfiguration> trafficAlgorithms) {
68          Map<String, TrafficAlgorithm> result = new LinkedHashMap<>();
69          for (TrafficStrategyConfiguration each : configuration.getTrafficStrategies()) {
70              if (null == trafficAlgorithms.get(each.getAlgorithmName())) {
71                  break;
72              }
73              AlgorithmConfiguration algorithmConfig = trafficAlgorithms.get(each.getAlgorithmName());
74              result.put(each.getName() + "." + each.getAlgorithmName(), TypedSPILoader.getService(TrafficAlgorithm.class, algorithmConfig.getType(), algorithmConfig.getProps()));
75          }
76          return result;
77      }
78      
79      private Map<String, LoadBalanceAlgorithm> createLoadBalanceAlgorithms(final Map<String, AlgorithmConfiguration> loadBalancers) {
80          Map<String, LoadBalanceAlgorithm> result = new LinkedHashMap<>();
81          for (TrafficStrategyConfiguration each : configuration.getTrafficStrategies()) {
82              if (null == loadBalancers.get(each.getLoadBalancerName())) {
83                  break;
84              }
85              AlgorithmConfiguration algorithmConfig = loadBalancers.get(each.getLoadBalancerName());
86              result.put(each.getName() + "." + each.getLoadBalancerName(), TypedSPILoader.getService(LoadBalanceAlgorithm.class, algorithmConfig.getType(), algorithmConfig.getProps()));
87          }
88          return result;
89      }
90      
91      private Collection<TrafficStrategyRule> createTrafficStrategyRules(final Collection<TrafficStrategyConfiguration> trafficStrategies,
92                                                                         final Map<String, TrafficAlgorithm> trafficAlgorithms, final Map<String, LoadBalanceAlgorithm> loadBalancers) {
93          Collection<TrafficStrategyRule> noneTransactionStrategyRules = new LinkedList<>();
94          Collection<TrafficStrategyRule> result = new LinkedList<>();
95          for (TrafficStrategyConfiguration each : trafficStrategies) {
96              TrafficAlgorithm trafficAlgorithm = getTrafficAlgorithm(each, trafficAlgorithms);
97              TrafficStrategyRule trafficStrategyRule = createTrafficStrategyRule(each, trafficAlgorithm, loadBalancers);
98              if (isTransactionStrategyRule(trafficAlgorithm)) {
99                  result.add(trafficStrategyRule);
100             } else {
101                 noneTransactionStrategyRules.add(trafficStrategyRule);
102             }
103         }
104         result.addAll(noneTransactionStrategyRules);
105         return result;
106     }
107     
108     private TrafficStrategyRule createTrafficStrategyRule(final TrafficStrategyConfiguration strategyConfig, final TrafficAlgorithm trafficAlgorithm,
109                                                           final Map<String, LoadBalanceAlgorithm> loadBalancers) {
110         TrafficStrategyRule result;
111         if (trafficAlgorithm instanceof SimplifiedTrafficAlgorithm) {
112             result = new TrafficStrategyRule(strategyConfig.getName(), Collections.emptyList(), trafficAlgorithm, null);
113         } else {
114             LoadBalanceAlgorithm loadBalancer = getLoadBalancer(strategyConfig, loadBalancers);
115             result = new TrafficStrategyRule(strategyConfig.getName(), new LinkedHashSet<>(strategyConfig.getLabels()), trafficAlgorithm, loadBalancer);
116         }
117         return result;
118     }
119     
120     private boolean isTransactionStrategyRule(final TrafficAlgorithm trafficAlgorithm) {
121         return trafficAlgorithm instanceof TransactionTrafficAlgorithm;
122     }
123     
124     /**
125      * Find matched strategy rule.
126      * 
127      * @param queryContext query context
128      * @param inTransaction is in transaction
129      * @return matched strategy rule
130      */
131     public Optional<TrafficStrategyRule> findMatchedStrategyRule(final QueryContext queryContext, final boolean inTransaction) {
132         for (TrafficStrategyRule each : strategyRules) {
133             if (match(each.getTrafficAlgorithm(), queryContext, inTransaction)) {
134                 return Optional.of(each);
135             }
136         }
137         return Optional.empty();
138     }
139     
140     private TrafficAlgorithm getTrafficAlgorithm(final TrafficStrategyConfiguration strategyConfig, final Map<String, TrafficAlgorithm> trafficAlgorithms) {
141         TrafficAlgorithm result = trafficAlgorithms.get(strategyConfig.getName() + "." + strategyConfig.getAlgorithmName());
142         Preconditions.checkState(null != result, "Traffic algorithm can not be null.");
143         return result;
144     }
145     
146     private boolean match(final TrafficAlgorithm trafficAlgorithm, final QueryContext queryContext, final boolean inTransaction) {
147         if (trafficAlgorithm instanceof TransactionTrafficAlgorithm) {
148             return matchTransactionTraffic((TransactionTrafficAlgorithm) trafficAlgorithm, inTransaction);
149         }
150         if (trafficAlgorithm instanceof HintTrafficAlgorithm) {
151             return matchHintTraffic((HintTrafficAlgorithm) trafficAlgorithm, queryContext.getHintValueContext());
152         }
153         if (trafficAlgorithm instanceof SegmentTrafficAlgorithm) {
154             SQLStatement sqlStatement = queryContext.getSqlStatementContext().getSqlStatement();
155             return matchSegmentTraffic((SegmentTrafficAlgorithm) trafficAlgorithm, queryContext.getSql(), sqlStatement);
156         }
157         return false;
158     }
159     
160     private boolean matchHintTraffic(final HintTrafficAlgorithm trafficAlgorithm, final HintValueContext hintValueContext) {
161         HintTrafficValue hintTrafficValue = new HintTrafficValue(hintValueContext);
162         return trafficAlgorithm.match(hintTrafficValue);
163     }
164     
165     private boolean matchSegmentTraffic(final SegmentTrafficAlgorithm trafficAlgorithm, final String sql, final SQLStatement sqlStatement) {
166         SegmentTrafficValue segmentTrafficValue = new SegmentTrafficValue(sqlStatement, sql);
167         return trafficAlgorithm.match(segmentTrafficValue);
168     }
169     
170     private boolean matchTransactionTraffic(final TransactionTrafficAlgorithm trafficAlgorithm, final boolean inTransaction) {
171         TransactionTrafficValue transactionTrafficValue = new TransactionTrafficValue(inTransaction);
172         return trafficAlgorithm.match(transactionTrafficValue);
173     }
174     
175     private LoadBalanceAlgorithm getLoadBalancer(final TrafficStrategyConfiguration strategyConfig, final Map<String, LoadBalanceAlgorithm> loadBalancers) {
176         LoadBalanceAlgorithm result = loadBalancers.get(strategyConfig.getName() + "." + strategyConfig.getLoadBalancerName());
177         Preconditions.checkState(null != result, "Traffic load balance algorithm can not be null.");
178         return result;
179     }
180     
181     /**
182      * Get label collection.
183      * 
184      * @return label collection
185      */
186     public Collection<String> getLabels() {
187         Collection<String> result = new HashSet<>();
188         for (TrafficStrategyRule each : strategyRules) {
189             result.addAll(each.getLabels());
190         }
191         return result;
192     }
193     
194     @Override
195     public RuleAttributes getAttributes() {
196         return new RuleAttributes();
197     }
198 }