The target

Continue the third analysis article in this series: analyzing the source code for the Routing Engine.

In the last article, we analyzed the source code of the parsing engine and learned that the sqlStatement obtained after parsing contains the context information needed to refine the sharding, that is, to serve the routing engine in the next step.

So, how does the routing engine work? By analyzing the source code, we tried to find out

Review documentation for a quick start

First of all, by referring to official documents, we know a variety of routing strategies of ShardingSphere and matching scenes, as shown in the following figure:

Concept to explain

In the official introduction, there are a lot of technical terms, such as: sharding key, sharding algorithm, Hint, forced sharding route, etc. Beginners must understand these concepts first, to better understand the routing engine works.

The above terms, consult: shardingsphere.apache.org/document/cu…

In addition:

Binding table: a primary table and a sub-table whose sharding rules are consistent. For example, if the t_ORDER and T_ORDER_item tables are sharded according to order_ID and the partitioning keys between the bound tables are identical, the two tables are bound to each other. Cartesian product association does not appear in multi-table associated query between bound tables, which greatly improves the efficiency of associated query.Copy the code

Parsing the source code

From the previous step, we learned that the routing engine matches sharding policies of databases and tables according to the parsing context and generates routing paths.

Next, we find out the working process of the routing engine by analyzing the source code:

// Select the entry, set the breakpoint, execute the route, GenerateExecutionContext (Final LogicSQL LogicSQL, final ShardingSphereMetaData metaData, RouteContext = route(logicSQL, metaData, props) {// RouteContext RouteContext = route(logicSQL, metaData, props); Rewrite (logicSQL, metaData, props, routeContext); // Rewrite SQLRewriteResult = rewrite(logicSQL, metaData, props, routeContext); // Execute ExecutionContext result = createExecutionContext(logicSQL, metaData, routeContext, rewriteResult); // Log printing logSQL(logicSQL, props, result); return result; }Copy the code

1. Obtain the actuator and start executing it

