Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * lmgr.c
4 : : * POSTGRES lock manager code
5 : : *
6 : : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/storage/lmgr/lmgr.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : :
16 : : #include "postgres.h"
17 : :
18 : : #include "access/subtrans.h"
19 : : #include "access/xact.h"
20 : : #include "catalog/catalog.h"
21 : : #include "commands/progress.h"
22 : : #include "miscadmin.h"
23 : : #include "pgstat.h"
24 : : #include "storage/lmgr.h"
25 : : #include "storage/proc.h"
26 : : #include "storage/procarray.h"
27 : : #include "utils/inval.h"
28 : :
29 : :
30 : : /*
31 : : * Per-backend counter for generating speculative insertion tokens.
32 : : *
33 : : * This may wrap around, but that's OK as it's only used for the short
34 : : * duration between inserting a tuple and checking that there are no (unique)
35 : : * constraint violations. It's theoretically possible that a backend sees a
36 : : * tuple that was speculatively inserted by another backend, but before it has
37 : : * started waiting on the token, the other backend completes its insertion,
38 : : * and then performs 2^32 unrelated insertions. And after all that, the
39 : : * first backend finally calls SpeculativeInsertionLockAcquire(), with the
40 : : * intention of waiting for the first insertion to complete, but ends up
41 : : * waiting for the latest unrelated insertion instead. Even then, nothing
42 : : * particularly bad happens: in the worst case they deadlock, causing one of
43 : : * the transactions to abort.
44 : : */
45 : : static uint32 speculativeInsertionToken = 0;
46 : :
47 : :
48 : : /*
49 : : * Struct to hold context info for transaction lock waits.
50 : : *
51 : : * 'oper' is the operation that needs to wait for the other transaction; 'rel'
52 : : * and 'ctid' specify the address of the tuple being waited for.
53 : : */
54 : : typedef struct XactLockTableWaitInfo
55 : : {
56 : : XLTW_Oper oper;
57 : : Relation rel;
58 : : const ItemPointerData *ctid;
59 : : } XactLockTableWaitInfo;
60 : :
61 : : static void XactLockTableWaitErrorCb(void *arg);
62 : :
63 : : /*
64 : : * RelationInitLockInfo
65 : : * Initializes the lock information in a relation descriptor.
66 : : *
67 : : * relcache.c must call this during creation of any reldesc.
68 : : */
69 : : void
10651 scrappy@hub.org 70 :CBC 2406678 : RelationInitLockInfo(Relation relation)
71 : : {
10226 bruce@momjian.us 72 [ - + ]: 2406678 : Assert(RelationIsValid(relation));
9880 73 [ - + ]: 2406678 : Assert(OidIsValid(RelationGetRelid(relation)));
74 : :
9485 tgl@sss.pgh.pa.us 75 : 2406678 : relation->rd_lockInfo.lockRelId.relId = RelationGetRelid(relation);
76 : :
8852 77 [ + + ]: 2406678 : if (relation->rd_rel->relisshared)
9485 78 : 357517 : relation->rd_lockInfo.lockRelId.dbId = InvalidOid;
79 : : else
80 : 2049161 : relation->rd_lockInfo.lockRelId.dbId = MyDatabaseId;
10651 scrappy@hub.org 81 : 2406678 : }
82 : :
83 : : /*
84 : : * SetLocktagRelationOid
85 : : * Set up a locktag for a relation, given only relation OID
86 : : */
87 : : static inline void
6977 tgl@sss.pgh.pa.us 88 : 18005715 : SetLocktagRelationOid(LOCKTAG *tag, Oid relid)
89 : : {
90 : : Oid dbid;
91 : :
92 [ + + ]: 18005715 : if (IsSharedRelation(relid))
93 : 836248 : dbid = InvalidOid;
94 : : else
95 : 17169467 : dbid = MyDatabaseId;
96 : :
97 : 18005715 : SET_LOCKTAG_RELATION(*tag, dbid, relid);
98 : 18005715 : }
99 : :
100 : : /*
101 : : * LockRelationOid
102 : : *
103 : : * Lock a relation given only its OID. This should generally be used
104 : : * before attempting to open the relation's relcache entry.
105 : : */
106 : : void
107 : 17826173 : LockRelationOid(Oid relid, LOCKMODE lockmode)
108 : : {
109 : : LOCKTAG tag;
110 : : LOCALLOCK *locallock;
111 : : LockAcquireResult res;
112 : :
113 : 17826173 : SetLocktagRelationOid(&tag, relid);
114 : :
176 fujii@postgresql.org 115 : 17826173 : res = LockAcquireExtended(&tag, lockmode, false, false, true, &locallock,
116 : : false);
117 : :
118 : : /*
119 : : * Now that we have the lock, check for invalidation messages, so that we
120 : : * will update or flush any stale relcache entry before we try to use it.
121 : : * RangeVarGetRelid() specifically relies on us for this. We can skip
122 : : * this in the not-uncommon case that we already had the same type of lock
123 : : * being requested, since then no one else could have modified the
124 : : * relcache entry in an undesirable way. (In the case where our own xact
125 : : * modifies the rel, the relcache update happens via
126 : : * CommandCounterIncrement, not here.)
127 : : *
128 : : * However, in corner cases where code acts on tables (usually catalogs)
129 : : * recursively, we might get here while still processing invalidation
130 : : * messages in some outer execution of this function or a sibling. The
131 : : * "cleared" status of the lock tells us whether we really are done
132 : : * absorbing relevant inval messages.
133 : : */
2556 tgl@sss.pgh.pa.us 134 [ + + ]: 17826164 : if (res != LOCKACQUIRE_ALREADY_CLEAR)
135 : : {
6977 136 : 15951344 : AcceptInvalidationMessages();
2556 137 : 15951344 : MarkLockClear(locallock);
138 : : }
6977 139 : 17826164 : }
140 : :
141 : : /*
142 : : * ConditionalLockRelationOid
143 : : *
144 : : * As above, but only lock if we can get the lock without blocking.
145 : : * Returns true iff the lock was acquired.
146 : : *
147 : : * NOTE: we do not currently need conditional versions of all the
148 : : * LockXXX routines in this file, but they could easily be added if needed.
149 : : */
150 : : bool
151 : 1081 : ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
152 : : {
153 : : LOCKTAG tag;
154 : : LOCALLOCK *locallock;
155 : : LockAcquireResult res;
156 : :
157 : 1081 : SetLocktagRelationOid(&tag, relid);
158 : :
176 fujii@postgresql.org 159 : 1081 : res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock,
160 : : false);
161 : :
6977 tgl@sss.pgh.pa.us 162 [ + + ]: 1081 : if (res == LOCKACQUIRE_NOT_AVAIL)
163 : 20 : return false;
164 : :
165 : : /*
166 : : * Now that we have the lock, check for invalidation messages; see notes
167 : : * in LockRelationOid.
168 : : */
2556 169 [ + + ]: 1061 : if (res != LOCKACQUIRE_ALREADY_CLEAR)
170 : : {
6977 171 : 1048 : AcceptInvalidationMessages();
2556 172 : 1048 : MarkLockClear(locallock);
173 : : }
174 : :
6977 175 : 1061 : return true;
176 : : }
177 : :
178 : : /*
179 : : * LockRelationId
180 : : *
181 : : * Lock, given a LockRelId. Same as LockRelationOid but take LockRelId as an
182 : : * input.
183 : : */
184 : : void
1257 rhaas@postgresql.org 185 : 107358 : LockRelationId(LockRelId *relid, LOCKMODE lockmode)
186 : : {
187 : : LOCKTAG tag;
188 : : LOCALLOCK *locallock;
189 : : LockAcquireResult res;
190 : :
191 : 107358 : SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
192 : :
176 fujii@postgresql.org 193 : 107358 : res = LockAcquireExtended(&tag, lockmode, false, false, true, &locallock,
194 : : false);
195 : :
196 : : /*
197 : : * Now that we have the lock, check for invalidation messages; see notes
198 : : * in LockRelationOid.
199 : : */
1257 rhaas@postgresql.org 200 [ + - ]: 107358 : if (res != LOCKACQUIRE_ALREADY_CLEAR)
201 : : {
202 : 107358 : AcceptInvalidationMessages();
203 : 107358 : MarkLockClear(locallock);
204 : : }
205 : 107358 : }
206 : :
207 : : /*
208 : : * UnlockRelationId
209 : : *
210 : : * Unlock, given a LockRelId. This is preferred over UnlockRelationOid
211 : : * for speed reasons.
212 : : */
213 : : void
6977 tgl@sss.pgh.pa.us 214 : 16099900 : UnlockRelationId(LockRelId *relid, LOCKMODE lockmode)
215 : : {
216 : : LOCKTAG tag;
217 : :
218 : 16099900 : SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
219 : :
220 : 16099900 : LockRelease(&tag, lockmode, false);
221 : 16099900 : }
222 : :
223 : : /*
224 : : * UnlockRelationOid
225 : : *
226 : : * Unlock, given only a relation Oid. Use UnlockRelationId if you can.
227 : : */
228 : : void
6959 229 : 165610 : UnlockRelationOid(Oid relid, LOCKMODE lockmode)
230 : : {
231 : : LOCKTAG tag;
232 : :
233 : 165610 : SetLocktagRelationOid(&tag, relid);
234 : :
235 : 165610 : LockRelease(&tag, lockmode, false);
236 : 165610 : }
237 : :
238 : : /*
239 : : * LockRelation
240 : : *
241 : : * This is a convenience routine for acquiring an additional lock on an
242 : : * already-open relation. Never try to do "relation_open(foo, NoLock)"
243 : : * and then lock with this.
244 : : */
245 : : void
9762 vadim4o@yahoo.com 246 : 23823 : LockRelation(Relation relation, LOCKMODE lockmode)
247 : : {
248 : : LOCKTAG tag;
249 : : LOCALLOCK *locallock;
250 : : LockAcquireResult res;
251 : :
7435 tgl@sss.pgh.pa.us 252 : 23823 : SET_LOCKTAG_RELATION(tag,
253 : : relation->rd_lockInfo.lockRelId.dbId,
254 : : relation->rd_lockInfo.lockRelId.relId);
255 : :
176 fujii@postgresql.org 256 : 23823 : res = LockAcquireExtended(&tag, lockmode, false, false, true, &locallock,
257 : : false);
258 : :
259 : : /*
260 : : * Now that we have the lock, check for invalidation messages; see notes
261 : : * in LockRelationOid.
262 : : */
2556 tgl@sss.pgh.pa.us 263 [ + - ]: 23823 : if (res != LOCKACQUIRE_ALREADY_CLEAR)
264 : : {
7405 265 : 23823 : AcceptInvalidationMessages();
2556 266 : 23823 : MarkLockClear(locallock);
267 : : }
9762 vadim4o@yahoo.com 268 : 23823 : }
269 : :
270 : : /*
271 : : * ConditionalLockRelation
272 : : *
273 : : * This is a convenience routine for acquiring an additional lock on an
274 : : * already-open relation. Never try to do "relation_open(foo, NoLock)"
275 : : * and then lock with this.
276 : : */
277 : : bool
8842 tgl@sss.pgh.pa.us 278 : 377 : ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
279 : : {
280 : : LOCKTAG tag;
281 : : LOCALLOCK *locallock;
282 : : LockAcquireResult res;
283 : :
7435 284 : 377 : SET_LOCKTAG_RELATION(tag,
285 : : relation->rd_lockInfo.lockRelId.dbId,
286 : : relation->rd_lockInfo.lockRelId.relId);
287 : :
176 fujii@postgresql.org 288 : 377 : res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock,
289 : : false);
290 : :
7405 tgl@sss.pgh.pa.us 291 [ + + ]: 377 : if (res == LOCKACQUIRE_NOT_AVAIL)
8842 292 : 204 : return false;
293 : :
294 : : /*
295 : : * Now that we have the lock, check for invalidation messages; see notes
296 : : * in LockRelationOid.
297 : : */
2556 298 [ + - ]: 173 : if (res != LOCKACQUIRE_ALREADY_CLEAR)
299 : : {
7405 300 : 173 : AcceptInvalidationMessages();
2556 301 : 173 : MarkLockClear(locallock);
302 : : }
303 : :
8842 304 : 173 : return true;
305 : : }
306 : :
307 : : /*
308 : : * UnlockRelation
309 : : *
310 : : * This is a convenience routine for unlocking a relation without also
311 : : * closing it.
312 : : */
313 : : void
9762 vadim4o@yahoo.com 314 : 173 : UnlockRelation(Relation relation, LOCKMODE lockmode)
315 : : {
316 : : LOCKTAG tag;
317 : :
7435 tgl@sss.pgh.pa.us 318 : 173 : SET_LOCKTAG_RELATION(tag,
319 : : relation->rd_lockInfo.lockRelId.dbId,
320 : : relation->rd_lockInfo.lockRelId.relId);
321 : :
7211 322 : 173 : LockRelease(&tag, lockmode, false);
9024 323 : 173 : }
324 : :
325 : : /*
326 : : * CheckRelationLockedByMe
327 : : *
328 : : * Returns true if current transaction holds a lock on 'relation' of mode
329 : : * 'lockmode'. If 'orstronger' is true, a stronger lockmode is also OK.
330 : : * ("Stronger" is defined as "numerically higher", which is a bit
331 : : * semantically dubious but is OK for the purposes we use this for.)
332 : : */
333 : : bool
2532 334 : 2168890 : CheckRelationLockedByMe(Relation relation, LOCKMODE lockmode, bool orstronger)
335 : : {
336 : : LOCKTAG tag;
337 : :
338 : 2168890 : SET_LOCKTAG_RELATION(tag,
339 : : relation->rd_lockInfo.lockRelId.dbId,
340 : : relation->rd_lockInfo.lockRelId.relId);
341 : :
436 noah@leadboat.com 342 : 2168890 : return LockHeldByMe(&tag, lockmode, orstronger);
343 : : }
344 : :
345 : : /*
346 : : * CheckRelationOidLockedByMe
347 : : *
348 : : * Like the above, but takes an OID as argument.
349 : : */
350 : : bool
351 : 12851 : CheckRelationOidLockedByMe(Oid relid, LOCKMODE lockmode, bool orstronger)
352 : : {
353 : : LOCKTAG tag;
354 : :
355 : 12851 : SetLocktagRelationOid(&tag, relid);
356 : :
357 : 12851 : return LockHeldByMe(&tag, lockmode, orstronger);
358 : : }
359 : :
360 : : /*
361 : : * LockHasWaitersRelation
362 : : *
363 : : * This is a function to check whether someone else is waiting for a
364 : : * lock which we are currently holding.
365 : : */
366 : : bool
4652 kgrittn@postgresql.o 367 :UBC 0 : LockHasWaitersRelation(Relation relation, LOCKMODE lockmode)
368 : : {
369 : : LOCKTAG tag;
370 : :
371 : 0 : SET_LOCKTAG_RELATION(tag,
372 : : relation->rd_lockInfo.lockRelId.dbId,
373 : : relation->rd_lockInfo.lockRelId.relId);
374 : :
375 : 0 : return LockHasWaiters(&tag, lockmode, false);
376 : : }
377 : :
378 : : /*
379 : : * LockRelationIdForSession
380 : : *
381 : : * This routine grabs a session-level lock on the target relation. The
382 : : * session lock persists across transaction boundaries. It will be removed
383 : : * when UnlockRelationIdForSession() is called, or if an ereport(ERROR) occurs,
384 : : * or if the backend exits.
385 : : *
386 : : * Note that one should also grab a transaction-level lock on the rel
387 : : * in any transaction that actually uses the rel, to ensure that the
388 : : * relcache entry is up to date.
389 : : */
390 : : void
6977 tgl@sss.pgh.pa.us 391 :CBC 14314 : LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
392 : : {
393 : : LOCKTAG tag;
394 : :
7435 395 : 14314 : SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
396 : :
6977 397 : 14314 : (void) LockAcquire(&tag, lockmode, true, false);
9024 398 : 14314 : }
399 : :
400 : : /*
401 : : * UnlockRelationIdForSession
402 : : */
403 : : void
6977 404 : 14293 : UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
405 : : {
406 : : LOCKTAG tag;
407 : :
7435 408 : 14293 : SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
409 : :
7211 410 : 14293 : LockRelease(&tag, lockmode, true);
9762 vadim4o@yahoo.com 411 : 14293 : }
412 : :
413 : : /*
414 : : * LockRelationForExtension
415 : : *
416 : : * This lock tag is used to interlock addition of pages to relations.
417 : : * We need such locking because bufmgr/smgr definition of P_NEW is not
418 : : * race-condition-proof.
419 : : *
420 : : * We assume the caller is already holding some type of regular lock on
421 : : * the relation, so no AcceptInvalidationMessages call is needed here.
422 : : */
423 : : void
7435 tgl@sss.pgh.pa.us 424 : 156065 : LockRelationForExtension(Relation relation, LOCKMODE lockmode)
425 : : {
426 : : LOCKTAG tag;
427 : :
428 : 156065 : SET_LOCKTAG_RELATION_EXTEND(tag,
429 : : relation->rd_lockInfo.lockRelId.dbId,
430 : : relation->rd_lockInfo.lockRelId.relId);
431 : :
6977 432 : 156065 : (void) LockAcquire(&tag, lockmode, false, false);
7435 433 : 156065 : }
434 : :
435 : : /*
436 : : * ConditionalLockRelationForExtension
437 : : *
438 : : * As above, but only lock if we can get the lock without blocking.
439 : : * Returns true iff the lock was acquired.
440 : : */
441 : : bool
3438 rhaas@postgresql.org 442 :UBC 0 : ConditionalLockRelationForExtension(Relation relation, LOCKMODE lockmode)
443 : : {
444 : : LOCKTAG tag;
445 : :
446 : 0 : SET_LOCKTAG_RELATION_EXTEND(tag,
447 : : relation->rd_lockInfo.lockRelId.dbId,
448 : : relation->rd_lockInfo.lockRelId.relId);
449 : :
450 : 0 : return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
451 : : }
452 : :
453 : : /*
454 : : * RelationExtensionLockWaiterCount
455 : : *
456 : : * Count the number of processes waiting for the given relation extension lock.
457 : : */
458 : : int
3438 rhaas@postgresql.org 459 :CBC 63632 : RelationExtensionLockWaiterCount(Relation relation)
460 : : {
461 : : LOCKTAG tag;
462 : :
463 : 63632 : SET_LOCKTAG_RELATION_EXTEND(tag,
464 : : relation->rd_lockInfo.lockRelId.dbId,
465 : : relation->rd_lockInfo.lockRelId.relId);
466 : :
467 : 63632 : return LockWaiterCount(&tag);
468 : : }
469 : :
470 : : /*
471 : : * UnlockRelationForExtension
472 : : */
473 : : void
7435 tgl@sss.pgh.pa.us 474 : 156065 : UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
475 : : {
476 : : LOCKTAG tag;
477 : :
478 : 156065 : SET_LOCKTAG_RELATION_EXTEND(tag,
479 : : relation->rd_lockInfo.lockRelId.dbId,
480 : : relation->rd_lockInfo.lockRelId.relId);
481 : :
7211 482 : 156065 : LockRelease(&tag, lockmode, false);
7435 483 : 156065 : }
484 : :
485 : : /*
486 : : * LockDatabaseFrozenIds
487 : : *
488 : : * This allows one backend per database to execute vac_update_datfrozenxid().
489 : : */
490 : : void
1848 noah@leadboat.com 491 : 906 : LockDatabaseFrozenIds(LOCKMODE lockmode)
492 : : {
493 : : LOCKTAG tag;
494 : :
495 : 906 : SET_LOCKTAG_DATABASE_FROZEN_IDS(tag, MyDatabaseId);
496 : :
497 : 906 : (void) LockAcquire(&tag, lockmode, false, false);
498 : 906 : }
499 : :
500 : : /*
501 : : * LockPage
502 : : *
503 : : * Obtain a page-level lock. This is currently used by some index access
504 : : * methods to lock individual index pages.
505 : : */
506 : : void
9762 vadim4o@yahoo.com 507 : 70 : LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
508 : : {
509 : : LOCKTAG tag;
510 : :
7435 tgl@sss.pgh.pa.us 511 : 70 : SET_LOCKTAG_PAGE(tag,
512 : : relation->rd_lockInfo.lockRelId.dbId,
513 : : relation->rd_lockInfo.lockRelId.relId,
514 : : blkno);
515 : :
6977 516 : 70 : (void) LockAcquire(&tag, lockmode, false, false);
9762 vadim4o@yahoo.com 517 : 70 : }
518 : :
519 : : /*
520 : : * ConditionalLockPage
521 : : *
522 : : * As above, but only lock if we can get the lock without blocking.
523 : : * Returns true iff the lock was acquired.
524 : : */
525 : : bool
8038 tgl@sss.pgh.pa.us 526 :UBC 0 : ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
527 : : {
528 : : LOCKTAG tag;
529 : :
7435 530 : 0 : SET_LOCKTAG_PAGE(tag,
531 : : relation->rd_lockInfo.lockRelId.dbId,
532 : : relation->rd_lockInfo.lockRelId.relId,
533 : : blkno);
534 : :
6977 535 : 0 : return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
536 : : }
537 : :
538 : : /*
539 : : * UnlockPage
540 : : */
541 : : void
9762 vadim4o@yahoo.com 542 :CBC 70 : UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
543 : : {
544 : : LOCKTAG tag;
545 : :
7435 tgl@sss.pgh.pa.us 546 : 70 : SET_LOCKTAG_PAGE(tag,
547 : : relation->rd_lockInfo.lockRelId.dbId,
548 : : relation->rd_lockInfo.lockRelId.relId,
549 : : blkno);
550 : :
7211 551 : 70 : LockRelease(&tag, lockmode, false);
10651 scrappy@hub.org 552 : 70 : }
553 : :
554 : : /*
555 : : * LockTuple
556 : : *
557 : : * Obtain a tuple-level lock. This is used in a less-than-intuitive fashion
558 : : * because we can't afford to keep a separate lock in shared memory for every
559 : : * tuple. See heap_lock_tuple before using this!
560 : : */
561 : : void
8 peter@eisentraut.org 562 :GNC 107769 : LockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode)
563 : : {
564 : : LOCKTAG tag;
565 : :
7434 tgl@sss.pgh.pa.us 566 :CBC 107769 : SET_LOCKTAG_TUPLE(tag,
567 : : relation->rd_lockInfo.lockRelId.dbId,
568 : : relation->rd_lockInfo.lockRelId.relId,
569 : : ItemPointerGetBlockNumber(tid),
570 : : ItemPointerGetOffsetNumber(tid));
571 : :
6977 572 : 107769 : (void) LockAcquire(&tag, lockmode, false, false);
7434 573 : 107769 : }
574 : :
575 : : /*
576 : : * ConditionalLockTuple
577 : : *
578 : : * As above, but only lock if we can get the lock without blocking.
579 : : * Returns true iff the lock was acquired.
580 : : */
581 : : bool
8 peter@eisentraut.org 582 :GNC 41 : ConditionalLockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode,
583 : : bool logLockFailure)
584 : : {
585 : : LOCKTAG tag;
586 : :
7341 tgl@sss.pgh.pa.us 587 :CBC 41 : SET_LOCKTAG_TUPLE(tag,
588 : : relation->rd_lockInfo.lockRelId.dbId,
589 : : relation->rd_lockInfo.lockRelId.relId,
590 : : ItemPointerGetBlockNumber(tid),
591 : : ItemPointerGetOffsetNumber(tid));
592 : :
176 fujii@postgresql.org 593 : 41 : return (LockAcquireExtended(&tag, lockmode, false, true, true, NULL,
594 : 41 : logLockFailure) != LOCKACQUIRE_NOT_AVAIL);
595 : : }
596 : :
597 : : /*
598 : : * UnlockTuple
599 : : */
600 : : void
8 peter@eisentraut.org 601 :GNC 131218 : UnlockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode)
602 : : {
603 : : LOCKTAG tag;
604 : :
7434 tgl@sss.pgh.pa.us 605 :CBC 131218 : SET_LOCKTAG_TUPLE(tag,
606 : : relation->rd_lockInfo.lockRelId.dbId,
607 : : relation->rd_lockInfo.lockRelId.relId,
608 : : ItemPointerGetBlockNumber(tid),
609 : : ItemPointerGetOffsetNumber(tid));
610 : :
7211 611 : 131218 : LockRelease(&tag, lockmode, false);
7434 612 : 131218 : }
613 : :
614 : : /*
615 : : * XactLockTableInsert
616 : : *
617 : : * Insert a lock showing that the given transaction ID is running ---
618 : : * this is done when an XID is acquired by a transaction or subtransaction.
619 : : * The lock can then be used to wait for the transaction to finish.
620 : : */
621 : : void
9762 vadim4o@yahoo.com 622 : 132409 : XactLockTableInsert(TransactionId xid)
623 : : {
624 : : LOCKTAG tag;
625 : :
7435 tgl@sss.pgh.pa.us 626 : 132409 : SET_LOCKTAG_TRANSACTION(tag, xid);
627 : :
6977 628 : 132409 : (void) LockAcquire(&tag, ExclusiveLock, false, false);
10651 scrappy@hub.org 629 : 132409 : }
630 : :
631 : : /*
632 : : * XactLockTableDelete
633 : : *
634 : : * Delete the lock showing that the given transaction ID is running.
635 : : * (This is never used for main transaction IDs; those locks are only
636 : : * released implicitly at transaction end. But we do use it for subtrans IDs.)
637 : : */
638 : : void
7660 tgl@sss.pgh.pa.us 639 : 2762 : XactLockTableDelete(TransactionId xid)
640 : : {
641 : : LOCKTAG tag;
642 : :
7435 643 : 2762 : SET_LOCKTAG_TRANSACTION(tag, xid);
644 : :
7211 645 : 2762 : LockRelease(&tag, ExclusiveLock, false);
7660 646 : 2762 : }
647 : :
648 : : /*
649 : : * XactLockTableWait
650 : : *
651 : : * Wait for the specified transaction to commit or abort. If an operation
652 : : * is specified, an error context callback is set up. If 'oper' is passed as
653 : : * None, no error context callback is set up.
654 : : *
655 : : * Note that this does the right thing for subtransactions: if we wait on a
656 : : * subtransaction, we will exit as soon as it aborts or its top parent commits.
657 : : * It takes some extra work to ensure this, because to save on shared memory
658 : : * the XID lock of a subtransaction is released when it ends, whether
659 : : * successfully or unsuccessfully. So we have to check if it's "still running"
660 : : * and if so wait for its parent.
661 : : */
662 : : void
8 peter@eisentraut.org 663 :GNC 391 : XactLockTableWait(TransactionId xid, Relation rel, const ItemPointerData *ctid,
664 : : XLTW_Oper oper)
665 : : {
666 : : LOCKTAG tag;
667 : : XactLockTableWaitInfo info;
668 : : ErrorContextCallback callback;
2803 alvherre@alvh.no-ip. 669 :CBC 391 : bool first = true;
670 : :
671 : : /*
672 : : * If an operation is specified, set up our verbose error context
673 : : * callback.
674 : : */
4189 675 [ + + ]: 391 : if (oper != XLTW_None)
676 : : {
677 [ - + ]: 372 : Assert(RelationIsValid(rel));
678 [ - + ]: 372 : Assert(ItemPointerIsValid(ctid));
679 : :
680 : 372 : info.rel = rel;
681 : 372 : info.ctid = ctid;
682 : 372 : info.oper = oper;
683 : :
684 : 372 : callback.callback = XactLockTableWaitErrorCb;
685 : 372 : callback.arg = &info;
686 : 372 : callback.previous = error_context_stack;
687 : 372 : error_context_stack = &callback;
688 : : }
689 : :
690 : : for (;;)
691 : : {
7660 tgl@sss.pgh.pa.us 692 [ - + ]: 394 : Assert(TransactionIdIsValid(xid));
6576 693 [ - + ]: 394 : Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
694 : :
7435 695 : 394 : SET_LOCKTAG_TRANSACTION(tag, xid);
696 : :
6977 697 : 394 : (void) LockAcquire(&tag, ShareLock, false, false);
698 : :
7211 699 : 387 : LockRelease(&tag, ShareLock, false);
700 : :
7660 701 [ + + ]: 387 : if (!TransactionIdIsInProgress(xid))
702 : 384 : break;
703 : :
704 : : /*
705 : : * If the Xid belonged to a subtransaction, then the lock would have
706 : : * gone away as soon as it was finished; for correct tuple visibility,
707 : : * the right action is to wait on its parent transaction to go away.
708 : : * But instead of going levels up one by one, we can just wait for the
709 : : * topmost transaction to finish with the same end result, which also
710 : : * incurs less locktable traffic.
711 : : *
712 : : * Some uses of this function don't involve tuple visibility -- such
713 : : * as when building snapshots for logical decoding. It is possible to
714 : : * see a transaction in ProcArray before it registers itself in the
715 : : * locktable. The topmost transaction in that case is the same xid,
716 : : * so we try again after a short sleep. (Don't sleep the first time
717 : : * through, to avoid slowing down the normal case.)
718 : : */
2803 alvherre@alvh.no-ip. 719 [ - + ]: 3 : if (!first)
720 : : {
98 fujii@postgresql.org 721 [ # # ]:UBC 0 : CHECK_FOR_INTERRUPTS();
2803 alvherre@alvh.no-ip. 722 : 0 : pg_usleep(1000L);
723 : : }
2803 alvherre@alvh.no-ip. 724 :CBC 3 : first = false;
725 : 3 : xid = SubTransGetTopmostTransaction(xid);
726 : : }
727 : :
4189 728 [ + + ]: 384 : if (oper != XLTW_None)
729 : 367 : error_context_stack = callback.previous;
10651 scrappy@hub.org 730 : 384 : }
731 : :
732 : : /*
733 : : * ConditionalXactLockTableWait
734 : : *
735 : : * As above, but only lock if we can get the lock without blocking.
736 : : * Returns true if the lock was acquired.
737 : : */
738 : : bool
176 fujii@postgresql.org 739 : 45 : ConditionalXactLockTableWait(TransactionId xid, bool logLockFailure)
740 : : {
741 : : LOCKTAG tag;
2803 alvherre@alvh.no-ip. 742 : 45 : bool first = true;
743 : :
744 : : for (;;)
745 : : {
7341 tgl@sss.pgh.pa.us 746 [ - + ]: 45 : Assert(TransactionIdIsValid(xid));
6576 747 [ - + ]: 45 : Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
748 : :
7341 749 : 45 : SET_LOCKTAG_TRANSACTION(tag, xid);
750 : :
176 fujii@postgresql.org 751 [ + - ]: 45 : if (LockAcquireExtended(&tag, ShareLock, false, true, true, NULL,
752 : : logLockFailure)
753 : : == LOCKACQUIRE_NOT_AVAIL)
7341 tgl@sss.pgh.pa.us 754 : 45 : return false;
755 : :
7211 tgl@sss.pgh.pa.us 756 :UBC 0 : LockRelease(&tag, ShareLock, false);
757 : :
7341 758 [ # # ]: 0 : if (!TransactionIdIsInProgress(xid))
759 : 0 : break;
760 : :
761 : : /* See XactLockTableWait about this case */
2803 alvherre@alvh.no-ip. 762 [ # # ]: 0 : if (!first)
763 : : {
98 fujii@postgresql.org 764 [ # # ]: 0 : CHECK_FOR_INTERRUPTS();
2803 alvherre@alvh.no-ip. 765 : 0 : pg_usleep(1000L);
766 : : }
767 : 0 : first = false;
768 : 0 : xid = SubTransGetTopmostTransaction(xid);
769 : : }
770 : :
7341 tgl@sss.pgh.pa.us 771 : 0 : return true;
772 : : }
773 : :
774 : : /*
775 : : * SpeculativeInsertionLockAcquire
776 : : *
777 : : * Insert a lock showing that the given transaction ID is inserting a tuple,
778 : : * but hasn't yet decided whether it's going to keep it. The lock can then be
779 : : * used to wait for the decision to go ahead with the insertion, or aborting
780 : : * it.
781 : : *
782 : : * The token is used to distinguish multiple insertions by the same
783 : : * transaction. It is returned to caller.
784 : : */
785 : : uint32
3774 andres@anarazel.de 786 :CBC 2070 : SpeculativeInsertionLockAcquire(TransactionId xid)
787 : : {
788 : : LOCKTAG tag;
789 : :
790 : 2070 : speculativeInsertionToken++;
791 : :
792 : : /*
793 : : * Check for wrap-around. Zero means no token is held, so don't use that.
794 : : */
795 [ - + ]: 2070 : if (speculativeInsertionToken == 0)
3774 andres@anarazel.de 796 :UBC 0 : speculativeInsertionToken = 1;
797 : :
3774 andres@anarazel.de 798 :CBC 2070 : SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
799 : :
800 : 2070 : (void) LockAcquire(&tag, ExclusiveLock, false, false);
801 : :
802 : 2070 : return speculativeInsertionToken;
803 : : }
804 : :
805 : : /*
806 : : * SpeculativeInsertionLockRelease
807 : : *
808 : : * Delete the lock showing that the given transaction is speculatively
809 : : * inserting a tuple.
810 : : */
811 : : void
812 : 2067 : SpeculativeInsertionLockRelease(TransactionId xid)
813 : : {
814 : : LOCKTAG tag;
815 : :
816 : 2067 : SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
817 : :
818 : 2067 : LockRelease(&tag, ExclusiveLock, false);
819 : 2067 : }
820 : :
821 : : /*
822 : : * SpeculativeInsertionWait
823 : : *
824 : : * Wait for the specified transaction to finish or abort the insertion of a
825 : : * tuple.
826 : : */
827 : : void
828 : 1 : SpeculativeInsertionWait(TransactionId xid, uint32 token)
829 : : {
830 : : LOCKTAG tag;
831 : :
832 : 1 : SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, token);
833 : :
834 [ - + ]: 1 : Assert(TransactionIdIsValid(xid));
835 [ - + ]: 1 : Assert(token != 0);
836 : :
837 : 1 : (void) LockAcquire(&tag, ShareLock, false, false);
838 : 1 : LockRelease(&tag, ShareLock, false);
839 : 1 : }
840 : :
841 : : /*
842 : : * XactLockTableWaitErrorCb
843 : : * Error context callback for transaction lock waits.
844 : : */
845 : : static void
4189 alvherre@alvh.no-ip. 846 : 6 : XactLockTableWaitErrorCb(void *arg)
847 : : {
848 : 6 : XactLockTableWaitInfo *info = (XactLockTableWaitInfo *) arg;
849 : :
850 : : /*
851 : : * We would like to print schema name too, but that would require a
852 : : * syscache lookup.
853 : : */
854 [ + - + - ]: 12 : if (info->oper != XLTW_None &&
855 [ + - ]: 12 : ItemPointerIsValid(info->ctid) && RelationIsValid(info->rel))
856 : : {
857 : : const char *cxt;
858 : :
859 [ + + - - : 6 : switch (info->oper)
- - - -
- ]
860 : : {
861 : 2 : case XLTW_Update:
862 : 2 : cxt = gettext_noop("while updating tuple (%u,%u) in relation \"%s\"");
863 : 2 : break;
864 : 4 : case XLTW_Delete:
865 : 4 : cxt = gettext_noop("while deleting tuple (%u,%u) in relation \"%s\"");
866 : 4 : break;
4189 alvherre@alvh.no-ip. 867 :UBC 0 : case XLTW_Lock:
868 : 0 : cxt = gettext_noop("while locking tuple (%u,%u) in relation \"%s\"");
869 : 0 : break;
870 : 0 : case XLTW_LockUpdated:
871 : 0 : cxt = gettext_noop("while locking updated version (%u,%u) of tuple in relation \"%s\"");
872 : 0 : break;
873 : 0 : case XLTW_InsertIndex:
874 : 0 : cxt = gettext_noop("while inserting index tuple (%u,%u) in relation \"%s\"");
875 : 0 : break;
876 : 0 : case XLTW_InsertIndexUnique:
877 : 0 : cxt = gettext_noop("while checking uniqueness of tuple (%u,%u) in relation \"%s\"");
878 : 0 : break;
879 : 0 : case XLTW_FetchUpdated:
880 : 0 : cxt = gettext_noop("while rechecking updated tuple (%u,%u) in relation \"%s\"");
881 : 0 : break;
882 : 0 : case XLTW_RecheckExclusionConstr:
883 : 0 : cxt = gettext_noop("while checking exclusion constraint on tuple (%u,%u) in relation \"%s\"");
884 : 0 : break;
885 : :
886 : 0 : default:
887 : 0 : return;
888 : : }
889 : :
4189 alvherre@alvh.no-ip. 890 :CBC 12 : errcontext(cxt,
4189 alvherre@alvh.no-ip. 891 :ECB (6) : ItemPointerGetBlockNumber(info->ctid),
4189 alvherre@alvh.no-ip. 892 :CBC 6 : ItemPointerGetOffsetNumber(info->ctid),
893 : 6 : RelationGetRelationName(info->rel));
894 : : }
895 : : }
896 : :
897 : : /*
898 : : * WaitForLockersMultiple
899 : : * Wait until no transaction holds locks that conflict with the given
900 : : * locktags at the given lockmode.
901 : : *
902 : : * To do this, obtain the current list of lockers, and wait on their VXIDs
903 : : * until they are finished.
904 : : *
905 : : * Note we don't try to acquire the locks on the given locktags, only the
906 : : * VXIDs and XIDs of their lock holders; if somebody grabs a conflicting lock
907 : : * on the objects after we obtained our initial list of lockers, we will not
908 : : * wait for them.
909 : : */
910 : : void
2349 911 : 1126 : WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress)
912 : : {
4362 913 : 1126 : List *holders = NIL;
914 : : ListCell *lc;
2349 915 : 1126 : int total = 0;
916 : 1126 : int done = 0;
917 : :
918 : : /* Done if no locks to wait for */
1116 tgl@sss.pgh.pa.us 919 [ - + ]: 1126 : if (locktags == NIL)
4362 alvherre@alvh.no-ip. 920 :UBC 0 : return;
921 : :
922 : : /* Collect the transactions we need to wait on */
4362 alvherre@alvh.no-ip. 923 [ + - + + :CBC 2428 : foreach(lc, locktags)
+ + ]
924 : : {
925 : 1302 : LOCKTAG *locktag = lfirst(lc);
926 : : int count;
927 : :
2349 928 : 1302 : holders = lappend(holders,
929 [ + + ]: 1302 : GetLockConflicts(locktag, lockmode,
930 : : progress ? &count : NULL));
931 [ + + ]: 1302 : if (progress)
932 : 1232 : total += count;
933 : : }
934 : :
935 [ + + ]: 1126 : if (progress)
936 : 1056 : pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, total);
937 : :
938 : : /*
939 : : * Note: GetLockConflicts() never reports our own xid, hence we need not
940 : : * check for that. Also, prepared xacts are reported and awaited.
941 : : */
942 : :
943 : : /* Finally wait for each such transaction to complete */
4362 944 [ + - + + : 2403 : foreach(lc, holders)
+ + ]
945 : : {
946 : 1302 : VirtualTransactionId *lockholders = lfirst(lc);
947 : :
948 [ + + ]: 1489 : while (VirtualTransactionIdIsValid(*lockholders))
949 : : {
950 : : /* If requested, publish who we're going to wait for. */
2349 951 [ + + ]: 212 : if (progress)
952 : : {
552 heikki.linnakangas@i 953 : 157 : PGPROC *holder = ProcNumberGetProc(lockholders->procNumber);
954 : :
2152 alvherre@alvh.no-ip. 955 [ + + ]: 157 : if (holder)
956 : 155 : pgstat_progress_update_param(PROGRESS_WAITFOR_CURRENT_PID,
957 : 155 : holder->pid);
958 : : }
4362 959 : 212 : VirtualXactLock(*lockholders, true);
960 : 187 : lockholders++;
961 : :
2349 962 [ + + ]: 187 : if (progress)
963 : 157 : pgstat_progress_update_param(PROGRESS_WAITFOR_DONE, ++done);
964 : : }
965 : : }
966 [ + + ]: 1101 : if (progress)
967 : : {
968 : 1056 : const int index[] = {
969 : : PROGRESS_WAITFOR_TOTAL,
970 : : PROGRESS_WAITFOR_DONE,
971 : : PROGRESS_WAITFOR_CURRENT_PID
972 : : };
2299 tgl@sss.pgh.pa.us 973 : 1056 : const int64 values[] = {
974 : : 0, 0, 0
975 : : };
976 : :
2349 alvherre@alvh.no-ip. 977 : 1056 : pgstat_progress_update_multi_param(3, index, values);
978 : : }
979 : :
4362 980 : 1101 : list_free_deep(holders);
981 : : }
982 : :
983 : : /*
984 : : * WaitForLockers
985 : : *
986 : : * Same as WaitForLockersMultiple, for a single lock tag.
987 : : */
988 : : void
2349 989 : 253 : WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode, bool progress)
990 : : {
991 : : List *l;
992 : :
4362 993 : 253 : l = list_make1(&heaplocktag);
2349 994 : 253 : WaitForLockersMultiple(l, lockmode, progress);
4362 995 : 253 : list_free(l);
996 : 253 : }
997 : :
998 : :
999 : : /*
1000 : : * LockDatabaseObject
1001 : : *
1002 : : * Obtain a lock on a general object of the current database. Don't use
1003 : : * this for shared objects (such as tablespaces). It's unwise to apply it
1004 : : * to relations, also, since a lock taken this way will NOT conflict with
1005 : : * locks taken via LockRelation and friends.
1006 : : */
1007 : : void
7434 tgl@sss.pgh.pa.us 1008 : 156207 : LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
1009 : : LOCKMODE lockmode)
1010 : : {
1011 : : LOCKTAG tag;
1012 : :
1013 : 156207 : SET_LOCKTAG_OBJECT(tag,
1014 : : MyDatabaseId,
1015 : : classid,
1016 : : objid,
1017 : : objsubid);
1018 : :
6977 1019 : 156207 : (void) LockAcquire(&tag, lockmode, false, false);
1020 : :
1021 : : /* Make sure syscaches are up-to-date with any changes we waited for */
5500 rhaas@postgresql.org 1022 : 156207 : AcceptInvalidationMessages();
7434 tgl@sss.pgh.pa.us 1023 : 156207 : }
1024 : :
1025 : : /*
1026 : : * ConditionalLockDatabaseObject
1027 : : *
1028 : : * As above, but only lock if we can get the lock without blocking.
1029 : : * Returns true iff the lock was acquired.
1030 : : */
1031 : : bool
522 tgl@sss.pgh.pa.us 1032 :UBC 0 : ConditionalLockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
1033 : : LOCKMODE lockmode)
1034 : : {
1035 : : LOCKTAG tag;
1036 : : LOCALLOCK *locallock;
1037 : : LockAcquireResult res;
1038 : :
1039 : 0 : SET_LOCKTAG_OBJECT(tag,
1040 : : MyDatabaseId,
1041 : : classid,
1042 : : objid,
1043 : : objsubid);
1044 : :
176 fujii@postgresql.org 1045 : 0 : res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock,
1046 : : false);
1047 : :
522 tgl@sss.pgh.pa.us 1048 [ # # ]: 0 : if (res == LOCKACQUIRE_NOT_AVAIL)
1049 : 0 : return false;
1050 : :
1051 : : /*
1052 : : * Now that we have the lock, check for invalidation messages; see notes
1053 : : * in LockRelationOid.
1054 : : */
1055 [ # # ]: 0 : if (res != LOCKACQUIRE_ALREADY_CLEAR)
1056 : : {
1057 : 0 : AcceptInvalidationMessages();
1058 : 0 : MarkLockClear(locallock);
1059 : : }
1060 : :
1061 : 0 : return true;
1062 : : }
1063 : :
1064 : : /*
1065 : : * UnlockDatabaseObject
1066 : : */
1067 : : void
7434 tgl@sss.pgh.pa.us 1068 :CBC 829 : UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
1069 : : LOCKMODE lockmode)
1070 : : {
1071 : : LOCKTAG tag;
1072 : :
1073 : 829 : SET_LOCKTAG_OBJECT(tag,
1074 : : MyDatabaseId,
1075 : : classid,
1076 : : objid,
1077 : : objsubid);
1078 : :
7211 1079 : 829 : LockRelease(&tag, lockmode, false);
7434 1080 : 829 : }
1081 : :
1082 : : /*
1083 : : * LockSharedObject
1084 : : *
1085 : : * Obtain a lock on a shared-across-databases object.
1086 : : */
1087 : : void
1088 : 24803 : LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
1089 : : LOCKMODE lockmode)
1090 : : {
1091 : : LOCKTAG tag;
1092 : :
1093 : 24803 : SET_LOCKTAG_OBJECT(tag,
1094 : : InvalidOid,
1095 : : classid,
1096 : : objid,
1097 : : objsubid);
1098 : :
6977 1099 : 24803 : (void) LockAcquire(&tag, lockmode, false, false);
1100 : :
1101 : : /* Make sure syscaches are up-to-date with any changes we waited for */
7065 1102 : 24801 : AcceptInvalidationMessages();
7434 1103 : 24801 : }
1104 : :
1105 : : /*
1106 : : * ConditionalLockSharedObject
1107 : : *
1108 : : * As above, but only lock if we can get the lock without blocking.
1109 : : * Returns true iff the lock was acquired.
1110 : : */
1111 : : bool
691 akorotkov@postgresql 1112 : 3 : ConditionalLockSharedObject(Oid classid, Oid objid, uint16 objsubid,
1113 : : LOCKMODE lockmode)
1114 : : {
1115 : : LOCKTAG tag;
1116 : : LOCALLOCK *locallock;
1117 : : LockAcquireResult res;
1118 : :
1119 : 3 : SET_LOCKTAG_OBJECT(tag,
1120 : : InvalidOid,
1121 : : classid,
1122 : : objid,
1123 : : objsubid);
1124 : :
176 fujii@postgresql.org 1125 : 3 : res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock,
1126 : : false);
1127 : :
691 akorotkov@postgresql 1128 [ - + ]: 3 : if (res == LOCKACQUIRE_NOT_AVAIL)
691 akorotkov@postgresql 1129 :UBC 0 : return false;
1130 : :
1131 : : /*
1132 : : * Now that we have the lock, check for invalidation messages; see notes
1133 : : * in LockRelationOid.
1134 : : */
691 akorotkov@postgresql 1135 [ + - ]:CBC 3 : if (res != LOCKACQUIRE_ALREADY_CLEAR)
1136 : : {
1137 : 3 : AcceptInvalidationMessages();
1138 : 3 : MarkLockClear(locallock);
1139 : : }
1140 : :
1141 : 3 : return true;
1142 : : }
1143 : :
1144 : : /*
1145 : : * UnlockSharedObject
1146 : : */
1147 : : void
7434 tgl@sss.pgh.pa.us 1148 : 805 : UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
1149 : : LOCKMODE lockmode)
1150 : : {
1151 : : LOCKTAG tag;
1152 : :
1153 : 805 : SET_LOCKTAG_OBJECT(tag,
1154 : : InvalidOid,
1155 : : classid,
1156 : : objid,
1157 : : objsubid);
1158 : :
7211 1159 : 805 : LockRelease(&tag, lockmode, false);
7434 1160 : 805 : }
1161 : :
1162 : : /*
1163 : : * LockSharedObjectForSession
1164 : : *
1165 : : * Obtain a session-level lock on a shared-across-databases object.
1166 : : * See LockRelationIdForSession for notes about session-level locks.
1167 : : */
1168 : : void
6147 1169 : 20 : LockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
1170 : : LOCKMODE lockmode)
1171 : : {
1172 : : LOCKTAG tag;
1173 : :
1174 : 20 : SET_LOCKTAG_OBJECT(tag,
1175 : : InvalidOid,
1176 : : classid,
1177 : : objid,
1178 : : objsubid);
1179 : :
1180 : 20 : (void) LockAcquire(&tag, lockmode, true, false);
1181 : 20 : }
1182 : :
1183 : : /*
1184 : : * UnlockSharedObjectForSession
1185 : : */
1186 : : void
1187 : 20 : UnlockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
1188 : : LOCKMODE lockmode)
1189 : : {
1190 : : LOCKTAG tag;
1191 : :
1192 : 20 : SET_LOCKTAG_OBJECT(tag,
1193 : : InvalidOid,
1194 : : classid,
1195 : : objid,
1196 : : objsubid);
1197 : :
1198 : 20 : LockRelease(&tag, lockmode, true);
1199 : 20 : }
1200 : :
1201 : : /*
1202 : : * LockApplyTransactionForSession
1203 : : *
1204 : : * Obtain a session-level lock on a transaction being applied on a logical
1205 : : * replication subscriber. See LockRelationIdForSession for notes about
1206 : : * session-level locks.
1207 : : */
1208 : : void
971 akapila@postgresql.o 1209 : 336 : LockApplyTransactionForSession(Oid suboid, TransactionId xid, uint16 objid,
1210 : : LOCKMODE lockmode)
1211 : : {
1212 : : LOCKTAG tag;
1213 : :
1214 : 336 : SET_LOCKTAG_APPLY_TRANSACTION(tag,
1215 : : MyDatabaseId,
1216 : : suboid,
1217 : : xid,
1218 : : objid);
1219 : :
1220 : 336 : (void) LockAcquire(&tag, lockmode, true, false);
1221 : 333 : }
1222 : :
1223 : : /*
1224 : : * UnlockApplyTransactionForSession
1225 : : */
1226 : : void
1227 : 328 : UnlockApplyTransactionForSession(Oid suboid, TransactionId xid, uint16 objid,
1228 : : LOCKMODE lockmode)
1229 : : {
1230 : : LOCKTAG tag;
1231 : :
1232 : 328 : SET_LOCKTAG_APPLY_TRANSACTION(tag,
1233 : : MyDatabaseId,
1234 : : suboid,
1235 : : xid,
1236 : : objid);
1237 : :
1238 : 328 : LockRelease(&tag, lockmode, true);
1239 : 328 : }
1240 : :
1241 : : /*
1242 : : * Append a description of a lockable object to buf.
1243 : : *
1244 : : * Ideally we would print names for the numeric values, but that requires
1245 : : * getting locks on system tables, which might cause problems since this is
1246 : : * typically used to report deadlock situations.
1247 : : */
1248 : : void
6654 tgl@sss.pgh.pa.us 1249 : 105 : DescribeLockTag(StringInfo buf, const LOCKTAG *tag)
1250 : : {
6451 1251 [ + - - - : 105 : switch ((LockTagType) tag->locktag_type)
- + + - +
- + + - ]
1252 : : {
6654 1253 : 35 : case LOCKTAG_RELATION:
1254 : 35 : appendStringInfo(buf,
1255 : 35 : _("relation %u of database %u"),
1256 : 35 : tag->locktag_field2,
1257 : 35 : tag->locktag_field1);
1258 : 35 : break;
6654 tgl@sss.pgh.pa.us 1259 :UBC 0 : case LOCKTAG_RELATION_EXTEND:
1260 : 0 : appendStringInfo(buf,
1261 : 0 : _("extension of relation %u of database %u"),
1262 : 0 : tag->locktag_field2,
1263 : 0 : tag->locktag_field1);
1264 : 0 : break;
1848 noah@leadboat.com 1265 : 0 : case LOCKTAG_DATABASE_FROZEN_IDS:
1266 : 0 : appendStringInfo(buf,
1267 : 0 : _("pg_database.datfrozenxid of database %u"),
1268 : 0 : tag->locktag_field1);
1269 : 0 : break;
6654 tgl@sss.pgh.pa.us 1270 : 0 : case LOCKTAG_PAGE:
1271 : 0 : appendStringInfo(buf,
1272 : 0 : _("page %u of relation %u of database %u"),
1273 : 0 : tag->locktag_field3,
1274 : 0 : tag->locktag_field2,
1275 : 0 : tag->locktag_field1);
1276 : 0 : break;
1277 : 0 : case LOCKTAG_TUPLE:
1278 : 0 : appendStringInfo(buf,
1279 : 0 : _("tuple (%u,%u) of relation %u of database %u"),
1280 : 0 : tag->locktag_field3,
1281 : 0 : tag->locktag_field4,
1282 : 0 : tag->locktag_field2,
1283 : 0 : tag->locktag_field1);
1284 : 0 : break;
6654 tgl@sss.pgh.pa.us 1285 :CBC 13 : case LOCKTAG_TRANSACTION:
1286 : 13 : appendStringInfo(buf,
1287 : 13 : _("transaction %u"),
1288 : 13 : tag->locktag_field1);
1289 : 13 : break;
6451 1290 : 41 : case LOCKTAG_VIRTUALTRANSACTION:
1291 : 41 : appendStringInfo(buf,
1292 : 41 : _("virtual transaction %d/%u"),
1293 : 41 : tag->locktag_field1,
1294 : 41 : tag->locktag_field2);
1295 : 41 : break;
3774 andres@anarazel.de 1296 :UBC 0 : case LOCKTAG_SPECULATIVE_TOKEN:
1297 : 0 : appendStringInfo(buf,
1298 : 0 : _("speculative token %u of transaction %u"),
1299 : 0 : tag->locktag_field2,
1300 : 0 : tag->locktag_field1);
1301 : 0 : break;
6654 tgl@sss.pgh.pa.us 1302 :GBC 2 : case LOCKTAG_OBJECT:
1303 : 2 : appendStringInfo(buf,
1304 : 2 : _("object %u of class %u of database %u"),
1305 : 2 : tag->locktag_field3,
1306 : 2 : tag->locktag_field2,
1307 : 2 : tag->locktag_field1);
1308 : 2 : break;
6654 tgl@sss.pgh.pa.us 1309 :UBC 0 : case LOCKTAG_USERLOCK:
1310 : : /* reserved for old contrib code, now on pgfoundry */
1311 : 0 : appendStringInfo(buf,
1312 : 0 : _("user lock [%u,%u,%u]"),
1313 : 0 : tag->locktag_field1,
1314 : 0 : tag->locktag_field2,
1315 : 0 : tag->locktag_field3);
1316 : 0 : break;
6654 tgl@sss.pgh.pa.us 1317 :CBC 11 : case LOCKTAG_ADVISORY:
1318 : 11 : appendStringInfo(buf,
1319 : 11 : _("advisory lock [%u,%u,%u,%u]"),
1320 : 11 : tag->locktag_field1,
1321 : 11 : tag->locktag_field2,
1322 : 11 : tag->locktag_field3,
1323 : 11 : tag->locktag_field4);
1324 : 11 : break;
971 akapila@postgresql.o 1325 : 3 : case LOCKTAG_APPLY_TRANSACTION:
1326 : 3 : appendStringInfo(buf,
1327 : 3 : _("remote transaction %u of subscription %u of database %u"),
1328 : 3 : tag->locktag_field3,
1329 : 3 : tag->locktag_field2,
1330 : 3 : tag->locktag_field1);
1331 : 3 : break;
6654 tgl@sss.pgh.pa.us 1332 :UBC 0 : default:
1333 : 0 : appendStringInfo(buf,
1334 : 0 : _("unrecognized locktag type %d"),
6451 1335 : 0 : (int) tag->locktag_type);
6654 1336 : 0 : break;
1337 : : }
6654 tgl@sss.pgh.pa.us 1338 :CBC 105 : }
1339 : :
1340 : : /*
1341 : : * GetLockNameFromTagType
1342 : : *
1343 : : * Given locktag type, return the corresponding lock name.
1344 : : */
1345 : : const char *
3467 rhaas@postgresql.org 1346 : 7 : GetLockNameFromTagType(uint16 locktag_type)
1347 : : {
1348 [ - + ]: 7 : if (locktag_type > LOCKTAG_LAST_TYPE)
3467 rhaas@postgresql.org 1349 :UBC 0 : return "???";
3467 rhaas@postgresql.org 1350 :CBC 7 : return LockTagTypeNames[locktag_type];
1351 : : }
|