PostgreSQL Source Code  git master
lockfuncs.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * lockfuncs.c
4  * Functions for SQL access to various lock-manager capabilities.
5  *
6  * Copyright (c) 2002-2022, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  * src/backend/utils/adt/lockfuncs.c
10  *
11  *-------------------------------------------------------------------------
12  */
13 #include "postgres.h"
14 
15 #include "access/htup_details.h"
16 #include "access/xact.h"
17 #include "catalog/pg_type.h"
18 #include "funcapi.h"
19 #include "miscadmin.h"
21 #include "utils/array.h"
22 #include "utils/builtins.h"
23 
24 
25 /*
26  * This must match enum LockTagType! Also, be sure to document any changes
27  * in the docs for the pg_locks view and for wait event types.
28  */
29 const char *const LockTagTypeNames[] = {
30  "relation",
31  "extend",
32  "frozenid",
33  "page",
34  "tuple",
35  "transactionid",
36  "virtualxid",
37  "spectoken",
38  "object",
39  "userlock",
40  "advisory"
41 };
42 
44  "array length mismatch");
45 
46 /* This must match enum PredicateLockTargetType (predicate_internals.h) */
47 static const char *const PredicateLockTagTypeNames[] = {
48  "relation",
49  "page",
50  "tuple"
51 };
52 
54  "array length mismatch");
55 
56 /* Working status for pg_lock_status */
57 typedef struct
58 {
59  LockData *lockData; /* state data from lmgr */
60  int currIdx; /* current PROCLOCK index */
61  PredicateLockData *predLockData; /* state data for pred locks */
62  int predLockIdx; /* current index for pred lock */
64 
65 /* Number of columns in pg_locks output */
66 #define NUM_LOCK_STATUS_COLUMNS 16
67 
68 /*
69  * VXIDGetDatum - Construct a text representation of a VXID
70  *
71  * This is currently only used in pg_lock_status, so we put it here.
72  */
73 static Datum
75 {
76  /*
77  * The representation is "<bid>/<lxid>", decimal and unsigned decimal
78  * respectively. Note that elog.c also knows how to format a vxid.
79  */
80  char vxidstr[32];
81 
82  snprintf(vxidstr, sizeof(vxidstr), "%d/%u", bid, lxid);
83 
84  return CStringGetTextDatum(vxidstr);
85 }
86 
87 
88 /*
89  * pg_lock_status - produce a view with one row per held or awaited lock mode
90  */
91 Datum
93 {
94  FuncCallContext *funcctx;
95  PG_Lock_Status *mystatus;
96  LockData *lockData;
97  PredicateLockData *predLockData;
98 
99  if (SRF_IS_FIRSTCALL())
100  {
101  TupleDesc tupdesc;
102  MemoryContext oldcontext;
103 
104  /* create a function context for cross-call persistence */
105  funcctx = SRF_FIRSTCALL_INIT();
106 
107  /*
108  * switch to memory context appropriate for multiple function calls
109  */
110  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
111 
112  /* build tupdesc for result tuples */
113  /* this had better match function's declaration in pg_proc.h */
115  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype",
116  TEXTOID, -1, 0);
117  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
118  OIDOID, -1, 0);
119  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation",
120  OIDOID, -1, 0);
121  TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page",
122  INT4OID, -1, 0);
123  TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple",
124  INT2OID, -1, 0);
125  TupleDescInitEntry(tupdesc, (AttrNumber) 6, "virtualxid",
126  TEXTOID, -1, 0);
127  TupleDescInitEntry(tupdesc, (AttrNumber) 7, "transactionid",
128  XIDOID, -1, 0);
129  TupleDescInitEntry(tupdesc, (AttrNumber) 8, "classid",
130  OIDOID, -1, 0);
131  TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objid",
132  OIDOID, -1, 0);
133  TupleDescInitEntry(tupdesc, (AttrNumber) 10, "objsubid",
134  INT2OID, -1, 0);
135  TupleDescInitEntry(tupdesc, (AttrNumber) 11, "virtualtransaction",
136  TEXTOID, -1, 0);
137  TupleDescInitEntry(tupdesc, (AttrNumber) 12, "pid",
138  INT4OID, -1, 0);
139  TupleDescInitEntry(tupdesc, (AttrNumber) 13, "mode",
140  TEXTOID, -1, 0);
141  TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted",
142  BOOLOID, -1, 0);
143  TupleDescInitEntry(tupdesc, (AttrNumber) 15, "fastpath",
144  BOOLOID, -1, 0);
145  TupleDescInitEntry(tupdesc, (AttrNumber) 16, "waitstart",
146  TIMESTAMPTZOID, -1, 0);
147 
148  funcctx->tuple_desc = BlessTupleDesc(tupdesc);
149 
150  /*
151  * Collect all the locking information that we will format and send
152  * out as a result set.
153  */
154  mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status));
155  funcctx->user_fctx = (void *) mystatus;
156 
157  mystatus->lockData = GetLockStatusData();
158  mystatus->currIdx = 0;
160  mystatus->predLockIdx = 0;
161 
162  MemoryContextSwitchTo(oldcontext);
163  }
164 
165  funcctx = SRF_PERCALL_SETUP();
166  mystatus = (PG_Lock_Status *) funcctx->user_fctx;
167  lockData = mystatus->lockData;
168 
169  while (mystatus->currIdx < lockData->nelements)
170  {
171  bool granted;
172  LOCKMODE mode = 0;
173  const char *locktypename;
174  char tnbuf[32];
176  bool nulls[NUM_LOCK_STATUS_COLUMNS] = {0};
177  HeapTuple tuple;
178  Datum result;
179  LockInstanceData *instance;
180 
181  instance = &(lockData->locks[mystatus->currIdx]);
182 
183  /*
184  * Look to see if there are any held lock modes in this PROCLOCK. If
185  * so, report, and destructively modify lockData so we don't report
186  * again.
187  */
188  granted = false;
189  if (instance->holdMask)
190  {
191  for (mode = 0; mode < MAX_LOCKMODES; mode++)
192  {
193  if (instance->holdMask & LOCKBIT_ON(mode))
194  {
195  granted = true;
196  instance->holdMask &= LOCKBIT_OFF(mode);
197  break;
198  }
199  }
200  }
201 
202  /*
203  * If no (more) held modes to report, see if PROC is waiting for a
204  * lock on this lock.
205  */
206  if (!granted)
207  {
208  if (instance->waitLockMode != NoLock)
209  {
210  /* Yes, so report it with proper mode */
211  mode = instance->waitLockMode;
212 
213  /*
214  * We are now done with this PROCLOCK, so advance pointer to
215  * continue with next one on next call.
216  */
217  mystatus->currIdx++;
218  }
219  else
220  {
221  /*
222  * Okay, we've displayed all the locks associated with this
223  * PROCLOCK, proceed to the next one.
224  */
225  mystatus->currIdx++;
226  continue;
227  }
228  }
229 
230  /*
231  * Form tuple with appropriate data.
232  */
233 
234  if (instance->locktag.locktag_type <= LOCKTAG_LAST_TYPE)
235  locktypename = LockTagTypeNames[instance->locktag.locktag_type];
236  else
237  {
238  snprintf(tnbuf, sizeof(tnbuf), "unknown %d",
239  (int) instance->locktag.locktag_type);
240  locktypename = tnbuf;
241  }
242  values[0] = CStringGetTextDatum(locktypename);
243 
244  switch ((LockTagType) instance->locktag.locktag_type)
245  {
246  case LOCKTAG_RELATION:
250  nulls[3] = true;
251  nulls[4] = true;
252  nulls[5] = true;
253  nulls[6] = true;
254  nulls[7] = true;
255  nulls[8] = true;
256  nulls[9] = true;
257  break;
260  nulls[2] = true;
261  nulls[3] = true;
262  nulls[4] = true;
263  nulls[5] = true;
264  nulls[6] = true;
265  nulls[7] = true;
266  nulls[8] = true;
267  nulls[9] = true;
268  break;
269  case LOCKTAG_PAGE:
273  nulls[4] = true;
274  nulls[5] = true;
275  nulls[6] = true;
276  nulls[7] = true;
277  nulls[8] = true;
278  nulls[9] = true;
279  break;
280  case LOCKTAG_TUPLE:
285  nulls[5] = true;
286  nulls[6] = true;
287  nulls[7] = true;
288  nulls[8] = true;
289  nulls[9] = true;
290  break;
291  case LOCKTAG_TRANSACTION:
292  values[6] =
294  nulls[1] = true;
295  nulls[2] = true;
296  nulls[3] = true;
297  nulls[4] = true;
298  nulls[5] = true;
299  nulls[7] = true;
300  nulls[8] = true;
301  nulls[9] = true;
302  break;
304  values[5] = VXIDGetDatum(instance->locktag.locktag_field1,
305  instance->locktag.locktag_field2);
306  nulls[1] = true;
307  nulls[2] = true;
308  nulls[3] = true;
309  nulls[4] = true;
310  nulls[6] = true;
311  nulls[7] = true;
312  nulls[8] = true;
313  nulls[9] = true;
314  break;
315  case LOCKTAG_OBJECT:
316  case LOCKTAG_USERLOCK:
317  case LOCKTAG_ADVISORY:
318  default: /* treat unknown locktags like OBJECT */
322  values[9] = Int16GetDatum(instance->locktag.locktag_field4);
323  nulls[2] = true;
324  nulls[3] = true;
325  nulls[4] = true;
326  nulls[5] = true;
327  nulls[6] = true;
328  break;
329  }
330 
331  values[10] = VXIDGetDatum(instance->backend, instance->lxid);
332  if (instance->pid != 0)
333  values[11] = Int32GetDatum(instance->pid);
334  else
335  nulls[11] = true;
337  values[13] = BoolGetDatum(granted);
338  values[14] = BoolGetDatum(instance->fastpath);
339  if (!granted && instance->waitStart != 0)
340  values[15] = TimestampTzGetDatum(instance->waitStart);
341  else
342  nulls[15] = true;
343 
344  tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
345  result = HeapTupleGetDatum(tuple);
346  SRF_RETURN_NEXT(funcctx, result);
347  }
348 
349  /*
350  * Have returned all regular locks. Now start on the SIREAD predicate
351  * locks.
352  */
353  predLockData = mystatus->predLockData;
354  if (mystatus->predLockIdx < predLockData->nelements)
355  {
356  PredicateLockTargetType lockType;
357 
358  PREDICATELOCKTARGETTAG *predTag = &(predLockData->locktags[mystatus->predLockIdx]);
359  SERIALIZABLEXACT *xact = &(predLockData->xacts[mystatus->predLockIdx]);
361  bool nulls[NUM_LOCK_STATUS_COLUMNS] = {0};
362  HeapTuple tuple;
363  Datum result;
364 
365  mystatus->predLockIdx++;
366 
367  /*
368  * Form tuple with appropriate data.
369  */
370 
371  /* lock type */
372  lockType = GET_PREDICATELOCKTARGETTAG_TYPE(*predTag);
373 
375 
376  /* lock target */
377  values[1] = GET_PREDICATELOCKTARGETTAG_DB(*predTag);
379  if (lockType == PREDLOCKTAG_TUPLE)
381  else
382  nulls[4] = true;
383  if ((lockType == PREDLOCKTAG_TUPLE) ||
384  (lockType == PREDLOCKTAG_PAGE))
386  else
387  nulls[3] = true;
388 
389  /* these fields are targets for other types of locks */
390  nulls[5] = true; /* virtualxid */
391  nulls[6] = true; /* transactionid */
392  nulls[7] = true; /* classid */
393  nulls[8] = true; /* objid */
394  nulls[9] = true; /* objsubid */
395 
396  /* lock holder */
397  values[10] = VXIDGetDatum(xact->vxid.backendId,
398  xact->vxid.localTransactionId);
399  if (xact->pid != 0)
400  values[11] = Int32GetDatum(xact->pid);
401  else
402  nulls[11] = true;
403 
404  /*
405  * Lock mode. Currently all predicate locks are SIReadLocks, which are
406  * always held (never waiting) and have no fast path
407  */
408  values[12] = CStringGetTextDatum("SIReadLock");
409  values[13] = BoolGetDatum(true);
410  values[14] = BoolGetDatum(false);
411  nulls[15] = true;
412 
413  tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
414  result = HeapTupleGetDatum(tuple);
415  SRF_RETURN_NEXT(funcctx, result);
416  }
417 
418  SRF_RETURN_DONE(funcctx);
419 }
420 
421 
422 /*
423  * pg_blocking_pids - produce an array of the PIDs blocking given PID
424  *
425  * The reported PIDs are those that hold a lock conflicting with blocked_pid's
426  * current request (hard block), or are requesting such a lock and are ahead
427  * of blocked_pid in the lock's wait queue (soft block).
428  *
429  * In parallel-query cases, we report all PIDs blocking any member of the
430  * given PID's lock group, and the reported PIDs are those of the blocking
431  * PIDs' lock group leaders. This allows callers to compare the result to
432  * lists of clients' pg_backend_pid() results even during a parallel query.
433  *
434  * Parallel query makes it possible for there to be duplicate PIDs in the
435  * result (either because multiple waiters are blocked by same PID, or
436  * because multiple blockers have same group leader PID). We do not bother
437  * to eliminate such duplicates from the result.
438  *
439  * We need not consider predicate locks here, since those don't block anything.
440  */
441 Datum
443 {
444  int blocked_pid = PG_GETARG_INT32(0);
445  Datum *arrayelems;
446  int narrayelems;
447  BlockedProcsData *lockData; /* state data from lmgr */
448  int i,
449  j;
450 
451  /* Collect a snapshot of lock manager state */
452  lockData = GetBlockerStatusData(blocked_pid);
453 
454  /* We can't need more output entries than there are reported PROCLOCKs */
455  arrayelems = (Datum *) palloc(lockData->nlocks * sizeof(Datum));
456  narrayelems = 0;
457 
458  /* For each blocked proc in the lock group ... */
459  for (i = 0; i < lockData->nprocs; i++)
460  {
461  BlockedProcData *bproc = &lockData->procs[i];
462  LockInstanceData *instances = &lockData->locks[bproc->first_lock];
463  int *preceding_waiters = &lockData->waiter_pids[bproc->first_waiter];
464  LockInstanceData *blocked_instance;
465  LockMethod lockMethodTable;
466  int conflictMask;
467 
468  /*
469  * Locate the blocked proc's own entry in the LockInstanceData array.
470  * There should be exactly one matching entry.
471  */
472  blocked_instance = NULL;
473  for (j = 0; j < bproc->num_locks; j++)
474  {
475  LockInstanceData *instance = &(instances[j]);
476 
477  if (instance->pid == bproc->pid)
478  {
479  Assert(blocked_instance == NULL);
480  blocked_instance = instance;
481  }
482  }
483  Assert(blocked_instance != NULL);
484 
485  lockMethodTable = GetLockTagsMethodTable(&(blocked_instance->locktag));
486  conflictMask = lockMethodTable->conflictTab[blocked_instance->waitLockMode];
487 
488  /* Now scan the PROCLOCK data for conflicting procs */
489  for (j = 0; j < bproc->num_locks; j++)
490  {
491  LockInstanceData *instance = &(instances[j]);
492 
493  /* A proc never blocks itself, so ignore that entry */
494  if (instance == blocked_instance)
495  continue;
496  /* Members of same lock group never block each other, either */
497  if (instance->leaderPid == blocked_instance->leaderPid)
498  continue;
499 
500  if (conflictMask & instance->holdMask)
501  {
502  /* hard block: blocked by lock already held by this entry */
503  }
504  else if (instance->waitLockMode != NoLock &&
505  (conflictMask & LOCKBIT_ON(instance->waitLockMode)))
506  {
507  /* conflict in lock requests; who's in front in wait queue? */
508  bool ahead = false;
509  int k;
510 
511  for (k = 0; k < bproc->num_waiters; k++)
512  {
513  if (preceding_waiters[k] == instance->pid)
514  {
515  /* soft block: this entry is ahead of blocked proc */
516  ahead = true;
517  break;
518  }
519  }
520  if (!ahead)
521  continue; /* not blocked by this entry */
522  }
523  else
524  {
525  /* not blocked by this entry */
526  continue;
527  }
528 
529  /* blocked by this entry, so emit a record */
530  arrayelems[narrayelems++] = Int32GetDatum(instance->leaderPid);
531  }
532  }
533 
534  /* Assert we didn't overrun arrayelems[] */
535  Assert(narrayelems <= lockData->nlocks);
536 
537  PG_RETURN_ARRAYTYPE_P(construct_array_builtin(arrayelems, narrayelems, INT4OID));
538 }
539 
540 
541 /*
542  * pg_safe_snapshot_blocking_pids - produce an array of the PIDs blocking
543  * given PID from getting a safe snapshot
544  *
545  * XXX this does not consider parallel-query cases; not clear how big a
546  * problem that is in practice
547  */
548 Datum
550 {
551  int blocked_pid = PG_GETARG_INT32(0);
552  int *blockers;
553  int num_blockers;
554  Datum *blocker_datums;
555 
556  /* A buffer big enough for any possible blocker list without truncation */
557  blockers = (int *) palloc(MaxBackends * sizeof(int));
558 
559  /* Collect a snapshot of processes waited for by GetSafeSnapshot */
560  num_blockers =
561  GetSafeSnapshotBlockingPids(blocked_pid, blockers, MaxBackends);
562 
563  /* Convert int array to Datum array */
564  if (num_blockers > 0)
565  {
566  int i;
567 
568  blocker_datums = (Datum *) palloc(num_blockers * sizeof(Datum));
569  for (i = 0; i < num_blockers; ++i)
570  blocker_datums[i] = Int32GetDatum(blockers[i]);
571  }
572  else
573  blocker_datums = NULL;
574 
575  PG_RETURN_ARRAYTYPE_P(construct_array_builtin(blocker_datums, num_blockers, INT4OID));
576 }
577 
578 
579 /*
580  * pg_isolation_test_session_is_blocked - support function for isolationtester
581  *
582  * Check if specified PID is blocked by any of the PIDs listed in the second
583  * argument. Currently, this looks for blocking caused by waiting for
584  * heavyweight locks or safe snapshots. We ignore blockage caused by PIDs
585  * not directly under the isolationtester's control, eg autovacuum.
586  *
587  * This is an undocumented function intended for use by the isolation tester,
588  * and may change in future releases as required for testing purposes.
589  */
590 Datum
592 {
593  int blocked_pid = PG_GETARG_INT32(0);
594  ArrayType *interesting_pids_a = PG_GETARG_ARRAYTYPE_P(1);
595  ArrayType *blocking_pids_a;
596  int32 *interesting_pids;
597  int32 *blocking_pids;
598  int num_interesting_pids;
599  int num_blocking_pids;
600  int dummy;
601  int i,
602  j;
603 
604  /* Validate the passed-in array */
605  Assert(ARR_ELEMTYPE(interesting_pids_a) == INT4OID);
606  if (array_contains_nulls(interesting_pids_a))
607  elog(ERROR, "array must not contain nulls");
608  interesting_pids = (int32 *) ARR_DATA_PTR(interesting_pids_a);
609  num_interesting_pids = ArrayGetNItems(ARR_NDIM(interesting_pids_a),
610  ARR_DIMS(interesting_pids_a));
611 
612  /*
613  * Get the PIDs of all sessions blocking the given session's attempt to
614  * acquire heavyweight locks.
615  */
616  blocking_pids_a =
618 
619  Assert(ARR_ELEMTYPE(blocking_pids_a) == INT4OID);
620  Assert(!array_contains_nulls(blocking_pids_a));
621  blocking_pids = (int32 *) ARR_DATA_PTR(blocking_pids_a);
622  num_blocking_pids = ArrayGetNItems(ARR_NDIM(blocking_pids_a),
623  ARR_DIMS(blocking_pids_a));
624 
625  /*
626  * Check if any of these are in the list of interesting PIDs, that being
627  * the sessions that the isolation tester is running. We don't use
628  * "arrayoverlaps" here, because it would lead to cache lookups and one of
629  * our goals is to run quickly with debug_discard_caches > 0. We expect
630  * blocking_pids to be usually empty and otherwise a very small number in
631  * isolation tester cases, so make that the outer loop of a naive search
632  * for a match.
633  */
634  for (i = 0; i < num_blocking_pids; i++)
635  for (j = 0; j < num_interesting_pids; j++)
636  {
637  if (blocking_pids[i] == interesting_pids[j])
638  PG_RETURN_BOOL(true);
639  }
640 
641  /*
642  * Check if blocked_pid is waiting for a safe snapshot. We could in
643  * theory check the resulting array of blocker PIDs against the
644  * interesting PIDs list, but since there is no danger of autovacuum
645  * blocking GetSafeSnapshot there seems to be no point in expending cycles
646  * on allocating a buffer and searching for overlap; so it's presently
647  * sufficient for the isolation tester's purposes to use a single element
648  * buffer and check if the number of safe snapshot blockers is non-zero.
649  */
650  if (GetSafeSnapshotBlockingPids(blocked_pid, &dummy, 1) > 0)
651  PG_RETURN_BOOL(true);
652 
653  PG_RETURN_BOOL(false);
654 }
655 
656 
657 /*
658  * Functions for manipulating advisory locks
659  *
660  * We make use of the locktag fields as follows:
661  *
662  * field1: MyDatabaseId ... ensures locks are local to each database
663  * field2: first of 2 int4 keys, or high-order half of an int8 key
664  * field3: second of 2 int4 keys, or low-order half of an int8 key
665  * field4: 1 if using an int8 key, 2 if using 2 int4 keys
666  */
667 #define SET_LOCKTAG_INT64(tag, key64) \
668  SET_LOCKTAG_ADVISORY(tag, \
669  MyDatabaseId, \
670  (uint32) ((key64) >> 32), \
671  (uint32) (key64), \
672  1)
673 #define SET_LOCKTAG_INT32(tag, key1, key2) \
674  SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key1, key2, 2)
675 
676 /*
677  * pg_advisory_lock(int8) - acquire exclusive lock on an int8 key
678  */
679 Datum
681 {
682  int64 key = PG_GETARG_INT64(0);
683  LOCKTAG tag;
684 
685  SET_LOCKTAG_INT64(tag, key);
686 
687  (void) LockAcquire(&tag, ExclusiveLock, true, false);
688 
689  PG_RETURN_VOID();
690 }
691 
692 /*
693  * pg_advisory_xact_lock(int8) - acquire xact scoped
694  * exclusive lock on an int8 key
695  */
696 Datum
698 {
699  int64 key = PG_GETARG_INT64(0);
700  LOCKTAG tag;
701 
702  SET_LOCKTAG_INT64(tag, key);
703 
704  (void) LockAcquire(&tag, ExclusiveLock, false, false);
705 
706  PG_RETURN_VOID();
707 }
708 
709 /*
710  * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
711  */
712 Datum
714 {
715  int64 key = PG_GETARG_INT64(0);
716  LOCKTAG tag;
717 
718  SET_LOCKTAG_INT64(tag, key);
719 
720  (void) LockAcquire(&tag, ShareLock, true, false);
721 
722  PG_RETURN_VOID();
723 }
724 
725 /*
726  * pg_advisory_xact_lock_shared(int8) - acquire xact scoped
727  * share lock on an int8 key
728  */
729 Datum
731 {
732  int64 key = PG_GETARG_INT64(0);
733  LOCKTAG tag;
734 
735  SET_LOCKTAG_INT64(tag, key);
736 
737  (void) LockAcquire(&tag, ShareLock, false, false);
738 
739  PG_RETURN_VOID();
740 }
741 
742 /*
743  * pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
744  *
745  * Returns true if successful, false if lock not available
746  */
747 Datum
749 {
750  int64 key = PG_GETARG_INT64(0);
751  LOCKTAG tag;
753 
754  SET_LOCKTAG_INT64(tag, key);
755 
756  res = LockAcquire(&tag, ExclusiveLock, true, true);
757 
759 }
760 
761 /*
762  * pg_try_advisory_xact_lock(int8) - acquire xact scoped
763  * exclusive lock on an int8 key, no wait
764  *
765  * Returns true if successful, false if lock not available
766  */
767 Datum
769 {
770  int64 key = PG_GETARG_INT64(0);
771  LOCKTAG tag;
773 
774  SET_LOCKTAG_INT64(tag, key);
775 
776  res = LockAcquire(&tag, ExclusiveLock, false, true);
777 
779 }
780 
781 /*
782  * pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
783  *
784  * Returns true if successful, false if lock not available
785  */
786 Datum
788 {
789  int64 key = PG_GETARG_INT64(0);
790  LOCKTAG tag;
792 
793  SET_LOCKTAG_INT64(tag, key);
794 
795  res = LockAcquire(&tag, ShareLock, true, true);
796 
798 }
799 
800 /*
801  * pg_try_advisory_xact_lock_shared(int8) - acquire xact scoped
802  * share lock on an int8 key, no wait
803  *
804  * Returns true if successful, false if lock not available
805  */
806 Datum
808 {
809  int64 key = PG_GETARG_INT64(0);
810  LOCKTAG tag;
812 
813  SET_LOCKTAG_INT64(tag, key);
814 
815  res = LockAcquire(&tag, ShareLock, false, true);
816 
818 }
819 
820 /*
821  * pg_advisory_unlock(int8) - release exclusive lock on an int8 key
822  *
823  * Returns true if successful, false if lock was not held
824 */
825 Datum
827 {
828  int64 key = PG_GETARG_INT64(0);
829  LOCKTAG tag;
830  bool res;
831 
832  SET_LOCKTAG_INT64(tag, key);
833 
834  res = LockRelease(&tag, ExclusiveLock, true);
835 
837 }
838 
839 /*
840  * pg_advisory_unlock_shared(int8) - release share lock on an int8 key
841  *
842  * Returns true if successful, false if lock was not held
843  */
844 Datum
846 {
847  int64 key = PG_GETARG_INT64(0);
848  LOCKTAG tag;
849  bool res;
850 
851  SET_LOCKTAG_INT64(tag, key);
852 
853  res = LockRelease(&tag, ShareLock, true);
854 
856 }
857 
858 /*
859  * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
860  */
861 Datum
863 {
864  int32 key1 = PG_GETARG_INT32(0);
865  int32 key2 = PG_GETARG_INT32(1);
866  LOCKTAG tag;
867 
868  SET_LOCKTAG_INT32(tag, key1, key2);
869 
870  (void) LockAcquire(&tag, ExclusiveLock, true, false);
871 
872  PG_RETURN_VOID();
873 }
874 
875 /*
876  * pg_advisory_xact_lock(int4, int4) - acquire xact scoped
877  * exclusive lock on 2 int4 keys
878  */
879 Datum
881 {
882  int32 key1 = PG_GETARG_INT32(0);
883  int32 key2 = PG_GETARG_INT32(1);
884  LOCKTAG tag;
885 
886  SET_LOCKTAG_INT32(tag, key1, key2);
887 
888  (void) LockAcquire(&tag, ExclusiveLock, false, false);
889 
890  PG_RETURN_VOID();
891 }
892 
893 /*
894  * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
895  */
896 Datum
898 {
899  int32 key1 = PG_GETARG_INT32(0);
900  int32 key2 = PG_GETARG_INT32(1);
901  LOCKTAG tag;
902 
903  SET_LOCKTAG_INT32(tag, key1, key2);
904 
905  (void) LockAcquire(&tag, ShareLock, true, false);
906 
907  PG_RETURN_VOID();
908 }
909 
910 /*
911  * pg_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
912  * share lock on 2 int4 keys
913  */
914 Datum
916 {
917  int32 key1 = PG_GETARG_INT32(0);
918  int32 key2 = PG_GETARG_INT32(1);
919  LOCKTAG tag;
920 
921  SET_LOCKTAG_INT32(tag, key1, key2);
922 
923  (void) LockAcquire(&tag, ShareLock, false, false);
924 
925  PG_RETURN_VOID();
926 }
927 
928 /*
929  * pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
930  *
931  * Returns true if successful, false if lock not available
932  */
933 Datum
935 {
936  int32 key1 = PG_GETARG_INT32(0);
937  int32 key2 = PG_GETARG_INT32(1);
938  LOCKTAG tag;
940 
941  SET_LOCKTAG_INT32(tag, key1, key2);
942 
943  res = LockAcquire(&tag, ExclusiveLock, true, true);
944 
946 }
947 
948 /*
949  * pg_try_advisory_xact_lock(int4, int4) - acquire xact scoped
950  * exclusive lock on 2 int4 keys, no wait
951  *
952  * Returns true if successful, false if lock not available
953  */
954 Datum
956 {
957  int32 key1 = PG_GETARG_INT32(0);
958  int32 key2 = PG_GETARG_INT32(1);
959  LOCKTAG tag;
961 
962  SET_LOCKTAG_INT32(tag, key1, key2);
963 
964  res = LockAcquire(&tag, ExclusiveLock, false, true);
965 
967 }
968 
969 /*
970  * pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
971  *
972  * Returns true if successful, false if lock not available
973  */
974 Datum
976 {
977  int32 key1 = PG_GETARG_INT32(0);
978  int32 key2 = PG_GETARG_INT32(1);
979  LOCKTAG tag;
981 
982  SET_LOCKTAG_INT32(tag, key1, key2);
983 
984  res = LockAcquire(&tag, ShareLock, true, true);
985 
987 }
988 
989 /*
990  * pg_try_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
991  * share lock on 2 int4 keys, no wait
992  *
993  * Returns true if successful, false if lock not available
994  */
995 Datum
997 {
998  int32 key1 = PG_GETARG_INT32(0);
999  int32 key2 = PG_GETARG_INT32(1);
1000  LOCKTAG tag;
1002 
1003  SET_LOCKTAG_INT32(tag, key1, key2);
1004 
1005  res = LockAcquire(&tag, ShareLock, false, true);
1006 
1008 }
1009 
1010 /*
1011  * pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
1012  *
1013  * Returns true if successful, false if lock was not held
1014 */
1015 Datum
1017 {
1018  int32 key1 = PG_GETARG_INT32(0);
1019  int32 key2 = PG_GETARG_INT32(1);
1020  LOCKTAG tag;
1021  bool res;
1022 
1023  SET_LOCKTAG_INT32(tag, key1, key2);
1024 
1025  res = LockRelease(&tag, ExclusiveLock, true);
1026 
1028 }
1029 
1030 /*
1031  * pg_advisory_unlock_shared(int4, int4) - release share lock on 2 int4 keys
1032  *
1033  * Returns true if successful, false if lock was not held
1034  */
1035 Datum
1037 {
1038  int32 key1 = PG_GETARG_INT32(0);
1039  int32 key2 = PG_GETARG_INT32(1);
1040  LOCKTAG tag;
1041  bool res;
1042 
1043  SET_LOCKTAG_INT32(tag, key1, key2);
1044 
1045  res = LockRelease(&tag, ShareLock, true);
1046 
1048 }
1049 
1050 /*
1051  * pg_advisory_unlock_all() - release all advisory locks
1052  */
1053 Datum
1055 {
1057 
1058  PG_RETURN_VOID();
1059 }
#define ARR_NDIM(a)
Definition: array.h:283
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:256
#define ARR_DATA_PTR(a)
Definition: array.h:315
#define DatumGetArrayTypeP(X)
Definition: array.h:254
#define ARR_ELEMTYPE(a)
Definition: array.h:285
#define PG_RETURN_ARRAYTYPE_P(x)
Definition: array.h:258
#define ARR_DIMS(a)
Definition: array.h:287
bool array_contains_nulls(ArrayType *array)
Definition: arrayfuncs.c:3738
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3363
int ArrayGetNItems(int ndim, const int *dims)
Definition: arrayutils.c:76
int16 AttrNumber
Definition: attnum.h:21
int BackendId
Definition: backendid.h:21
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define CStringGetTextDatum(s)
Definition: builtins.h:88
signed int int32
Definition: c.h:430
#define lengthof(array)
Definition: c.h:724
uint32 LocalTransactionId
Definition: c.h:590
#define ERROR
Definition: elog.h:39
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2071
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:303
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:307
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:309
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:305
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:327
int MaxBackends
Definition: globals.c:140
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
int j
Definition: isn.c:74
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
LockAcquireResult LockAcquire(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock, bool dontWait)
Definition: lock.c:747
bool LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
Definition: lock.c:1975
BlockedProcsData * GetBlockerStatusData(int blocked_pid)
Definition: lock.c:3838
LockData * GetLockStatusData(void)
Definition: lock.c:3646
void LockReleaseSession(LOCKMETHODID lockmethodid)
Definition: lock.c:2454
const char * GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode)
Definition: lock.c:4100
LockMethod GetLockTagsMethodTable(const LOCKTAG *locktag)
Definition: lock.c:499
LockTagType
Definition: lock.h:141
@ LOCKTAG_OBJECT
Definition: lock.h:150
@ LOCKTAG_RELATION_EXTEND
Definition: lock.h:143
@ LOCKTAG_RELATION
Definition: lock.h:142
@ LOCKTAG_TUPLE
Definition: lock.h:146
@ LOCKTAG_USERLOCK
Definition: lock.h:151
@ LOCKTAG_DATABASE_FROZEN_IDS
Definition: lock.h:144
@ LOCKTAG_VIRTUALTRANSACTION
Definition: lock.h:148
@ LOCKTAG_TRANSACTION
Definition: lock.h:147
@ LOCKTAG_PAGE
Definition: lock.h:145
@ LOCKTAG_ADVISORY
Definition: lock.h:152
#define USER_LOCKMETHOD
Definition: lock.h:131
#define LOCKBIT_OFF(lockmode)
Definition: lock.h:90
#define LOCKTAG_LAST_TYPE
Definition: lock.h:155
#define MAX_LOCKMODES
Definition: lock.h:87
#define LOCKBIT_ON(lockmode)
Definition: lock.h:89
LockAcquireResult
Definition: lock.h:493
@ LOCKACQUIRE_NOT_AVAIL
Definition: lock.h:494
int LOCKMODE
Definition: lockdefs.h:26
#define NoLock
Definition: lockdefs.h:34
#define ExclusiveLock
Definition: lockdefs.h:42
#define ShareLock
Definition: lockdefs.h:40
Datum pg_advisory_lock_int4(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:862
#define SET_LOCKTAG_INT64(tag, key64)
Definition: lockfuncs.c:667
Datum pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:955
Datum pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:826
Datum pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:897
Datum pg_safe_snapshot_blocking_pids(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:549
Datum pg_advisory_lock_int8(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:680
Datum pg_try_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:807
Datum pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:697
Datum pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:975
Datum pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:934
#define SET_LOCKTAG_INT32(tag, key1, key2)
Definition: lockfuncs.c:673
#define NUM_LOCK_STATUS_COLUMNS
Definition: lockfuncs.c:66
Datum pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:1036
Datum pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:1016
static const char *const PredicateLockTagTypeNames[]
Definition: lockfuncs.c:47
Datum pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:787
Datum pg_lock_status(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:92
Datum pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:880
Datum pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:768
Datum pg_blocking_pids(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:442
Datum pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:713
Datum pg_try_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:996
static Datum VXIDGetDatum(BackendId bid, LocalTransactionId lxid)
Definition: lockfuncs.c:74
Datum pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:730
Datum pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:845
Datum pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:748
Datum pg_advisory_unlock_all(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:1054
const char *const LockTagTypeNames[]
Definition: lockfuncs.c:29
Datum pg_isolation_test_session_is_blocked(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:591
StaticAssertDecl(lengthof(LockTagTypeNames)==(LOCKTAG_ADVISORY+1), "array length mismatch")
Datum pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
Definition: lockfuncs.c:915
void * palloc(Size size)
Definition: mcxt.c:1199
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:135
static PgChecksumMode mode
Definition: pg_checksums.c:65
while(p+4<=pend)
#define snprintf
Definition: port.h:238
static Datum TransactionIdGetDatum(TransactionId X)
Definition: postgres.h:620
uintptr_t Datum
Definition: postgres.h:412
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:520
static Datum UInt16GetDatum(uint16 X)
Definition: postgres.h:540
static Datum BoolGetDatum(bool X)
Definition: postgres.h:450
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:600
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:560
static Datum UInt32GetDatum(uint32 X)
Definition: postgres.h:580
PredicateLockData * GetPredicateLockStatusData(void)
Definition: predicate.c:1444
int GetSafeSnapshotBlockingPids(int blocked_pid, int *output, int output_size)
Definition: predicate.c:1629
PredicateLockTargetType
@ PREDLOCKTAG_PAGE
@ PREDLOCKTAG_TUPLE
#define GET_PREDICATELOCKTARGETTAG_DB(locktag)
#define GET_PREDICATELOCKTARGETTAG_RELATION(locktag)
#define GET_PREDICATELOCKTARGETTAG_TYPE(locktag)
#define GET_PREDICATELOCKTARGETTAG_PAGE(locktag)
#define GET_PREDICATELOCKTARGETTAG_OFFSET(locktag)
int first_lock
Definition: lock.h:469
int first_waiter
Definition: lock.h:473
int num_waiters
Definition: lock.h:474
int num_locks
Definition: lock.h:470
LockInstanceData * locks
Definition: lock.h:480
int * waiter_pids
Definition: lock.h:481
BlockedProcData * procs
Definition: lock.h:479
void * user_fctx
Definition: funcapi.h:82
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
TupleDesc tuple_desc
Definition: funcapi.h:112
Definition: lock.h:168
uint8 locktag_type
Definition: lock.h:173
uint32 locktag_field3
Definition: lock.h:171
uint32 locktag_field1
Definition: lock.h:169
uint8 locktag_lockmethodid
Definition: lock.h:174
uint16 locktag_field4
Definition: lock.h:172
uint32 locktag_field2
Definition: lock.h:170
Definition: lock.h:459
LockInstanceData * locks
Definition: lock.h:461
int nelements
Definition: lock.h:460
LOCKMASK holdMask
Definition: lock.h:447
LOCKMODE waitLockMode
Definition: lock.h:448
bool fastpath
Definition: lock.h:455
LOCKTAG locktag
Definition: lock.h:446
TimestampTz waitStart
Definition: lock.h:451
int leaderPid
Definition: lock.h:454
BackendId backend
Definition: lock.h:449
LocalTransactionId lxid
Definition: lock.h:450
const LOCKMASK * conflictTab
Definition: lock.h:116
PredicateLockData * predLockData
Definition: lockfuncs.c:61
LockData * lockData
Definition: lockfuncs.c:59
PREDICATELOCKTARGETTAG * locktags
SERIALIZABLEXACT * xacts
VirtualTransactionId vxid
LocalTransactionId localTransactionId
Definition: lock.h:67
BackendId backendId
Definition: lock.h:66
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:45
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:583
static Datum TimestampTzGetDatum(TimestampTz X)
Definition: timestamp.h:52