Re: obtaining row locking information - Mailing list pgsql-hackers
From | Tatsuo Ishii |
---|---|
Subject | Re: obtaining row locking information |
Date | |
Msg-id | 20050812.122725.104030712.t-ishii@sra.co.jp Whole thread Raw |
In response to | obtaining row locking information (Tatsuo Ishii <t-ishii@sra.co.jp>) |
Responses |
Re: obtaining row locking information
|
List | pgsql-hackers |
> Hi, > > With a help from Bruce, I wrote a small function which returns row > locking information(see attached file if you are interested). Here is > a sample result: > > test=# select * from pgrowlocks('t1'); > locked_row | lock_type | locker | multi > ------------+-----------+--------+------- > (0,1) | Shared | 1 | t > (0,3) | Exclusive | 575 | f > (2 rows) > > I think it will be more usefull if actual xids are shown in the case > "locker" is a multixid. It seems GetMultiXactIdMembers() does the > job. Unfortunately that is a static funtcion, however. Is there any > chance GetMultiXactIdMembers() becomes public funtion? I enhanced pgrowlocks() to use GetMultiXactIdMembers() so that it displays each xid belonging to particular multi xid (see attached source code). test=# select * from pgrowlocks('t1');locked_row | lock_type | locker | multi | xids ------------+-----------+--------+-------+----------- (0,1) | Shared | 3 | t | {646,647} (1 row) However even one of transactions, for example 647 commits, still it shows as if 647 is a member of muitixid 3. test=# select * from pgrowlocks('t1');locked_row | lock_type | locker | multi | xids ------------+-----------+--------+-------+----------- (0,1) | Shared | 3 | t | {646,647} (1 row) Am I missing something? -- Tatsuo Ishii /** $PostgreSQL$** Copyright (c) 2005 Tatsuo Ishii** Permission to use, copy, modify, and distribute this software and*its documentation for any purpose, without fee, and without a* written agreement is hereby granted, provided that theabove* copyright notice and this paragraph and the following two* paragraphs appear in all copies.** IN NO EVENT SHALLTHE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING* LOSTPROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS* DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEENADVISED* OF THE POSSIBILITY OF SUCH DAMAGE.** THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT* LIMITEDTO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR* A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDERIS ON AN "AS* IS" BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,* SUPPORT, UPDATES, ENHANCEMENTS,OR MODIFICATIONS.*/ #include "postgres.h" #include "funcapi.h" #include "access/heapam.h" #include "access/multixact.h" #include "access/transam.h" #include "catalog/namespace.h" #include "catalog/pg_type.h" #include "utils/builtins.h" PG_FUNCTION_INFO_V1(pgrowlocks); extern Datum pgrowlocks(PG_FUNCTION_ARGS); /* ----------* pgrowlocks:* returns tids of rows being locked** C FUNCTION definition* pgrowlocks(text) returns set of pgrowlocks_type*see pgrowlocks.sql for pgrowlocks_type* ----------*/ #define DUMMY_TUPLE "public.pgrowlocks_type" #define NCHARS 32 /** define this if makeRangeVarFromNameList() has two arguments. As far* as I know, this only happens in 8.0.x.*/ #undef MAKERANGEVARFROMNAMELIST_HAS_TWO_ARGS typedef struct {HeapScanDesc scan;int ncolumns; } MyData; Datum pgrowlocks(PG_FUNCTION_ARGS) {FuncCallContext *funcctx;HeapScanDesc scan;HeapTuple tuple;TupleDesc tupdesc;AttInMetadata *attinmeta;Datum result;MyData *mydata;Relation rel; if (SRF_IS_FIRSTCALL()){ text *relname; RangeVar *relrv; MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); tupdesc = RelationNameGetTupleDesc(DUMMY_TUPLE); attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta= attinmeta; relname = PG_GETARG_TEXT_P(0); #ifdef MAKERANGEVARFROMNAMELIST_HAS_TWO_ARGS relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname, "pgrowlocks")); #else relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); #endif rel = heap_openrv(relrv, AccessShareLock); scan = heap_beginscan(rel, SnapshotNow, 0, NULL); mydata = palloc(sizeof(*mydata)); mydata->scan = scan; mydata->ncolumns = tupdesc->natts; funcctx->user_fctx = mydata; MemoryContextSwitchTo(oldcontext);} funcctx = SRF_PERCALL_SETUP();attinmeta = funcctx->attinmeta;mydata = (MyData *)funcctx->user_fctx;scan = mydata->scan; /* scan the relation */while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL){ /* must hold a buffer lockto call HeapTupleSatisfiesUpdate */ LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE); if (HeapTupleSatisfiesUpdate(tuple->t_data, GetCurrentCommandId(), scan->rs_cbuf) == HeapTupleBeingUpdated) { char **values; int i; values = (char **) palloc(mydata->ncolumns * sizeof(char *)); i = 0; values[i++] = (char *)DirectFunctionCall1(tidout, PointerGetDatum(&tuple->t_self)); #ifdef HEAP_XMAX_SHARED_LOCK if (tuple->t_data->t_infomask & HEAP_XMAX_SHARED_LOCK) values[i++] = pstrdup("Shared"); else values[i++] = pstrdup("Exclusive"); #else values[i++] = pstrdup("Exclusive"); #endif values[i] = palloc(NCHARS*sizeof(char)); snprintf(values[i++], NCHARS, "%d", HeapTupleHeaderGetXmax(tuple->t_data)); #ifdef HEAP_XMAX_SHARED_LOCK if (tuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI) { TransactionId*xids; int nxids; int j; values[i++] = pstrdup("true"); nxids = GetMultiXactIdMembers(HeapTupleHeaderGetXmax(tuple->t_data),&xids); if (nxids == -1) { elog(ERROR, "GetMultiXactIdMembers returns error"); } values[i] = palloc(NCHARS*nxids); strcpy(values[i], "{"); for (j=0;j<nxids;j++) { char buf[NCHARS]; snprintf(buf, NCHARS, "%d", xids[j]); strcat(values[i], buf); if ((j+1) != nxids) { strcat(values[i], ","); } } strcat(values[i], "}"); i++; } else { values[i++] = pstrdup("false"); values[i++] = pstrdup("{}"); } #else values[i++] = pstrdup("false"); values[i++] = pstrdup("{}"); #endif LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK); /* build a tuple */ tuple = BuildTupleFromCStrings(attinmeta, values); /* make the tuple into a datum */ result = HeapTupleGetDatum(tuple); /* Clean up */ for (i = 0; i < mydata->ncolumns; i++) pfree(values[i]); pfree(values); SRF_RETURN_NEXT(funcctx, result); } else { LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK); }} heap_endscan(scan);heap_close(scan->rs_rd, AccessShareLock); SRF_RETURN_DONE(funcctx); }
pgsql-hackers by date: