Various comments in GetOldestXmin mention the possibility of the oldest xmin going backward, and assert that this is actually safe. It's not.
Consider: A table has a toastable column. A row is updated in a way that changes the toasted value. There are now two row versions pointing to different toast values, one live and one dead. Now suppose the toast table - but not the main table - is vacuumed; the dead toast entries are removed, even though they are still referenced by the dead main-table row. Autovacuum treats the main table and toast table separately, so this can happen. Now suppose that OldestXmin goes backwards so that the older main table row version is no longer dead, but merely recently-dead. At this point, VACUUM FULL (or similar rewrites) on the table will fail with "missing chunk number 0 for ..." toast errors, because it tries to copy the recently-dead row, but that row's toasted values have been vacuumed away already. (I've been working for a while with someone on IRC to track down the source of unexplained semi-repeatable "missing chunk number 0 ..." errors from VACUUM FULL. I don't know at this stage whether this is the actual problem, but it matches the symptoms.) -- Andrew (irc:RhodiumToad)