Skip to content

Commit e28bb88

Browse files
committed
Revert changes to CONCURRENTLY that "sped up" Xmin advance
This reverts commit d9d0762 "VACUUM: ignore indexing operations with CONCURRENTLY". These changes caused indexes created with the CONCURRENTLY option to miss heap tuples that were HOT-updated and HOT-pruned during the index creation. Before these changes, HOT pruning would have been prevented by the Xmin of the transaction creating the index, but because this change was precisely to allow the Xmin to move forward ignoring that backend, now other backends scanning the table can prune them. This is not a problem for VACUUM (which requires a lock that conflicts with a CREATE INDEX CONCURRENTLY operation), but HOT-prune can definitely occur. In other words, Xmin advancement was sped up, but at the cost of corrupting the resulting index. Regrettably, this means that the new feature in PG14 that RIC/CIC on very large tables no longer force VACUUM to retain very old tuples goes away. We might try to implement it again in a later release, but for now the risk of indexes missing tuples is too high and there's no easy fix. Backpatch to 14, where this change appeared. Reported-by: Peter Slavov <[email protected]> Diagnosys-by: Andrey Borodin <[email protected]> Diagnosys-by: Michael Paquier <[email protected]> Diagnosys-by: Andres Freund <[email protected]> Discussion: https://postgr.es/m/17485-396609c6925b982d%40postgresql.org
1 parent 16c80e7 commit e28bb88

File tree

3 files changed

+7
-36
lines changed

3 files changed

+7
-36
lines changed

doc/src/sgml/ref/create_index.sgml

-2
Original file line numberDiff line numberDiff line change
@@ -861,8 +861,6 @@ Indexes:
861861
Like any long-running transaction, <command>CREATE INDEX</command> on a
862862
table can affect which tuples can be removed by concurrent
863863
<command>VACUUM</command> on any other table.
864-
Excepted from this are operations with the <literal>CONCURRENTLY</literal>
865-
option for indexes that are not partial and do not index any expressions.
866864
</para>
867865

868866
<para>

doc/src/sgml/ref/reindex.sgml

-2
Original file line numberDiff line numberDiff line change
@@ -475,8 +475,6 @@ Indexes:
475475
Like any long-running transaction, <command>REINDEX</command> on a table
476476
can affect which tuples can be removed by concurrent
477477
<command>VACUUM</command> on any other table.
478-
Excepted from this are operations with the <literal>CONCURRENTLY</literal>
479-
option for indexes that are not partial and do not index any expressions.
480478
</para>
481479

482480
<para>

src/backend/storage/ipc/procarray.c

+7-32
Original file line numberDiff line numberDiff line change
@@ -1659,13 +1659,7 @@ TransactionIdIsActive(TransactionId xid)
16591659
* relations that's not required, since only backends in my own database could
16601660
* ever see the tuples in them. Also, we can ignore concurrently running lazy
16611661
* VACUUMs because (a) they must be working on other tables, and (b) they
1662-
* don't need to do snapshot-based lookups. Similarly, for the non-catalog
1663-
* horizon, we can ignore CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY
1664-
* when they are working on non-partial, non-expressional indexes, for the
1665-
* same reasons and because they can't run in transaction blocks. (They are
1666-
* not possible to ignore for catalogs, because CIC and RC do some catalog
1667-
* operations.) Do note that this means that CIC and RC must use a lock level
1668-
* that conflicts with VACUUM.
1662+
* don't need to do snapshot-based lookups.
16691663
*
16701664
* This also computes a horizon used to truncate pg_subtrans. For that
16711665
* backends in all databases have to be considered, and concurrently running
@@ -1715,6 +1709,9 @@ ComputeXidHorizons(ComputeXidHorizonsResult *h)
17151709
bool in_recovery = RecoveryInProgress();
17161710
TransactionId *other_xids = ProcGlobal->xids;
17171711

