LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - xid8funcs.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 78.2 % 220 172 2 5 41 1 77 5 89 5 76 1 5
Current Date: 2023-04-08 17:13:01 Functions: 90.5 % 21 19 2 11 2 6 12
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (60,120] days: 100.0 % 5 5 5
Legend: Lines: hit not hit (240..) days: 77.7 % 215 167 2 5 41 1 77 89 5 76
Function coverage date bins:
(60,120] days: 100.0 % 1 1 1
(240..) days: 56.2 % 32 18 2 11 1 6 12

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  * xid8funcs.c
                                  3                 :  *
                                  4                 :  *  Export internal transaction IDs to user level.
                                  5                 :  *
                                  6                 :  * Note that only top-level transaction IDs are exposed to user sessions.
                                  7                 :  * This is important because xid8s frequently persist beyond the global
                                  8                 :  * xmin horizon, or may even be shipped to other machines, so we cannot
                                  9                 :  * rely on being able to correlate subtransaction IDs with their parents
                                 10                 :  * via functions such as SubTransGetTopmostTransaction().
                                 11                 :  *
                                 12                 :  * These functions are used to support the txid_XXX functions and the newer
                                 13                 :  * pg_current_xact_id, pg_current_snapshot and related fmgr functions, since
                                 14                 :  * the only difference between them is whether they expose xid8 or int8 values
                                 15                 :  * to users.  The txid_XXX variants should eventually be dropped.
                                 16                 :  *
                                 17                 :  *
                                 18                 :  *  Copyright (c) 2003-2023, PostgreSQL Global Development Group
                                 19                 :  *  Author: Jan Wieck, Afilias USA INC.
                                 20                 :  *  64-bit txids: Marko Kreen, Skype Technologies
                                 21                 :  *
                                 22                 :  *  src/backend/utils/adt/xid8funcs.c
                                 23                 :  *
                                 24                 :  *-------------------------------------------------------------------------
                                 25                 :  */
                                 26                 : 
                                 27                 : #include "postgres.h"
                                 28                 : 
                                 29                 : #include "access/clog.h"
                                 30                 : #include "access/transam.h"
                                 31                 : #include "access/xact.h"
                                 32                 : #include "access/xlog.h"
                                 33                 : #include "funcapi.h"
                                 34                 : #include "lib/qunique.h"
                                 35                 : #include "libpq/pqformat.h"
                                 36                 : #include "miscadmin.h"
                                 37                 : #include "postmaster/postmaster.h"
                                 38                 : #include "storage/lwlock.h"
                                 39                 : #include "storage/procarray.h"
                                 40                 : #include "utils/builtins.h"
                                 41                 : #include "utils/memutils.h"
                                 42                 : #include "utils/snapmgr.h"
                                 43                 : #include "utils/xid8.h"
                                 44                 : 
                                 45                 : 
                                 46                 : /*
                                 47                 :  * If defined, use bsearch() function for searching for xid8s in snapshots
                                 48                 :  * that have more than the specified number of values.
                                 49                 :  */
                                 50                 : #define USE_BSEARCH_IF_NXIP_GREATER 30
                                 51                 : 
                                 52                 : 
                                 53                 : /*
                                 54                 :  * Snapshot containing FullTransactionIds.
                                 55                 :  */
                                 56                 : typedef struct
                                 57                 : {
                                 58                 :     /*
                                 59                 :      * 4-byte length hdr, should not be touched directly.
                                 60                 :      *
                                 61                 :      * Explicit embedding is ok as we want always correct alignment anyway.
                                 62                 :      */
                                 63                 :     int32       __varsz;
                                 64                 : 
                                 65                 :     uint32      nxip;           /* number of fxids in xip array */
                                 66                 :     FullTransactionId xmin;
                                 67                 :     FullTransactionId xmax;
                                 68                 :     /* in-progress fxids, xmin <= xip[i] < xmax: */
                                 69                 :     FullTransactionId xip[FLEXIBLE_ARRAY_MEMBER];
                                 70                 : } pg_snapshot;
                                 71                 : 
                                 72                 : #define PG_SNAPSHOT_SIZE(nxip) \
                                 73                 :     (offsetof(pg_snapshot, xip) + sizeof(FullTransactionId) * (nxip))
                                 74                 : #define PG_SNAPSHOT_MAX_NXIP \
                                 75                 :     ((MaxAllocSize - offsetof(pg_snapshot, xip)) / sizeof(FullTransactionId))
                                 76                 : 
                                 77                 : /*
                                 78                 :  * Compile-time limits on the procarray (MAX_BACKENDS processes plus
                                 79                 :  * MAX_BACKENDS prepared transactions) guarantee nxip won't be too large.
                                 80                 :  */
                                 81                 : StaticAssertDecl(MAX_BACKENDS * 2 <= PG_SNAPSHOT_MAX_NXIP,
                                 82                 :                  "possible overflow in pg_current_snapshot()");
                                 83                 : 
                                 84                 : 
                                 85                 : /*
                                 86                 :  * Helper to get a TransactionId from a 64-bit xid with wraparound detection.
                                 87                 :  *
                                 88                 :  * It is an ERROR if the xid is in the future.  Otherwise, returns true if
                                 89                 :  * the transaction is still new enough that we can determine whether it
                                 90                 :  * committed and false otherwise.  If *extracted_xid is not NULL, it is set
                                 91                 :  * to the low 32 bits of the transaction ID (i.e. the actual XID, without the
                                 92                 :  * epoch).
                                 93                 :  *
                                 94                 :  * The caller must hold XactTruncationLock since it's dealing with arbitrary
                                 95                 :  * XIDs, and must continue to hold it until it's done with any clog lookups
                                 96                 :  * relating to those XIDs.
                                 97                 :  */
                                 98                 : static bool
 1097 tmunro                     99 GIC          42 : TransactionIdInRecentPast(FullTransactionId fxid, TransactionId *extracted_xid)
                                100                 : {
                                101              42 :     uint32      xid_epoch = EpochFromFullTransactionId(fxid);
                                102              42 :     TransactionId xid = XidFromFullTransactionId(fxid);
                                103                 :     uint32      now_epoch;
                                104                 :     TransactionId now_epoch_next_xid;
                                105                 :     FullTransactionId now_fullxid;
                                106                 : 
 1473 tmunro                    107 CBC          42 :     now_fullxid = ReadNextFullTransactionId();
 1473 tmunro                    108 GIC          42 :     now_epoch_next_xid = XidFromFullTransactionId(now_fullxid);
 1473 tmunro                    109 CBC          42 :     now_epoch = EpochFromFullTransactionId(now_fullxid);
 2207 rhaas                     110 ECB             : 
 2207 rhaas                     111 GIC          42 :     if (extracted_xid != NULL)
                                112              42 :         *extracted_xid = xid;
                                113                 : 
                                114              42 :     if (!TransactionIdIsValid(xid))
 2207 rhaas                     115 LBC           0 :         return false;
 2207 rhaas                     116 ECB             : 
                                117                 :     /* For non-normal transaction IDs, we can ignore the epoch. */
 2207 rhaas                     118 GIC          42 :     if (!TransactionIdIsNormal(xid))
 2207 rhaas                     119 CBC          12 :         return true;
 2207 rhaas                     120 ECB             : 
                                121                 :     /* If the transaction ID is in the future, throw an error. */
 1097 tmunro                    122 CBC          30 :     if (!FullTransactionIdPrecedes(fxid, now_fullxid))
 2207 rhaas                     123 GBC           6 :         ereport(ERROR,
                                124                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                125                 :                  errmsg("transaction ID %llu is in the future",
  384 tgl                       126 ECB             :                         (unsigned long long) U64FromFullTransactionId(fxid))));
 2207 rhaas                     127                 : 
                                128                 :     /*
                                129                 :      * ShmemVariableCache->oldestClogXid is protected by XactTruncationLock,
                                130                 :      * but we don't acquire that lock here.  Instead, we require the caller to
                                131                 :      * acquire it, because the caller is presumably going to look up the
                                132                 :      * returned XID.  If we took and released the lock within this function, a
                                133                 :      * CLOG truncation could occur before the caller finished with the XID.
                                134                 :      */
 1059 tgl                       135 GIC          24 :     Assert(LWLockHeldByMe(XactTruncationLock));
                                136                 : 
                                137                 :     /*
                                138                 :      * If the transaction ID has wrapped around, it's definitely too old to
                                139                 :      * determine the commit status.  Otherwise, we can compare it to
                                140                 :      * ShmemVariableCache->oldestClogXid to determine whether the relevant
                                141                 :      * CLOG entry is guaranteed to still exist.
                                142                 :      */
 2207 rhaas                     143 CBC          24 :     if (xid_epoch + 1 < now_epoch
 1474 tmunro                    144 GIC          24 :         || (xid_epoch + 1 == now_epoch && xid < now_epoch_next_xid)
 2207 rhaas                     145              24 :         || TransactionIdPrecedes(xid, ShmemVariableCache->oldestClogXid))
                                146               6 :         return false;
                                147                 : 
                                148              18 :     return true;
                                149                 : }
                                150                 : 
 5657 tgl                       151 ECB             : /*
 1097 tmunro                    152                 :  * Convert a TransactionId obtained from a snapshot held by the caller to a
                                153                 :  * FullTransactionId.  Use next_fxid as a reference FullTransactionId, so that
                                154                 :  * we can compute the high order bits.  It must have been obtained by the
                                155                 :  * caller with ReadNextFullTransactionId() after the snapshot was created.
 5657 tgl                       156                 :  */
                                157                 : static FullTransactionId
 1097 tmunro                    158 GIC          45 : widen_snapshot_xid(TransactionId xid, FullTransactionId next_fxid)
                                159                 : {
                                160              45 :     TransactionId next_xid = XidFromFullTransactionId(next_fxid);
                                161              45 :     uint32      epoch = EpochFromFullTransactionId(next_fxid);
                                162                 : 
                                163                 :     /* Special transaction ID. */
 5657 tgl                       164              45 :     if (!TransactionIdIsNormal(xid))
 1097 tmunro                    165 UIC           0 :         return FullTransactionIdFromEpochAndXid(0, xid);
 5657 tgl                       166 ECB             : 
                                167                 :     /*
 1097 tmunro                    168                 :      * The 64 bit result must be <= next_fxid, since next_fxid hadn't been
                                169                 :      * issued yet when the snapshot was created.  Every TransactionId in the
                                170                 :      * snapshot must therefore be from the same epoch as next_fxid, or the
                                171                 :      * epoch before.  We know this because next_fxid is never allow to get
                                172                 :      * more than one epoch ahead of the TransactionIds in any snapshot.
 1097 tmunro                    173 EUB             :      */
 1097 tmunro                    174 GIC          45 :     if (xid > next_xid)
 5657 tgl                       175 UIC           0 :         epoch--;
                                176                 : 
 1097 tmunro                    177 GIC          45 :     return FullTransactionIdFromEpochAndXid(epoch, xid);
                                178                 : }
                                179                 : 
                                180                 : /*
                                181                 :  * txid comparator for qsort/bsearch
 5657 tgl                       182 ECB             :  */
 5657 tgl                       183 EUB             : static int
 1097 tmunro                    184 GIC        1367 : cmp_fxid(const void *aa, const void *bb)
 5657 tgl                       185 ECB             : {
 1097 tmunro                    186 GIC        1367 :     FullTransactionId a = *(const FullTransactionId *) aa;
                                187            1367 :     FullTransactionId b = *(const FullTransactionId *) bb;
                                188                 : 
                                189            1367 :     if (FullTransactionIdPrecedes(a, b))
 5657 tgl                       190             329 :         return -1;
 1097 tmunro                    191            1038 :     if (FullTransactionIdPrecedes(b, a))
 5657 tgl                       192 CBC         852 :         return 1;
 5657 tgl                       193 GIC         186 :     return 0;
 5657 tgl                       194 ECB             : }
                                195                 : 
                                196                 : /*
 3251 heikki.linnakangas        197                 :  * Sort a snapshot's txids, so we can use bsearch() later.  Also remove
                                198                 :  * any duplicates.
 5657 tgl                       199                 :  *
                                200                 :  * For consistency of on-disk representation, we always sort even if bsearch
                                201                 :  * will not be used.
                                202                 :  */
                                203                 : static void
 1097 tmunro                    204 GIC          12 : sort_snapshot(pg_snapshot *snap)
                                205                 : {
 5657 tgl                       206              12 :     if (snap->nxip > 1)
                                207                 :     {
 1097 tmunro                    208              10 :         qsort(snap->xip, snap->nxip, sizeof(FullTransactionId), cmp_fxid);
                                209              10 :         snap->nxip = qunique(snap->xip, snap->nxip, sizeof(FullTransactionId),
                                210                 :                              cmp_fxid);
                                211                 :     }
 5657 tgl                       212 CBC          12 : }
                                213                 : 
 5657 tgl                       214 ECB             : /*
                                215                 :  * check fxid visibility.
                                216                 :  */
                                217                 : static bool
 1097 tmunro                    218 GIC         510 : is_visible_fxid(FullTransactionId value, const pg_snapshot *snap)
                                219                 : {
 1097 tmunro                    220 CBC         510 :     if (FullTransactionIdPrecedes(value, snap->xmin))
 5657 tgl                       221 GIC          66 :         return true;
 1097 tmunro                    222             444 :     else if (!FullTransactionIdPrecedes(value, snap->xmax))
 5657 tgl                       223              84 :         return false;
                                224                 : #ifdef USE_BSEARCH_IF_NXIP_GREATER
                                225             360 :     else if (snap->nxip > USE_BSEARCH_IF_NXIP_GREATER)
 5657 tgl                       226 ECB             :     {
                                227                 :         void       *res;
                                228                 : 
 1097 tmunro                    229 CBC         300 :         res = bsearch(&value, snap->xip, snap->nxip, sizeof(FullTransactionId),
 1097 tmunro                    230 ECB             :                       cmp_fxid);
 5657 tgl                       231                 :         /* if found, transaction is still in progress */
 5657 tgl                       232 GIC         300 :         return (res) ? false : true;
 5657 tgl                       233 ECB             :     }
                                234                 : #endif
                                235                 :     else
                                236                 :     {
 5624 bruce                     237                 :         uint32      i;
                                238                 : 
 5657 tgl                       239 GIC         180 :         for (i = 0; i < snap->nxip; i++)
 5657 tgl                       240 ECB             :         {
 1097 tmunro                    241 GIC         144 :             if (FullTransactionIdEquals(value, snap->xip[i]))
 5657 tgl                       242              24 :                 return false;
                                243                 :         }
                                244              36 :         return true;
                                245                 :     }
                                246                 : }
 5657 tgl                       247 ECB             : 
                                248                 : /*
 1097 tmunro                    249                 :  * helper functions to use StringInfo for pg_snapshot creation.
 5657 tgl                       250                 :  */
                                251                 : 
                                252                 : static StringInfo
 1097 tmunro                    253 GIC          93 : buf_init(FullTransactionId xmin, FullTransactionId xmax)
                                254                 : {
                                255                 :     pg_snapshot snap;
                                256                 :     StringInfo  buf;
                                257                 : 
 5657 tgl                       258              93 :     snap.xmin = xmin;
                                259              93 :     snap.xmax = xmax;
                                260              93 :     snap.nxip = 0;
 5657 tgl                       261 ECB             : 
 5657 tgl                       262 GIC          93 :     buf = makeStringInfo();
  100 peter                     263 GNC          93 :     appendBinaryStringInfo(buf, &snap, PG_SNAPSHOT_SIZE(0));
 5657 tgl                       264 GIC          93 :     return buf;
                                265                 : }
 5657 tgl                       266 ECB             : 
                                267                 : static void
 1097 tmunro                    268 CBC         312 : buf_add_txid(StringInfo buf, FullTransactionId fxid)
                                269                 : {
                                270             312 :     pg_snapshot *snap = (pg_snapshot *) buf->data;
 5657 tgl                       271 ECB             : 
                                272                 :     /* do this before possible realloc */
 5657 tgl                       273 GIC         312 :     snap->nxip++;
                                274                 : 
  100 peter                     275 GNC         312 :     appendBinaryStringInfo(buf, &fxid, sizeof(fxid));
 5657 tgl                       276 CBC         312 : }
                                277                 : 
 1097 tmunro                    278 ECB             : static pg_snapshot *
 5657 tgl                       279 GIC          75 : buf_finalize(StringInfo buf)
                                280                 : {
 1097 tmunro                    281 CBC          75 :     pg_snapshot *snap = (pg_snapshot *) buf->data;
                                282                 : 
 5657 tgl                       283              75 :     SET_VARSIZE(snap, buf->len);
 5657 tgl                       284 ECB             : 
                                285                 :     /* buf is not needed anymore */
 5657 tgl                       286 GIC          75 :     buf->data = NULL;
 5657 tgl                       287 CBC          75 :     pfree(buf);
                                288                 : 
                                289              75 :     return snap;
                                290                 : }
 5657 tgl                       291 ECB             : 
                                292                 : /*
                                293                 :  * parse snapshot from cstring
                                294                 :  */
 1097 tmunro                    295                 : static pg_snapshot *
  116 tgl                       296 GNC         117 : parse_snapshot(const char *str, Node *escontext)
 5657 tgl                       297 ECB             : {
                                298                 :     FullTransactionId xmin;
                                299                 :     FullTransactionId xmax;
 1097 tmunro                    300 GIC         117 :     FullTransactionId last_val = InvalidFullTransactionId;
                                301                 :     FullTransactionId val;
 5657 tgl                       302             117 :     const char *str_start = str;
                                303                 :     char       *endp;
 5624 bruce                     304 ECB             :     StringInfo  buf;
                                305                 : 
  478 peter                     306 GIC         117 :     xmin = FullTransactionIdFromU64(strtou64(str, &endp, 10));
 5657 tgl                       307             117 :     if (*endp != ':')
 5657 tgl                       308 LBC           0 :         goto bad_format;
 5657 tgl                       309 GIC         117 :     str = endp + 1;
 5657 tgl                       310 ECB             : 
  478 peter                     311 GIC         117 :     xmax = FullTransactionIdFromU64(strtou64(str, &endp, 10));
 5657 tgl                       312             117 :     if (*endp != ':')
 5657 tgl                       313 UIC           0 :         goto bad_format;
 5657 tgl                       314 CBC         117 :     str = endp + 1;
 5657 tgl                       315 ECB             : 
 5657 tgl                       316 EUB             :     /* it should look sane */
 1097 tmunro                    317 CBC         117 :     if (!FullTransactionIdIsValid(xmin) ||
 1097 tmunro                    318 GIC         111 :         !FullTransactionIdIsValid(xmax) ||
 1097 tmunro                    319 CBC         105 :         FullTransactionIdPrecedes(xmax, xmin))
 5657 tgl                       320              24 :         goto bad_format;
 5657 tgl                       321 EUB             : 
 5657 tgl                       322 ECB             :     /* allocate buffer */
 5657 tgl                       323 GIC          93 :     buf = buf_init(xmin, xmax);
                                324                 : 
 5657 tgl                       325 ECB             :     /* loop over values */
 5657 tgl                       326 CBC         411 :     while (*str != '\0')
 5657 tgl                       327 ECB             :     {
                                328                 :         /* read next value */
  478 peter                     329 GIC         336 :         val = FullTransactionIdFromU64(strtou64(str, &endp, 10));
 5657 tgl                       330             336 :         str = endp;
 5657 tgl                       331 ECB             : 
                                332                 :         /* require the input to be in order */
 1097 tmunro                    333 GIC         336 :         if (FullTransactionIdPrecedes(val, xmin) ||
 1097 tmunro                    334 CBC         330 :             FullTransactionIdFollowsOrEquals(val, xmax) ||
 1097 tmunro                    335 GIC         330 :             FullTransactionIdPrecedes(val, last_val))
 5657 tgl                       336              18 :             goto bad_format;
 5624 bruce                     337 ECB             : 
 3251 heikki.linnakangas        338                 :         /* skip duplicates */
 1097 tmunro                    339 GIC         318 :         if (!FullTransactionIdEquals(val, last_val))
 3251 heikki.linnakangas        340             312 :             buf_add_txid(buf, val);
 5657 tgl                       341 CBC         318 :         last_val = val;
 5657 tgl                       342 ECB             : 
 5657 tgl                       343 CBC         318 :         if (*str == ',')
                                344             258 :             str++;
 5657 tgl                       345 GIC          60 :         else if (*str != '\0')
 5657 tgl                       346 UIC           0 :             goto bad_format;
 5657 tgl                       347 ECB             :     }
                                348                 : 
 5657 tgl                       349 CBC          75 :     return buf_finalize(buf);
                                350                 : 
                                351              42 : bad_format:
  116 tgl                       352 GNC          42 :     ereturn(escontext, NULL,
 2807 tgl                       353 ECB             :             (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 2272 alvherre                  354 EUB             :              errmsg("invalid input syntax for type %s: \"%s\"",
                                355                 :                     "pg_snapshot", str_start)));
 5657 tgl                       356 ECB             : }
                                357                 : 
                                358                 : /*
 1097 tmunro                    359                 :  * pg_current_xact_id() returns xid8
                                360                 :  *
                                361                 :  *  Return the current toplevel full transaction ID.
                                362                 :  *  If the current transaction does not have one, one is assigned.
                                363                 :  */
                                364                 : Datum
 1097 tmunro                    365 GIC        2865 : pg_current_xact_id(PG_FUNCTION_ARGS)
                                366                 : {
                                367                 :     /*
                                368                 :      * Must prevent during recovery because if an xid is not assigned we try
                                369                 :      * to assign one, which would fail. Programs already rely on this function
                                370                 :      * to always return a valid current xid, so we should not change this to
                                371                 :      * return NULL or similar invalid xid.
 4859 simon                     372 ECB             :      */
 1097 tmunro                    373 GIC        2865 :     PreventCommandDuringRecovery("pg_current_xact_id()");
                                374                 : 
                                375            2865 :     PG_RETURN_FULLTRANSACTIONID(GetTopFullTransactionId());
                                376                 : }
                                377                 : 
                                378                 : /*
                                379                 :  * Same as pg_current_xact_id() but doesn't assign a new xid if there
 1097 tmunro                    380 ECB             :  * isn't one yet.
                                381                 :  */
 2420 rhaas                     382                 : Datum
 1097 tmunro                    383 GIC          12 : pg_current_xact_id_if_assigned(PG_FUNCTION_ARGS)
                                384                 : {
                                385              12 :     FullTransactionId topfxid = GetTopFullTransactionIdIfAny();
                                386                 : 
                                387              12 :     if (!FullTransactionIdIsValid(topfxid))
 2420 rhaas                     388               6 :         PG_RETURN_NULL();
                                389                 : 
 1097 tmunro                    390 CBC           6 :     PG_RETURN_FULLTRANSACTIONID(topfxid);
                                391                 : }
 2420 rhaas                     392 ECB             : 
                                393                 : /*
 1097 tmunro                    394                 :  * pg_current_snapshot() returns pg_snapshot
 5657 tgl                       395                 :  *
                                396                 :  *      Return current snapshot
                                397                 :  *
                                398                 :  * Note that only top-transaction XIDs are included in the snapshot.
                                399                 :  */
                                400                 : Datum
 1097 tmunro                    401 GIC          12 : pg_current_snapshot(PG_FUNCTION_ARGS)
                                402                 : {
                                403                 :     pg_snapshot *snap;
                                404                 :     uint32      nxip,
                                405                 :                 i;
                                406                 :     Snapshot    cur;
                                407              12 :     FullTransactionId next_fxid = ReadNextFullTransactionId();
 5657 tgl                       408 ECB             : 
 5445 alvherre                  409 GIC          12 :     cur = GetActiveSnapshot();
 5657 tgl                       410              12 :     if (cur == NULL)
 5445 alvherre                  411 UIC           0 :         elog(ERROR, "no active snapshot set");
                                412                 : 
                                413                 :     /* allocate */
 5657 tgl                       414 CBC          12 :     nxip = cur->xcnt;
 1097 tmunro                    415              12 :     snap = palloc(PG_SNAPSHOT_SIZE(nxip));
                                416                 : 
                                417                 :     /* fill */
                                418              12 :     snap->xmin = widen_snapshot_xid(cur->xmin, next_fxid);
                                419              12 :     snap->xmax = widen_snapshot_xid(cur->xmax, next_fxid);
 5657 tgl                       420              12 :     snap->nxip = nxip;
                                421              33 :     for (i = 0; i < nxip; i++)
 1097 tmunro                    422              21 :         snap->xip[i] = widen_snapshot_xid(cur->xip[i], next_fxid);
                                423                 : 
                                424                 :     /*
                                425                 :      * We want them guaranteed to be in ascending order.  This also removes
                                426                 :      * any duplicate xids.  Normally, an XID can only be assigned to one
                                427                 :      * backend, but when preparing a transaction for two-phase commit, there
                                428                 :      * is a transient state when both the original backend and the dummy
                                429                 :      * PGPROC entry reserved for the prepared transaction hold the same XID.
                                430                 :      */
 5657 tgl                       431              12 :     sort_snapshot(snap);
                                432                 : 
                                433                 :     /* set size after sorting, because it may have removed duplicate xips */
 1097 tmunro                    434              12 :     SET_VARSIZE(snap, PG_SNAPSHOT_SIZE(snap->nxip));
                                435                 : 
 5657 tgl                       436              12 :     PG_RETURN_POINTER(snap);
                                437                 : }
                                438                 : 
                                439                 : /*
                                440                 :  * pg_snapshot_in(cstring) returns pg_snapshot
                                441                 :  *
                                442                 :  *      input function for type pg_snapshot
                                443                 :  */
                                444                 : Datum
 1097 tmunro                    445             117 : pg_snapshot_in(PG_FUNCTION_ARGS)
                                446                 : {
 5657 tgl                       447             117 :     char       *str = PG_GETARG_CSTRING(0);
                                448                 :     pg_snapshot *snap;
                                449                 : 
  116 tgl                       450 GNC         117 :     snap = parse_snapshot(str, fcinfo->context);
                                451                 : 
 5657 tgl                       452 CBC          87 :     PG_RETURN_POINTER(snap);
                                453                 : }
                                454                 : 
                                455                 : /*
                                456                 :  * pg_snapshot_out(pg_snapshot) returns cstring
                                457                 :  *
                                458                 :  *      output function for type pg_snapshot
                                459                 :  */
                                460                 : Datum
 1097 tmunro                    461              62 : pg_snapshot_out(PG_FUNCTION_ARGS)
                                462                 : {
                                463              62 :     pg_snapshot *snap = (pg_snapshot *) PG_GETARG_VARLENA_P(0);
                                464                 :     StringInfoData str;
                                465                 :     uint32      i;
                                466                 : 
 5657 tgl                       467              62 :     initStringInfo(&str);
                                468                 : 
 1097 tmunro                    469              62 :     appendStringInfo(&str, UINT64_FORMAT ":",
                                470                 :                      U64FromFullTransactionId(snap->xmin));
                                471              62 :     appendStringInfo(&str, UINT64_FORMAT ":",
                                472                 :                      U64FromFullTransactionId(snap->xmax));
                                473                 : 
 5657 tgl                       474             344 :     for (i = 0; i < snap->nxip; i++)
                                475                 :     {
                                476             282 :         if (i > 0)
                                477             232 :             appendStringInfoChar(&str, ',');
 1097 tmunro                    478             282 :         appendStringInfo(&str, UINT64_FORMAT,
                                479                 :                          U64FromFullTransactionId(snap->xip[i]));
                                480                 :     }
                                481                 : 
 5657 tgl                       482              62 :     PG_RETURN_CSTRING(str.data);
                                483                 : }
                                484                 : 
                                485                 : /*
                                486                 :  * pg_snapshot_recv(internal) returns pg_snapshot
                                487                 :  *
                                488                 :  *      binary input function for type pg_snapshot
                                489                 :  *
                                490                 :  *      format: int4 nxip, int8 xmin, int8 xmax, int8 xip
                                491                 :  */
                                492                 : Datum
 1097 tmunro                    493 UBC           0 : pg_snapshot_recv(PG_FUNCTION_ARGS)
                                494                 : {
 5624 bruce                     495               0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
                                496                 :     pg_snapshot *snap;
 1097 tmunro                    497               0 :     FullTransactionId last = InvalidFullTransactionId;
                                498                 :     int         nxip;
                                499                 :     int         i;
                                500                 :     FullTransactionId xmin;
                                501                 :     FullTransactionId xmax;
                                502                 : 
                                503                 :     /* load and validate nxip */
 5657 tgl                       504               0 :     nxip = pq_getmsgint(buf, 4);
 1097 tmunro                    505               0 :     if (nxip < 0 || nxip > PG_SNAPSHOT_MAX_NXIP)
 5657 tgl                       506               0 :         goto bad_format;
                                507                 : 
 1097 tmunro                    508               0 :     xmin = FullTransactionIdFromU64((uint64) pq_getmsgint64(buf));
                                509               0 :     xmax = FullTransactionIdFromU64((uint64) pq_getmsgint64(buf));
                                510               0 :     if (!FullTransactionIdIsValid(xmin) ||
                                511               0 :         !FullTransactionIdIsValid(xmax) ||
                                512               0 :         FullTransactionIdPrecedes(xmax, xmin))
 5657 tgl                       513               0 :         goto bad_format;
                                514                 : 
 1097 tmunro                    515               0 :     snap = palloc(PG_SNAPSHOT_SIZE(nxip));
 5657 tgl                       516               0 :     snap->xmin = xmin;
                                517               0 :     snap->xmax = xmax;
                                518                 : 
                                519               0 :     for (i = 0; i < nxip; i++)
                                520                 :     {
                                521                 :         FullTransactionId cur =
 1097 tmunro                    522               0 :         FullTransactionIdFromU64((uint64) pq_getmsgint64(buf));
                                523                 : 
                                524               0 :         if (FullTransactionIdPrecedes(cur, last) ||
                                525               0 :             FullTransactionIdPrecedes(cur, xmin) ||
                                526               0 :             FullTransactionIdPrecedes(xmax, cur))
 5657 tgl                       527               0 :             goto bad_format;
                                528                 : 
                                529                 :         /* skip duplicate xips */
 1097 tmunro                    530               0 :         if (FullTransactionIdEquals(cur, last))
                                531                 :         {
 3251 heikki.linnakangas        532               0 :             i--;
                                533               0 :             nxip--;
                                534               0 :             continue;
                                535                 :         }
                                536                 : 
 5657 tgl                       537               0 :         snap->xip[i] = cur;
                                538               0 :         last = cur;
                                539                 :     }
 3251 heikki.linnakangas        540               0 :     snap->nxip = nxip;
 1097 tmunro                    541               0 :     SET_VARSIZE(snap, PG_SNAPSHOT_SIZE(nxip));
 5657 tgl                       542               0 :     PG_RETURN_POINTER(snap);
                                543                 : 
                                544               0 : bad_format:
 2807                           545               0 :     ereport(ERROR,
                                546                 :             (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
                                547                 :              errmsg("invalid external pg_snapshot data")));
                                548                 :     PG_RETURN_POINTER(NULL);    /* keep compiler quiet */
                                549                 : }
                                550                 : 
                                551                 : /*
                                552                 :  * pg_snapshot_send(pg_snapshot) returns bytea
                                553                 :  *
                                554                 :  *      binary output function for type pg_snapshot
                                555                 :  *
                                556                 :  *      format: int4 nxip, u64 xmin, u64 xmax, u64 xip...
                                557                 :  */
                                558                 : Datum
 1097 tmunro                    559               0 : pg_snapshot_send(PG_FUNCTION_ARGS)
                                560                 : {
                                561               0 :     pg_snapshot *snap = (pg_snapshot *) PG_GETARG_VARLENA_P(0);
                                562                 :     StringInfoData buf;
                                563                 :     uint32      i;
                                564                 : 
 5657 tgl                       565               0 :     pq_begintypsend(&buf);
 2006 andres                    566               0 :     pq_sendint32(&buf, snap->nxip);
 1097 tmunro                    567               0 :     pq_sendint64(&buf, (int64) U64FromFullTransactionId(snap->xmin));
                                568               0 :     pq_sendint64(&buf, (int64) U64FromFullTransactionId(snap->xmax));
 5657 tgl                       569               0 :     for (i = 0; i < snap->nxip; i++)
 1097 tmunro                    570               0 :         pq_sendint64(&buf, (int64) U64FromFullTransactionId(snap->xip[i]));
 5657 tgl                       571               0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
                                572                 : }
                                573                 : 
                                574                 : /*
                                575                 :  * pg_visible_in_snapshot(xid8, pg_snapshot) returns bool
                                576                 :  *
                                577                 :  *      is txid visible in snapshot ?
                                578                 :  */
                                579                 : Datum
 1097 tmunro                    580 CBC         510 : pg_visible_in_snapshot(PG_FUNCTION_ARGS)
                                581                 : {
                                582             510 :     FullTransactionId value = PG_GETARG_FULLTRANSACTIONID(0);
                                583             510 :     pg_snapshot *snap = (pg_snapshot *) PG_GETARG_VARLENA_P(1);
                                584                 : 
                                585             510 :     PG_RETURN_BOOL(is_visible_fxid(value, snap));
                                586                 : }
                                587                 : 
                                588                 : /*
                                589                 :  * pg_snapshot_xmin(pg_snapshot) returns xid8
                                590                 :  *
                                591                 :  *      return snapshot's xmin
                                592                 :  */
                                593                 : Datum
                                594              30 : pg_snapshot_xmin(PG_FUNCTION_ARGS)
                                595                 : {
                                596              30 :     pg_snapshot *snap = (pg_snapshot *) PG_GETARG_VARLENA_P(0);
                                597                 : 
                                598              30 :     PG_RETURN_FULLTRANSACTIONID(snap->xmin);
                                599                 : }
                                600                 : 
                                601                 : /*
                                602                 :  * pg_snapshot_xmax(pg_snapshot) returns xid8
                                603                 :  *
                                604                 :  *      return snapshot's xmax
                                605                 :  */
                                606                 : Datum
                                607              24 : pg_snapshot_xmax(PG_FUNCTION_ARGS)
                                608                 : {
                                609              24 :     pg_snapshot *snap = (pg_snapshot *) PG_GETARG_VARLENA_P(0);
                                610                 : 
                                611              24 :     PG_RETURN_FULLTRANSACTIONID(snap->xmax);
                                612                 : }
                                613                 : 
                                614                 : /*
                                615                 :  * pg_snapshot_xip(pg_snapshot) returns setof xid8
                                616                 :  *
                                617                 :  *      return in-progress xid8s in snapshot.
                                618                 :  */
                                619                 : Datum
                                620             246 : pg_snapshot_xip(PG_FUNCTION_ARGS)
                                621                 : {
                                622                 :     FuncCallContext *fctx;
                                623                 :     pg_snapshot *snap;
                                624                 :     FullTransactionId value;
                                625                 : 
                                626                 :     /* on first call initialize fctx and get copy of snapshot */
 5624 bruce                     627             246 :     if (SRF_IS_FIRSTCALL())
                                628                 :     {
 1097 tmunro                    629              24 :         pg_snapshot *arg = (pg_snapshot *) PG_GETARG_VARLENA_P(0);
                                630                 : 
 5657 tgl                       631              24 :         fctx = SRF_FIRSTCALL_INIT();
                                632                 : 
                                633                 :         /* make a copy of user snapshot */
                                634              24 :         snap = MemoryContextAlloc(fctx->multi_call_memory_ctx, VARSIZE(arg));
                                635              24 :         memcpy(snap, arg, VARSIZE(arg));
                                636                 : 
                                637              24 :         fctx->user_fctx = snap;
                                638                 :     }
                                639                 : 
                                640                 :     /* return values one-by-one */
                                641             246 :     fctx = SRF_PERCALL_SETUP();
                                642             246 :     snap = fctx->user_fctx;
 5624 bruce                     643             246 :     if (fctx->call_cntr < snap->nxip)
                                644                 :     {
 5657 tgl                       645             222 :         value = snap->xip[fctx->call_cntr];
 1097 tmunro                    646             222 :         SRF_RETURN_NEXT(fctx, FullTransactionIdGetDatum(value));
                                647                 :     }
                                648                 :     else
                                649                 :     {
 5657 tgl                       650              24 :         SRF_RETURN_DONE(fctx);
                                651                 :     }
                                652                 : }
                                653                 : 
                                654                 : /*
                                655                 :  * Report the status of a recent transaction ID, or null for wrapped,
                                656                 :  * truncated away or otherwise too old XIDs.
                                657                 :  *
                                658                 :  * The passed epoch-qualified xid is treated as a normal xid, not a
                                659                 :  * multixact id.
                                660                 :  *
                                661                 :  * If it points to a committed subxact the result is the subxact status even
                                662                 :  * though the parent xact may still be in progress or may have aborted.
                                663                 :  */
                                664                 : Datum
 1097 tmunro                    665              42 : pg_xact_status(PG_FUNCTION_ARGS)
                                666                 : {
                                667                 :     const char *status;
                                668              42 :     FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0);
                                669                 :     TransactionId xid;
                                670                 : 
                                671                 :     /*
                                672                 :      * We must protect against concurrent truncation of clog entries to avoid
                                673                 :      * an I/O error on SLRU lookup.
                                674                 :      */
 1059 tgl                       675              42 :     LWLockAcquire(XactTruncationLock, LW_SHARED);
 1097 tmunro                    676              42 :     if (TransactionIdInRecentPast(fxid, &xid))
                                677                 :     {
 2207 rhaas                     678              30 :         Assert(TransactionIdIsValid(xid));
                                679                 : 
                                680                 :         /*
                                681                 :          * Like when doing visiblity checks on a row, check whether the
                                682                 :          * transaction is still in progress before looking into the CLOG.
                                683                 :          * Otherwise we would incorrectly return "committed" for a transaction
                                684                 :          * that is committing and has already updated the CLOG, but hasn't
                                685                 :          * removed its XID from the proc array yet. (See comment on that race
                                686                 :          * condition at the top of heapam_visibility.c)
                                687                 :          */
  286 heikki.linnakangas        688              30 :         if (TransactionIdIsInProgress(xid))
 2036 peter_e                   689               6 :             status = "in progress";
 2207 rhaas                     690              24 :         else if (TransactionIdDidCommit(xid))
 2036 peter_e                   691              18 :             status = "committed";
                                692                 :         else
                                693                 :         {
                                694                 :             /* it must have aborted or crashed */
  286 heikki.linnakangas        695               6 :             status = "aborted";
                                696                 :         }
                                697                 :     }
                                698                 :     else
                                699                 :     {
 2207 rhaas                     700               6 :         status = NULL;
                                701                 :     }
 1059 tgl                       702              36 :     LWLockRelease(XactTruncationLock);
                                703                 : 
 2207 rhaas                     704              36 :     if (status == NULL)
                                705               6 :         PG_RETURN_NULL();
                                706                 :     else
                                707              30 :         PG_RETURN_TEXT_P(cstring_to_text(status));
                                708                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a