|
| 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 | +Datumlock_status_srf(PG_FUNCTION_ARGS); |
| 20 | + |
| 21 | +staticintnext_lock(intlocks[]); |
| 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 | +MemoryContextoldcxt; |
| 32 | +TupleDesctupdesc; |
| 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 | +HeapTupletuple; |
| 63 | +Datumresult; |
| 64 | +char**values; |
| 65 | +LOCKMODEmode; |
| 66 | +intnum_attrs; |
| 67 | +inti; |
| 68 | +intcurrIdx=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 | +elseif (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 | +staticLOCKMODE |
| 133 | +next_lock(intlocks[]) |
| 134 | +{ |
| 135 | +LOCKMODEi; |
| 136 | + |
| 137 | +for (i=0;i<MAX_LOCKMODES;i++) |
| 138 | +{ |
| 139 | +if (locks[i]!=0) |
| 140 | +returni; |
| 141 | +} |
| 142 | + |
| 143 | +/* No locks found: this should not occur */ |
| 144 | +Assert(false); |
| 145 | +return-1; |
| 146 | +} |