Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit5da1c4b

Browse files
Re-think guts of DROP INDEX CONCURRENTLY.
Concurrent behaviour was flawed when usinga two-step process, so add an additionalphase of processing to ensure concurrencyfor both SELECTs and INSERT/UPDATE/DELETEs.Backpatch to 9.2Andres Freund, tweaked by me
1 parent0237b39 commit5da1c4b

File tree

1 file changed

+90
-14
lines changed

1 file changed

+90
-14
lines changed

‎src/backend/catalog/index.c

Lines changed: 90 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*/
13221326
heapId=IndexGetRelation(indexId, false);
13231327
if (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
*/
13431359
if (concurrent)
13441360
{
@@ -1357,21 +1373,21 @@ index_drop(Oid indexId, bool concurrent)
13571373
elog(ERROR,"cache lookup failed for index %u",indexId);
13581374
indexForm= (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

13661389
heap_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 */
13761392
heaprelid=userHeapRelation->rd_lockInfo.lockRelId;
13771393
SET_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 itfor 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)
14301446
old_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
*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp