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

Commit7aa772f

Browse files
committed
Now that we've rearranged relation open to get a lock before touching
the rel, it's easy to get rid of the narrow race-condition window thatused to exist in VACUUM and CLUSTER. Did some minor code-beautificationwork in the same area, too.
1 parente91600d commit7aa772f

File tree

8 files changed

+151
-89
lines changed

8 files changed

+151
-89
lines changed

‎src/backend/access/heap/heapam.c

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.218 2006/07/31 20:08:59 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.219 2006/08/18 16:09:08 tgl Exp $
1212
*
1313
*
1414
* INTERFACE ROUTINES
@@ -53,6 +53,7 @@
5353
#include"utils/inval.h"
5454
#include"utils/lsyscache.h"
5555
#include"utils/relcache.h"
56+
#include"utils/syscache.h"
5657

5758

5859
staticXLogRecPtrlog_heap_update(Relationreln,Bufferoldbuf,
@@ -702,14 +703,56 @@ relation_open(Oid relationId, LOCKMODE lockmode)
702703
}
703704

704705
/* ----------------
705-
*conditional_relation_open - openwith option not to wait
706+
*try_relation_open - openany relation by relation OID
706707
*
707-
*As above, but if nowait is true, then throw an error rather than
708-
*waiting whenthelock is notimmediately obtainable.
708+
*Same as relation_open, except return NULL instead of failing
709+
*iftherelation does notexist.
709710
* ----------------
710711
*/
711712
Relation
712-
conditional_relation_open(OidrelationId,LOCKMODElockmode,boolnowait)
713+
try_relation_open(OidrelationId,LOCKMODElockmode)
714+
{
715+
Relationr;
716+
717+
Assert(lockmode >=NoLock&&lockmode<MAX_LOCKMODES);
718+
719+
/* Get the lock first */
720+
if (lockmode!=NoLock)
721+
LockRelationOid(relationId,lockmode);
722+
723+
/*
724+
* Now that we have the lock, probe to see if the relation really
725+
* exists or not.
726+
*/
727+
if (!SearchSysCacheExists(RELOID,
728+
ObjectIdGetDatum(relationId),
729+
0,0,0))
730+
{
731+
/* Release useless lock */
732+
if (lockmode!=NoLock)
733+
UnlockRelationOid(relationId,lockmode);
734+
735+
returnNULL;
736+
}
737+
738+
/* Should be safe to do a relcache load */
739+
r=RelationIdGetRelation(relationId);
740+
741+
if (!RelationIsValid(r))
742+
elog(ERROR,"could not open relation with OID %u",relationId);
743+
744+
returnr;
745+
}
746+
747+
/* ----------------
748+
*relation_open_nowait - open but don't wait for lock
749+
*
750+
*Same as relation_open, except throw an error instead of waiting
751+
*when the requested lock is not immediately obtainable.
752+
* ----------------
753+
*/
754+
Relation
755+
relation_open_nowait(OidrelationId,LOCKMODElockmode)
713756
{
714757
Relationr;
715758

@@ -718,27 +761,22 @@ conditional_relation_open(Oid relationId, LOCKMODE lockmode, bool nowait)
718761
/* Get the lock before trying to open the relcache entry */
719762
if (lockmode!=NoLock)
720763
{
721-
if (nowait)
764+
if (!ConditionalLockRelationOid(relationId,lockmode))
722765
{
723-
if (!ConditionalLockRelationOid(relationId,lockmode))
724-
{
725-
/* try to throw error by name; relation could be deleted... */
726-
char*relname=get_rel_name(relationId);
727-
728-
if (relname)
729-
ereport(ERROR,
730-
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
731-
errmsg("could not obtain lock on relation \"%s\"",
732-
relname)));
733-
else
734-
ereport(ERROR,
735-
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
736-
errmsg("could not obtain lock on relation with OID %u",
737-
relationId)));
738-
}
766+
/* try to throw error by name; relation could be deleted... */
767+
char*relname=get_rel_name(relationId);
768+
769+
if (relname)
770+
ereport(ERROR,
771+
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
772+
errmsg("could not obtain lock on relation \"%s\"",
773+
relname)));
774+
else
775+
ereport(ERROR,
776+
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
777+
errmsg("could not obtain lock on relation with OID %u",
778+
relationId)));
739779
}
740-
else
741-
LockRelationOid(relationId,lockmode);
742780
}
743781

744782
/* The relcache does all the real work... */
@@ -753,7 +791,7 @@ conditional_relation_open(Oid relationId, LOCKMODE lockmode, bool nowait)
753791
/* ----------------
754792
*relation_openrv - open any relation specified by a RangeVar
755793
*
756-
*As above, but the relation is specified by a RangeVar.
794+
*Same as relation_open, but the relation is specified by a RangeVar.
757795
* ----------------
758796
*/
759797
Relation

‎src/backend/commands/analyze.c

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.96 2006/07/14 14:52:18 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.97 2006/08/18 16:09:08 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -129,20 +129,16 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
129129
CHECK_FOR_INTERRUPTS();
130130

