@@ -1318,6 +1318,10 @@ index_drop(Oid indexId, bool concurrent)
1318
1318
* table lock strong enough to prevent all queries on the table from
1319
1319
* proceeding until we commit and send out a shared-cache-inval notice
1320
1320
* that will make them update their index lists.
1321
+ *
1322
+ * In the concurrent case we make sure that nobody can be looking at the
1323
+ * indexes by dropping the index in multiple steps, so we don't need a full
1324
+ * AccessExclusiveLock yet.
1321
1325
*/
1322
1326
heapId = IndexGetRelation (indexId , false);
1323
1327
if (concurrent )
@@ -1338,7 +1342,19 @@ index_drop(Oid indexId, bool concurrent)
1338
1342
1339
1343
/*
1340
1344
* Drop Index concurrently is similar in many ways to creating an index
1341
- * concurrently, so some actions are similar to DefineIndex()
1345
+ * concurrently, so some actions are similar to DefineIndex() just in the
1346
+ * reverse order.
1347
+ *
1348
+ * First we unset indisvalid so queries starting afterwards don't use the
1349
+ * index to answer queries anymore. We have to keep indisready = true
1350
+ * so transactions that are still scanning the index can continue to
1351
+ * see valid index contents. E.g. when they are using READ COMMITTED mode,
1352
+ * and another transactions that started later commits makes changes and
1353
+ * commits, they need to see those new tuples in the index.
1354
+ *
1355
+ * After all transactions that could possibly have used it for queries
1356
+ * ended we can unset indisready and wait till nobody could be updating it
1357
+ * anymore.
1342
1358
*/
1343
1359
if (concurrent )
1344
1360
{
@@ -1357,21 +1373,21 @@ index_drop(Oid indexId, bool concurrent)
1357
1373
elog (ERROR , "cache lookup failed for index %u" , indexId );
1358
1374
indexForm = (Form_pg_index ) GETSTRUCT (tuple );
1359
1375
1360
- indexForm -> indisvalid = false; /* make unusable for queries */
1361
- indexForm -> indisready = false; /* make invisible to changes */
1376
+ /*
1377
+ * If indisready == true we leave it set so the index still gets
1378
+ * maintained by pre-existing transactions. We only need to ensure
1379
+ * that indisvalid is false.
1380
+ */
1381
+ if (indexForm -> indisvalid )
1382
+ {
1383
+ indexForm -> indisvalid = false; /* make unusable for new queries */
1362
1384
1363
- simple_heap_update (indexRelation , & tuple -> t_self , tuple );
1364
- CatalogUpdateIndexes (indexRelation , tuple );
1385
+ simple_heap_update (indexRelation , & tuple -> t_self , tuple );
1386
+ CatalogUpdateIndexes (indexRelation , tuple );
1387
+ }
1365
1388
1366
1389
heap_close (indexRelation , RowExclusiveLock );
1367
1390
1368
- /*
1369
- * Invalidate the relcache for the table, so that after this
1370
- * transaction we will refresh the index list. Forgetting just the
1371
- * index is not enough.
1372
- */
1373
- CacheInvalidateRelcache (userHeapRelation );
1374
-
1375
1391
/* save lockrelid and locktag for below, then close but keep locks */
1376
1392
heaprelid = userHeapRelation -> rd_lockInfo .lockRelId ;
1377
1393
SET_LOCKTAG_RELATION (heaplocktag , heaprelid .dbId , heaprelid .relId );
@@ -1383,8 +1399,8 @@ index_drop(Oid indexId, bool concurrent)
1383
1399
/*
1384
1400
* For a concurrent drop, it's important to make the catalog entries
1385
1401
* visible to other transactions before we drop the index. The index
1386
- * will be marked not indisvalid, so that no one else tries to either
1387
- * insert into it or use it for queries.
1402
+ * will be marked not indisvalid, so that no one else tries to use it
1403
+ * for queries.
1388
1404
*
1389
1405
* We must commit our current transaction so that the index update
1390
1406
* becomes visible; then start another. Note that all the data
@@ -1430,6 +1446,66 @@ index_drop(Oid indexId, bool concurrent)
1430
1446
old_lockholders ++ ;
1431
1447
}
1432
1448
1449
+ /*
1450
+ * Now we are sure that nobody uses the index for queries, they just
1451
+ * might have it opened for updating it. So now we can unset
1452
+ * indisready and wait till nobody could update the index anymore.
1453
+ */
1454
+ indexRelation = heap_open (IndexRelationId , RowExclusiveLock );
1455
+
1456
+ userHeapRelation = heap_open (heapId , ShareUpdateExclusiveLock );
1457
+ userIndexRelation = index_open (indexId , ShareUpdateExclusiveLock );
1458
+
1459
+ tuple = SearchSysCacheCopy1 (INDEXRELID ,
1460
+ ObjectIdGetDatum (indexId ));
1461
+ if (!HeapTupleIsValid (tuple ))
1462
+ elog (ERROR , "cache lookup failed for index %u" , indexId );
1463
+ indexForm = (Form_pg_index ) GETSTRUCT (tuple );
1464
+
1465
+ Assert (indexForm -> indisvalid == false);
1466
+ if (indexForm -> indisready )
1467
+ {
1468
+ indexForm -> indisready = false; /* don't update index anymore */
1469
+
1470
+ simple_heap_update (indexRelation , & tuple -> t_self , tuple );
1471
+ CatalogUpdateIndexes (indexRelation , tuple );
1472
+ }
1473
+
1474
+ heap_close (indexRelation , RowExclusiveLock );
1475
+
1476
+ /*
1477
+ * Close the relations again, though still holding session lock.
1478
+ */
1479
+ heap_close (userHeapRelation , NoLock );
1480
+ index_close (userIndexRelation , NoLock );
1481
+
1482
+ /*
1483
+ * Invalidate the relcache for the table, so that aft
57AE
er this
1484
+ * transaction we will refresh the index list. Forgetting just the
1485
+ * index is not enough.
1486
+ */
1487
+ CacheInvalidateRelcache (userHeapRelation );
1488
+
1489
+ /*
1490
+ * Just as with indisvalid = false we need to make sure indisready
1491
+ * is false is visible for everyone.
1492
+ */
1493
+ CommitTransactionCommand ();
1494
+ StartTransactionCommand ();
1495
+
1496
+ /*
1497
+ * Wait till everyone that saw indisready = true finished so we can
1498
+ * finally really remove the index. The logic here is the same as
1499
+ * above.
1500
+ */
1501
+ old_lockholders = GetLockConflicts (& heaplocktag , AccessExclusiveLock );
1502
+
1503
+ while (VirtualTransactionIdIsValid (* old_lockholders ))
1504
+ {
1505
+ VirtualXactLock (* old_lockholders , true);
1506
+ old_lockholders ++ ;
1507
+ }
1508
+
1433
1509
/*
1434
1510
* Re-open relations to allow us to complete our actions.
1435
1511
*
0 commit comments