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

Commit6cc842a

Browse files
committed
Revise lock manager to support "session level" locks as well as "transaction
level" locks. A session lock is not released at transaction commit (but itis released on transaction abort, to ensure recovery after an elog(ERROR)).In VACUUM, use a session lock to protect the master table while vacuuming aTOAST table, so that the TOAST table can be done in an independenttransaction.I also took this opportunity to do some cleanup and renaming in the lockcode. The previously noted bug in ProcLockWakeup, that it couldn't wake upany waiters beyond the first non-wakeable waiter, is now fixed. Also founda previously unknown bug of the same kind (failure to scan all members ofa lock queue in some cases) in DeadLockCheck. This might have led to failureto detect a deadlock condition, resulting in indefinite waits, but it'sdifficult to characterize the conditions required to trigger a failure.
1 parentb2145e9 commit6cc842a

File tree

11 files changed

+1018
-960
lines changed

11 files changed

+1018
-960
lines changed

‎contrib/userlock/user_locks.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ user_lock(uint32 id1, uint32 id2, LOCKMODE lockmode)
3333
tag.objId.blkno= (BlockNumber)id2;
3434
tag.offnum= (OffsetNumber) (id1&0xffff);
3535

36-
returnLockAcquire(USER_LOCKMETHOD,&tag,lockmode);
36+
returnLockAcquire(USER_LOCKMETHOD,&tag,InvalidTransactionId,lockmode);
3737
}
3838

3939
int
@@ -47,7 +47,7 @@ user_unlock(uint32 id1, uint32 id2, LOCKMODE lockmode)
4747
tag.objId.blkno= (BlockNumber)id2;
4848
tag.offnum= (OffsetNumber) (id1&0xffff);
4949

50-
returnLockRelease(USER_LOCKMETHOD,&tag,lockmode);
50+
returnLockRelease(USER_LOCKMETHOD,&tag,InvalidTransactionId,lockmode);
5151
}
5252

5353
int
@@ -89,7 +89,7 @@ user_unlock_all()
8989
}
9090

9191
proc= (PROC*)MAKE_PTR(location);
92-
returnLockReleaseAll(USER_LOCKMETHOD,&proc->lockQueue);
92+
returnLockReleaseAll(USER_LOCKMETHOD,proc, false,InvalidTransactionId);
9393
}
9494

9595
/* end of file */

‎src/backend/access/transam/xact.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.89 2000/12/18 00:44:45 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.90 2000/12/22 00:51:53 tgl Exp $
1212
*
1313
* NOTES
1414
*Transaction aborts can now occur two ways:
@@ -741,7 +741,7 @@ AtCommit_Locks(void)
741741
*Then you're up a creek! -mer 5/24/92
742742
* ----------------
743743
*/
744-
ProcReleaseLocks();
744+
ProcReleaseLocks(true);
745745
}
746746

747747
/* --------------------------------
@@ -828,7 +828,7 @@ AtAbort_Locks(void)
828828
*Then you're up a creek without a paddle! -mer
829829
* ----------------
830830
*/
831-
ProcReleaseLocks();
831+
ProcReleaseLocks(false);
832832
}
833833

834834

‎src/backend/commands/vacuum.c

Lines changed: 49 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.177 2000/12/08 06:43:44 inoue Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.178 2000/12/22 00:51:53 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -61,7 +61,7 @@ static void vacuum_init(void);
6161
staticvoidvacuum_shutdown(void);
6262
staticvoidvac_vacuum(NameData*VacRelP,boolanalyze,List*anal_cols2);
6363
staticVRelListgetrels(NameData*VacRelP);
64-
staticvoidvacuum_rel(Oidrelid,boolis_toastrel);
64+
staticvoidvacuum_rel(Oidrelid);
6565
staticvoidscan_heap(VRelStats*vacrelstats,Relationonerel,VacPageListvacuum_pages,VacPageListfraged_pages);
6666
staticvoidrepair_frag(VRelStats*vacrelstats,Relationonerel,VacPageListvacuum_pages,VacPageListfraged_pages,intnindices,Relation*Irel);
6767
staticvoidvacuum_heap(VRelStats*vacrelstats,Relationonerel,VacPageListvacpagelist);
@@ -239,7 +239,7 @@ vac_vacuum(NameData *VacRelP, bool analyze, List *anal_cols2)
239239
/* vacuum each heap relation */
240240
for (cur=vrl;cur!= (VRelList)NULL;cur=cur->vrl_next)
241241
{
242-
vacuum_rel(cur->vrl_relid, false);
242+
vacuum_rel(cur->vrl_relid);
243243
/* analyze separately so locking is minimized */
244244
if (analyze)
245245
analyze_rel(cur->vrl_relid,anal_cols2,MESSAGE_LEVEL);
@@ -308,7 +308,7 @@ getrels(NameData *VacRelP)
308308

309309
if (rkind!=RELKIND_RELATION)
310310
{
311-
elog(NOTICE,"Vacuum: can not processindecies, views and certain system tables");
311+
elog(NOTICE,"Vacuum: can not processindices, views and certain system tables");
312312
continue;
313313
}
314314

@@ -342,32 +342,34 @@ getrels(NameData *VacRelP)
342342
*vacuum_rel() -- vacuum one heap relation
343343
*
344344
*This routine vacuums a single heap, cleans out its indices, and
345-
*updates itsstatisticsnum_pages and num_tuples statistics.
345+
*updates its num_pages and num_tuples statistics.
346346
*
347347
*Doing one heap at a time incurs extra overhead, since we need to
348348
*check that the heap exists again just before we vacuum it.The
349349
*reason that we do this is so that vacuuming can be spread across
350350
*many small transactions. Otherwise, two-phase locking would require
351351
*us to lock the entire database during one pass of the vacuum cleaner.
352+
*
353+
*At entry and exit, we are not inside a transaction.
352354
*/
353355
staticvoid
354-
vacuum_rel(Oidrelid,boolis_toastrel)
356+
vacuum_rel(Oidrelid)
355357
{
356358
Relationonerel;
359+
LockRelIdonerelid;
357360
VacPageListDatavacuum_pages;/* List of pages to vacuum and/or clean
358-
* indices */
361+
* indices */
359362
VacPageListDatafraged_pages;/* List of pages with space enough for
360-
* re-using */
361-
VacPage*vacpage;
363+
* re-using */
362364
Relation*Irel;
363365
int32nindices,
364366
i;
365367
VRelStats*vacrelstats;
366368
boolreindex= false;
367369
Oidtoast_relid;
368370

369-
if (!is_toastrel)
370-
StartTransactionCommand();
371+
/* Begin a transaction for vacuuming this relation */
372+
StartTransactionCommand();
371373

372374
/*
373375
* Check for user-requested abort.Note we want this to be inside a
@@ -384,8 +386,7 @@ vacuum_rel(Oid relid, bool is_toastrel)
384386
ObjectIdGetDatum(relid),
385387
0,0,0))
386388
{
387-
if (!is_toastrel)
388-
CommitTransactionCommand();
389+
CommitTransactionCommand();
389390
return;
390391
}
391392

@@ -403,13 +404,25 @@ vacuum_rel(Oid relid, bool is_toastrel)
403404
elog(NOTICE,"Skipping \"%s\" --- only table owner can VACUUM it",
404405
RelationGetRelationName(onerel));
405406
heap_close(onerel,AccessExclusiveLock);
406-
if (!is_toastrel)
407-
CommitTransactionCommand();
407+
CommitTransactionCommand();
408408
return;
409409
}
410410

411411
/*
412-
* Remember the relation'ss TOAST relation for later
412+
* Get a session-level exclusive lock too. This will protect our
413+
* exclusive access to the relation across multiple transactions,
414+
* so that we can vacuum the relation's TOAST table (if any) secure
415+
* in the knowledge that no one is diddling the parent relation.
416+
*
417+
* NOTE: this cannot block, even if someone else is waiting for access,
418+
* because the lock manager knows that both lock requests are from the
419+
* same process.
420+
*/
421+
onerelid=onerel->rd_lockInfo.lockRelId;
422+
LockRelationForSession(&onerelid,AccessExclusiveLock);
423+
424+
/*
425+
* Remember the relation's TOAST relation for later
413426
*/
414427
toast_relid=onerel->rd_rel->reltoastrelid;
415428

@@ -500,21 +513,6 @@ vacuum_rel(Oid relid, bool is_toastrel)
500513
if (reindex)
501514
activate_indexes_of_a_table(relid, true);
502515

503-
/*
504-
* ok - free vacuum_pages list of reaped pages
505-
*
506-
* Isn't this a waste of code? Upcoming commit should free memory, no?
507-
*/
508-
if (vacuum_pages.num_pages>0)
509-
{
510-
vacpage=vacuum_pages.pagedesc;
511-
for (i=0;i<vacuum_pages.num_pages;i++,vacpage++)
512-
pfree(*vacpage);
513-
pfree(vacuum_pages.pagedesc);
514-
if (fraged_pages.num_pages>0)
515-
pfree(fraged_pages.pagedesc);
516-
}
517-
518516
/* all done with this class, but hold lock until commit */
519517
heap_close(onerel,NoLock);
520518

@@ -523,19 +521,25 @@ vacuum_rel(Oid relid, bool is_toastrel)
523521
vacrelstats->num_tuples,vacrelstats->hasindex,
524522
vacrelstats);
525523

524+
/*
525+
* Complete the transaction and free all temporary memory used.
526+
*/
527+
CommitTransactionCommand();
528+
526529
/*
527530
* If the relation has a secondary toast one, vacuum that too
528-
* while we still hold the lock on the master table. We don't
529-
* need to propagate "analyze" to it, because the toaster
531+
* while we still hold thesessionlock on the master table.
532+
*We don'tneed to propagate "analyze" to it, because the toaster
530533
* always uses hardcoded index access and statistics are
531534
* totally unimportant for toast relations
532535
*/
533536
if (toast_relid!=InvalidOid)
534-
vacuum_rel(toast_relid, true);
537+
vacuum_rel(toast_relid);
535538

536-
/* next command frees attribute stats */
537-
if (!is_toastrel)
538-
CommitTransactionCommand();
539+
/*
540+
* Now release the session-level lock on the master table.
541+
*/
542+
UnlockRelationForSession(&onerelid,AccessExclusiveLock);
539543
}
540544

