executor 分析
无论是分库分表、还是读写分离,一个SQL在DB上执行前都需要经过特定规则运算获得运行的目标库表信息。路由引擎的职责定位就是计算SQL应该在哪个数据库、哪个表上执行。 前者结果会传给后续执行引擎,然后根据其数据库标识获取对应的数据库连接;后者结果则会传给改写引擎在SQL执行前进行表名的改写,即替换为正确的物理表名 。
首先可以看一下shardingsphere.infra.executor.sql这个包下的一些架构
shardingsphere.infra.executor.sql
├── executor.sql.context
├── executor.sql.excute
├── executor.sql.hook
├── executor.sql.log
├── executor.sql.prepare
│ ├── dirver
│ │ ├── jdbc
│ │ ├── DriverExecutionPrepareEngine
│ │ ├── ExecutorDriverManager
│ │ ├── SQLExecutionUnitBuilder
│ │ ├── StorageResourceOption
│ ├── raw
│ ├── AbstractExecutionPrepareEngine
│ └── ExecutionPrepareEngine
│ └── ExecutionPrepareDecorator
....
这个包下面的具体类太多,我们这里还是具体分析一个链路:昨天聊到的ShardingSpherePreparedStatement是整个ShardingSphere的基础类,在ShardingSphere启动时候,会调用ShardingSpherePreparedStatement的 初始化方法。把DataSource里面初始化好的上下文比如MetaDataContexts载入到ShardingSpherePreparedStatement 里面的各种配置参数和上下文中。调用execute方法时,会首先
executionContext = createExecutionContext();
if (metaDataContexts.getDefaultMetaData().getRuleMetaData().getRules().stream().anyMatch(each -> each instanceof RawExecutionRule)) {
// TODO process getStatement
Collection<ExecuteResult> executeResults = rawExecutor.execute(createRawExecutionGroups(), new RawSQLExecutorCallback());
return executeResults.iterator().next() instanceof QueryResult;
}
在createExecutionContext创建的过程中 首先调用SQLCheckEngine.check检查sql
private ExecutionContext createExecutionContext() {
LogicSQL logicSQL = createLogicSQL();
SQLCheckEngine.check(logicSQL.getSqlStatementContext().getSqlStatement(), logicSQL.getParameters(), metaDataContexts.getDefaultMetaData(), metaDataContexts.getAuthentication());
ExecutionContext result = kernelProcessor.generateExecutionContext(logicSQL, metaDataContexts.getDefaultMetaData(), metaDataContexts.getProps());
findGeneratedKey(result).ifPresent(generatedKey -> generatedValues.addAll(generatedKey.getGeneratedValues()));
return result;
}
SQLChecker是 org.apache.shardingsphere.infra.audit 包中基本工具
/**
* SQL checker.
*
*/
public interface SQLChecker extends OrderedSPI {
SQLCheckType getSQLCheckType();
SQLCheckResult check(SQLStatement sqlStatement, List<Object> parameters, ShardingSphereMetaData metaData, Authentication auth);
}
检查sql格式以后调用了generateExecutionContext方法创建了ExecutionContext
public ExecutionContext generateExecutionContext(final LogicSQL logicSQL, final ShardingSphereMetaData metaData, final ConfigurationProperties props) {
RouteContext routeContext = route(logicSQL, metaData, props);
SQLRewriteResult rewriteResult = rewrite(logicSQL, metaData, props, routeContext);
ExecutionContext result = createExecutionContext(logicSQL, metaData, routeContext, rewriteResult);
logSQL(logicSQL, props, result);
return result;
}
在创建ExecutionContext中第一步是调用route路由
private RouteContext route路由(final LogicSQL logicSQL, final ShardingSphereMetaData metaData, final ConfigurationProperties props) {
return new SQLRouteEngine(metaData.getRuleMetaData().getRules(), props).route(logicSQL, metaData);
}
SQLRouteEngine 路由引擎
public final class SQLRouteEngine {
private final Collection<ShardingSphereRule> rules;
private final ConfigurationProperties props;
private final SPIRoutingHook routingHook = new SPIRoutingHook();
public RouteContext route(final LogicSQL logicSQL, final ShardingSphereMetaData metaData) {
routingHook.start(logicSQL.getSql());
try {
SQLRouteExecutor executor = isNeedAllSchemas(logicSQL.getSqlStatementContext().getSqlStatement()) ? new AllSQLRouteExecutor() : new PartialSQLRouteExecutor(rules, props);
RouteContext result = executor.route(logicSQL, metaData);
routingHook.finishSuccess(result, metaData.getSchema());
return result;
// CHECKSTYLE:OFF
} catch (final Exception ex) {
// CHECKSTYLE:ON
routingHook.finishFailure(ex);
throw ex;
}
}
// TODO use dynamic config to judge UnconfiguredSchema
private boolean isNeedAllSchemas(final SQLStatement sqlStatement) {
return sqlStatement instanceof MySQLShowTablesStatement;
}
}
路由引擎第一步调用了
public final class SPIRoutingHook implements RoutingHook {
RoutingHook注册在ShardingSphereServiceLoader
ShardingSphereServiceLoader.register(RoutingHook.class)
*/
public final class AllSQLRouteExecutor implements SQLRouteExecutor {
@Override
public RouteContext route(final LogicSQL logicSQL, final ShardingSphereMetaData metaData) {
RouteContext result = new RouteContext();
for (String each : metaData.getResource().getDataSources().keySet()) {
result.getRouteUnits().add(new RouteUnit(new RouteMapper(each, each), Collections.emptyList()));
}
return result;
}
}
AllSQLRouteExecutor 实现了SQLRouteExecutor
中调用
result.getRouteUnits().add(new RouteUnit(new RouteMapper(each, each), Collections.emptyList()));
RouteUnit的实现
public final class RouteUnit {
private final RouteMapper dataSourceMapper;
private final Collection<RouteMapper> tableMappers;
/**
* Get logic table names.
*
* @return logic table names
*/
public Set<String> getLogicTableNames() {
return tableMappers.stream().map(RouteMapper::getLogicName).collect(Collectors.toCollection(() -> new HashSet<>(tableMappers.size(), 1)));
}
/**
* Get actual table names.
*
* @param logicTableName logic table name
* @return actual table names
*/
public Set<String> getActualTableNames(final String logicTableName) {
return tableMappers.stream().filter(each -> logicTableName.equalsIgnoreCase(each.getLogicName())).map(RouteMapper::getActualName).collect(Collectors.toSet());
}
/**
* Find table mapper.
*
* @param logicDataSourceName logic data source name
* @param actualTableName actual table name
* @return table mapper
*/
public Optional<RouteMapper> findTableMapper(final String logicDataSourceName, final String actualTableName) {
for (RouteMapper each : tableMappers) {
if (logicDataSourceName.equalsIgnoreCase(dataSourceMapper.getLogicName()) && actualTableName.equalsIgnoreCase(each.getActualName())) {
return Optional.of(each);
}
}
return Optional.empty();
}
}
RouteMapper的实现
public final class RouteMapper {
private final String logicName;
private final String actualName;
}