项目简介
pgrust 是用 Rust 重写的 PostgreSQL 数据库系统,兼容 Postgres 18.3,通过超过 4.6 万条回归查询,磁盘格式与原生 Postgres 兼容。项目目标是通过 Rust 和 AI 辅助开发降低修改 Postgres 的门槛。
README 预览
pgrust\n\n\n A Postgres rewrite in Rust.\n\n\n\n \n \n \n \n \n\n\n\n Browser demo\n | \n Discord\n | \n Get pgrust updates\n | \n Issues\n\n\n\n\npgrust targets compatibility with Postgres 18.3 and matches Postgres's\nexpected output across more than 46,000 regression queries.\n\npgrust is disk compatible with Postgres and can boot from an existing Postgres\n18.3 data directory.\n\nThe goal is to make Postgres easier to change from the inside: keep the behavior\nPostgres-shaped, keep the real Postgres tests as the oracle, and use Rust plus\nAI-assisted programming to explore deeper server changes.\n\nUpdate: We're working on a new not yet published version of pgrust that currently passes 100% of Postgres regression suite, has a thread per connection model instead of process per connection, is 50% faster than Postgres on transaction workloads, and is ~300x faster than Postgres on analytical workloads (2x slower than Clickhouse on clickbench and we think it can get faster than Clickhouse). Follow pgrust or join our Discord for updates!\n\n## Follow pgrust\n\n[Get project updates by email](https://pgrust.com/#updates), including new\nreleases, compatibility milestones, and architecture experiments.\n\n## Status\n\npgrust is not production-ready yet. It is not performance optimized yet.\n\nExisting Postgres extensions and procedural language extensions such as\nPL/Python, PL/Perl, and PL/Tcl are not generally compatible yet. Some bundled\ncontrib modules are already ported, and more compatibility may be possible over\ntime.\n\n## Roadmap\n\n- multithreaded Postgres internals\n- built-in connection pooling\n- better JSON-heavy workload support\n- fast forking and branching workflows\n- storage experiments, including no-vacuum designs\n- runtime guardrails for bad queries and AI-generated SQL\n- fewer sudden bad plan switches\n\n## Try It\n\nTry the WebAssembly demo at https://pgrust.com.
常见问题 (5)
故障排除如何修复 pgrust 中崩溃恢复后 DROP TABLE 挂起且 CPU 占用 100% 的问题?
这是由 WAL 重做(redo)过程中泄漏的缓冲区 pin 引起的:恢复预取器(recovery prefetcher)的 io_uring 通道会将最后一个预取的页面一直 pin 在启动线程的 ring slot 中。随后 InvalidateBuffer 会在这一外部 pin 上自旋,且无法被取消。
修复方法:将 pgrust 升级到包含 PR #2062、提交 4f84297963e(xlogrecovery: drain prefetch pins after the redo loop)的构建版本。该补丁会在重做循环结束后、恢复结束检查点(end-of-recovery checkpoint)之前立即排空预取 ring,并使对外部 pin 的等待变为可取消。使用以下命令构建并重启:
git fetch origin
git checkout 4f84297963e # or any later commit containing the fix
cargo build --release --locked --bin postgres
然后重启服务器并重试 DROP TABLE。恢复完成后,通过查看 pg_buffercache 中的 pinning_backends = 0 来验证该关系不存在泄漏的 pin。
针对存在漏洞构建的临时缓解措施:在计划停机之前,于大批量插入后运行 CHECKPOINT,使这些页面在恢复时不会仅从 WAL 重放。这无法防止意外崩溃。如果某个后端已经在自旋,pg_cancel_backend 无法将其停止;请使用打过补丁的构建版本重启。
故障排除在 pgrust 中,对包含 PostgreSQL IDENTITY 列的表执行 INSERT 并运行 EXPLAIN VERBOSE 时,出现 "T_NextValueExpr deparse arm unported" 错误,该如何修复?
当 EXPLAIN VERBOSE 对 GENERATED ALWAYS AS IDENTITY 列的执行计划进行反解析时,会影响 pgrust 0.2。临时解决方法:运行不带 VERBOSE 的 EXPLAIN,例如:
EXPLAIN INSERT INTO t (v) VALUES (1);
在使用其他选项时,也可以省略 VERBOSE:
EXPLAIN (ANALYZE, BUFFERS) INSERT INTO t (v) VALUES (1);
执行计划仍会打印,但包含 identity 序列的 nextval(...) 表达式的详细 Output: 行将被省略。
永久修复:将 pgrust 升级到包含 PR #472 的构建版本(已于 2026-08-08 在 main 分支上修复)。该修复将 NextValueExpr 反解析为 nextval('seq'),与 PostgreSQL 18.6 保持一致。serial 列不受影响,因为它们使用的是常规的 DEFAULT nextval(...) 路径。
故障排除如何修复在 pgrust 中向 format() 传递 NULLIF、GREATEST、IS NULL 或 AND 时出现的 "funcapi exprType: node family T_NullIfExpr not ported" 错误?
将 pgrust 升级到包含提交 77ab13c454b 的当前 main 构建版本。该修复使 funcapi 将参数类型解析委托给 nodes_core::node_funcs::expr_type,覆盖 T_NullIfExpr、T_MinMaxExpr、T_NullTest、T_BoolExpr、T_DistinctExpr、T_BooleanTest、T_ScalarArrayOpExpr、T_SubPlan 及相关表达式族。这会影响使用 PostgreSQL 18.3 兼容代码的 pgrust 0.2,以及使用运行时解析的 "any" 或 VARIADIC "any" 参数的函数,例如 format()、concat()、concat_ws() 和 json_build_object()。如果无法立即升级,请在物化 CTE 或子查询中对问题表达式求值,并将结果列/Var 传递给函数,而不是传递原始表达式。
故障排除如何修复启动 SERIALIZABLE 事务时出现的 "SERIALIZABLEXACT slots exhausted and the pg_serial summarization path is not ported" panic?
当固定大小的 SERIALIZABLEXACT 池(大小为 (MaxBackends + max_prepared_xacts) * 10)已满时,就会发生此 panic。在受影响的 pgrust 构建版本中,pg_serial SLRU 摘要化尚未实现,因此 GetSerializableTransactionSnapshot 会 panic,而不是回收最旧的已提交可串行化事务。
修复方法是升级到包含 PR #168 的最新 main 构建版本。该版本移植了真正的 pg_serial SLRU,并使 GetSerializableTransactionSnapshotInt 通过循环调用 SummarizeOldestCommittedSxact 和 CreatePredXact 来工作,与 PostgreSQL 的行为一致。SerialAdd、SerialSetActiveSerXmin 和 CheckPointPredicate 也已实现。
步骤:
1. 获取并构建包含 PR #168 的 main 提交。
2. 重新部署并重启数据库。
3. 可选择使用 scripts/ssi-sxact-exhaustion-e2e.sh 进行验证;该回归测试会耗尽槽位池,运行 CHECKPOINT,并确认没有发生 panic 且服务器保持健康。
旧版本上的临时缓解措施:
- 降低 SERIALIZABLE 事务的并发度或提交速率。
- 避免长时间运行且会固定(pin)SxactGlobalXmin 的 SERIALIZABLE 会话。
- 如果安全,可增大 max_prepared_transactions 或 MaxBackends 以提高池阈值,然后重启。
- 仅当正确性要求允许时,才将高变更率的事务迁移到 READ COMMITTED;这会削弱可串行化保证。
故障排除如何修复 pgrust 并行/morsel VACUUM 在 coverage-guard 触发后出现的 dead_items_info.num_items 双重计数或调试断言失败?
此 bug 影响通过 PGRUST_RUNTIME_VACUUM=1 启用的实验性 parallel/morsel VACUUM 路径。当 coverage guard 回退 resume_g 时,leader 可能会在 serial arm 重新扫描之前,处理位于恢复点之上的 deferred-cleanup 页面。dead_items_add() 替换了该块的 TID,但仍会再次递增 dead_items_info.num_items,导致重复计数,并在 debug 构建中触发 debug_assert_eq!(tids.len() as i64, vacrel.dead_items_info.num_items) 断言失败。
修复方法:更新到包含 PR #469/当前 main 的 pgrust 构建。该修复使 round_drain_plan 将 leader 延迟的清理页面钳制在回退后的恢复块之下,确保每个页面仅由一个 arm 排空。回归测试包括 morsel_coverage_trip_counts_each_dead_item_once 和 morsel_verified_round_drains_all_runs_and_deferred。
临时解决方法:禁用实验性并行 vacuum 路径:
unset PGRUST_RUNTIME_VACUUM
# or
PGRUST_RUNTIME_VACUUM=0
请勿在生产环境中启用诸如 PGRUST_RUNTIME_VACUUM_FAULT=lose-local 之类的测试故障注入。