]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/lockfuncs.c
Code review for pg_locks feature. Make shmemoffset of PROCLOCK structs
[postgresql] / src / backend / utils / adt / lockfuncs.c
1 /*-------------------------------------------------------------------------
2  *
3  * lockfuncs.c
4  *              Set-returning functions to view the state of locks within the DB.
5  * 
6  * Copyright (c) 2002, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  *              $Header: /cvsroot/pgsql/src/backend/utils/adt/lockfuncs.c,v 1.5 2002/08/31 17:14:28 tgl Exp $
10  *
11  *-------------------------------------------------------------------------
12  */
13 #include "postgres.h"
14
15 #include "funcapi.h"
16 #include "access/heapam.h"
17 #include "catalog/pg_type.h"
18 #include "storage/lock.h"
19 #include "storage/proc.h"
20 #include "utils/builtins.h"
21
22
23 /* Working status for pg_lock_status */
24 typedef struct
25 {
26         LockData   *lockData;           /* state data from lmgr */
27         int                     currIdx;                /* current PROCLOCK index */
28 } PG_Lock_Status;
29
30 /*
31  * pg_lock_status - produce a view with one row per held or awaited lock mode
32  */
33 Datum
34 pg_lock_status(PG_FUNCTION_ARGS)
35 {
36         FuncCallContext    *funcctx;
37         PG_Lock_Status     *mystatus;
38         LockData   *lockData;
39
40         if (SRF_IS_FIRSTCALL())
41         {
42                 TupleDesc               tupdesc;
43                 MemoryContext   oldcontext;
44
45                 /* create a function context for cross-call persistence */
46                 funcctx = SRF_FIRSTCALL_INIT();
47
48                 /* switch to memory context appropriate for multiple function calls */
49                 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
50
51                 /* build tupdesc for result tuples */
52                 /* this had better match pg_locks view in initdb.sh */
53                 tupdesc = CreateTemplateTupleDesc(6, WITHOUTOID);
54                 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relation",
55                                                    OIDOID, -1, 0, false);
56                 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
57                                                    OIDOID, -1, 0, false);
58                 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "transaction",
59                                                    XIDOID, -1, 0, false);
60                 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pid",
61                                                    INT4OID, -1, 0, false);
62                 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "mode",
63                                                    TEXTOID, -1, 0, false);
64                 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "granted",
65                                                    BOOLOID, -1, 0, false);
66
67                 funcctx->slot = TupleDescGetSlot(tupdesc);
68
69                 /*
70                  * Collect all the locking information that we will format
71                  * and send out as a result set.
72                  */
73                 mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status));
74                 funcctx->user_fctx = (void *) mystatus;
75
76                 mystatus->lockData = GetLockStatusData();
77                 mystatus->currIdx = 0;
78
79                 MemoryContextSwitchTo(oldcontext);
80         }
81
82         funcctx = SRF_PERCALL_SETUP();
83         mystatus = (PG_Lock_Status *) funcctx->user_fctx;
84         lockData = mystatus->lockData;
85
86         while (mystatus->currIdx < lockData->nelements)
87         {
88                 PROCLOCK                 *holder;
89                 LOCK                     *lock;
90                 PGPROC                   *proc;
91                 bool                    granted;
92                 LOCKMODE                  mode;
93                 Datum                   values[6];
94                 char                    nulls[6];
95                 HeapTuple                 tuple;
96                 Datum                     result;
97
98                 holder          = &(lockData->holders[mystatus->currIdx]);
99                 lock            = &(lockData->locks[mystatus->currIdx]);
100                 proc            = &(lockData->procs[mystatus->currIdx]);
101
102                 /*
103                  * Look to see if there are any held lock modes in this PROCLOCK.
104                  * If so, report, and destructively modify lockData so we don't
105                  * report again.
106                  */
107                 granted = false;
108                 for (mode = 0; mode < MAX_LOCKMODES; mode++)
109                 {
110                         if (holder->holding[mode] > 0)
111                         {
112                                 granted = true;
113                                 holder->holding[mode] = 0;
114                                 break;
115                         }
116                 }
117
118                 /*
119                  * If no (more) held modes to report, see if PROC is waiting for
120                  * a lock on this lock.
121                  */
122                 if (!granted)
123                 {
124                         if (proc->waitLock == (LOCK *) MAKE_PTR(holder->tag.lock))
125                         {
126                                 /* Yes, so report it with proper mode */
127                                 mode = proc->waitLockMode;
128                                 /*
129                                  * We are now done with this PROCLOCK, so advance pointer
130                                  * to continue with next one on next call.
131                                  */
132                                 mystatus->currIdx++;
133                         }
134                         else
135                         {
136                                 /*
137                                  * Okay, we've displayed all the locks associated with this
138                                  * PROCLOCK, proceed to the next one.
139                                  */
140                                 mystatus->currIdx++;
141                                 continue;
142                         }
143                 }
144
145                 /*
146                  * Form tuple with appropriate data.
147                  */
148                 MemSet(values, 0, sizeof(values));
149                 MemSet(nulls, ' ', sizeof(nulls));
150
151                 if (lock->tag.relId == XactLockTableId && lock->tag.dbId == 0)
152                 {
153                         /* Lock is for transaction ID */
154                         nulls[0] = 'n';
155                         nulls[1] = 'n';
156                         values[2] = TransactionIdGetDatum(lock->tag.objId.xid);
157                 }
158                 else
159                 {
160                         /* Lock is for a relation */
161                         values[0] = ObjectIdGetDatum(lock->tag.relId);
162                         values[1] = ObjectIdGetDatum(lock->tag.dbId);
163                         nulls[2] = 'n';
164
165                 }
166
167                 values[3] = Int32GetDatum(proc->pid);
168                 values[4] = DirectFunctionCall1(textin,
169                                                                         CStringGetDatum(GetLockmodeName(mode)));
170                 values[5] = BoolGetDatum(granted);
171
172                 tuple = heap_formtuple(funcctx->slot->ttc_tupleDescriptor,
173                                                            values, nulls);
174                 result = TupleGetDatum(funcctx->slot, tuple);
175                 SRF_RETURN_NEXT(funcctx, result);
176         }
177
178         SRF_RETURN_DONE(funcctx);
179 }