00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "postgres.h"
00031
00032 #include <signal.h>
00033 #include <unistd.h>
00034
00035 #include "access/transam.h"
00036 #include "access/twophase.h"
00037 #include "access/twophase_rmgr.h"
00038 #include "miscadmin.h"
00039 #include "pg_trace.h"
00040 #include "pgstat.h"
00041 #include "storage/proc.h"
00042 #include "storage/sinvaladt.h"
00043 #include "storage/spin.h"
00044 #include "storage/standby.h"
00045 #include "utils/memutils.h"
00046 #include "utils/ps_status.h"
00047 #include "utils/resowner_private.h"
00048
00049
00050
00051 int max_locks_per_xact;
00052
00053 #define NLOCKENTS() \
00054 mul_size(max_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
00055
00056
00057
00058
00059
00060
00061
00062 static const LOCKMASK LockConflicts[] = {
00063 0,
00064
00065
00066 (1 << AccessExclusiveLock),
00067
00068
00069 (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
00070
00071
00072 (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
00073 (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
00074
00075
00076 (1 << ShareUpdateExclusiveLock) |
00077 (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
00078 (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
00079
00080
00081 (1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
00082 (1 << ShareRowExclusiveLock) |
00083 (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
00084
00085
00086 (1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
00087 (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
00088 (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
00089
00090
00091 (1 << RowShareLock) |
00092 (1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
00093 (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
00094 (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
00095
00096
00097 (1 << AccessShareLock) | (1 << RowShareLock) |
00098 (1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
00099 (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
00100 (1 << ExclusiveLock) | (1 << AccessExclusiveLock)
00101
00102 };
00103
00104
00105 static const char *const lock_mode_names[] =
00106 {
00107 "INVALID",
00108 "AccessShareLock",
00109 "RowShareLock",
00110 "RowExclusiveLock",
00111 "ShareUpdateExclusiveLock",
00112 "ShareLock",
00113 "ShareRowExclusiveLock",
00114 "ExclusiveLock",
00115 "AccessExclusiveLock"
00116 };
00117
00118 #ifndef LOCK_DEBUG
00119 static bool Dummy_trace = false;
00120 #endif
00121
00122 static const LockMethodData default_lockmethod = {
00123 AccessExclusiveLock,
00124 LockConflicts,
00125 lock_mode_names,
00126 #ifdef LOCK_DEBUG
00127 &Trace_locks
00128 #else
00129 &Dummy_trace
00130 #endif
00131 };
00132
00133 static const LockMethodData user_lockmethod = {
00134 AccessExclusiveLock,
00135 LockConflicts,
00136 lock_mode_names,
00137 #ifdef LOCK_DEBUG
00138 &Trace_userlocks
00139 #else
00140 &Dummy_trace
00141 #endif
00142 };
00143
00144
00145
00146
00147 static const LockMethod LockMethods[] = {
00148 NULL,
00149 &default_lockmethod,
00150 &user_lockmethod
00151 };
00152
00153
00154
00155 typedef struct TwoPhaseLockRecord
00156 {
00157 LOCKTAG locktag;
00158 LOCKMODE lockmode;
00159 } TwoPhaseLockRecord;
00160
00161
00162
00163
00164
00165
00166
00167
00168 static int FastPathLocalUseCount = 0;
00169
00170
00171 #define FAST_PATH_BITS_PER_SLOT 3
00172 #define FAST_PATH_LOCKNUMBER_OFFSET 1
00173 #define FAST_PATH_MASK ((1 << FAST_PATH_BITS_PER_SLOT) - 1)
00174 #define FAST_PATH_GET_BITS(proc, n) \
00175 (((proc)->fpLockBits >> (FAST_PATH_BITS_PER_SLOT * n)) & FAST_PATH_MASK)
00176 #define FAST_PATH_BIT_POSITION(n, l) \
00177 (AssertMacro((l) >= FAST_PATH_LOCKNUMBER_OFFSET), \
00178 AssertMacro((l) < FAST_PATH_BITS_PER_SLOT+FAST_PATH_LOCKNUMBER_OFFSET), \
00179 AssertMacro((n) < FP_LOCK_SLOTS_PER_BACKEND), \
00180 ((l) - FAST_PATH_LOCKNUMBER_OFFSET + FAST_PATH_BITS_PER_SLOT * (n)))
00181 #define FAST_PATH_SET_LOCKMODE(proc, n, l) \
00182 (proc)->fpLockBits |= UINT64CONST(1) << FAST_PATH_BIT_POSITION(n, l)
00183 #define FAST_PATH_CLEAR_LOCKMODE(proc, n, l) \
00184 (proc)->fpLockBits &= ~(UINT64CONST(1) << FAST_PATH_BIT_POSITION(n, l))
00185 #define FAST_PATH_CHECK_LOCKMODE(proc, n, l) \
00186 ((proc)->fpLockBits & (UINT64CONST(1) << FAST_PATH_BIT_POSITION(n, l)))
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196 #define EligibleForRelationFastPath(locktag, mode) \
00197 ((locktag)->locktag_lockmethodid == DEFAULT_LOCKMETHOD && \
00198 (locktag)->locktag_type == LOCKTAG_RELATION && \
00199 (locktag)->locktag_field1 == MyDatabaseId && \
00200 MyDatabaseId != InvalidOid && \
00201 (mode) < ShareUpdateExclusiveLock)
00202 #define ConflictsWithRelationFastPath(locktag, mode) \
00203 ((locktag)->locktag_lockmethodid == DEFAULT_LOCKMETHOD && \
00204 (locktag)->locktag_type == LOCKTAG_RELATION && \
00205 (locktag)->locktag_field1 != InvalidOid && \
00206 (mode) > ShareUpdateExclusiveLock)
00207
00208 static bool FastPathGrantRelationLock(Oid relid, LOCKMODE lockmode);
00209 static bool FastPathUnGrantRelationLock(Oid relid, LOCKMODE lockmode);
00210 static bool FastPathTransferRelationLocks(LockMethod lockMethodTable,
00211 const LOCKTAG *locktag, uint32 hashcode);
00212 static PROCLOCK *FastPathGetRelationLockEntry(LOCALLOCK *locallock);
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229 #define FAST_PATH_STRONG_LOCK_HASH_BITS 10
00230 #define FAST_PATH_STRONG_LOCK_HASH_PARTITIONS \
00231 (1 << FAST_PATH_STRONG_LOCK_HASH_BITS)
00232 #define FastPathStrongLockHashPartition(hashcode) \
00233 ((hashcode) % FAST_PATH_STRONG_LOCK_HASH_PARTITIONS)
00234
00235 typedef struct
00236 {
00237 slock_t mutex;
00238 uint32 count[FAST_PATH_STRONG_LOCK_HASH_PARTITIONS];
00239 } FastPathStrongRelationLockData;
00240
00241 FastPathStrongRelationLockData *FastPathStrongRelationLocks;
00242
00243
00244
00245
00246
00247
00248
00249
00250 static HTAB *LockMethodLockHash;
00251 static HTAB *LockMethodProcLockHash;
00252 static HTAB *LockMethodLocalHash;
00253
00254
00255
00256 static LOCALLOCK *StrongLockInProgress;
00257 static LOCALLOCK *awaitedLock;
00258 static ResourceOwner awaitedOwner;
00259
00260
00261 #ifdef LOCK_DEBUG
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280 int Trace_lock_oidmin = FirstNormalObjectId;
00281 bool Trace_locks = false;
00282 bool Trace_userlocks = false;
00283 int Trace_lock_table = 0;
00284 bool Debug_deadlocks = false;
00285
00286
00287 inline static bool
00288 LOCK_DEBUG_ENABLED(const LOCKTAG *tag)
00289 {
00290 return
00291 (*(LockMethods[tag->locktag_lockmethodid]->trace_flag) &&
00292 ((Oid) tag->locktag_field2 >= (Oid) Trace_lock_oidmin))
00293 || (Trace_lock_table &&
00294 (tag->locktag_field2 == Trace_lock_table));
00295 }
00296
00297
00298 inline static void
00299 LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type)
00300 {
00301 if (LOCK_DEBUG_ENABLED(&lock->tag))
00302 elog(LOG,
00303 "%s: lock(%p) id(%u,%u,%u,%u,%u,%u) grantMask(%x) "
00304 "req(%d,%d,%d,%d,%d,%d,%d)=%d "
00305 "grant(%d,%d,%d,%d,%d,%d,%d)=%d wait(%d) type(%s)",
00306 where, lock,
00307 lock->tag.locktag_field1, lock->tag.locktag_field2,
00308 lock->tag.locktag_field3, lock->tag.locktag_field4,
00309 lock->tag.locktag_type, lock->tag.locktag_lockmethodid,
00310 lock->grantMask,
00311 lock->requested[1], lock->requested[2], lock->requested[3],
00312 lock->requested[4], lock->requested[5], lock->requested[6],
00313 lock->requested[7], lock->nRequested,
00314 lock->granted[1], lock->granted[2], lock->granted[3],
00315 lock->granted[4], lock->granted[5], lock->granted[6],
00316 lock->granted[7], lock->nGranted,
00317 lock->waitProcs.size,
00318 LockMethods[LOCK_LOCKMETHOD(*lock)]->lockModeNames[type]);
00319 }
00320
00321
00322 inline static void
00323 PROCLOCK_PRINT(const char *where, const PROCLOCK *proclockP)
00324 {
00325 if (LOCK_DEBUG_ENABLED(&proclockP->tag.myLock->tag))
00326 elog(LOG,
00327 "%s: proclock(%p) lock(%p) method(%u) proc(%p) hold(%x)",
00328 where, proclockP, proclockP->tag.myLock,
00329 PROCLOCK_LOCKMETHOD(*(proclockP)),
00330 proclockP->tag.myProc, (int) proclockP->holdMask);
00331 }
00332 #else
00333
00334 #define LOCK_PRINT(where, lock, type)
00335 #define PROCLOCK_PRINT(where, proclockP)
00336 #endif
00337
00338
00339 static uint32 proclock_hash(const void *key, Size keysize);
00340 static void RemoveLocalLock(LOCALLOCK *locallock);
00341 static PROCLOCK *SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
00342 const LOCKTAG *locktag, uint32 hashcode, LOCKMODE lockmode);
00343 static void GrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner);
00344 static void BeginStrongLockAcquire(LOCALLOCK *locallock, uint32 fasthashcode);
00345 static void FinishStrongLockAcquire(void);
00346 static void WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner);
00347 static void ReleaseLockIfHeld(LOCALLOCK *locallock, bool sessionLock);
00348 static void LockReassignOwner(LOCALLOCK *locallock, ResourceOwner parent);
00349 static bool UnGrantLock(LOCK *lock, LOCKMODE lockmode,
00350 PROCLOCK *proclock, LockMethod lockMethodTable);
00351 static void CleanUpLock(LOCK *lock, PROCLOCK *proclock,
00352 LockMethod lockMethodTable, uint32 hashcode,
00353 bool wakeupNeeded);
00354 static void LockRefindAndRelease(LockMethod lockMethodTable, PGPROC *proc,
00355 LOCKTAG *locktag, LOCKMODE lockmode,
00356 bool decrement_strong_lock_count);
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 void
00372 InitLocks(void)
00373 {
00374 HASHCTL info;
00375 int hash_flags;
00376 long init_table_size,
00377 max_table_size;
00378 bool found;
00379
00380
00381
00382
00383
00384 max_table_size = NLOCKENTS();
00385 init_table_size = max_table_size / 2;
00386
00387
00388
00389
00390
00391 MemSet(&info, 0, sizeof(info));
00392 info.keysize = sizeof(LOCKTAG);
00393 info.entrysize = sizeof(LOCK);
00394 info.hash = tag_hash;
00395 info.num_partitions = NUM_LOCK_PARTITIONS;
00396 hash_flags = (HASH_ELEM | HASH_FUNCTION | HASH_PARTITION);
00397
00398 LockMethodLockHash = ShmemInitHash("LOCK hash",
00399 init_table_size,
00400 max_table_size,
00401 &info,
00402 hash_flags);
00403
00404
00405 max_table_size *= 2;
00406 init_table_size *= 2;
00407
00408
00409
00410
00411
00412 info.keysize = sizeof(PROCLOCKTAG);
00413 info.entrysize = sizeof(PROCLOCK);
00414 info.hash = proclock_hash;
00415 info.num_partitions = NUM_LOCK_PARTITIONS;
00416 hash_flags = (HASH_ELEM | HASH_FUNCTION | HASH_PARTITION);
00417
00418 LockMethodProcLockHash = ShmemInitHash("PROCLOCK hash",
00419 init_table_size,
00420 max_table_size,
00421 &info,
00422 hash_flags);
00423
00424
00425
00426
00427 FastPathStrongRelationLocks =
00428 ShmemInitStruct("Fast Path Strong Relation Lock Data",
00429 sizeof(FastPathStrongRelationLockData), &found);
00430 if (!found)
00431 SpinLockInit(&FastPathStrongRelationLocks->mutex);
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442 if (LockMethodLocalHash)
00443 hash_destroy(LockMethodLocalHash);
00444
00445 info.keysize = sizeof(LOCALLOCKTAG);
00446 info.entrysize = sizeof(LOCALLOCK);
00447 info.hash = tag_hash;
00448 hash_flags = (HASH_ELEM | HASH_FUNCTION);
00449
00450 LockMethodLocalHash = hash_create("LOCALLOCK hash",
00451 16,
00452 &info,
00453 hash_flags);
00454 }
00455
00456
00457
00458
00459
00460 LockMethod
00461 GetLocksMethodTable(const LOCK *lock)
00462 {
00463 LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*lock);
00464
00465 Assert(0 < lockmethodid && lockmethodid < lengthof(LockMethods));
00466 return LockMethods[lockmethodid];
00467 }
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478 uint32
00479 LockTagHashCode(const LOCKTAG *locktag)
00480 {
00481 return get_hash_value(LockMethodLockHash, (const void *) locktag);
00482 }
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495 static uint32
00496 proclock_hash(const void *key, Size keysize)
00497 {
00498 const PROCLOCKTAG *proclocktag = (const PROCLOCKTAG *) key;
00499 uint32 lockhash;
00500 Datum procptr;
00501
00502 Assert(keysize == sizeof(PROCLOCKTAG));
00503
00504
00505 lockhash = LockTagHashCode(&proclocktag->myLock->tag);
00506
00507
00508
00509
00510
00511
00512
00513
00514 procptr = PointerGetDatum(proclocktag->myProc);
00515 lockhash ^= ((uint32) procptr) << LOG2_NUM_LOCK_PARTITIONS;
00516
00517 return lockhash;
00518 }
00519
00520
00521
00522
00523
00524
00525
00526 static inline uint32
00527 ProcLockHashCode(const PROCLOCKTAG *proclocktag, uint32 hashcode)
00528 {
00529 uint32 lockhash = hashcode;
00530 Datum procptr;
00531
00532
00533
00534
00535 procptr = PointerGetDatum(proclocktag->myProc);
00536 lockhash ^= ((uint32) procptr) << LOG2_NUM_LOCK_PARTITIONS;
00537
00538 return lockhash;
00539 }
00540
00541
00542
00543
00544 bool
00545 DoLockModesConflict(LOCKMODE mode1, LOCKMODE mode2)
00546 {
00547 LockMethod lockMethodTable = LockMethods[DEFAULT_LOCKMETHOD];
00548
00549 if (lockMethodTable->conflictTab[mode1] & LOCKBIT_ON(mode2))
00550 return true;
00551
00552 return false;
00553 }
00554
00555
00556
00557
00558
00559 bool
00560 LockHasWaiters(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
00561 {
00562 LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
00563 LockMethod lockMethodTable;
00564 LOCALLOCKTAG localtag;
00565 LOCALLOCK *locallock;
00566 LOCK *lock;
00567 PROCLOCK *proclock;
00568 LWLockId partitionLock;
00569 bool hasWaiters = false;
00570
00571 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
00572 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
00573 lockMethodTable = LockMethods[lockmethodid];
00574 if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
00575 elog(ERROR, "unrecognized lock mode: %d", lockmode);
00576
00577 #ifdef LOCK_DEBUG
00578 if (LOCK_DEBUG_ENABLED(locktag))
00579 elog(LOG, "LockHasWaiters: lock [%u,%u] %s",
00580 locktag->locktag_field1, locktag->locktag_field2,
00581 lockMethodTable->lockModeNames[lockmode]);
00582 #endif
00583
00584
00585
00586
00587 MemSet(&localtag, 0, sizeof(localtag));
00588 localtag.lock = *locktag;
00589 localtag.mode = lockmode;
00590
00591 locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,
00592 (void *) &localtag,
00593 HASH_FIND, NULL);
00594
00595
00596
00597
00598 if (!locallock || locallock->nLocks <= 0)
00599 {
00600 elog(WARNING, "you don't own a lock of type %s",
00601 lockMethodTable->lockModeNames[lockmode]);
00602 return false;
00603 }
00604
00605
00606
00607
00608 partitionLock = LockHashPartitionLock(locallock->hashcode);
00609
00610 LWLockAcquire(partitionLock, LW_SHARED);
00611
00612
00613
00614
00615
00616
00617 lock = locallock->lock;
00618 LOCK_PRINT("LockHasWaiters: found", lock, lockmode);
00619 proclock = locallock->proclock;
00620 PROCLOCK_PRINT("LockHasWaiters: found", proclock);
00621
00622
00623
00624
00625
00626 if (!(proclock->holdMask & LOCKBIT_ON(lockmode)))
00627 {
00628 PROCLOCK_PRINT("LockHasWaiters: WRONGTYPE", proclock);
00629 LWLockRelease(partitionLock);
00630 elog(WARNING, "you don't own a lock of type %s",
00631 lockMethodTable->lockModeNames[lockmode]);
00632 RemoveLocalLock(locallock);
00633 return false;
00634 }
00635
00636
00637
00638
00639 if ((lockMethodTable->conflictTab[lockmode] & lock->waitMask) != 0)
00640 hasWaiters = true;
00641
00642 LWLockRelease(partitionLock);
00643
00644 return hasWaiters;
00645 }
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671 LockAcquireResult
00672 LockAcquire(const LOCKTAG *locktag,
00673 LOCKMODE lockmode,
00674 bool sessionLock,
00675 bool dontWait)
00676 {
00677 return LockAcquireExtended(locktag, lockmode, sessionLock, dontWait, true);
00678 }
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689 LockAcquireResult
00690 LockAcquireExtended(const LOCKTAG *locktag,
00691 LOCKMODE lockmode,
00692 bool sessionLock,
00693 bool dontWait,
00694 bool reportMemoryError)
00695 {
00696 LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
00697 LockMethod lockMethodTable;
00698 LOCALLOCKTAG localtag;
00699 LOCALLOCK *locallock;
00700 LOCK *lock;
00701 PROCLOCK *proclock;
00702 bool found;
00703 ResourceOwner owner;
00704 uint32 hashcode;
00705 LWLockId partitionLock;
00706 int status;
00707 bool log_lock = false;
00708
00709 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
00710 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
00711 lockMethodTable = LockMethods[lockmethodid];
00712 if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
00713 elog(ERROR, "unrecognized lock mode: %d", lockmode);
00714
00715 if (RecoveryInProgress() && !InRecovery &&
00716 (locktag->locktag_type == LOCKTAG_OBJECT ||
00717 locktag->locktag_type == LOCKTAG_RELATION) &&
00718 lockmode > RowExclusiveLock)
00719 ereport(ERROR,
00720 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00721 errmsg("cannot acquire lock mode %s on database objects while recovery is in progress",
00722 lockMethodTable->lockModeNames[lockmode]),
00723 errhint("Only RowExclusiveLock or less can be acquired on database objects during recovery.")));
00724
00725 #ifdef LOCK_DEBUG
00726 if (LOCK_DEBUG_ENABLED(locktag))
00727 elog(LOG, "LockAcquire: lock [%u,%u] %s",
00728 locktag->locktag_field1, locktag->locktag_field2,
00729 lockMethodTable->lockModeNames[lockmode]);
00730 #endif
00731
00732
00733 if (sessionLock)
00734 owner = NULL;
00735 else
00736 owner = CurrentResourceOwner;
00737
00738
00739
00740
00741 MemSet(&localtag, 0, sizeof(localtag));
00742 localtag.lock = *locktag;
00743 localtag.mode = lockmode;
00744
00745 locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,
00746 (void *) &localtag,
00747 HASH_ENTER, &found);
00748
00749
00750
00751
00752 if (!found)
00753 {
00754 locallock->lock = NULL;
00755 locallock->proclock = NULL;
00756 locallock->hashcode = LockTagHashCode(&(localtag.lock));
00757 locallock->nLocks = 0;
00758 locallock->numLockOwners = 0;
00759 locallock->maxLockOwners = 8;
00760 locallock->holdsStrongLockCount = FALSE;
00761 locallock->lockOwners = NULL;
00762 locallock->lockOwners = (LOCALLOCKOWNER *)
00763 MemoryContextAlloc(TopMemoryContext,
00764 locallock->maxLockOwners * sizeof(LOCALLOCKOWNER));
00765 }
00766 else
00767 {
00768
00769 if (locallock->numLockOwners >= locallock->maxLockOwners)
00770 {
00771 int newsize = locallock->maxLockOwners * 2;
00772
00773 locallock->lockOwners = (LOCALLOCKOWNER *)
00774 repalloc(locallock->lockOwners,
00775 newsize * sizeof(LOCALLOCKOWNER));
00776 locallock->maxLockOwners = newsize;
00777 }
00778 }
00779 hashcode = locallock->hashcode;
00780
00781
00782
00783
00784 if (locallock->nLocks > 0)
00785 {
00786 GrantLockLocal(locallock, owner);
00787 return LOCKACQUIRE_ALREADY_HELD;
00788 }
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800 if (lockmode >= AccessExclusiveLock &&
00801 locktag->locktag_type == LOCKTAG_RELATION &&
00802 !RecoveryInProgress() &&
00803 XLogStandbyInfoActive())
00804 {
00805 LogAccessExclusiveLockPrepare();
00806 log_lock = true;
00807 }
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819 if (EligibleForRelationFastPath(locktag, lockmode)
00820 && FastPathLocalUseCount < FP_LOCK_SLOTS_PER_BACKEND)
00821 {
00822 uint32 fasthashcode = FastPathStrongLockHashPartition(hashcode);
00823 bool acquired;
00824
00825
00826
00827
00828
00829
00830
00831 LWLockAcquire(MyProc->backendLock, LW_EXCLUSIVE);
00832 if (FastPathStrongRelationLocks->count[fasthashcode] != 0)
00833 acquired = false;
00834 else
00835 acquired = FastPathGrantRelationLock(locktag->locktag_field2,
00836 lockmode);
00837 LWLockRelease(MyProc->backendLock);
00838 if (acquired)
00839 {
00840 GrantLockLocal(locallock, owner);
00841 return LOCKACQUIRE_OK;
00842 }
00843 }
00844
00845
00846
00847
00848
00849
00850
00851 if (ConflictsWithRelationFastPath(locktag, lockmode))
00852 {
00853 uint32 fasthashcode = FastPathStrongLockHashPartition(hashcode);
00854
00855 BeginStrongLockAcquire(locallock, fasthashcode);
00856 if (!FastPathTransferRelationLocks(lockMethodTable, locktag,
00857 hashcode))
00858 {
00859 AbortStrongLockAcquire();
00860 if (reportMemoryError)
00861 ereport(ERROR,
00862 (errcode(ERRCODE_OUT_OF_MEMORY),
00863 errmsg("out of shared memory"),
00864 errhint("You might need to increase max_locks_per_transaction.")));
00865 else
00866 return LOCKACQUIRE_NOT_AVAIL;
00867 }
00868 }
00869
00870
00871
00872
00873
00874
00875 partitionLock = LockHashPartitionLock(hashcode);
00876
00877 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
00878
00879
00880
00881
00882 proclock = SetupLockInTable(lockMethodTable, MyProc, locktag,
00883 hashcode, lockmode);
00884 if (!proclock)
00885 {
00886 AbortStrongLockAcquire();
00887 LWLockRelease(partitionLock);
00888 if (reportMemoryError)
00889 ereport(ERROR,
00890 (errcode(ERRCODE_OUT_OF_MEMORY),
00891 errmsg("out of shared memory"),
00892 errhint("You might need to increase max_locks_per_transaction.")));
00893 else
00894 return LOCKACQUIRE_NOT_AVAIL;
00895 }
00896 locallock->proclock = proclock;
00897 lock = proclock->tag.myLock;
00898 locallock->lock = lock;
00899
00900
00901
00902
00903
00904
00905 if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)
00906 status = STATUS_FOUND;
00907 else
00908 status = LockCheckConflicts(lockMethodTable, lockmode,
00909 lock, proclock, MyProc);
00910
00911 if (status == STATUS_OK)
00912 {
00913
00914 GrantLock(lock, proclock, lockmode);
00915 GrantLockLocal(locallock, owner);
00916 }
00917 else
00918 {
00919 Assert(status == STATUS_FOUND);
00920
00921
00922
00923
00924
00925
00926 if (dontWait)
00927 {
00928 AbortStrongLockAcquire();
00929 if (proclock->holdMask == 0)
00930 {
00931 uint32 proclock_hashcode;
00932
00933 proclock_hashcode = ProcLockHashCode(&proclock->tag, hashcode);
00934 SHMQueueDelete(&proclock->lockLink);
00935 SHMQueueDelete(&proclock->procLink);
00936 if (!hash_search_with_hash_value(LockMethodProcLockHash,
00937 (void *) &(proclock->tag),
00938 proclock_hashcode,
00939 HASH_REMOVE,
00940 NULL))
00941 elog(PANIC, "proclock table corrupted");
00942 }
00943 else
00944 PROCLOCK_PRINT("LockAcquire: NOWAIT", proclock);
00945 lock->nRequested--;
00946 lock->requested[lockmode]--;
00947 LOCK_PRINT("LockAcquire: conditional lock failed", lock, lockmode);
00948 Assert((lock->nRequested > 0) && (lock->requested[lockmode] >= 0));
00949 Assert(lock->nGranted <= lock->nRequested);
00950 LWLockRelease(partitionLock);
00951 if (locallock->nLocks == 0)
00952 RemoveLocalLock(locallock);
00953 return LOCKACQUIRE_NOT_AVAIL;
00954 }
00955
00956
00957
00958
00959 MyProc->heldLocks = proclock->holdMask;
00960
00961
00962
00963
00964
00965 TRACE_POSTGRESQL_LOCK_WAIT_START(locktag->locktag_field1,
00966 locktag->locktag_field2,
00967 locktag->locktag_field3,
00968 locktag->locktag_field4,
00969 locktag->locktag_type,
00970 lockmode);
00971
00972 WaitOnLock(locallock, owner);
00973
00974 TRACE_POSTGRESQL_LOCK_WAIT_DONE(locktag->locktag_field1,
00975 locktag->locktag_field2,
00976 locktag->locktag_field3,
00977 locktag->locktag_field4,
00978 locktag->locktag_type,
00979 lockmode);
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991 if (!(proclock->holdMask & LOCKBIT_ON(lockmode)))
00992 {
00993 AbortStrongLockAcquire();
00994 PROCLOCK_PRINT("LockAcquire: INCONSISTENT", proclock);
00995 LOCK_PRINT("LockAcquire: INCONSISTENT", lock, lockmode);
00996
00997 LWLockRelease(partitionLock);
00998 elog(ERROR, "LockAcquire failed");
00999 }
01000 PROCLOCK_PRINT("LockAcquire: granted", proclock);
01001 LOCK_PRINT("LockAcquire: granted", lock, lockmode);
01002 }
01003
01004
01005
01006
01007
01008 FinishStrongLockAcquire();
01009
01010 LWLockRelease(partitionLock);
01011
01012
01013
01014
01015
01016 if (log_lock)
01017 {
01018
01019
01020
01021
01022
01023 LogAccessExclusiveLock(locktag->locktag_field1,
01024 locktag->locktag_field2);
01025 }
01026
01027 return LOCKACQUIRE_OK;
01028 }
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040 static PROCLOCK *
01041 SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
01042 const LOCKTAG *locktag, uint32 hashcode, LOCKMODE lockmode)
01043 {
01044 LOCK *lock;
01045 PROCLOCK *proclock;
01046 PROCLOCKTAG proclocktag;
01047 uint32 proclock_hashcode;
01048 bool found;
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058 lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
01059 (const void *) locktag,
01060 hashcode,
01061 HASH_ENTER_NULL,
01062 &found);
01063 if (!lock)
01064 return NULL;
01065
01066
01067
01068
01069 if (!found)
01070 {
01071 lock->grantMask = 0;
01072 lock->waitMask = 0;
01073 SHMQueueInit(&(lock->procLocks));
01074 ProcQueueInit(&(lock->waitProcs));
01075 lock->nRequested = 0;
01076 lock->nGranted = 0;
01077 MemSet(lock->requested, 0, sizeof(int) * MAX_LOCKMODES);
01078 MemSet(lock->granted, 0, sizeof(int) * MAX_LOCKMODES);
01079 LOCK_PRINT("LockAcquire: new", lock, lockmode);
01080 }
01081 else
01082 {
01083 LOCK_PRINT("LockAcquire: found", lock, lockmode);
01084 Assert((lock->nRequested >= 0) && (lock->requested[lockmode] >= 0));
01085 Assert((lock->nGranted >= 0) && (lock->granted[lockmode] >= 0));
01086 Assert(lock->nGranted <= lock->nRequested);
01087 }
01088
01089
01090
01091
01092 proclocktag.myLock = lock;
01093 proclocktag.myProc = proc;
01094
01095 proclock_hashcode = ProcLockHashCode(&proclocktag, hashcode);
01096
01097
01098
01099
01100 proclock = (PROCLOCK *) hash_search_with_hash_value(LockMethodProcLockHash,
01101 (void *) &proclocktag,
01102 proclock_hashcode,
01103 HASH_ENTER_NULL,
01104 &found);
01105 if (!proclock)
01106 {
01107
01108 if (lock->nRequested == 0)
01109 {
01110
01111
01112
01113
01114
01115
01116 Assert(SHMQueueEmpty(&(lock->procLocks)));
01117 if (!hash_search_with_hash_value(LockMethodLockHash,
01118 (void *) &(lock->tag),
01119 hashcode,
01120 HASH_REMOVE,
01121 NULL))
01122 elog(PANIC, "lock table corrupted");
01123 }
01124 return NULL;
01125 }
01126
01127
01128
01129
01130 if (!found)
01131 {
01132 uint32 partition = LockHashPartition(hashcode);
01133
01134 proclock->holdMask = 0;
01135 proclock->releaseMask = 0;
01136
01137 SHMQueueInsertBefore(&lock->procLocks, &proclock->lockLink);
01138 SHMQueueInsertBefore(&(proc->myProcLocks[partition]),
01139 &proclock->procLink);
01140 PROCLOCK_PRINT("LockAcquire: new", proclock);
01141 }
01142 else
01143 {
01144 PROCLOCK_PRINT("LockAcquire: found", proclock);
01145 Assert((proclock->holdMask & ~lock->grantMask) == 0);
01146
01147 #ifdef CHECK_DEADLOCK_RISK
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163 {
01164 int i;
01165
01166 for (i = lockMethodTable->numLockModes; i > 0; i--)
01167 {
01168 if (proclock->holdMask & LOCKBIT_ON(i))
01169 {
01170 if (i >= (int) lockmode)
01171 break;
01172 elog(LOG, "deadlock risk: raising lock level"
01173 " from %s to %s on object %u/%u/%u",
01174 lockMethodTable->lockModeNames[i],
01175 lockMethodTable->lockModeNames[lockmode],
01176 lock->tag.locktag_field1, lock->tag.locktag_field2,
01177 lock->tag.locktag_field3);
01178 break;
01179 }
01180 }
01181 }
01182 #endif
01183 }
01184
01185
01186
01187
01188
01189
01190 lock->nRequested++;
01191 lock->requested[lockmode]++;
01192 Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0));
01193
01194
01195
01196
01197
01198 if (proclock->holdMask & LOCKBIT_ON(lockmode))
01199 elog(ERROR, "lock %s on object %u/%u/%u is already held",
01200 lockMethodTable->lockModeNames[lockmode],
01201 lock->tag.locktag_field1, lock->tag.locktag_field2,
01202 lock->tag.locktag_field3);
01203
01204 return proclock;
01205 }
01206
01207
01208
01209
01210 static void
01211 RemoveLocalLock(LOCALLOCK *locallock)
01212 {
01213 int i;
01214
01215 for (i = locallock->numLockOwners - 1; i >= 0; i--)
01216 {
01217 if (locallock->lockOwners[i].owner != NULL)
01218 ResourceOwnerForgetLock(locallock->lockOwners[i].owner, locallock);
01219 }
01220 pfree(locallock->lockOwners);
01221 locallock->lockOwners = NULL;
01222
01223 if (locallock->holdsStrongLockCount)
01224 {
01225 uint32 fasthashcode;
01226
01227 fasthashcode = FastPathStrongLockHashPartition(locallock->hashcode);
01228
01229 SpinLockAcquire(&FastPathStrongRelationLocks->mutex);
01230 Assert(FastPathStrongRelationLocks->count[fasthashcode] > 0);
01231 FastPathStrongRelationLocks->count[fasthashcode]--;
01232 locallock->holdsStrongLockCount = FALSE;
01233 SpinLockRelease(&FastPathStrongRelationLocks->mutex);
01234 }
01235
01236 if (!hash_search(LockMethodLocalHash,
01237 (void *) &(locallock->tag),
01238 HASH_REMOVE, NULL))
01239 elog(WARNING, "locallock table corrupted");
01240 }
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255 int
01256 LockCheckConflicts(LockMethod lockMethodTable,
01257 LOCKMODE lockmode,
01258 LOCK *lock,
01259 PROCLOCK *proclock,
01260 PGPROC *proc)
01261 {
01262 int numLockModes = lockMethodTable->numLockModes;
01263 LOCKMASK myLocks;
01264 LOCKMASK otherLocks;
01265 int i;
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276 if (!(lockMethodTable->conflictTab[lockmode] & lock->grantMask))
01277 {
01278 PROCLOCK_PRINT("LockCheckConflicts: no conflict", proclock);
01279 return STATUS_OK;
01280 }
01281
01282
01283
01284
01285
01286
01287 myLocks = proclock->holdMask;
01288 otherLocks = 0;
01289 for (i = 1; i <= numLockModes; i++)
01290 {
01291 int myHolding = (myLocks & LOCKBIT_ON(i)) ? 1 : 0;
01292
01293 if (lock->granted[i] > myHolding)
01294 otherLocks |= LOCKBIT_ON(i);
01295 }
01296
01297
01298
01299
01300
01301
01302 if (!(lockMethodTable->conflictTab[lockmode] & otherLocks))
01303 {
01304
01305 PROCLOCK_PRINT("LockCheckConflicts: resolved", proclock);
01306 return STATUS_OK;
01307 }
01308
01309 PROCLOCK_PRINT("LockCheckConflicts: conflicting", proclock);
01310 return STATUS_FOUND;
01311 }
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324 void
01325 GrantLock(LOCK *lock, PROCLOCK *proclock, LOCKMODE lockmode)
01326 {
01327 lock->nGranted++;
01328 lock->granted[lockmode]++;
01329 lock->grantMask |= LOCKBIT_ON(lockmode);
01330 if (lock->granted[lockmode] == lock->requested[lockmode])
01331 lock->waitMask &= LOCKBIT_OFF(lockmode);
01332 proclock->holdMask |= LOCKBIT_ON(lockmode);
01333 LOCK_PRINT("GrantLock", lock, lockmode);
01334 Assert((lock->nGranted > 0) && (lock->granted[lockmode] > 0));
01335 Assert(lock->nGranted <= lock->nRequested);
01336 }
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347 static bool
01348 UnGrantLock(LOCK *lock, LOCKMODE lockmode,
01349 PROCLOCK *proclock, LockMethod lockMethodTable)
01350 {
01351 bool wakeupNeeded = false;
01352
01353 Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0));
01354 Assert((lock->nGranted > 0) && (lock->granted[lockmode] > 0));
01355 Assert(lock->nGranted <= lock->nRequested);
01356
01357
01358
01359
01360 lock->nRequested--;
01361 lock->requested[lockmode]--;
01362 lock->nGranted--;
01363 lock->granted[lockmode]--;
01364
01365 if (lock->granted[lockmode] == 0)
01366 {
01367
01368 lock->grantMask &= LOCKBIT_OFF(lockmode);
01369 }
01370
01371 LOCK_PRINT("UnGrantLock: updated", lock, lockmode);
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382 if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)
01383 wakeupNeeded = true;
01384
01385
01386
01387
01388 proclock->holdMask &= LOCKBIT_OFF(lockmode);
01389 PROCLOCK_PRINT("UnGrantLock: updated", proclock);
01390
01391 return wakeupNeeded;
01392 }
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404 static void
01405 CleanUpLock(LOCK *lock, PROCLOCK *proclock,
01406 LockMethod lockMethodTable, uint32 hashcode,
01407 bool wakeupNeeded)
01408 {
01409
01410
01411
01412
01413 if (proclock->holdMask == 0)
01414 {
01415 uint32 proclock_hashcode;
01416
01417 PROCLOCK_PRINT("CleanUpLock: deleting", proclock);
01418 SHMQueueDelete(&proclock->lockLink);
01419 SHMQueueDelete(&proclock->procLink);
01420 proclock_hashcode = ProcLockHashCode(&proclock->tag, hashcode);
01421 if (!hash_search_with_hash_value(LockMethodProcLockHash,
01422 (void *) &(proclock->tag),
01423 proclock_hashcode,
01424 HASH_REMOVE,
01425 NULL))
01426 elog(PANIC, "proclock table corrupted");
01427 }
01428
01429 if (lock->nRequested == 0)
01430 {
01431
01432
01433
01434
01435 LOCK_PRINT("CleanUpLock: deleting", lock, 0);
01436 Assert(SHMQueueEmpty(&(lock->procLocks)));
01437 if (!hash_search_with_hash_value(LockMethodLockHash,
01438 (void *) &(lock->tag),
01439 hashcode,
01440 HASH_REMOVE,
01441 NULL))
01442 elog(PANIC, "lock table corrupted");
01443 }
01444 else if (wakeupNeeded)
01445 {
01446
01447 ProcLockWakeup(lockMethodTable, lock);
01448 }
01449 }
01450
01451
01452
01453
01454
01455
01456
01457
01458 static void
01459 GrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner)
01460 {
01461 LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
01462 int i;
01463
01464 Assert(locallock->numLockOwners < locallock->maxLockOwners);
01465
01466 locallock->nLocks++;
01467
01468 for (i = 0; i < locallock->numLockOwners; i++)
01469 {
01470 if (lockOwners[i].owner == owner)
01471 {
01472 lockOwners[i].nLocks++;
01473 return;
01474 }
01475 }
01476 lockOwners[i].owner = owner;
01477 lockOwners[i].nLocks = 1;
01478 locallock->numLockOwners++;
01479 if (owner != NULL)
01480 ResourceOwnerRememberLock(owner, locallock);
01481 }
01482
01483
01484
01485
01486
01487 static void
01488 BeginStrongLockAcquire(LOCALLOCK *locallock, uint32 fasthashcode)
01489 {
01490 Assert(StrongLockInProgress == NULL);
01491 Assert(locallock->holdsStrongLockCount == FALSE);
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502 SpinLockAcquire(&FastPathStrongRelationLocks->mutex);
01503 FastPathStrongRelationLocks->count[fasthashcode]++;
01504 locallock->holdsStrongLockCount = TRUE;
01505 StrongLockInProgress = locallock;
01506 SpinLockRelease(&FastPathStrongRelationLocks->mutex);
01507 }
01508
01509
01510
01511
01512
01513 static void
01514 FinishStrongLockAcquire(void)
01515 {
01516 StrongLockInProgress = NULL;
01517 }
01518
01519
01520
01521
01522
01523 void
01524 AbortStrongLockAcquire(void)
01525 {
01526 uint32 fasthashcode;
01527 LOCALLOCK *locallock = StrongLockInProgress;
01528
01529 if (locallock == NULL)
01530 return;
01531
01532 fasthashcode = FastPathStrongLockHashPartition(locallock->hashcode);
01533 Assert(locallock->holdsStrongLockCount == TRUE);
01534 SpinLockAcquire(&FastPathStrongRelationLocks->mutex);
01535 FastPathStrongRelationLocks->count[fasthashcode]--;
01536 locallock->holdsStrongLockCount = FALSE;
01537 StrongLockInProgress = NULL;
01538 SpinLockRelease(&FastPathStrongRelationLocks->mutex);
01539 }
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551 void
01552 GrantAwaitedLock(void)
01553 {
01554 GrantLockLocal(awaitedLock, awaitedOwner);
01555 }
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565 static void
01566 WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
01567 {
01568 LOCKMETHODID lockmethodid = LOCALLOCK_LOCKMETHOD(*locallock);
01569 LockMethod lockMethodTable = LockMethods[lockmethodid];
01570 char *volatile new_status = NULL;
01571
01572 LOCK_PRINT("WaitOnLock: sleeping on lock",
01573 locallock->lock, locallock->tag.mode);
01574
01575
01576 if (update_process_title)
01577 {
01578 const char *old_status;
01579 int len;
01580
01581 old_status = get_ps_display(&len);
01582 new_status = (char *) palloc(len + 8 + 1);
01583 memcpy(new_status, old_status, len);
01584 strcpy(new_status + len, " waiting");
01585 set_ps_display(new_status, false);
01586 new_status[len] = '\0';
01587 }
01588 pgstat_report_waiting(true);
01589
01590 awaitedLock = locallock;
01591 awaitedOwner = owner;
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610 PG_TRY();
01611 {
01612 if (ProcSleep(locallock, lockMethodTable) != STATUS_OK)
01613 {
01614
01615
01616
01617
01618 awaitedLock = NULL;
01619 LOCK_PRINT("WaitOnLock: aborting on lock",
01620 locallock->lock, locallock->tag.mode);
01621 LWLockRelease(LockHashPartitionLock(locallock->hashcode));
01622
01623
01624
01625
01626
01627 DeadLockReport();
01628
01629 }
01630 }
01631 PG_CATCH();
01632 {
01633
01634
01635
01636 pgstat_report_waiting(false);
01637 if (update_process_title)
01638 {
01639 set_ps_display(new_status, false);
01640 pfree(new_status);
01641 }
01642
01643
01644 PG_RE_THROW();
01645 }
01646 PG_END_TRY();
01647
01648 awaitedLock = NULL;
01649
01650
01651 pgstat_report_waiting(false);
01652 if (update_process_title)
01653 {
01654 set_ps_display(new_status, false);
01655 pfree(new_status);
01656 }
01657
01658 LOCK_PRINT("WaitOnLock: wakeup on lock",
01659 locallock->lock, locallock->tag.mode);
01660 }
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672 void
01673 RemoveFromWaitQueue(PGPROC *proc, uint32 hashcode)
01674 {
01675 LOCK *waitLock = proc->waitLock;
01676 PROCLOCK *proclock = proc->waitProcLock;
01677 LOCKMODE lockmode = proc->waitLockMode;
01678 LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*waitLock);
01679
01680
01681 Assert(proc->waitStatus == STATUS_WAITING);
01682 Assert(proc->links.next != NULL);
01683 Assert(waitLock);
01684 Assert(waitLock->waitProcs.size > 0);
01685 Assert(0 < lockmethodid && lockmethodid < lengthof(LockMethods));
01686
01687
01688 SHMQueueDelete(&(proc->links));
01689 waitLock->waitProcs.size--;
01690
01691
01692 Assert(waitLock->nRequested > 0);
01693 Assert(waitLock->nRequested > proc->waitLock->nGranted);
01694 waitLock->nRequested--;
01695 Assert(waitLock->requested[lockmode] > 0);
01696 waitLock->requested[lockmode]--;
01697
01698 if (waitLock->granted[lockmode] == waitLock->requested[lockmode])
01699 waitLock->waitMask &= LOCKBIT_OFF(lockmode);
01700
01701
01702 proc->waitLock = NULL;
01703 proc->waitProcLock = NULL;
01704 proc->waitStatus = STATUS_ERROR;
01705
01706
01707
01708
01709
01710
01711
01712
01713 CleanUpLock(waitLock, proclock,
01714 LockMethods[lockmethodid], hashcode,
01715 true);
01716 }
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729 bool
01730 LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
01731 {
01732 LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
01733 LockMethod lockMethodTable;
01734 LOCALLOCKTAG localtag;
01735 LOCALLOCK *locallock;
01736 LOCK *lock;
01737 PROCLOCK *proclock;
01738 LWLockId partitionLock;
01739 bool wakeupNeeded;
01740
01741 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
01742 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
01743 lockMethodTable = LockMethods[lockmethodid];
01744 if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
01745 elog(ERROR, "unrecognized lock mode: %d", lockmode);
01746
01747 #ifdef LOCK_DEBUG
01748 if (LOCK_DEBUG_ENABLED(locktag))
01749 elog(LOG, "LockRelease: lock [%u,%u] %s",
01750 locktag->locktag_field1, locktag->locktag_field2,
01751 lockMethodTable->lockModeNames[lockmode]);
01752 #endif
01753
01754
01755
01756
01757 MemSet(&localtag, 0, sizeof(localtag));
01758 localtag.lock = *locktag;
01759 localtag.mode = lockmode;
01760
01761 locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,
01762 (void *) &localtag,
01763 HASH_FIND, NULL);
01764
01765
01766
01767
01768 if (!locallock || locallock->nLocks <= 0)
01769 {
01770 elog(WARNING, "you don't own a lock of type %s",
01771 lockMethodTable->lockModeNames[lockmode]);
01772 return FALSE;
01773 }
01774
01775
01776
01777
01778 {
01779 LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
01780 ResourceOwner owner;
01781 int i;
01782
01783
01784 if (sessionLock)
01785 owner = NULL;
01786 else
01787 owner = CurrentResourceOwner;
01788
01789 for (i = locallock->numLockOwners - 1; i >= 0; i--)
01790 {
01791 if (lockOwners[i].owner == owner)
01792 {
01793 Assert(lockOwners[i].nLocks > 0);
01794 if (--lockOwners[i].nLocks == 0)
01795 {
01796 if (owner != NULL)
01797 ResourceOwnerForgetLock(owner, locallock);
01798
01799 locallock->numLockOwners--;
01800 if (i < locallock->numLockOwners)
01801 lockOwners[i] = lockOwners[locallock->numLockOwners];
01802 }
01803 break;
01804 }
01805 }
01806 if (i < 0)
01807 {
01808
01809 elog(WARNING, "you don't own a lock of type %s",
01810 lockMethodTable->lockModeNames[lockmode]);
01811 return FALSE;
01812 }
01813 }
01814
01815
01816
01817
01818
01819 locallock->nLocks--;
01820
01821 if (locallock->nLocks > 0)
01822 return TRUE;
01823
01824
01825 if (EligibleForRelationFastPath(locktag, lockmode)
01826 && FastPathLocalUseCount > 0)
01827 {
01828 bool released;
01829
01830
01831
01832
01833
01834 LWLockAcquire(MyProc->backendLock, LW_EXCLUSIVE);
01835 released = FastPathUnGrantRelationLock(locktag->locktag_field2,
01836 lockmode);
01837 LWLockRelease(MyProc->backendLock);
01838 if (released)
01839 {
01840 RemoveLocalLock(locallock);
01841 return TRUE;
01842 }
01843 }
01844
01845
01846
01847
01848 partitionLock = LockHashPartitionLock(locallock->hashcode);
01849
01850 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
01851
01852
01853
01854
01855
01856
01857
01858
01859 lock = locallock->lock;
01860 if (!lock)
01861 {
01862 PROCLOCKTAG proclocktag;
01863 bool found;
01864
01865 Assert(EligibleForRelationFastPath(locktag, lockmode));
01866 lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
01867 (const void *) locktag,
01868 locallock->hashcode,
01869 HASH_FIND,
01870 &found);
01871 Assert(found && lock != NULL);
01872 locallock->lock = lock;
01873
01874 proclocktag.myLock = lock;
01875 proclocktag.myProc = MyProc;
01876 locallock->proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash,
01877 (void *) &proclocktag,
01878 HASH_FIND, &found);
01879 Assert(found);
01880 }
01881 LOCK_PRINT("LockRelease: found", lock, lockmode);
01882 proclock = locallock->proclock;
01883 PROCLOCK_PRINT("LockRelease: found", proclock);
01884
01885
01886
01887
01888
01889 if (!(proclock->holdMask & LOCKBIT_ON(lockmode)))
01890 {
01891 PROCLOCK_PRINT("LockRelease: WRONGTYPE", proclock);
01892 LWLockRelease(partitionLock);
01893 elog(WARNING, "you don't own a lock of type %s",
01894 lockMethodTable->lockModeNames[lockmode]);
01895 RemoveLocalLock(locallock);
01896 return FALSE;
01897 }
01898
01899
01900
01901
01902 wakeupNeeded = UnGrantLock(lock, lockmode, proclock, lockMethodTable);
01903
01904 CleanUpLock(lock, proclock,
01905 lockMethodTable, locallock->hashcode,
01906 wakeupNeeded);
01907
01908 LWLockRelease(partitionLock);
01909
01910 RemoveLocalLock(locallock);
01911 return TRUE;
01912 }
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922 void
01923 LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
01924 {
01925 HASH_SEQ_STATUS status;
01926 LockMethod lockMethodTable;
01927 int i,
01928 numLockModes;
01929 LOCALLOCK *locallock;
01930 LOCK *lock;
01931 PROCLOCK *proclock;
01932 int partition;
01933 bool have_fast_path_lwlock = false;
01934
01935 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
01936 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
01937 lockMethodTable = LockMethods[lockmethodid];
01938
01939 #ifdef LOCK_DEBUG
01940 if (*(lockMethodTable->trace_flag))
01941 elog(LOG, "LockReleaseAll: lockmethod=%d", lockmethodid);
01942 #endif
01943
01944
01945
01946
01947
01948
01949
01950 if (lockmethodid == DEFAULT_LOCKMETHOD)
01951 VirtualXactLockTableCleanup();
01952
01953 numLockModes = lockMethodTable->numLockModes;
01954
01955
01956
01957
01958
01959
01960
01961
01962 hash_seq_init(&status, LockMethodLocalHash);
01963
01964 while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
01965 {
01966
01967
01968
01969
01970
01971 if (locallock->nLocks == 0)
01972 {
01973 RemoveLocalLock(locallock);
01974 continue;
01975 }
01976
01977
01978 if (LOCALLOCK_LOCKMETHOD(*locallock) != lockmethodid)
01979 continue;
01980
01981
01982
01983
01984
01985
01986 if (!allLocks)
01987 {
01988 LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
01989
01990
01991 for (i = 0; i < locallock->numLockOwners ; i++)
01992 {
01993 if (lockOwners[i].owner == NULL)
01994 lockOwners[0] = lockOwners[i];
01995 else
01996 ResourceOwnerForgetLock(lockOwners[i].owner, locallock);
01997 }
01998
01999 if (locallock->numLockOwners > 0 &&
02000 lockOwners[0].owner == NULL &&
02001 lockOwners[0].nLocks > 0)
02002 {
02003
02004 locallock->nLocks = lockOwners[0].nLocks;
02005 locallock->numLockOwners = 1;
02006
02007 continue;
02008 }
02009 else
02010 locallock->numLockOwners = 0;
02011 }
02012
02013
02014
02015
02016
02017 if (locallock->proclock == NULL || locallock->lock == NULL)
02018 {
02019 LOCKMODE lockmode = locallock->tag.mode;
02020 Oid relid;
02021
02022
02023 if (!EligibleForRelationFastPath(&locallock->tag.lock, lockmode))
02024 elog(PANIC, "locallock table corrupted");
02025
02026
02027
02028
02029
02030
02031 if (!have_fast_path_lwlock)
02032 {
02033 LWLockAcquire(MyProc->backendLock, LW_EXCLUSIVE);
02034 have_fast_path_lwlock = true;
02035 }
02036
02037
02038 relid = locallock->tag.lock.locktag_field2;
02039 if (FastPathUnGrantRelationLock(relid, lockmode))
02040 {
02041 RemoveLocalLock(locallock);
02042 continue;
02043 }
02044
02045
02046
02047
02048
02049
02050 LWLockRelease(MyProc->backendLock);
02051 have_fast_path_lwlock = false;
02052
02053
02054
02055
02056
02057
02058
02059
02060 LockRefindAndRelease(lockMethodTable, MyProc,
02061 &locallock->tag.lock, lockmode, false);
02062 RemoveLocalLock(locallock);
02063 continue;
02064 }
02065
02066
02067 if (locallock->nLocks > 0)
02068 locallock->proclock->releaseMask |= LOCKBIT_ON(locallock->tag.mode);
02069
02070
02071 RemoveLocalLock(locallock);
02072 }
02073
02074 if (have_fast_path_lwlock)
02075 LWLockRelease(MyProc->backendLock);
02076
02077
02078
02079
02080 for (partition = 0; partition < NUM_LOCK_PARTITIONS; partition++)
02081 {
02082 LWLockId partitionLock = FirstLockMgrLock + partition;
02083 SHM_QUEUE *procLocks = &(MyProc->myProcLocks[partition]);
02084
02085 proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
02086 offsetof(PROCLOCK, procLink));
02087
02088 if (!proclock)
02089 continue;
02090
02091 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
02092
02093 while (proclock)
02094 {
02095 bool wakeupNeeded = false;
02096 PROCLOCK *nextplock;
02097
02098
02099 nextplock = (PROCLOCK *)
02100 SHMQueueNext(procLocks, &proclock->procLink,
02101 offsetof(PROCLOCK, procLink));
02102
02103 Assert(proclock->tag.myProc == MyProc);
02104
02105 lock = proclock->tag.myLock;
02106
02107
02108 if (LOCK_LOCKMETHOD(*lock) != lockmethodid)
02109 goto next_item;
02110
02111
02112
02113
02114
02115 if (allLocks)
02116 proclock->releaseMask = proclock->holdMask;
02117 else
02118 Assert((proclock->releaseMask & ~proclock->holdMask) == 0);
02119
02120
02121
02122
02123
02124 if (proclock->releaseMask == 0 && proclock->holdMask != 0)
02125 goto next_item;
02126
02127 PROCLOCK_PRINT("LockReleaseAll", proclock);
02128 LOCK_PRINT("LockReleaseAll", lock, 0);
02129 Assert(lock->nRequested >= 0);
02130 Assert(lock->nGranted >= 0);
02131 Assert(lock->nGranted <= lock->nRequested);
02132 Assert((proclock->holdMask & ~lock->grantMask) == 0);
02133
02134
02135
02136
02137 for (i = 1; i <= numLockModes; i++)
02138 {
02139 if (proclock->releaseMask & LOCKBIT_ON(i))
02140 wakeupNeeded |= UnGrantLock(lock, i, proclock,
02141 lockMethodTable);
02142 }
02143 Assert((lock->nRequested >= 0) && (lock->nGranted >= 0));
02144 Assert(lock->nGranted <= lock->nRequested);
02145 LOCK_PRINT("LockReleaseAll: updated", lock, 0);
02146
02147 proclock->releaseMask = 0;
02148
02149
02150 CleanUpLock(lock, proclock,
02151 lockMethodTable,
02152 LockTagHashCode(&lock->tag),
02153 wakeupNeeded);
02154
02155 next_item:
02156 proclock = nextplock;
02157 }
02158
02159 LWLockRelease(partitionLock);
02160 }
02161
02162 #ifdef LOCK_DEBUG
02163 if (*(lockMethodTable->trace_flag))
02164 elog(LOG, "LockReleaseAll done");
02165 #endif
02166 }
02167
02168
02169
02170
02171
02172 void
02173 LockReleaseSession(LOCKMETHODID lockmethodid)
02174 {
02175 HASH_SEQ_STATUS status;
02176 LOCALLOCK *locallock;
02177
02178 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
02179 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
02180
02181 hash_seq_init(&status, LockMethodLocalHash);
02182
02183 while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
02184 {
02185
02186 if (LOCALLOCK_LOCKMETHOD(*locallock) != lockmethodid)
02187 continue;
02188
02189 ReleaseLockIfHeld(locallock, true);
02190 }
02191 }
02192
02193
02194
02195
02196
02197
02198
02199
02200
02201
02202 void
02203 LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks)
02204 {
02205 if (locallocks == NULL)
02206 {
02207 HASH_SEQ_STATUS status;
02208 LOCALLOCK *locallock;
02209
02210 hash_seq_init(&status, LockMethodLocalHash);
02211
02212 while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
02213 ReleaseLockIfHeld(locallock, false);
02214 }
02215 else
02216 {
02217 int i;
02218
02219 for (i = nlocks - 1; i >= 0; i--)
02220 ReleaseLockIfHeld(locallocks[i], false);
02221 }
02222 }
02223
02224
02225
02226
02227
02228
02229
02230
02231
02232
02233
02234
02235
02236
02237 static void
02238 ReleaseLockIfHeld(LOCALLOCK *locallock, bool sessionLock)
02239 {
02240 ResourceOwner owner;
02241 LOCALLOCKOWNER *lockOwners;
02242 int i;
02243
02244
02245 if (sessionLock)
02246 owner = NULL;
02247 else
02248 owner = CurrentResourceOwner;
02249
02250
02251 lockOwners = locallock->lockOwners;
02252 for (i = locallock->numLockOwners - 1; i >= 0; i--)
02253 {
02254 if (lockOwners[i].owner == owner)
02255 {
02256 Assert(lockOwners[i].nLocks > 0);
02257 if (lockOwners[i].nLocks < locallock->nLocks)
02258 {
02259
02260
02261
02262
02263 locallock->nLocks -= lockOwners[i].nLocks;
02264
02265 locallock->numLockOwners--;
02266 if (owner != NULL)
02267 ResourceOwnerForgetLock(owner, locallock);
02268 if (i < locallock->numLockOwners)
02269 lockOwners[i] = lockOwners[locallock->numLockOwners];
02270 }
02271 else
02272 {
02273 Assert(lockOwners[i].nLocks == locallock->nLocks);
02274
02275 lockOwners[i].nLocks = 1;
02276 locallock->nLocks = 1;
02277 if (!LockRelease(&locallock->tag.lock,
02278 locallock->tag.mode,
02279 sessionLock))
02280 elog(WARNING, "ReleaseLockIfHeld: failed??");
02281 }
02282 break;
02283 }
02284 }
02285 }
02286
02287
02288
02289
02290
02291
02292
02293
02294
02295
02296
02297 void
02298 LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks)
02299 {
02300 ResourceOwner parent = ResourceOwnerGetParent(CurrentResourceOwner);
02301
02302 Assert(parent != NULL);
02303
02304 if (locallocks == NULL)
02305 {
02306 HASH_SEQ_STATUS status;
02307 LOCALLOCK *locallock;
02308
02309 hash_seq_init(&status, LockMethodLocalHash);
02310
02311 while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
02312 LockReassignOwner(locallock, parent);
02313 }
02314 else
02315 {
02316 int i;
02317
02318 for (i = nlocks - 1; i >= 0; i--)
02319 LockReassignOwner(locallocks[i], parent);
02320 }
02321 }
02322
02323
02324
02325
02326
02327 static void
02328 LockReassignOwner(LOCALLOCK *locallock, ResourceOwner parent)
02329 {
02330 LOCALLOCKOWNER *lockOwners;
02331 int i;
02332 int ic = -1;
02333 int ip = -1;
02334
02335
02336
02337
02338
02339 lockOwners = locallock->lockOwners;
02340 for (i = locallock->numLockOwners - 1; i >= 0; i--)
02341 {
02342 if (lockOwners[i].owner == CurrentResourceOwner)
02343 ic = i;
02344 else if (lockOwners[i].owner == parent)
02345 ip = i;
02346 }
02347
02348 if (ic < 0)
02349 return;
02350
02351 if (ip < 0)
02352 {
02353
02354 lockOwners[ic].owner = parent;
02355 ResourceOwnerRememberLock(parent, locallock);
02356 }
02357 else
02358 {
02359
02360 lockOwners[ip].nLocks += lockOwners[ic].nLocks;
02361
02362 locallock->numLockOwners--;
02363 if (ic < locallock->numLockOwners)
02364 lockOwners[ic] = lockOwners[locallock->numLockOwners];
02365 }
02366 ResourceOwnerForgetLock(CurrentResourceOwner, locallock);
02367 }
02368
02369
02370
02371
02372
02373 static bool
02374 FastPathGrantRelationLock(Oid relid, LOCKMODE lockmode)
02375 {
02376 uint32 f;
02377 uint32 unused_slot = FP_LOCK_SLOTS_PER_BACKEND;
02378
02379
02380 for (f = 0; f < FP_LOCK_SLOTS_PER_BACKEND; f++)
02381 {
02382 if (FAST_PATH_GET_BITS(MyProc, f) == 0)
02383 unused_slot = f;
02384 else if (MyProc->fpRelId[f] == relid)
02385 {
02386 Assert(!FAST_PATH_CHECK_LOCKMODE(MyProc, f, lockmode));
02387 FAST_PATH_SET_LOCKMODE(MyProc, f, lockmode);
02388 return true;
02389 }
02390 }
02391
02392
02393 if (unused_slot < FP_LOCK_SLOTS_PER_BACKEND)
02394 {
02395 MyProc->fpRelId[unused_slot] = relid;
02396 FAST_PATH_SET_LOCKMODE(MyProc, unused_slot, lockmode);
02397 ++FastPathLocalUseCount;
02398 return true;
02399 }
02400
02401
02402 return false;
02403 }
02404
02405
02406
02407
02408
02409
02410 static bool
02411 FastPathUnGrantRelationLock(Oid relid, LOCKMODE lockmode)
02412 {
02413 uint32 f;
02414 bool result = false;
02415
02416 FastPathLocalUseCount = 0;
02417 for (f = 0; f < FP_LOCK_SLOTS_PER_BACKEND; f++)
02418 {
02419 if (MyProc->fpRelId[f] == relid
02420 && FAST_PATH_CHECK_LOCKMODE(MyProc, f, lockmode))
02421 {
02422 Assert(!result);
02423 FAST_PATH_CLEAR_LOCKMODE(MyProc, f, lockmode);
02424 result = true;
02425 }
02426 if (FAST_PATH_GET_BITS(MyProc, f) != 0)
02427 ++FastPathLocalUseCount;
02428 }
02429 return result;
02430 }
02431
02432
02433
02434
02435
02436
02437
02438
02439 static bool
02440 FastPathTransferRelationLocks(LockMethod lockMethodTable, const LOCKTAG *locktag,
02441 uint32 hashcode)
02442 {
02443 LWLockId partitionLock = LockHashPartitionLock(hashcode);
02444 Oid relid = locktag->locktag_field2;
02445 uint32 i;
02446
02447
02448
02449
02450
02451
02452
02453 for (i = 0; i < ProcGlobal->allProcCount; i++)
02454 {
02455 PGPROC *proc = &ProcGlobal->allProcs[i];
02456 uint32 f;
02457
02458 LWLockAcquire(proc->backendLock, LW_EXCLUSIVE);
02459
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472
02473
02474
02475 if (proc->databaseId != locktag->locktag_field1)
02476 {
02477 LWLockRelease(proc->backendLock);
02478 continue;
02479 }
02480
02481 for (f = 0; f < FP_LOCK_SLOTS_PER_BACKEND; f++)
02482 {
02483 uint32 lockmode;
02484
02485
02486 if (relid != proc->fpRelId[f] || FAST_PATH_GET_BITS(proc, f) == 0)
02487 continue;
02488
02489
02490 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
02491 for (lockmode = FAST_PATH_LOCKNUMBER_OFFSET;
02492 lockmode < FAST_PATH_LOCKNUMBER_OFFSET + FAST_PATH_BITS_PER_SLOT;
02493 ++lockmode)
02494 {
02495 PROCLOCK *proclock;
02496
02497 if (!FAST_PATH_CHECK_LOCKMODE(proc, f, lockmode))
02498 continue;
02499 proclock = SetupLockInTable(lockMethodTable, proc, locktag,
02500 hashcode, lockmode);
02501 if (!proclock)
02502 {
02503 LWLockRelease(partitionLock);
02504 return false;
02505 }
02506 GrantLock(proclock->tag.myLock, proclock, lockmode);
02507 FAST_PATH_CLEAR_LOCKMODE(proc, f, lockmode);
02508 }
02509 LWLockRelease(partitionLock);
02510 }
02511 LWLockRelease(proc->backendLock);
02512 }
02513 return true;
02514 }
02515
02516
02517
02518
02519
02520
02521 static PROCLOCK *
02522 FastPathGetRelationLockEntry(LOCALLOCK *locallock)
02523 {
02524 LockMethod lockMethodTable = LockMethods[DEFAULT_LOCKMETHOD];
02525 LOCKTAG *locktag = &locallock->tag.lock;
02526 PROCLOCK *proclock = NULL;
02527 LWLockId partitionLock = LockHashPartitionLock(locallock->hashcode);
02528 Oid relid = locktag->locktag_field2;
02529 uint32 f;
02530
02531 LWLockAcquire(MyProc->backendLock, LW_EXCLUSIVE);
02532
02533 for (f = 0; f < FP_LOCK_SLOTS_PER_BACKEND; f++)
02534 {
02535 uint32 lockmode;
02536
02537
02538 if (relid != MyProc->fpRelId[f] || FAST_PATH_GET_BITS(MyProc, f) == 0)
02539 continue;
02540
02541
02542 lockmode = locallock->tag.mode;
02543 if (!FAST_PATH_CHECK_LOCKMODE(MyProc, f, lockmode))
02544 break;
02545
02546
02547 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
02548
02549 proclock = SetupLockInTable(lockMethodTable, MyProc, locktag,
02550 locallock->hashcode, lockmode);
02551 if (!proclock)
02552 {
02553 LWLockRelease(partitionLock);
02554 ereport(ERROR,
02555 (errcode(ERRCODE_OUT_OF_MEMORY),
02556 errmsg("out of shared memory"),
02557 errhint("You might need to increase max_locks_per_transaction.")));
02558 }
02559 GrantLock(proclock->tag.myLock, proclock, lockmode);
02560 FAST_PATH_CLEAR_LOCKMODE(MyProc, f, lockmode);
02561
02562 LWLockRelease(partitionLock);
02563 }
02564
02565 LWLockRelease(MyProc->backendLock);
02566
02567
02568 if (proclock == NULL)
02569 {
02570 LOCK *lock;
02571 PROCLOCKTAG proclocktag;
02572 uint32 proclock_hashcode;
02573
02574 LWLockAcquire(partitionLock, LW_SHARED);
02575
02576 lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
02577 (void *) locktag,
02578 locallock->hashcode,
02579 HASH_FIND,
02580 NULL);
02581 if (!lock)
02582 elog(ERROR, "failed to re-find shared lock object");
02583
02584 proclocktag.myLock = lock;
02585 proclocktag.myProc = MyProc;
02586
02587 proclock_hashcode = ProcLockHashCode(&proclocktag, locallock->hashcode);
02588 proclock = (PROCLOCK *)
02589 hash_search_with_hash_value(LockMethodProcLockHash,
02590 (void *) &proclocktag,
02591 proclock_hashcode,
02592 HASH_FIND,
02593 NULL);
02594 if (!proclock)
02595 elog(ERROR, "failed to re-find shared proclock object");
02596 LWLockRelease(partitionLock);
02597 }
02598
02599 return proclock;
02600 }
02601
02602
02603
02604
02605
02606
02607
02608
02609
02610
02611
02612
02613
02614
02615
02616
02617
02618 VirtualTransactionId *
02619 GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
02620 {
02621 static VirtualTransactionId *vxids;
02622 LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
02623 LockMethod lockMethodTable;
02624 LOCK *lock;
02625 LOCKMASK conflictMask;
02626 SHM_QUEUE *procLocks;
02627 PROCLOCK *proclock;
02628 uint32 hashcode;
02629 LWLockId partitionLock;
02630 int count = 0;
02631 int fast_count = 0;
02632
02633 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
02634 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
02635 lockMethodTable = LockMethods[lockmethodid];
02636 if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
02637 elog(ERROR, "unrecognized lock mode: %d", lockmode);
02638
02639
02640
02641
02642
02643
02644 if (InHotStandby)
02645 {
02646 if (vxids == NULL)
02647 vxids = (VirtualTransactionId *)
02648 MemoryContextAlloc(TopMemoryContext,
02649 sizeof(VirtualTransactionId) * (MaxBackends + 1));
02650 }
02651 else
02652 vxids = (VirtualTransactionId *)
02653 palloc0(sizeof(VirtualTransactionId) * (MaxBackends + 1));
02654
02655
02656 hashcode = LockTagHashCode(locktag);
02657 partitionLock = LockHashPartitionLock(hashcode);
02658 conflictMask = lockMethodTable->conflictTab[lockmode];
02659
02660
02661
02662
02663
02664
02665 if (ConflictsWithRelationFastPath(locktag, lockmode))
02666 {
02667 int i;
02668 Oid relid = locktag->locktag_field2;
02669 VirtualTransactionId vxid;
02670
02671
02672
02673
02674
02675
02676
02677
02678
02679
02680
02681 for (i = 0; i < ProcGlobal->allProcCount; i++)
02682 {
02683 PGPROC *proc = &ProcGlobal->allProcs[i];
02684 uint32 f;
02685
02686
02687 if (proc == MyProc)
02688 continue;
02689
02690 LWLockAcquire(proc->backendLock, LW_SHARED);
02691
02692
02693
02694
02695
02696
02697
02698
02699
02700 if (proc->databaseId != locktag->locktag_field1)
02701 {
02702 LWLockRelease(proc->backendLock);
02703 continue;
02704 }
02705
02706 for (f = 0; f < FP_LOCK_SLOTS_PER_BACKEND; f++)
02707 {
02708 uint32 lockmask;
02709
02710
02711 if (relid != proc->fpRelId[f])
02712 continue;
02713 lockmask = FAST_PATH_GET_BITS(proc, f);
02714 if (!lockmask)
02715 continue;
02716 lockmask <<= FAST_PATH_LOCKNUMBER_OFFSET;
02717
02718
02719
02720
02721
02722 if ((lockmask & conflictMask) == 0)
02723 break;
02724
02725
02726 GET_VXID_FROM_PGPROC(vxid, *proc);
02727
02728
02729
02730
02731
02732
02733 if (VirtualTransactionIdIsValid(vxid))
02734 vxids[count++] = vxid;
02735 break;
02736 }
02737
02738 LWLockRelease(proc->backendLock);
02739 }
02740 }
02741
02742
02743 fast_count = count;
02744
02745
02746
02747
02748 LWLockAcquire(partitionLock, LW_SHARED);
02749
02750 lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
02751 (const void *) locktag,
02752 hashcode,
02753 HASH_FIND,
02754 NULL);
02755 if (!lock)
02756 {
02757
02758
02759
02760
02761 LWLockRelease(partitionLock);
02762 return vxids;
02763 }
02764
02765
02766
02767
02768
02769 procLocks = &(lock->procLocks);
02770
02771 proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
02772 offsetof(PROCLOCK, lockLink));
02773
02774 while (proclock)
02775 {
02776 if (conflictMask & proclock->holdMask)
02777 {
02778 PGPROC *proc = proclock->tag.myProc;
02779
02780
02781 if (proc != MyProc)
02782 {
02783 VirtualTransactionId vxid;
02784
02785 GET_VXID_FROM_PGPROC(vxid, *proc);
02786
02787
02788
02789
02790
02791
02792 if (VirtualTransactionIdIsValid(vxid))
02793 {
02794 int i;
02795
02796
02797 for (i = 0; i < fast_count; ++i)
02798 if (VirtualTransactionIdEquals(vxids[i], vxid))
02799 break;
02800 if (i >= fast_count)
02801 vxids[count++] = vxid;
02802 }
02803 }
02804 }
02805
02806 proclock = (PROCLOCK *) SHMQueueNext(procLocks, &proclock->lockLink,
02807 offsetof(PROCLOCK, lockLink));
02808 }
02809
02810 LWLockRelease(partitionLock);
02811
02812 if (count > MaxBackends)
02813 elog(PANIC, "too many conflicting locks found");
02814
02815 return vxids;
02816 }
02817
02818
02819
02820
02821
02822
02823
02824
02825
02826
02827
02828
02829 static void
02830 LockRefindAndRelease(LockMethod lockMethodTable, PGPROC *proc,
02831 LOCKTAG *locktag, LOCKMODE lockmode,
02832 bool decrement_strong_lock_count)
02833 {
02834 LOCK *lock;
02835 PROCLOCK *proclock;
02836 PROCLOCKTAG proclocktag;
02837 uint32 hashcode;
02838 uint32 proclock_hashcode;
02839 LWLockId partitionLock;
02840 bool wakeupNeeded;
02841
02842 hashcode = LockTagHashCode(locktag);
02843 partitionLock = LockHashPartitionLock(hashcode);
02844
02845 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
02846
02847
02848
02849
02850 lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
02851 (void *) locktag,
02852 hashcode,
02853 HASH_FIND,
02854 NULL);
02855 if (!lock)
02856 elog(PANIC, "failed to re-find shared lock object");
02857
02858
02859
02860
02861 proclocktag.myLock = lock;
02862 proclocktag.myProc = proc;
02863
02864 proclock_hashcode = ProcLockHashCode(&proclocktag, hashcode);
02865
02866 proclock = (PROCLOCK *) hash_search_with_hash_value(LockMethodProcLockHash,
02867 (void *) &proclocktag,
02868 proclock_hashcode,
02869 HASH_FIND,
02870 NULL);
02871 if (!proclock)
02872 elog(PANIC, "failed to re-find shared proclock object");
02873
02874
02875
02876
02877
02878 if (!(proclock->holdMask & LOCKBIT_ON(lockmode)))
02879 {
02880 PROCLOCK_PRINT("lock_twophase_postcommit: WRONGTYPE", proclock);
02881 LWLockRelease(partitionLock);
02882 elog(WARNING, "you don't own a lock of type %s",
02883 lockMethodTable->lockModeNames[lockmode]);
02884 return;
02885 }
02886
02887
02888
02889
02890 wakeupNeeded = UnGrantLock(lock, lockmode, proclock, lockMethodTable);
02891
02892 CleanUpLock(lock, proclock,
02893 lockMethodTable, hashcode,
02894 wakeupNeeded);
02895
02896 LWLockRelease(partitionLock);
02897
02898
02899
02900
02901 if (decrement_strong_lock_count
02902 && ConflictsWithRelationFastPath(&lock->tag, lockmode))
02903 {
02904 uint32 fasthashcode = FastPathStrongLockHashPartition(hashcode);
02905
02906 SpinLockAcquire(&FastPathStrongRelationLocks->mutex);
02907 FastPathStrongRelationLocks->count[fasthashcode]--;
02908 SpinLockRelease(&FastPathStrongRelationLocks->mutex);
02909 }
02910 }
02911
02912
02913
02914
02915
02916
02917
02918
02919
02920
02921
02922
02923
02924
02925 void
02926 AtPrepare_Locks(void)
02927 {
02928 HASH_SEQ_STATUS status;
02929 LOCALLOCK *locallock;
02930
02931
02932
02933
02934
02935
02936
02937 hash_seq_init(&status, LockMethodLocalHash);
02938
02939 while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
02940 {
02941 TwoPhaseLockRecord record;
02942 LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
02943 bool haveSessionLock;
02944 bool haveXactLock;
02945 int i;
02946
02947
02948
02949
02950
02951 if (locallock->tag.lock.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
02952 continue;
02953
02954
02955 if (locallock->nLocks <= 0)
02956 continue;
02957
02958
02959 haveSessionLock = haveXactLock = false;
02960 for (i = locallock->numLockOwners - 1; i >= 0; i--)
02961 {
02962 if (lockOwners[i].owner == NULL)
02963 haveSessionLock = true;
02964 else
02965 haveXactLock = true;
02966 }
02967
02968
02969 if (!haveXactLock)
02970 continue;
02971
02972
02973
02974
02975
02976
02977
02978
02979
02980
02981
02982
02983
02984
02985 if (haveSessionLock)
02986 ereport(ERROR,
02987 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02988 errmsg("cannot PREPARE while holding both session-level and transaction-level locks on the same object")));
02989
02990
02991
02992
02993
02994
02995
02996 if (locallock->proclock == NULL)
02997 {
02998 locallock->proclock = FastPathGetRelationLockEntry(locallock);
02999 locallock->lock = locallock->proclock->tag.myLock;
03000 }
03001
03002
03003
03004
03005
03006
03007 locallock->holdsStrongLockCount = FALSE;
03008
03009
03010
03011
03012 memcpy(&(record.locktag), &(locallock->tag.lock), sizeof(LOCKTAG));
03013 record.lockmode = locallock->tag.mode;
03014
03015 RegisterTwoPhaseRecord(TWOPHASE_RM_LOCK_ID, 0,
03016 &record, sizeof(TwoPhaseLockRecord));
03017 }
03018 }
03019
03020
03021
03022
03023
03024
03025
03026
03027
03028
03029
03030
03031
03032
03033
03034
03035 void
03036 PostPrepare_Locks(TransactionId xid)
03037 {
03038 PGPROC *newproc = TwoPhaseGetDummyProc(xid);
03039 HASH_SEQ_STATUS status;
03040 LOCALLOCK *locallock;
03041 LOCK *lock;
03042 PROCLOCK *proclock;
03043 PROCLOCKTAG proclocktag;
03044 int partition;
03045
03046
03047 START_CRIT_SECTION();
03048
03049
03050
03051
03052
03053
03054
03055
03056
03057
03058 hash_seq_init(&status, LockMethodLocalHash);
03059
03060 while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
03061 {
03062 LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
03063 bool haveSessionLock;
03064 bool haveXactLock;
03065 int i;
03066
03067 if (locallock->proclock == NULL || locallock->lock == NULL)
03068 {
03069
03070
03071
03072
03073 Assert(locallock->nLocks == 0);
03074 RemoveLocalLock(locallock);
03075 continue;
03076 }
03077
03078
03079 if (locallock->tag.lock.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
03080 continue;
03081
03082
03083 haveSessionLock = haveXactLock = false;
03084 for (i = locallock->numLockOwners - 1; i >= 0; i--)
03085 {
03086 if (lockOwners[i].owner == NULL)
03087 haveSessionLock = true;
03088 else
03089 haveXactLock = true;
03090 }
03091
03092
03093 if (!haveXactLock)
03094 continue;
03095
03096
03097 if (haveSessionLock)
03098 ereport(PANIC,
03099 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
03100 errmsg("cannot PREPARE while holding both session-level and transaction-level locks on the same object")));
03101
03102
03103 if (locallock->nLocks > 0)
03104 locallock->proclock->releaseMask |= LOCKBIT_ON(locallock->tag.mode);
03105
03106
03107 RemoveLocalLock(locallock);
03108 }
03109
03110
03111
03112
03113 for (partition = 0; partition < NUM_LOCK_PARTITIONS; partition++)
03114 {
03115 LWLockId partitionLock = FirstLockMgrLock + partition;
03116 SHM_QUEUE *procLocks = &(MyProc->myProcLocks[partition]);
03117
03118 proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
03119 offsetof(PROCLOCK, procLink));
03120
03121 if (!proclock)
03122 continue;
03123
03124 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
03125
03126 while (proclock)
03127 {
03128 PROCLOCK *nextplock;
03129
03130
03131 nextplock = (PROCLOCK *)
03132 SHMQueueNext(procLocks, &proclock->procLink,
03133 offsetof(PROCLOCK, procLink));
03134
03135 Assert(proclock->tag.myProc == MyProc);
03136
03137 lock = proclock->tag.myLock;
03138
03139
03140 if (lock->tag.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
03141 goto next_item;
03142
03143 PROCLOCK_PRINT("PostPrepare_Locks", proclock);
03144 LOCK_PRINT("PostPrepare_Locks", lock, 0);
03145 Assert(lock->nRequested >= 0);
03146 Assert(lock->nGranted >= 0);
03147 Assert(lock->nGranted <= lock->nRequested);
03148 Assert((proclock->holdMask & ~lock->grantMask) == 0);
03149
03150
03151 if (proclock->releaseMask == 0)
03152 goto next_item;
03153
03154
03155 if (proclock->releaseMask != proclock->holdMask)
03156 elog(PANIC, "we seem to have dropped a bit somewhere");
03157
03158
03159
03160
03161
03162
03163
03164
03165
03166
03167
03168
03169
03170
03171 SHMQueueDelete(&proclock->procLink);
03172
03173
03174
03175
03176 proclocktag.myLock = lock;
03177 proclocktag.myProc = newproc;
03178
03179
03180
03181
03182
03183
03184 if (!hash_update_hash_key(LockMethodProcLockHash,
03185 (void *) proclock,
03186 (void *) &proclocktag))
03187 elog(PANIC, "duplicate entry found while reassigning a prepared transaction's locks");
03188
03189
03190 SHMQueueInsertBefore(&(newproc->myProcLocks[partition]),
03191 &proclock->procLink);
03192
03193 PROCLOCK_PRINT("PostPrepare_Locks: updated", proclock);
03194
03195 next_item:
03196 proclock = nextplock;
03197 }
03198
03199 LWLockRelease(partitionLock);
03200 }
03201
03202 END_CRIT_SECTION();
03203 }
03204
03205
03206
03207
03208
03209 Size
03210 LockShmemSize(void)
03211 {
03212 Size size = 0;
03213 long max_table_size;
03214
03215
03216 max_table_size = NLOCKENTS();
03217 size = add_size(size, hash_estimate_size(max_table_size, sizeof(LOCK)));
03218
03219
03220 max_table_size *= 2;
03221 size = add_size(size, hash_estimate_size(max_table_size, sizeof(PROCLOCK)));
03222
03223
03224
03225
03226 size = add_size(size, size / 10);
03227
03228 return size;
03229 }
03230
03231
03232
03233
03234
03235
03236
03237
03238
03239
03240
03241
03242
03243
03244
03245 LockData *
03246 GetLockStatusData(void)
03247 {
03248 LockData *data;
03249 PROCLOCK *proclock;
03250 HASH_SEQ_STATUS seqstat;
03251 int els;
03252 int el;
03253 int i;
03254
03255 data = (LockData *) palloc(sizeof(LockData));
03256
03257
03258 els = MaxBackends;
03259 el = 0;
03260 data->locks = (LockInstanceData *) palloc(sizeof(LockInstanceData) * els);
03261
03262
03263
03264
03265
03266
03267
03268
03269
03270
03271 for (i = 0; i < ProcGlobal->allProcCount; ++i)
03272 {
03273 PGPROC *proc = &ProcGlobal->allProcs[i];
03274 uint32 f;
03275
03276 LWLockAcquire(proc->backendLock, LW_SHARED);
03277
03278 for (f = 0; f < FP_LOCK_SLOTS_PER_BACKEND; ++f)
03279 {
03280 LockInstanceData *instance;
03281 uint32 lockbits = FAST_PATH_GET_BITS(proc, f);
03282
03283
03284 if (!lockbits)
03285 continue;
03286
03287 if (el >= els)
03288 {
03289 els += MaxBackends;
03290 data->locks = (LockInstanceData *)
03291 repalloc(data->locks, sizeof(LockInstanceData) * els);
03292 }
03293
03294 instance = &data->locks[el];
03295 SET_LOCKTAG_RELATION(instance->locktag, proc->databaseId,
03296 proc->fpRelId[f]);
03297 instance->holdMask = lockbits << FAST_PATH_LOCKNUMBER_OFFSET;
03298 instance->waitLockMode = NoLock;
03299 instance->backend = proc->backendId;
03300 instance->lxid = proc->lxid;
03301 instance->pid = proc->pid;
03302 instance->fastpath = true;
03303
03304 el++;
03305 }
03306
03307 if (proc->fpVXIDLock)
03308 {
03309 VirtualTransactionId vxid;
03310 LockInstanceData *instance;
03311
03312 if (el >= els)
03313 {
03314 els += MaxBackends;
03315 data->locks = (LockInstanceData *)
03316 repalloc(data->locks, sizeof(LockInstanceData) * els);
03317 }
03318
03319 vxid.backendId = proc->backendId;
03320 vxid.localTransactionId = proc->fpLocalTransactionId;
03321
03322 instance = &data->locks[el];
03323 SET_LOCKTAG_VIRTUALTRANSACTION(instance->locktag, vxid);
03324 instance->holdMask = LOCKBIT_ON(ExclusiveLock);
03325 instance->waitLockMode = NoLock;
03326 instance->backend = proc->backendId;
03327 instance->lxid = proc->lxid;
03328 instance->pid = proc->pid;
03329 instance->fastpath = true;
03330
03331 el++;
03332 }
03333
03334 LWLockRelease(proc->backendLock);
03335 }
03336
03337
03338
03339
03340
03341
03342
03343
03344
03345
03346
03347
03348
03349
03350 for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
03351 LWLockAcquire(FirstLockMgrLock + i, LW_SHARED);
03352
03353
03354 data->nelements = el + hash_get_num_entries(LockMethodProcLockHash);
03355 if (data->nelements > els)
03356 {
03357 els = data->nelements;
03358 data->locks = (LockInstanceData *)
03359 repalloc(data->locks, sizeof(LockInstanceData) * els);
03360 }
03361
03362
03363 hash_seq_init(&seqstat, LockMethodProcLockHash);
03364
03365 while ((proclock = (PROCLOCK *) hash_seq_search(&seqstat)))
03366 {
03367 PGPROC *proc = proclock->tag.myProc;
03368 LOCK *lock = proclock->tag.myLock;
03369 LockInstanceData *instance = &data->locks[el];
03370
03371 memcpy(&instance->locktag, &lock->tag, sizeof(LOCKTAG));
03372 instance->holdMask = proclock->holdMask;
03373 if (proc->waitLock == proclock->tag.myLock)
03374 instance->waitLockMode = proc->waitLockMode;
03375 else
03376 instance->waitLockMode = NoLock;
03377 instance->backend = proc->backendId;
03378 instance->lxid = proc->lxid;
03379 instance->pid = proc->pid;
03380 instance->fastpath = false;
03381
03382 el++;
03383 }
03384
03385
03386
03387
03388
03389
03390
03391
03392 for (i = NUM_LOCK_PARTITIONS; --i >= 0;)
03393 LWLockRelease(FirstLockMgrLock + i);
03394
03395 Assert(el == data->nelements);
03396
03397 return data;
03398 }
03399
03400
03401
03402
03403
03404 xl_standby_lock *
03405 GetRunningTransactionLocks(int *nlocks)
03406 {
03407 PROCLOCK *proclock;
03408 HASH_SEQ_STATUS seqstat;
03409 int i;
03410 int index;
03411 int els;
03412 xl_standby_lock *accessExclusiveLocks;
03413
03414
03415
03416
03417
03418
03419 for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
03420 LWLockAcquire(FirstLockMgrLock + i, LW_SHARED);
03421
03422
03423 els = hash_get_num_entries(LockMethodProcLockHash);
03424
03425
03426
03427
03428
03429 accessExclusiveLocks = palloc(els * sizeof(xl_standby_lock));
03430
03431
03432 hash_seq_init(&seqstat, LockMethodProcLockHash);
03433
03434
03435
03436
03437
03438
03439
03440
03441 index = 0;
03442 while ((proclock = (PROCLOCK *) hash_seq_search(&seqstat)))
03443 {
03444
03445 if ((proclock->holdMask & LOCKBIT_ON(AccessExclusiveLock)) &&
03446 proclock->tag.myLock->tag.locktag_type == LOCKTAG_RELATION)
03447 {
03448 PGPROC *proc = proclock->tag.myProc;
03449 PGXACT *pgxact = &ProcGlobal->allPgXact[proc->pgprocno];
03450 LOCK *lock = proclock->tag.myLock;
03451 TransactionId xid = pgxact->xid;
03452
03453
03454
03455
03456
03457
03458
03459 if (!TransactionIdIsValid(xid))
03460 continue;
03461
03462 accessExclusiveLocks[index].xid = xid;
03463 accessExclusiveLocks[index].dbOid = lock->tag.locktag_field1;
03464 accessExclusiveLocks[index].relOid = lock->tag.locktag_field2;
03465
03466 index++;
03467 }
03468 }
03469
03470
03471
03472
03473
03474
03475
03476
03477 for (i = NUM_LOCK_PARTITIONS; --i >= 0;)
03478 LWLockRelease(FirstLockMgrLock + i);
03479
03480 *nlocks = index;
03481 return accessExclusiveLocks;
03482 }
03483
03484
03485 const char *
03486 GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode)
03487 {
03488 Assert(lockmethodid > 0 && lockmethodid < lengthof(LockMethods));
03489 Assert(mode > 0 && mode <= LockMethods[lockmethodid]->numLockModes);
03490 return LockMethods[lockmethodid]->lockModeNames[mode];
03491 }
03492
03493 #ifdef LOCK_DEBUG
03494
03495
03496
03497
03498
03499 void
03500 DumpLocks(PGPROC *proc)
03501 {
03502 SHM_QUEUE *procLocks;
03503 PROCLOCK *proclock;
03504 LOCK *lock;
03505 int i;
03506
03507 if (proc == NULL)
03508 return;
03509
03510 if (proc->waitLock)
03511 LOCK_PRINT("DumpLocks: waiting on", proc->waitLock, 0);
03512
03513 for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
03514 {
03515 procLocks = &(proc->myProcLocks[i]);
03516
03517 proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
03518 offsetof(PROCLOCK, procLink));
03519
03520 while (proclock)
03521 {
03522 Assert(proclock->tag.myProc == proc);
03523
03524 lock = proclock->tag.myLock;
03525
03526 PROCLOCK_PRINT("DumpLocks", proclock);
03527 LOCK_PRINT("DumpLocks", lock, 0);
03528
03529 proclock = (PROCLOCK *)
03530 SHMQueueNext(procLocks, &proclock->procLink,
03531 offsetof(PROCLOCK, procLink));
03532 }
03533 }
03534 }
03535
03536
03537
03538
03539
03540
03541 void
03542 DumpAllLocks(void)
03543 {
03544 PGPROC *proc;
03545 PROCLOCK *proclock;
03546 LOCK *lock;
03547 HASH_SEQ_STATUS status;
03548
03549 proc = MyProc;
03550
03551 if (proc && proc->waitLock)
03552 LOCK_PRINT("DumpAllLocks: waiting on", proc->waitLock, 0);
03553
03554 hash_seq_init(&status, LockMethodProcLockHash);
03555
03556 while ((proclock = (PROCLOCK *) hash_seq_search(&status)) != NULL)
03557 {
03558 PROCLOCK_PRINT("DumpAllLocks", proclock);
03559
03560 lock = proclock->tag.myLock;
03561 if (lock)
03562 LOCK_PRINT("DumpAllLocks", lock, 0);
03563 else
03564 elog(LOG, "DumpAllLocks: proclock->tag.myLock = NULL");
03565 }
03566 }
03567 #endif
03568
03569
03570
03571
03572
03573
03574
03575
03576
03577
03578
03579
03580
03581
03582
03583
03584
03585
03586
03587
03588
03589
03590
03591
03592
03593
03594
03595
03596
03597
03598 void
03599 lock_twophase_recover(TransactionId xid, uint16 info,
03600 void *recdata, uint32 len)
03601 {
03602 TwoPhaseLockRecord *rec = (TwoPhaseLockRecord *) recdata;
03603 PGPROC *proc = TwoPhaseGetDummyProc(xid);
03604 LOCKTAG *locktag;
03605 LOCKMODE lockmode;
03606 LOCKMETHODID lockmethodid;
03607 LOCK *lock;
03608 PROCLOCK *proclock;
03609 PROCLOCKTAG proclocktag;
03610 bool found;
03611 uint32 hashcode;
03612 uint32 proclock_hashcode;
03613 int partition;
03614 LWLockId partitionLock;
03615 LockMethod lockMethodTable;
03616
03617 Assert(len == sizeof(TwoPhaseLockRecord));
03618 locktag = &rec->locktag;
03619 lockmode = rec->lockmode;
03620 lockmethodid = locktag->locktag_lockmethodid;
03621
03622 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
03623 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
03624 lockMethodTable = LockMethods[lockmethodid];
03625
03626 hashcode = LockTagHashCode(locktag);
03627 partition = LockHashPartition(hashcode);
03628 partitionLock = LockHashPartitionLock(hashcode);
03629
03630 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
03631
03632
03633
03634
03635 lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
03636 (void *) locktag,
03637 hashcode,
03638 HASH_ENTER_NULL,
03639 &found);
03640 if (!lock)
03641 {
03642 LWLockRelease(partitionLock);
03643 ereport(ERROR,
03644 (errcode(ERRCODE_OUT_OF_MEMORY),
03645 errmsg("out of shared memory"),
03646 errhint("You might need to increase max_locks_per_transaction.")));
03647 }
03648
03649
03650
03651
03652 if (!found)
03653 {
03654 lock->grantMask = 0;
03655 lock->waitMask = 0;
03656 SHMQueueInit(&(lock->procLocks));
03657 ProcQueueInit(&(lock->waitProcs));
03658 lock->nRequested = 0;
03659 lock->nGranted = 0;
03660 MemSet(lock->requested, 0, sizeof(int) * MAX_LOCKMODES);
03661 MemSet(lock->granted, 0, sizeof(int) * MAX_LOCKMODES);
03662 LOCK_PRINT("lock_twophase_recover: new", lock, lockmode);
03663 }
03664 else
03665 {
03666 LOCK_PRINT("lock_twophase_recover: found", lock, lockmode);
03667 Assert((lock->nRequested >= 0) && (lock->requested[lockmode] >= 0));
03668 Assert((lock->nGranted >= 0) && (lock->granted[lockmode] >= 0));
03669 Assert(lock->nGranted <= lock->nRequested);
03670 }
03671
03672
03673
03674
03675 proclocktag.myLock = lock;
03676 proclocktag.myProc = proc;
03677
03678 proclock_hashcode = ProcLockHashCode(&proclocktag, hashcode);
03679
03680
03681
03682
03683 proclock = (PROCLOCK *) hash_search_with_hash_value(LockMethodProcLockHash,
03684 (void *) &proclocktag,
03685 proclock_hashcode,
03686 HASH_ENTER_NULL,
03687 &found);
03688 if (!proclock)
03689 {
03690
03691 if (lock->nRequested == 0)
03692 {
03693
03694
03695
03696
03697
03698
03699 Assert(SHMQueueEmpty(&(lock->procLocks)));
03700 if (!hash_search_with_hash_value(LockMethodLockHash,
03701 (void *) &(lock->tag),
03702 hashcode,
03703 HASH_REMOVE,
03704 NULL))
03705 elog(PANIC, "lock table corrupted");
03706 }
03707 LWLockRelease(partitionLock);
03708 ereport(ERROR,
03709 (errcode(ERRCODE_OUT_OF_MEMORY),
03710 errmsg("out of shared memory"),
03711 errhint("You might need to increase max_locks_per_transaction.")));
03712 }
03713
03714
03715
03716
03717 if (!found)
03718 {
03719 proclock->holdMask = 0;
03720 proclock->releaseMask = 0;
03721
03722 SHMQueueInsertBefore(&lock->procLocks, &proclock->lockLink);
03723 SHMQueueInsertBefore(&(proc->myProcLocks[partition]),
03724 &proclock->procLink);
03725 PROCLOCK_PRINT("lock_twophase_recover: new", proclock);
03726 }
03727 else
03728 {
03729 PROCLOCK_PRINT("lock_twophase_recover: found", proclock);
03730 Assert((proclock->holdMask & ~lock->grantMask) == 0);
03731 }
03732
03733
03734
03735
03736
03737 lock->nRequested++;
03738 lock->requested[lockmode]++;
03739 Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0));
03740
03741
03742
03743
03744 if (proclock->holdMask & LOCKBIT_ON(lockmode))
03745 elog(ERROR, "lock %s on object %u/%u/%u is already held",
03746 lockMethodTable->lockModeNames[lockmode],
03747 lock->tag.locktag_field1, lock->tag.locktag_field2,
03748 lock->tag.locktag_field3);
03749
03750
03751
03752
03753
03754
03755 GrantLock(lock, proclock, lockmode);
03756
03757
03758
03759
03760
03761 if (ConflictsWithRelationFastPath(&lock->tag, lockmode))
03762 {
03763 uint32 fasthashcode = FastPathStrongLockHashPartition(hashcode);
03764
03765 SpinLockAcquire(&FastPathStrongRelationLocks->mutex);
03766 FastPathStrongRelationLocks->count[fasthashcode]++;
03767 SpinLockRelease(&FastPathStrongRelationLocks->mutex);
03768 }
03769
03770 LWLockRelease(partitionLock);
03771 }
03772
03773
03774
03775
03776
03777 void
03778 lock_twophase_standby_recover(TransactionId xid, uint16 info,
03779 void *recdata, uint32 len)
03780 {
03781 TwoPhaseLockRecord *rec = (TwoPhaseLockRecord *) recdata;
03782 LOCKTAG *locktag;
03783 LOCKMODE lockmode;
03784 LOCKMETHODID lockmethodid;
03785
03786 Assert(len == sizeof(TwoPhaseLockRecord));
03787 locktag = &rec->locktag;
03788 lockmode = rec->lockmode;
03789 lockmethodid = locktag->locktag_lockmethodid;
03790
03791 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
03792 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
03793
03794 if (lockmode == AccessExclusiveLock &&
03795 locktag->locktag_type == LOCKTAG_RELATION)
03796 {
03797 StandbyAcquireAccessExclusiveLock(xid,
03798 locktag->locktag_field1 ,
03799 locktag->locktag_field2 );
03800 }
03801 }
03802
03803
03804
03805
03806
03807
03808
03809 void
03810 lock_twophase_postcommit(TransactionId xid, uint16 info,
03811 void *recdata, uint32 len)
03812 {
03813 TwoPhaseLockRecord *rec = (TwoPhaseLockRecord *) recdata;
03814 PGPROC *proc = TwoPhaseGetDummyProc(xid);
03815 LOCKTAG *locktag;
03816 LOCKMETHODID lockmethodid;
03817 LockMethod lockMethodTable;
03818
03819 Assert(len == sizeof(TwoPhaseLockRecord));
03820 locktag = &rec->locktag;
03821 lockmethodid = locktag->locktag_lockmethodid;
03822
03823 if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
03824 elog(ERROR, "unrecognized lock method: %d", lockmethodid);
03825 lockMethodTable = LockMethods[lockmethodid];
03826
03827 LockRefindAndRelease(lockMethodTable, proc, locktag, rec->lockmode, true);
03828 }
03829
03830
03831
03832
03833
03834
03835 void
03836 lock_twophase_postabort(TransactionId xid, uint16 info,
03837 void *recdata, uint32 len)
03838 {
03839 lock_twophase_postcommit(xid, info, recdata, len);
03840 }
03841
03842
03843
03844
03845
03846
03847
03848
03849
03850
03851
03852
03853
03854
03855
03856
03857
03858
03859 void
03860 VirtualXactLockTableInsert(VirtualTransactionId vxid)
03861 {
03862 Assert(VirtualTransactionIdIsValid(vxid));
03863
03864 LWLockAcquire(MyProc->backendLock, LW_EXCLUSIVE);
03865
03866 Assert(MyProc->backendId == vxid.backendId);
03867 Assert(MyProc->fpLocalTransactionId == InvalidLocalTransactionId);
03868 Assert(MyProc->fpVXIDLock == false);
03869
03870 MyProc->fpVXIDLock = true;
03871 MyProc->fpLocalTransactionId = vxid.localTransactionId;
03872
03873 LWLockRelease(MyProc->backendLock);
03874 }
03875
03876
03877
03878
03879
03880
03881
03882 void
03883 VirtualXactLockTableCleanup()
03884 {
03885 bool fastpath;
03886 LocalTransactionId lxid;
03887
03888 Assert(MyProc->backendId != InvalidBackendId);
03889
03890
03891
03892
03893 LWLockAcquire(MyProc->backendLock, LW_EXCLUSIVE);
03894
03895 fastpath = MyProc->fpVXIDLock;
03896 lxid = MyProc->fpLocalTransactionId;
03897 MyProc->fpVXIDLock = false;
03898 MyProc->fpLocalTransactionId = InvalidLocalTransactionId;
03899
03900 LWLockRelease(MyProc->backendLock);
03901
03902
03903
03904
03905
03906 if (!fastpath && LocalTransactionIdIsValid(lxid))
03907 {
03908 VirtualTransactionId vxid;
03909 LOCKTAG locktag;
03910
03911 vxid.backendId = MyBackendId;
03912 vxid.localTransactionId = lxid;
03913 SET_LOCKTAG_VIRTUALTRANSACTION(locktag, vxid);
03914
03915 LockRefindAndRelease(LockMethods[DEFAULT_LOCKMETHOD], MyProc,
03916 &locktag, ExclusiveLock, false);
03917 }
03918 }
03919
03920
03921
03922
03923
03924
03925
03926
03927
03928
03929 bool
03930 VirtualXactLock(VirtualTransactionId vxid, bool wait)
03931 {
03932 LOCKTAG tag;
03933 PGPROC *proc;
03934
03935 Assert(VirtualTransactionIdIsValid(vxid));
03936
03937 SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid);
03938
03939
03940
03941
03942
03943
03944
03945
03946
03947 proc = BackendIdGetProc(vxid.backendId);
03948 if (proc == NULL)
03949 return true;
03950
03951
03952
03953
03954
03955
03956 LWLockAcquire(proc->backendLock, LW_EXCLUSIVE);
03957
03958
03959 if (proc->backendId != vxid.backendId
03960 || proc->fpLocalTransactionId != vxid.localTransactionId)
03961 {
03962 LWLockRelease(proc->backendLock);
03963 return true;
03964 }
03965
03966
03967
03968
03969
03970 if (!wait)
03971 {
03972 LWLockRelease(proc->backendLock);
03973 return false;
03974 }
03975
03976
03977
03978
03979
03980
03981 if (proc->fpVXIDLock)
03982 {
03983 PROCLOCK *proclock;
03984 uint32 hashcode;
03985 LWLockId partitionLock;
03986
03987 hashcode = LockTagHashCode(&tag);
03988
03989 partitionLock = LockHashPartitionLock(hashcode);
03990 LWLockAcquire(partitionLock, LW_EXCLUSIVE);
03991
03992 proclock = SetupLockInTable(LockMethods[DEFAULT_LOCKMETHOD], proc,
03993 &tag, hashcode, ExclusiveLock);
03994 if (!proclock)
03995 {
03996 LWLockRelease(partitionLock);
03997 ereport(ERROR,
03998 (errcode(ERRCODE_OUT_OF_MEMORY),
03999 errmsg("out of shared memory"),
04000 errhint("You might need to increase max_locks_per_transaction.")));
04001 }
04002 GrantLock(proclock->tag.myLock, proclock, ExclusiveLock);
04003
04004 LWLockRelease(partitionLock);
04005
04006 proc->fpVXIDLock = false;
04007 }
04008
04009
04010 LWLockRelease(proc->backendLock);
04011
04012
04013 (void) LockAcquire(&tag, ShareLock, false, false);
04014
04015 LockRelease(&tag, ShareLock, false);
04016 return true;
04017 }