]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/lockfuncs.c
Add lock file.
[postgresql] / src / backend / utils / adt / lockfuncs.c
1 /*
2  * lockfuncs.c
3  *              Set-returning functions to view the state of locks within the DB.
4  * 
5  * Copyright (c) 2002, PostgreSQL Global Development Group
6  *
7  * IDENTIFICATION
8  *              $Header: /cvsroot/pgsql/src/backend/utils/adt/lockfuncs.c,v 1.1 2002/08/17 13:11:43 momjian Exp $
9  */
10
11 #include "postgres.h"
12 #include "fmgr.h"
13 #include "funcapi.h"
14 #include "storage/lmgr.h"
15 #include "storage/lock.h"
16 #include "storage/lwlock.h"
17 #include "storage/proc.h"
18
19 Datum lock_status_srf(PG_FUNCTION_ARGS);
20
21 static int next_lock(int locks[]);
22
23 Datum
24 lock_status_srf(PG_FUNCTION_ARGS)
25 {
26         FuncCallContext         *funccxt;
27         LockData                        *lockData;
28
29         if (SRF_IS_FIRSTCALL())
30         {
31                 MemoryContext   oldcxt;
32                 TupleDesc               tupdesc;
33
34                 funccxt = SRF_FIRSTCALL_INIT();
35                 tupdesc = RelationNameGetTupleDesc("pg_catalog.pg_locks_result");
36                 funccxt->slot = TupleDescGetSlot(tupdesc);
37                 funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc);
38
39                 oldcxt = MemoryContextSwitchTo(funccxt->fmctx);
40
41                 /*
42                  * Preload all the locking information that we will eventually format
43                  * and send out as a result set. This is palloc'ed, but since the
44                  * MemoryContext is reset when the SRF finishes, we don't need to
45                  * free it ourselves.
46                  */
47                 funccxt->user_fctx = (LockData *) palloc(sizeof(LockData));
48
49                 GetLockStatusData(funccxt->user_fctx);
50
51                 MemoryContextSwitchTo(oldcxt);
52         }
53
54         funccxt = SRF_PERCALL_SETUP();
55         lockData = (LockData *) funccxt->user_fctx;
56
57         while (lockData->currIdx < lockData->nelements)
58         {
59                 PROCLOCK                 *holder;
60                 LOCK                     *lock;
61                 PGPROC                   *proc;
62                 HeapTuple                 tuple;
63                 Datum                     result;
64                 char                    **values;
65                 LOCKMODE                  mode;
66                 int                               num_attrs;
67                 int                               i;
68                 int                               currIdx = lockData->currIdx;
69
70                 holder          = &(lockData->holders[currIdx]);
71                 lock            = &(lockData->locks[currIdx]);
72                 proc            = &(lockData->procs[currIdx]);
73                 num_attrs       = funccxt->attinmeta->tupdesc->natts;
74
75                 values = (char **) palloc(sizeof(*values) * num_attrs);
76
77                 for (i = 0; i < num_attrs; i++)
78                         values[i] = (char *) palloc(32);
79
80                 /* The OID of the locked relation */
81                 snprintf(values[0], 32, "%u", lock->tag.relId);
82                 /* The database the relation is in */
83                 snprintf(values[1], 32, "%u", lock->tag.dbId);
84                 /* The PID of the backend holding or waiting for the lock */
85                 snprintf(values[2], 32, "%d", proc->pid);
86
87                 /*
88                  * We need to report both the locks held (i.e. successfully acquired)
89                  * by this holder, as well as the locks upon which it is still
90                  * waiting, if any. Since a single PROCLOCK struct may contain
91                  * multiple locks, we may need to loop several times before we
92                  * advance the array index and continue on.
93                  */
94                 if (holder->nHolding > 0)
95                 {
96                         /* Already held locks */
97                         mode = next_lock(holder->holding);
98                         holder->holding[mode]--;
99                         holder->nHolding--;
100
101                         strcpy(values[4], "t");
102                 }
103                 else if (proc->waitLock != NULL)
104                 {
105                         /* Lock that is still being waited on */
106                         mode = proc->waitLockMode;
107                         proc->waitLock = NULL;
108                         proc->waitLockMode = NoLock;
109
110                         strcpy(values[4], "f");
111                 }
112                 else
113                 {
114                         /*
115                          * Okay, we've displayed all the lock's belonging to this PROCLOCK,
116                          * procede to the next one.
117                          */
118                         lockData->currIdx++;
119                         continue;
120                 }
121
122                 strncpy(values[3], GetLockmodeName(mode), 32);
123
124                 tuple = BuildTupleFromCStrings(funccxt->attinmeta, values);
125                 result = TupleGetDatum(funccxt->slot, tuple);
126                 SRF_RETURN_NEXT(funccxt, result);
127         }
128
129         SRF_RETURN_DONE(funccxt);
130 }
131
132 static LOCKMODE
133 next_lock(int locks[])
134 {
135         LOCKMODE i;
136
137         for (i = 0; i < MAX_LOCKMODES; i++)
138         {
139                 if (locks[i] != 0)
140                         return i;
141         }
142
143         /* No locks found: this should not occur */
144         Assert(false);
145         return -1;
146 }