1712+
/* inferred after ProcArrayLock is released */
1713+
h->catalog_oldest_nonremovable = InvalidTransactionId;
1714+
17181715
LWLockAcquire(ProcArrayLock, LW_SHARED);
17191716

17201717
h->latest_completed = ShmemVariableCache->latestCompletedXid;
@@ -1734,7 +1731,6 @@ ComputeXidHorizons(ComputeXidHorizonsResult *h)
17341731

17351732
h->oldest_considered_running = initial;
17361733
h->shared_oldest_nonremovable = initial;
1737-
h->catalog_oldest_nonremovable = initial;
17381734
h->data_oldest_nonremovable = initial;
17391735

17401736
/*
@@ -1833,25 +1829,11 @@ ComputeXidHorizons(ComputeXidHorizonsResult *h)
18331829
(statusFlags & PROC_AFFECTS_ALL_HORIZONS) ||
18341830
in_recovery)
18351831
{
1836-
/*
1837-
* We can ignore this backend if it's running CREATE INDEX
1838-
* CONCURRENTLY or REINDEX CONCURRENTLY on a "safe" index -- but
1839-
* only on vacuums of user-defined tables.
1840-
*/
1841-
if (!(statusFlags & PROC_IN_SAFE_IC))
1842-
h->data_oldest_nonremovable =
1843-
TransactionIdOlder(h->data_oldest_nonremovable, xmin);
1844-
1845-
/* Catalog tables need to consider all backends in this db */
1846-
h->catalog_oldest_nonremovable =
1847-
TransactionIdOlder(h->catalog_oldest_nonremovable, xmin);
1832+
h->data_oldest_nonremovable =
1833+
TransactionIdOlder(h->data_oldest_nonremovable, xmin);
18481834
}
18491835
}
18501836

1851-
/* catalog horizon should never be later than data */
1852-
Assert(TransactionIdPrecedesOrEquals(h->catalog_oldest_nonremovable,
1853-
h->data_oldest_nonremovable));
1854-
18551837
/*
18561838
* If in recovery fetch oldest xid in KnownAssignedXids, will be applied
18571839
* after lock is released.
@@ -1873,8 +1855,6 @@ ComputeXidHorizons(ComputeXidHorizonsResult *h)
18731855
TransactionIdOlder(h->shared_oldest_nonremovable, kaxmin);
18741856
h->data_oldest_nonremovable =
18751857
TransactionIdOlder(h->data_oldest_nonremovable, kaxmin);
1876-
h->catalog_oldest_nonremovable =
1877-
TransactionIdOlder(h->catalog_oldest_nonremovable, kaxmin);
18781858
/* temp relations cannot be accessed in recovery */
18791859
}
18801860
else
@@ -1901,9 +1881,6 @@ ComputeXidHorizons(ComputeXidHorizonsResult *h)
19011881
h->data_oldest_nonremovable =
19021882
TransactionIdRetreatedBy(h->data_oldest_nonremovable,
19031883
vacuum_defer_cleanup_age);
1904-
h->catalog_oldest_nonremovable =
1905-
TransactionIdRetreatedBy(h->catalog_oldest_nonremovable,
1906-
vacuum_defer_cleanup_age);
19071884
/* defer doesn't apply to temp relations */
19081885
}
19091886

@@ -1926,9 +1903,7 @@ ComputeXidHorizons(ComputeXidHorizonsResult *h)
19261903
h->shared_oldest_nonremovable =
19271904
TransactionIdOlder(h->shared_oldest_nonremovable,
19281905
h->slot_catalog_xmin);
1929-
h->catalog_oldest_nonremovable =
1930-
TransactionIdOlder(h->catalog_oldest_nonremovable,
1931-
h->slot_xmin);
1906+
h->catalog_oldest_nonremovable = h->data_oldest_nonremovable;
19321907
h->catalog_oldest_nonremovable =
19331908
TransactionIdOlder(h->catalog_oldest_nonremovable,
19341909
h->slot_catalog_xmin);

0 commit comments

Comments
 (0)