LCOV - code coverage report
Current view: top level - src/backend/utils/time - snapmgr.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 89.3 % 534 477
Test Date: 2026-07-25 22:15:46 Functions: 100.0 % 49 49
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 57.4 % 366 210

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

Generated by: LCOV version 2.0-1