你好 Slack Overflowvians。
所以我遇到了这个运行 8.3.11 的 PostgreSQL 服务器(是的,我知道),它处于锁定状态:
ERROR: database is not accepting commands to avoid wraparound data loss in database "postgres"
HINT: Stop the postmaster and use a standalone backend to vacuum that database.
autovacuum=on
通常自动清理守护进程(但是由于这些损坏的数据库对象,该数据库的 XID 从未被重置。
以下是使用管理员用户在单用户模式下运行服务器时的输出片段:
SELECT oid, relname, age(relfrozenxid) FROM pg_class WHERE relkind = 't' ORDER BY age(relfrozenxid) DESC LIMIT 4;
----
1: oid = "2421459" (typeid = 26, len = 4, typmod = -1, byval = t)
2: relname = "pg_toast_2421456" (typeid = 19, len = 64, typmod = -1, byval = f)
3: age = "2146484084" (typeid = 23, len = 4, typmod = -1, byval = t)
----
1: oid = "2421450" (typeid = 26, len = 4, typmod = -1, byval = t)
2: relname = "pg_toast_2421447" (typeid = 19, len = 64, typmod = -1, byval = f)
3: age = "2146484084" (typeid = 23, len = 4, typmod = -1, byval = t)
----
1: oid = "2421435" (typeid = 26, len = 4, typmod = -1, byval = t)
2: relname = "pg_toast_2421432" (typeid = 19, len = 64, typmod = -1, byval = f)
3: age = "2146484084" (typeid = 23, len = 4, typmod = -1, byval = t)
----
1: oid = "2421426" (typeid = 26, len = 4, typmod = -1, byval = t)
2: relname = "pg_toast_2421423" (typeid = 19, len = 64, typmod = -1, byval = f)
3: age = "2146484084" (typeid = 23, len = 4, typmod = -1, byval = t)
请注意,此服务器上的年龄远高于vacuum_freeze_min_age
(成功 VACUUM 后设置的值),因此它发出上述原始错误的原因。以上是在运行之后VACUUM FULL
;所有其他表都很好。
SELECT relfilenode FROM pg_class WHERE oid=2421459;
因此,当我们查看磁盘时(使用上面每个表的 pg_class.relfilenode 值),toast 表的文件丢失了:
$ find /var/lib/pgsql/data/ -type f -name '2421426' | wc -l # Bad toast
0
当我们在磁盘上查看 toast 的索引时
SELECT relfilenode FROM pg_class WHERE (select reltoastidxid FROM pg_class WHERE oid=2421459)
$ find /var/lib/pgsql/data/ -type f -name '2421459' | wc -l # Bad toast's index
0
然后我们试图找到与坏 toast 记录相关的表:
SELECT * FROM pg_class WHERE reltoastrelid=2421459;
上面的每个表格都有 0 个结果!没有用于VACUUM
重置这些关系的 XID 的命令的表。
当我们检查 pg_depend 表并发现这些 TOAST 表没有引用时:
SELECT * FROM pg_depend WHERE refobjid IN(2421459,2421450,2421435,2421426)
问题
- 你能从 pg_class 表中删除坏的 TOAST 表和 TOAST 表索引吗(例如
DELETE FROM pg_class where oid=2421459
) - 我们还需要从其他表中删除关系吗?
- 我们可以只创建一个临时表并将其链接到 TOAST 的索引的 oid 吗?
上面 #3 的示例:
CREATE TABLE adoptedparent (colnameblah char(1));
UPDATE pg_class SET reltoastrelid=2421459 WHERE relname='adoptedparent';
VACUUM FULL VERBOSE adoptedparent
编辑:
select txid_current()
是 3094769499,所以这些表很久以前就损坏了。我们不需要恢复数据。我们在 Linux 2.6.18-238.el5 上运行 ext4 文件系统。我们检查了相关lost+found/
目录,文件不存在。