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