presto代码解析一

本文详细解析了Presto中的TaskExecutor,包括Runner的run方法流程,以及几种重要的操作符如ScanFilterAndProjectOperator(已单独介绍)、HashAggregationOperator、FilterAndProjectOperator、TaskOutputOperator、ExchangeOperator、OrderByOperator和TopNOperator的工作原理和关键方法。通过这些内容,深入理解Presto的任务执行和数据处理过程。

1.TaskExecutor

    一个TaskExecutor负责执行多个split的实际操作,首先会构造一个线程池,在线程池中预制多个线程。
    public synchronized void start()
    {
        checkState(!closed, "TaskExecutor is closed");
        for (int i = 0; i < runnerThreads; i++) {
            addRunnerThread();
        }
    }

Runner是实际的线程类,继承了runnable接口,其run方法实现了比较复杂的操作

1 重要类介绍

PrioritizedSplitRunner

1 run方法流程介绍

 首先从pendingSplits中获取到一个被挂起的还没有线程资源的split,把这个split加入到runningSplits中,然后调用该split的

split的数据,处理的流程是“并行遍历”这个driver的operators集合,这个operator集合中包含了处理这个split数据的所有操作符。
在构造完一个线程后,就会尝试去pendingSplits中获取split,这是一个priorityBlockingQuene,如果没有元素,就会阻塞。

2 操作符介绍

2 ScanFilterAndProjectOperator(已挪至专题文章进行介绍)

 这个操作符用于扫描原始数据,从操作符的名字可以看出,这个操作符其实可以完成三部分工作:扫描+过滤+投影

1 重要变量包括:

       1)) CursorProcessor cursorProcessor
        代码生成,用于快速扫描数据源
       2)) PageProcessor pageProcessor
        代码生成,用于快速处理一个page内的数据
       3)) boolean finishing
         用于标示是否扫面完split内的全部数据

2 重要方法包括:

       1)) Page getOutput()
public Page getOutput()
    {
        if (!finishing) {
            createSourceIfNecessary(); //根据不同的connector创建数据源

            if (cursor != null) {
                int rowsProcessed = cursorProcessor.process(operatorContext.getSession().toConnectorSession(), cursor, ROWS_PER_PAGE, pageBuilder);//使用代码生成扫描数据源,迭代读取过程

                pageSourceMemoryContext.setBytes(cursor.getSystemMemoryUsage());

                long bytesProcessed = cursor.getCompletedBytes() - completedBytes;
                long elapsedNanos = cursor.getReadTimeNanos() - readTimeNanos;
                operatorContext.recordGeneratedInput(bytesProcessed, rowsProcessed, elapsedNanos);
                completedBytes = cursor.getCompletedBytes();
                readTimeNanos = cursor.getReadTimeNanos();

                if (rowsProcessed == 0) {
                    finishing = true;
                }
            }
            else {
                if (currentPage == null) {
                    currentPage = pageSource.getNextPage();

                    if (currentPage != null) {
                        // update operator stats
                        long endCompletedBytes = pageSource.getCompletedBytes();
                        long endReadTimeNanos = pageSource.getReadTimeNanos();
                        operatorContext.recordGeneratedInput(endCompletedBytes - completedBytes, currentPage.getPositionCount(), endReadTimeNanos - readTimeNanos);
                        completedBytes = endCompletedBytes;
                        readTimeNanos = endReadTimeNanos;
                    }

                    currentPosition = 
以下是个简单的Presto字段级别血缘解析Java实现代码示例: ```java import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class PrestoFieldLineageAnalyzer { private QueryPlan queryPlan; private Map<String, List<String>> fieldLineage = new HashMap<>(); public PrestoFieldLineageAnalyzer(String query) { // 解析查询语句 this.queryPlan = QueryParser.parse(query); } public Map<String, List<String>> analyze() { // 构建查询树 QueryNode rootNode = buildQueryTree(queryPlan); // 计算字段血缘 calculateFieldLineage(rootNode); // 输出结果 return fieldLineage; } private QueryNode buildQueryTree(QueryPlan queryPlan) { // 构建查询树的代码 // ... } private void calculateFieldLineage(QueryNode node) { // 如果是叶子节点,则将输出字段加入血缘关系列表 if (node.isLeaf()) { for (String field : node.getOutputFields()) { if (!fieldLineage.containsKey(field)) { fieldLineage.put(field, new ArrayList<>()); } } return; } // 递归计算输入字段与输出字段之间的血缘关系 for (QueryNode child : node.getChildren()) { calculateFieldLineage(child); for (String outputField : child.getOutputFields()) { for (String inputField : child.getInputFields(outputField)) { if (!fieldLineage.containsKey(outputField)) { fieldLineage.put(outputField, new ArrayList<>()); } List<String> inputFields = fieldLineage.get(outputField); if (!inputFields.contains(inputField)) { inputFields.add(inputField); } } } } } } ``` 这段代码中,我们首先使用QueryParser将查询语句解析为查询计划,然后构建查询树,最后计算字段血缘关系。计算字段血缘的逻辑在calculateFieldLineage方法中实现,它会递归遍历查询树,从叶子节点开始计算每个字段的血缘关系。最后,将计算得到的字段血缘关系保存在个Map中,并返回给用户。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值