541545
/*
@@ -1786,9 +1790,13 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)"
17861790
if (num_moved>0)
17871791
{
17881792
/*
1789-
* We have to commit our tuple' movings before we'll truncate
1790-
* relation, but we shouldn't lose our locks. And so - quick hack:
1791-
* record status of current transaction as committed, and continue.
1793+
* We have to commit our tuple movings before we truncate the
1794+
* relation. Ideally we should do Commit/StartTransactionCommand
1795+
* here, relying on the session-level table lock to protect our
1796+
* exclusive access to the relation. However, that would require
1797+
* a lot of extra code to close and re-open the relation, indices,
1798+
* etc. For now, a quick hack: record status of current transaction
1799+
* as committed, and continue.
17921800
*/
17931801
RecordTransactionCommit();
17941802
}
@@ -1852,7 +1860,7 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)"
18521860
/*
18531861
* Reflect the motion of system tuples to catalog cache here.
18541862
*/
1855-
CommandCounterIncrement();
1863+
CommandCounterIncrement();
18561864

18571865
if (Nvacpagelist.num_pages>0)
18581866
{

‎src/backend/storage/ipc/ipci.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.37 2000/12/03 17:18:10 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.38 2000/12/22 00:51:54 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -84,7 +84,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int maxBackends)
8484
* Set up lock manager
8585
*/
8686
InitLocks();
87-
if (InitLockTable()==INVALID_TABLEID)
87+
if (InitLockTable(maxBackends)==INVALID_TABLEID)
8888
elog(FATAL,"Couldn't create the lock table");
8989

