200 lines
6.2 KiB
C
200 lines
6.2 KiB
C
/*-------------------------------------------------------------------------
|
|||
|
|
*
|
||
|
|
* snapbuild_internal.h
|
||
|
|
* This file contains declarations for logical decoding utility
|
||
|
|
* functions for internal use.
|
||
|
|
*
|
||
|
|
* Copyright (c) 2024-2025, PostgreSQL Global Development Group
|
||
|
|
*
|
||
|
|
* src/include/replication/snapbuild_internal.h
|
||
|
|
*
|
||
|
|
*-------------------------------------------------------------------------
|
||
|
|
*/
|
||
|
|
|
||
|
|
#ifndef SNAPBUILD_INTERNAL_H
|
||
|
|
#define SNAPBUILD_INTERNAL_H
|
||
|
|
|
||
|
|
#include "port/pg_crc32c.h"
|
||
|
|
#include "replication/reorderbuffer.h"
|
||
|
|
#include "replication/snapbuild.h"
|
||
|
|
|
||
|
|
/*
|
||
|
|
* This struct contains the current state of the snapshot building
|
||
|
|
* machinery. It is exposed to the public, so pay attention when changing its
|
||
|
|
* contents.
|
||
|
|
*/
|
||
|
|
struct SnapBuild
|
||
|
|
{
|
||
|
|
/* how far are we along building our first full snapshot */
|
||
|
|
SnapBuildState state;
|
||
|
|
|
||
|
|
/* private memory context used to allocate memory for this module. */
|
||
|
|
MemoryContext context;
|
||
|
|
|
||
|
|
/* all transactions < than this have committed/aborted */
|
||
|
|
TransactionId xmin;
|
||
|
|
|
||
|
|
/* all transactions >= than this are uncommitted */
|
||
|
|
TransactionId xmax;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Don't replay commits from an LSN < this LSN. This can be set externally
|
||
|
|
* but it will also be advanced (never retreat) from within snapbuild.c.
|
||
|
|
*/
|
||
|
|
XLogRecPtr start_decoding_at;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* LSN at which two-phase decoding was enabled or LSN at which we found a
|
||
|
|
* consistent point at the time of slot creation.
|
||
|
|
*
|
||
|
|
* The prepared transactions, that were skipped because previously
|
||
|
|
* two-phase was not enabled or are not covered by initial snapshot, need
|
||
|
|
* to be sent later along with commit prepared and they must be before
|
||
|
|
* this point.
|
||
|
|
*/
|
||
|
|
XLogRecPtr two_phase_at;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Don't start decoding WAL until the "xl_running_xacts" information
|
||
|
|
* indicates there are no running xids with an xid smaller than this.
|
||
|
|
*/
|
||
|
|
TransactionId initial_xmin_horizon;
|
||
|
|
|
||
|
|
/* Indicates if we are building full snapshot or just catalog one. */
|
||
|
|
bool building_full_snapshot;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Indicates if we are using the snapshot builder for the creation of a
|
||
|
|
* logical replication slot. If it's true, the start point for decoding
|
||
|
|
* changes is not determined yet. So we skip snapshot restores to properly
|
||
|
|
* find the start point. See SnapBuildFindSnapshot() for details.
|
||
|
|
*/
|
||
|
|
bool in_slot_creation;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Snapshot that's valid to see the catalog state seen at this moment.
|
||
|
|
*/
|
||
|
|
Snapshot snapshot;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* LSN of the last location we are sure a snapshot has been serialized to.
|
||
|
|
*/
|
||
|
|
XLogRecPtr last_serialized_snapshot;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* The reorderbuffer we need to update with usable snapshots et al.
|
||
|
|
*/
|
||
|
|
ReorderBuffer *reorder;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* TransactionId at which the next phase of initial snapshot building will
|
||
|
|
* happen. InvalidTransactionId if not known (i.e. SNAPBUILD_START), or
|
||
|
|
* when no next phase necessary (SNAPBUILD_CONSISTENT).
|
||
|
|
*/
|
||
|
|
TransactionId next_phase_at;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Array of transactions which could have catalog changes that committed
|
||
|
|
* between xmin and xmax.
|
||
|
|
*/
|
||
|
|
struct
|
||
|
|
{
|
||
|
|
/* number of committed transactions */
|
||
|
|
size_t xcnt;
|
||
|
|
|
||
|
|
/* available space for committed transactions */
|
||
|
|
size_t xcnt_space;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Until we reach a CONSISTENT state, we record commits of all
|
||
|
|
* transactions, not just the catalog changing ones. Record when that
|
||
|
|
* changes so we know we cannot export a snapshot safely anymore.
|
||
|
|
*/
|
||
|
|
bool includes_all_transactions;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Array of committed transactions that have modified the catalog.
|
||
|
|
*
|
||
|
|
* As this array is frequently modified we do *not* keep it in
|
||
|
|
* xidComparator order. Instead we sort the array when building &
|
||
|
|
* distributing a snapshot.
|
||
|
|
*
|
||
|
|
* TODO: It's unclear whether that reasoning has much merit. Every
|
||
|
|
* time we add something here after becoming consistent will also
|
||
|
|
* require distributing a snapshot. Storing them sorted would
|
||
|
|
* potentially also make it easier to purge (but more complicated wrt
|
||
|
|
* wraparound?). Should be improved if sorting while building the
|
||
|
|
* snapshot shows up in profiles.
|
||
|
|
*/
|
||
|
|
TransactionId *xip;
|
||
|
|
} committed;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Array of transactions and subtransactions that had modified catalogs
|
||
|
|
* and were running when the snapshot was serialized.
|
||
|
|
*
|
||
|
|
* We normally rely on some WAL record types such as HEAP2_NEW_CID to know
|
||
|
|
* if the transaction has changed the catalog. But it could happen that
|
||
|
|
* the logical decoding decodes only the commit record of the transaction
|
||
|
|
* after restoring the previously serialized snapshot in which case we
|
||
|
|
* will miss adding the xid to the snapshot and end up looking at the
|
||
|
|
* catalogs with the wrong snapshot.
|
||
|
|
*
|
||
|
|
* Now to avoid the above problem, we serialize the transactions that had
|
||
|
|
* modified the catalogs and are still running at the time of snapshot
|
||
|
|
* serialization. We fill this array while restoring the snapshot and then
|
||
|
|
* refer it while decoding commit to ensure if the xact has modified the
|
||
|
|
* catalog. We discard this array when all the xids in the list become old
|
||
|
|
* enough to matter. See SnapBuildPurgeOlderTxn for details.
|
||
|
|
*/
|
||
|
|
struct
|
||
|
|
{
|
||
|
|
/* number of transactions */
|
||
|
|
size_t xcnt;
|
||
|
|
|
||
|
|
/* This array must be sorted in xidComparator order */
|
||
|
|
TransactionId *xip;
|
||
|
|
} catchange;
|
||
|
|
};
|
||
|
|
|
||
|
|
/* -----------------------------------
|
||
|
|
* Snapshot serialization support
|
||
|
|
* -----------------------------------
|
||
|
|
*/
|
||
|
|
|
||
|
|
/*
|
||
|
|
* We store current state of struct SnapBuild on disk in the following manner:
|
||
|
|
*
|
||
|
|
* struct SnapBuildOnDisk;
|
||
|
|
* TransactionId * committed.xcnt; (*not xcnt_space*)
|
||
|
|
* TransactionId * catchange.xcnt;
|
||
|
|
*
|
||
|
|
* Check if the SnapBuildOnDiskConstantSize and SnapBuildOnDiskNotChecksummedSize
|
||
|
|
* macros need to be updated when modifying the SnapBuildOnDisk struct.
|
||
|
|
*/
|
||
|
|
typedef struct SnapBuildOnDisk
|
||
|
|
{
|
||
|
|
/* first part of this struct needs to be version independent */
|
||
|
|
|
||
|
|
/* data not covered by checksum */
|
||
|
|
uint32 magic;
|
||
|
|
pg_crc32c checksum;
|
||
|
|
|
||
|
|
/* data covered by checksum */
|
||
|
|
|
||
|
|
/* version, in case we want to support pg_upgrade */
|
||
|
|
uint32 version;
|
||
|
|
/* how large is the on disk data, excluding the constant sized part */
|
||
|
|
uint32 length;
|
||
|
|
|
||
|
|
/* version dependent part */
|
||
|
|
SnapBuild builder;
|
||
|
|
|
||
|
|
/* variable amount of TransactionIds follows */
|
||
|
|
} SnapBuildOnDisk;
|
||
|
|
|
||
|
|
extern bool SnapBuildRestoreSnapshot(SnapBuildOnDisk *ondisk, XLogRecPtr lsn,
|
||
|
|
MemoryContext context, bool missing_ok);
|
||
|
|
|
||
|
|
#endif /* SNAPBUILD_INTERNAL_H */
|