LCOV - differential code coverage report
Current view: top level - src/backend/utils/time - snapmgr.c (source / functions) Coverage Total Hit UNC LBC UBC GBC GIC GNC CBC DUB DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 89.6 % 586 525 1 1 59 1 1 19 504 92 93
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 50 50 9 41 1 9
Baseline: 16@8cea358b128 Branches: 56.0 % 448 251 5 3 189 6 3 242
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed [..60] days: 100.0 % 4 4 4
(120,180] days: 100.0 % 13 13 13
(180,240] days: 66.7 % 3 2 1 2
(240..) days: 89.4 % 566 506 1 59 1 1 504
Function coverage date bins:
(120,180] days: 100.0 % 4 4 4
(240..) days: 100.0 % 46 46 5 41
Branch coverage date bins:
[..60] days: 50.0 % 2 1 1 1
(180,240] days: 33.3 % 6 2 4 2
(240..) days: 56.4 % 440 248 3 189 6 242

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

Generated by: LCOV version 2.1-beta2-3-g6141622