Re: obtaining row locking information

Поиск
Список
Период
Сортировка
От Tatsuo Ishii
Тема Re: obtaining row locking information
Дата
Msg-id 20050812.122725.104030712.t-ishii@sra.co.jp
обсуждение исходный текст
Ответ на obtaining row locking information  (Tatsuo Ishii <t-ishii@sra.co.jp>)
Ответы Re: obtaining row locking information  (Alvaro Herrera <alvherre@alvh.no-ip.org>)
Список 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 по дате отправления:

Предыдущее
От: Bruce Momjian
Дата:
Сообщение: Re: ereport(ERROR) and files
Следующее
От: Tom Lane
Дата:
Сообщение: Re: ereport(ERROR) and files