Postgresql源码(118)elog/ereport报错跳转功能分析

1 日志接口

elog.c完成PG中日志的生产、记录工作,对外常用接口如下:

1.1 最常用的ereport和elog

ereport(ERROR,(errcode(ERRCODE_UNDEFINED_TABLE),errmsg("relation \"%s\" does not exist",relation->relname)));
elog(ERROR, "unexpected enrtype: %d", enrmd->enrtype);

其实都是在调用errstart和errfinish函数完成具体工作。

#define elog(elevel, ...)  \ereport(elevel, errmsg_internal(__VA_ARGS__))#define ereport(elevel, ...)	\ereport_domain(elevel, TEXTDOMAIN, __VA_ARGS__)#define ereport_domain(elevel, domain, ...)	\do { \pg_prevent_errno_in_scope(); \if (__builtin_constant_p(elevel) && (elevel) >= ERROR ? \errstart_cold(elevel, domain) : \errstart(elevel, domain)) \__VA_ARGS__, errfinish(__FILE__, __LINE__, __func__); \if (__builtin_constant_p(elevel) && (elevel) >= ERROR) \pg_unreachable(); \} while(0)

2 日志数据结构

  • 单条日志被抽象为ErrorData,记录了日志的全部信息。
  • elog.c提供了一个深度为5的stack来存放最多五层的ErrorData,大部分场景下,stack只会使用一层:
#define ERRORDATA_STACK_SIZE  5
static ErrorData errordata[ERRORDATA_STACK_SIZE];

在这里插入图片描述

3 日志的工作流程

每一条日志都是经过errstart和errfinish函数处理的,分工大致为:

  • errstart
    1. 在errdata堆栈中压入一个新的edata
    2. 为edata填充部分错误信息,例如错误等级、需要输出到server/client、按需升级错误等级(例如Crit区域中大于等于ERROR的需要变成PINIC)
  • errfinish
    1. 在进入errfinish前,错误信息的文本经过errmsg或errmsg_internal函数中的EVALUATE_MESSAGE宏记入edata中的message中,内存用的是errfinish
    2. 三部分工作:
      • 3.1 完成PG_TRY()、PG_CATCH()跳转功能,为errfinish添加try/catch功能
      • 3.2 完成error_context_stack的回调功能,为errfinish增加报错信息
      • 3.3 完成EmitErrorReport,为errfinish发送错误信息

3.1 完成PG_TRY()、PG_CATCH()跳转功能,为errfinish添加try/catch功能

注意PG_CATCH和PG_FINALLY是二选一的,区别是PG_FINALLY会在最后把异常重新抛出去,而PG_CATCH自己处理完了就不在向上抛了。

#define PG_TRY()  \do { \sigjmp_buf *_save_exception_stack = PG_exception_stack; \ErrorContextCallback *_save_context_stack = error_context_stack; \sigjmp_buf _local_sigjmp_buf; \bool _do_rethrow = false; \if (sigsetjmp(_local_sigjmp_buf, 0) == 0) \{ \PG_exception_stack = &_local_sigjmp_buf#define PG_CATCH(...)	\} \else \{ \PG_exception_stack = _save_exception_stack; \error_context_stack = _save_context_stack#define PG_FINALLY() \} \else \_do_rethrow = true; \{ \PG_exception_stack = _save_exception_stack; \error_context_stack = _save_context_stack#define PG_END_TRY()  \} \if (_do_rethrow) \PG_RE_THROW(); \PG_exception_stack = _save_exception_stack; \error_context_stack = _save_context_stack; \} while (0)

我们先看一个PG中常规的报错流程,注意是不在PG_TRY中的elog(ERROR),发生>=ERROR级别的异常后,在errfinish中会抛出异常,jmp到PostgresMain函数中的sigsetjmp的位置,进入异常回收流程。
在这里插入图片描述
那么如果代码中的报错被PG_TRY、PG_CATCH包裹时,抛出异常会发生什么呢?
在这里插入图片描述

3.2 完成error_context_stack的回调功能,为errfinish增加报错信息

error_context_stack是一个Lisrt记录了回调函数回调函数的参数,这里的函数的作用是添加报错信息,因为这些函数会在errfinish时被调用,函数中往往都会使用errcontext_msg记录一些更详细的报错文本。

typedef struct ErrorContextCallback
{struct ErrorContextCallback *previous;void		(*callback) (void *arg);void	   *arg;
} ErrorContextCallback;extern PGDLLIMPORT ErrorContextCallback *error_context_stack;

例如pl编译时配置的plpgsql_compile_error_callback函数,为了增加编译报错时,错误的发生的位置等:

do_compile...plerrcontext.callback = plpgsql_compile_error_callback;plerrcontext.arg = forValidator ? proc_source : NULL;plerrcontext.previous = error_context_stack;error_context_stack = &plerrcontext;...
static void
plpgsql_compile_error_callback(void *arg)
{if (arg){/** Try to convert syntax error position to reference text of original* CREATE FUNCTION or DO command.*/if (function_parse_error_transpose((const char *) arg))return;/** Done if a syntax error position was reported; otherwise we have to* fall back to a "near line N" report.*/}if (plpgsql_error_funcname)errcontext("compilation of PL/pgSQL function \"%s\" near line %d",plpgsql_error_funcname, plpgsql_latest_lineno());
}

error_context_stack和上面提到的PG_exception_stack都会在TRY中进行保存和恢复,为什么:

  • PG_exception_stack比较好理解,因为TRY时会建一个新的jmpbuf用PG_exception_stack指向,之前的旧值需要记录下来,TRY完了需要恢复。
  • error_context_stack的回调函数是在子模块中配置的,正常执行完子模块会把error_context_stack恢复原样,但一旦error发生了跳转,恢复逻辑就被跳过了。所以在TRY中自带了恢复error_context_stack的逻辑。

3.3 完成EmitErrorReport,为errfinish发送错误信息

errfinish......EmitErrorReport......

EmitErrorReport函数中会执行发送逻辑:

EmitErrorReport...if (edata->output_to_server && emit_log_hook)(*emit_log_hook) (edata);/* Send to server log, if enabled */if (edata->output_to_server)send_message_to_server_log(edata);    // 写 write_syslog/* Send to client, if enabled */if (edata->output_to_client)send_message_to_frontend(edata);      // 写libpq,发送到客户端或主进程

4 CopyErrorData / FlushErrorState / FreeErrorData

由于edata中的信息是在ErrorContext中申请的,在PG_CATCH时,是能拿到edata使用的,但在catch时不应该使用ErrorContext申请任何内存,所以惯用法是在PG_CATCH中用CopyErrorData把edata拷贝到当前的上下文中,在进行操作。然后把ErrorContext中的edata用FlushErrorState清理干净。

