学习让我快乐

争于世, 不争于势;简洁, 高效, 赏心悦目

PG 中的优化器: 概念

本文章内容根据 PG9.6 代码而来. 我个人感觉, 对 PG 优化器的学习一定要切合一个特定的链路, 更细化地说是一个特定的查询. 因为 PG 优化器被用来处理所有可能的查询, 它里面包含了大量的分支判断, 虽然 PG 将若干分支进行了一定的抽象汇总, 但是如果没有特定查询场景下, 咋一看也是有点蒙的. 另外该篇文章主要着重于对优化过程中所用到的各种概念的描述, 并未太过详细地描...

21亿次事务之后...

最近在看 Greenplum 的分布式事务执行框架, 发现了一个较为有意思的 bug, 该 bug 出现在判定分布式事务先后次序的逻辑上面, 会导致在执行 21 亿事务之后, 准确来说是 2147483659 次事务之后, 后续的分布式事务可能会构造出错误的分布式快照, 导致了之前的事务插入的数据对之后的事务不再可见. 为了能够搞清楚这个 bug 是怎么发生的, 我们先简单介绍下 GP 中的...

PG 中的事务: XLOG

本文章内容根据 PG9.6 代码而来. XLOG, 也即 WAL 在 PG 中的别称, 我们这里不对 WAL 背后的细节背景做过多介绍, 更专注与 PG 中是如何实现 WAL 的, 即 PG 的 XLOG 模块. 在 PG 之中, 每一条 XLOG 都对应着一个 XLogRecord, 其内存放着所有与当前 XLOG 相关的信息, 大致来说主要就是: 当前 XLO...

指令级优化参考手册: 三

最近在做的一些事对性能要求极其苛刻, 以至于最后不得不下潜到指令级找寻一些可能存在的优化点. 这里总结记录了在此过程中所得到的一些通用化优化规则. 在试图应用这些规则来优化自己的程序之前要首先铭记先贤们说过的: “过早优化是万恶之源”. 因此我们建议除非是使用了 perf 等工具找到了程序热点, 否则不应该首先应用这些规则来对程序进行优化. 我个人认为在写代码的过程中惦记着怎么把这段代码最优...

为什么 unlock 时没有唤醒我?

还是我们的 ADB PG 测试实例, 收到了测试脚本执行超时的报警, 看了一下发现是由于已经执行很久的 DELETE 持有的锁阻塞了测试脚本中 DDL 的执行, 又看了一下这个 DELETE backend 的堆栈: #0 0x00002b2049a2af67 in semop () from /lib64/libc.so.6 #1 0x0000000000770bc4 in PGSe...

SIGUSR2 导致的血案

有一天忽然收到我们 ADB PG 测试实例重启的报警, 当时上去看了下发现是实例部署个关于内存控制的参数没配置合适导致计算节点 OOM 了, 恰好当时 master 在处于恢复残留两阶段事务的关键链路, 发现无法链接 segment, 毕竟此时 segment 处于 recovery mode, 便 PANIC 退出了. 当时按照预案配置好相关参数, 理论上是需要一次重启才能使实例生效的, ...

函数调用的背后

一般情况下, 我们很少会关注函数调用是如何实现的, 反正大概就是压栈出栈什么的. 但是在我们 debug 时, 尤其是在 debug coredump 时, 知道这背后的细节还是会起到很大帮助的. 如我们在 debug qtcreator 时, 见 为什么我的 QtCreator 看不了 GCC 源码. 之前我对这方面的掌握一直零零散散的, 这里总结一下. 目前据我所知, 编译器在实现函数...

PG 的扩展性: 类型

如果需要在系统中实现一个支持用户自定义数据类型的功能, 你该怎么做? 如果是我的话, 我在系统中将只负责为这个数据类型提供一个定长/变长的存储空间, 之后关于对这个存储空间的使用与解析全部交于用户去做. 在 PG 中, 也是类似做法. PG 中使用长度固定为 8 字节(起码在 64 位机器上)的 Datum 来表示所有的用户数据类型. 即 Datum 肩负着在 PG 内核与用户代码之间传递数...

为什么我的 QtCreator 看不了 GCC 源码

在分析 GCC 中的整数转换之初, 我一如既往地想把 GCC 源码导入到 QtCreator 中, 没想到遇到了: 以及一堆堆栈. Thread 12 Crashed:: Thread (pooled) 0 libCPlusPlus.4.10.2.dylib 0x000000010a8e3178 CPlusPlus::Parser::parseClassOrNamesp...

PG 中的事务: 快照

本文章内容根据 PG9.6 代码而来. 众所众知, PG 通过 MVCC 多版本机制实现了事务. 在 PG 中, 每个 query 在执行时, 都会首先通过 GetSnapshotData() 来获取一张快照, 这个快照可以认为是数据库在某一特定时间点下所有数据的集合, 这张快照中包含的信息很简单: xmin, 当前正在运行的事务集合中最小的 xid 值. 所有在 xmin...

PG 中的事务: 事务 id

本文章内容根据 PG9.6 代码而来. PG 之中, 使用 uint32 来表示存放事务 id, 因此如不作任何处理的情况下, 最多只能运行 2 ** 32 个事务, 很显然这是不合理的. 为了解决这个问题, PG 使用了很巧妙的一个法子: 将 uint32 取值空间作为一个环来看待, 定义对于环中任一一点, 该点向前(顺时针方向) 2 ** 31 范围内的事务都认为发生在该点之后...

GCC 中的整数转换

一直以来, 我对 C/C++ 中的整数类型转换规则了解一直是云里雾里的, 尤其是涉及到有符号整数类型时, 更是说不清个所以然. 这种情况一直存在着, 主要是我在业务日常开发上很少遇到整数类型转换, 所以也一直没想着去搞清, 直至遇到了 Postgresql 代码, PG 代码中在 TransactionIdPrecedes() 等函数实现中大量使用了整数类型转换(详见 PG 中的事务 id)...

PG 中的 statistics collector

本文章内容根据 PG9.6 代码而来. PG 中的 statistics collector 负责收集, 保存, 持久化 PG 运行中产生的各种 metric 信息, 如表的增, 删, 改行数等. statistics collector 收集到的所有信息都保存在内存中, 存放在 pgStatDBHash 指向的哈希表中. 该哈希表的结构等同于 std::unordered_map...