RouteContext route(Final LogicSQL LogicSQL, final ShardingSphereMetaData metaData) {RouteContext route(final LogicSQL LogicSQL, final ShardingSphereMetaData metaData) { Use full or partial route actuators. The condition is as follows: sqlStatement instanceof MySQLShowTablesStatement? SQLRouteExecutor executor = isNeedAllSchemas(logicSQL.getSqlStatementContext().getSqlStatement()) ? new AllSQLRouteExecutor() : new PartialSQLRouteExecutor(rules, props); return executor.route(logicSQL, metaData); }Copy the code

2. After obtaining the configured sharding rules, verify and merge them

public RouteContext createRouteContext(final LogicSQL logicSQL, final ShardingSphereMetaData metaData, final ShardingRule rule, final ConfigurationProperties props) { RouteContext result = new RouteContext(); SQLStatement sqlStatement = logicSQL.getSqlStatementContext().getSqlStatement(); ShardingConditions = createShardingConditions(logicSQL, metaData, rule); / / validators verify fragmentation rules Optional < ShardingStatementValidator > validator = ShardingStatementValidatorFactory.newInstance(sqlStatement, shardingConditions); validator.ifPresent(v -> v.preValidate(rule, logicSQL.getSqlStatementContext(), logicSQL.getParameters(), metaData.getSchema())); /* * Whether the current sharding rule needs to be merged * 1, * 2 DML statements, is the query and includes the subquery * / if (sqlStatement instanceof DMLStatement && shardingConditions. IsNeedMerge ()) {/ / Keep only the last rule shardingconditions.merge (); } // After obtaining the corresponding policy, execute the routing policy. And to write the results result variable ShardingRouteEngineFactory. NewInstance (rule, metaData, logicSQL getSqlStatementContext (), shardingConditions, props).route(result, rule); validator.ifPresent(v -> v.postValidate(rule, logicSQL.getSqlStatementContext(), result, metaData.getSchema())); return result; }Copy the code

3. Run the sharding rule

Public void route(final RouteContext RouteContext, final ShardingRule ShardingRule) {/** * DataNode: Path information after routing, Including the DB, table * / Collection < DataNode > dataNodes = getDataNodes (shardingRule, shardingRule getTableRule (logicTableName)); routeContext.getOriginalDataNodes().addAll(originalDataNodes); for (DataNode each : DataNodes) {// Iterate over the returned data node, To the routing context 】 【 routeContext. GetRouteUnits (). The add (new RouteUnit (new RouteMapper (each. GetDataSourceName (), each.getDataSourceName()), Collections.singleton(new RouteMapper(logicTableName, each.getTableName())))); }}Copy the code

3.1. Access to sub-database rules and sub-table rules

private Collection<DataNode> getDataNodes(final ShardingRule shardingRule, Final TableRule TableRule) {ShardingStrategy databaseShardingStrategy = createShardingStrategy(shardingRule.getDatabaseShardingStrategyConfiguration(tableRule), shardingRule.getShardingAlgorithms(), shardingRule.getDefaultShardingColumn()); // Table strategy ShardingStrategy tableShardingStrategy = createShardingStrategy(shardingRule.getTableShardingStrategyConfiguration(tableRule), shardingRule.getShardingAlgorithms(), shardingRule.getDefaultShardingColumn()); // Whether to enforce sharding: If (isRoutingByHint(shardingRule, tableRule)) {return routeByHint(tableRule, routeByHint) databaseShardingStrategy, tableShardingStrategy); } // Whether to use the standard route, Library and tables are not hint if (isRoutingByShardingConditions (shardingRule tableRule)) {return routeByShardingConditions (shardingRule, tableRule, databaseShardingStrategy, tableShardingStrategy); } return routeByMixedConditions(shardingRule, tableRule, databaseShardingStrategy, tableShardingStrategy); }Copy the code

3.2. Determine whether to directly route

private boolean isRoutingByHint(final ShardingRule shardingRule, Final TableRule TableRule) {/ / configure the hint strategy return shardingRule. GetDatabaseShardingStrategyConfiguration (TableRule) instanceof HintShardingStrategyConfiguration && shardingRule.getTableShardingStrategyConfiguration(tableRule) instanceof  HintShardingStrategyConfiguration; }Copy the code

3.3. Perform database sorting first, and then table sorting

private Collection<DataNode> route0(final TableRule tableRule, final ShardingStrategy databaseShardingStrategy, final List<ShardingConditionValue> databaseShardingValues, final ShardingStrategy tableShardingStrategy, Final List<ShardingConditionValue> tableShardingValues) {// Execute the routing policy of the database. Results the Collection < String > routedDataSources = routeDataSources (tableRule databaseShardingStrategy, databaseShardingValues); Collection<DataNode> result = new LinkedList<>(); for (String each : RoutedDataSources (routedDataSources) {// Execute the routing policy for the table, Result. addAll(routeTables(tableRule, each, tableShardingStrategy, tableShardingValues)); } return result; }Copy the code
private Collection<String> doSharding(final Collection<String> availableTargetNames, final ListShardingConditionValue<? > shardingValue) { Collection<String> result = new LinkedList<>(); for (Comparable<? > each : shardingValue.getValues()) { String target; // After executing the configured sharding algorithm, Fragmentation results target = shardingAlgorithm. DoSharding (availableTargetNames, new PreciseShardingValue(shardingValue.getTableName(), shardingValue.getColumnName(), each)); if (null ! = target && availableTargetNames.contains(target)) { result.add(target); } else if (null ! = target && ! availableTargetNames.contains(target)) { throw new ShardingSphereException(String.format("Route table %s does not exist,  available actual table: %s", target, availableTargetNames)); } } return result; }Copy the code

At this point, let’s break the point and check the sharding algorithm and the path information after sharding:

As you can see, the sharding path is as expected.

3.4. Encapsulation results are returned

4. Obtain the final route path

The flow chart

conclusion

In short, the routing engine generates routing paths by matching the sharding strategy of the corresponding database and table with the parsing context.