diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index bb60b23093..d8644ace22 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -3159,9 +3159,6 @@ index_set_state_flags(Oid indexId, IndexStateFlagsAction action) HeapTuple indexTuple; Form_pg_index indexForm; - /* Assert that current xact hasn't done any transactional updates */ - Assert(GetTopTransactionIdIfAny() == InvalidTransactionId); - /* Open pg_index and fetch a writable copy of the index's tuple */ pg_index = table_open(IndexRelationId, RowExclusiveLock); @@ -3181,12 +3178,13 @@ index_set_state_flags(Oid indexId, IndexStateFlagsAction action) Assert(!indexForm->indisvalid); indexForm->indisready = true; break; - case INDEX_CREATE_SET_VALID: + case INDEX_CREATE_SET_VALID_INDCHECKXMIN: /* Set indisvalid during a CREATE INDEX CONCURRENTLY sequence */ Assert(indexForm->indislive); Assert(indexForm->indisready); Assert(!indexForm->indisvalid); indexForm->indisvalid = true; + indexForm->indcheckxmin = true; break; case INDEX_DROP_CLEAR_VALID: @@ -3220,9 +3218,10 @@ index_set_state_flags(Oid indexId, IndexStateFlagsAction action) break; } - /* ... and write it back in-place */ - heap_inplace_update(pg_index, indexTuple); + /* ... and update the heap tuple now */ + CatalogTupleUpdate(pg_index, &indexTuple->t_self, indexTuple); + heap_freetuple(indexTuple); table_close(pg_index, RowExclusiveLock); } diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 579b998954..652e3f1947 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -471,7 +471,6 @@ DefineIndex(Oid relationId, bits16 constr_flags; int numberOfAttributes; int numberOfKeyAttributes; - TransactionId limitXmin; ObjectAddress address; LockRelId heaprelid; LOCKTAG heaplocktag; @@ -1414,10 +1413,8 @@ DefineIndex(Oid relationId, * Drop the reference snapshot. We must do this before waiting out other * snapshot holders, else we will deadlock against other processes also * doing CREATE INDEX CONCURRENTLY, which would see our snapshot as one - * they must wait for. But first, save the snapshot's xmin to use as - * limitXmin for GetCurrentVirtualXIDs(). + * they must wait for. */ - limitXmin = snapshot->xmin; PopActiveSnapshot(); UnregisterSnapshot(snapshot); @@ -1436,20 +1433,19 @@ DefineIndex(Oid relationId, /* We should now definitely not be advertising any xmin. */ Assert(MyPgXact->xmin == InvalidTransactionId); - /* - * The index is now valid in the sense that it contains all currently - * interesting tuples. But since it might not contain tuples deleted just - * before the reference snap was taken, we have to wait out any - * transactions that might have older snapshots. - */ - pgstat_progress_update_param(PROGRESS_CREATEIDX_PHASE, +pgstat_progress_update_param(PROGRESS_CREATEIDX_PHASE, PROGRESS_CREATEIDX_PHASE_WAIT_3); - WaitForOlderSnapshots(limitXmin, true); /* + * The index is now valid in the sense that it contains all currently + * interesting tuples. But it might not contain tuples deleted just + * before the reference snap was taken. Instead of waiting out any + * transactions that might have older snapshots, we mark indcheckxmin + * to true so that the index can only be used for newer snapshots. + * * Index can now be marked valid -- update its pg_index entry */ - index_set_state_flags(indexRelationId, INDEX_CREATE_SET_VALID); + index_set_state_flags(indexRelationId, INDEX_CREATE_SET_VALID_INDCHECKXMIN); /* * The pg_index update will cause backends (including this one) to update diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index 1113d25b2d..c4717e7aca 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -24,7 +24,7 @@ typedef enum { INDEX_CREATE_SET_READY, - INDEX_CREATE_SET_VALID, + INDEX_CREATE_SET_VALID_INDCHECKXMIN, INDEX_DROP_CLEAR_VALID, INDEX_DROP_SET_DEAD } IndexStateFlagsAction; diff --git a/src/test/isolation/expected/multiple-cic-2.out b/src/test/isolation/expected/multiple-cic-2.out new file mode 100644 index 0000000000..d7c2e8df6e --- /dev/null +++ b/src/test/isolation/expected/multiple-cic-2.out @@ -0,0 +1,77 @@ +Parsed test spec with 2 sessions + +starting permutation: s1l s2l s1i s1ul s2i +step s1l: SELECT pg_advisory_lock(281458); +pg_advisory_lock + + +step s2l: SELECT pg_advisory_lock(281458); +step s1i: + CREATE INDEX CONCURRENTLY mcic_one_pkey ON mcic_one (id) + +step s1ul: SELECT pg_advisory_unlock_all(); +pg_advisory_unlock_all + + +step s2l: <... completed> +pg_advisory_lock + + +step s2i: + CREATE INDEX CONCURRENTLY mcic_one_pkey2 ON mcic_one (id) + +pg_advisory_unlock_all + + +pg_advisory_unlock_all + + + +starting permutation: s1l s1i s2l s1ul s2i +step s1l: SELECT pg_advisory_lock(281458); +pg_advisory_lock + + +step s1i: + CREATE INDEX CONCURRENTLY mcic_one_pkey ON mcic_one (id) + +step s2l: SELECT pg_advisory_lock(281458); +step s1ul: SELECT pg_advisory_unlock_all(); +pg_advisory_unlock_all + + +step s2l: <... completed> +pg_advisory_lock + + +step s2i: + CREATE INDEX CONCURRENTLY mcic_one_pkey2 ON mcic_one (id) + +pg_advisory_unlock_all + + +pg_advisory_unlock_all + + + +starting permutation: s1l s2i s1i s1ul +step s1l: SELECT pg_advisory_lock(281458); +pg_advisory_lock + + +step s2i: + CREATE INDEX CONCURRENTLY mcic_one_pkey2 ON mcic_one (id) + +step s1i: + CREATE INDEX CONCURRENTLY mcic_one_pkey ON mcic_one (id) + +step s1ul: SELECT pg_advisory_unlock_all(); +pg_advisory_unlock_all + + +pg_advisory_unlock_all + + +pg_advisory_unlock_all + + diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule index 74b50779e2..c3870a189e 100644 --- a/src/test/isolation/isolation_schedule +++ b/src/test/isolation/isolation_schedule @@ -62,6 +62,7 @@ test: skip-locked-3 test: skip-locked-4 test: drop-index-concurrently-1 test: multiple-cic +test: multiple-cic-2 test: alter-table-1 test: alter-table-2 test: alter-table-3 diff --git a/src/test/isolation/specs/multiple-cic-2.spec b/src/test/isolation/specs/multiple-cic-2.spec new file mode 100644 index 0000000000..b86db39694 --- /dev/null +++ b/src/test/isolation/specs/multiple-cic-2.spec @@ -0,0 +1,33 @@ +# Test multiple CREATE INDEX CONCURRENTLY working simultaneously + +setup +{ + CREATE TABLE mcic_one ( + id int + ); +} +teardown +{ + DROP TABLE mcic_one; +} + +session "s1" +step "s1l" { SELECT pg_advisory_lock(281458); } +step "s1i" { + CREATE INDEX CONCURRENTLY mcic_one_pkey ON mcic_one (id) + } +step "s1ul" { SELECT pg_advisory_unlock_all(); } +teardown { SELECT pg_advisory_unlock_all(); } + + +session "s2" +step "s2l" { SELECT pg_advisory_lock(281458); } +step "s2i" { + CREATE INDEX CONCURRENTLY mcic_one_pkey2 ON mcic_one (id) + } +teardown { SELECT pg_advisory_unlock_all(); } + + +permutation "s1l" "s2l" "s1i" "s1ul" "s2i" +permutation "s1l" "s1i" "s2l" "s1ul" "s2i" +permutation "s1l" "s2i" "s1i" "s1ul"