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

Commit2f0e480

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 parent72a4231 commit2f0e480

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
@@ -1316,6 +1316,10 @@ index_drop(Oid indexId, bool concurrent)
13161316
* table lock strong enough to prevent all queries on the table from
13171317
* proceeding until we commit and send out a shared-cache-inval notice
13181318
* that will make them update their index lists.
1319+
*
1320+
* In the concurrent case we make sure that nobody can be looking at the
1321+
* indexes by dropping the index in multiple steps, so we don't need a full
1322+
* AccessExclusiveLock yet.
13191323
*/
13201324
heapId=IndexGetRelation(indexId, false);
13211325
if (concurrent)
@@ -1336,7 +1340,19 @@ index_drop(Oid indexId, bool concurrent)
13361340

13371341
/*
13381342
* Drop Index concurrently is similar in many ways to creating an index
1339-
* concurrently, so some actions are similar to DefineIndex()
1343+
* concurrently, so some actions are similar to DefineIndex() just in the
1344+
* reverse order.
1345+
*
1346+
* First we unset indisvalid so queries starting afterwards don't use the
1347+
* index to answer queries anymore. We have to keep indisready = true
1348+
* so transactions that are still scanning the index can continue to
1349+
* see valid index contents. E.g. when they are using READ COMMITTED mode,
1350+
* and another transactions that started later commits makes changes and
1351+
* commits, they need to see those new tuples in the index.
1352+
*
1353+
* After all transactions that could possibly have used it for queries
1354+
* ended we can unset indisready and wait till nobody could be updating it
1355+
* anymore.
13401356
*/
13411357
if (concurrent)
13421358
{
@@ -1355,21 +1371,21 @@ index_drop(Oid indexId, bool concurrent)
13551371
elog(ERROR,"cache lookup failed for index %u",indexId);
13561372
indexForm= (Form_pg_index)GETSTRUCT(tuple);
13571373

1358-
indexForm->indisvalid= false;/* make unusable for queries */
1359-
indexForm->indisready= false;/* make invisible to changes */
1374+
/*
1375+
* If indisready == true we leave it set so the index still gets
1376+
* maintained by pre-existing transactions. We only need to ensure
1377+
* that indisvalid is false.
1378+
*/
1379+
if (indexForm->indisvalid)
1380+
{
1381+
indexForm->indisvalid= false;/* make unusable for new queries */
13601382

1361-
simple_heap_update(indexRelation,&tuple->t_self,tuple);
1362-
CatalogUpdateIndexes(indexRelation,tuple);
1383+
simple_heap_update(indexRelation,&tuple->t_self,tuple);
1384+
CatalogUpdateIndexes(indexRelation,tuple);
1385+
}
13631386

13641387
heap_close(indexRelation,RowExclusiveLock);
13651388

1366-
/*
1367-
* Invalidate the relcache for the table, so that after this
1368-
* transaction we will refresh the index list. Forgetting just the
1369-
* index is not enough.
1370-
*/
1371-
CacheInvalidateRelcache(userHeapRelation);
1372-
13731389
/* save lockrelid and locktag for below, then close but keep locks */
13741390
heaprelid=userHeapRelation->rd_lockInfo.lockRelId;
13751391
SET_LOCKTAG_RELATION(heaplocktag,heaprelid.dbId,heaprelid.relId);
@@ -1381,8 +1397,8 @@ index_drop(Oid indexId, bool concurrent)
13811397
/*
13821398
* For a concurrent drop, it's important to make the catalog entries
13831399
* visible to other transactions before we drop the index. The index
1384-
* will be marked not indisvalid, so that no one else tries toeither
1385-
*insert into it or use itfor queries.
1400+
* will be marked not indisvalid, so that no one else tries touse it
1401+
* for queries.
13861402
*
13871403
* We must commit our current transaction so that the index update
13881404
* becomes visible; then start another. Note that all the data
@@ -1428,6 +1444,66 @@ index_drop(Oid indexId, bool concurrent)
14281444
old_lockholders++;
14291445
}
14301446

1447+
/*
1448+
* Now we are sure that nobody uses the index for queries, they just
1449+
* might have it opened for updating it. So now we can unset
1450+
* indisready and wait till nobody could update the index anymore.
1451+
*/
1452+
indexRelation=heap_open(IndexRelationId,RowExclusiveLock);
1453+
1454+
userHeapRelation=heap_open(heapId,ShareUpdateExclusiveLock);
1455+
userIndexRelation=index_open(indexId,ShareUpdateExclusiveLock);
1456+
1457+
tuple=SearchSysCacheCopy1(INDEXRELID,
1458+
ObjectIdGetDatum(indexId));
1459+
if (!HeapTupleIsValid(tuple))
1460+
elog(ERROR,"cache lookup failed for index %u",indexId);
1461+
indexForm= (Form_pg_index)GETSTRUCT(tuple);
1462+
1463+
Assert(indexForm->indisvalid== false);
1464+
if (indexForm->indisready)
1465+
{
1466+
indexForm->indisready= false;/* don't update index anymore */
1467+
1468+
simple_heap_update(indexRelation,&tuple->t_self,tuple);
1469+
CatalogUpdateIndexes(indexRelation,tuple);
1470+
}
1471+
1472+
heap_close(indexRelation,RowExclusiveLock);
1473+
1474+
/*
1475+
* Close the relations again, though still holding session lock.
1476+
*/
1477+
heap_close(userHeapRelation,NoLock);
1478+
index_close(userIndexRelation,NoLock);
1479+
1480+
/*
1481+
* Invalidate the relcache for the table, so that after this
1482+
* transaction we will refresh the index list. Forgetting just the
1483+
* index is not enough.
1484+
*/
1485+
CacheInvalidateRelcache(userHeapRelation);
1486+
1487+
/*
1488+
* Just as with indisvalid = false we need to make sure indisready
1489+
* is false is visible for everyone.
1490+
*/
1491+
CommitTransactionCommand();
1492+
StartTransactionCommand();
1493+
1494+
/*
1495+
* Wait till everyone that saw indisready = true finished so we can
1496+
* finally really remove the index. The logic here is the same as
1497+
* above.
1498+
*/
1499+
old_lockholders=GetLockConflicts(&heaplocktag,AccessExclusiveLock);
1500+
1501+
while (VirtualTransactionIdIsValid(*old_lockholders))
1502+
{
1503+
VirtualXactLock(*old_lockholders, true);
1504+
old_lockholders++;
1505+
}
1506+
14311507
/*
14321508
* Re-open relations to allow us to complete our actions.
14331509
*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp