greenplum中的Instrumentation统计数据

版本号

PostgreSQL 8.3.23 (Greenplum Database 5.0.0 build dev)


设置gp_enable_query_metrics

gpconfig -c gp_enable_query_metrics -v on    //设置
gpstop -r    //重启

hook

query_info_collect_hook可用于获取queryDesc相关信息

相关代码

以"SELECT * from instrument_test where id>1000 order by id limit 1000;"为例

PortalStart

void
PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot,
            const char *seqServerHost, int seqServerPort, QueryDispatchDesc *ddesc)
{
    PG_TRY();
    {
        switch (portal->strategy)
        {
            case PORTAL_ONE_SELECT:
                /* 
                 * #define GP_INSTRUMENT_OPTS (gp_enable_query_metrics ? INSTRUMENT_ROWS : INSTRUMENT_NONE)
                 * 因为开启了 gp_enable_query_metrics, queryDesc->instrument_options被设置
                 * 此处可以在gdb上设置 set var queryDesc->instrument_options=INSTRUMENT_ALL(0x7FFFFFFF),
                 * 以查看greenplum的处理
                 */
                queryDesc = CreateQueryDesc((PlannedStmt *) linitial(portal->stmts),
                                            portal->sourceText,
                                            (gp_select_invisible ? SnapshotAny : ActiveSnapshot),
                                            InvalidSnapshot,
                                            None_Receiver,
                                            params,
                                            GP_INSTRUMENT_OPTS);
                    
                // 这是运行时可以修改queryDesc->instrument_options的hook                        
                if (query_info_collect_hook)
                    (*query_info_collect_hook)(METRICS_QUERY_SUBMIT, queryDesc);
                    
                ExecutorStart(queryDesc, eflags);
                
                portal->queryDesc = queryDesc;
        }
    }
}

ExecutorStart

void
ExecutorStart(QueryDesc *queryDesc, int eflags)
{
    EState       *estate;
    
    // 同样是运行时可以修改queryDesc->instrument_options的hook
    if (query_info_collect_hook)
        (*query_info_collect_hook)(METRICS_QUERY_START, queryDesc);
    
    // 把queryDesc->instrument_options赋值给estate->es_instrument
    estate->es_instrument = queryDesc->instrument_options;
    
    PG_TRY();
    {
        InitPlan(queryDesc, eflags);
    }
}

InitPlan

static void
InitPlan(QueryDesc *queryDesc, int eflags)
{
    PlanState  *planstate;
    
    planstate = ExecInitNode(start_plan_node, estate, eflags);
    queryDesc->planstate = planstate;

    if (query_info_collect_hook)
        (*query_info_collect_hook)(METRICS_PLAN_NODE_INITIALIZE, queryDesc);
}

ExecInitNode

PlanState *
ExecInitNode(Plan *node, EState *estate, int eflags)
{
    PlanState  *result;

    // 如果前面设置了queryDesc->instrument_options,这里会为queryDesc->planstate->instrument分配内存
    if (estate->es_instrument && result != NULL)
        result->instrument = GpInstrAlloc(node, estate->es_instrument);
        
    return result;
}

GpInstrAlloc

Instrumentation *
GpInstrAlloc(const Plan *node, int instrument_options)
{
    Instrumentation *instr = NULL;

    if (shouldPickInstrInShmem(nodeTag(node)))
        instr = pickInstrFromShmem(node, instrument_options);

    return instr;
}

pickInstrFromShmem

static Instrumentation *
pickInstrFromShmem(const Plan *plan, int instrument_options)
{
    Instrumentation *instr = NULL;

    // 此处省略instr的处理步骤
    
    /* 
     * 如果前面设置了set var queryDesc->instrument_options=INSTRUMENT_ALL(0x7FFFFFFF),
     * 则这里会设置need_timer=true;
     * need_cdb用于EXPLAIN ANALYZE
     */
    if (NULL != instr && instrument_options & (INSTRUMENT_TIMER | INSTRUMENT_CDB))
    {
        instr->need_timer = (instrument_options & INSTRUMENT_TIMER) != 0;
        instr->need_cdb = (instrument_options & INSTRUMENT_CDB) != 0;
    }

    return instr;
}

PortalRun

bool
PortalRun(Portal portal, int64 count, bool isTopLevel,
          DestReceiver *dest, DestReceiver *altdest,
          char *completionTag)
{
    PG_TRY();
    {
        switch (portal->strategy)
        {
            case PORTAL_ONE_SELECT:
                (void) PortalRunSelect(portal, true, count, dest);
        }
    }
}

PortalRunSelect

static int64
PortalRunSelect(Portal portal,
                bool forward,
                int64 count,
                DestReceiver *dest)
{
    uint64        nprocessed;
    
    if (forward)
    {
        if (portal->holdStore)
        else
        {
            ExecutorRun(queryDesc, direction, count);
        }
    }
}

ExecutorRun

TupleTableSlot *
ExecutorRun(QueryDesc *queryDesc,
            ScanDirection direction, long count)
{
    TupleTableSlot *result = NULL;
    
    PG_TRY();
    {
        else if (exec_identity == GP_ROOT_SLICE)
        {
            result = ExecutePlan(estate,
                                 queryDesc->planstate,
                                 operation,
                                 count,
                                 direction,
                                 dest);
        }
    }
}

ExecutePlan

static TupleTableSlot *
ExecutePlan(EState *estate,
            PlanState *planstate,
            CmdType operation,
            long numberTuples,
            ScanDirection direction,
            DestReceiver *dest)
{
    for (;;)
    {
        if (estate->es_useEvalPlan)
        {
        }
        else
            planSlot = ExecProcNode(planstate);
    }
}

ExecProcNode

TupleTableSlot *
ExecProcNode(PlanState *node)
{
    /* 
     * 如果前面用gdb设置了queryDesc->instrument_options=0x7FFFFFFF,
     * 此处在获取一行tuple之前设置instrument->starttime 
     */
    if (node->instrument)
        INSTR_START_NODE(node->instrument);

greenplum中的Instrumentation统计数据

    /* 
     * 此处会将获取每行tuple的时间累加到node->instrument->counter
     */
    if (node->instrument)
        INSTR_STOP_NODE(node->instrument, TupIsNull(result) ? 0 : 1);

greenplum中的Instrumentation统计数据

}

PortalDrop

void
PortalDrop(Portal portal, bool isTopCommit)
{
    if (portal->cleanup)
        (*portal->cleanup) (portal); // 通过回调进入PortalCleanup
}

PortalCleanup

void
PortalCleanup(Portal portal)
{ 
    queryDesc = PortalGetQueryDesc(portal);
    if (queryDesc)
    { // queryDesc被释放
        portal->queryDesc = NULL;
        PG_TRY();
        {
            ExecutorEnd(queryDesc);
        }
    }
}

ExecutorEnd

void
ExecutorEnd(QueryDesc *queryDesc)
{
    // 通过hook这个可以获得相关的统计数据
    if (query_info_collect_hook)
        (*query_info_collect_hook)(METRICS_QUERY_DONE, queryDesc);
}
上一篇:带protobuf的通用型makefile


下一篇:How to partition a disk, set its file system type & mount it