Console提交查询过程
Console::executeCommand()直接提交sql
Console::process(),包装Query,启动查询
QueryRunner::startQuery,启动查询
构造Query
Query query = queryRunner.startQuery(finalSql),来构建StatementClient
StatementClient负责构造查询和获取结果与coordinator通信
构造请求
Request request = buildQueryRequest(session, query);
执行restful(/v1/statement)
JsonResponse<QueryResults> response = JsonResponse.execute(QUERY_RESULTS_CODEC, httpClient, request);
处理结果
processResponse(response.getHeaders(), response.getValue());
Query::分批拉数据
query.renderOutput(System.out, outputFormat, interactive)
第一种方式,动态刷屏分批拉数据
statusPrinter.printInitialStatusUpdates();
第二种方式,非动态拉取最终结果
waitForData();
共同点:
都是调获取结果,前面说了StatementClient负责构造查询和获取结果与coordinator通信
(/v1/statement/{queryId}/{token})
StatementClient::advance()
主要先获取分批nextUri,构造查询
以SQL查询为例看SQL执行(感谢引文博主,原文点击该链接)
下面的执行图引用自(presto 0.166概述),感谢
=====================================================================================================================================================
presto-cli:
Presto.main():
Console.run():
Console.executeCommand():
Console.process():
QueryRunner.startQuery():
QueryRunner.startInternalQuery():
StatementClient.StatementClient():
StatementClient.buildQueryRequest(): 构建 http 请求参数
JsonResponse.execute(): 这里开始发送请求到 StatmentResource,并且会把 response 返回值转为 json,方便后续渲染
StatementClient.processResponse(): 这里会直接尝试处理 query 响应,看看有没有返回
Query.renderOutput(): 开始打印结果到控制台
Query.renderQueryOutput(): 这里会根据是否是"交互"模式,来决定如何渲染输出结果. 这里只考虑以"交互"模式渲染结果.
StatusPrinter.printInitialStatusUpdates():
StatementClient.advance(): 这里会循环去发送 http 请求去 Coordinator 获取返回值
JsonResponse.execute(): 同上
=====================================================================================================================================================
presto-main: [Coordinator,Worker] 都是用这份代码
StatementResource.createQuery(): 接收 cli 请求
Query.create():
Query.Query():
SqlQueryManager.createQuery():
QueryQueueManager.submit():
SqlQueryExecution.start(): Async
SqlQueryExecution.analyzeQuery(): 分析查询语句,生成查询计划
SqlQueryExecution.planDistribution(): 分发查询计划到激活的节点
SqlQueryScheduler.SqlQueryScheduler():
SqlQueryScheduler.createStages(): 关键代码,创建 stage 树,并指定 StageScheduler. StageScheduler 有 4 个实现类,后续异步调用的时候,会使用 Jdk 的 BiFunction 方式来调用.
SqlQueryScheduler.start(): 如果状态机显示查询未完成,则执行
SqlQueryScheduler.schedule(): Async, 循环执行,直到 execution 完成.
stageSchedulers.get(stage.getStageId()).schedule(): 使用上述 StageScheduler 的实现类来分发 Task 到工作节点.
SqlStageExecution.scheduleTask(): 根据不同的 StageScheduler 实现,进入该方法的入口可能不一样,入口可能是[scheduleTask,scheduleSplits]
HttpRemoteTaskFactory.createRemoteTask(): 创建 http remote task
HttpRemoteTask.start(): 如果状态机显示查询未完成,则执行
HttpRemoteTask.scheduleUpdate():
HttpRemoteTask.sendUpdate(): Async,
HttpClient.executeAsync(): 发送请求到 TaskResource.createOrUpdateTask()
TaskResource.createOrUpdateTask(): 接收 Task 的 rest 接口
SqlTaskManager.updateTask():
SqlTask.updateTask():
SqlTaskExecutionFactory.create():
SqlTaskExecution.createSqlTaskExecution():
SqlTaskExecution.SqlTaskExecution(): [driverRunnerFactoriesWithSplitLifeCycle,driverRunnerFactoriesWithDriverGroupLifeCycle,driverRunnerFactoriesWithTaskLifeCycle] 比较重要
TaskExecutor.addTask():
List<TaskHandle>.add(): 填加 taskHandle 之后,不考虑返回值,sql 执行在 presto 能就告一段落了,会异步到 TaskExecutor 执行.
TaskExecutor.start(): 该方法含有 @PostConstruct ,所以在 presto 启动时就会执行
TaskExecutor.addRunnerThread():
ExecutorService.execute():
TaskRunner.run(): Asyc
PrioritizedSplitRunner.take(): 该方法会阻塞,直到有值返回
PrioritizedSplitRunner.process():
DriverSplitRunner.processFor():
Driver.processFor():
Driver.processInternal():
Driver.processNewSources(): 更新 TaskResource
Opertator.getOutput(): 会根据不同的 sql 操作,得到不同的 Operator 实现类.然后根据实现,调用对应的 connector . 该方法返回的是一个 Page, Page 相当于一张 RDBMS 的表,只不过 Page 是列存储的. 获取 page 的时候,会根据 [Block 类型,文件格式]等,使用相应的 Loader 来 load 取数据.
Operator.addInput(): 下一个 Operator 如果需要上一个 Operator 的输出,则会调用该方法
StatementResource.asyncQueryResults(): 异步返回查询结果给 cli
Query.waitForResults():
Futures.transform(): 提供一个 function 和 executor 给 guava
BoundedExecutor.execute(): 这个方法会由 guava 异步回调
coreExecutor.execute(this::drainQueue): 这里会使用 JDK 的 Executor 来调度异步任务
BoundedExecutor.drainQueue():
queue.poll().run(): 这里执行的时候,意味着会执行 Futures.transform() 的 function 参数
Query.getNextResult():
Query.getCachedResult(): 首先会尝试从缓存里去获取返回值
ExchangeClient.pollPage(): 从 ExchangeClient 中获取结果页
QueryResults.QueryResults(): 根据结果页生成 QueryResults 返回给 cli
=====================================================================================================================================================