9090
/*

‎src/backend/storage/lmgr/README

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1-
$Header: /cvsroot/pgsql/src/backend/storage/lmgr/README,v 1.3 1998/07/06 18:16:07 momjian Exp $
1+
$Header: /cvsroot/pgsql/src/backend/storage/lmgr/README,v 1.4 2000/12/22 00:51:54 tgl Exp $
22

3-
There are two fundemental lock structures. Lock methods describe the
4-
locking behavior. We currently only support multi-level locking. Lock
5-
modes describe the mode of the lock(read/write or shared/exclusive).
3+
There are two fundamental lock structures: the per-lockable-object LOCK
4+
struct, and the per-lock-holder HOLDER struct. A LOCK object exists
5+
for each lockable object that currently has locks held or requested on it.
6+
A HOLDER struct exists for each transaction that is holding or requesting
7+
lock(s) on each LOCK object.
8+
9+
Lock methods describe the overall locking behavior. Currently there are
10+
two lock methods: DEFAULT and USER. (USER locks are non-blocking.)
11+
12+
Lock modes describe the type of the lock (read/write or shared/exclusive).
613
See src/tools/backend/index.html and src/include/storage/lock.h for more
714
details.
815

@@ -12,10 +19,10 @@ The lock manager's LOCK:
1219

1320
tag -
1421
The key fields that are used for hashing locks in the shared memory
15-
lock hash table. This iskept as a separate struct to ensure that we
16-
always zero out the correct number of bytes.This isa problem as
17-
part ofthetag is an itempointer which is 6 bytes and causes 2
18-
additional bytes to be added as padding.
22+
lock hash table. This isdeclared as a separate struct to ensure that
23+
wealways zero out the correct number of bytes.It iscritical that
24+
any alignment-padding bytesthecompiler might insert in the struct
25+
be zeroed out, else the hash computation will be random.
1926

2027
tag.relId -
2128
Uniquely identifies the relation that the lock corresponds to.
@@ -30,17 +37,17 @@ tag -
3037
tuple within the block. If we are setting a table level lock
3138
both the blockId and tupleId (in an item pointer this is called
3239
the position) are set to invalid, if it is a page level lock the
33-
blockId is valid, while thetuleId is still invalid. Finally if
40+
blockId is valid, while thetupleId is still invalid. Finally if
3441
this is a tuple level lock (we currently never do this) then both
3542
the blockId and tupleId are set to valid specifications. This is
3643
how we get the appearance of a multi-level lock table while using
3744
only a single table (see Gray's paper on 2 phase locking if
3845
you are puzzled about how multi-level lock tables work).
3946

4047
mask -
41-
This field indicates what types of locks are currently heldin the
42-
givenlock. It is used (against the lock table's conflict table)
43-
to determine if the new lock request will conflict with existing
48+
This field indicates what types of locks are currently heldon the
49+
givenlockable object. It is used (against the lock table's conflict
50+
table)to determine if the new lock request will conflict with existing
4451
lock types held. Conficts are determined by bitwise AND operations
4552
between the mask and the conflict table entry for the given lock type
4653
to be set. The current representation is that each bit (1 through 5)
@@ -73,7 +80,7 @@ holders -
7380

7481
nActive -
7582
Keeps a count of how many times this lock has been succesfully acquired.
76-
This count does not include attempts thatwere rejected due to conflicts,
83+
This count does not include attempts thatare waiting due to conflicts,
7784
but can count the same backend twice (e.g. a read then a write -- since
7885
its the same transaction this won't cause a conflict)
7986

@@ -85,3 +92,39 @@ activeHolders -
8592

8693
---------------------------------------------------------------------------
8794

95+
The lock manager's HOLDER:
96+
97+
tag -
98+
The key fields that are used for hashing entries in the shared memory
99+
holder hash table. This is declared as a separate struct to ensure that
100+
we always zero out the correct number of bytes.
101+
102+
tag.lock
103+
SHMEM offset of the LOCK object this holder is for.
104+
105+
tag.pid
106+
PID of backend process that owns this holder.
107+
108+
tag.xid
109+
XID of transaction this holder is for, or InvalidTransactionId
110+
if the holder is for session-level locking.
111+
112+
Note that this structure will support multiple transactions running
113+
concurrently in one backend, which may be handy if we someday decide
114+
to support nested transactions. Currently, the XID field is only needed
115+
to distinguish per-transaction locks from session locks. User locks
116+
are always session locks, and we also use session locks for multi-
117+
transaction operations like VACUUM.
118+
119+
holders -
120+
The number of successfully acquired locks of each type for this holder.
121+
(CAUTION: the semantics are not the same as the LOCK's holder[], which
122+
counts both acquired and pending requests. Probably a different name
123+
should be used...)
124+
125+
nHolding -
126+
Sum of the holders[] array.
127+
128+
queue -
129+
List link for shared memory queue of all the HOLDER objects for the
130+
same backend.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp