• postgresql源码学习(50)—— 小白学习Dtrace追踪源码函数调用


           不知不觉第50篇了,昨天在文章里(https://mp.weixin.qq.com/s/AzBGzYhGxYjSf7Sptj55lQ)学到一个追踪源码执行情况的利器 —— Dtrace,本篇记录下实验和笔记。

    一、 解决痛点

          学习以来一直有一个疑惑,如何将pg中执行的SQL语句和源码对应起来?回顾下之前学到的gdb调试方法,看看适用场景,以及不足。

    常用调试方法

    • 已知函数名:gdb调试。包括很常用的一些语句例如checkpoint,对应函数名网上都能搜到
    • 慢查询卡在某个特定函数:可以gdb跟踪进程然后查看调用栈
    • 有报错信息:根据报错文本在源码中搜索

           但是,如果是业务任意执行的一条语句、出现了某些怪异的现象(例如原文是加长字段长度后其统计信息被删除),如何能知道它究竟调用了pg中的哪些函数?而哪些函数是不符合我们预期的?Dtrace就能解决这个问题。

    二、 准备工作

           DTrace叫动态追踪(Dynamic Tracing),本身是源于Solaris系统的,无法在Linux中运行 。因为非常好用,有了Linux移植版,名SystemTap。SystemTap 也定义了一种类似的脚本语言,方便用户根据需要自由扩展。更多简介可以参考:https://blog.csdn.net/Hehuyi_In/article/details/108910781

    1. 安装SystemTap

    我Oracle Linux 7的虚拟机自带了这个工具,如果没有,可以安装以下包

    yum -y install systemtap systemtap-runtime

    执行hello world测试命令

    stap -e 'probe begin{printf("Hello, World"); exit();}'

    上面那些提示对测试没什么影响,可以不管它。

           如果不能输出Hello, World,则需要根据提示装一些kernel相关的包,注意必须跟操作系统的版本是一致的,不能直接yum安装最新版。

    2. 使用--enable-dtrace选项编译安装pg

    postgresql源码学习(一)—— 源码编译安装与gdb调试入门_Hehuyi_In的博客-CSDN博客_postgresql 源码调试

    三、 开始测试

    准备完终于可以开始测了,就以原文的例子,看看加长字段长度会调用什么函数。

    1. Systemtap脚本准备

    vi function.c

          脚本内容,process中的路径自行替换,function中的*代表输出所有函数(因为不知道具体有哪些,可以利用通配符缩小范围,例如*Start*)

    probe process("/data/postgres/base/14.0/bin/postgres").function("*") {
            printf("%s: %s\n", execname(), ppfunc());
    }

    2. 创建测试表

    1. create table t(id int,info varchar(10));
    2. insert into t select n,left(md5(random()::text),10) from generate_series(1,1000) as n;
    3. analyze t;

    3. 执行Systemtap脚本

           注意这个工具启动需要一定时间,所以不要一执行完脚本立刻执行对应SQL,会抓漏或者抓不到数据,可以等下面的提示出来了再开始执行。

    stap function.c > mylog.txt

           红色的提示可以忽略,实际已经装了这个包,并不影响使用,WARNING的信息虽然多,但也不影响使用。

    4. 执行加长字段语句

    alter table t alter COLUMN info type varchar(20);

    这里发现需要另开一个会话才能抓到,直接在原先会话执行一直是些空闲等待的函数

    5. 观察输出结果

    再开一个窗口,mylog.txt中有输出后退出脚本,否则会记录很多无用信息。

    按原文搜一下statistic相关函数,发现有了

    cat mylog.txt | sort | uniq | grep -i statistic

    再看看日志中的内容

    四、 源码学习

    定位到函数后,就回到了熟悉的内容,gdb也好vscode也好,可以根据函数名调试和搜索它了。

           RemoveStatistics函数用于为单表或单列删除pg_statistic系统表中对应的记录。如果attnum为零(未指定列),删除该表的所有记录;如果指定了列,则删除该列的记录。

    1. /*
    2. * RemoveStatistics --- remove entries in pg_statistic for a rel or column
    3. *
    4. * If attnum is zero, remove all entries for rel; else remove only the one(s)
    5. * for that column.
    6. */
    7. void
    8. RemoveStatistics(Oid relid, AttrNumber attnum)
    9. {
    10. Relation pgstatistic;
    11. SysScanDesc scan;
    12. ScanKeyData key[2];
    13. int nkeys;
    14. HeapTuple tuple;
    15. pgstatistic = table_open(StatisticRelationId, RowExclusiveLock);
    16. ScanKeyInit(&key[0],
    17. Anum_pg_statistic_starelid,
    18. BTEqualStrategyNumber, F_OIDEQ,
    19. ObjectIdGetDatum(relid));
    20. if (attnum == 0)
    21. nkeys = 1;
    22. else
    23. {
    24. ScanKeyInit(&key[1],
    25. Anum_pg_statistic_staattnum,
    26. BTEqualStrategyNumber, F_INT2EQ,
    27. Int16GetDatum(attnum));
    28. nkeys = 2;
    29. }
    30. scan = systable_beginscan(pgstatistic, StatisticRelidAttnumInhIndexId, true,
    31. NULL, nkeys, key);
    32. /* we must loop even when attnum != 0, in case of inherited stats */
    33. while (HeapTupleIsValid(tuple = systable_getnext(scan)))
    34. CatalogTupleDelete(pgstatistic, &tuple->t_self);
    35. systable_endscan(scan);
    36. table_close(pgstatistic, RowExclusiveLock);
    37. }

    另外看了下会调用该函数的文件

    点开看了看,大概有以下函数(操作)会删除统计信息:

    • heap_drop_with_catalog - removes specified relation from catalogs,删表
    • RemoveAttributeById - This is the guts of ALTER TABLE DROP COLUMN,删列
    • index_drop - 删索引
    • ATExecAlterColumnType - ALTER COLUMN .. SET DATA TYPE,改字段类型,注释为
    1. /*
    2. * Drop any pg_statistic entry for the column, since it's now wrong type
    3. */
    4. RemoveStatistics(RelationGetRelid(rel), attnum);

     这方法感觉有点傻,应该有更方便能看到函数调用信息的工具?不过暂时没搜到,留待以后吧~

    参考

    PostgreSQL修改列类型又掉坑了!

    使用动态追踪Dtrace分析问题

    https://gist.github.com/alexandrnikitin/7fd095371e8c105f6cb9ab7f87664547

    PostgreSQL数据库统计信息——统计信息系统表_肥叔菌的博客-CSDN博客_postgresql 表统计信息

    《Linux性能优化实战》笔记(24)—— 动态追踪 DTrace_Hehuyi_In的博客-CSDN博客_dtrace linux

    postgresql源码学习(一)—— 源码编译安装与gdb调试入门_Hehuyi_In的博客-CSDN博客_postgresql 源码调试

    源码研究方法论----PG篇.mp4--吕海波_哔哩哔哩_bilibili

  • 相关阅读:
    内容分发网络 CDN
    245:vue+openlayers 利用canvas绘制边线纹路
    TI/德州仪器 TPS2051CDBVR 功率电子开关
    选择合格的数据采集公司,需注意这些
    LoadRunner介绍和脚本录制
    Java中常见的限流算法讲解以及实现思路
    吴恩达2022机器学习专项课测评来了!
    云安全—NIST SP 500-292
    重学C++重构你的C++知识体系 升级版 学习笔记
    Springboot 项目启动类放置位置
  • 原文地址:https://blog.csdn.net/Hehuyi_In/article/details/128053559