Presto 从提交SQL到获取结果 源码详解(1)

流程:

1.        Presto Client  提交SQL 

          入口:com.facebook.presto.cli.Console.run()

    // Session 初始化
    ClientSession session = clientOptions.toClientSession();


    // 判断是否存在SQL,即判断当前为 命令模式还是会话模式。会话模式需实时获取命令再二次提交给服务端。
    if (hasQuery) {}


    // 文件模式检测
    if (isFromFile) {}
    

    //生存QueryRunner对象,包装请求参数及配置
    QueryRunner queryRunner = new QueryRunner()


    //SQL切分,经过queryRunner.startQuery提交给服务端 /v1/statement接口。获得Response
    if (hasQuery) {
       return executeCommand(queryRunner, query, clientOptions.outputFormat, clientOptions.ignoreErrors);
    }
    queryRunner.startQuery.xxxx


    //Response 返回请求被接收及部分taskID等参数,随后进入advance 循环获取Nexturl
    boolean success = query.renderOutput(System.out, outputFormat, interactive);
    renderQueryOutput(out, outputFormat, interactive);
    private void processInitialStatusUpdates(WarningsPrinter warningsPrinter)
    client.advance();
    URI nextUri = currentStatusInfo().getNextUri();


    //后续逻辑为:频繁请求Nexturl。 若JSON<QueryResults>不包含nextUri,说明查询已结束(成功|失败)随后获取执行结果;若包含nextUri,则还需要继续访问nextUri以获取下一批的查询结果
    
    



    


        

2.  请求提交至服务端,服务端对象初始化及statement校验

        

    //Server端构建 交互状态接口   
    com.facebook.presto.server.protocol




    //  创建Query对象,初始化taskID 等,返回nexturl
    @Path("/v1/statement")
    public class StatementResource{
    Query query = Query.create()
    
    }




    //指定Task nextURL请求路径
    @Path("{queryId}/{token}")
    public void getQueryResults(
    asyncQueryResults(query, OptionalLong.of(token), maxWait, targetResultSize, uriInfo, proto, asyncResponse);
    )

    ListenableFuture<QueryResults> queryResultsFuture = query.waitForResults(token, uriInfo, scheme, wait, targetResultSize);
	getFutureStateChange()



    //检测SQL状态,新请求|已提交|运行中。若是新请求则调用SqlQueryManager.createQuery	
	// ensure the query has been submitted
	submissionFuture.submitQuery();
    querySubmissionFuture = queryManager.createQuery(queryId, sessionContext, this.query);
	
    // if query query submission has not finished, wait for it to finish
    if (!submissionFuture.isDone()) {
       return submissionFuture;
    }
    


    // decode session
    // prepare query   
/*
此时:Antlr解析语法,生成基础Statement,获得结构化解析结果
*/
    preparedQuery = queryPreparer.prepareQuery(session, query, warningCollector);
    



    // select resource group
    // apply system defaults for query
    // create query execution
    queryExecution = queryExecutionFactory.createQueryExecution()
    
/*
此时:创建QueryExecution后,会生成Analyzer对象,进行SQL权限校验及语法语义校验
例如:权限检查
		– 库表 增删改查权限
     语法检查
        - Where 后条件判断
        - Group 1,2,3 字段判断
        - Order By 是否可行 等常规语法语义判断
*/
    StatementAnalyzer  analyzer = new Analyzer()



 
// 识别并处理 EXPLAIN xxx ,DESCRIBE xxx,SHOW xxx 等特殊情况
Statement rewrittenStatement = StatementRewrite.rewrite


// vistor分析语义
Analysis analysis = new Analysis(rewrittenStatement, parameters, isDescribe);
StatementAnalyzer analyzer = new StatementAnalyzer(analysis, metadata, sqlParser, accessControl, session, warningCollector);
analyzer.analyze(rewrittenStatement, Optional.empty());


// check column access permissions for each table 遍历库表字段,检测字段权限
analysis.getTableColumnReferences().forEach.xxxxx
accessControlInfo.getAccessControl().checkCanSelectFromColumns
AccessControlManager.checkCanSelectFromColumns

//检测catalog
authenticationCheck(() -> checkCanAccessCatalog(identity, tableName.getCatalogName()));
FileBasedSystemAccessControl.checkCanAccessCatalog

//检测查询字段
authorizationCheck(() -> systemAccessControl.get().checkCanSelectFromColumns(identity, tableName.asCatalogSchemaTableName(), columnNames));
ForwardingSystemAccessControl.checkCanSelectFromColumns






    







3. Presto execution.resourceGroups 资源组调用

   // resourceGroupManager 资源组提交任务
   resourceGroupManager.submit(preparedQuery.getStatement(), queryExecution, selectionContext, queryExecutor);


/* 关于资源组:
   当PrestoServer通过main方法run初始化时
			1.首先执行PluginManager的loadPlugins,向InternalResourceGroupManager中一个存放ResourceGroupManagerFactory类型元素的Map 添加可用的资源组管理工厂类。
			2.调用 InternalResourceGroupManager 的 loadConfigurationManager 方法,读取etc/resource-groups.properties文件中的配置项resource-groups.configuration-manager
			3.读取configurationMF中对应的ResourceGroupCMFactory,调用create方法构建ResourceGroupCM对象,赋值给InternalResourceGroupManager类的configurationManager

   此处,即触发资源组调用

*/


    //Group调用
    package com.facebook.presto.execution.resourceGroups;
    submit();
    createGroupIfNecessary(selectionContext, executor);
    groups.get(selectionContext.getResourceGroupId()).run(queryExecution);
    public void run(ManagedQueryExecution query)
        executor.execute(query::start);
    private void waitForMinimumWorkers()
	private void startExecution()

    //当前Group是否可运行
    canRun &= group.canRunMore();

    //runningQueries上锁,开始执行
    executor.execute(query::start);
    addSuccessCallback(minimumWorkerFuture, () -> queryExecutor.submit(this::startExecution));


    

4.构建执行计划


private void startExecution()
SetThreadName ignored = new SetThreadName("Query-%s", stateMachine.getQueryId())


// analyze query  生成逻辑执行计划
PlanRoot plan = analyzeQuery();


// plan distribution of query  生成物理执行计划
planDistribution(plan);


// if query is not finished, start the scheduler, otherwise cancel it   任务调度
SqlQueryScheduler scheduler = queryScheduler.get();

if (!stateMachine.isDone()) {
   scheduler.start();
}

下文详细介绍各个执行计划构建过程

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值