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