Header And Logo

PostgreSQL
| The world's most advanced open source database.

pgrowlocks.c

Go to the documentation of this file.
00001 /*
00002  * contrib/pgrowlocks/pgrowlocks.c
00003  *
00004  * Copyright (c) 2005-2006  Tatsuo Ishii
00005  *
00006  * Permission to use, copy, modify, and distribute this software and
00007  * its documentation for any purpose, without fee, and without a
00008  * written agreement is hereby granted, provided that the above
00009  * copyright notice and this paragraph and the following two
00010  * paragraphs appear in all copies.
00011  *
00012  * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
00013  * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
00014  * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
00015  * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED
00016  * OF THE POSSIBILITY OF SUCH DAMAGE.
00017  *
00018  * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00020  * A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS
00021  * IS" BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,
00022  * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
00023  */
00024 
00025 #include "postgres.h"
00026 
00027 #include "access/multixact.h"
00028 #include "access/relscan.h"
00029 #include "access/xact.h"
00030 #include "catalog/namespace.h"
00031 #include "funcapi.h"
00032 #include "miscadmin.h"
00033 #include "storage/bufmgr.h"
00034 #include "storage/procarray.h"
00035 #include "utils/acl.h"
00036 #include "utils/builtins.h"
00037 #include "utils/rel.h"
00038 #include "utils/tqual.h"
00039 
00040 
00041 PG_MODULE_MAGIC;
00042 
00043 PG_FUNCTION_INFO_V1(pgrowlocks);
00044 
00045 extern Datum pgrowlocks(PG_FUNCTION_ARGS);
00046 
00047 /* ----------
00048  * pgrowlocks:
00049  * returns tids of rows being locked
00050  * ----------
00051  */
00052 
00053 #define NCHARS 32
00054 
00055 typedef struct
00056 {
00057     Relation    rel;
00058     HeapScanDesc scan;
00059     int         ncolumns;
00060 } MyData;
00061 
00062 #define     Atnum_tid       0
00063 #define     Atnum_xmax      1
00064 #define     Atnum_ismulti   2
00065 #define     Atnum_xids      3
00066 #define     Atnum_modes     4
00067 #define     Atnum_pids      5
00068 
00069 Datum
00070 pgrowlocks(PG_FUNCTION_ARGS)
00071 {
00072     FuncCallContext *funcctx;
00073     HeapScanDesc scan;
00074     HeapTuple   tuple;
00075     TupleDesc   tupdesc;
00076     AttInMetadata *attinmeta;
00077     Datum       result;
00078     MyData     *mydata;
00079     Relation    rel;
00080 
00081     if (SRF_IS_FIRSTCALL())
00082     {
00083         text       *relname;
00084         RangeVar   *relrv;
00085         MemoryContext oldcontext;
00086         AclResult   aclresult;
00087 
00088         funcctx = SRF_FIRSTCALL_INIT();
00089         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
00090 
00091         /* Build a tuple descriptor for our result type */
00092         if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
00093             elog(ERROR, "return type must be a row type");
00094 
00095         attinmeta = TupleDescGetAttInMetadata(tupdesc);
00096         funcctx->attinmeta = attinmeta;
00097 
00098         relname = PG_GETARG_TEXT_P(0);
00099         relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
00100         rel = heap_openrv(relrv, AccessShareLock);
00101 
00102         /* check permissions: must have SELECT on table */
00103         aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
00104                                       ACL_SELECT);
00105         if (aclresult != ACLCHECK_OK)
00106             aclcheck_error(aclresult, ACL_KIND_CLASS,
00107                            RelationGetRelationName(rel));
00108 
00109         scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
00110         mydata = palloc(sizeof(*mydata));
00111         mydata->rel = rel;
00112         mydata->scan = scan;
00113         mydata->ncolumns = tupdesc->natts;
00114         funcctx->user_fctx = mydata;
00115 
00116         MemoryContextSwitchTo(oldcontext);
00117     }
00118 
00119     funcctx = SRF_PERCALL_SETUP();
00120     attinmeta = funcctx->attinmeta;
00121     mydata = (MyData *) funcctx->user_fctx;
00122     scan = mydata->scan;
00123 
00124     /* scan the relation */
00125     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
00126     {
00127         HTSU_Result htsu;
00128         TransactionId xmax;
00129         uint16      infomask;
00130 
00131         /* must hold a buffer lock to call HeapTupleSatisfiesUpdate */
00132         LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
00133 
00134         htsu = HeapTupleSatisfiesUpdate(tuple->t_data,
00135                                         GetCurrentCommandId(false),
00136                                         scan->rs_cbuf);
00137         xmax = HeapTupleHeaderGetRawXmax(tuple->t_data);
00138         infomask = tuple->t_data->t_infomask;
00139 
00140         /*
00141          * a tuple is locked if HTSU returns BeingUpdated, and if it returns
00142          * MayBeUpdated but the Xmax is valid and pointing at us.
00143          */
00144         if (htsu == HeapTupleBeingUpdated ||
00145             (htsu == HeapTupleMayBeUpdated &&
00146              !(infomask & HEAP_XMAX_INVALID) &&
00147              !(infomask & HEAP_XMAX_IS_MULTI) &&
00148              (xmax == GetCurrentTransactionIdIfAny())))
00149         {
00150             char      **values;
00151 
00152             values = (char **) palloc(mydata->ncolumns * sizeof(char *));
00153 
00154             values[Atnum_tid] = (char *) DirectFunctionCall1(tidout,
00155                                                              PointerGetDatum(&tuple->t_self));
00156 
00157             values[Atnum_xmax] = palloc(NCHARS * sizeof(char));
00158             snprintf(values[Atnum_xmax], NCHARS, "%d", xmax);
00159             if (infomask & HEAP_XMAX_IS_MULTI)
00160             {
00161                 MultiXactMember *members;
00162                 int         nmembers;
00163                 bool        first = true;
00164                 bool        allow_old;
00165 
00166                 values[Atnum_ismulti] = pstrdup("true");
00167 
00168                 allow_old = !(infomask & HEAP_LOCK_MASK) &&
00169                              (infomask & HEAP_XMAX_LOCK_ONLY);
00170                 nmembers = GetMultiXactIdMembers(xmax, &members, allow_old);
00171                 if (nmembers == -1)
00172                 {
00173                     values[Atnum_xids] = "{0}";
00174                     values[Atnum_modes] = "{transient upgrade status}";
00175                     values[Atnum_pids] = "{0}";
00176                 }
00177                 else
00178                 {
00179                     int         j;
00180 
00181                     values[Atnum_xids] = palloc(NCHARS * nmembers);
00182                     values[Atnum_modes] = palloc(NCHARS * nmembers);
00183                     values[Atnum_pids] = palloc(NCHARS * nmembers);
00184 
00185                     strcpy(values[Atnum_xids], "{");
00186                     strcpy(values[Atnum_modes], "{");
00187                     strcpy(values[Atnum_pids], "{");
00188 
00189                     for (j = 0; j < nmembers; j++)
00190                     {
00191                         char        buf[NCHARS];
00192 
00193                         if (!first)
00194                         {
00195                             strcat(values[Atnum_xids], ",");
00196                             strcat(values[Atnum_modes], ",");
00197                             strcat(values[Atnum_pids], ",");
00198                         }
00199                         snprintf(buf, NCHARS, "%d", members[j].xid);
00200                         strcat(values[Atnum_xids], buf);
00201                         switch (members[j].status)
00202                         {
00203                             case MultiXactStatusUpdate:
00204                                 snprintf(buf, NCHARS, "Update");
00205                                 break;
00206                             case MultiXactStatusNoKeyUpdate:
00207                                 snprintf(buf, NCHARS, "No Key Update");
00208                                 break;
00209                             case MultiXactStatusForUpdate:
00210                                 snprintf(buf, NCHARS, "For Update");
00211                                 break;
00212                             case MultiXactStatusForNoKeyUpdate:
00213                                 snprintf(buf, NCHARS, "For No Key Update");
00214                                 break;
00215                             case MultiXactStatusForShare:
00216                                 snprintf(buf, NCHARS, "Share");
00217                                 break;
00218                             case MultiXactStatusForKeyShare:
00219                                 snprintf(buf, NCHARS, "Key Share");
00220                                 break;
00221                         }
00222                         strcat(values[Atnum_modes], buf);
00223                         snprintf(buf, NCHARS, "%d",
00224                                  BackendXidGetPid(members[j].xid));
00225                         strcat(values[Atnum_pids], buf);
00226 
00227                         first = false;
00228                     }
00229 
00230                     strcat(values[Atnum_xids], "}");
00231                     strcat(values[Atnum_modes], "}");
00232                     strcat(values[Atnum_pids], "}");
00233                 }
00234             }
00235             else
00236             {
00237                 values[Atnum_ismulti] = pstrdup("false");
00238 
00239                 values[Atnum_xids] = palloc(NCHARS * sizeof(char));
00240                 snprintf(values[Atnum_xids], NCHARS, "{%d}", xmax);
00241 
00242                 values[Atnum_modes] = palloc(NCHARS);
00243                 if (infomask & HEAP_XMAX_LOCK_ONLY)
00244                 {
00245                     if (HEAP_XMAX_IS_SHR_LOCKED(infomask))
00246                         snprintf(values[Atnum_modes], NCHARS, "{For Share}");
00247                     else if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask))
00248                         snprintf(values[Atnum_modes], NCHARS, "{For Key Share}");
00249                     else if (HEAP_XMAX_IS_EXCL_LOCKED(infomask))
00250                     {
00251                         if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
00252                             snprintf(values[Atnum_modes], NCHARS, "{For Update}");
00253                         else
00254                             snprintf(values[Atnum_modes], NCHARS, "{For No Key Update}");
00255                     }
00256                     else
00257                         /* neither keyshare nor exclusive bit it set */
00258                         snprintf(values[Atnum_modes], NCHARS,
00259                                  "{transient upgrade status}");
00260                 }
00261                 else
00262                 {
00263                     if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
00264                         snprintf(values[Atnum_modes], NCHARS, "{Update}");
00265                     else
00266                         snprintf(values[Atnum_modes], NCHARS, "{No Key Update}");
00267                 }
00268 
00269                 values[Atnum_pids] = palloc(NCHARS * sizeof(char));
00270                 snprintf(values[Atnum_pids], NCHARS, "{%d}",
00271                          BackendXidGetPid(xmax));
00272             }
00273 
00274             LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
00275 
00276             /* build a tuple */
00277             tuple = BuildTupleFromCStrings(attinmeta, values);
00278 
00279             /* make the tuple into a datum */
00280             result = HeapTupleGetDatum(tuple);
00281 
00282             /*
00283              * no need to pfree what we allocated; it's on a short-lived memory
00284              * context anyway
00285              */
00286 
00287             SRF_RETURN_NEXT(funcctx, result);
00288         }
00289         else
00290         {
00291             LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
00292         }
00293     }
00294 
00295     heap_endscan(scan);
00296     heap_close(mydata->rel, AccessShareLock);
00297 
00298     SRF_RETURN_DONE(funcctx);
00299 }