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