131131
/*
132-
*Race condition -- if the pg_class tuple has gone away sincethelast
133-
*time we saw it, we don't need to process it.
132+
*Open the relation, getting only a read lock on it. Iftherel has
133+
*been dropped since we last saw it, we don't need to process it.
134134
*/
135-
if (!SearchSysCacheExists(RELOID,
136-
ObjectIdGetDatum(relid),
137-
0,0,0))
135+
onerel=try_relation_open(relid,AccessShareLock);
136+
if (!onerel)
138137
return;
139138

140139
/*
141-
* Open the class, getting only a read lock on it, and check permissions.
142-
* Permissions check should match vacuum's check!
140+
* Check permissions --- this should match vacuum's check!
143141
*/
144-
onerel=relation_open(relid,AccessShareLock);
145-
146142
if (!(pg_class_ownercheck(RelationGetRelid(onerel),GetUserId())||
147143
(pg_database_ownercheck(MyDatabaseId,GetUserId())&& !onerel->rd_rel->relisshared)))
148144
{

‎src/backend/commands/cluster.c

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.152 2006/07/31 20:09:00 tgl Exp $
14+
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.153 2006/08/18 16:09:08 tgl Exp $
1515
*
1616
*-------------------------------------------------------------------------
1717
*/
@@ -239,6 +239,18 @@ cluster_rel(RelToCluster *rvtc, bool recheck)
239239
/* Check for user-requested abort. */
240240
CHECK_FOR_INTERRUPTS();
241241

242+
/*
243+
* We grab exclusive access to the target rel and index for the duration
244+
* of the transaction.(This is redundant for the single-transaction
245+
* case, since cluster() already did it.) The index lock is taken inside
246+
* check_index_is_clusterable.
247+
*/
248+
OldHeap=try_relation_open(rvtc->tableOid,AccessExclusiveLock);
249+
250+
/* If the table has gone away, we can skip processing it */
251+
if (!OldHeap)
252+
return;
253+
242254
/*
243255
* Since we may open a new transaction for each relation, we have to check
244256
* that the relation still is what we think it is.
@@ -252,46 +264,45 @@ cluster_rel(RelToCluster *rvtc, bool recheck)
252264
HeapTupletuple;
253265
Form_pg_indexindexForm;
254266

267+
/* Check that the user still owns the relation */
268+
if (!pg_class_ownercheck(rvtc->tableOid,GetUserId()))
269+
{
270+
relation_close(OldHeap,AccessExclusiveLock);
271+
return;
272+
}
273+
255274
/*
256-
* Checkif therelation andindex stillexist before opening them
275+
* Checkthat the index stillexists
257276
*/
258277
if (!SearchSysCacheExists(RELOID,
259-
ObjectIdGetDatum(rvtc->tableOid),
260-
0,0,0)||
261-
!SearchSysCacheExists(RELOID,
262278
ObjectIdGetDatum(rvtc->indexOid),
263279
0,0,0))
280+
{
281+
relation_close(OldHeap,AccessExclusiveLock);
264282
return;
265-
266-
/* Check that the user still owns the relation */
267-
if (!pg_class_ownercheck(rvtc->tableOid,GetUserId()))
268-
return;
283+
}
269284

270285
/*
271286
* Check that the index is still the one with indisclustered set.
272287
*/
273288
tuple=SearchSysCache(INDEXRELID,
274289
ObjectIdGetDatum(rvtc->indexOid),
275290
0,0,0);
276-
if (!HeapTupleIsValid(tuple))
277-
return;/* could have gone away... */
291+
if (!HeapTupleIsValid(tuple))/* probably can't happen */
292+
{
293+
relation_close(OldHeap,AccessExclusiveLock);
294+
return;
295+
}
278296
indexForm= (Form_pg_index)GETSTRUCT(tuple);
279297
if (!indexForm->indisclustered)
280298
{
281299
ReleaseSysCache(tuple);
300+
relation_close(OldHeap,AccessExclusiveLock);
282301
return;
283302
}
284303
ReleaseSysCache(tuple);
285304
}
286305

287-
/*
288-
* We grab exclusive access to the target rel and index for the duration
289-
* of the transaction.(This is redundant for the single- transaction
290-
* case, since cluster() already did it.) The index lock is taken inside
291-
* check_index_is_clusterable.
292-
*/
293-
OldHeap=heap_open(rvtc->tableOid,AccessExclusiveLock);
294-
295306
/* Check index is valid to cluster on */
296307
check_index_is_clusterable(OldHeap,rvtc->indexOid,recheck);
297308

‎src/backend/commands/lockcmds.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/lockcmds.c,v 1.14 2006/03/05 15:58:24 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/lockcmds.c,v 1.15 2006/08/18 16:09:08 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -59,7 +59,10 @@ LockTableCommand(LockStmt *lockstmt)
5959
aclcheck_error(aclresult,ACL_KIND_CLASS,
6060
get_rel_name(reloid));
6161

62-
rel=conditional_relation_open(reloid,lockstmt->mode,lockstmt->nowait);
62+
if (lockstmt->nowait)
63+
rel=relation_open_nowait(reloid,lockstmt->mode);
64+
else
65+
rel=relation_open(reloid,lockstmt->mode);
6366

6467
/* Currently, we only allow plain tables to be locked */
6568
if (rel->rd_rel->relkind!=RELKIND_RELATION)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp