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