@@ -1318,6 +1318,10 @@ index_drop(Oid indexId, bool concurrent)
13181318 * table lock strong enough to prevent all queries on the table from
13191319 * proceeding until we commit and send out a shared-cache-inval notice
13201320 * 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.
13211325 */
13221326heapId = IndexGetRelation (indexId , false);
13231327if (concurrent )
@@ -1338,7 +1342,19 @@ index_drop(Oid indexId, bool concurrent)
13381342
13391343/*
13401344 * 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.
13421358 */
13431359if (concurrent )
13441360{
@@ -1357,21 +1373,21 @@ index_drop(Oid indexId, bool concurrent)
13571373elog (ERROR ,"cache lookup failed for index %u" ,indexId );
13581374indexForm = (Form_pg_index )GETSTRUCT (tuple );
13591375
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 */
13621384
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+ }
13651388
13661389heap_close (indexRelation ,RowExclusiveLock );
13671390
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-
13751391/* save lockrelid and locktag for below, then close but keep locks */
13761392heaprelid = userHeapRelation -> rd_lockInfo .lockRelId ;
13771393SET_LOCKTAG_RELATION (heaplocktag ,heaprelid .dbId ,heaprelid .relId );
@@ -1383,8 +1399,8 @@ index_drop(Oid indexId, bool concurrent)
13831399/*
13841400 * For a concurrent drop, it's important to make the catalog entries
13851401 * visible to other transactions before we drop the index. The index
1386- * will be marked not indisvalid, so that no one else tries toeither
1387- *insert into it or use it for queries.
1402+ * will be marked not indisvalid, so that no one else tries touse it
1403+ * for queries.
13881404 *
13891405 * We must commit our current transaction so that the index update
13901406 * becomes visible; then start another. Note that all the data
@@ -1430,6 +1446,66 @@ index_drop(Oid indexId, bool concurrent)
14301446old_lockholders ++ ;
14311447}
14321448
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 after 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+
14331509/*
14341510 * Re-open relations to allow us to complete our actions.
14351511 *