准备
Presto有两大分支一个prestodb,另一个是prestosql。二者的区别找到了一篇文章,可以了解一下。
我选择的是prestodb,git clone https://github.com/prestodb/presto.git
我写博客时,最近的commit
cba87b4f111983b5483ab2ecf580573ac0afa595
,这次提交完善了Materialized Views,详细可见 https://github.com/prestosql/presto/commit/88116a4a3fda92f0caa725d9b1a83e9b22f7dcf4
直接对master代码进行分析了,找到presto-cli模块下的com.facebook.presto.cli.Presto
idea中双击shift快速搜索到
分析
打开后代码很少,主要是对console的操作:创建、判断是否需要展示帮助或者展示版本信息、然后到真正的run,正常返回为0否则为1。
package com.facebook.presto.cli;
import static io.airlift.airline.SingleCommand.singleCommand;
public final class Presto
{
private Presto() {}
public static void main(String[] args)
{
Console console = singleCommand(Console.class).parse(args);
if (console.helpOption.showHelpIfRequested() ||
console.versionOption.showVersionIfRequested()) {
return;
}
System.exit(console.run() ? 0 : 1);
}
}
console.run()方法也不难理解
- 先是做一些判断:是execute参数提交的?还是file提交的?并做相应的处理。
- 如果客户端终止了,查询也随之终止。
// abort any running query if the CLI is terminated
AtomicBoolean exiting = new AtomicBoolean();
ThreadInterruptor interruptor = new ThreadInterruptor();
CountDownLatch exited = new CountDownLatch(1);
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
exiting.set(true);
interruptor.interrupt();
awaitUninterruptibly(exited, EXIT_DELAY.toMillis(), MILLISECONDS);
}));
- 将query传入并执行命令。
进入executeCommand,发现它将query拆分成一条一条的交给process(查看StatementSplitter发现是按逗号拆分)
private static boolean executeCommand(QueryRunner queryRunner, String query, OutputFormat outputFormat, boolean ignoreErrors)
{
boolean success = true;
StatementSplitter splitter = new StatementSplitter(query);
for (Statement split : splitter.getCompleteStatements()) {
if (!isEmptyStatement(split.statement())) {
if (!process(queryRunner, split.statement(), outputFormat, () -> {}, false)) {
if (!ignoreErrors) {
return false;
}
success = false;
}
}
}
if (!isEmptyStatement(splitter.getPartialStatement())) {
System.err.println("Non-terminated statement: " + splitter.getPartialStatement());
return false;
}
return success;
}
process调用queryRunner.startQuery(finalSql)
实际上是startQuery层次调用startInternalQuery
最终得到StatementClientV1
public final class StatementClientFactory
{
private StatementClientFactory() {}
public static StatementClient newStatementClient(OkHttpClient httpClient, ClientSession session, String query)
{
return new StatementClientV1(httpClient, session, query);
}
}
在StatementClientV1的构造方法中构造查询请求
接着进入可以看到url的路径
不难定位到com/facebook/presto/server/protocol/QueuedStatementResource.java:161
在这里对请求做出了响应,完成整个提交的请求。