LCOV - differential code coverage report
Current view: top level - src/backend/utils/time - snapmgr.c (source / functions) Coverage Total Hit UBC GBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 87.4 % 564 493 71 493
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 49 49 49
Baseline: lcov-20250906-005545-baseline Branches: 55.5 % 434 241 193 1 240
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 0.0 % 2 0 2
(30,360] days: 100.0 % 2 2 2
(360..) days: 87.7 % 560 491 69 491
Function coverage date bins:
(360..) days: 100.0 % 49 49 49
Branch coverage date bins:
(7,30] days: 0.0 % 2 0 2
(360..) days: 55.8 % 432 241 191 1 240

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * snapmgr.c
                                  4                 :                :  *      PostgreSQL snapshot manager
                                  5                 :                :  *
                                  6                 :                :  * The following functions return an MVCC snapshot that can be used in tuple
                                  7                 :                :  * visibility checks:
                                  8                 :                :  *
                                  9                 :                :  * - GetTransactionSnapshot
                                 10                 :                :  * - GetLatestSnapshot
                                 11                 :                :  * - GetCatalogSnapshot
                                 12                 :                :  * - GetNonHistoricCatalogSnapshot
                                 13                 :                :  *
                                 14                 :                :  * Each of these functions returns a reference to a statically allocated
                                 15                 :                :  * snapshot.  The statically allocated snapshot is subject to change on any
                                 16                 :                :  * snapshot-related function call, and should not be used directly.  Instead,
                                 17                 :                :  * call PushActiveSnapshot() or RegisterSnapshot() to create a longer-lived
                                 18                 :                :  * copy and use that.
                                 19                 :                :  *
                                 20                 :                :  * We keep track of snapshots in two ways: those "registered" by resowner.c,
                                 21                 :                :  * and the "active snapshot" stack.  All snapshots in either of them live in
                                 22                 :                :  * persistent memory.  When a snapshot is no longer in any of these lists
                                 23                 :                :  * (tracked by separate refcounts on each snapshot), its memory can be freed.
                                 24                 :                :  *
                                 25                 :                :  * In addition to the above-mentioned MVCC snapshots, there are some special
                                 26                 :                :  * snapshots like SnapshotSelf, SnapshotAny, and "dirty" snapshots.  They can
                                 27                 :                :  * only be used in limited contexts and cannot be registered or pushed to the
                                 28                 :                :  * active stack.
                                 29                 :                :  *
                                 30                 :                :  * ActiveSnapshot stack
                                 31                 :                :  * --------------------
                                 32                 :                :  *
                                 33                 :                :  * Most visibility checks use the current "active snapshot" returned by
                                 34                 :                :  * GetActiveSnapshot().  When running normal queries, the active snapshot is
                                 35                 :                :  * set when query execution begins based on the transaction isolation level.
                                 36                 :                :  *
                                 37                 :                :  * The active snapshot is tracked in a stack so that the currently active one
                                 38                 :                :  * is at the top of the stack.  It mirrors the process call stack: whenever we
                                 39                 :                :  * recurse or switch context to fetch rows from a different portal for
                                 40                 :                :  * example, the appropriate snapshot is pushed to become the active snapshot,
                                 41                 :                :  * and popped on return.  Once upon a time, ActiveSnapshot was just a global
                                 42                 :                :  * variable that was saved and restored similar to CurrentMemoryContext, but
                                 43                 :                :  * nowadays it's managed as a separate data structure so that we can keep
                                 44                 :                :  * track of which snapshots are in use and reset MyProc->xmin when there is no
                                 45                 :                :  * active snapshot.
                                 46                 :                :  *
                                 47                 :                :  * However, there are a couple of exceptions where the active snapshot stack
                                 48                 :                :  * does not strictly mirror the call stack:
                                 49                 :                :  *
                                 50                 :                :  * - VACUUM and a few other utility commands manage their own transactions,
                                 51                 :                :  *   which take their own snapshots.  They are called with an active snapshot
                                 52                 :                :  *   set, like most utility commands, but they pop the active snapshot that
                                 53                 :                :  *   was pushed by the caller.  PortalRunUtility knows about the possibility
                                 54                 :                :  *   that the snapshot it pushed is no longer active on return.
                                 55                 :                :  *
                                 56                 :                :  * - When COMMIT or ROLLBACK is executed within a procedure or DO-block, the
                                 57                 :                :  *   active snapshot stack is destroyed, and re-established later when
                                 58                 :                :  *   subsequent statements in the procedure are executed.  There are many
                                 59                 :                :  *   limitations on when in-procedure COMMIT/ROLLBACK is allowed; one such
                                 60                 :                :  *   limitation is that all the snapshots on the active snapshot stack are
                                 61                 :                :  *   known to portals that are being executed, which makes it safe to reset
                                 62                 :                :  *   the stack.  See EnsurePortalSnapshotExists().
                                 63                 :                :  *
                                 64                 :                :  * Registered snapshots
                                 65                 :                :  * --------------------
                                 66                 :                :  *
                                 67                 :                :  * In addition to snapshots pushed to the active snapshot stack, a snapshot
                                 68                 :                :  * can be registered with a resource owner.
                                 69                 :                :  *
                                 70                 :                :  * The FirstXactSnapshot, if any, is treated a bit specially: we increment its
                                 71                 :                :  * regd_count and list it in RegisteredSnapshots, but this reference is not
                                 72                 :                :  * tracked by a resource owner. We used to use the TopTransactionResourceOwner
                                 73                 :                :  * to track this snapshot reference, but that introduces logical circularity
                                 74                 :                :  * and thus makes it impossible to clean up in a sane fashion.  It's better to
                                 75                 :                :  * handle this reference as an internally-tracked registration, so that this
                                 76                 :                :  * module is entirely lower-level than ResourceOwners.
                                 77                 :                :  *
                                 78                 :                :  * Likewise, any snapshots that have been exported by pg_export_snapshot
                                 79                 :                :  * have regd_count = 1 and are listed in RegisteredSnapshots, but are not
                                 80                 :                :  * tracked by any resource owner.
                                 81                 :                :  *
                                 82                 :                :  * Likewise, the CatalogSnapshot is listed in RegisteredSnapshots when it
                                 83                 :                :  * is valid, but is not tracked by any resource owner.
                                 84                 :                :  *
                                 85                 :                :  * The same is true for historic snapshots used during logical decoding,
                                 86                 :                :  * their lifetime is managed separately (as they live longer than one xact.c
                                 87                 :                :  * transaction).
                                 88                 :                :  *
                                 89                 :                :  * These arrangements let us reset MyProc->xmin when there are no snapshots
                                 90                 :                :  * referenced by this transaction, and advance it when the one with oldest
                                 91                 :                :  * Xmin is no longer referenced.  For simplicity however, only registered
                                 92                 :                :  * snapshots not active snapshots participate in tracking which one is oldest;
                                 93                 :                :  * we don't try to change MyProc->xmin except when the active-snapshot
                                 94                 :                :  * stack is empty.
                                 95                 :                :  *
                                 96                 :                :  *
                                 97                 :                :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
                                 98                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                 99                 :                :  *
                                100                 :                :  * IDENTIFICATION
                                101                 :                :  *    src/backend/utils/time/snapmgr.c
                                102                 :                :  *
                                103                 :                :  *-------------------------------------------------------------------------
                                104                 :                :  */
                                105                 :                : #include "postgres.h"
                                106                 :                : 
                                107                 :                : #include <sys/stat.h>
                                108                 :                : #include <unistd.h>
                                109                 :                : 
                                110                 :                : #include "access/subtrans.h"
                                111                 :                : #include "access/transam.h"
                                112                 :                : #include "access/xact.h"
                                113                 :                : #include "datatype/timestamp.h"
                                114                 :                : #include "lib/pairingheap.h"
                                115                 :                : #include "miscadmin.h"
                                116                 :                : #include "port/pg_lfind.h"
                                117                 :                : #include "storage/fd.h"
                                118                 :                : #include "storage/predicate.h"
                                119                 :                : #include "storage/proc.h"
                                120                 :                : #include "storage/procarray.h"
                                121                 :                : #include "utils/builtins.h"
                                122                 :                : #include "utils/memutils.h"
                                123                 :                : #include "utils/resowner.h"
                                124                 :                : #include "utils/snapmgr.h"
                                125                 :                : #include "utils/syscache.h"
                                126                 :                : 
                                127                 :                : 
                                128                 :                : /*
                                129                 :                :  * CurrentSnapshot points to the only snapshot taken in transaction-snapshot
                                130                 :                :  * mode, and to the latest one taken in a read-committed transaction.
                                131                 :                :  * SecondarySnapshot is a snapshot that's always up-to-date as of the current
                                132                 :                :  * instant, even in transaction-snapshot mode.  It should only be used for
                                133                 :                :  * special-purpose code (say, RI checking.)  CatalogSnapshot points to an
                                134                 :                :  * MVCC snapshot intended to be used for catalog scans; we must invalidate it
                                135                 :                :  * whenever a system catalog change occurs.
                                136                 :                :  *
                                137                 :                :  * These SnapshotData structs are static to simplify memory allocation
                                138                 :                :  * (see the hack in GetSnapshotData to avoid repeated malloc/free).
                                139                 :                :  */
                                140                 :                : static SnapshotData CurrentSnapshotData = {SNAPSHOT_MVCC};
                                141                 :                : static SnapshotData SecondarySnapshotData = {SNAPSHOT_MVCC};
                                142                 :                : static SnapshotData CatalogSnapshotData = {SNAPSHOT_MVCC};
                                143                 :                : SnapshotData SnapshotSelfData = {SNAPSHOT_SELF};
                                144                 :                : SnapshotData SnapshotAnyData = {SNAPSHOT_ANY};
                                145                 :                : SnapshotData SnapshotToastData = {SNAPSHOT_TOAST};
                                146                 :                : 
                                147                 :                : /* Pointers to valid snapshots */
                                148                 :                : static Snapshot CurrentSnapshot = NULL;
                                149                 :                : static Snapshot SecondarySnapshot = NULL;
                                150                 :                : static Snapshot CatalogSnapshot = NULL;
                                151                 :                : static Snapshot HistoricSnapshot = NULL;
                                152                 :                : 
                                153                 :                : /*
                                154                 :                :  * These are updated by GetSnapshotData.  We initialize them this way
                                155                 :                :  * for the convenience of TransactionIdIsInProgress: even in bootstrap
                                156                 :                :  * mode, we don't want it to say that BootstrapTransactionId is in progress.
                                157                 :                :  */
                                158                 :                : TransactionId TransactionXmin = FirstNormalTransactionId;
                                159                 :                : TransactionId RecentXmin = FirstNormalTransactionId;
                                160                 :                : 
                                161                 :                : /* (table, ctid) => (cmin, cmax) mapping during timetravel */
                                162                 :                : static HTAB *tuplecid_data = NULL;
                                163                 :                : 
                                164                 :                : /*
                                165                 :                :  * Elements of the active snapshot stack.
                                166                 :                :  *
                                167                 :                :  * Each element here accounts for exactly one active_count on SnapshotData.
                                168                 :                :  *
                                169                 :                :  * NB: the code assumes that elements in this list are in non-increasing
                                170                 :                :  * order of as_level; also, the list must be NULL-terminated.
                                171                 :                :  */
                                172                 :                : typedef struct ActiveSnapshotElt
                                173                 :                : {
                                174                 :                :     Snapshot    as_snap;
                                175                 :                :     int         as_level;
                                176                 :                :     struct ActiveSnapshotElt *as_next;
                                177                 :                : } ActiveSnapshotElt;
                                178                 :                : 
                                179                 :                : /* Top of the stack of active snapshots */
                                180                 :                : static ActiveSnapshotElt *ActiveSnapshot = NULL;
                                181                 :                : 
                                182                 :                : /*
                                183                 :                :  * Currently registered Snapshots.  Ordered in a heap by xmin, so that we can
                                184                 :                :  * quickly find the one with lowest xmin, to advance our MyProc->xmin.
                                185                 :                :  */
                                186                 :                : static int  xmin_cmp(const pairingheap_node *a, const pairingheap_node *b,
                                187                 :                :                      void *arg);
                                188                 :                : 
                                189                 :                : static pairingheap RegisteredSnapshots = {&xmin_cmp, NULL, NULL};
                                190                 :                : 
                                191                 :                : /* first GetTransactionSnapshot call in a transaction? */
                                192                 :                : bool        FirstSnapshotSet = false;
                                193                 :                : 
                                194                 :                : /*
                                195                 :                :  * Remember the serializable transaction snapshot, if any.  We cannot trust
                                196                 :                :  * FirstSnapshotSet in combination with IsolationUsesXactSnapshot(), because
                                197                 :                :  * GUC may be reset before us, changing the value of IsolationUsesXactSnapshot.
                                198                 :                :  */
                                199                 :                : static Snapshot FirstXactSnapshot = NULL;
                                200                 :                : 
                                201                 :                : /* Define pathname of exported-snapshot files */
                                202                 :                : #define SNAPSHOT_EXPORT_DIR "pg_snapshots"
                                203                 :                : 
                                204                 :                : /* Structure holding info about exported snapshot. */
                                205                 :                : typedef struct ExportedSnapshot
                                206                 :                : {
                                207                 :                :     char       *snapfile;
                                208                 :                :     Snapshot    snapshot;
                                209                 :                : } ExportedSnapshot;
                                210                 :                : 
                                211                 :                : /* Current xact's exported snapshots (a list of ExportedSnapshot structs) */
                                212                 :                : static List *exportedSnapshots = NIL;
                                213                 :                : 
                                214                 :                : /* Prototypes for local functions */
                                215                 :                : static Snapshot CopySnapshot(Snapshot snapshot);
                                216                 :                : static void UnregisterSnapshotNoOwner(Snapshot snapshot);
                                217                 :                : static void FreeSnapshot(Snapshot snapshot);
                                218                 :                : static void SnapshotResetXmin(void);
                                219                 :                : 
                                220                 :                : /* ResourceOwner callbacks to track snapshot references */
                                221                 :                : static void ResOwnerReleaseSnapshot(Datum res);
                                222                 :                : 
                                223                 :                : static const ResourceOwnerDesc snapshot_resowner_desc =
                                224                 :                : {
                                225                 :                :     .name = "snapshot reference",
                                226                 :                :     .release_phase = RESOURCE_RELEASE_AFTER_LOCKS,
                                227                 :                :     .release_priority = RELEASE_PRIO_SNAPSHOT_REFS,
                                228                 :                :     .ReleaseResource = ResOwnerReleaseSnapshot,
                                229                 :                :     .DebugPrint = NULL          /* the default message is fine */
                                230                 :                : };
                                231                 :                : 
                                232                 :                : /* Convenience wrappers over ResourceOwnerRemember/Forget */
                                233                 :                : static inline void
  668 heikki.linnakangas@i      234                 :CBC     6870380 : ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snap)
                                235                 :                : {
                                236                 :        6870380 :     ResourceOwnerRemember(owner, PointerGetDatum(snap), &snapshot_resowner_desc);
                                237                 :        6870380 : }
                                238                 :                : static inline void
                                239                 :        6840784 : ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snap)
                                240                 :                : {
                                241                 :        6840784 :     ResourceOwnerForget(owner, PointerGetDatum(snap), &snapshot_resowner_desc);
                                242                 :        6840784 : }
                                243                 :                : 
                                244                 :                : /*
                                245                 :                :  * Snapshot fields to be serialized.
                                246                 :                :  *
                                247                 :                :  * Only these fields need to be sent to the cooperating backend; the
                                248                 :                :  * remaining ones can (and must) be set by the receiver upon restore.
                                249                 :                :  */
                                250                 :                : typedef struct SerializedSnapshotData
                                251                 :                : {
                                252                 :                :     TransactionId xmin;
                                253                 :                :     TransactionId xmax;
                                254                 :                :     uint32      xcnt;
                                255                 :                :     int32       subxcnt;
                                256                 :                :     bool        suboverflowed;
                                257                 :                :     bool        takenDuringRecovery;
                                258                 :                :     CommandId   curcid;
                                259                 :                : } SerializedSnapshotData;
                                260                 :                : 
                                261                 :                : /*
                                262                 :                :  * GetTransactionSnapshot
                                263                 :                :  *      Get the appropriate snapshot for a new query in a transaction.
                                264                 :                :  *
                                265                 :                :  * Note that the return value points at static storage that will be modified
                                266                 :                :  * by future calls and by CommandCounterIncrement().  Callers must call
                                267                 :                :  * RegisterSnapshot or PushActiveSnapshot on the returned snap before doing
                                268                 :                :  * any other non-trivial work that could invalidate it.
                                269                 :                :  */
                                270                 :                : Snapshot
 6373 alvherre@alvh.no-ip.      271                 :         841153 : GetTransactionSnapshot(void)
                                272                 :                : {
                                273                 :                :     /*
                                274                 :                :      * Return historic snapshot if doing logical decoding.
                                275                 :                :      *
                                276                 :                :      * Historic snapshots are only usable for catalog access, not for
                                277                 :                :      * general-purpose queries.  The caller is responsible for ensuring that
                                278                 :                :      * the snapshot is used correctly! (PostgreSQL code never calls this
                                279                 :                :      * during logical decoding, but extensions can do it.)
                                280                 :                :      */
 4205 rhaas@postgresql.org      281         [ -  + ]:         841153 :     if (HistoricSnapshotActive())
                                282                 :                :     {
                                283                 :                :         /*
                                284                 :                :          * We'll never need a non-historic transaction snapshot in this
                                285                 :                :          * (sub-)transaction, so there's no need to be careful to set one up
                                286                 :                :          * for later calls to GetTransactionSnapshot().
                                287                 :                :          */
   15 heikki.linnakangas@i      288         [ #  # ]:UBC           0 :         Assert(!FirstSnapshotSet);
                                289                 :              0 :         return HistoricSnapshot;
                                290                 :                :     }
                                291                 :                : 
                                292                 :                :     /* First call in transaction? */
 6326 alvherre@alvh.no-ip.      293         [ +  + ]:CBC      841153 :     if (!FirstSnapshotSet)
                                294                 :                :     {
                                295                 :                :         /*
                                296                 :                :          * Don't allow catalog snapshot to be older than xact snapshot.  Must
                                297                 :                :          * do this first to allow the empty-heap Assert to succeed.
                                298                 :                :          */
 3217 tgl@sss.pgh.pa.us         299                 :         272827 :         InvalidateCatalogSnapshot();
                                300                 :                : 
 3885 heikki.linnakangas@i      301         [ -  + ]:         272827 :         Assert(pairingheap_is_empty(&RegisteredSnapshots));
 5094 tgl@sss.pgh.pa.us         302         [ -  + ]:         272827 :         Assert(FirstXactSnapshot == NULL);
                                303                 :                : 
 3782 rhaas@postgresql.org      304         [ -  + ]:         272827 :         if (IsInParallelMode())
 3782 rhaas@postgresql.org      305         [ #  # ]:UBC           0 :             elog(ERROR,
                                306                 :                :                  "cannot take query snapshot during a parallel operation");
                                307                 :                : 
                                308                 :                :         /*
                                309                 :                :          * In transaction-snapshot mode, the first snapshot must live until
                                310                 :                :          * end of xact regardless of what the caller does with it, so we must
                                311                 :                :          * make a copy of it rather than returning CurrentSnapshotData
                                312                 :                :          * directly.  Furthermore, if we're running in serializable mode,
                                313                 :                :          * predicate.c needs to wrap the snapshot fetch in its own processing.
                                314                 :                :          */
 5474 mail@joeconway.com        315         [ +  + ]:CBC      272827 :         if (IsolationUsesXactSnapshot())
                                316                 :                :         {
                                317                 :                :             /* First, create the snapshot in CurrentSnapshotData */
 5325 heikki.linnakangas@i      318         [ +  + ]:           2730 :             if (IsolationIsSerializable())
 5094 tgl@sss.pgh.pa.us         319                 :           1640 :                 CurrentSnapshot = GetSerializableTransactionSnapshot(&CurrentSnapshotData);
                                320                 :                :             else
 5325 heikki.linnakangas@i      321                 :           1090 :                 CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
                                322                 :                :             /* Make a saved copy */
 5094 tgl@sss.pgh.pa.us         323                 :           2730 :             CurrentSnapshot = CopySnapshot(CurrentSnapshot);
                                324                 :           2730 :             FirstXactSnapshot = CurrentSnapshot;
                                325                 :                :             /* Mark it as "registered" in FirstXactSnapshot */
                                326                 :           2730 :             FirstXactSnapshot->regd_count++;
 3885 heikki.linnakangas@i      327                 :           2730 :             pairingheap_add(&RegisteredSnapshots, &FirstXactSnapshot->ph_node);
                                328                 :                :         }
                                329                 :                :         else
 5325                           330                 :         270097 :             CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
                                331                 :                : 
                                332                 :         272827 :         FirstSnapshotSet = true;
 6326 alvherre@alvh.no-ip.      333                 :         272827 :         return CurrentSnapshot;
                                334                 :                :     }
                                335                 :                : 
 5474 mail@joeconway.com        336         [ +  + ]:         568326 :     if (IsolationUsesXactSnapshot())
 6326 alvherre@alvh.no-ip.      337                 :          74865 :         return CurrentSnapshot;
                                338                 :                : 
                                339                 :                :     /* Don't allow catalog snapshot to be older than xact snapshot. */
 3217 tgl@sss.pgh.pa.us         340                 :         493461 :     InvalidateCatalogSnapshot();
                                341                 :                : 
 6326 alvherre@alvh.no-ip.      342                 :         493461 :     CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
                                343                 :                : 
                                344                 :         493461 :     return CurrentSnapshot;
                                345                 :                : }
                                346                 :                : 
                                347                 :                : /*
                                348                 :                :  * GetLatestSnapshot
                                349                 :                :  *      Get a snapshot that is up-to-date as of the current instant,
                                350                 :                :  *      even if we are executing in transaction-snapshot mode.
                                351                 :                :  */
                                352                 :                : Snapshot
 6373                           353                 :          76274 : GetLatestSnapshot(void)
                                354                 :                : {
                                355                 :                :     /*
                                356                 :                :      * We might be able to relax this, but nothing that could otherwise work
                                357                 :                :      * needs it.
                                358                 :                :      */
 3782 rhaas@postgresql.org      359         [ -  + ]:          76274 :     if (IsInParallelMode())
 3782 rhaas@postgresql.org      360         [ #  # ]:UBC           0 :         elog(ERROR,
                                361                 :                :              "cannot update SecondarySnapshot during a parallel operation");
                                362                 :                : 
                                363                 :                :     /*
                                364                 :                :      * So far there are no cases requiring support for GetLatestSnapshot()
                                365                 :                :      * during logical decoding, but it wouldn't be hard to add if required.
                                366                 :                :      */
 4205 rhaas@postgresql.org      367         [ -  + ]:CBC       76274 :     Assert(!HistoricSnapshotActive());
                                368                 :                : 
                                369                 :                :     /* If first call in transaction, go ahead and set the xact snapshot */
 6326 alvherre@alvh.no-ip.      370         [ +  + ]:          76274 :     if (!FirstSnapshotSet)
 4815 tgl@sss.pgh.pa.us         371                 :             50 :         return GetTransactionSnapshot();
                                372                 :                : 
 6326 alvherre@alvh.no-ip.      373                 :          76224 :     SecondarySnapshot = GetSnapshotData(&SecondarySnapshotData);
                                374                 :                : 
                                375                 :          76224 :     return SecondarySnapshot;
                                376                 :                : }
                                377                 :                : 
                                378                 :                : /*
                                379                 :                :  * GetCatalogSnapshot
                                380                 :                :  *      Get a snapshot that is sufficiently up-to-date for scan of the
                                381                 :                :  *      system catalog with the specified OID.
                                382                 :                :  */
                                383                 :                : Snapshot
 4449 rhaas@postgresql.org      384                 :        6248032 : GetCatalogSnapshot(Oid relid)
                                385                 :                : {
                                386                 :                :     /*
                                387                 :                :      * Return historic snapshot while we're doing logical decoding, so we can
                                388                 :                :      * see the appropriate state of the catalog.
                                389                 :                :      *
                                390                 :                :      * This is the primary reason for needing to reset the system caches after
                                391                 :                :      * finishing decoding.
                                392                 :                :      */
 4205                           393         [ +  + ]:        6248032 :     if (HistoricSnapshotActive())
                                394                 :          15614 :         return HistoricSnapshot;
                                395                 :                : 
                                396                 :        6232418 :     return GetNonHistoricCatalogSnapshot(relid);
                                397                 :                : }
                                398                 :                : 
                                399                 :                : /*
                                400                 :                :  * GetNonHistoricCatalogSnapshot
                                401                 :                :  *      Get a snapshot that is sufficiently up-to-date for scan of the system
                                402                 :                :  *      catalog with the specified OID, even while historic snapshots are set
                                403                 :                :  *      up.
                                404                 :                :  */
                                405                 :                : Snapshot
                                406                 :        6234018 : GetNonHistoricCatalogSnapshot(Oid relid)
                                407                 :                : {
                                408                 :                :     /*
                                409                 :                :      * If the caller is trying to scan a relation that has no syscache, no
                                410                 :                :      * catcache invalidations will be sent when it is updated.  For a few key
                                411                 :                :      * relations, snapshot invalidations are sent instead.  If we're trying to
                                412                 :                :      * scan a relation for which neither catcache nor snapshot invalidations
                                413                 :                :      * are sent, we must refresh the snapshot every time.
                                414                 :                :      */
 3217 tgl@sss.pgh.pa.us         415         [ +  + ]:        6234018 :     if (CatalogSnapshot &&
                                416         [ +  + ]:        5507175 :         !RelationInvalidatesSnapshotsOnly(relid) &&
 4449 rhaas@postgresql.org      417         [ +  + ]:        4770118 :         !RelationHasSysCache(relid))
 3217 tgl@sss.pgh.pa.us         418                 :         230071 :         InvalidateCatalogSnapshot();
                                419                 :                : 
                                420         [ +  + ]:        6234018 :     if (CatalogSnapshot == NULL)
                                421                 :                :     {
                                422                 :                :         /* Get new snapshot. */
 4449 rhaas@postgresql.org      423                 :         956914 :         CatalogSnapshot = GetSnapshotData(&CatalogSnapshotData);
                                424                 :                : 
                                425                 :                :         /*
                                426                 :                :          * Make sure the catalog snapshot will be accounted for in decisions
                                427                 :                :          * about advancing PGPROC->xmin.  We could apply RegisterSnapshot, but
                                428                 :                :          * that would result in making a physical copy, which is overkill; and
                                429                 :                :          * it would also create a dependency on some resource owner, which we
                                430                 :                :          * do not want for reasons explained at the head of this file. Instead
                                431                 :                :          * just shove the CatalogSnapshot into the pairing heap manually. This
                                432                 :                :          * has to be reversed in InvalidateCatalogSnapshot, of course.
                                433                 :                :          *
                                434                 :                :          * NB: it had better be impossible for this to throw error, since the
                                435                 :                :          * CatalogSnapshot pointer is already valid.
                                436                 :                :          */
 3217 tgl@sss.pgh.pa.us         437                 :         956914 :         pairingheap_add(&RegisteredSnapshots, &CatalogSnapshot->ph_node);
                                438                 :                :     }
                                439                 :                : 
 4449 rhaas@postgresql.org      440                 :        6234018 :     return CatalogSnapshot;
                                441                 :                : }
                                442                 :                : 
                                443                 :                : /*
                                444                 :                :  * InvalidateCatalogSnapshot
                                445                 :                :  *      Mark the current catalog snapshot, if any, as invalid
                                446                 :                :  *
                                447                 :                :  * We could change this API to allow the caller to provide more fine-grained
                                448                 :                :  * invalidation details, so that a change to relation A wouldn't prevent us
                                449                 :                :  * from using our cached snapshot to scan relation B, but so far there's no
                                450                 :                :  * evidence that the CPU cycles we spent tracking such fine details would be
                                451                 :                :  * well-spent.
                                452                 :                :  */
                                453                 :                : void
 3675 andres@anarazel.de        454                 :       13891541 : InvalidateCatalogSnapshot(void)
                                455                 :                : {
 3217 tgl@sss.pgh.pa.us         456         [ +  + ]:       13891541 :     if (CatalogSnapshot)
                                457                 :                :     {
                                458                 :         956914 :         pairingheap_remove(&RegisteredSnapshots, &CatalogSnapshot->ph_node);
                                459                 :         956914 :         CatalogSnapshot = NULL;
                                460                 :         956914 :         SnapshotResetXmin();
                                461                 :                :     }
                                462                 :       13891541 : }
                                463                 :                : 
                                464                 :                : /*
                                465                 :                :  * InvalidateCatalogSnapshotConditionally
                                466                 :                :  *      Drop catalog snapshot if it's the only one we have
                                467                 :                :  *
                                468                 :                :  * This is called when we are about to wait for client input, so we don't
                                469                 :                :  * want to continue holding the catalog snapshot if it might mean that the
                                470                 :                :  * global xmin horizon can't advance.  However, if there are other snapshots
                                471                 :                :  * still active or registered, the catalog snapshot isn't likely to be the
                                472                 :                :  * oldest one, so we might as well keep it.
                                473                 :                :  */
                                474                 :                : void
                                475                 :         387995 : InvalidateCatalogSnapshotConditionally(void)
                                476                 :                : {
                                477         [ +  + ]:         387995 :     if (CatalogSnapshot &&
                                478         [ +  + ]:          55978 :         ActiveSnapshot == NULL &&
                                479   [ +  -  +  + ]:          55141 :         pairingheap_is_singular(&RegisteredSnapshots))
                                480                 :           9045 :         InvalidateCatalogSnapshot();
 4449 rhaas@postgresql.org      481                 :         387995 : }
                                482                 :                : 
                                483                 :                : /*
                                484                 :                :  * SnapshotSetCommandId
                                485                 :                :  *      Propagate CommandCounterIncrement into the static snapshots, if set
                                486                 :                :  */
                                487                 :                : void
 6326 alvherre@alvh.no-ip.      488                 :         596116 : SnapshotSetCommandId(CommandId curcid)
                                489                 :                : {
                                490         [ +  + ]:         596116 :     if (!FirstSnapshotSet)
                                491                 :          10083 :         return;
                                492                 :                : 
                                493         [ +  - ]:         586033 :     if (CurrentSnapshot)
                                494                 :         586033 :         CurrentSnapshot->curcid = curcid;
                                495         [ +  + ]:         586033 :     if (SecondarySnapshot)
                                496                 :          79198 :         SecondarySnapshot->curcid = curcid;
                                497                 :                :     /* Should we do the same with CatalogSnapshot? */
                                498                 :                : }
                                499                 :                : 
                                500                 :                : /*
                                501                 :                :  * SetTransactionSnapshot
                                502                 :                :  *      Set the transaction's snapshot from an imported MVCC snapshot.
                                503                 :                :  *
                                504                 :                :  * Note that this is very closely tied to GetTransactionSnapshot --- it
                                505                 :                :  * must take care of all the same considerations as the first-snapshot case
                                506                 :                :  * in GetTransactionSnapshot.
                                507                 :                :  */
                                508                 :                : static void
 3006 andres@anarazel.de        509                 :           1590 : SetTransactionSnapshot(Snapshot sourcesnap, VirtualTransactionId *sourcevxid,
                                510                 :                :                        int sourcepid, PGPROC *sourceproc)
                                511                 :                : {
                                512                 :                :     /* Caller should have checked this already */
 5068 tgl@sss.pgh.pa.us         513         [ -  + ]:           1590 :     Assert(!FirstSnapshotSet);
                                514                 :                : 
                                515                 :                :     /* Better do this to ensure following Assert succeeds. */
 3217                           516                 :           1590 :     InvalidateCatalogSnapshot();
                                517                 :                : 
 3885 heikki.linnakangas@i      518         [ -  + ]:           1590 :     Assert(pairingheap_is_empty(&RegisteredSnapshots));
 5068 tgl@sss.pgh.pa.us         519         [ -  + ]:           1590 :     Assert(FirstXactSnapshot == NULL);
 4196 rhaas@postgresql.org      520         [ -  + ]:           1590 :     Assert(!HistoricSnapshotActive());
                                521                 :                : 
                                522                 :                :     /*
                                523                 :                :      * Even though we are not going to use the snapshot it computes, we must
                                524                 :                :      * call GetSnapshotData, for two reasons: (1) to be sure that
                                525                 :                :      * CurrentSnapshotData's XID arrays have been allocated, and (2) to update
                                526                 :                :      * the state for GlobalVis*.
                                527                 :                :      */
 5068 tgl@sss.pgh.pa.us         528                 :           1590 :     CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
                                529                 :                : 
                                530                 :                :     /*
                                531                 :                :      * Now copy appropriate fields from the source snapshot.
                                532                 :                :      */
                                533                 :           1590 :     CurrentSnapshot->xmin = sourcesnap->xmin;
                                534                 :           1590 :     CurrentSnapshot->xmax = sourcesnap->xmax;
                                535                 :           1590 :     CurrentSnapshot->xcnt = sourcesnap->xcnt;
                                536         [ -  + ]:           1590 :     Assert(sourcesnap->xcnt <= GetMaxSnapshotXidCount());
 1283                           537         [ +  + ]:           1590 :     if (sourcesnap->xcnt > 0)
                                538                 :            350 :         memcpy(CurrentSnapshot->xip, sourcesnap->xip,
                                539                 :            350 :                sourcesnap->xcnt * sizeof(TransactionId));
 5068                           540                 :           1590 :     CurrentSnapshot->subxcnt = sourcesnap->subxcnt;
                                541         [ -  + ]:           1590 :     Assert(sourcesnap->subxcnt <= GetMaxSnapshotSubxidCount());
 1283                           542         [ -  + ]:           1590 :     if (sourcesnap->subxcnt > 0)
 1283 tgl@sss.pgh.pa.us         543                 :UBC           0 :         memcpy(CurrentSnapshot->subxip, sourcesnap->subxip,
                                544                 :              0 :                sourcesnap->subxcnt * sizeof(TransactionId));
 5068 tgl@sss.pgh.pa.us         545                 :CBC        1590 :     CurrentSnapshot->suboverflowed = sourcesnap->suboverflowed;
                                546                 :           1590 :     CurrentSnapshot->takenDuringRecovery = sourcesnap->takenDuringRecovery;
                                547                 :                :     /* NB: curcid should NOT be copied, it's a local matter */
                                548                 :                : 
 1846 andres@anarazel.de        549                 :           1590 :     CurrentSnapshot->snapXactCompletionCount = 0;
                                550                 :                : 
                                551                 :                :     /*
                                552                 :                :      * Now we have to fix what GetSnapshotData did with MyProc->xmin and
                                553                 :                :      * TransactionXmin.  There is a race condition: to make sure we are not
                                554                 :                :      * causing the global xmin to go backwards, we have to test that the
                                555                 :                :      * source transaction is still running, and that has to be done
                                556                 :                :      * atomically. So let procarray.c do it.
                                557                 :                :      *
                                558                 :                :      * Note: in serializable mode, predicate.c will do this a second time. It
                                559                 :                :      * doesn't seem worth contorting the logic here to avoid two calls,
                                560                 :                :      * especially since it's not clear that predicate.c *must* do this.
                                561                 :                :      */
 3782 rhaas@postgresql.org      562         [ +  + ]:           1590 :     if (sourceproc != NULL)
                                563                 :                :     {
                                564         [ -  + ]:           1572 :         if (!ProcArrayInstallRestoredXmin(CurrentSnapshot->xmin, sourceproc))
 3782 rhaas@postgresql.org      565         [ #  # ]:UBC           0 :             ereport(ERROR,
                                566                 :                :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                                567                 :                :                      errmsg("could not import the requested snapshot"),
                                568                 :                :                      errdetail("The source transaction is not running anymore.")));
                                569                 :                :     }
 3006 andres@anarazel.de        570         [ -  + ]:CBC          18 :     else if (!ProcArrayInstallImportedXmin(CurrentSnapshot->xmin, sourcevxid))
 5068 tgl@sss.pgh.pa.us         571         [ #  # ]:UBC           0 :         ereport(ERROR,
                                572                 :                :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                                573                 :                :                  errmsg("could not import the requested snapshot"),
                                574                 :                :                  errdetail("The source process with PID %d is not running anymore.",
                                575                 :                :                            sourcepid)));
                                576                 :                : 
                                577                 :                :     /*
                                578                 :                :      * In transaction-snapshot mode, the first snapshot must live until end of
                                579                 :                :      * xact, so we must make a copy of it.  Furthermore, if we're running in
                                580                 :                :      * serializable mode, predicate.c needs to do its own processing.
                                581                 :                :      */
 5068 tgl@sss.pgh.pa.us         582         [ +  + ]:CBC        1590 :     if (IsolationUsesXactSnapshot())
                                583                 :                :     {
                                584         [ +  + ]:            232 :         if (IsolationIsSerializable())
 3006 andres@anarazel.de        585                 :             13 :             SetSerializableTransactionSnapshot(CurrentSnapshot, sourcevxid,
                                586                 :                :                                                sourcepid);
                                587                 :                :         /* Make a saved copy */
 5068 tgl@sss.pgh.pa.us         588                 :            232 :         CurrentSnapshot = CopySnapshot(CurrentSnapshot);
                                589                 :            232 :         FirstXactSnapshot = CurrentSnapshot;
                                590                 :                :         /* Mark it as "registered" in FirstXactSnapshot */
                                591                 :            232 :         FirstXactSnapshot->regd_count++;
 3885 heikki.linnakangas@i      592                 :            232 :         pairingheap_add(&RegisteredSnapshots, &FirstXactSnapshot->ph_node);
                                593                 :                :     }
                                594                 :                : 
 5068 tgl@sss.pgh.pa.us         595                 :           1590 :     FirstSnapshotSet = true;
                                596                 :           1590 : }
                                597                 :                : 
                                598                 :                : /*
                                599                 :                :  * CopySnapshot
                                600                 :                :  *      Copy the given snapshot.
                                601                 :                :  *
                                602                 :                :  * The copy is palloc'd in TopTransactionContext and has initial refcounts set
                                603                 :                :  * to 0.  The returned snapshot has the copied flag set.
                                604                 :                :  */
                                605                 :                : static Snapshot
 6373 alvherre@alvh.no-ip.      606                 :        7169214 : CopySnapshot(Snapshot snapshot)
                                607                 :                : {
                                608                 :                :     Snapshot    newsnap;
                                609                 :                :     Size        subxipoff;
                                610                 :                :     Size        size;
                                611                 :                : 
 6326                           612         [ -  + ]:        7169214 :     Assert(snapshot != InvalidSnapshot);
                                613                 :                : 
                                614                 :                :     /* We allocate any XID arrays needed in the same palloc block. */
 6373                           615                 :        7169214 :     size = subxipoff = sizeof(SnapshotData) +
                                616                 :        7169214 :         snapshot->xcnt * sizeof(TransactionId);
                                617         [ +  + ]:        7169214 :     if (snapshot->subxcnt > 0)
                                618                 :          67402 :         size += snapshot->subxcnt * sizeof(TransactionId);
                                619                 :                : 
 6326                           620                 :        7169214 :     newsnap = (Snapshot) MemoryContextAlloc(TopTransactionContext, size);
 6373                           621                 :        7169214 :     memcpy(newsnap, snapshot, sizeof(SnapshotData));
                                622                 :                : 
 6326                           623                 :        7169214 :     newsnap->regd_count = 0;
                                624                 :        7169214 :     newsnap->active_count = 0;
                                625                 :        7169214 :     newsnap->copied = true;
 1846 andres@anarazel.de        626                 :        7169214 :     newsnap->snapXactCompletionCount = 0;
                                627                 :                : 
                                628                 :                :     /* setup XID array */
 6373 alvherre@alvh.no-ip.      629         [ +  + ]:        7169214 :     if (snapshot->xcnt > 0)
                                630                 :                :     {
                                631                 :        1566229 :         newsnap->xip = (TransactionId *) (newsnap + 1);
                                632                 :        1566229 :         memcpy(newsnap->xip, snapshot->xip,
                                633                 :        1566229 :                snapshot->xcnt * sizeof(TransactionId));
                                634                 :                :     }
                                635                 :                :     else
                                636                 :        5602985 :         newsnap->xip = NULL;
                                637                 :                : 
                                638                 :                :     /*
                                639                 :                :      * Setup subXID array. Don't bother to copy it if it had overflowed,
                                640                 :                :      * though, because it's not used anywhere in that case. Except if it's a
                                641                 :                :      * snapshot taken during recovery; all the top-level XIDs are in subxip as
                                642                 :                :      * well in that case, so we mustn't lose them.
                                643                 :                :      */
 5740 simon@2ndQuadrant.co      644         [ +  + ]:        7169214 :     if (snapshot->subxcnt > 0 &&
                                645   [ +  +  +  + ]:          67402 :         (!snapshot->suboverflowed || snapshot->takenDuringRecovery))
                                646                 :                :     {
 6373 alvherre@alvh.no-ip.      647                 :          67389 :         newsnap->subxip = (TransactionId *) ((char *) newsnap + subxipoff);
                                648                 :          67389 :         memcpy(newsnap->subxip, snapshot->subxip,
                                649                 :          67389 :                snapshot->subxcnt * sizeof(TransactionId));
                                650                 :                :     }
                                651                 :                :     else
                                652                 :        7101825 :         newsnap->subxip = NULL;
                                653                 :                : 
                                654                 :        7169214 :     return newsnap;
                                655                 :                : }
                                656                 :                : 
                                657                 :                : /*
                                658                 :                :  * FreeSnapshot
                                659                 :                :  *      Free the memory associated with a snapshot.
                                660                 :                :  */
                                661                 :                : static void
 6326                           662                 :        7145001 : FreeSnapshot(Snapshot snapshot)
                                663                 :                : {
                                664         [ -  + ]:        7145001 :     Assert(snapshot->regd_count == 0);
                                665         [ -  + ]:        7145001 :     Assert(snapshot->active_count == 0);
 6266                           666         [ -  + ]:        7145001 :     Assert(snapshot->copied);
                                667                 :                : 
 6326                           668                 :        7145001 :     pfree(snapshot);
                                669                 :        7145001 : }
                                670                 :                : 
                                671                 :                : /*
                                672                 :                :  * PushActiveSnapshot
                                673                 :                :  *      Set the given snapshot as the current active snapshot
                                674                 :                :  *
                                675                 :                :  * If the passed snapshot is a statically-allocated one, or it is possibly
                                676                 :                :  * subject to a future command counter update, create a new long-lived copy
                                677                 :                :  * with active refcount=1.  Otherwise, only increment the refcount.
                                678                 :                :  */
                                679                 :                : void
 1082 pg@bowt.ie                680                 :         922207 : PushActiveSnapshot(Snapshot snapshot)
                                681                 :                : {
                                682                 :         922207 :     PushActiveSnapshotWithLevel(snapshot, GetCurrentTransactionNestLevel());
 1436 tgl@sss.pgh.pa.us         683                 :         922207 : }
                                684                 :                : 
                                685                 :                : /*
                                686                 :                :  * PushActiveSnapshotWithLevel
                                687                 :                :  *      Set the given snapshot as the current active snapshot
                                688                 :                :  *
                                689                 :                :  * Same as PushActiveSnapshot except that caller can specify the
                                690                 :                :  * transaction nesting level that "owns" the snapshot.  This level
                                691                 :                :  * must not be deeper than the current top of the snapshot stack.
                                692                 :                :  */
                                693                 :                : void
 1082 pg@bowt.ie                694                 :        1068330 : PushActiveSnapshotWithLevel(Snapshot snapshot, int snap_level)
                                695                 :                : {
                                696                 :                :     ActiveSnapshotElt *newactive;
                                697                 :                : 
                                698         [ -  + ]:        1068330 :     Assert(snapshot != InvalidSnapshot);
 1436 tgl@sss.pgh.pa.us         699   [ +  +  -  + ]:        1068330 :     Assert(ActiveSnapshot == NULL || snap_level >= ActiveSnapshot->as_level);
                                700                 :                : 
 6326 alvherre@alvh.no-ip.      701                 :        1068330 :     newactive = MemoryContextAlloc(TopTransactionContext, sizeof(ActiveSnapshotElt));
                                702                 :                : 
                                703                 :                :     /*
                                704                 :                :      * Checking SecondarySnapshot is probably useless here, but it seems
                                705                 :                :      * better to be sure.
                                706                 :                :      */
 1082 pg@bowt.ie                707   [ +  +  +  + ]:        1068330 :     if (snapshot == CurrentSnapshot || snapshot == SecondarySnapshot ||
                                708         [ -  + ]:         231979 :         !snapshot->copied)
                                709                 :         836351 :         newactive->as_snap = CopySnapshot(snapshot);
                                710                 :                :     else
                                711                 :         231979 :         newactive->as_snap = snapshot;
                                712                 :                : 
 6326 alvherre@alvh.no-ip.      713                 :        1068330 :     newactive->as_next = ActiveSnapshot;
 1436 tgl@sss.pgh.pa.us         714                 :        1068330 :     newactive->as_level = snap_level;
                                715                 :                : 
 6326 alvherre@alvh.no-ip.      716                 :        1068330 :     newactive->as_snap->active_count++;
                                717                 :                : 
                                718                 :        1068330 :     ActiveSnapshot = newactive;
                                719                 :        1068330 : }
                                720                 :                : 
                                721                 :                : /*
                                722                 :                :  * PushCopiedSnapshot
                                723                 :                :  *      As above, except forcibly copy the presented snapshot.
                                724                 :                :  *
                                725                 :                :  * This should be used when the ActiveSnapshot has to be modifiable, for
                                726                 :                :  * example if the caller intends to call UpdateActiveSnapshotCommandId.
                                727                 :                :  * The new snapshot will be released when popped from the stack.
                                728                 :                :  */
                                729                 :                : void
 5304 tgl@sss.pgh.pa.us         730                 :          57131 : PushCopiedSnapshot(Snapshot snapshot)
                                731                 :                : {
                                732                 :          57131 :     PushActiveSnapshot(CopySnapshot(snapshot));
                                733                 :          57131 : }
                                734                 :                : 
                                735                 :                : /*
                                736                 :                :  * UpdateActiveSnapshotCommandId
                                737                 :                :  *
                                738                 :                :  * Update the current CID of the active snapshot.  This can only be applied
                                739                 :                :  * to a snapshot that is not referenced elsewhere.
                                740                 :                :  */
                                741                 :                : void
                                742                 :          55748 : UpdateActiveSnapshotCommandId(void)
                                743                 :                : {
                                744                 :                :     CommandId   save_curcid,
                                745                 :                :                 curcid;
                                746                 :                : 
                                747         [ -  + ]:          55748 :     Assert(ActiveSnapshot != NULL);
                                748         [ -  + ]:          55748 :     Assert(ActiveSnapshot->as_snap->active_count == 1);
                                749         [ -  + ]:          55748 :     Assert(ActiveSnapshot->as_snap->regd_count == 0);
                                750                 :                : 
                                751                 :                :     /*
                                752                 :                :      * Don't allow modification of the active snapshot during parallel
                                753                 :                :      * operation.  We share the snapshot to worker backends at the beginning
                                754                 :                :      * of parallel operation, so any change to the snapshot can lead to
                                755                 :                :      * inconsistencies.  We have other defenses against
                                756                 :                :      * CommandCounterIncrement, but there are a few places that call this
                                757                 :                :      * directly, so we put an additional guard here.
                                758                 :                :      */
 3782 rhaas@postgresql.org      759                 :          55748 :     save_curcid = ActiveSnapshot->as_snap->curcid;
                                760                 :          55748 :     curcid = GetCurrentCommandId(false);
                                761   [ +  +  -  + ]:          55748 :     if (IsInParallelMode() && save_curcid != curcid)
 3782 rhaas@postgresql.org      762         [ #  # ]:UBC           0 :         elog(ERROR, "cannot modify commandid in active snapshot during a parallel operation");
 3782 rhaas@postgresql.org      763                 :CBC       55748 :     ActiveSnapshot->as_snap->curcid = curcid;
 6326 alvherre@alvh.no-ip.      764                 :          55748 : }
                                765                 :                : 
                                766                 :                : /*
                                767                 :                :  * PopActiveSnapshot
                                768                 :                :  *
                                769                 :                :  * Remove the topmost snapshot from the active snapshot stack, decrementing the
                                770                 :                :  * reference count, and free it if this was the last reference.
                                771                 :                :  */
                                772                 :                : void
                                773                 :        1040858 : PopActiveSnapshot(void)
                                774                 :                : {
                                775                 :                :     ActiveSnapshotElt *newstack;
                                776                 :                : 
                                777                 :        1040858 :     newstack = ActiveSnapshot->as_next;
                                778                 :                : 
                                779         [ -  + ]:        1040858 :     Assert(ActiveSnapshot->as_snap->active_count > 0);
                                780                 :                : 
                                781                 :        1040858 :     ActiveSnapshot->as_snap->active_count--;
                                782                 :                : 
                                783         [ +  + ]:        1040858 :     if (ActiveSnapshot->as_snap->active_count == 0 &&
                                784         [ +  + ]:        1022468 :         ActiveSnapshot->as_snap->regd_count == 0)
                                785                 :         733561 :         FreeSnapshot(ActiveSnapshot->as_snap);
                                786                 :                : 
                                787                 :        1040858 :     pfree(ActiveSnapshot);
                                788                 :        1040858 :     ActiveSnapshot = newstack;
                                789                 :                : 
                                790                 :        1040858 :     SnapshotResetXmin();
 6373                           791                 :        1040858 : }
                                792                 :                : 
                                793                 :                : /*
                                794                 :                :  * GetActiveSnapshot
                                795                 :                :  *      Return the topmost snapshot in the Active stack.
                                796                 :                :  */
                                797                 :                : Snapshot
 6326                           798                 :        1244132 : GetActiveSnapshot(void)
                                799                 :                : {
                                800         [ -  + ]:        1244132 :     Assert(ActiveSnapshot != NULL);
                                801                 :                : 
                                802                 :        1244132 :     return ActiveSnapshot->as_snap;
                                803                 :                : }
                                804                 :                : 
                                805                 :                : /*
                                806                 :                :  * ActiveSnapshotSet
                                807                 :                :  *      Return whether there is at least one snapshot in the Active stack
                                808                 :                :  */
                                809                 :                : bool
                                810                 :         690971 : ActiveSnapshotSet(void)
                                811                 :                : {
                                812                 :         690971 :     return ActiveSnapshot != NULL;
                                813                 :                : }
                                814                 :                : 
                                815                 :                : /*
                                816                 :                :  * RegisterSnapshot
                                817                 :                :  *      Register a snapshot as being in use by the current resource owner
                                818                 :                :  *
                                819                 :                :  * If InvalidSnapshot is passed, it is not registered.
                                820                 :                :  */
                                821                 :                : Snapshot
                                822                 :        7450574 : RegisterSnapshot(Snapshot snapshot)
                                823                 :                : {
 6120                           824         [ +  + ]:        7450574 :     if (snapshot == InvalidSnapshot)
                                825                 :         580310 :         return InvalidSnapshot;
                                826                 :                : 
                                827                 :        6870264 :     return RegisterSnapshotOnOwner(snapshot, CurrentResourceOwner);
                                828                 :                : }
                                829                 :                : 
                                830                 :                : /*
                                831                 :                :  * RegisterSnapshotOnOwner
                                832                 :                :  *      As above, but use the specified resource owner
                                833                 :                :  */
                                834                 :                : Snapshot
                                835                 :        6870380 : RegisterSnapshotOnOwner(Snapshot snapshot, ResourceOwner owner)
                                836                 :                : {
                                837                 :                :     Snapshot    snap;
                                838                 :                : 
 6326                           839         [ -  + ]:        6870380 :     if (snapshot == InvalidSnapshot)
 6326 alvherre@alvh.no-ip.      840                 :UBC           0 :         return InvalidSnapshot;
                                841                 :                : 
                                842                 :                :     /* Static snapshot?  Create a persistent copy */
 6129 alvherre@alvh.no-ip.      843         [ +  + ]:CBC     6870380 :     snap = snapshot->copied ? snapshot : CopySnapshot(snapshot);
                                844                 :                : 
                                845                 :                :     /* and tell resowner.c about it */
  668 heikki.linnakangas@i      846                 :        6870380 :     ResourceOwnerEnlarge(owner);
 6129 alvherre@alvh.no-ip.      847                 :        6870380 :     snap->regd_count++;
 6120                           848                 :        6870380 :     ResourceOwnerRememberSnapshot(owner, snap);
                                849                 :                : 
 3885 heikki.linnakangas@i      850         [ +  + ]:        6870380 :     if (snap->regd_count == 1)
                                851                 :        6561249 :         pairingheap_add(&RegisteredSnapshots, &snap->ph_node);
                                852                 :                : 
 6129 alvherre@alvh.no-ip.      853                 :        6870380 :     return snap;
                                854                 :                : }
                                855                 :                : 
                                856                 :                : /*
                                857                 :                :  * UnregisterSnapshot
                                858                 :                :  *
                                859                 :                :  * Decrement the reference count of a snapshot, remove the corresponding
                                860                 :                :  * reference from CurrentResourceOwner, and free the snapshot if no more
                                861                 :                :  * references remain.
                                862                 :                :  */
                                863                 :                : void
 6326                           864                 :        7370875 : UnregisterSnapshot(Snapshot snapshot)
                                865                 :                : {
 6120                           866         [ +  + ]:        7370875 :     if (snapshot == NULL)
                                867                 :         551589 :         return;
                                868                 :                : 
                                869                 :        6819286 :     UnregisterSnapshotFromOwner(snapshot, CurrentResourceOwner);
                                870                 :                : }
                                871                 :                : 
                                872                 :                : /*
                                873                 :                :  * UnregisterSnapshotFromOwner
                                874                 :                :  *      As above, but use the specified resource owner
                                875                 :                :  */
                                876                 :                : void
                                877                 :        6840784 : UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner)
                                878                 :                : {
 6129                           879         [ -  + ]:        6840784 :     if (snapshot == NULL)
 6326 alvherre@alvh.no-ip.      880                 :UBC           0 :         return;
                                881                 :                : 
  668 heikki.linnakangas@i      882                 :CBC     6840784 :     ResourceOwnerForgetSnapshot(owner, snapshot);
                                883                 :        6840784 :     UnregisterSnapshotNoOwner(snapshot);
                                884                 :                : }
                                885                 :                : 
                                886                 :                : static void
                                887                 :        6870380 : UnregisterSnapshotNoOwner(Snapshot snapshot)
                                888                 :                : {
 6129 alvherre@alvh.no-ip.      889         [ -  + ]:        6870380 :     Assert(snapshot->regd_count > 0);
 3885 heikki.linnakangas@i      890         [ -  + ]:        6870380 :     Assert(!pairingheap_is_empty(&RegisteredSnapshots));
                                891                 :                : 
                                892                 :        6870380 :     snapshot->regd_count--;
                                893         [ +  + ]:        6870380 :     if (snapshot->regd_count == 0)
                                894                 :        6561249 :         pairingheap_remove(&RegisteredSnapshots, &snapshot->ph_node);
                                895                 :                : 
                                896   [ +  +  +  + ]:        6870380 :     if (snapshot->regd_count == 0 && snapshot->active_count == 0)
                                897                 :                :     {
 6129 alvherre@alvh.no-ip.      898                 :        6408584 :         FreeSnapshot(snapshot);
                                899                 :        6408584 :         SnapshotResetXmin();
                                900                 :                :     }
 6326                           901                 :        6870380 : }
                                902                 :                : 
                                903                 :                : /*
                                904                 :                :  * Comparison function for RegisteredSnapshots heap.  Snapshots are ordered
                                905                 :                :  * by xmin, so that the snapshot with smallest xmin is at the top.
                                906                 :                :  */
                                907                 :                : static int
 3885 heikki.linnakangas@i      908                 :        6568782 : xmin_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg)
                                909                 :                : {
                                910                 :        6568782 :     const SnapshotData *asnap = pairingheap_const_container(SnapshotData, ph_node, a);
                                911                 :        6568782 :     const SnapshotData *bsnap = pairingheap_const_container(SnapshotData, ph_node, b);
                                912                 :                : 
                                913         [ +  + ]:        6568782 :     if (TransactionIdPrecedes(asnap->xmin, bsnap->xmin))
                                914                 :          45169 :         return 1;
                                915         [ +  + ]:        6523613 :     else if (TransactionIdFollows(asnap->xmin, bsnap->xmin))
                                916                 :          10163 :         return -1;
                                917                 :                :     else
                                918                 :        6513450 :         return 0;
                                919                 :                : }
                                920                 :                : 
                                921                 :                : /*
                                922                 :                :  * SnapshotResetXmin
                                923                 :                :  *
                                924                 :                :  * If there are no more snapshots, we can reset our PGPROC->xmin to
                                925                 :                :  * InvalidTransactionId. Note we can do this without locking because we assume
                                926                 :                :  * that storing an Xid is atomic.
                                927                 :                :  *
                                928                 :                :  * Even if there are some remaining snapshots, we may be able to advance our
                                929                 :                :  * PGPROC->xmin to some degree.  This typically happens when a portal is
                                930                 :                :  * dropped.  For efficiency, we only consider recomputing PGPROC->xmin when
                                931                 :                :  * the active snapshot stack is empty; this allows us not to need to track
                                932                 :                :  * which active snapshot is oldest.
                                933                 :                :  */
                                934                 :                : static void
 6326 alvherre@alvh.no-ip.      935                 :        8436300 : SnapshotResetXmin(void)
                                936                 :                : {
                                937                 :                :     Snapshot    minSnapshot;
                                938                 :                : 
 3885 heikki.linnakangas@i      939         [ +  + ]:        8436300 :     if (ActiveSnapshot != NULL)
                                940                 :        6185852 :         return;
                                941                 :                : 
                                942         [ +  + ]:        2250448 :     if (pairingheap_is_empty(&RegisteredSnapshots))
                                943                 :                :     {
  259                           944                 :         690944 :         MyProc->xmin = TransactionXmin = InvalidTransactionId;
 3885                           945                 :         690944 :         return;
                                946                 :                :     }
                                947                 :                : 
                                948                 :        1559504 :     minSnapshot = pairingheap_container(SnapshotData, ph_node,
                                949                 :                :                                         pairingheap_first(&RegisteredSnapshots));
                                950                 :                : 
 1850 andres@anarazel.de        951         [ +  + ]:        1559504 :     if (TransactionIdPrecedes(MyProc->xmin, minSnapshot->xmin))
  259 heikki.linnakangas@i      952                 :           3664 :         MyProc->xmin = TransactionXmin = minSnapshot->xmin;
                                953                 :                : }
                                954                 :                : 
                                955                 :                : /*
                                956                 :                :  * AtSubCommit_Snapshot
                                957                 :                :  */
                                958                 :                : void
 6326 alvherre@alvh.no-ip.      959                 :           4433 : AtSubCommit_Snapshot(int level)
                                960                 :                : {
                                961                 :                :     ActiveSnapshotElt *active;
                                962                 :                : 
                                963                 :                :     /*
                                964                 :                :      * Relabel the active snapshots set in this subtransaction as though they
                                965                 :                :      * are owned by the parent subxact.
                                966                 :                :      */
                                967         [ +  + ]:           4433 :     for (active = ActiveSnapshot; active != NULL; active = active->as_next)
                                968                 :                :     {
                                969         [ +  - ]:           3631 :         if (active->as_level < level)
                                970                 :           3631 :             break;
 6326 alvherre@alvh.no-ip.      971                 :UBC           0 :         active->as_level = level - 1;
                                972                 :                :     }
 6326 alvherre@alvh.no-ip.      973                 :CBC        4433 : }
                                974                 :                : 
                                975                 :                : /*
                                976                 :                :  * AtSubAbort_Snapshot
                                977                 :                :  *      Clean up snapshots after a subtransaction abort
                                978                 :                :  */
                                979                 :                : void
                                980                 :           4674 : AtSubAbort_Snapshot(int level)
                                981                 :                : {
                                982                 :                :     /* Forget the active snapshots set by this subtransaction */
                                983   [ +  +  +  + ]:           7530 :     while (ActiveSnapshot && ActiveSnapshot->as_level >= level)
                                984                 :                :     {
                                985                 :                :         ActiveSnapshotElt *next;
                                986                 :                : 
                                987                 :           2856 :         next = ActiveSnapshot->as_next;
                                988                 :                : 
                                989                 :                :         /*
                                990                 :                :          * Decrement the snapshot's active count.  If it's still registered or
                                991                 :                :          * marked as active by an outer subtransaction, we can't free it yet.
                                992                 :                :          */
                                993         [ -  + ]:           2856 :         Assert(ActiveSnapshot->as_snap->active_count >= 1);
                                994                 :           2856 :         ActiveSnapshot->as_snap->active_count -= 1;
                                995                 :                : 
                                996         [ +  - ]:           2856 :         if (ActiveSnapshot->as_snap->active_count == 0 &&
                                997         [ +  - ]:           2856 :             ActiveSnapshot->as_snap->regd_count == 0)
                                998                 :           2856 :             FreeSnapshot(ActiveSnapshot->as_snap);
                                999                 :                : 
                               1000                 :                :         /* and free the stack element */
                               1001                 :           2856 :         pfree(ActiveSnapshot);
                               1002                 :                : 
                               1003                 :           2856 :         ActiveSnapshot = next;
                               1004                 :                :     }
                               1005                 :                : 
                               1006                 :           4674 :     SnapshotResetXmin();
                               1007                 :           4674 : }
                               1008                 :                : 
                               1009                 :                : /*
                               1010                 :                :  * AtEOXact_Snapshot
                               1011                 :                :  *      Snapshot manager's cleanup function for end of transaction
                               1012                 :                :  */
                               1013                 :                : void
 3075 simon@2ndQuadrant.co     1014                 :         319780 : AtEOXact_Snapshot(bool isCommit, bool resetXmin)
                               1015                 :                : {
                               1016                 :                :     /*
                               1017                 :                :      * In transaction-snapshot mode we must release our privately-managed
                               1018                 :                :      * reference to the transaction snapshot.  We must remove it from
                               1019                 :                :      * RegisteredSnapshots to keep the check below happy.  But we don't bother
                               1020                 :                :      * to do FreeSnapshot, for two reasons: the memory will go away with
                               1021                 :                :      * TopTransactionContext anyway, and if someone has left the snapshot
                               1022                 :                :      * stacked as active, we don't want the code below to be chasing through a
                               1023                 :                :      * dangling pointer.
                               1024                 :                :      */
 5094 tgl@sss.pgh.pa.us        1025         [ +  + ]:         319780 :     if (FirstXactSnapshot != NULL)
                               1026                 :                :     {
                               1027         [ -  + ]:           2962 :         Assert(FirstXactSnapshot->regd_count > 0);
 3885 heikki.linnakangas@i     1028         [ -  + ]:           2962 :         Assert(!pairingheap_is_empty(&RegisteredSnapshots));
                               1029                 :           2962 :         pairingheap_remove(&RegisteredSnapshots, &FirstXactSnapshot->ph_node);
                               1030                 :                :     }
 5094 tgl@sss.pgh.pa.us        1031                 :         319780 :     FirstXactSnapshot = NULL;
                               1032                 :                : 
                               1033                 :                :     /*
                               1034                 :                :      * If we exported any snapshots, clean them up.
                               1035                 :                :      */
 5068                          1036         [ +  + ]:         319780 :     if (exportedSnapshots != NIL)
                               1037                 :                :     {
                               1038                 :                :         ListCell   *lc;
                               1039                 :                : 
                               1040                 :                :         /*
                               1041                 :                :          * Get rid of the files.  Unlink failure is only a WARNING because (1)
                               1042                 :                :          * it's too late to abort the transaction, and (2) leaving a leaked
                               1043                 :                :          * file around has little real consequence anyway.
                               1044                 :                :          *
                               1045                 :                :          * We also need to remove the snapshots from RegisteredSnapshots to
                               1046                 :                :          * prevent a warning below.
                               1047                 :                :          *
                               1048                 :                :          * As with the FirstXactSnapshot, we don't need to free resources of
                               1049                 :                :          * the snapshot itself as it will go away with the memory context.
                               1050                 :                :          */
 3885 heikki.linnakangas@i     1051   [ +  -  +  +  :             20 :         foreach(lc, exportedSnapshots)
                                              +  + ]
                               1052                 :                :         {
 2999 tgl@sss.pgh.pa.us        1053                 :             10 :             ExportedSnapshot *esnap = (ExportedSnapshot *) lfirst(lc);
                               1054                 :                : 
 3006 andres@anarazel.de       1055         [ -  + ]:             10 :             if (unlink(esnap->snapfile))
 3006 andres@anarazel.de       1056         [ #  # ]:UBC           0 :                 elog(WARNING, "could not unlink file \"%s\": %m",
                               1057                 :                :                      esnap->snapfile);
                               1058                 :                : 
 3006 andres@anarazel.de       1059                 :CBC          10 :             pairingheap_remove(&RegisteredSnapshots,
                               1060                 :             10 :                                &esnap->snapshot->ph_node);
                               1061                 :                :         }
                               1062                 :                : 
 5068 tgl@sss.pgh.pa.us        1063                 :             10 :         exportedSnapshots = NIL;
                               1064                 :                :     }
                               1065                 :                : 
                               1066                 :                :     /* Drop catalog snapshot if any */
 3217                          1067                 :         319780 :     InvalidateCatalogSnapshot();
                               1068                 :                : 
                               1069                 :                :     /* On commit, complain about leftover snapshots */
 6326 alvherre@alvh.no-ip.     1070         [ +  + ]:         319780 :     if (isCommit)
                               1071                 :                :     {
                               1072                 :                :         ActiveSnapshotElt *active;
                               1073                 :                : 
 3885 heikki.linnakangas@i     1074         [ -  + ]:         294804 :         if (!pairingheap_is_empty(&RegisteredSnapshots))
 3885 heikki.linnakangas@i     1075         [ #  # ]:UBC           0 :             elog(WARNING, "registered snapshots seem to remain after cleanup");
                               1076                 :                : 
                               1077                 :                :         /* complain about unpopped active snapshots */
 6326 alvherre@alvh.no-ip.     1078         [ -  + ]:CBC      294804 :         for (active = ActiveSnapshot; active != NULL; active = active->as_next)
 6158 alvherre@alvh.no-ip.     1079         [ #  # ]:UBC           0 :             elog(WARNING, "snapshot %p still active", active);
                               1080                 :                :     }
                               1081                 :                : 
                               1082                 :                :     /*
                               1083                 :                :      * And reset our state.  We don't need to free the memory explicitly --
                               1084                 :                :      * it'll go away with TopTransactionContext.
                               1085                 :                :      */
 6326 alvherre@alvh.no-ip.     1086                 :CBC      319780 :     ActiveSnapshot = NULL;
 3885 heikki.linnakangas@i     1087                 :         319780 :     pairingheap_reset(&RegisteredSnapshots);
                               1088                 :                : 
 6326 alvherre@alvh.no-ip.     1089                 :         319780 :     CurrentSnapshot = NULL;
                               1090                 :         319780 :     SecondarySnapshot = NULL;
                               1091                 :                : 
                               1092                 :         319780 :     FirstSnapshotSet = false;
                               1093                 :                : 
                               1094                 :                :     /*
                               1095                 :                :      * During normal commit processing, we call ProcArrayEndTransaction() to
                               1096                 :                :      * reset the MyProc->xmin. That call happens prior to the call to
                               1097                 :                :      * AtEOXact_Snapshot(), so we need not touch xmin here at all.
                               1098                 :                :      */
 3075 simon@2ndQuadrant.co     1099         [ +  + ]:         319780 :     if (resetXmin)
                               1100                 :          25270 :         SnapshotResetXmin();
                               1101                 :                : 
 1850 andres@anarazel.de       1102   [ +  +  -  + ]:         319780 :     Assert(resetXmin || MyProc->xmin == 0);
 6373 alvherre@alvh.no-ip.     1103                 :         319780 : }
                               1104                 :                : 
                               1105                 :                : 
                               1106                 :                : /*
                               1107                 :                :  * ExportSnapshot
                               1108                 :                :  *      Export the snapshot to a file so that other backends can import it.
                               1109                 :                :  *      Returns the token (the file name) that can be used to import this
                               1110                 :                :  *      snapshot.
                               1111                 :                :  */
                               1112                 :                : char *
 5068 tgl@sss.pgh.pa.us        1113                 :             10 : ExportSnapshot(Snapshot snapshot)
                               1114                 :                : {
                               1115                 :                :     TransactionId topXid;
                               1116                 :                :     TransactionId *children;
                               1117                 :                :     ExportedSnapshot *esnap;
                               1118                 :                :     int         nchildren;
                               1119                 :                :     int         addTopXid;
                               1120                 :                :     StringInfoData buf;
                               1121                 :                :     FILE       *f;
                               1122                 :                :     int         i;
                               1123                 :                :     MemoryContext oldcxt;
                               1124                 :                :     char        path[MAXPGPATH];
                               1125                 :                :     char        pathtmp[MAXPGPATH];
                               1126                 :                : 
                               1127                 :                :     /*
                               1128                 :                :      * It's tempting to call RequireTransactionBlock here, since it's not very
                               1129                 :                :      * useful to export a snapshot that will disappear immediately afterwards.
                               1130                 :                :      * However, we haven't got enough information to do that, since we don't
                               1131                 :                :      * know if we're at top level or not.  For example, we could be inside a
                               1132                 :                :      * plpgsql function that is going to fire off other transactions via
                               1133                 :                :      * dblink.  Rather than disallow perfectly legitimate usages, don't make a
                               1134                 :                :      * check.
                               1135                 :                :      *
                               1136                 :                :      * Also note that we don't make any restriction on the transaction's
                               1137                 :                :      * isolation level; however, importers must check the level if they are
                               1138                 :                :      * serializable.
                               1139                 :                :      */
                               1140                 :                : 
                               1141                 :                :     /*
                               1142                 :                :      * Get our transaction ID if there is one, to include in the snapshot.
                               1143                 :                :      */
 3006 andres@anarazel.de       1144                 :             10 :     topXid = GetTopTransactionIdIfAny();
                               1145                 :                : 
                               1146                 :                :     /*
                               1147                 :                :      * We cannot export a snapshot from a subtransaction because there's no
                               1148                 :                :      * easy way for importers to verify that the same subtransaction is still
                               1149                 :                :      * running.
                               1150                 :                :      */
 5068 tgl@sss.pgh.pa.us        1151         [ -  + ]:             10 :     if (IsSubTransaction())
 5068 tgl@sss.pgh.pa.us        1152         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1153                 :                :                 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
                               1154                 :                :                  errmsg("cannot export a snapshot from a subtransaction")));
                               1155                 :                : 
                               1156                 :                :     /*
                               1157                 :                :      * We do however allow previous committed subtransactions to exist.
                               1158                 :                :      * Importers of the snapshot must see them as still running, so get their
                               1159                 :                :      * XIDs to add them to the snapshot.
                               1160                 :                :      */
 5068 tgl@sss.pgh.pa.us        1161                 :CBC          10 :     nchildren = xactGetCommittedChildren(&children);
                               1162                 :                : 
                               1163                 :                :     /*
                               1164                 :                :      * Generate file path for the snapshot.  We start numbering of snapshots
                               1165                 :                :      * inside the transaction from 1.
                               1166                 :                :      */
 3006 andres@anarazel.de       1167                 :             10 :     snprintf(path, sizeof(path), SNAPSHOT_EXPORT_DIR "/%08X-%08X-%d",
  552 heikki.linnakangas@i     1168                 :             10 :              MyProc->vxid.procNumber, MyProc->vxid.lxid,
                               1169                 :             10 :              list_length(exportedSnapshots) + 1);
                               1170                 :                : 
                               1171                 :                :     /*
                               1172                 :                :      * Copy the snapshot into TopTransactionContext, add it to the
                               1173                 :                :      * exportedSnapshots list, and mark it pseudo-registered.  We do this to
                               1174                 :                :      * ensure that the snapshot's xmin is honored for the rest of the
                               1175                 :                :      * transaction.
                               1176                 :                :      */
 5068 tgl@sss.pgh.pa.us        1177                 :             10 :     snapshot = CopySnapshot(snapshot);
                               1178                 :                : 
                               1179                 :             10 :     oldcxt = MemoryContextSwitchTo(TopTransactionContext);
 3006 andres@anarazel.de       1180                 :             10 :     esnap = (ExportedSnapshot *) palloc(sizeof(ExportedSnapshot));
                               1181                 :             10 :     esnap->snapfile = pstrdup(path);
                               1182                 :             10 :     esnap->snapshot = snapshot;
                               1183                 :             10 :     exportedSnapshots = lappend(exportedSnapshots, esnap);
 5068 tgl@sss.pgh.pa.us        1184                 :             10 :     MemoryContextSwitchTo(oldcxt);
                               1185                 :                : 
                               1186                 :             10 :     snapshot->regd_count++;
 3885 heikki.linnakangas@i     1187                 :             10 :     pairingheap_add(&RegisteredSnapshots, &snapshot->ph_node);
                               1188                 :                : 
                               1189                 :                :     /*
                               1190                 :                :      * Fill buf with a text serialization of the snapshot, plus identification
                               1191                 :                :      * data about this transaction.  The format expected by ImportSnapshot is
                               1192                 :                :      * pretty rigid: each line must be fieldname:value.
                               1193                 :                :      */
 5068 tgl@sss.pgh.pa.us        1194                 :             10 :     initStringInfo(&buf);
                               1195                 :                : 
  552 heikki.linnakangas@i     1196                 :             10 :     appendStringInfo(&buf, "vxid:%d/%u\n", MyProc->vxid.procNumber, MyProc->vxid.lxid);
 3006 andres@anarazel.de       1197                 :             10 :     appendStringInfo(&buf, "pid:%d\n", MyProcPid);
 5068 tgl@sss.pgh.pa.us        1198                 :             10 :     appendStringInfo(&buf, "dbid:%u\n", MyDatabaseId);
                               1199                 :             10 :     appendStringInfo(&buf, "iso:%d\n", XactIsoLevel);
                               1200                 :             10 :     appendStringInfo(&buf, "ro:%d\n", XactReadOnly);
                               1201                 :                : 
                               1202                 :             10 :     appendStringInfo(&buf, "xmin:%u\n", snapshot->xmin);
                               1203                 :             10 :     appendStringInfo(&buf, "xmax:%u\n", snapshot->xmax);
                               1204                 :                : 
                               1205                 :                :     /*
                               1206                 :                :      * We must include our own top transaction ID in the top-xid data, since
                               1207                 :                :      * by definition we will still be running when the importing transaction
                               1208                 :                :      * adopts the snapshot, but GetSnapshotData never includes our own XID in
                               1209                 :                :      * the snapshot.  (There must, therefore, be enough room to add it.)
                               1210                 :                :      *
                               1211                 :                :      * However, it could be that our topXid is after the xmax, in which case
                               1212                 :                :      * we shouldn't include it because xip[] members are expected to be before
                               1213                 :                :      * xmax.  (We need not make the same check for subxip[] members, see
                               1214                 :                :      * snapshot.h.)
                               1215                 :                :      */
 3006 andres@anarazel.de       1216                 :             10 :     addTopXid = (TransactionIdIsValid(topXid) &&
 2999 tgl@sss.pgh.pa.us        1217   [ -  +  -  - ]:             10 :                  TransactionIdPrecedes(topXid, snapshot->xmax)) ? 1 : 0;
 5068                          1218                 :             10 :     appendStringInfo(&buf, "xcnt:%d\n", snapshot->xcnt + addTopXid);
                               1219         [ -  + ]:             10 :     for (i = 0; i < snapshot->xcnt; i++)
 5068 tgl@sss.pgh.pa.us        1220                 :UBC           0 :         appendStringInfo(&buf, "xip:%u\n", snapshot->xip[i]);
 5068 tgl@sss.pgh.pa.us        1221         [ -  + ]:CBC          10 :     if (addTopXid)
 5068 tgl@sss.pgh.pa.us        1222                 :UBC           0 :         appendStringInfo(&buf, "xip:%u\n", topXid);
                               1223                 :                : 
                               1224                 :                :     /*
                               1225                 :                :      * Similarly, we add our subcommitted child XIDs to the subxid data. Here,
                               1226                 :                :      * we have to cope with possible overflow.
                               1227                 :                :      */
 5068 tgl@sss.pgh.pa.us        1228   [ +  -  -  + ]:CBC          20 :     if (snapshot->suboverflowed ||
                               1229                 :             10 :         snapshot->subxcnt + nchildren > GetMaxSnapshotSubxidCount())
 5068 tgl@sss.pgh.pa.us        1230                 :UBC           0 :         appendStringInfoString(&buf, "sof:1\n");
                               1231                 :                :     else
                               1232                 :                :     {
 5068 tgl@sss.pgh.pa.us        1233                 :CBC          10 :         appendStringInfoString(&buf, "sof:0\n");
                               1234                 :             10 :         appendStringInfo(&buf, "sxcnt:%d\n", snapshot->subxcnt + nchildren);
                               1235         [ -  + ]:             10 :         for (i = 0; i < snapshot->subxcnt; i++)
 5068 tgl@sss.pgh.pa.us        1236                 :UBC           0 :             appendStringInfo(&buf, "sxp:%u\n", snapshot->subxip[i]);
 5068 tgl@sss.pgh.pa.us        1237         [ -  + ]:CBC          10 :         for (i = 0; i < nchildren; i++)
 5068 tgl@sss.pgh.pa.us        1238                 :UBC           0 :             appendStringInfo(&buf, "sxp:%u\n", children[i]);
                               1239                 :                :     }
 5068 tgl@sss.pgh.pa.us        1240                 :CBC          10 :     appendStringInfo(&buf, "rec:%u\n", snapshot->takenDuringRecovery);
                               1241                 :                : 
                               1242                 :                :     /*
                               1243                 :                :      * Now write the text representation into a file.  We first write to a
                               1244                 :                :      * ".tmp" filename, and rename to final filename if no error.  This
                               1245                 :                :      * ensures that no other backend can read an incomplete file
                               1246                 :                :      * (ImportSnapshot won't allow it because of its valid-characters check).
                               1247                 :                :      */
 3006 andres@anarazel.de       1248                 :             10 :     snprintf(pathtmp, sizeof(pathtmp), "%s.tmp", path);
 5068 tgl@sss.pgh.pa.us        1249         [ -  + ]:             10 :     if (!(f = AllocateFile(pathtmp, PG_BINARY_W)))
 5068 tgl@sss.pgh.pa.us        1250         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1251                 :                :                 (errcode_for_file_access(),
                               1252                 :                :                  errmsg("could not create file \"%s\": %m", pathtmp)));
                               1253                 :                : 
 5068 tgl@sss.pgh.pa.us        1254         [ -  + ]:CBC          10 :     if (fwrite(buf.data, buf.len, 1, f) != 1)
 5068 tgl@sss.pgh.pa.us        1255         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1256                 :                :                 (errcode_for_file_access(),
                               1257                 :                :                  errmsg("could not write to file \"%s\": %m", pathtmp)));
                               1258                 :                : 
                               1259                 :                :     /* no fsync() since file need not survive a system crash */
                               1260                 :                : 
 5068 tgl@sss.pgh.pa.us        1261         [ -  + ]:CBC          10 :     if (FreeFile(f))
 5068 tgl@sss.pgh.pa.us        1262         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1263                 :                :                 (errcode_for_file_access(),
                               1264                 :                :                  errmsg("could not write to file \"%s\": %m", pathtmp)));
                               1265                 :                : 
                               1266                 :                :     /*
                               1267                 :                :      * Now that we have written everything into a .tmp file, rename the file
                               1268                 :                :      * to remove the .tmp suffix.
                               1269                 :                :      */
 5068 tgl@sss.pgh.pa.us        1270         [ -  + ]:CBC          10 :     if (rename(pathtmp, path) < 0)
 5068 tgl@sss.pgh.pa.us        1271         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1272                 :                :                 (errcode_for_file_access(),
                               1273                 :                :                  errmsg("could not rename file \"%s\" to \"%s\": %m",
                               1274                 :                :                         pathtmp, path)));
                               1275                 :                : 
                               1276                 :                :     /*
                               1277                 :                :      * The basename of the file is what we return from pg_export_snapshot().
                               1278                 :                :      * It's already in path in a textual format and we know that the path
                               1279                 :                :      * starts with SNAPSHOT_EXPORT_DIR.  Skip over the prefix and the slash
                               1280                 :                :      * and pstrdup it so as not to return the address of a local variable.
                               1281                 :                :      */
 5068 tgl@sss.pgh.pa.us        1282                 :CBC          10 :     return pstrdup(path + strlen(SNAPSHOT_EXPORT_DIR) + 1);
                               1283                 :                : }
                               1284                 :                : 
                               1285                 :                : /*
                               1286                 :                :  * pg_export_snapshot
                               1287                 :                :  *      SQL-callable wrapper for ExportSnapshot.
                               1288                 :                :  */
                               1289                 :                : Datum
                               1290                 :              9 : pg_export_snapshot(PG_FUNCTION_ARGS)
                               1291                 :                : {
                               1292                 :                :     char       *snapshotName;
                               1293                 :                : 
                               1294                 :              9 :     snapshotName = ExportSnapshot(GetActiveSnapshot());
                               1295                 :              9 :     PG_RETURN_TEXT_P(cstring_to_text(snapshotName));
                               1296                 :                : }
                               1297                 :                : 
                               1298                 :                : 
                               1299                 :                : /*
                               1300                 :                :  * Parsing subroutines for ImportSnapshot: parse a line with the given
                               1301                 :                :  * prefix followed by a value, and advance *s to the next line.  The
                               1302                 :                :  * filename is provided for use in error messages.
                               1303                 :                :  */
                               1304                 :                : static int
                               1305                 :            126 : parseIntFromText(const char *prefix, char **s, const char *filename)
                               1306                 :                : {
                               1307                 :            126 :     char       *ptr = *s;
                               1308                 :            126 :     int         prefixlen = strlen(prefix);
                               1309                 :                :     int         val;
                               1310                 :                : 
                               1311         [ -  + ]:            126 :     if (strncmp(ptr, prefix, prefixlen) != 0)
 5068 tgl@sss.pgh.pa.us        1312         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1313                 :                :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                               1314                 :                :                  errmsg("invalid snapshot data in file \"%s\"", filename)));
 5068 tgl@sss.pgh.pa.us        1315                 :CBC         126 :     ptr += prefixlen;
                               1316         [ -  + ]:            126 :     if (sscanf(ptr, "%d", &val) != 1)
 5068 tgl@sss.pgh.pa.us        1317         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1318                 :                :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                               1319                 :                :                  errmsg("invalid snapshot data in file \"%s\"", filename)));
 5068 tgl@sss.pgh.pa.us        1320                 :CBC         126 :     ptr = strchr(ptr, '\n');
                               1321         [ -  + ]:            126 :     if (!ptr)
 5068 tgl@sss.pgh.pa.us        1322         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1323                 :                :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                               1324                 :                :                  errmsg("invalid snapshot data in file \"%s\"", filename)));
 5068 tgl@sss.pgh.pa.us        1325                 :CBC         126 :     *s = ptr + 1;
                               1326                 :            126 :     return val;
                               1327                 :                : }
                               1328                 :                : 
                               1329                 :                : static TransactionId
                               1330                 :             54 : parseXidFromText(const char *prefix, char **s, const char *filename)
                               1331                 :                : {
                               1332                 :             54 :     char       *ptr = *s;
                               1333                 :             54 :     int         prefixlen = strlen(prefix);
                               1334                 :                :     TransactionId val;
                               1335                 :                : 
                               1336         [ -  + ]:             54 :     if (strncmp(ptr, prefix, prefixlen) != 0)
 5068 tgl@sss.pgh.pa.us        1337         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1338                 :                :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                               1339                 :                :                  errmsg("invalid snapshot data in file \"%s\"", filename)));
 5068 tgl@sss.pgh.pa.us        1340                 :CBC          54 :     ptr += prefixlen;
                               1341         [ -  + ]:             54 :     if (sscanf(ptr, "%u", &val) != 1)
 5068 tgl@sss.pgh.pa.us        1342         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1343                 :                :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                               1344                 :                :                  errmsg("invalid snapshot data in file \"%s\"", filename)));
 5068 tgl@sss.pgh.pa.us        1345                 :CBC          54 :     ptr = strchr(ptr, '\n');
                               1346         [ -  + ]:             54 :     if (!ptr)
 5068 tgl@sss.pgh.pa.us        1347         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1348                 :                :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                               1349                 :                :                  errmsg("invalid snapshot data in file \"%s\"", filename)));
 5068 tgl@sss.pgh.pa.us        1350                 :CBC          54 :     *s = ptr + 1;
                               1351                 :             54 :     return val;
                               1352                 :                : }
                               1353                 :                : 
                               1354                 :                : static void
 3006 andres@anarazel.de       1355                 :             18 : parseVxidFromText(const char *prefix, char **s, const char *filename,
                               1356                 :                :                   VirtualTransactionId *vxid)
                               1357                 :                : {
                               1358                 :             18 :     char       *ptr = *s;
                               1359                 :             18 :     int         prefixlen = strlen(prefix);
                               1360                 :                : 
                               1361         [ -  + ]:             18 :     if (strncmp(ptr, prefix, prefixlen) != 0)
 3006 andres@anarazel.de       1362         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1363                 :                :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                               1364                 :                :                  errmsg("invalid snapshot data in file \"%s\"", filename)));
 3006 andres@anarazel.de       1365                 :CBC          18 :     ptr += prefixlen;
  552 heikki.linnakangas@i     1366         [ -  + ]:             18 :     if (sscanf(ptr, "%d/%u", &vxid->procNumber, &vxid->localTransactionId) != 2)
 3006 andres@anarazel.de       1367         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1368                 :                :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                               1369                 :                :                  errmsg("invalid snapshot data in file \"%s\"", filename)));
 3006 andres@anarazel.de       1370                 :CBC          18 :     ptr = strchr(ptr, '\n');
                               1371         [ -  + ]:             18 :     if (!ptr)
 3006 andres@anarazel.de       1372         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1373                 :                :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                               1374                 :                :                  errmsg("invalid snapshot data in file \"%s\"", filename)));
 3006 andres@anarazel.de       1375                 :CBC          18 :     *s = ptr + 1;
                               1376                 :             18 : }
                               1377                 :                : 
                               1378                 :                : /*
                               1379                 :                :  * ImportSnapshot
                               1380                 :                :  *      Import a previously exported snapshot.  The argument should be a
                               1381                 :                :  *      filename in SNAPSHOT_EXPORT_DIR.  Load the snapshot from that file.
                               1382                 :                :  *      This is called by "SET TRANSACTION SNAPSHOT 'foo'".
                               1383                 :                :  */
                               1384                 :                : void
 5068 tgl@sss.pgh.pa.us        1385                 :             24 : ImportSnapshot(const char *idstr)
                               1386                 :                : {
                               1387                 :                :     char        path[MAXPGPATH];
                               1388                 :                :     FILE       *f;
                               1389                 :                :     struct stat stat_buf;
                               1390                 :                :     char       *filebuf;
                               1391                 :                :     int         xcnt;
                               1392                 :                :     int         i;
                               1393                 :                :     VirtualTransactionId src_vxid;
                               1394                 :                :     int         src_pid;
                               1395                 :                :     Oid         src_dbid;
                               1396                 :                :     int         src_isolevel;
                               1397                 :                :     bool        src_readonly;
                               1398                 :                :     SnapshotData snapshot;
                               1399                 :                : 
                               1400                 :                :     /*
                               1401                 :                :      * Must be at top level of a fresh transaction.  Note in particular that
                               1402                 :                :      * we check we haven't acquired an XID --- if we have, it's conceivable
                               1403                 :                :      * that the snapshot would show it as not running, making for very screwy
                               1404                 :                :      * behavior.
                               1405                 :                :      */
                               1406   [ +  -  +  - ]:             48 :     if (FirstSnapshotSet ||
                               1407         [ -  + ]:             48 :         GetTopTransactionIdIfAny() != InvalidTransactionId ||
                               1408                 :             24 :         IsSubTransaction())
 5068 tgl@sss.pgh.pa.us        1409         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1410                 :                :                 (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
                               1411                 :                :                  errmsg("SET TRANSACTION SNAPSHOT must be called before any query")));
                               1412                 :                : 
                               1413                 :                :     /*
                               1414                 :                :      * If we are in read committed mode then the next query would execute with
                               1415                 :                :      * a new snapshot thus making this function call quite useless.
                               1416                 :                :      */
 5068 tgl@sss.pgh.pa.us        1417         [ -  + ]:CBC          24 :     if (!IsolationUsesXactSnapshot())
 5068 tgl@sss.pgh.pa.us        1418         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1419                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               1420                 :                :                  errmsg("a snapshot-importing transaction must have isolation level SERIALIZABLE or REPEATABLE READ")));
                               1421                 :                : 
                               1422                 :                :     /*
                               1423                 :                :      * Verify the identifier: only 0-9, A-F and hyphens are allowed.  We do
                               1424                 :                :      * this mainly to prevent reading arbitrary files.
                               1425                 :                :      */
 5068 tgl@sss.pgh.pa.us        1426         [ +  + ]:CBC          24 :     if (strspn(idstr, "0123456789ABCDEF-") != strlen(idstr))
                               1427         [ +  - ]:              3 :         ereport(ERROR,
                               1428                 :                :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               1429                 :                :                  errmsg("invalid snapshot identifier: \"%s\"", idstr)));
                               1430                 :                : 
                               1431                 :                :     /* OK, read the file */
                               1432                 :             21 :     snprintf(path, MAXPGPATH, SNAPSHOT_EXPORT_DIR "/%s", idstr);
                               1433                 :                : 
                               1434                 :             21 :     f = AllocateFile(path, PG_BINARY_R);
                               1435         [ +  + ]:             21 :     if (!f)
                               1436                 :                :     {
                               1437                 :                :         /*
                               1438                 :                :          * If file is missing while identifier has a correct format, avoid
                               1439                 :                :          * system errors.
                               1440                 :                :          */
  718 michael@paquier.xyz      1441         [ +  - ]:              3 :         if (errno == ENOENT)
                               1442         [ +  - ]:              3 :             ereport(ERROR,
                               1443                 :                :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
                               1444                 :                :                      errmsg("snapshot \"%s\" does not exist", idstr)));
                               1445                 :                :         else
  718 michael@paquier.xyz      1446         [ #  # ]:UBC           0 :             ereport(ERROR,
                               1447                 :                :                     (errcode_for_file_access(),
                               1448                 :                :                      errmsg("could not open file \"%s\" for reading: %m",
                               1449                 :                :                             path)));
                               1450                 :                :     }
                               1451                 :                : 
                               1452                 :                :     /* get the size of the file so that we know how much memory we need */
 5068 tgl@sss.pgh.pa.us        1453         [ -  + ]:CBC          18 :     if (fstat(fileno(f), &stat_buf))
 5068 tgl@sss.pgh.pa.us        1454         [ #  # ]:UBC           0 :         elog(ERROR, "could not stat file \"%s\": %m", path);
                               1455                 :                : 
                               1456                 :                :     /* and read the file into a palloc'd string */
 5068 tgl@sss.pgh.pa.us        1457                 :CBC          18 :     filebuf = (char *) palloc(stat_buf.st_size + 1);
                               1458         [ -  + ]:             18 :     if (fread(filebuf, stat_buf.st_size, 1, f) != 1)
 5068 tgl@sss.pgh.pa.us        1459         [ #  # ]:UBC           0 :         elog(ERROR, "could not read file \"%s\": %m", path);
                               1460                 :                : 
 5068 tgl@sss.pgh.pa.us        1461                 :CBC          18 :     filebuf[stat_buf.st_size] = '\0';
                               1462                 :                : 
                               1463                 :             18 :     FreeFile(f);
                               1464                 :                : 
                               1465                 :                :     /*
                               1466                 :                :      * Construct a snapshot struct by parsing the file content.
                               1467                 :                :      */
                               1468                 :             18 :     memset(&snapshot, 0, sizeof(snapshot));
                               1469                 :                : 
 3006 andres@anarazel.de       1470                 :             18 :     parseVxidFromText("vxid:", &filebuf, path, &src_vxid);
                               1471                 :             18 :     src_pid = parseIntFromText("pid:", &filebuf, path);
                               1472                 :                :     /* we abuse parseXidFromText a bit here ... */
 5068 tgl@sss.pgh.pa.us        1473                 :             18 :     src_dbid = parseXidFromText("dbid:", &filebuf, path);
                               1474                 :             18 :     src_isolevel = parseIntFromText("iso:", &filebuf, path);
                               1475                 :             18 :     src_readonly = parseIntFromText("ro:", &filebuf, path);
                               1476                 :                : 
 2390 michael@paquier.xyz      1477                 :             18 :     snapshot.snapshot_type = SNAPSHOT_MVCC;
                               1478                 :                : 
 5068 tgl@sss.pgh.pa.us        1479                 :             18 :     snapshot.xmin = parseXidFromText("xmin:", &filebuf, path);
                               1480                 :             18 :     snapshot.xmax = parseXidFromText("xmax:", &filebuf, path);
                               1481                 :                : 
                               1482                 :             18 :     snapshot.xcnt = xcnt = parseIntFromText("xcnt:", &filebuf, path);
                               1483                 :                : 
                               1484                 :                :     /* sanity-check the xid count before palloc */
                               1485   [ +  -  -  + ]:             18 :     if (xcnt < 0 || xcnt > GetMaxSnapshotXidCount())
 5068 tgl@sss.pgh.pa.us        1486         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1487                 :                :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                               1488                 :                :                  errmsg("invalid snapshot data in file \"%s\"", path)));
                               1489                 :                : 
 5068 tgl@sss.pgh.pa.us        1490                 :CBC          18 :     snapshot.xip = (TransactionId *) palloc(xcnt * sizeof(TransactionId));
                               1491         [ -  + ]:             18 :     for (i = 0; i < xcnt; i++)
 5068 tgl@sss.pgh.pa.us        1492                 :UBC           0 :         snapshot.xip[i] = parseXidFromText("xip:", &filebuf, path);
                               1493                 :                : 
 5068 tgl@sss.pgh.pa.us        1494                 :CBC          18 :     snapshot.suboverflowed = parseIntFromText("sof:", &filebuf, path);
                               1495                 :                : 
                               1496         [ +  - ]:             18 :     if (!snapshot.suboverflowed)
                               1497                 :                :     {
                               1498                 :             18 :         snapshot.subxcnt = xcnt = parseIntFromText("sxcnt:", &filebuf, path);
                               1499                 :                : 
                               1500                 :                :         /* sanity-check the xid count before palloc */
                               1501   [ +  -  -  + ]:             18 :         if (xcnt < 0 || xcnt > GetMaxSnapshotSubxidCount())
 5068 tgl@sss.pgh.pa.us        1502         [ #  # ]:UBC           0 :             ereport(ERROR,
                               1503                 :                :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                               1504                 :                :                      errmsg("invalid snapshot data in file \"%s\"", path)));
                               1505                 :                : 
 5068 tgl@sss.pgh.pa.us        1506                 :CBC          18 :         snapshot.subxip = (TransactionId *) palloc(xcnt * sizeof(TransactionId));
                               1507         [ -  + ]:             18 :         for (i = 0; i < xcnt; i++)
 5068 tgl@sss.pgh.pa.us        1508                 :UBC           0 :             snapshot.subxip[i] = parseXidFromText("sxp:", &filebuf, path);
                               1509                 :                :     }
                               1510                 :                :     else
                               1511                 :                :     {
                               1512                 :              0 :         snapshot.subxcnt = 0;
                               1513                 :              0 :         snapshot.subxip = NULL;
                               1514                 :                :     }
                               1515                 :                : 
 5068 tgl@sss.pgh.pa.us        1516                 :CBC          18 :     snapshot.takenDuringRecovery = parseIntFromText("rec:", &filebuf, path);
                               1517                 :                : 
                               1518                 :                :     /*
                               1519                 :                :      * Do some additional sanity checking, just to protect ourselves.  We
                               1520                 :                :      * don't trouble to check the array elements, just the most critical
                               1521                 :                :      * fields.
                               1522                 :                :      */
 3006 andres@anarazel.de       1523   [ +  -  +  - ]:             18 :     if (!VirtualTransactionIdIsValid(src_vxid) ||
 5068 tgl@sss.pgh.pa.us        1524                 :             18 :         !OidIsValid(src_dbid) ||
                               1525         [ +  - ]:             18 :         !TransactionIdIsNormal(snapshot.xmin) ||
                               1526         [ -  + ]:             18 :         !TransactionIdIsNormal(snapshot.xmax))
 5068 tgl@sss.pgh.pa.us        1527         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1528                 :                :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                               1529                 :                :                  errmsg("invalid snapshot data in file \"%s\"", path)));
                               1530                 :                : 
                               1531                 :                :     /*
                               1532                 :                :      * If we're serializable, the source transaction must be too, otherwise
                               1533                 :                :      * predicate.c has problems (SxactGlobalXmin could go backwards).  Also, a
                               1534                 :                :      * non-read-only transaction can't adopt a snapshot from a read-only
                               1535                 :                :      * transaction, as predicate.c handles the cases very differently.
                               1536                 :                :      */
 5068 tgl@sss.pgh.pa.us        1537         [ -  + ]:CBC          18 :     if (IsolationIsSerializable())
                               1538                 :                :     {
 5068 tgl@sss.pgh.pa.us        1539         [ #  # ]:UBC           0 :         if (src_isolevel != XACT_SERIALIZABLE)
                               1540         [ #  # ]:              0 :             ereport(ERROR,
                               1541                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               1542                 :                :                      errmsg("a serializable transaction cannot import a snapshot from a non-serializable transaction")));
                               1543   [ #  #  #  # ]:              0 :         if (src_readonly && !XactReadOnly)
                               1544         [ #  # ]:              0 :             ereport(ERROR,
                               1545                 :                :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               1546                 :                :                      errmsg("a non-read-only serializable transaction cannot import a snapshot from a read-only transaction")));
                               1547                 :                :     }
                               1548                 :                : 
                               1549                 :                :     /*
                               1550                 :                :      * We cannot import a snapshot that was taken in a different database,
                               1551                 :                :      * because vacuum calculates OldestXmin on a per-database basis; so the
                               1552                 :                :      * source transaction's xmin doesn't protect us from data loss.  This
                               1553                 :                :      * restriction could be removed if the source transaction were to mark its
                               1554                 :                :      * xmin as being globally applicable.  But that would require some
                               1555                 :                :      * additional syntax, since that has to be known when the snapshot is
                               1556                 :                :      * initially taken.  (See pgsql-hackers discussion of 2011-10-21.)
                               1557                 :                :      */
 5068 tgl@sss.pgh.pa.us        1558         [ -  + ]:CBC          18 :     if (src_dbid != MyDatabaseId)
 5068 tgl@sss.pgh.pa.us        1559         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1560                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               1561                 :                :                  errmsg("cannot import a snapshot from a different database")));
                               1562                 :                : 
                               1563                 :                :     /* OK, install the snapshot */
 3006 andres@anarazel.de       1564                 :CBC          18 :     SetTransactionSnapshot(&snapshot, &src_vxid, src_pid, NULL);
 5068 tgl@sss.pgh.pa.us        1565                 :             18 : }
                               1566                 :                : 
                               1567                 :                : /*
                               1568                 :                :  * XactHasExportedSnapshots
                               1569                 :                :  *      Test whether current transaction has exported any snapshots.
                               1570                 :                :  */
                               1571                 :                : bool
                               1572                 :            308 : XactHasExportedSnapshots(void)
                               1573                 :                : {
                               1574                 :            308 :     return (exportedSnapshots != NIL);
                               1575                 :                : }
                               1576                 :                : 
                               1577                 :                : /*
                               1578                 :                :  * DeleteAllExportedSnapshotFiles
                               1579                 :                :  *      Clean up any files that have been left behind by a crashed backend
                               1580                 :                :  *      that had exported snapshots before it died.
                               1581                 :                :  *
                               1582                 :                :  * This should be called during database startup or crash recovery.
                               1583                 :                :  */
                               1584                 :                : void
                               1585                 :            204 : DeleteAllExportedSnapshotFiles(void)
                               1586                 :                : {
                               1587                 :                :     char        buf[MAXPGPATH + sizeof(SNAPSHOT_EXPORT_DIR)];
                               1588                 :                :     DIR        *s_dir;
                               1589                 :                :     struct dirent *s_de;
                               1590                 :                : 
                               1591                 :                :     /*
                               1592                 :                :      * Problems in reading the directory, or unlinking files, are reported at
                               1593                 :                :      * LOG level.  Since we're running in the startup process, ERROR level
                               1594                 :                :      * would prevent database start, and it's not important enough for that.
                               1595                 :                :      */
 2833                          1596                 :            204 :     s_dir = AllocateDir(SNAPSHOT_EXPORT_DIR);
                               1597                 :                : 
                               1598         [ +  + ]:            612 :     while ((s_de = ReadDirExtended(s_dir, SNAPSHOT_EXPORT_DIR, LOG)) != NULL)
                               1599                 :                :     {
 5068                          1600         [ +  + ]:            408 :         if (strcmp(s_de->d_name, ".") == 0 ||
                               1601         [ +  - ]:            204 :             strcmp(s_de->d_name, "..") == 0)
                               1602                 :            408 :             continue;
                               1603                 :                : 
 3070 peter_e@gmx.net          1604                 :UBC           0 :         snprintf(buf, sizeof(buf), SNAPSHOT_EXPORT_DIR "/%s", s_de->d_name);
                               1605                 :                : 
 2833 tgl@sss.pgh.pa.us        1606         [ #  # ]:              0 :         if (unlink(buf) != 0)
                               1607         [ #  # ]:              0 :             ereport(LOG,
                               1608                 :                :                     (errcode_for_file_access(),
                               1609                 :                :                      errmsg("could not remove file \"%s\": %m", buf)));
                               1610                 :                :     }
                               1611                 :                : 
 5068 tgl@sss.pgh.pa.us        1612                 :CBC         204 :     FreeDir(s_dir);
                               1613                 :            204 : }
                               1614                 :                : 
                               1615                 :                : /*
                               1616                 :                :  * ThereAreNoPriorRegisteredSnapshots
                               1617                 :                :  *      Is the registered snapshot count less than or equal to one?
                               1618                 :                :  *
                               1619                 :                :  * Don't use this to settle important decisions.  While zero registrations and
                               1620                 :                :  * no ActiveSnapshot would confirm a certain idleness, the system makes no
                               1621                 :                :  * guarantees about the significance of one registered snapshot.
                               1622                 :                :  */
                               1623                 :                : bool
 4662 simon@2ndQuadrant.co     1624                 :             30 : ThereAreNoPriorRegisteredSnapshots(void)
                               1625                 :                : {
 3885 heikki.linnakangas@i     1626         [ -  + ]:             30 :     if (pairingheap_is_empty(&RegisteredSnapshots) ||
 3885 heikki.linnakangas@i     1627   [ #  #  #  # ]:UBC           0 :         pairingheap_is_singular(&RegisteredSnapshots))
 4662 simon@2ndQuadrant.co     1628                 :CBC          30 :         return true;
                               1629                 :                : 
 4662 simon@2ndQuadrant.co     1630                 :UBC           0 :     return false;
                               1631                 :                : }
                               1632                 :                : 
                               1633                 :                : /*
                               1634                 :                :  * HaveRegisteredOrActiveSnapshot
                               1635                 :                :  *      Is there any registered or active snapshot?
                               1636                 :                :  *
                               1637                 :                :  * NB: Unless pushed or active, the cached catalog snapshot will not cause
                               1638                 :                :  * this function to return true. That allows this function to be used in
                               1639                 :                :  * checks enforcing a longer-lived snapshot.
                               1640                 :                :  */
                               1641                 :                : bool
 1295 andres@anarazel.de       1642                 :CBC     4816247 : HaveRegisteredOrActiveSnapshot(void)
                               1643                 :                : {
                               1644         [ +  + ]:        4816247 :     if (ActiveSnapshot != NULL)
                               1645                 :        4816034 :         return true;
                               1646                 :                : 
                               1647                 :                :     /*
                               1648                 :                :      * The catalog snapshot is in RegisteredSnapshots when valid, but can be
                               1649                 :                :      * removed at any time due to invalidation processing. If explicitly
                               1650                 :                :      * registered more than one snapshot has to be in RegisteredSnapshots.
                               1651                 :                :      */
 1239 tgl@sss.pgh.pa.us        1652         [ +  + ]:            213 :     if (CatalogSnapshot != NULL &&
                               1653   [ +  -  -  + ]:             17 :         pairingheap_is_singular(&RegisteredSnapshots))
 1295 andres@anarazel.de       1654                 :UBC           0 :         return false;
                               1655                 :                : 
 1239 tgl@sss.pgh.pa.us        1656                 :CBC         213 :     return !pairingheap_is_empty(&RegisteredSnapshots);
                               1657                 :                : }
                               1658                 :                : 
                               1659                 :                : 
                               1660                 :                : /*
                               1661                 :                :  * Setup a snapshot that replaces normal catalog snapshots that allows catalog
                               1662                 :                :  * access to behave just like it did at a certain point in the past.
                               1663                 :                :  *
                               1664                 :                :  * Needed for logical decoding.
                               1665                 :                :  */
                               1666                 :                : void
 4205 rhaas@postgresql.org     1667                 :           4737 : SetupHistoricSnapshot(Snapshot historic_snapshot, HTAB *tuplecids)
                               1668                 :                : {
                               1669         [ -  + ]:           4737 :     Assert(historic_snapshot != NULL);
                               1670                 :                : 
                               1671                 :                :     /* setup the timetravel snapshot */
                               1672                 :           4737 :     HistoricSnapshot = historic_snapshot;
                               1673                 :                : 
                               1674                 :                :     /* setup (cmin, cmax) lookup hash */
                               1675                 :           4737 :     tuplecid_data = tuplecids;
                               1676                 :           4737 : }
                               1677                 :                : 
                               1678                 :                : 
                               1679                 :                : /*
                               1680                 :                :  * Make catalog snapshots behave normally again.
                               1681                 :                :  */
                               1682                 :                : void
                               1683                 :           4731 : TeardownHistoricSnapshot(bool is_error)
                               1684                 :                : {
                               1685                 :           4731 :     HistoricSnapshot = NULL;
                               1686                 :           4731 :     tuplecid_data = NULL;
                               1687                 :           4731 : }
                               1688                 :                : 
                               1689                 :                : bool
                               1690                 :        9031576 : HistoricSnapshotActive(void)
                               1691                 :                : {
                               1692                 :        9031576 :     return HistoricSnapshot != NULL;
                               1693                 :                : }
                               1694                 :                : 
                               1695                 :                : HTAB *
                               1696                 :            768 : HistoricSnapshotGetTupleCids(void)
                               1697                 :                : {
                               1698         [ -  + ]:            768 :     Assert(HistoricSnapshotActive());
                               1699                 :            768 :     return tuplecid_data;
                               1700                 :                : }
                               1701                 :                : 
                               1702                 :                : /*
                               1703                 :                :  * EstimateSnapshotSpace
                               1704                 :                :  *      Returns the size needed to store the given snapshot.
                               1705                 :                :  *
                               1706                 :                :  * We are exporting only required fields from the Snapshot, stored in
                               1707                 :                :  * SerializedSnapshotData.
                               1708                 :                :  */
                               1709                 :                : Size
 1082 pg@bowt.ie               1710                 :           1255 : EstimateSnapshotSpace(Snapshot snapshot)
                               1711                 :                : {
                               1712                 :                :     Size        size;
                               1713                 :                : 
                               1714         [ -  + ]:           1255 :     Assert(snapshot != InvalidSnapshot);
                               1715         [ -  + ]:           1255 :     Assert(snapshot->snapshot_type == SNAPSHOT_MVCC);
                               1716                 :                : 
                               1717                 :                :     /* We allocate any XID arrays needed in the same palloc block. */
 3782 rhaas@postgresql.org     1718                 :           1255 :     size = add_size(sizeof(SerializedSnapshotData),
 1082 pg@bowt.ie               1719                 :           1255 :                     mul_size(snapshot->xcnt, sizeof(TransactionId)));
                               1720         [ -  + ]:           1255 :     if (snapshot->subxcnt > 0 &&
 1082 pg@bowt.ie               1721   [ #  #  #  # ]:UBC           0 :         (!snapshot->suboverflowed || snapshot->takenDuringRecovery))
 3782 rhaas@postgresql.org     1722                 :              0 :         size = add_size(size,
 1082 pg@bowt.ie               1723                 :              0 :                         mul_size(snapshot->subxcnt, sizeof(TransactionId)));
                               1724                 :                : 
 3782 rhaas@postgresql.org     1725                 :CBC        1255 :     return size;
                               1726                 :                : }
                               1727                 :                : 
                               1728                 :                : /*
                               1729                 :                :  * SerializeSnapshot
                               1730                 :                :  *      Dumps the serialized snapshot (extracted from given snapshot) onto the
                               1731                 :                :  *      memory location at start_address.
                               1732                 :                :  */
                               1733                 :                : void
                               1734                 :           1088 : SerializeSnapshot(Snapshot snapshot, char *start_address)
                               1735                 :                : {
                               1736                 :                :     SerializedSnapshotData serialized_snapshot;
                               1737                 :                : 
                               1738         [ -  + ]:           1088 :     Assert(snapshot->subxcnt >= 0);
                               1739                 :                : 
                               1740                 :                :     /* Copy all required fields */
 3110 noah@leadboat.com        1741                 :           1088 :     serialized_snapshot.xmin = snapshot->xmin;
                               1742                 :           1088 :     serialized_snapshot.xmax = snapshot->xmax;
                               1743                 :           1088 :     serialized_snapshot.xcnt = snapshot->xcnt;
                               1744                 :           1088 :     serialized_snapshot.subxcnt = snapshot->subxcnt;
                               1745                 :           1088 :     serialized_snapshot.suboverflowed = snapshot->suboverflowed;
                               1746                 :           1088 :     serialized_snapshot.takenDuringRecovery = snapshot->takenDuringRecovery;
                               1747                 :           1088 :     serialized_snapshot.curcid = snapshot->curcid;
                               1748                 :                : 
                               1749                 :                :     /*
                               1750                 :                :      * Ignore the SubXID array if it has overflowed, unless the snapshot was
                               1751                 :                :      * taken during recovery - in that case, top-level XIDs are in subxip as
                               1752                 :                :      * well, and we mustn't lose them.
                               1753                 :                :      */
 2996 simon@2ndQuadrant.co     1754   [ -  +  -  - ]:           1088 :     if (serialized_snapshot.suboverflowed && !snapshot->takenDuringRecovery)
 2996 simon@2ndQuadrant.co     1755                 :UBC           0 :         serialized_snapshot.subxcnt = 0;
                               1756                 :                : 
                               1757                 :                :     /* Copy struct to possibly-unaligned buffer */
 3110 noah@leadboat.com        1758                 :CBC        1088 :     memcpy(start_address,
                               1759                 :                :            &serialized_snapshot, sizeof(SerializedSnapshotData));
                               1760                 :                : 
                               1761                 :                :     /* Copy XID array */
 3782 rhaas@postgresql.org     1762         [ +  + ]:           1088 :     if (snapshot->xcnt > 0)
 3110 noah@leadboat.com        1763                 :            555 :         memcpy((TransactionId *) (start_address +
                               1764                 :                :                                   sizeof(SerializedSnapshotData)),
 3782 rhaas@postgresql.org     1765                 :            555 :                snapshot->xip, snapshot->xcnt * sizeof(TransactionId));
                               1766                 :                : 
                               1767                 :                :     /*
                               1768                 :                :      * Copy SubXID array. Don't bother to copy it if it had overflowed,
                               1769                 :                :      * though, because it's not used anywhere in that case. Except if it's a
                               1770                 :                :      * snapshot taken during recovery; all the top-level XIDs are in subxip as
                               1771                 :                :      * well in that case, so we mustn't lose them.
                               1772                 :                :      */
 3110 noah@leadboat.com        1773         [ -  + ]:           1088 :     if (serialized_snapshot.subxcnt > 0)
                               1774                 :                :     {
 3759 bruce@momjian.us         1775                 :UBC           0 :         Size        subxipoff = sizeof(SerializedSnapshotData) +
  841 tgl@sss.pgh.pa.us        1776                 :              0 :             snapshot->xcnt * sizeof(TransactionId);
                               1777                 :                : 
 3110 noah@leadboat.com        1778                 :              0 :         memcpy((TransactionId *) (start_address + subxipoff),
 3782 rhaas@postgresql.org     1779                 :              0 :                snapshot->subxip, snapshot->subxcnt * sizeof(TransactionId));
                               1780                 :                :     }
 3782 rhaas@postgresql.org     1781                 :CBC        1088 : }
                               1782                 :                : 
                               1783                 :                : /*
                               1784                 :                :  * RestoreSnapshot
                               1785                 :                :  *      Restore a serialized snapshot from the specified address.
                               1786                 :                :  *
                               1787                 :                :  * The copy is palloc'd in TopTransactionContext and has initial refcounts set
                               1788                 :                :  * to 0.  The returned snapshot has the copied flag set.
                               1789                 :                :  */
                               1790                 :                : Snapshot
                               1791                 :           3394 : RestoreSnapshot(char *start_address)
                               1792                 :                : {
                               1793                 :                :     SerializedSnapshotData serialized_snapshot;
                               1794                 :                :     Size        size;
                               1795                 :                :     Snapshot    snapshot;
                               1796                 :                :     TransactionId *serialized_xids;
                               1797                 :                : 
 3110 noah@leadboat.com        1798                 :           3394 :     memcpy(&serialized_snapshot, start_address,
                               1799                 :                :            sizeof(SerializedSnapshotData));
 3782 rhaas@postgresql.org     1800                 :           3394 :     serialized_xids = (TransactionId *)
                               1801                 :                :         (start_address + sizeof(SerializedSnapshotData));
                               1802                 :                : 
                               1803                 :                :     /* We allocate any XID arrays needed in the same palloc block. */
                               1804                 :           3394 :     size = sizeof(SnapshotData)
 3110 noah@leadboat.com        1805                 :           3394 :         + serialized_snapshot.xcnt * sizeof(TransactionId)
                               1806                 :           3394 :         + serialized_snapshot.subxcnt * sizeof(TransactionId);
                               1807                 :                : 
                               1808                 :                :     /* Copy all required fields */
 3782 rhaas@postgresql.org     1809                 :           3394 :     snapshot = (Snapshot) MemoryContextAlloc(TopTransactionContext, size);
 2420 andres@anarazel.de       1810                 :           3394 :     snapshot->snapshot_type = SNAPSHOT_MVCC;
 3110 noah@leadboat.com        1811                 :           3394 :     snapshot->xmin = serialized_snapshot.xmin;
                               1812                 :           3394 :     snapshot->xmax = serialized_snapshot.xmax;
 3782 rhaas@postgresql.org     1813                 :           3394 :     snapshot->xip = NULL;
 3110 noah@leadboat.com        1814                 :           3394 :     snapshot->xcnt = serialized_snapshot.xcnt;
 3782 rhaas@postgresql.org     1815                 :           3394 :     snapshot->subxip = NULL;
 3110 noah@leadboat.com        1816                 :           3394 :     snapshot->subxcnt = serialized_snapshot.subxcnt;
                               1817                 :           3394 :     snapshot->suboverflowed = serialized_snapshot.suboverflowed;
                               1818                 :           3394 :     snapshot->takenDuringRecovery = serialized_snapshot.takenDuringRecovery;
                               1819                 :           3394 :     snapshot->curcid = serialized_snapshot.curcid;
 1846 andres@anarazel.de       1820                 :           3394 :     snapshot->snapXactCompletionCount = 0;
                               1821                 :                : 
                               1822                 :                :     /* Copy XIDs, if present. */
 3110 noah@leadboat.com        1823         [ +  + ]:           3394 :     if (serialized_snapshot.xcnt > 0)
                               1824                 :                :     {
 3782 rhaas@postgresql.org     1825                 :           1061 :         snapshot->xip = (TransactionId *) (snapshot + 1);
                               1826                 :           1061 :         memcpy(snapshot->xip, serialized_xids,
 3110 noah@leadboat.com        1827                 :           1061 :                serialized_snapshot.xcnt * sizeof(TransactionId));
                               1828                 :                :     }
                               1829                 :                : 
                               1830                 :                :     /* Copy SubXIDs, if present. */
                               1831         [ -  + ]:           3394 :     if (serialized_snapshot.subxcnt > 0)
                               1832                 :                :     {
 3354 rhaas@postgresql.org     1833                 :UBC           0 :         snapshot->subxip = ((TransactionId *) (snapshot + 1)) +
 3110 noah@leadboat.com        1834                 :              0 :             serialized_snapshot.xcnt;
                               1835                 :              0 :         memcpy(snapshot->subxip, serialized_xids + serialized_snapshot.xcnt,
                               1836                 :              0 :                serialized_snapshot.subxcnt * sizeof(TransactionId));
                               1837                 :                :     }
                               1838                 :                : 
                               1839                 :                :     /* Set the copied flag so that the caller will set refcounts correctly. */
 3782 rhaas@postgresql.org     1840                 :CBC        3394 :     snapshot->regd_count = 0;
                               1841                 :           3394 :     snapshot->active_count = 0;
                               1842                 :           3394 :     snapshot->copied = true;
                               1843                 :                : 
                               1844                 :           3394 :     return snapshot;
                               1845                 :                : }
                               1846                 :                : 
                               1847                 :                : /*
                               1848                 :                :  * Install a restored snapshot as the transaction snapshot.
                               1849                 :                :  *
                               1850                 :                :  * The second argument is of type void * so that snapmgr.h need not include
                               1851                 :                :  * the declaration for PGPROC.
                               1852                 :                :  */
                               1853                 :                : void
 1909 andres@anarazel.de       1854                 :           1572 : RestoreTransactionSnapshot(Snapshot snapshot, void *source_pgproc)
                               1855                 :                : {
                               1856                 :           1572 :     SetTransactionSnapshot(snapshot, NULL, InvalidPid, source_pgproc);
 3782 rhaas@postgresql.org     1857                 :           1572 : }
                               1858                 :                : 
                               1859                 :                : /*
                               1860                 :                :  * XidInMVCCSnapshot
                               1861                 :                :  *      Is the given XID still-in-progress according to the snapshot?
                               1862                 :                :  *
                               1863                 :                :  * Note: GetSnapshotData never stores either top xid or subxids of our own
                               1864                 :                :  * backend into a snapshot, so these xids will not be reported as "running"
                               1865                 :                :  * by this function.  This is OK for current uses, because we always check
                               1866                 :                :  * TransactionIdIsCurrentTransactionId first, except when it's known the
                               1867                 :                :  * XID could not be ours anyway.
                               1868                 :                :  */
                               1869                 :                : bool
 2420 andres@anarazel.de       1870                 :       68709977 : XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
                               1871                 :                : {
                               1872                 :                :     /*
                               1873                 :                :      * Make a quick range check to eliminate most XIDs without looking at the
                               1874                 :                :      * xip arrays.  Note that this is OK even if we convert a subxact XID to
                               1875                 :                :      * its parent below, because a subxact with XID < xmin has surely also got
                               1876                 :                :      * a parent with XID < xmin, while one with XID >= xmax must belong to a
                               1877                 :                :      * parent that was not yet committed at the time of this snapshot.
                               1878                 :                :      */
                               1879                 :                : 
                               1880                 :                :     /* Any xid < xmin is not in-progress */
                               1881         [ +  + ]:       68709977 :     if (TransactionIdPrecedes(xid, snapshot->xmin))
                               1882                 :       64325975 :         return false;
                               1883                 :                :     /* Any xid >= xmax is in-progress */
                               1884         [ +  + ]:        4384002 :     if (TransactionIdFollowsOrEquals(xid, snapshot->xmax))
                               1885                 :          18467 :         return true;
                               1886                 :                : 
                               1887                 :                :     /*
                               1888                 :                :      * Snapshot information is stored slightly differently in snapshots taken
                               1889                 :                :      * during recovery.
                               1890                 :                :      */
                               1891         [ +  + ]:        4365535 :     if (!snapshot->takenDuringRecovery)
                               1892                 :                :     {
                               1893                 :                :         /*
                               1894                 :                :          * If the snapshot contains full subxact data, the fastest way to
                               1895                 :                :          * check things is just to compare the given XID against both subxact
                               1896                 :                :          * XIDs and top-level XIDs.  If the snapshot overflowed, we have to
                               1897                 :                :          * use pg_subtrans to convert a subxact XID to its parent XID, but
                               1898                 :                :          * then we need only look at top-level XIDs not subxacts.
                               1899                 :                :          */
                               1900         [ +  + ]:        4365455 :         if (!snapshot->suboverflowed)
                               1901                 :                :         {
                               1902                 :                :             /* we have full data, so search subxip */
 1130 john.naylor@postgres     1903         [ +  + ]:        4365105 :             if (pg_lfind32(xid, snapshot->subxip, snapshot->subxcnt))
                               1904                 :            240 :                 return true;
                               1905                 :                : 
                               1906                 :                :             /* not there, fall through to search xip[] */
                               1907                 :                :         }
                               1908                 :                :         else
                               1909                 :                :         {
                               1910                 :                :             /*
                               1911                 :                :              * Snapshot overflowed, so convert xid to top-level.  This is safe
                               1912                 :                :              * because we eliminated too-old XIDs above.
                               1913                 :                :              */
 2420 andres@anarazel.de       1914                 :            350 :             xid = SubTransGetTopmostTransaction(xid);
                               1915                 :                : 
                               1916                 :                :             /*
                               1917                 :                :              * If xid was indeed a subxact, we might now have an xid < xmin,
                               1918                 :                :              * so recheck to avoid an array scan.  No point in rechecking
                               1919                 :                :              * xmax.
                               1920                 :                :              */
                               1921         [ -  + ]:            350 :             if (TransactionIdPrecedes(xid, snapshot->xmin))
 2420 andres@anarazel.de       1922                 :UBC           0 :                 return false;
                               1923                 :                :         }
                               1924                 :                : 
 1130 john.naylor@postgres     1925         [ +  + ]:CBC     4365215 :         if (pg_lfind32(xid, snapshot->xip, snapshot->xcnt))
                               1926                 :          20916 :             return true;
                               1927                 :                :     }
                               1928                 :                :     else
                               1929                 :                :     {
                               1930                 :                :         /*
                               1931                 :                :          * In recovery we store all xids in the subxip array because it is by
                               1932                 :                :          * far the bigger array, and we mostly don't know which xids are
                               1933                 :                :          * top-level and which are subxacts. The xip array is empty.
                               1934                 :                :          *
                               1935                 :                :          * We start by searching subtrans, if we overflowed.
                               1936                 :                :          */
 2420 andres@anarazel.de       1937         [ +  + ]:             80 :         if (snapshot->suboverflowed)
                               1938                 :                :         {
                               1939                 :                :             /*
                               1940                 :                :              * Snapshot overflowed, so convert xid to top-level.  This is safe
                               1941                 :                :              * because we eliminated too-old XIDs above.
                               1942                 :                :              */
                               1943                 :              4 :             xid = SubTransGetTopmostTransaction(xid);
                               1944                 :                : 
                               1945                 :                :             /*
                               1946                 :                :              * If xid was indeed a subxact, we might now have an xid < xmin,
                               1947                 :                :              * so recheck to avoid an array scan.  No point in rechecking
                               1948                 :                :              * xmax.
                               1949                 :                :              */
                               1950         [ -  + ]:              4 :             if (TransactionIdPrecedes(xid, snapshot->xmin))
 2420 andres@anarazel.de       1951                 :UBC           0 :                 return false;
                               1952                 :                :         }
                               1953                 :                : 
                               1954                 :                :         /*
                               1955                 :                :          * We now have either a top-level xid higher than xmin or an
                               1956                 :                :          * indeterminate xid. We don't know whether it's top level or subxact
                               1957                 :                :          * but it doesn't matter. If it's present, the xid is visible.
                               1958                 :                :          */
 1130 john.naylor@postgres     1959         [ +  + ]:CBC          80 :         if (pg_lfind32(xid, snapshot->subxip, snapshot->subxcnt))
                               1960                 :              6 :             return true;
                               1961                 :                :     }
                               1962                 :                : 
 2420 andres@anarazel.de       1963                 :        4344373 :     return false;
                               1964                 :                : }
                               1965                 :                : 
                               1966                 :                : /* ResourceOwner callbacks */
                               1967                 :                : 
                               1968                 :                : static void
  668 heikki.linnakangas@i     1969                 :          29596 : ResOwnerReleaseSnapshot(Datum res)
                               1970                 :                : {
                               1971                 :          29596 :     UnregisterSnapshotNoOwner((Snapshot) DatumGetPointer(res));
                               1972                 :          29596 : }
        

Generated by: LCOV version 2.4-beta