例如PL中的用法

		PG_CATCH();{ErrorData  *edata;....../* Save error info in our stmt_mcontext */MemoryContextSwitchTo(stmt_mcontext);// 拷贝edata到当前上下文中edata = CopyErrorData();// ErrorContext中的用完尽快释放FlushErrorState();......// 尽情使用使用edataexception_matches_conditions(edata, exception->conditions)......	

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/237518.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

文献速递:生成对抗网络医学影像中的应用—— CG-3DSRGAN:用于从低剂量PET图像恢复图像质量的分类指导的3D生成对抗网络

文献速递:生成对抗网络医学影像中的应用—— CG-3DSRGAN:用于从低剂量PET图像恢复图像质量的分类指导的3D生成对抗网络 本周给大家分享文献的主题是生成对抗网络(Generative adversarial networks, GANs)在医学影像中的应用。文献…

JFreeChart 生成图表,并为图表标注特殊点、添加文本标识框

一、项目场景: Java使用JFreeChart库生成图片,主要场景为将具体的数据 可视化 生成曲线图等的图表。 本篇文章主要针对为数据集生成的图表添加特殊点及其标识框。具体包括两种场景:x轴为 时间戳 类型和普通 数值 类型。(y轴都为…

【ceph】pg down的处理流程

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》:python零基础入门学习 《python运维脚本》: python运维脚本实践 《shell》:shell学习 《terraform》持续更新中:terraform_Aws学习零基础入门到最佳实战 《k8…

【AI美图】第09期效果图,AI人工智能汽车+摩托车系列图集

期待中的未来AI汽车 欢迎来到未来的世界,一个充满创新和无限可能的世界,这里有你从未见过的科技奇迹——AI汽车。 想象一下,你站在十字路口,繁忙的交通信号灯在你的视线中闪烁,汽车如潮水般涌来,但是&…

灰度化、二值化、边缘检测、轮廓检测

灰度化 定义 灰度图像是只含亮度信息,不含色彩信息的图像。灰度化处理是把彩色图像转换为灰度图像的过程,是图像处理中的基本操作。OpenCV 中彩色图像使用 BGR 格式。灰度图像中用 8bit 数字 0~255 表示灰度,如:0 表…

使用汇编和反汇编引擎写一个x86任意地址hook

最简单的Hook 刚开始学的时候,用的hook都是最基础的5字节hook,也不会使用hook框架,hook流程如下: 构建一个jmp指令跳转到你的函数(函数需定义为裸函数)保存被hook地址的至少5字节机器码,然后写入构建的jmp指令接着在…

Layui 2.9.2 列表商品展示页 用模板引擎 laytpl Ajax 读取json 数据 筛选数组 filter css 限制文体显示过长用。。。代替

全代码&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><title>软件管理器</title><meta name"renderer" content"webkit"><meta http-equiv"X-UA-Compatible" conten…

Flink系列之:Elasticsearch SQL 连接器

Flink系列之&#xff1a;Elasticsearch SQL 连接器 一、Elasticsearch SQL 连接器二、创建 Elasticsearch表三、连接器参数四、Key 处理五、动态索引六、数据类型映射 一、Elasticsearch SQL 连接器 Sink: BatchSink: Streaming Append & Upsert ModeElasticsearch 连接器…

Graylog配置日志保留策略

找了半天没找到说的清楚的&#xff0c;只能抠官方文档 graylog的归档&#xff08;日志持久化&#xff09;只有付费版才能用&#xff0c;所以日志只能存在es中 1.理解官方给出的几个概念 轮转策略 (Index Rotation Strategy): 轮转策略定义了何时创建新的索引以及何时关闭旧的索…

pytorch-模型预测概率值为负数

在进行ocr识别模型预测的时候&#xff0c;发现预测的结果是正确的&#xff0c;但是概率值是负数&#xff1a; net_out net(img) #torch.Size([70, 1, 41]) logit, preds net_out.max(2) #41是类别 需要对类别取最大值 preds preds.transpose(1, 0).contiguous().view(-1) …

Win10安装Gogs保姆级教程

什么是 Gogs? Gogs 是一款极易搭建的自助 Git 服务。 开发目的 Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自助 Git 服务。使用 Go 语言开发使得 Gogs 能够通过独立的二进制分发&#xff0c;并且支持 Go 语言支持的 所有平台&#xff0c;包括 Linux、Mac OS X…

微软官方出品:GPT大模型编排工具,支持C#、Python等多个语言版本

随着ChatGPT的火热&#xff0c;基于大模型开发应用已经成为新的风口。虽然目前的大型模型已经具备相当高的智能水平&#xff0c;但它们仍然无法完全实现业务流程的自动化&#xff0c;从而达到用户的目标。 微软官方开源的Semantic Kernel的AI编排工具&#xff0c;就可以很好的…

C语言struct,union内存对齐

测试环境&#xff1a; #include<stdio.h> int main(){//1字节对齐struct XXX{unsigned char ch;unsigned int in;unsigned short si;}__attribute__((packed));struct XXX xxx;printf("%zd\n",sizeof(xxx));//7#pragma pack(1)struct YYY{unsigned char ch;u…

057:vue组件方法中加载匿名函数

第057个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

CSS:元素显示模式与背景

CSS&#xff1a;元素显示模式与背景 元素显示模式什么是元素显示模式块级元素 block行内元素 inline行内块元素 inline-block元素显示模式对比元素显示模式转换 display 背景背景颜色 background-color背景图片 background-image背景平铺 background-repeat背景图片位置 backgr…

MIT6.5840-2023-Lab4B: Sharded K/V Service-Sharded K/V Server

实验内容 实现一个分片 k/v 存储系统&#xff0c;分片指如所有以“a”开头的键可能是一个分片&#xff0c;所有以 “b”开头的键可能是另一个分片。每个副本组仅处理几个分片的 Put、Append 操作&#xff0c;实现并行操作&#xff0c;系统总吞吐量&#xff08;单位时间的放入和…

恶意软件样本行为分析——Process Monitor和Wireshark

1.1 实验名称 恶意软件样本行为分析 1.2 实验目的 1) 熟悉 Process Monitor 的使用 2) 熟悉抓包工具 Wireshark 的使用 3) VMware 的熟悉和使用 4) 灰鸽子木马的行为分析 1.3 实验步骤及内容 第一阶段&#xff1a;熟悉 Process Monitor 的使用 利用 Process …

在Linux上安装CLion

本教程将指导你如何在Linux系统上安装CLion&#xff0c;下载地址为&#xff1a;https://download.jetbrains.com.cn/cpp/CLion-2022.3.3.tar.gz。以下是详细的安装步骤&#xff1a; 步骤1&#xff1a;下载CLion 首先&#xff0c;你需要使用wget命令从提供的URL下载CLion的tar…

Redis安全性加强:认证与加密实践

大家好&#xff0c;我是升仔 引言 Redis作为一个广泛使用的高性能键值存储系统&#xff0c;在众多应用场景中扮演着重要角色。然而&#xff0c;由于其默认配置不强调安全性&#xff0c;因此在生产环境中部署Redis时&#xff0c;加强其安全性是非常重要的。 1、实际使用场景&…

前端学习——关于前端框架的思考

前端框架 我们知道在AngularJS&#xff0c;react&#xff0c;vue等前端框架出现之前&#xff0c;前端开发都是通过js直接操作dom树来实现的&#xff0c;而有了前端框架之后&#xff0c;前端开发基本上不需要在直接操作dom树&#xff0c;相当于在原生html的dom树之间和前端程序…