public inbox for [email protected]help / color / mirror / Atom feed
[PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits 25+ messages / 4 participants [nested] [flat]
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v3] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 122 ++++++++++++++++++++++++++++++- src/include/storage/proc.h | 6 +- 2 files changed, 124 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 75552c64ed..5019397d50 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -385,7 +385,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -406,7 +409,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_IC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -426,7 +430,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_IC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -519,6 +524,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1045,6 +1051,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1431,6 +1448,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_IC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1490,6 +1516,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_IC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1546,6 +1581,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_IC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); @@ -3021,6 +3065,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) PROGRESS_CREATEIDX_ACCESS_METHOD_OID }; int64 progress_vals[4]; + bool safe_index = true; /* * Create a memory context that will survive forced transaction commits we @@ -3324,6 +3369,23 @@ ReindexRelationConcurrently(Oid relationOid, int options) */ newIndexRel = index_open(newIndexId, ShareUpdateExclusiveLock); + /* + * When doing concurrent reindex, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX + * CONCURRENTLY to ignore us when waiting for concurrent snapshots. + * That can only be done for indexes that don't execute any + * expressions. Determine that for all involved indexes together. (The + * flag is reset automatically at transaction end, so it must be set + * for each transaction.) + */ + if (safe_index) + { + IndexInfo *newIndexInfo = BuildIndexInfo(newIndexRel); + + safe_index = newIndexInfo->ii_Expressions == NIL && + newIndexInfo->ii_Predicate == NIL; + } + /* * Save the list of OIDs and locks in private context */ @@ -3393,6 +3455,15 @@ ReindexRelationConcurrently(Oid relationOid, int options) CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_IC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 2 of REINDEX CONCURRENTLY * @@ -3456,6 +3527,15 @@ ReindexRelationConcurrently(Oid relationOid, int options) } StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_IC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of REINDEX CONCURRENTLY * @@ -3559,6 +3639,15 @@ ReindexRelationConcurrently(Oid relationOid, int options) StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_IC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + forboth(lc, indexIds, lc2, newIndexIds) { char *oldName; @@ -3609,6 +3698,15 @@ ReindexRelationConcurrently(Oid relationOid, int options) CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_IC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 5 of REINDEX CONCURRENTLY * @@ -3641,6 +3739,15 @@ ReindexRelationConcurrently(Oid relationOid, int options) CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_IC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 6 of REINDEX CONCURRENTLY * @@ -3692,6 +3799,15 @@ ReindexRelationConcurrently(Oid relationOid, int options) /* Start a new transaction to finish process properly */ StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_IC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* Log what we did */ if (options & REINDEXOPT_VERBOSE) { diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..50ce5c8cf2 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_IC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_IC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.21.0 --5k2hsgqhdfnmvlms-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v4 2/2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 92 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 ++- 2 files changed, 94 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 75552c64ed..4abb60ea44 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -94,6 +94,7 @@ static void ReindexMultipleInternal(List *relids, int options); static void reindex_error_callback(void *args); static void update_relispartition(Oid relationId, bool newval); static bool CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts); +static void set_safe_index_flag(void); /* * callback argument type for RangeVarCallbackForReindexIndex() @@ -385,7 +386,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -406,7 +410,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_IC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -426,7 +431,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_IC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -519,6 +525,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1045,6 +1052,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1431,6 +1449,10 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + set_safe_index_flag(); + /* * The index is now visible, so we can report the OID. */ @@ -1490,6 +1512,10 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + set_safe_index_flag(); + /* * Phase 3 of concurrent index build * @@ -1546,6 +1572,10 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + set_safe_index_flag(); + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); @@ -3021,6 +3051,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) PROGRESS_CREATEIDX_ACCESS_METHOD_OID }; int64 progress_vals[4]; + bool safe_index = true; /* * Create a memory context that will survive forced transaction commits we @@ -3324,6 +3355,23 @@ ReindexRelationConcurrently(Oid relationOid, int options) */ newIndexRel = index_open(newIndexId, ShareUpdateExclusiveLock); + /* + * When doing concurrent reindex, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX + * CONCURRENTLY to ignore us when waiting for concurrent snapshots. + * That can only be done for indexes that don't execute any + * expressions. Determine that for all involved indexes together. (The + * flag is reset automatically at transaction end, so it must be set + * for each transaction.) + */ + if (safe_index) + { + IndexInfo *newIndexInfo = BuildIndexInfo(newIndexRel); + + safe_index = newIndexInfo->ii_Expressions == NIL && + newIndexInfo->ii_Predicate == NIL; + } + /* * Save the list of OIDs and locks in private context */ @@ -3393,6 +3441,10 @@ ReindexRelationConcurrently(Oid relationOid, int options) CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + set_safe_index_flag(); + /* * Phase 2 of REINDEX CONCURRENTLY * @@ -3456,6 +3508,10 @@ ReindexRelationConcurrently(Oid relationOid, int options) } StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + set_safe_index_flag(); + /* * Phase 3 of REINDEX CONCURRENTLY * @@ -3559,6 +3615,10 @@ ReindexRelationConcurrently(Oid relationOid, int options) StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + set_safe_index_flag(); + forboth(lc, indexIds, lc2, newIndexIds) { char *oldName; @@ -3609,6 +3669,10 @@ ReindexRelationConcurrently(Oid relationOid, int options) CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + set_safe_index_flag(); + /* * Phase 5 of REINDEX CONCURRENTLY * @@ -3641,6 +3705,10 @@ ReindexRelationConcurrently(Oid relationOid, int options) CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + set_safe_index_flag(); + /* * Phase 6 of REINDEX CONCURRENTLY * @@ -3692,6 +3760,10 @@ ReindexRelationConcurrently(Oid relationOid, int options) /* Start a new transaction to finish process properly */ StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + set_safe_index_flag(); + /* Log what we did */ if (options & REINDEXOPT_VERBOSE) { @@ -3896,3 +3968,17 @@ update_relispartition(Oid relationId, bool newval) heap_freetuple(tup); table_close(classRel, RowExclusiveLock); } + +/* + * Set a PGPROC flag to tell concurrent VACUUM, CREATE INDEX CONCURRENTLY and + * REINDEX CONCURRENTLY to ignore us when waiting for concurrent snapshots. + * Should be called just after starting a transaction. + */ +static void +set_safe_index_flag() +{ + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->statusFlags |= PROC_IN_SAFE_IC; + ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags; + LWLockRelease(ProcArrayLock); +} diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 63aea0e253..6664803e2a 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_IC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_IC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.21.0 --52xkrdy5w45ewuyh-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v5] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 85 +++++++++++++++++++++++++++++--- src/include/storage/proc.h | 6 ++- 2 files changed, 83 insertions(+), 8 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 35696f9f75..44ea84c54d 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -68,6 +68,7 @@ /* non-export function prototypes */ +static bool CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts); static void CheckPredicate(Expr *predicate); static void ComputeIndexAttrs(IndexInfo *indexInfo, Oid *typeOidP, @@ -87,13 +88,12 @@ static char *ChooseIndexNameAddition(List *colnames); static List *ChooseIndexColumnNames(List *indexElems); static void RangeVarCallbackForReindexIndex(const RangeVar *relation, Oid relId, Oid oldRelId, void *arg); -static bool ReindexRelationConcurrently(Oid relationOid, int options); - +static void reindex_error_callback(void *args); static void ReindexPartitions(Oid relid, int options, bool isTopLevel); static void ReindexMultipleInternal(List *relids, int options); -static void reindex_error_callback(void *args); +static bool ReindexRelationConcurrently(Oid relationOid, int options); static void update_relispartition(Oid relationId, bool newval); -static bool CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts); +static inline void set_safe_index_flag(void); /* * callback argument type for RangeVarCallbackForReindexIndex() @@ -385,7 +385,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -406,7 +409,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_IC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -426,7 +430,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_IC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -519,6 +524,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1045,6 +1051,10 @@ DefineIndex(Oid relationId, } } + /* Determine whether we can call set_safe_index_flag */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1431,6 +1441,10 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + set_safe_index_flag(); + /* * The index is now visible, so we can report the OID. */ @@ -1490,6 +1504,10 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + set_safe_index_flag(); + /* * Phase 3 of concurrent index build * @@ -1546,6 +1564,10 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + set_safe_index_flag(); + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); @@ -3021,6 +3043,7 @@ ReindexRelationConcurrently(Oid relationOid, int options) PROGRESS_CREATEIDX_ACCESS_METHOD_OID }; int64 progress_vals[4]; + bool all_indexes_safe = true; /* * Create a memory context that will survive forced transaction commits we @@ -3325,6 +3348,12 @@ ReindexRelationConcurrently(Oid relationOid, int options) */ newIndexRel = index_open(newIndexId, ShareUpdateExclusiveLock); + /* consider safety of this index for set_safe_index_flag */ + if (all_indexes_safe && + (newIndexRel->rd_indexprs != NIL || + newIndexRel->rd_indpred != NIL)) + all_indexes_safe = false; + /* * Save the list of OIDs and locks in private context */ @@ -3394,6 +3423,10 @@ ReindexRelationConcurrently(Oid relationOid, int options) CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (all_indexes_safe) + set_safe_index_flag(); + /* * Phase 2 of REINDEX CONCURRENTLY * @@ -3457,6 +3490,10 @@ ReindexRelationConcurrently(Oid relationOid, int options) } StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (all_indexes_safe) + set_safe_index_flag(); + /* * Phase 3 of REINDEX CONCURRENTLY * @@ -3610,6 +3647,10 @@ ReindexRelationConcurrently(Oid relationOid, int options) CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (all_indexes_safe) + set_safe_index_flag(); + /* * Phase 5 of REINDEX CONCURRENTLY * @@ -3642,6 +3683,10 @@ ReindexRelationConcurrently(Oid relationOid, int options) CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (all_indexes_safe) + set_safe_index_flag(); + /* * Phase 6 of REINDEX CONCURRENTLY * @@ -3897,3 +3942,29 @@ update_relispartition(Oid relationId, bool newval) heap_freetuple(tup); table_close(classRel, RowExclusiveLock); } + +/* + * Set the PROC_IN_SAFE_IC flag in my PGPROC entry. + * + * When doing concurrent index builds, we can set this flag + * to tell other processes concurrently running VACUUM, CREATE + * INDEX CONCURRENTLY and REINDEX CONCURRENTLY to ignore us when + * doing their waits for concurrent snapshots. On one hand it + * avoids pointlessly waiting for a process that's not interesting + * anyway, but more importantly it avoids deadlocks in some cases. + * + * This can only be done for indexes that don't execute any expressions. + * Caller is responsible for only calling this routine when that + * assumption holds true. + * + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ +static inline void +set_safe_index_flag(void) +{ + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->statusFlags |= PROC_IN_SAFE_IC; + ProcGlobal->statusFlags[MyProc->pgxactoff] = MyProc->statusFlags; + LWLockRelease(ProcArrayLock); +} diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 1067f58f51..b2347ffd79 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_IC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_IC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --rwEMma7ioTxnRzrJ-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits @ 2020-08-05 02:04 Alvaro Herrera <[email protected]> 0 siblings, 0 replies; 25+ messages in thread From: Alvaro Herrera @ 2020-08-05 02:04 UTC (permalink / raw) --- src/backend/commands/indexcmds.c | 50 ++++++++++++++++++++++++++++++-- src/include/storage/proc.h | 6 +++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 254dbcdce5..459f6fa5db 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -372,7 +372,10 @@ CompareOpclassOptions(Datum *opts1, Datum *opts2, int natts) * lazy VACUUMs, because they won't be fazed by missing index entries * either. (Manual ANALYZEs, however, can't be excluded because they * might be within transactions that are going to do arbitrary operations - * later.) + * later.) Processes running CREATE INDEX CONCURRENTLY or REINDEX CONCURRENTLY + * on indexes that are neither expressional nor partial are also safe to + * ignore, since we know that those processes won't examine any data + * outside the table they're indexing. * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. @@ -393,7 +396,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) VirtualTransactionId *old_snapshots; old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_old_snapshots); if (progress) pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, n_old_snapshots); @@ -413,7 +417,8 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress) newer_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM + | PROC_IN_SAFE_CIC, &n_newer_snapshots); for (j = i; j < n_old_snapshots; j++) { @@ -506,6 +511,7 @@ DefineIndex(Oid relationId, bool amcanorder; amoptions_function amoptions; bool partitioned; + bool safe_index; Datum reloptions; int16 *coloptions; IndexInfo *indexInfo; @@ -1033,6 +1039,17 @@ DefineIndex(Oid relationId, } } + /* + * When doing concurrent index builds, we can set a PGPROC flag to tell + * concurrent VACUUM, CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY + * to ignore us when waiting for concurrent snapshots. That can only be + * done for indexes that don't execute any expressions. Determine that. + * (The flag is reset automatically at transaction end, so it must be + * set for each transaction.) + */ + safe_index = indexInfo->ii_Expressions == NIL && + indexInfo->ii_Predicate == NIL; + /* * Report index creation if appropriate (delay this till after most of the * error checks) @@ -1419,6 +1436,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * The index is now visible, so we can report the OID. */ @@ -1478,6 +1504,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* * Phase 3 of concurrent index build * @@ -1534,6 +1569,15 @@ DefineIndex(Oid relationId, CommitTransactionCommand(); StartTransactionCommand(); + /* Tell concurrent index builds to ignore us, if index qualifies */ + if (safe_index) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + MyProc->vacuumFlags |= PROC_IN_SAFE_CIC; + ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags; + LWLockRelease(ProcArrayLock); + } + /* We should now definitely not be advertising any xmin. */ Assert(MyProc->xmin == InvalidTransactionId); diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 9c9a50ae45..d91e199a60 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -53,13 +53,17 @@ struct XidCache */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ +#define PROC_IN_SAFE_CIC 0x04 /* currently running CREATE INDEX + * CONCURRENTLY or REINDEX + * CONCURRENTLY on non-expressional, + * non-partial index */ #define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */ #define PROC_IN_LOGICAL_DECODING 0x10 /* currently doing logical * decoding outside xact */ /* flags reset at EOXact */ #define PROC_VACUUM_STATE_MASK \ - (PROC_IN_VACUUM | PROC_VACUUM_FOR_WRAPAROUND) + (PROC_IN_VACUUM | PROC_IN_SAFE_CIC | PROC_VACUUM_FOR_WRAPAROUND) /* * We allow a small number of "weak" relation locks (AccessShareLock, -- 2.20.1 --nFreZHaLTZJo0R7j-- ^ permalink raw reply [nested|flat] 25+ messages in thread
* Re: Extension Enhancement: Buffer Invalidation in pg_buffercache @ 2023-07-03 08:26 Palak Chaturvedi <[email protected]> 0 siblings, 2 replies; 25+ messages in thread From: Palak Chaturvedi @ 2023-07-03 08:26 UTC (permalink / raw) To: Thomas Munro <[email protected]>; pgsql-hackers Hi Thomas, Thank you for your suggestions. I have added the sql in the meson build as well. On Sat, 1 Jul 2023 at 03:39, Thomas Munro <[email protected]> wrote: > > On Fri, Jun 30, 2023 at 10:47 PM Palak Chaturvedi > <[email protected]> wrote: > > pgbench=# select count(pg_buffercache_invalidate(bufferid)) from > > pg_buffercache where relfilenode = > > pg_relation_filenode('pgbench_accounts'::regclass); > > Hi Palak, > > Thanks for working on this! I think this will be very useful for > testing existing workloads but also for testing future work on > prefetching with AIO (and DIO), work on putting SLRUs (or anything > else) into the buffer pool, nearby proposals for caching buffer > mapping information, etc etc. > > Palak and I talked about this idea a bit last week (stimulated by a > recent thread[1], but the topic has certainly come up before), and we > discussed some different ways one could specify which pages are > dropped. For example, perhaps the pg_prewarm extension could have an > 'unwarm' option instead. I personally thought the buffer ID-based > approach was quite good because it's extremely simple, while giving > the user the full power of SQL to say which buffers. Half a table? > Visibility map? Everything? Root page of an index? I think that's > probably better than something that requires more code and > complication but is less flexible in the end. It feels like the right > level of rawness for something primarily of interest to hackers and > advanced users. I don't think it matters that there is a window > between selecting a buffer ID and invalidating it, for the intended > use cases. That's my vote, anyway, let's see if others have other > ideas... > > We also talked a bit about how one might control the kernel page cache > in more fine-grained ways for testing purposes, but it seems like the > pgfincore project has that covered with its pgfadvise_willneed() and > pgfadvise_dontneed(). IMHO that project could use more page-oriented > operations (instead of just counts and coarse grains operations) but > that's something that could be material for patches to send to the > extension maintainers. This work, in contrast, is more tangled up > with bufmgr.c internals, so it feels like this feature belongs in a > core contrib module. > > Some initial thoughts on the patch: > > I wonder if we should include a simple exercise in > contrib/pg_buffercache/sql/pg_buffercache.sql. One problem is that > it's not guaranteed to succeed in general. It doesn't wait for pins > to go away, and it doesn't retry cleaning dirty buffers after one > attempt, it just returns false, which I think is probably the right > approach, but it makes the behaviour too non-deterministic for simple > tests. Perhaps it's enough to include an exercise where we call it a > few times to hit a couple of cases, but not verify what effect it has. > > It should be restricted by role, but I wonder which role it should be. > Testing for superuser is now out of fashion. > > Where the Makefile mentions 1.4--1.5.sql, the meson.build file needs > to do the same. That's because PostgreSQL is currently in transition > from autoconf/gmake to meson/ninja[2], so for now we have to maintain > both build systems. That's why it fails to build in some CI tasks[3]. > You can enable CI in your own GitHub account if you want to run test > builds on several operating systems, see [4] for info. > > [1] https://www.postgresql.org/message-id/flat/CAFSGpE3y_oMK1uHhcHxGxBxs%2BKrjMMdGrE%2B6HHOu0vttVET0UQ%4... > [2] https://wiki.postgresql.org/wiki/Meson > [3] http://cfbot.cputube.org/palak-chaturvedi.html > [4] https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob_plain;f=src/tools/ci/README;hb=HEAD Attachments: [application/octet-stream] v1-0001-Invalidate-Buffer-By-Bufnum.patch (5.9K, ../../CALfch1_cu_uurBGVG+GO_AtyyYxnuLU5GWf0ahHMre_HDqGDyw@mail.gmail.com/2-v1-0001-Invalidate-Buffer-By-Bufnum.patch) download | inline diff: From 02ea352d84ed87e156617de8b8020811680cb412 Mon Sep 17 00:00:00 2001 From: Palak <[email protected]> Date: Fri, 30 Jun 2023 08:21:06 +0000 Subject: [PATCH v1] Invalidate Buffer By Bufnum --- contrib/pg_buffercache/Makefile | 2 +- contrib/pg_buffercache/meson.build | 1 + .../pg_buffercache--1.4--1.5.sql | 6 ++ contrib/pg_buffercache/pg_buffercache.control | 2 +- contrib/pg_buffercache/pg_buffercache_pages.c | 27 ++++++++ src/backend/storage/buffer/bufmgr.c | 64 +++++++++++++++++++ src/include/storage/bufmgr.h | 3 + 7 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 contrib/pg_buffercache/pg_buffercache--1.4--1.5.sql diff --git a/contrib/pg_buffercache/Makefile b/contrib/pg_buffercache/Makefile index d6b58d4da9..eae65ead9e 100644 --- a/contrib/pg_buffercache/Makefile +++ b/contrib/pg_buffercache/Makefile @@ -8,7 +8,7 @@ OBJS = \ EXTENSION = pg_buffercache DATA = pg_buffercache--1.2.sql pg_buffercache--1.2--1.3.sql \ pg_buffercache--1.1--1.2.sql pg_buffercache--1.0--1.1.sql \ - pg_buffercache--1.3--1.4.sql + pg_buffercache--1.3--1.4.sql pg_buffercache--1.4--1.5.sql PGFILEDESC = "pg_buffercache - monitoring of shared buffer cache in real-time" REGRESS = pg_buffercache diff --git a/contrib/pg_buffercache/meson.build b/contrib/pg_buffercache/meson.build index c51edf37d1..748463bc19 100644 --- a/contrib/pg_buffercache/meson.build +++ b/contrib/pg_buffercache/meson.build @@ -22,6 +22,7 @@ install_data( 'pg_buffercache--1.2--1.3.sql', 'pg_buffercache--1.2.sql', 'pg_buffercache--1.3--1.4.sql', + 'pg_buffercache--1.4--1.5.sql', 'pg_buffercache.control', kwargs: contrib_data_args, ) diff --git a/contrib/pg_buffercache/pg_buffercache--1.4--1.5.sql b/contrib/pg_buffercache/pg_buffercache--1.4--1.5.sql new file mode 100644 index 0000000000..c7e47456d7 --- /dev/null +++ b/contrib/pg_buffercache/pg_buffercache--1.4--1.5.sql @@ -0,0 +1,6 @@ +\echo Use "ALTER EXTENSION pg_buffercache UPDATE TO '1.5'" to load this file. \quit + +CREATE FUNCTION pg_buffercache_invalidate(IN int) +RETURNS bool +AS 'MODULE_PATHNAME', 'pg_buffercache_invalidate' +LANGUAGE C PARALLEL SAFE; diff --git a/contrib/pg_buffercache/pg_buffercache.control b/contrib/pg_buffercache/pg_buffercache.control index a82ae5f9bb..5ee875f77d 100644 --- a/contrib/pg_buffercache/pg_buffercache.control +++ b/contrib/pg_buffercache/pg_buffercache.control @@ -1,5 +1,5 @@ # pg_buffercache extension comment = 'examine the shared buffer cache' -default_version = '1.4' +default_version = '1.5' module_pathname = '$libdir/pg_buffercache' relocatable = true diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c index 3316732365..6dd02fe6af 100644 --- a/contrib/pg_buffercache/pg_buffercache_pages.c +++ b/contrib/pg_buffercache/pg_buffercache_pages.c @@ -64,6 +64,33 @@ PG_FUNCTION_INFO_V1(pg_buffercache_pages); PG_FUNCTION_INFO_V1(pg_buffercache_summary); PG_FUNCTION_INFO_V1(pg_buffercache_usage_counts); +PG_FUNCTION_INFO_V1(pg_buffercache_invalidate); +Datum +pg_buffercache_invalidate(PG_FUNCTION_ARGS) +{ + Buffer bufnum; + bool result; + + if (PG_ARGISNULL(0)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("buffernum cannot be NULL"))); + } + + bufnum = PG_GETARG_INT32(0); + if (bufnum < 0 || bufnum > NBuffers) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("buffernum is not valid"))); + + } + + result = TryInvalidateBuffer(bufnum); + PG_RETURN_BOOL(result); +} + Datum pg_buffercache_pages(PG_FUNCTION_ARGS) { diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 3c59bbd04e..376afcf996 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -5592,3 +5592,67 @@ TestForOldSnapshot_impl(Snapshot snapshot, Relation relation) (errcode(ERRCODE_SNAPSHOT_TOO_OLD), errmsg("snapshot too old"))); } + +/* +Try Invalidating a buffer using bufnum. +If the buffer is invalid, the function returns false. +The function checks for dirty buffer and flushes the dirty buffer before invalidating. +If the buffer is still dirty it returns false. +*/ +bool +TryInvalidateBuffer(Buffer bufnum) +{ + BufferDesc *bufHdr = GetBufferDescriptor(bufnum - 1); + uint32 buf_state; + + ReservePrivateRefCountEntry(); + + buf_state = LockBufHdr(bufHdr); + if ((buf_state & BM_VALID) == BM_VALID) + { + /* + * The buffer is pinned therefore cannot invalidate. + */ + if (BUF_STATE_GET_REFCOUNT(buf_state) > 0) + { + UnlockBufHdr(bufHdr, buf_state); + return false; + } + if ((buf_state & BM_DIRTY) == BM_DIRTY) + { + /* + * Try once to flush the dirty buffer. + */ + PinBuffer_Locked(bufHdr); + LWLockAcquire(BufferDescriptorGetContentLock(bufHdr), LW_SHARED); + FlushBuffer(bufHdr, NULL, IOOBJECT_RELATION, IOCONTEXT_NORMAL); + LWLockRelease(BufferDescriptorGetContentLock(bufHdr)); + UnpinBuffer(bufHdr); + buf_state = LockBufHdr(bufHdr); + if (BUF_STATE_GET_REFCOUNT(buf_state) > 0) + { + UnlockBufHdr(bufHdr, buf_state); + return false; + } + + /* + * If its dirty again or not valid anymore give up. + */ + + if ((buf_state & (BM_DIRTY | BM_VALID)) != (BM_VALID)) + { + UnlockBufHdr(bufHdr, buf_state); + return false; + } + + } + + InvalidateBuffer(bufHdr); + return true; + } + else + { + UnlockBufHdr(bufHdr, buf_state); + return false; + } +} diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index 0f5fb6be00..4ba3d9089b 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -252,6 +252,9 @@ extern bool BgBufferSync(struct WritebackContext *wb_context); extern void TestForOldSnapshot_impl(Snapshot snapshot, Relation relation); + +extern bool TryInvalidateBuffer(Buffer bufnum); + /* in buf_init.c */ extern void InitBufferPool(void); extern Size BufferShmemSize(void); -- 2.25.1 ^ permalink raw reply [nested|flat] 25+ messages in thread
* Re: Extension Enhancement: Buffer Invalidation in pg_buffercache @ 2023-07-04 08:50 Japin Li <[email protected]> parent: Palak Chaturvedi <[email protected]> 1 sibling, 0 replies; 25+ messages in thread From: Japin Li @ 2023-07-04 08:50 UTC (permalink / raw) To: Palak Chaturvedi <[email protected]>; +Cc: Thomas Munro <[email protected]>; pgsql-hackers; [email protected] On Mon, 03 Jul 2023 at 16:26, Palak Chaturvedi <[email protected]> wrote: > Hi Thomas, > Thank you for your suggestions. I have added the sql in the meson > build as well. > > On Sat, 1 Jul 2023 at 03:39, Thomas Munro <[email protected]> wrote: >> >> On Fri, Jun 30, 2023 at 10:47 PM Palak Chaturvedi >> <[email protected]> wrote: >> > pgbench=# select count(pg_buffercache_invalidate(bufferid)) from >> > pg_buffercache where relfilenode = >> > pg_relation_filenode('pgbench_accounts'::regclass); >> >> Hi Palak, >> >> Thanks for working on this! I think this will be very useful for >> testing existing workloads but also for testing future work on >> prefetching with AIO (and DIO), work on putting SLRUs (or anything >> else) into the buffer pool, nearby proposals for caching buffer >> mapping information, etc etc. >> >> Palak and I talked about this idea a bit last week (stimulated by a >> recent thread[1], but the topic has certainly come up before), and we >> discussed some different ways one could specify which pages are >> dropped. For example, perhaps the pg_prewarm extension could have an >> 'unwarm' option instead. I personally thought the buffer ID-based >> approach was quite good because it's extremely simple, while giving >> the user the full power of SQL to say which buffers. Half a table? >> Visibility map? Everything? Root page of an index? I think that's >> probably better than something that requires more code and >> complication but is less flexible in the end. It feels like the right >> level of rawness for something primarily of interest to hackers and >> advanced users. I don't think it matters that there is a window >> between selecting a buffer ID and invalidating it, for the intended >> use cases. That's my vote, anyway, let's see if others have other >> ideas... >> >> We also talked a bit about how one might control the kernel page cache >> in more fine-grained ways for testing purposes, but it seems like the >> pgfincore project has that covered with its pgfadvise_willneed() and >> pgfadvise_dontneed(). IMHO that project could use more page-oriented >> operations (instead of just counts and coarse grains operations) but >> that's something that could be material for patches to send to the >> extension maintainers. This work, in contrast, is more tangled up >> with bufmgr.c internals, so it feels like this feature belongs in a >> core contrib module. >> >> Some initial thoughts on the patch: >> >> I wonder if we should include a simple exercise in >> contrib/pg_buffercache/sql/pg_buffercache.sql. One problem is that >> it's not guaranteed to succeed in general. It doesn't wait for pins >> to go away, and it doesn't retry cleaning dirty buffers after one >> attempt, it just returns false, which I think is probably the right >> approach, but it makes the behaviour too non-deterministic for simple >> tests. Perhaps it's enough to include an exercise where we call it a >> few times to hit a couple of cases, but not verify what effect it has. >> >> It should be restricted by role, but I wonder which role it should be. >> Testing for superuser is now out of fashion. >> >> Where the Makefile mentions 1.4--1.5.sql, the meson.build file needs >> to do the same. That's because PostgreSQL is currently in transition >> from autoconf/gmake to meson/ninja[2], so for now we have to maintain >> both build systems. That's why it fails to build in some CI tasks[3]. >> You can enable CI in your own GitHub account if you want to run test >> builds on several operating systems, see [4] for info. >> >> [1] https://www.postgresql.org/message-id/flat/CAFSGpE3y_oMK1uHhcHxGxBxs%2BKrjMMdGrE%2B6HHOu0vttVET0UQ%4... >> [2] https://wiki.postgresql.org/wiki/Meson >> [3] http://cfbot.cputube.org/palak-chaturvedi.html >> [4] https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob_plain;f=src/tools/ci/README;hb=HEAD I think, zero is not a valid buffer identifier. See src/include/storage/buf.h. + bufnum = PG_GETARG_INT32(0); + if (bufnum < 0 || bufnum > NBuffers) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("buffernum is not valid"))); + + } If we use SELECT pg_buffercache_invalidate(0), it will crash. -- Regrads, Japin Li. ^ permalink raw reply [nested|flat] 25+ messages in thread
* Re: Extension Enhancement: Buffer Invalidation in pg_buffercache @ 2023-07-19 00:45 Andres Freund <[email protected]> parent: Palak Chaturvedi <[email protected]> 1 sibling, 0 replies; 25+ messages in thread From: Andres Freund @ 2023-07-19 00:45 UTC (permalink / raw) To: Palak Chaturvedi <[email protected]>; +Cc: Thomas Munro <[email protected]>; pgsql-hackers Hi, I wanted this feature a couple times before... On 2023-07-03 13:56:29 +0530, Palak Chaturvedi wrote: > +PG_FUNCTION_INFO_V1(pg_buffercache_invalidate); > +Datum > +pg_buffercache_invalidate(PG_FUNCTION_ARGS) I don't think "invalidating" is the right terminology. Note that we already have InvalidateBuffer() - but it's something we can't allow users to do, as it throws away dirty buffer contents (it's used for things like dropping a table). How about using "discarding" for this functionality? Using the buffer ID as the identifier doesn't seem great, because what that buffer is used for, could have changed since the buffer ID has been acquired (via the pg_buffercache view presumably)? My suspicion is that the usual usecase for this would be to drop all buffers that can be dropped? > + if (bufnum < 0 || bufnum > NBuffers) > + { > + ereport(ERROR, > + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), > + errmsg("buffernum is not valid"))); > + > + } > + > + result = TryInvalidateBuffer(bufnum); > + PG_RETURN_BOOL(result); > +} I think this should be restricted to superuser by default (by revoking permissions from PUBLIC). We allow normal users to use pg_prewarm(...), true - but we perform an ACL check on the relation, so it can only be used for relations you have access too. This function could be used to affect performance of other users quite substantially. > +/* > +Try Invalidating a buffer using bufnum. > +If the buffer is invalid, the function returns false. > +The function checks for dirty buffer and flushes the dirty buffer before invalidating. > +If the buffer is still dirty it returns false. > +*/ > +bool > +TryInvalidateBuffer(Buffer bufnum) > +{ > + BufferDesc *bufHdr = GetBufferDescriptor(bufnum - 1); > + uint32 buf_state; > + > + ReservePrivateRefCountEntry(); > + > + buf_state = LockBufHdr(bufHdr); > + if ((buf_state & BM_VALID) == BM_VALID) > + { > + /* > + * The buffer is pinned therefore cannot invalidate. > + */ > + if (BUF_STATE_GET_REFCOUNT(buf_state) > 0) > + { > + UnlockBufHdr(bufHdr, buf_state); > + return false; > + } > + if ((buf_state & BM_DIRTY) == BM_DIRTY) > + { > + /* > + * Try once to flush the dirty buffer. > + */ > + PinBuffer_Locked(bufHdr); > + LWLockAcquire(BufferDescriptorGetContentLock(bufHdr), LW_SHARED); > + FlushBuffer(bufHdr, NULL, IOOBJECT_RELATION, IOCONTEXT_NORMAL); > + LWLockRelease(BufferDescriptorGetContentLock(bufHdr)); > + UnpinBuffer(bufHdr); > + buf_state = LockBufHdr(bufHdr); > + if (BUF_STATE_GET_REFCOUNT(buf_state) > 0) > + { > + UnlockBufHdr(bufHdr, buf_state); > + return false; > + } > + > + /* > + * If its dirty again or not valid anymore give up. > + */ > + > + if ((buf_state & (BM_DIRTY | BM_VALID)) != (BM_VALID)) > + { > + UnlockBufHdr(bufHdr, buf_state); > + return false; > + } > + > + } > + > + InvalidateBuffer(bufHdr); I'm wary of using InvalidateBuffer() here, it's typically used for different purposes, including throwing valid contents away. That seems a bit scary. I think you should be able to just use InvalidateVictimBuffer()? Greetings, Andres Freund ^ permalink raw reply [nested|flat] 25+ messages in thread
end of thread, other threads:[~2023-07-19 00:45 UTC | newest] Thread overview: 25+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v5] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v3] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v4 2/2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2020-08-05 02:04 [PATCH v2] Avoid spurious CREATE INDEX CONCURRENTLY waits Alvaro Herrera <[email protected]> 2023-07-03 08:26 Re: Extension Enhancement: Buffer Invalidation in pg_buffercache Palak Chaturvedi <[email protected]> 2023-07-04 08:50 ` Re: Extension Enhancement: Buffer Invalidation in pg_buffercache Japin Li <[email protected]> 2023-07-19 00:45 ` Re: Extension Enhancement: Buffer Invalidation in pg_buffercache Andres Freund <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox