]> granicus.if.org Git - postgresql/commitdiff
Add lock file.
authorBruce Momjian <bruce@momjian.us>
Sat, 17 Aug 2002 13:11:43 +0000 (13:11 +0000)
committerBruce Momjian <bruce@momjian.us>
Sat, 17 Aug 2002 13:11:43 +0000 (13:11 +0000)
src/backend/utils/adt/lockfuncs.c [new file with mode: 0644]

diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
new file mode 100644 (file)
index 0000000..0b1933a
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * lockfuncs.c
+ *             Set-returning functions to view the state of locks within the DB.
+ * 
+ * Copyright (c) 2002, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *             $Header: /cvsroot/pgsql/src/backend/utils/adt/lockfuncs.c,v 1.1 2002/08/17 13:11:43 momjian Exp $
+ */
+
+#include "postgres.h"
+#include "fmgr.h"
+#include "funcapi.h"
+#include "storage/lmgr.h"
+#include "storage/lock.h"
+#include "storage/lwlock.h"
+#include "storage/proc.h"
+
+Datum lock_status_srf(PG_FUNCTION_ARGS);
+
+static int next_lock(int locks[]);
+
+Datum
+lock_status_srf(PG_FUNCTION_ARGS)
+{
+       FuncCallContext         *funccxt;
+       LockData                        *lockData;
+
+       if (SRF_IS_FIRSTCALL())
+       {
+               MemoryContext   oldcxt;
+               TupleDesc               tupdesc;
+
+               funccxt = SRF_FIRSTCALL_INIT();
+               tupdesc = RelationNameGetTupleDesc("pg_catalog.pg_locks_result");
+               funccxt->slot = TupleDescGetSlot(tupdesc);
+               funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc);
+
+               oldcxt = MemoryContextSwitchTo(funccxt->fmctx);
+
+               /*
+                * Preload all the locking information that we will eventually format
+                * and send out as a result set. This is palloc'ed, but since the
+                * MemoryContext is reset when the SRF finishes, we don't need to
+                * free it ourselves.
+                */
+               funccxt->user_fctx = (LockData *) palloc(sizeof(LockData));
+
+               GetLockStatusData(funccxt->user_fctx);
+
+               MemoryContextSwitchTo(oldcxt);
+       }
+
+       funccxt = SRF_PERCALL_SETUP();
+       lockData = (LockData *) funccxt->user_fctx;
+
+       while (lockData->currIdx < lockData->nelements)
+       {
+               PROCLOCK                 *holder;
+               LOCK                     *lock;
+               PGPROC                   *proc;
+               HeapTuple                 tuple;
+               Datum                     result;
+               char                    **values;
+               LOCKMODE                  mode;
+               int                               num_attrs;
+               int                               i;
+               int                               currIdx = lockData->currIdx;
+
+               holder          = &(lockData->holders[currIdx]);
+               lock            = &(lockData->locks[currIdx]);
+               proc            = &(lockData->procs[currIdx]);
+               num_attrs       = funccxt->attinmeta->tupdesc->natts;
+
+               values = (char **) palloc(sizeof(*values) * num_attrs);
+
+               for (i = 0; i < num_attrs; i++)
+                       values[i] = (char *) palloc(32);
+
+               /* The OID of the locked relation */
+               snprintf(values[0], 32, "%u", lock->tag.relId);
+               /* The database the relation is in */
+               snprintf(values[1], 32, "%u", lock->tag.dbId);
+               /* The PID of the backend holding or waiting for the lock */
+               snprintf(values[2], 32, "%d", proc->pid);
+
+               /*
+                * We need to report both the locks held (i.e. successfully acquired)
+                * by this holder, as well as the locks upon which it is still
+                * waiting, if any. Since a single PROCLOCK struct may contain
+                * multiple locks, we may need to loop several times before we
+                * advance the array index and continue on.
+                */
+               if (holder->nHolding > 0)
+               {
+                       /* Already held locks */
+                       mode = next_lock(holder->holding);
+                       holder->holding[mode]--;
+                       holder->nHolding--;
+
+                       strcpy(values[4], "t");
+               }
+               else if (proc->waitLock != NULL)
+               {
+                       /* Lock that is still being waited on */
+                       mode = proc->waitLockMode;
+                       proc->waitLock = NULL;
+                       proc->waitLockMode = NoLock;
+
+                       strcpy(values[4], "f");
+               }
+               else
+               {
+                       /*
+                        * Okay, we've displayed all the lock's belonging to this PROCLOCK,
+                        * procede to the next one.
+                        */
+                       lockData->currIdx++;
+                       continue;
+               }
+
+               strncpy(values[3], GetLockmodeName(mode), 32);
+
+               tuple = BuildTupleFromCStrings(funccxt->attinmeta, values);
+               result = TupleGetDatum(funccxt->slot, tuple);
+               SRF_RETURN_NEXT(funccxt, result);
+       }
+
+       SRF_RETURN_DONE(funccxt);
+}
+
+static LOCKMODE
+next_lock(int locks[])
+{
+       LOCKMODE i;
+
+       for (i = 0; i < MAX_LOCKMODES; i++)
+       {
+               if (locks[i] != 0)
+                       return i;
+       }
+
+       /* No locks found: this should not occur */
+       Assert(false);
+       return -1;
+}