LCOV - differential code coverage report
Current view: top level - src/backend/utils/time - snapmgr.c (source / functions) Coverage Total Hit UNC LBC UBC GNC CBC DCB
Current: c38de3ae6098ccf1904109f2e550eb4777f66024 vs e352ac8c5c90ed6ce792f044c22145578542a330 Lines: 88.2 % 576 508 1 12 55 9 499 5
Current Date: 2026-11-05 14:14:01 +0100 Functions: 100.0 % 50 50 3 47
Baseline: lcov-20261105-baseline Branches: 56.4 % 450 254 5 5 186 5 249
Baseline Date: 2026-11-05 14:14:01 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 87.5 % 8 7 1 4 3
(30,360] days: 91.3 % 23 21 2 5 16
(360..) days: 88.1 % 545 480 12 53 480
Function coverage date bins:
(7,30] days: 100.0 % 1 1 1
(30,360] days: 100.0 % 1 1 1
(360..) days: 100.0 % 48 48 2 46
Branch coverage date bins:
(7,30] days: 25.0 % 4 1 3 1
(30,360] days: 70.8 % 24 17 2 5 4 13
(360..) days: 55.9 % 422 236 5 181 236

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

Generated by: LCOV version 2.0-1