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