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