Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * lmgr.c
4 : * POSTGRES lock manager code
5 : *
6 : * Portions Copyright (c) 1996-2017, 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/transam.h"
20 : #include "access/xact.h"
21 : #include "catalog/catalog.h"
22 : #include "miscadmin.h"
23 : #include "storage/lmgr.h"
24 : #include "storage/procarray.h"
25 : #include "utils/inval.h"
26 :
27 :
28 : /*
29 : * Per-backend counter for generating speculative insertion tokens.
30 : *
31 : * This may wrap around, but that's OK as it's only used for the short
32 : * duration between inserting a tuple and checking that there are no (unique)
33 : * constraint violations. It's theoretically possible that a backend sees a
34 : * tuple that was speculatively inserted by another backend, but before it has
35 : * started waiting on the token, the other backend completes its insertion,
36 : * and then performs 2^32 unrelated insertions. And after all that, the
37 : * first backend finally calls SpeculativeInsertionLockAcquire(), with the
38 : * intention of waiting for the first insertion to complete, but ends up
39 : * waiting for the latest unrelated insertion instead. Even then, nothing
40 : * particularly bad happens: in the worst case they deadlock, causing one of
41 : * the transactions to abort.
42 : */
43 : static uint32 speculativeInsertionToken = 0;
44 :
45 :
46 : /*
47 : * Struct to hold context info for transaction lock waits.
48 : *
49 : * 'oper' is the operation that needs to wait for the other transaction; 'rel'
50 : * and 'ctid' specify the address of the tuple being waited for.
51 : */
52 : typedef struct XactLockTableWaitInfo
53 : {
54 : XLTW_Oper oper;
55 : Relation rel;
56 : ItemPointer ctid;
57 : } XactLockTableWaitInfo;
58 :
59 : static void XactLockTableWaitErrorCb(void *arg);
60 :
61 : /*
62 : * RelationInitLockInfo
63 : * Initializes the lock information in a relation descriptor.
64 : *
65 : * relcache.c must call this during creation of any reldesc.
66 : */
67 : void
68 70901 : RelationInitLockInfo(Relation relation)
69 : {
70 70901 : Assert(RelationIsValid(relation));
71 70901 : Assert(OidIsValid(RelationGetRelid(relation)));
72 :
73 70901 : relation->rd_lockInfo.lockRelId.relId = RelationGetRelid(relation);
74 :
75 70901 : if (relation->rd_rel->relisshared)
76 7945 : relation->rd_lockInfo.lockRelId.dbId = InvalidOid;
77 : else
78 62956 : relation->rd_lockInfo.lockRelId.dbId = MyDatabaseId;
79 70901 : }
80 :
81 : /*
82 : * SetLocktagRelationOid
83 : * Set up a locktag for a relation, given only relation OID
84 : */
85 : static inline void
86 940254 : SetLocktagRelationOid(LOCKTAG *tag, Oid relid)
87 : {
88 : Oid dbid;
89 :
90 940254 : if (IsSharedRelation(relid))
91 41988 : dbid = InvalidOid;
92 : else
93 898266 : dbid = MyDatabaseId;
94 :
95 940254 : SET_LOCKTAG_RELATION(*tag, dbid, relid);
96 940254 : }
97 :
98 : /*
99 : * LockRelationOid
100 : *
101 : * Lock a relation given only its OID. This should generally be used
102 : * before attempting to open the relation's relcache entry.
103 : */
104 : void
105 939368 : LockRelationOid(Oid relid, LOCKMODE lockmode)
106 : {
107 : LOCKTAG tag;
108 : LockAcquireResult res;
109 :
110 939368 : SetLocktagRelationOid(&tag, relid);
111 :
112 939368 : res = LockAcquire(&tag, lockmode, false, false);
113 :
114 : /*
115 : * Now that we have the lock, check for invalidation messages, so that we
116 : * will update or flush any stale relcache entry before we try to use it.
117 : * RangeVarGetRelid() specifically relies on us for this. We can skip
118 : * this in the not-uncommon case that we already had the same type of lock
119 : * being requested, since then no one else could have modified the
120 : * relcache entry in an undesirable way. (In the case where our own xact
121 : * modifies the rel, the relcache update happens via
122 : * CommandCounterIncrement, not here.)
123 : */
124 939368 : if (res != LOCKACQUIRE_ALREADY_HELD)
125 844276 : AcceptInvalidationMessages();
126 939368 : }
127 :
128 : /*
129 : * ConditionalLockRelationOid
130 : *
131 : * As above, but only lock if we can get the lock without blocking.
132 : * Returns TRUE iff the lock was acquired.
133 : *
134 : * NOTE: we do not currently need conditional versions of all the
135 : * LockXXX routines in this file, but they could easily be added if needed.
136 : */
137 : bool
138 61 : ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
139 : {
140 : LOCKTAG tag;
141 : LockAcquireResult res;
142 :
143 61 : SetLocktagRelationOid(&tag, relid);
144 :
145 61 : res = LockAcquire(&tag, lockmode, false, true);
146 :
147 61 : if (res == LOCKACQUIRE_NOT_AVAIL)
148 2 : return false;
149 :
150 : /*
151 : * Now that we have the lock, check for invalidation messages; see notes
152 : * in LockRelationOid.
153 : */
154 59 : if (res != LOCKACQUIRE_ALREADY_HELD)
155 59 : AcceptInvalidationMessages();
156 :
157 59 : return true;
158 : }
159 :
160 : /*
161 : * UnlockRelationId
162 : *
163 : * Unlock, given a LockRelId. This is preferred over UnlockRelationOid
164 : * for speed reasons.
165 : */
166 : void
167 828830 : UnlockRelationId(LockRelId *relid, LOCKMODE lockmode)
168 : {
169 : LOCKTAG tag;
170 :
171 828830 : SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
172 :
173 828830 : LockRelease(&tag, lockmode, false);
174 828830 : }
175 :
176 : /*
177 : * UnlockRelationOid
178 : *
179 : * Unlock, given only a relation Oid. Use UnlockRelationId if you can.
180 : */
181 : void
182 825 : UnlockRelationOid(Oid relid, LOCKMODE lockmode)
183 : {
184 : LOCKTAG tag;
185 :
186 825 : SetLocktagRelationOid(&tag, relid);
187 :
188 825 : LockRelease(&tag, lockmode, false);
189 825 : }
190 :
191 : /*
192 : * LockRelation
193 : *
194 : * This is a convenience routine for acquiring an additional lock on an
195 : * already-open relation. Never try to do "relation_open(foo, NoLock)"
196 : * and then lock with this.
197 : */
198 : void
199 1365 : LockRelation(Relation relation, LOCKMODE lockmode)
200 : {
201 : LOCKTAG tag;
202 : LockAcquireResult res;
203 :
204 1365 : SET_LOCKTAG_RELATION(tag,
205 : relation->rd_lockInfo.lockRelId.dbId,
206 : relation->rd_lockInfo.lockRelId.relId);
207 :
208 1365 : res = LockAcquire(&tag, lockmode, false, false);
209 :
210 : /*
211 : * Now that we have the lock, check for invalidation messages; see notes
212 : * in LockRelationOid.
213 : */
214 1365 : if (res != LOCKACQUIRE_ALREADY_HELD)
215 1365 : AcceptInvalidationMessages();
216 1365 : }
217 :
218 : /*
219 : * ConditionalLockRelation
220 : *
221 : * This is a convenience routine for acquiring an additional lock on an
222 : * already-open relation. Never try to do "relation_open(foo, NoLock)"
223 : * and then lock with this.
224 : */
225 : bool
226 12 : ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
227 : {
228 : LOCKTAG tag;
229 : LockAcquireResult res;
230 :
231 12 : SET_LOCKTAG_RELATION(tag,
232 : relation->rd_lockInfo.lockRelId.dbId,
233 : relation->rd_lockInfo.lockRelId.relId);
234 :
235 12 : res = LockAcquire(&tag, lockmode, false, true);
236 :
237 12 : if (res == LOCKACQUIRE_NOT_AVAIL)
238 0 : return false;
239 :
240 : /*
241 : * Now that we have the lock, check for invalidation messages; see notes
242 : * in LockRelationOid.
243 : */
244 12 : if (res != LOCKACQUIRE_ALREADY_HELD)
245 12 : AcceptInvalidationMessages();
246 :
247 12 : return true;
248 : }
249 :
250 : /*
251 : * UnlockRelation
252 : *
253 : * This is a convenience routine for unlocking a relation without also
254 : * closing it.
255 : */
256 : void
257 12 : UnlockRelation(Relation relation, LOCKMODE lockmode)
258 : {
259 : LOCKTAG tag;
260 :
261 12 : SET_LOCKTAG_RELATION(tag,
262 : relation->rd_lockInfo.lockRelId.dbId,
263 : relation->rd_lockInfo.lockRelId.relId);
264 :
265 12 : LockRelease(&tag, lockmode, false);
266 12 : }
267 :
268 : /*
269 : * LockHasWaitersRelation
270 : *
271 : * This is a function to check whether someone else is waiting for a
272 : * lock which we are currently holding.
273 : */
274 : bool
275 0 : LockHasWaitersRelation(Relation relation, LOCKMODE lockmode)
276 : {
277 : LOCKTAG tag;
278 :
279 0 : SET_LOCKTAG_RELATION(tag,
280 : relation->rd_lockInfo.lockRelId.dbId,
281 : relation->rd_lockInfo.lockRelId.relId);
282 :
283 0 : return LockHasWaiters(&tag, lockmode, false);
284 : }
285 :
286 : /*
287 : * LockRelationIdForSession
288 : *
289 : * This routine grabs a session-level lock on the target relation. The
290 : * session lock persists across transaction boundaries. It will be removed
291 : * when UnlockRelationIdForSession() is called, or if an ereport(ERROR) occurs,
292 : * or if the backend exits.
293 : *
294 : * Note that one should also grab a transaction-level lock on the rel
295 : * in any transaction that actually uses the rel, to ensure that the
296 : * relcache entry is up to date.
297 : */
298 : void
299 414 : LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
300 : {
301 : LOCKTAG tag;
302 :
303 414 : SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
304 :
305 414 : (void) LockAcquire(&tag, lockmode, true, false);
306 414 : }
307 :
308 : /*
309 : * UnlockRelationIdForSession
310 : */
311 : void
312 411 : UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
313 : {
314 : LOCKTAG tag;
315 :
316 411 : SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
317 :
318 411 : LockRelease(&tag, lockmode, true);
319 411 : }
320 :
321 : /*
322 : * LockRelationForExtension
323 : *
324 : * This lock tag is used to interlock addition of pages to relations.
325 : * We need such locking because bufmgr/smgr definition of P_NEW is not
326 : * race-condition-proof.
327 : *
328 : * We assume the caller is already holding some type of regular lock on
329 : * the relation, so no AcceptInvalidationMessages call is needed here.
330 : */
331 : void
332 2952 : LockRelationForExtension(Relation relation, LOCKMODE lockmode)
333 : {
334 : LOCKTAG tag;
335 :
336 2952 : SET_LOCKTAG_RELATION_EXTEND(tag,
337 : relation->rd_lockInfo.lockRelId.dbId,
338 : relation->rd_lockInfo.lockRelId.relId);
339 :
340 2952 : (void) LockAcquire(&tag, lockmode, false, false);
341 2952 : }
342 :
343 : /*
344 : * ConditionalLockRelationForExtension
345 : *
346 : * As above, but only lock if we can get the lock without blocking.
347 : * Returns TRUE iff the lock was acquired.
348 : */
349 : bool
350 6395 : ConditionalLockRelationForExtension(Relation relation, LOCKMODE lockmode)
351 : {
352 : LOCKTAG tag;
353 :
354 6395 : SET_LOCKTAG_RELATION_EXTEND(tag,
355 : relation->rd_lockInfo.lockRelId.dbId,
356 : relation->rd_lockInfo.lockRelId.relId);
357 :
358 6395 : return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
359 : }
360 :
361 : /*
362 : * RelationExtensionLockWaiterCount
363 : *
364 : * Count the number of processes waiting for the given relation extension lock.
365 : */
366 : int
367 6 : RelationExtensionLockWaiterCount(Relation relation)
368 : {
369 : LOCKTAG tag;
370 :
371 6 : SET_LOCKTAG_RELATION_EXTEND(tag,
372 : relation->rd_lockInfo.lockRelId.dbId,
373 : relation->rd_lockInfo.lockRelId.relId);
374 :
375 6 : return LockWaiterCount(&tag);
376 : }
377 :
378 : /*
379 : * UnlockRelationForExtension
380 : */
381 : void
382 9334 : UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
383 : {
384 : LOCKTAG tag;
385 :
386 9334 : SET_LOCKTAG_RELATION_EXTEND(tag,
387 : relation->rd_lockInfo.lockRelId.dbId,
388 : relation->rd_lockInfo.lockRelId.relId);
389 :
390 9334 : LockRelease(&tag, lockmode, false);
391 9334 : }
392 :
393 : /*
394 : * LockPage
395 : *
396 : * Obtain a page-level lock. This is currently used by some index access
397 : * methods to lock individual index pages.
398 : */
399 : void
400 0 : LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
401 : {
402 : LOCKTAG tag;
403 :
404 0 : SET_LOCKTAG_PAGE(tag,
405 : relation->rd_lockInfo.lockRelId.dbId,
406 : relation->rd_lockInfo.lockRelId.relId,
407 : blkno);
408 :
409 0 : (void) LockAcquire(&tag, lockmode, false, false);
410 0 : }
411 :
412 : /*
413 : * ConditionalLockPage
414 : *
415 : * As above, but only lock if we can get the lock without blocking.
416 : * Returns TRUE iff the lock was acquired.
417 : */
418 : bool
419 7 : ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
420 : {
421 : LOCKTAG tag;
422 :
423 7 : SET_LOCKTAG_PAGE(tag,
424 : relation->rd_lockInfo.lockRelId.dbId,
425 : relation->rd_lockInfo.lockRelId.relId,
426 : blkno);
427 :
428 7 : return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
429 : }
430 :
431 : /*
432 : * UnlockPage
433 : */
434 : void
435 7 : UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
436 : {
437 : LOCKTAG tag;
438 :
439 7 : SET_LOCKTAG_PAGE(tag,
440 : relation->rd_lockInfo.lockRelId.dbId,
441 : relation->rd_lockInfo.lockRelId.relId,
442 : blkno);
443 :
444 7 : LockRelease(&tag, lockmode, false);
445 7 : }
446 :
447 : /*
448 : * LockTuple
449 : *
450 : * Obtain a tuple-level lock. This is used in a less-than-intuitive fashion
451 : * because we can't afford to keep a separate lock in shared memory for every
452 : * tuple. See heap_lock_tuple before using this!
453 : */
454 : void
455 1 : LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
456 : {
457 : LOCKTAG tag;
458 :
459 1 : SET_LOCKTAG_TUPLE(tag,
460 : relation->rd_lockInfo.lockRelId.dbId,
461 : relation->rd_lockInfo.lockRelId.relId,
462 : ItemPointerGetBlockNumber(tid),
463 : ItemPointerGetOffsetNumber(tid));
464 :
465 1 : (void) LockAcquire(&tag, lockmode, false, false);
466 1 : }
467 :
468 : /*
469 : * ConditionalLockTuple
470 : *
471 : * As above, but only lock if we can get the lock without blocking.
472 : * Returns TRUE iff the lock was acquired.
473 : */
474 : bool
475 0 : ConditionalLockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
476 : {
477 : LOCKTAG tag;
478 :
479 0 : SET_LOCKTAG_TUPLE(tag,
480 : relation->rd_lockInfo.lockRelId.dbId,
481 : relation->rd_lockInfo.lockRelId.relId,
482 : ItemPointerGetBlockNumber(tid),
483 : ItemPointerGetOffsetNumber(tid));
484 :
485 0 : return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
486 : }
487 :
488 : /*
489 : * UnlockTuple
490 : */
491 : void
492 1 : UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
493 : {
494 : LOCKTAG tag;
495 :
496 1 : SET_LOCKTAG_TUPLE(tag,
497 : relation->rd_lockInfo.lockRelId.dbId,
498 : relation->rd_lockInfo.lockRelId.relId,
499 : ItemPointerGetBlockNumber(tid),
500 : ItemPointerGetOffsetNumber(tid));
501 :
502 1 : LockRelease(&tag, lockmode, false);
503 1 : }
504 :
505 : /*
506 : * XactLockTableInsert
507 : *
508 : * Insert a lock showing that the given transaction ID is running ---
509 : * this is done when an XID is acquired by a transaction or subtransaction.
510 : * The lock can then be used to wait for the transaction to finish.
511 : */
512 : void
513 10626 : XactLockTableInsert(TransactionId xid)
514 : {
515 : LOCKTAG tag;
516 :
517 10626 : SET_LOCKTAG_TRANSACTION(tag, xid);
518 :
519 10626 : (void) LockAcquire(&tag, ExclusiveLock, false, false);
520 10626 : }
521 :
522 : /*
523 : * XactLockTableDelete
524 : *
525 : * Delete the lock showing that the given transaction ID is running.
526 : * (This is never used for main transaction IDs; those locks are only
527 : * released implicitly at transaction end. But we do use it for subtrans IDs.)
528 : */
529 : void
530 24 : XactLockTableDelete(TransactionId xid)
531 : {
532 : LOCKTAG tag;
533 :
534 24 : SET_LOCKTAG_TRANSACTION(tag, xid);
535 :
536 24 : LockRelease(&tag, ExclusiveLock, false);
537 24 : }
538 :
539 : /*
540 : * XactLockTableWait
541 : *
542 : * Wait for the specified transaction to commit or abort. If an operation
543 : * is specified, an error context callback is set up. If 'oper' is passed as
544 : * None, no error context callback is set up.
545 : *
546 : * Note that this does the right thing for subtransactions: if we wait on a
547 : * subtransaction, we will exit as soon as it aborts or its top parent commits.
548 : * It takes some extra work to ensure this, because to save on shared memory
549 : * the XID lock of a subtransaction is released when it ends, whether
550 : * successfully or unsuccessfully. So we have to check if it's "still running"
551 : * and if so wait for its parent.
552 : */
553 : void
554 1 : XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid,
555 : XLTW_Oper oper)
556 : {
557 : LOCKTAG tag;
558 : XactLockTableWaitInfo info;
559 : ErrorContextCallback callback;
560 :
561 : /*
562 : * If an operation is specified, set up our verbose error context
563 : * callback.
564 : */
565 1 : if (oper != XLTW_None)
566 : {
567 1 : Assert(RelationIsValid(rel));
568 1 : Assert(ItemPointerIsValid(ctid));
569 :
570 1 : info.rel = rel;
571 1 : info.ctid = ctid;
572 1 : info.oper = oper;
573 :
574 1 : callback.callback = XactLockTableWaitErrorCb;
575 1 : callback.arg = &info;
576 1 : callback.previous = error_context_stack;
577 1 : error_context_stack = &callback;
578 : }
579 :
580 : for (;;)
581 : {
582 1 : Assert(TransactionIdIsValid(xid));
583 1 : Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
584 :
585 1 : SET_LOCKTAG_TRANSACTION(tag, xid);
586 :
587 1 : (void) LockAcquire(&tag, ShareLock, false, false);
588 :
589 1 : LockRelease(&tag, ShareLock, false);
590 :
591 1 : if (!TransactionIdIsInProgress(xid))
592 1 : break;
593 0 : xid = SubTransGetParent(xid);
594 0 : }
595 :
596 1 : if (oper != XLTW_None)
597 1 : error_context_stack = callback.previous;
598 1 : }
599 :
600 : /*
601 : * ConditionalXactLockTableWait
602 : *
603 : * As above, but only lock if we can get the lock without blocking.
604 : * Returns TRUE if the lock was acquired.
605 : */
606 : bool
607 0 : ConditionalXactLockTableWait(TransactionId xid)
608 : {
609 : LOCKTAG tag;
610 :
611 : for (;;)
612 : {
613 0 : Assert(TransactionIdIsValid(xid));
614 0 : Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
615 :
616 0 : SET_LOCKTAG_TRANSACTION(tag, xid);
617 :
618 0 : if (LockAcquire(&tag, ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL)
619 0 : return false;
620 :
621 0 : LockRelease(&tag, ShareLock, false);
622 :
623 0 : if (!TransactionIdIsInProgress(xid))
624 0 : break;
625 0 : xid = SubTransGetParent(xid);
626 0 : }
627 :
628 0 : return true;
629 : }
630 :
631 : /*
632 : * SpeculativeInsertionLockAcquire
633 : *
634 : * Insert a lock showing that the given transaction ID is inserting a tuple,
635 : * but hasn't yet decided whether it's going to keep it. The lock can then be
636 : * used to wait for the decision to go ahead with the insertion, or aborting
637 : * it.
638 : *
639 : * The token is used to distinguish multiple insertions by the same
640 : * transaction. It is returned to caller.
641 : */
642 : uint32
643 55 : SpeculativeInsertionLockAcquire(TransactionId xid)
644 : {
645 : LOCKTAG tag;
646 :
647 55 : speculativeInsertionToken++;
648 :
649 : /*
650 : * Check for wrap-around. Zero means no token is held, so don't use that.
651 : */
652 55 : if (speculativeInsertionToken == 0)
653 0 : speculativeInsertionToken = 1;
654 :
655 55 : SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
656 :
657 55 : (void) LockAcquire(&tag, ExclusiveLock, false, false);
658 :
659 55 : return speculativeInsertionToken;
660 : }
661 :
662 : /*
663 : * SpeculativeInsertionLockRelease
664 : *
665 : * Delete the lock showing that the given transaction is speculatively
666 : * inserting a tuple.
667 : */
668 : void
669 54 : SpeculativeInsertionLockRelease(TransactionId xid)
670 : {
671 : LOCKTAG tag;
672 :
673 54 : SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
674 :
675 54 : LockRelease(&tag, ExclusiveLock, false);
676 54 : }
677 :
678 : /*
679 : * SpeculativeInsertionWait
680 : *
681 : * Wait for the specified transaction to finish or abort the insertion of a
682 : * tuple.
683 : */
684 : void
685 0 : SpeculativeInsertionWait(TransactionId xid, uint32 token)
686 : {
687 : LOCKTAG tag;
688 :
689 0 : SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, token);
690 :
691 0 : Assert(TransactionIdIsValid(xid));
692 0 : Assert(token != 0);
693 :
694 0 : (void) LockAcquire(&tag, ShareLock, false, false);
695 0 : LockRelease(&tag, ShareLock, false);
696 0 : }
697 :
698 : /*
699 : * XactLockTableWaitErrorContextCb
700 : * Error context callback for transaction lock waits.
701 : */
702 : static void
703 0 : XactLockTableWaitErrorCb(void *arg)
704 : {
705 0 : XactLockTableWaitInfo *info = (XactLockTableWaitInfo *) arg;
706 :
707 : /*
708 : * We would like to print schema name too, but that would require a
709 : * syscache lookup.
710 : */
711 0 : if (info->oper != XLTW_None &&
712 0 : ItemPointerIsValid(info->ctid) && RelationIsValid(info->rel))
713 : {
714 : const char *cxt;
715 :
716 0 : switch (info->oper)
717 : {
718 : case XLTW_Update:
719 0 : cxt = gettext_noop("while updating tuple (%u,%u) in relation \"%s\"");
720 0 : break;
721 : case XLTW_Delete:
722 0 : cxt = gettext_noop("while deleting tuple (%u,%u) in relation \"%s\"");
723 0 : break;
724 : case XLTW_Lock:
725 0 : cxt = gettext_noop("while locking tuple (%u,%u) in relation \"%s\"");
726 0 : break;
727 : case XLTW_LockUpdated:
728 0 : cxt = gettext_noop("while locking updated version (%u,%u) of tuple in relation \"%s\"");
729 0 : break;
730 : case XLTW_InsertIndex:
731 0 : cxt = gettext_noop("while inserting index tuple (%u,%u) in relation \"%s\"");
732 0 : break;
733 : case XLTW_InsertIndexUnique:
734 0 : cxt = gettext_noop("while checking uniqueness of tuple (%u,%u) in relation \"%s\"");
735 0 : break;
736 : case XLTW_FetchUpdated:
737 0 : cxt = gettext_noop("while rechecking updated tuple (%u,%u) in relation \"%s\"");
738 0 : break;
739 : case XLTW_RecheckExclusionConstr:
740 0 : cxt = gettext_noop("while checking exclusion constraint on tuple (%u,%u) in relation \"%s\"");
741 0 : break;
742 :
743 : default:
744 0 : return;
745 : }
746 :
747 0 : errcontext(cxt,
748 0 : ItemPointerGetBlockNumber(info->ctid),
749 0 : ItemPointerGetOffsetNumber(info->ctid),
750 0 : RelationGetRelationName(info->rel));
751 : }
752 : }
753 :
754 : /*
755 : * WaitForLockersMultiple
756 : * Wait until no transaction holds locks that conflict with the given
757 : * locktags at the given lockmode.
758 : *
759 : * To do this, obtain the current list of lockers, and wait on their VXIDs
760 : * until they are finished.
761 : *
762 : * Note we don't try to acquire the locks on the given locktags, only the VXIDs
763 : * of its lock holders; if somebody grabs a conflicting lock on the objects
764 : * after we obtained our initial list of lockers, we will not wait for them.
765 : */
766 : void
767 23 : WaitForLockersMultiple(List *locktags, LOCKMODE lockmode)
768 : {
769 23 : List *holders = NIL;
770 : ListCell *lc;
771 :
772 : /* Done if no locks to wait for */
773 23 : if (list_length(locktags) == 0)
774 23 : return;
775 :
776 : /* Collect the transactions we need to wait on */
777 46 : foreach(lc, locktags)
778 : {
779 23 : LOCKTAG *locktag = lfirst(lc);
780 :
781 23 : holders = lappend(holders, GetLockConflicts(locktag, lockmode));
782 : }
783 :
784 : /*
785 : * Note: GetLockConflicts() never reports our own xid, hence we need not
786 : * check for that. Also, prepared xacts are not reported, which is fine
787 : * since they certainly aren't going to do anything anymore.
788 : */
789 :
790 : /* Finally wait for each such transaction to complete */
791 46 : foreach(lc, holders)
792 : {
793 23 : VirtualTransactionId *lockholders = lfirst(lc);
794 :
795 46 : while (VirtualTransactionIdIsValid(*lockholders))
796 : {
797 0 : VirtualXactLock(*lockholders, true);
798 0 : lockholders++;
799 : }
800 : }
801 :
802 23 : list_free_deep(holders);
803 : }
804 :
805 : /*
806 : * WaitForLockers
807 : *
808 : * Same as WaitForLockersMultiple, for a single lock tag.
809 : */
810 : void
811 23 : WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode)
812 : {
813 : List *l;
814 :
815 23 : l = list_make1(&heaplocktag);
816 23 : WaitForLockersMultiple(l, lockmode);
817 23 : list_free(l);
818 23 : }
819 :
820 :
821 : /*
822 : * LockDatabaseObject
823 : *
824 : * Obtain a lock on a general object of the current database. Don't use
825 : * this for shared objects (such as tablespaces). It's unwise to apply it
826 : * to relations, also, since a lock taken this way will NOT conflict with
827 : * locks taken via LockRelation and friends.
828 : */
829 : void
830 12673 : LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
831 : LOCKMODE lockmode)
832 : {
833 : LOCKTAG tag;
834 :
835 12673 : SET_LOCKTAG_OBJECT(tag,
836 : MyDatabaseId,
837 : classid,
838 : objid,
839 : objsubid);
840 :
841 12673 : (void) LockAcquire(&tag, lockmode, false, false);
842 :
843 : /* Make sure syscaches are up-to-date with any changes we waited for */
844 12673 : AcceptInvalidationMessages();
845 12673 : }
846 :
847 : /*
848 : * UnlockDatabaseObject
849 : */
850 : void
851 115 : UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
852 : LOCKMODE lockmode)
853 : {
854 : LOCKTAG tag;
855 :
856 115 : SET_LOCKTAG_OBJECT(tag,
857 : MyDatabaseId,
858 : classid,
859 : objid,
860 : objsubid);
861 :
862 115 : LockRelease(&tag, lockmode, false);
863 115 : }
864 :
865 : /*
866 : * LockSharedObject
867 : *
868 : * Obtain a lock on a shared-across-databases object.
869 : */
870 : void
871 1072 : LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
872 : LOCKMODE lockmode)
873 : {
874 : LOCKTAG tag;
875 :
876 1072 : SET_LOCKTAG_OBJECT(tag,
877 : InvalidOid,
878 : classid,
879 : objid,
880 : objsubid);
881 :
882 1072 : (void) LockAcquire(&tag, lockmode, false, false);
883 :
884 : /* Make sure syscaches are up-to-date with any changes we waited for */
885 1072 : AcceptInvalidationMessages();
886 1072 : }
887 :
888 : /*
889 : * UnlockSharedObject
890 : */
891 : void
892 6 : UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
893 : LOCKMODE lockmode)
894 : {
895 : LOCKTAG tag;
896 :
897 6 : SET_LOCKTAG_OBJECT(tag,
898 : InvalidOid,
899 : classid,
900 : objid,
901 : objsubid);
902 :
903 6 : LockRelease(&tag, lockmode, false);
904 6 : }
905 :
906 : /*
907 : * LockSharedObjectForSession
908 : *
909 : * Obtain a session-level lock on a shared-across-databases object.
910 : * See LockRelationIdForSession for notes about session-level locks.
911 : */
912 : void
913 0 : LockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
914 : LOCKMODE lockmode)
915 : {
916 : LOCKTAG tag;
917 :
918 0 : SET_LOCKTAG_OBJECT(tag,
919 : InvalidOid,
920 : classid,
921 : objid,
922 : objsubid);
923 :
924 0 : (void) LockAcquire(&tag, lockmode, true, false);
925 0 : }
926 :
927 : /*
928 : * UnlockSharedObjectForSession
929 : */
930 : void
931 0 : UnlockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
932 : LOCKMODE lockmode)
933 : {
934 : LOCKTAG tag;
935 :
936 0 : SET_LOCKTAG_OBJECT(tag,
937 : InvalidOid,
938 : classid,
939 : objid,
940 : objsubid);
941 :
942 0 : LockRelease(&tag, lockmode, true);
943 0 : }
944 :
945 :
946 : /*
947 : * Append a description of a lockable object to buf.
948 : *
949 : * Ideally we would print names for the numeric values, but that requires
950 : * getting locks on system tables, which might cause problems since this is
951 : * typically used to report deadlock situations.
952 : */
953 : void
954 0 : DescribeLockTag(StringInfo buf, const LOCKTAG *tag)
955 : {
956 0 : switch ((LockTagType) tag->locktag_type)
957 : {
958 : case LOCKTAG_RELATION:
959 0 : appendStringInfo(buf,
960 : _("relation %u of database %u"),
961 : tag->locktag_field2,
962 : tag->locktag_field1);
963 0 : break;
964 : case LOCKTAG_RELATION_EXTEND:
965 0 : appendStringInfo(buf,
966 : _("extension of relation %u of database %u"),
967 : tag->locktag_field2,
968 : tag->locktag_field1);
969 0 : break;
970 : case LOCKTAG_PAGE:
971 0 : appendStringInfo(buf,
972 : _("page %u of relation %u of database %u"),
973 : tag->locktag_field3,
974 : tag->locktag_field2,
975 : tag->locktag_field1);
976 0 : break;
977 : case LOCKTAG_TUPLE:
978 0 : appendStringInfo(buf,
979 : _("tuple (%u,%u) of relation %u of database %u"),
980 : tag->locktag_field3,
981 0 : tag->locktag_field4,
982 : tag->locktag_field2,
983 : tag->locktag_field1);
984 0 : break;
985 : case LOCKTAG_TRANSACTION:
986 0 : appendStringInfo(buf,
987 : _("transaction %u"),
988 : tag->locktag_field1);
989 0 : break;
990 : case LOCKTAG_VIRTUALTRANSACTION:
991 0 : appendStringInfo(buf,
992 : _("virtual transaction %d/%u"),
993 : tag->locktag_field1,
994 : tag->locktag_field2);
995 0 : break;
996 : case LOCKTAG_SPECULATIVE_TOKEN:
997 0 : appendStringInfo(buf,
998 : _("speculative token %u of transaction %u"),
999 : tag->locktag_field2,
1000 : tag->locktag_field1);
1001 0 : break;
1002 : case LOCKTAG_OBJECT:
1003 0 : appendStringInfo(buf,
1004 : _("object %u of class %u of database %u"),
1005 : tag->locktag_field3,
1006 : tag->locktag_field2,
1007 : tag->locktag_field1);
1008 0 : break;
1009 : case LOCKTAG_USERLOCK:
1010 : /* reserved for old contrib code, now on pgfoundry */
1011 0 : appendStringInfo(buf,
1012 : _("user lock [%u,%u,%u]"),
1013 : tag->locktag_field1,
1014 : tag->locktag_field2,
1015 : tag->locktag_field3);
1016 0 : break;
1017 : case LOCKTAG_ADVISORY:
1018 0 : appendStringInfo(buf,
1019 : _("advisory lock [%u,%u,%u,%u]"),
1020 : tag->locktag_field1,
1021 : tag->locktag_field2,
1022 : tag->locktag_field3,
1023 0 : tag->locktag_field4);
1024 0 : break;
1025 : default:
1026 0 : appendStringInfo(buf,
1027 : _("unrecognized locktag type %d"),
1028 0 : (int) tag->locktag_type);
1029 0 : break;
1030 : }
1031 0 : }
1032 :
1033 : /*
1034 : * GetLockNameFromTagType
1035 : *
1036 : * Given locktag type, return the corresponding lock name.
1037 : */
1038 : const char *
1039 0 : GetLockNameFromTagType(uint16 locktag_type)
1040 : {
1041 0 : if (locktag_type > LOCKTAG_LAST_TYPE)
1042 0 : return "???";
1043 0 : return LockTagTypeNames[locktag_type];
1044 : }
|