8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.333 2010/02/07 20:48:09 tgl Exp $
11
+ * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.334 2010/02/07 22:40:33 tgl Exp $
12
12
*
13
13
*
14
14
* INTERFACE ROUTINES
@@ -1541,6 +1541,8 @@ IndexBuildHeapScan(Relation heapRelation,
1541
1541
IndexBuildCallback callback ,
1542
1542
void * callback_state )
1543
1543
{
1544
+ bool is_system_catalog ;
1545
+ bool checking_uniqueness ;
1544
1546
HeapScanDesc scan ;
1545
1547
HeapTuple heapTuple ;
1546
1548
Datum values [INDEX_MAX_KEYS ];
@@ -1560,6 +1562,13 @@ IndexBuildHeapScan(Relation heapRelation,
1560
1562
*/
1561
1563
Assert (OidIsValid (indexRelation -> rd_rel -> relam ));
1562
1564
1565
+ /* Remember if it's a system catalog */
1566
+ is_system_catalog = IsSystemRelation (heapRelation );
1567
+
1568
+ /* See whether we're verifying uniqueness/exclusion properties */
1569
+ checking_uniqueness = (indexInfo -> ii_Unique ||
1570
+ indexInfo -> ii_ExclusionOps != NULL );
1571
+
1563
1572
/*
1564
1573
* Need an EState for evaluation of index expressions and partial-index
1565
1574
* predicates. Also a slot to hold the current tuple.
@@ -1652,6 +1661,7 @@ IndexBuildHeapScan(Relation heapRelation,
1652
1661
{
1653
1662
/* do our own time qual check */
1654
1663
bool indexIt ;
1664
+ TransactionId xwait ;
1655
1665
1656
1666
recheck :
1657
1667
@@ -1710,29 +1720,31 @@ IndexBuildHeapScan(Relation heapRelation,
1710
1720
case HEAPTUPLE_INSERT_IN_PROGRESS :
1711
1721
1712
1722
/*
1713
- * Since caller should hold ShareLock or better, we should
1714
- * not see any tuples inserted by open transactions ---
1715
- * unless it's our own transaction. (Consider INSERT
1716
- * followed by CREATE INDEX within a transaction.) An
1717
- * exception occurs when reindexing a system catalog,
1718
- * because we often release lock on system catalogs before
1719
- * committing. In that case we wait for the inserting
1720
- * transaction to finish and check again. (We could do
1721
- * that on user tables too, but since the case is not
1722
- * expected it seems better to throw an error.)
1723
+ * Since caller should hold ShareLock or better, normally
1724
+ * the only way to see this is if it was inserted earlier
1725
+ * in our own transaction. However, it can happen in
1726
+ * system catalogs, since we tend to release write lock
1727
+ * before commit there. Give a warning if neither case
1728
+ * applies.
1723
1729
*/
1724
- if (! TransactionIdIsCurrentTransactionId (
1725
- HeapTupleHeaderGetXmin ( heapTuple -> t_data ) ))
1730
+ xwait = HeapTupleHeaderGetXmin ( heapTuple -> t_data );
1731
+ if (! TransactionIdIsCurrentTransactionId ( xwait ))
1726
1732
{
1727
- if (!IsSystemRelation (heapRelation ))
1728
- elog (ERROR , "concurrent insert in progress" );
1729
- else
1733
+ if (!is_system_catalog )
1734
+ elog (WARNING , "concurrent insert in progress within table \"%s\"" ,
1735
+ RelationGetRelationName (heapRelation ));
1736
+
1737
+ /*
1738
+ * If we are performing uniqueness checks, indexing
1739
+ * such a tuple could lead to a bogus uniqueness
1740
+ * failure. In that case we wait for the inserting
1741
+ * transaction to finish and check again.
1742
+ */
1743
+ if (checking_uniqueness )
1730
1744
{
1731
1745
/*
1732
1746
* Must drop the lock on the buffer before we wait
1733
1747
*/
1734
- TransactionId xwait = HeapTupleHeaderGetXmin (heapTuple -> t_data );
1735
-
1736
1748
LockBuffer (scan -> rs_cbuf , BUFFER_LOCK_UNLOCK );
1737
1749
XactLockTableWait (xwait );
1738
1750
goto recheck ;
@@ -1749,30 +1761,27 @@ IndexBuildHeapScan(Relation heapRelation,
1749
1761
case HEAPTUPLE_DELETE_IN_PROGRESS :
1750
1762
1751
1763
/*
1752
- * Since caller should hold ShareLock or better, we should
1753
- * not see any tuples deleted by open transactions ---
1754
- * unless it's our own transaction. (Consider DELETE
1755
- * followed by CREATE INDEX within a transaction.) An
1756
- * exception occurs when reindexing a system catalog,
1757
- * because we often release lock on system catalogs before
1758
- * committing. In that case we wait for the deleting
1759
- * transaction to finish and check again. (We could do
1760
- * that on user tables too, but since the case is not
1761
- * expected it seems better to throw an error.)
1764
+ * Similar situation to INSERT_IN_PROGRESS case.
1762
1765
*/
1763
1766
Assert (!(heapTuple -> t_data -> t_infomask & HEAP_XMAX_IS_MULTI ));
1764
- if (! TransactionIdIsCurrentTransactionId (
1765
- HeapTupleHeaderGetXmax ( heapTuple -> t_data ) ))
1767
+ xwait = HeapTupleHeaderGetXmax ( heapTuple -> t_data );
1768
+ if (! TransactionIdIsCurrentTransactionId ( xwait ))
1766
1769
{
1767
- if (!IsSystemRelation (heapRelation ))
1768
- elog (ERROR , "concurrent delete in progress" );
1769
- else
1770
+ if (!is_system_catalog )
1771
+ elog (WARNING , "concurrent delete in progress within table \"%s\"" ,
1772
+ RelationGetRelationName (heapRelation ));
1773
+
1774
+ /*
1775
+ * If we are performing uniqueness checks, assuming
1776
+ * the tuple is dead could lead to missing a uniqueness
1777
+ * violation. In that case we wait for the deleting
1778
+ * transaction to finish and check again.
1779
+ */
1780
+ if (checking_uniqueness )
1770
1781
{
1771
1782
/*
1772
1783
* Must drop the lock on the buffer before we wait
1773
1784
*/
1774
- TransactionId xwait = HeapTupleHeaderGetXmax (heapTuple -> t_data );
1775
-
1776
1785
LockBuffer (scan -> rs_cbuf , BUFFER_LOCK_UNLOCK );
1777
1786
XactLockTableWait (xwait );
1778
1787
goto recheck ;
@@ -2402,7 +2411,7 @@ IndexGetRelation(Oid indexId)
2402
2411
* reindex_index - This routine is used to recreate a single index
2403
2412
*/
2404
2413
void
2405
- reindex_index (Oid indexId )
2414
+ reindex_index (Oid indexId , bool skip_constraint_checks )
2406
2415
{
2407
2416
Relation iRel ,
2408
2417
heapRelation ,
@@ -2411,6 +2420,7 @@ reindex_index(Oid indexId)
2411
2420
IndexInfo * indexInfo ;
2412
2421
HeapTuple indexTuple ;
2413
2422
Form_pg_index indexForm ;
2423
+ volatile bool skipped_constraint = false;
2414
2424
2415
2425
/*
2416
2426
* Open and lock the parent heap relation. ShareLock is sufficient since
@@ -2448,6 +2458,17 @@ reindex_index(Oid indexId)
2448
2458
/* Fetch info needed for index_build */
2449
2459
indexInfo = BuildIndexInfo (iRel );
2450
2460
2461
+ /* If requested, skip checking uniqueness/exclusion constraints */
2462
+ if (skip_constraint_checks )
2463
+ {
2464
+ if (indexInfo -> ii_Unique || indexInfo -> ii_ExclusionOps != NULL )
2465
+ skipped_constraint = true;
2466
+ indexInfo -> ii_Unique = false;
2467
+ indexInfo -> ii_ExclusionOps = NULL ;
2468
+ indexInfo -> ii_ExclusionProcs = NULL ;
2469
+ indexInfo -> ii_ExclusionStrats = NULL ;
2470
+ }
2471
+
2451
2472
/* We'll build a new physical relation for the index */
2452
2473
RelationSetNewRelfilenode (iRel , InvalidTransactionId );
2453
2474
@@ -2466,33 +2487,38 @@ reindex_index(Oid indexId)
2466
2487
2467
2488
/*
2468
2489
* If the index is marked invalid or not ready (ie, it's from a failed
2469
- * CREATE INDEX CONCURRENTLY), we can now mark it valid. This allows
2470
- * REINDEX to be used to clean up in such cases.
2490
+ * CREATE INDEX CONCURRENTLY), and we didn't skip a uniqueness check,
2491
+ * we can now mark it valid. This allows REINDEX to be used to clean up
2492
+ * in such cases.
2471
2493
*
2472
2494
* We can also reset indcheckxmin, because we have now done a
2473
2495
* non-concurrent index build, *except* in the case where index_build
2474
2496
* found some still-broken HOT chains.
2475
2497
*/
2476
- pg_index = heap_open (IndexRelationId , RowExclusiveLock );
2498
+ if (!skipped_constraint )
2499
+ {
2500
+ pg_index = heap_open (IndexRelationId , RowExclusiveLock );
2477
2501
2478
- indexTuple = SearchSysCacheCopy (INDEXRELID ,
2479
- ObjectIdGetDatum (indexId ),
2480
- 0 , 0 , 0 );
2481
- if (!HeapTupleIsValid (indexTuple ))
2482
- elog (ERROR , "cache lookup failed for index %u" , indexId );
2483
- indexForm = (Form_pg_index ) GETSTRUCT (indexTuple );
2502
+ indexTuple = SearchSysCacheCopy (INDEXRELID ,
2503
+ ObjectIdGetDatum (indexId ),
2504
+ 0 , 0 , 0 );
2505
+ if (!HeapTupleIsValid (indexTuple ))
2506
+ elog (ERROR , "cache lookup failed for index %u" , indexId );
2507
+ indexForm = (Form_pg_index ) GETSTRUCT (indexTuple );
2484
2508
2485
- if (!indexForm -> indisvalid || !indexForm -> indisready ||
2486
- (indexForm -> indcheckxmin && !indexInfo -> ii_BrokenHotChain ))
2487
- {
2488
- indexForm -> indisvalid = true;
2489
- indexForm -> indisready = true;
2490
- if (!indexInfo -> ii_BrokenHotChain )
2491
- indexForm -> indcheckxmin = false;
2492
- simple_heap_update (pg_index , & indexTuple -> t_self , indexTuple );
2493
- CatalogUpdateIndexes (pg_index , indexTuple );
2509
+ if (!indexForm -> indisvalid || !indexForm -> indisready ||
2510
+ (indexForm -> indcheckxmin && !indexInfo -> ii_BrokenHotChain ))
2511
+ {
2512
+ indexForm -> indisvalid = true;
2513
+ indexForm -> indisready = true;
2514
+ if (!indexInfo -> ii_BrokenHotChain )
2515
+ indexForm -> indcheckxmin = false;
2516
+ simple_heap_update (pg_index , & indexTuple -> t_self , indexTuple );
2517
+ CatalogUpdateIndexes (pg_index , indexTuple );
2518
+ }
2519
+
2520
+ heap_close (pg_index , RowExclusiveLock );
2494
2521
}
2495
- heap_close (pg_index , RowExclusiveLock );
2496
2522
2497
2523
/* Close rels, but keep locks */
2498
2524
index_close (iRel , NoLock );
@@ -2513,6 +2539,11 @@ reindex_index(Oid indexId)
2513
2539
* do CCI after having collected the index list. (This way we can still use
2514
2540
* catalog indexes while collecting the list.)
2515
2541
*
2542
+ * We also skip rechecking uniqueness/exclusion constraint properties if
2543
+ * heap_rebuilt is true. This avoids likely deadlock conditions when doing
2544
+ * VACUUM FULL or CLUSTER on system catalogs. REINDEX should be used to
2545
+ * rebuild an index if constraint inconsistency is suspected.
2546
+ *
2516
2547
* Returns true if any indexes were rebuilt. Note that a
2517
2548
* CommandCounterIncrement will occur after each index rebuild.
2518
2549
*/
@@ -2594,7 +2625,7 @@ reindex_relation(Oid relid, bool toast_too, bool heap_rebuilt)
2594
2625
if (is_pg_class )
2595
2626
RelationSetIndexList (rel , doneIndexes , InvalidOid );
2596
2627
2597
- reindex_index (indexOid );
2628
+ reindex_index (indexOid , heap_rebuilt );
2598
2629
2599
2630
CommandCounterIncrement ();
2600
2631
0 commit comments