1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-07-01 00:25:06 +02:00

Refactor PostgreSQL interface to remove most code duplication.

Having a copy per version worked well until it was time to add new features or modify existing functions.  Then it was necessary to modify every version and try to keep them all in sync.

Consolidate all the PostgreSQL types into a single file using #if for type versions.  Many types do not change or change infrequently so this cuts down on duplication.  In addition, it is far easier to see what has changed when a new version is added.

Use macros to write the interface functions.  There is still duplication here since some changes require a new copy of the macro, but it is far less than before.
This commit is contained in:
David Steele
2019-03-21 21:11:36 +04:00
parent e938a89250
commit 7cf7373761
42 changed files with 2359 additions and 4911 deletions

View File

@ -8,17 +8,7 @@ PostgreSQL Interface
#include "common/memContext.h"
#include "common/regExp.h"
#include "postgres/interface.h"
#include "postgres/interface/v083.h"
#include "postgres/interface/v084.h"
#include "postgres/interface/v090.h"
#include "postgres/interface/v091.h"
#include "postgres/interface/v092.h"
#include "postgres/interface/v093.h"
#include "postgres/interface/v094.h"
#include "postgres/interface/v095.h"
#include "postgres/interface/v096.h"
#include "postgres/interface/v100.h"
#include "postgres/interface/v110.h"
#include "postgres/interface/version.h"
#include "postgres/version.h"
#include "storage/helper.h"
@ -62,24 +52,24 @@ typedef struct PgInterface
unsigned int version;
// Does pg_control match this version of PostgreSQL?
bool (*controlIs)(const Buffer *);
bool (*controlIs)(const unsigned char *);
// Convert pg_control to a common data structure
PgControl (*control)(const Buffer *);
PgControl (*control)(const unsigned char *);
// Does the WAL header match this version of PostgreSQL?
bool (*walIs)(const Buffer *);
bool (*walIs)(const unsigned char *);
// Convert WAL header to a common data structure
PgWal (*wal)(const Buffer *);
PgWal (*wal)(const unsigned char *);
#ifdef DEBUG
// Create pg_control for testing
void (*controlTest)(PgControl, Buffer *);
void (*controlTest)(PgControl, unsigned char *);
// Create WAL header for testing
void (*walTest)(PgWal, Buffer *);
void (*walTest)(PgWal, unsigned char *);
#endif
} PgInterface;
@ -241,6 +231,9 @@ static const PgInterface pgInterface[] =
},
};
// Total PostgreSQL versions in pgInterface
#define PG_INTERFACE_SIZE (sizeof(pgInterface) / sizeof(PgInterface))
/***********************************************************************************************************************************
These pg_control fields are common to all versions of PostgreSQL, so we can use them to generate error messages when the pg_control
version cannot be found.
@ -267,9 +260,9 @@ pgControlFromBuffer(const Buffer *controlFile)
// Search for the version of PostgreSQL that uses this control file
const PgInterface *interface = NULL;
for (unsigned int interfaceIdx = 0; interfaceIdx < sizeof(pgInterface) / sizeof(PgInterface); interfaceIdx++)
for (unsigned int interfaceIdx = 0; interfaceIdx < PG_INTERFACE_SIZE; interfaceIdx++)
{
if (pgInterface[interfaceIdx].controlIs(controlFile))
if (pgInterface[interfaceIdx].controlIs(bufPtr(controlFile)))
{
interface = &pgInterface[interfaceIdx];
break;
@ -289,7 +282,7 @@ pgControlFromBuffer(const Buffer *controlFile)
}
// Get info from the control file
PgControl result = interface->control(controlFile);
PgControl result = interface->control(bufPtr(controlFile));
result.version = interface->version;
// Check the segment size
@ -366,9 +359,9 @@ pgWalFromBuffer(const Buffer *walBuffer)
// Search for the version of PostgreSQL that uses this WAL magic
const PgInterface *interface = NULL;
for (unsigned int interfaceIdx = 0; interfaceIdx < sizeof(pgInterface) / sizeof(PgInterface); interfaceIdx++)
for (unsigned int interfaceIdx = 0; interfaceIdx < PG_INTERFACE_SIZE; interfaceIdx++)
{
if (pgInterface[interfaceIdx].walIs(walBuffer))
if (pgInterface[interfaceIdx].walIs(bufPtr(walBuffer)))
{
interface = &pgInterface[interfaceIdx];
break;
@ -386,7 +379,7 @@ pgWalFromBuffer(const Buffer *walBuffer)
}
// Get info from the control file
PgWal result = interface->wal(walBuffer);
PgWal result = interface->wal(bufPtr(walBuffer));
result.version = interface->version;
FUNCTION_LOG_RETURN(PG_WAL, result);
@ -442,7 +435,7 @@ pgControlTestToBuffer(PgControl pgControl)
// Find the interface for the version of PostgreSQL
const PgInterface *interface = NULL;
for (unsigned int interfaceIdx = 0; interfaceIdx < sizeof(pgInterface) / sizeof(PgInterface); interfaceIdx++)
for (unsigned int interfaceIdx = 0; interfaceIdx < PG_INTERFACE_SIZE; interfaceIdx++)
{
if (pgInterface[interfaceIdx].version == pgControl.version)
{
@ -456,7 +449,7 @@ pgControlTestToBuffer(PgControl pgControl)
THROW_FMT(AssertError, "invalid version %u", pgControl.version);
// Generate pg_control
interface->controlTest(pgControl, result);
interface->controlTest(pgControl, bufPtr(result));
FUNCTION_TEST_RETURN(result);
}
@ -474,7 +467,7 @@ pgWalTestToBuffer(PgWal pgWal, Buffer *walBuffer)
// Find the interface for the version of PostgreSQL
const PgInterface *interface = NULL;
for (unsigned int interfaceIdx = 0; interfaceIdx < sizeof(pgInterface) / sizeof(PgInterface); interfaceIdx++)
for (unsigned int interfaceIdx = 0; interfaceIdx < PG_INTERFACE_SIZE; interfaceIdx++)
{
if (pgInterface[interfaceIdx].version == pgWal.version)
{
@ -488,7 +481,7 @@ pgWalTestToBuffer(PgWal pgWal, Buffer *walBuffer)
THROW_FMT(AssertError, "invalid version %u", pgWal.version);
// Generate pg_control
interface->walTest(pgWal, walBuffer);
interface->walTest(pgWal, bufPtr(walBuffer));
FUNCTION_TEST_RETURN_VOID();
}

View File

@ -1,236 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 8.3 Types
***********************************************************************************************************************************/
/***********************************************************************************************************************************
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uint32 TransactionId;
/* MultiXactId must be equivalent to TransactionId, to fit in t_xmax */
typedef TransactionId MultiXactId;
typedef uint32 MultiXactOffset;
/***********************************************************************************************************************************
Types from src/include/postgres_ext.h
***********************************************************************************************************************************/
/*
* Object ID is a fundamental type in Postgres.
*/
typedef unsigned int Oid;
/***********************************************************************************************************************************
Types from src/include/utils/pg_crc32.h
***********************************************************************************************************************************/
typedef uint32 pg_crc32;
/***********************************************************************************************************************************
Types from src/include/access/xlogdefs.h
***********************************************************************************************************************************/
/*
* Pointer to a location in the XLOG. These pointers are 64 bits wide,
* because we don't want them ever to overflow.
*
* NOTE: xrecoff == 0 is used to indicate an invalid pointer. This is OK
* because we use page headers in the XLOG, so no XLOG record can start
* right at the beginning of a file.
*
* NOTE: the "log file number" is somewhat misnamed, since the actual files
* making up the XLOG are much smaller than 4Gb. Each actual file is an
* XLogSegSize-byte "segment" of a logical log file having the indicated
* xlogid. The log file number and segment number together identify a
* physical XLOG file. Segment number and offset within the physical file
* are computed from xrecoff div and mod XLogSegSize.
*/
typedef struct XLogRecPtr
{
uint32 xlogid; /* log file #, 0 based */
uint32 xrecoff; /* byte offset of location in log file */
} XLogRecPtr;
/*
* TimeLineID (TLI) - identifies different database histories to prevent
* confusion after restoring a prior state of a database installation.
* TLI does not change in a normal stop/restart of the database (including
* crash-and-recover cases); but we must assign a new TLI after doing
* a recovery to a prior state, a/k/a point-in-time recovery. This makes
* the new WAL logfile sequence we generate distinguishable from the
* sequence that was generated in the previous incarnation.
*/
typedef uint32 TimeLineID;
/***********************************************************************************************************************************
Types from src/include/catalog/catversion.h
***********************************************************************************************************************************/
/*
* We could use anything we wanted for version numbers, but I recommend
* following the "YYYYMMDDN" style often used for DNS zone serial numbers.
* YYYYMMDD are the date of the change, and N is the number of the change
* on that day. (Hopefully we'll never commit ten independent sets of
* catalog changes on the same day...)
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200711281
/***********************************************************************************************************************************
Types from src/include/catalog/pg_control.h
***********************************************************************************************************************************/
/* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 833
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
* a copy of the latest one in pg_control for possible disaster recovery.
*/
typedef struct CheckPoint
{
XLogRecPtr redo; /* next RecPtr available when we began to
* create CheckPoint (i.e. REDO start point) */
TimeLineID ThisTimeLineID; /* current TLI */
uint32 nextXidEpoch; /* higher-order bits of nextXid */
TransactionId nextXid; /* next free XID */
Oid nextOid; /* next free OID */
MultiXactId nextMulti; /* next free MultiXactId */
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
time_t time; /* time stamp of checkpoint */
} CheckPoint;
/* System status indicator */
typedef enum DBState
{
DB_STARTUP = 0,
DB_SHUTDOWNED,
DB_SHUTDOWNING,
DB_IN_CRASH_RECOVERY,
DB_IN_ARCHIVE_RECOVERY,
DB_IN_PRODUCTION
} DBState;
#define LOCALE_NAME_BUFLEN 128
/*
* Contents of pg_control.
*
* NOTE: try to keep this under 512 bytes so that it will fit on one physical
* sector of typical disk drives. This reduces the odds of corruption due to
* power failure midway through a write. Currently it fits comfortably,
* but we could probably reduce LOCALE_NAME_BUFLEN if things get tight.
*/
typedef struct ControlFileData
{
/*
* Unique system identifier --- to ensure we match up xlog files with the
* installation that produced them.
*/
uint64 system_identifier;
/*
* Version identifier information. Keep these fields at the same offset,
* especially pg_control_version; they won't be real useful if they move
* around. (For historical reasons they must be 8 bytes into the file
* rather than immediately at the front.)
*
* pg_control_version identifies the format of pg_control itself.
* catalog_version_no identifies the format of the system catalogs.
*
* There are additional version identifiers in individual files; for
* example, WAL logs contain per-page magic numbers that can serve as
* version cues for the WAL log.
*/
uint32 pg_control_version; /* PG_CONTROL_VERSION */
uint32 catalog_version_no; /* see catversion.h */
/*
* System status data
*/
DBState state; /* see enum above */
time_t time; /* time stamp of last pg_control update */
XLogRecPtr checkPoint; /* last check point record ptr */
XLogRecPtr prevCheckPoint; /* previous check point record ptr */
CheckPoint checkPointCopy; /* copy of last check point record */
XLogRecPtr minRecoveryPoint; /* must replay xlog to here */
/*
* This data is used to check for hardware-architecture compatibility of
* the database and the backend executable. We need not check endianness
* explicitly, since the pg_control version will surely look wrong to a
* machine of different endianness, but we do need to worry about MAXALIGN
* and floating-point format. (Note: storage layout nominally also
* depends on SHORTALIGN and INTALIGN, but in practice these are the same
* on all architectures of interest.)
*
* Testing just one double value is not a very bulletproof test for
* floating-point compatibility, but it will catch most cases.
*/
uint32 maxAlign; /* alignment requirement for tuples */
double floatFormat; /* constant 1234567.0 */
#define FLOATFORMAT_VALUE 1234567.0
/*
* This data is used to make sure that configuration of this database is
* compatible with the backend executable.
*/
uint32 blcksz; /* data block size for this DB */
uint32 relseg_size; /* blocks per segment of large relation */
uint32 xlog_blcksz; /* block size within WAL files */
uint32 xlog_seg_size; /* size of each WAL segment */
uint32 nameDataLen; /* catalog name field width */
uint32 indexMaxKeys; /* max number of columns in an index */
uint32 toast_max_chunk_size; /* chunk size in TOAST tables */
/* flag indicating internal format of timestamp, interval, time */
uint32 enableIntTimes; /* int64 storage enabled? */
/* active locales */
uint32 localeBuflen;
char lc_collate[LOCALE_NAME_BUFLEN];
char lc_ctype[LOCALE_NAME_BUFLEN];
/* CRC of all above ... MUST BE LAST! */
pg_crc32 crc;
} ControlFileData;
/***********************************************************************************************************************************
Types from src/include/access/xlog_internal.h
***********************************************************************************************************************************/
/*
* Each page of XLOG file has a header like this:
*/
#define XLOG_PAGE_MAGIC 0xD062 /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData
{
uint16 xlp_magic; /* magic value for correctness checks */
uint16 xlp_info; /* flag bits, see below */
TimeLineID xlp_tli; /* TimeLineID of first record on page */
XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
} XLogPageHeaderData;
/*
* When the XLP_LONG_HEADER flag is set, we store additional fields in the
* page header. (This is ordinarily done just in the first page of an
* XLOG file.) The additional fields serve to identify the file accurately.
*/
typedef struct XLogLongPageHeaderData
{
XLogPageHeaderData std; /* standard header fields */
uint64 xlp_sysid; /* system identifier from pg_control */
uint32 xlp_seg_size; /* just as a cross-check */
uint32 xlp_xlog_blcksz; /* just as a cross-check */
} XLogLongPageHeaderData;
/* This flag indicates a "long" page header */
#define XLP_LONG_HEADER 0x0002

View File

@ -1,121 +1,10 @@
/***********************************************************************************************************************************
PostgreSQL 8.3 Interface
See postgres/interface.c for documentation.
See postgres/interface/version.intern.h for documentation.
***********************************************************************************************************************************/
#include "common/debug.h"
#include "common/log.h"
#include "postgres/interface/v083.h"
#define PG_VERSION PG_VERSION_83
#include "postgres/interface/v083.auto.c"
#include "postgres/interface/version.intern.h"
/**********************************************************************************************************************************/
bool
pgInterfaceControlIs083(const Buffer *controlFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(controlFile != NULL);
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
FUNCTION_TEST_RETURN(
controlData->pg_control_version == PG_CONTROL_VERSION && controlData->catalog_version_no == CATALOG_VERSION_NO);
}
/**********************************************************************************************************************************/
PgControl
pgInterfaceControl083(const Buffer *controlFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, controlFile);
FUNCTION_LOG_END();
ASSERT(controlFile != NULL);
ASSERT(pgInterfaceControlIs083(controlFile));
PgControl result = {0};
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
result.systemId = controlData->system_identifier;
result.controlVersion = controlData->pg_control_version;
result.catalogVersion = controlData->catalog_version_no;
result.pageSize = controlData->blcksz;
result.walSegmentSize = controlData->xlog_seg_size;
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
/**********************************************************************************************************************************/
bool
pgInterfaceWalIs083(const Buffer *walFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(walFile != NULL);
FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
}
/**********************************************************************************************************************************/
PgWal
pgInterfaceWal083(const Buffer *walFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, walFile);
FUNCTION_LOG_END();
ASSERT(walFile != NULL);
ASSERT(pgInterfaceWalIs083(walFile));
PgWal result = {0};
result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
FUNCTION_LOG_RETURN(PG_WAL, result);
}
#ifdef DEBUG
/**********************************************************************************************************************************/
void
pgInterfaceControlTest083(PgControl pgControl, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_CONTROL, pgControl);
FUNCTION_TEST_END();
ControlFileData *controlData = (ControlFileData *)bufPtr(buffer);
controlData->system_identifier = pgControl.systemId;
controlData->pg_control_version = pgControl.controlVersion == 0 ? PG_CONTROL_VERSION : pgControl.controlVersion;
controlData->catalog_version_no = pgControl.catalogVersion == 0 ? CATALOG_VERSION_NO : pgControl.catalogVersion;
controlData->blcksz = pgControl.pageSize;
controlData->xlog_seg_size = pgControl.walSegmentSize;
FUNCTION_TEST_RETURN_VOID();
}
/**********************************************************************************************************************************/
void
pgInterfaceWalTest083(PgWal pgWal, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_WAL, pgWal);
FUNCTION_TEST_END();
XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
walData->std.xlp_magic = XLOG_PAGE_MAGIC;
walData->xlp_sysid = pgWal.systemId;
FUNCTION_TEST_RETURN_VOID();
}
#endif
PG_INTERFACE(083);

View File

@ -1,25 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 8.3 Interface
***********************************************************************************************************************************/
#ifndef POSTGRES_INTERFACE_INTERFACE083_H
#define POSTGRES_INTERFACE_INTERFACE083_H
#include "postgres/interface.h"
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs083(const Buffer *controlFile);
PgControl pgInterfaceControl083(const Buffer *controlFile);
bool pgInterfaceWalIs083(const Buffer *walFile);
PgWal pgInterfaceWal083(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest083(PgControl pgControl, Buffer *buffer);
void pgInterfaceWalTest083(PgWal pgWal, Buffer *buffer);
#endif
#endif

View File

@ -1,241 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 8.4 Types
***********************************************************************************************************************************/
/***********************************************************************************************************************************
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uint32 TransactionId;
/* MultiXactId must be equivalent to TransactionId, to fit in t_xmax */
typedef TransactionId MultiXactId;
typedef uint32 MultiXactOffset;
/***********************************************************************************************************************************
Types from src/include/pgtime.h
***********************************************************************************************************************************/
/*
* The API of this library is generally similar to the corresponding
* C library functions, except that we use pg_time_t which (we hope) is
* 64 bits wide, and which is most definitely signed not unsigned.
*/
typedef int64 pg_time_t;
/***********************************************************************************************************************************
Types from src/include/postgres_ext.h
***********************************************************************************************************************************/
/*
* Object ID is a fundamental type in Postgres.
*/
typedef unsigned int Oid;
/***********************************************************************************************************************************
Types from src/include/utils/pg_crc32.h
***********************************************************************************************************************************/
typedef uint32 pg_crc32;
/***********************************************************************************************************************************
Types from src/include/access/xlogdefs.h
***********************************************************************************************************************************/
/*
* Pointer to a location in the XLOG. These pointers are 64 bits wide,
* because we don't want them ever to overflow.
*
* NOTE: xrecoff == 0 is used to indicate an invalid pointer. This is OK
* because we use page headers in the XLOG, so no XLOG record can start
* right at the beginning of a file.
*
* NOTE: the "log file number" is somewhat misnamed, since the actual files
* making up the XLOG are much smaller than 4Gb. Each actual file is an
* XLogSegSize-byte "segment" of a logical log file having the indicated
* xlogid. The log file number and segment number together identify a
* physical XLOG file. Segment number and offset within the physical file
* are computed from xrecoff div and mod XLogSegSize.
*/
typedef struct XLogRecPtr
{
uint32 xlogid; /* log file #, 0 based */
uint32 xrecoff; /* byte offset of location in log file */
} XLogRecPtr;
/*
* TimeLineID (TLI) - identifies different database histories to prevent
* confusion after restoring a prior state of a database installation.
* TLI does not change in a normal stop/restart of the database (including
* crash-and-recover cases); but we must assign a new TLI after doing
* a recovery to a prior state, a/k/a point-in-time recovery. This makes
* the new WAL logfile sequence we generate distinguishable from the
* sequence that was generated in the previous incarnation.
*/
typedef uint32 TimeLineID;
/***********************************************************************************************************************************
Types from src/include/catalog/catversion.h
***********************************************************************************************************************************/
/*
* We could use anything we wanted for version numbers, but I recommend
* following the "YYYYMMDDN" style often used for DNS zone serial numbers.
* YYYYMMDD are the date of the change, and N is the number of the change
* on that day. (Hopefully we'll never commit ten independent sets of
* catalog changes on the same day...)
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200904091
/***********************************************************************************************************************************
Types from src/include/catalog/pg_control.h
***********************************************************************************************************************************/
/* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 843
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
* a copy of the latest one in pg_control for possible disaster recovery.
*/
typedef struct CheckPoint
{
XLogRecPtr redo; /* next RecPtr available when we began to
* create CheckPoint (i.e. REDO start point) */
TimeLineID ThisTimeLineID; /* current TLI */
uint32 nextXidEpoch; /* higher-order bits of nextXid */
TransactionId nextXid; /* next free XID */
Oid nextOid; /* next free OID */
MultiXactId nextMulti; /* next free MultiXactId */
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
pg_time_t time; /* time stamp of checkpoint */
} CheckPoint;
/* System status indicator */
typedef enum DBState
{
DB_STARTUP = 0,
DB_SHUTDOWNED,
DB_SHUTDOWNING,
DB_IN_CRASH_RECOVERY,
DB_IN_ARCHIVE_RECOVERY,
DB_IN_PRODUCTION
} DBState;
/*
* Contents of pg_control.
*
* NOTE: try to keep this under 512 bytes so that it will fit on one physical
* sector of typical disk drives. This reduces the odds of corruption due to
* power failure midway through a write.
*/
typedef struct ControlFileData
{
/*
* Unique system identifier --- to ensure we match up xlog files with the
* installation that produced them.
*/
uint64 system_identifier;
/*
* Version identifier information. Keep these fields at the same offset,
* especially pg_control_version; they won't be real useful if they move
* around. (For historical reasons they must be 8 bytes into the file
* rather than immediately at the front.)
*
* pg_control_version identifies the format of pg_control itself.
* catalog_version_no identifies the format of the system catalogs.
*
* There are additional version identifiers in individual files; for
* example, WAL logs contain per-page magic numbers that can serve as
* version cues for the WAL log.
*/
uint32 pg_control_version; /* PG_CONTROL_VERSION */
uint32 catalog_version_no; /* see catversion.h */
/*
* System status data
*/
DBState state; /* see enum above */
pg_time_t time; /* time stamp of last pg_control update */
XLogRecPtr checkPoint; /* last check point record ptr */
XLogRecPtr prevCheckPoint; /* previous check point record ptr */
CheckPoint checkPointCopy; /* copy of last check point record */
XLogRecPtr minRecoveryPoint; /* must replay xlog to here */
/*
* This data is used to check for hardware-architecture compatibility of
* the database and the backend executable. We need not check endianness
* explicitly, since the pg_control version will surely look wrong to a
* machine of different endianness, but we do need to worry about MAXALIGN
* and floating-point format. (Note: storage layout nominally also
* depends on SHORTALIGN and INTALIGN, but in practice these are the same
* on all architectures of interest.)
*
* Testing just one double value is not a very bulletproof test for
* floating-point compatibility, but it will catch most cases.
*/
uint32 maxAlign; /* alignment requirement for tuples */
double floatFormat; /* constant 1234567.0 */
#define FLOATFORMAT_VALUE 1234567.0
/*
* This data is used to make sure that configuration of this database is
* compatible with the backend executable.
*/
uint32 blcksz; /* data block size for this DB */
uint32 relseg_size; /* blocks per segment of large relation */
uint32 xlog_blcksz; /* block size within WAL files */
uint32 xlog_seg_size; /* size of each WAL segment */
uint32 nameDataLen; /* catalog name field width */
uint32 indexMaxKeys; /* max number of columns in an index */
uint32 toast_max_chunk_size; /* chunk size in TOAST tables */
/* flag indicating internal format of timestamp, interval, time */
bool enableIntTimes; /* int64 storage enabled? */
/* flags indicating pass-by-value status of various types */
bool float4ByVal; /* float4 pass-by-value? */
bool float8ByVal; /* float8, int8, etc pass-by-value? */
/* CRC of all above ... MUST BE LAST! */
pg_crc32 crc;
} ControlFileData;
/***********************************************************************************************************************************
Types from src/include/access/xlog_internal.h
***********************************************************************************************************************************/
/*
* Each page of XLOG file has a header like this:
*/
#define XLOG_PAGE_MAGIC 0xD063 /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData
{
uint16 xlp_magic; /* magic value for correctness checks */
uint16 xlp_info; /* flag bits, see below */
TimeLineID xlp_tli; /* TimeLineID of first record on page */
XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
} XLogPageHeaderData;
/*
* When the XLP_LONG_HEADER flag is set, we store additional fields in the
* page header. (This is ordinarily done just in the first page of an
* XLOG file.) The additional fields serve to identify the file accurately.
*/
typedef struct XLogLongPageHeaderData
{
XLogPageHeaderData std; /* standard header fields */
uint64 xlp_sysid; /* system identifier from pg_control */
uint32 xlp_seg_size; /* just as a cross-check */
uint32 xlp_xlog_blcksz; /* just as a cross-check */
} XLogLongPageHeaderData;
/* This flag indicates a "long" page header */
#define XLP_LONG_HEADER 0x0002

View File

@ -1,121 +1,10 @@
/***********************************************************************************************************************************
PostgreSQL 8.4 Interface
See postgres/interface.c for documentation.
See postgres/interface/version.intern.h for documentation.
***********************************************************************************************************************************/
#include "common/debug.h"
#include "common/log.h"
#include "postgres/interface/v084.h"
#define PG_VERSION PG_VERSION_84
#include "postgres/interface/v084.auto.c"
#include "postgres/interface/version.intern.h"
/**********************************************************************************************************************************/
bool
pgInterfaceControlIs084(const Buffer *controlFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(controlFile != NULL);
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
FUNCTION_TEST_RETURN(
controlData->pg_control_version == PG_CONTROL_VERSION && controlData->catalog_version_no == CATALOG_VERSION_NO);
}
/**********************************************************************************************************************************/
PgControl
pgInterfaceControl084(const Buffer *controlFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, controlFile);
FUNCTION_LOG_END();
ASSERT(controlFile != NULL);
ASSERT(pgInterfaceControlIs084(controlFile));
PgControl result = {0};
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
result.systemId = controlData->system_identifier;
result.controlVersion = controlData->pg_control_version;
result.catalogVersion = controlData->catalog_version_no;
result.pageSize = controlData->blcksz;
result.walSegmentSize = controlData->xlog_seg_size;
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
/**********************************************************************************************************************************/
bool
pgInterfaceWalIs084(const Buffer *walFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(walFile != NULL);
FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
}
/**********************************************************************************************************************************/
PgWal
pgInterfaceWal084(const Buffer *walFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, walFile);
FUNCTION_LOG_END();
ASSERT(walFile != NULL);
ASSERT(pgInterfaceWalIs084(walFile));
PgWal result = {0};
result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
FUNCTION_LOG_RETURN(PG_WAL, result);
}
#ifdef DEBUG
/**********************************************************************************************************************************/
void
pgInterfaceControlTest084(PgControl pgControl, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_CONTROL, pgControl);
FUNCTION_TEST_END();
ControlFileData *controlData = (ControlFileData *)bufPtr(buffer);
controlData->system_identifier = pgControl.systemId;
controlData->pg_control_version = pgControl.controlVersion == 0 ? PG_CONTROL_VERSION : pgControl.controlVersion;
controlData->catalog_version_no = pgControl.catalogVersion == 0 ? CATALOG_VERSION_NO : pgControl.catalogVersion;
controlData->blcksz = pgControl.pageSize;
controlData->xlog_seg_size = pgControl.walSegmentSize;
FUNCTION_TEST_RETURN_VOID();
}
/**********************************************************************************************************************************/
void
pgInterfaceWalTest084(PgWal pgWal, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_WAL, pgWal);
FUNCTION_TEST_END();
XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
walData->std.xlp_magic = XLOG_PAGE_MAGIC;
walData->xlp_sysid = pgWal.systemId;
FUNCTION_TEST_RETURN_VOID();
}
#endif
PG_INTERFACE(084);

View File

@ -1,25 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 8.4 Interface
***********************************************************************************************************************************/
#ifndef POSTGRES_INTERFACE_INTERFACE084_H
#define POSTGRES_INTERFACE_INTERFACE084_H
#include "postgres/interface.h"
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs084(const Buffer *controlFile);
PgControl pgInterfaceControl084(const Buffer *controlFile);
bool pgInterfaceWalIs084(const Buffer *walFile);
PgWal pgInterfaceWal084(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest084(PgControl pgControl, Buffer *buffer);
void pgInterfaceWalTest084(PgWal pgWal, Buffer *buffer);
#endif
#endif

View File

@ -1,285 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 9.0 Types
***********************************************************************************************************************************/
/***********************************************************************************************************************************
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uint32 TransactionId;
/* MultiXactId must be equivalent to TransactionId, to fit in t_xmax */
typedef TransactionId MultiXactId;
typedef uint32 MultiXactOffset;
/***********************************************************************************************************************************
Types from src/include/pgtime.h
***********************************************************************************************************************************/
/*
* The API of this library is generally similar to the corresponding
* C library functions, except that we use pg_time_t which (we hope) is
* 64 bits wide, and which is most definitely signed not unsigned.
*/
typedef int64 pg_time_t;
/***********************************************************************************************************************************
Types from src/include/postgres_ext.h
***********************************************************************************************************************************/
/*
* Object ID is a fundamental type in Postgres.
*/
typedef unsigned int Oid;
/***********************************************************************************************************************************
Types from src/include/utils/pg_crc32.h
***********************************************************************************************************************************/
typedef uint32 pg_crc32;
/***********************************************************************************************************************************
Types from src/include/access/xlogdefs.h
***********************************************************************************************************************************/
/*
* Pointer to a location in the XLOG. These pointers are 64 bits wide,
* because we don't want them ever to overflow.
*
* NOTE: xrecoff == 0 is used to indicate an invalid pointer. This is OK
* because we use page headers in the XLOG, so no XLOG record can start
* right at the beginning of a file.
*
* NOTE: the "log file number" is somewhat misnamed, since the actual files
* making up the XLOG are much smaller than 4Gb. Each actual file is an
* XLogSegSize-byte "segment" of a logical log file having the indicated
* xlogid. The log file number and segment number together identify a
* physical XLOG file. Segment number and offset within the physical file
* are computed from xrecoff div and mod XLogSegSize.
*/
typedef struct XLogRecPtr
{
uint32 xlogid; /* log file #, 0 based */
uint32 xrecoff; /* byte offset of location in log file */
} XLogRecPtr;
/*
* TimeLineID (TLI) - identifies different database histories to prevent
* confusion after restoring a prior state of a database installation.
* TLI does not change in a normal stop/restart of the database (including
* crash-and-recover cases); but we must assign a new TLI after doing
* a recovery to a prior state, a/k/a point-in-time recovery. This makes
* the new WAL logfile sequence we generate distinguishable from the
* sequence that was generated in the previous incarnation.
*/
typedef uint32 TimeLineID;
/***********************************************************************************************************************************
Types from src/include/catalog/catversion.h
***********************************************************************************************************************************/
/*
* We could use anything we wanted for version numbers, but I recommend
* following the "YYYYMMDDN" style often used for DNS zone serial numbers.
* YYYYMMDD are the date of the change, and N is the number of the change
* on that day. (Hopefully we'll never commit ten independent sets of
* catalog changes on the same day...)
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201008051
/***********************************************************************************************************************************
Types from src/include/catalog/pg_control.h
***********************************************************************************************************************************/
/* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 903
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
* a copy of the latest one in pg_control for possible disaster recovery.
* Changing this struct requires a PG_CONTROL_VERSION bump.
*/
typedef struct CheckPoint
{
XLogRecPtr redo; /* next RecPtr available when we began to
* create CheckPoint (i.e. REDO start point) */
TimeLineID ThisTimeLineID; /* current TLI */
uint32 nextXidEpoch; /* higher-order bits of nextXid */
TransactionId nextXid; /* next free XID */
Oid nextOid; /* next free OID */
MultiXactId nextMulti; /* next free MultiXactId */
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
Oid oldestXidDB; /* database with minimum datfrozenxid */
pg_time_t time; /* time stamp of checkpoint */
/*
* Oldest XID still running. This is only needed to initialize hot standby
* mode from an online checkpoint, so we only bother calculating this for
* online checkpoints and only when wal_level is hot_standby. Otherwise it's
* set to InvalidTransactionId.
*/
TransactionId oldestActiveXid;
} CheckPoint;
/*
* System status indicator. Note this is stored in pg_control; if you change
* it, you must bump PG_CONTROL_VERSION
*/
typedef enum DBState
{
DB_STARTUP = 0,
DB_SHUTDOWNED,
DB_SHUTDOWNED_IN_RECOVERY,
DB_SHUTDOWNING,
DB_IN_CRASH_RECOVERY,
DB_IN_ARCHIVE_RECOVERY,
DB_IN_PRODUCTION
} DBState;
/*
* Contents of pg_control.
*
* NOTE: try to keep this under 512 bytes so that it will fit on one physical
* sector of typical disk drives. This reduces the odds of corruption due to
* power failure midway through a write.
*/
typedef struct ControlFileData
{
/*
* Unique system identifier --- to ensure we match up xlog files with the
* installation that produced them.
*/
uint64 system_identifier;
/*
* Version identifier information. Keep these fields at the same offset,
* especially pg_control_version; they won't be real useful if they move
* around. (For historical reasons they must be 8 bytes into the file
* rather than immediately at the front.)
*
* pg_control_version identifies the format of pg_control itself.
* catalog_version_no identifies the format of the system catalogs.
*
* There are additional version identifiers in individual files; for
* example, WAL logs contain per-page magic numbers that can serve as
* version cues for the WAL log.
*/
uint32 pg_control_version; /* PG_CONTROL_VERSION */
uint32 catalog_version_no; /* see catversion.h */
/*
* System status data
*/
DBState state; /* see enum above */
pg_time_t time; /* time stamp of last pg_control update */
XLogRecPtr checkPoint; /* last check point record ptr */
XLogRecPtr prevCheckPoint; /* previous check point record ptr */
CheckPoint checkPointCopy; /* copy of last check point record */
/*
* These two values determine the minimum point we must recover up to
* before starting up:
*
* minRecoveryPoint is updated to the latest replayed LSN whenever we
* flush a data change during archive recovery. That guards against
* starting archive recovery, aborting it, and restarting with an earlier
* stop location. If we've already flushed data changes from WAL record X
* to disk, we mustn't start up until we reach X again. Zero when not
* doing archive recovery.
*
* backupStartPoint is the redo pointer of the backup start checkpoint, if
* we are recovering from an online backup and haven't reached the end of
* backup yet. It is reset to zero when the end of backup is reached, and
* we mustn't start up before that. A boolean would suffice otherwise, but
* we use the redo pointer as a cross-check when we see an end-of-backup
* record, to make sure the end-of-backup record corresponds the base
* backup we're recovering from.
*/
XLogRecPtr minRecoveryPoint;
XLogRecPtr backupStartPoint;
/*
* Parameter settings that determine if the WAL can be used for archival
* or hot standby.
*/
int wal_level;
int MaxConnections;
int max_prepared_xacts;
int max_locks_per_xact;
/*
* This data is used to check for hardware-architecture compatibility of
* the database and the backend executable. We need not check endianness
* explicitly, since the pg_control version will surely look wrong to a
* machine of different endianness, but we do need to worry about MAXALIGN
* and floating-point format. (Note: storage layout nominally also
* depends on SHORTALIGN and INTALIGN, but in practice these are the same
* on all architectures of interest.)
*
* Testing just one double value is not a very bulletproof test for
* floating-point compatibility, but it will catch most cases.
*/
uint32 maxAlign; /* alignment requirement for tuples */
double floatFormat; /* constant 1234567.0 */
#define FLOATFORMAT_VALUE 1234567.0
/*
* This data is used to make sure that configuration of this database is
* compatible with the backend executable.
*/
uint32 blcksz; /* data block size for this DB */
uint32 relseg_size; /* blocks per segment of large relation */
uint32 xlog_blcksz; /* block size within WAL files */
uint32 xlog_seg_size; /* size of each WAL segment */
uint32 nameDataLen; /* catalog name field width */
uint32 indexMaxKeys; /* max number of columns in an index */
uint32 toast_max_chunk_size; /* chunk size in TOAST tables */
/* flag indicating internal format of timestamp, interval, time */
bool enableIntTimes; /* int64 storage enabled? */
/* flags indicating pass-by-value status of various types */
bool float4ByVal; /* float4 pass-by-value? */
bool float8ByVal; /* float8, int8, etc pass-by-value? */
/* CRC of all above ... MUST BE LAST! */
pg_crc32 crc;
} ControlFileData;
/***********************************************************************************************************************************
Types from src/include/access/xlog_internal.h
***********************************************************************************************************************************/
/*
* Each page of XLOG file has a header like this:
*/
#define XLOG_PAGE_MAGIC 0xD064 /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData
{
uint16 xlp_magic; /* magic value for correctness checks */
uint16 xlp_info; /* flag bits, see below */
TimeLineID xlp_tli; /* TimeLineID of first record on page */
XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
} XLogPageHeaderData;
/*
* When the XLP_LONG_HEADER flag is set, we store additional fields in the
* page header. (This is ordinarily done just in the first page of an
* XLOG file.) The additional fields serve to identify the file accurately.
*/
typedef struct XLogLongPageHeaderData
{
XLogPageHeaderData std; /* standard header fields */
uint64 xlp_sysid; /* system identifier from pg_control */
uint32 xlp_seg_size; /* just as a cross-check */
uint32 xlp_xlog_blcksz; /* just as a cross-check */
} XLogLongPageHeaderData;
/* This flag indicates a "long" page header */
#define XLP_LONG_HEADER 0x0002

View File

@ -1,121 +1,10 @@
/***********************************************************************************************************************************
PostgreSQL 9.0 Interface
See postgres/interface.c for documentation.
See postgres/interface/version.intern.h for documentation.
***********************************************************************************************************************************/
#include "common/debug.h"
#include "common/log.h"
#include "postgres/interface/v090.h"
#define PG_VERSION PG_VERSION_90
#include "postgres/interface/v090.auto.c"
#include "postgres/interface/version.intern.h"
/**********************************************************************************************************************************/
bool
pgInterfaceControlIs090(const Buffer *controlFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(controlFile != NULL);
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
FUNCTION_TEST_RETURN(
controlData->pg_control_version == PG_CONTROL_VERSION && controlData->catalog_version_no == CATALOG_VERSION_NO);
}
/**********************************************************************************************************************************/
PgControl
pgInterfaceControl090(const Buffer *controlFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, controlFile);
FUNCTION_LOG_END();
ASSERT(controlFile != NULL);
ASSERT(pgInterfaceControlIs090(controlFile));
PgControl result = {0};
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
result.systemId = controlData->system_identifier;
result.controlVersion = controlData->pg_control_version;
result.catalogVersion = controlData->catalog_version_no;
result.pageSize = controlData->blcksz;
result.walSegmentSize = controlData->xlog_seg_size;
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
/**********************************************************************************************************************************/
bool
pgInterfaceWalIs090(const Buffer *walFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(walFile != NULL);
FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
}
/**********************************************************************************************************************************/
PgWal
pgInterfaceWal090(const Buffer *walFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, walFile);
FUNCTION_LOG_END();
ASSERT(walFile != NULL);
ASSERT(pgInterfaceWalIs090(walFile));
PgWal result = {0};
result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
FUNCTION_LOG_RETURN(PG_WAL, result);
}
#ifdef DEBUG
/**********************************************************************************************************************************/
void
pgInterfaceControlTest090(PgControl pgControl, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_CONTROL, pgControl);
FUNCTION_TEST_END();
ControlFileData *controlData = (ControlFileData *)bufPtr(buffer);
controlData->system_identifier = pgControl.systemId;
controlData->pg_control_version = pgControl.controlVersion == 0 ? PG_CONTROL_VERSION : pgControl.controlVersion;
controlData->catalog_version_no = pgControl.catalogVersion == 0 ? CATALOG_VERSION_NO : pgControl.catalogVersion;
controlData->blcksz = pgControl.pageSize;
controlData->xlog_seg_size = pgControl.walSegmentSize;
FUNCTION_TEST_RETURN_VOID();
}
/**********************************************************************************************************************************/
void
pgInterfaceWalTest090(PgWal pgWal, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_WAL, pgWal);
FUNCTION_TEST_END();
XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
walData->std.xlp_magic = XLOG_PAGE_MAGIC;
walData->xlp_sysid = pgWal.systemId;
FUNCTION_TEST_RETURN_VOID();
}
#endif
PG_INTERFACE(090);

View File

@ -1,25 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 9.0 Interface
***********************************************************************************************************************************/
#ifndef POSTGRES_INTERFACE_INTERFACE090_H
#define POSTGRES_INTERFACE_INTERFACE090_H
#include "postgres/interface.h"
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs090(const Buffer *controlFile);
PgControl pgInterfaceControl090(const Buffer *controlFile);
bool pgInterfaceWalIs090(const Buffer *walFile);
PgWal pgInterfaceWal090(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest090(PgControl pgControl, Buffer *buffer);
void pgInterfaceWalTest090(PgWal pgWal, Buffer *buffer);
#endif
#endif

View File

@ -1,285 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 9.1 Types
***********************************************************************************************************************************/
/***********************************************************************************************************************************
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uint32 TransactionId;
/* MultiXactId must be equivalent to TransactionId, to fit in t_xmax */
typedef TransactionId MultiXactId;
typedef uint32 MultiXactOffset;
/***********************************************************************************************************************************
Types from src/include/pgtime.h
***********************************************************************************************************************************/
/*
* The API of this library is generally similar to the corresponding
* C library functions, except that we use pg_time_t which (we hope) is
* 64 bits wide, and which is most definitely signed not unsigned.
*/
typedef int64 pg_time_t;
/***********************************************************************************************************************************
Types from src/include/postgres_ext.h
***********************************************************************************************************************************/
/*
* Object ID is a fundamental type in Postgres.
*/
typedef unsigned int Oid;
/***********************************************************************************************************************************
Types from src/include/utils/pg_crc32.h
***********************************************************************************************************************************/
typedef uint32 pg_crc32;
/***********************************************************************************************************************************
Types from src/include/access/xlogdefs.h
***********************************************************************************************************************************/
/*
* Pointer to a location in the XLOG. These pointers are 64 bits wide,
* because we don't want them ever to overflow.
*
* NOTE: xrecoff == 0 is used to indicate an invalid pointer. This is OK
* because we use page headers in the XLOG, so no XLOG record can start
* right at the beginning of a file.
*
* NOTE: the "log file number" is somewhat misnamed, since the actual files
* making up the XLOG are much smaller than 4Gb. Each actual file is an
* XLogSegSize-byte "segment" of a logical log file having the indicated
* xlogid. The log file number and segment number together identify a
* physical XLOG file. Segment number and offset within the physical file
* are computed from xrecoff div and mod XLogSegSize.
*/
typedef struct XLogRecPtr
{
uint32 xlogid; /* log file #, 0 based */
uint32 xrecoff; /* byte offset of location in log file */
} XLogRecPtr;
/*
* TimeLineID (TLI) - identifies different database histories to prevent
* confusion after restoring a prior state of a database installation.
* TLI does not change in a normal stop/restart of the database (including
* crash-and-recover cases); but we must assign a new TLI after doing
* a recovery to a prior state, a/k/a point-in-time recovery. This makes
* the new WAL logfile sequence we generate distinguishable from the
* sequence that was generated in the previous incarnation.
*/
typedef uint32 TimeLineID;
/***********************************************************************************************************************************
Types from src/include/catalog/catversion.h
***********************************************************************************************************************************/
/*
* We could use anything we wanted for version numbers, but I recommend
* following the "YYYYMMDDN" style often used for DNS zone serial numbers.
* YYYYMMDD are the date of the change, and N is the number of the change
* on that day. (Hopefully we'll never commit ten independent sets of
* catalog changes on the same day...)
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201105231
/***********************************************************************************************************************************
Types from src/include/catalog/pg_control.h
***********************************************************************************************************************************/
/* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 903
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
* a copy of the latest one in pg_control for possible disaster recovery.
* Changing this struct requires a PG_CONTROL_VERSION bump.
*/
typedef struct CheckPoint
{
XLogRecPtr redo; /* next RecPtr available when we began to
* create CheckPoint (i.e. REDO start point) */
TimeLineID ThisTimeLineID; /* current TLI */
uint32 nextXidEpoch; /* higher-order bits of nextXid */
TransactionId nextXid; /* next free XID */
Oid nextOid; /* next free OID */
MultiXactId nextMulti; /* next free MultiXactId */
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
Oid oldestXidDB; /* database with minimum datfrozenxid */
pg_time_t time; /* time stamp of checkpoint */
/*
* Oldest XID still running. This is only needed to initialize hot standby
* mode from an online checkpoint, so we only bother calculating this for
* online checkpoints and only when wal_level is hot_standby. Otherwise
* it's set to InvalidTransactionId.
*/
TransactionId oldestActiveXid;
} CheckPoint;
/*
* System status indicator. Note this is stored in pg_control; if you change
* it, you must bump PG_CONTROL_VERSION
*/
typedef enum DBState
{
DB_STARTUP = 0,
DB_SHUTDOWNED,
DB_SHUTDOWNED_IN_RECOVERY,
DB_SHUTDOWNING,
DB_IN_CRASH_RECOVERY,
DB_IN_ARCHIVE_RECOVERY,
DB_IN_PRODUCTION
} DBState;
/*
* Contents of pg_control.
*
* NOTE: try to keep this under 512 bytes so that it will fit on one physical
* sector of typical disk drives. This reduces the odds of corruption due to
* power failure midway through a write.
*/
typedef struct ControlFileData
{
/*
* Unique system identifier --- to ensure we match up xlog files with the
* installation that produced them.
*/
uint64 system_identifier;
/*
* Version identifier information. Keep these fields at the same offset,
* especially pg_control_version; they won't be real useful if they move
* around. (For historical reasons they must be 8 bytes into the file
* rather than immediately at the front.)
*
* pg_control_version identifies the format of pg_control itself.
* catalog_version_no identifies the format of the system catalogs.
*
* There are additional version identifiers in individual files; for
* example, WAL logs contain per-page magic numbers that can serve as
* version cues for the WAL log.
*/
uint32 pg_control_version; /* PG_CONTROL_VERSION */
uint32 catalog_version_no; /* see catversion.h */
/*
* System status data
*/
DBState state; /* see enum above */
pg_time_t time; /* time stamp of last pg_control update */
XLogRecPtr checkPoint; /* last check point record ptr */
XLogRecPtr prevCheckPoint; /* previous check point record ptr */
CheckPoint checkPointCopy; /* copy of last check point record */
/*
* These two values determine the minimum point we must recover up to
* before starting up:
*
* minRecoveryPoint is updated to the latest replayed LSN whenever we
* flush a data change during archive recovery. That guards against
* starting archive recovery, aborting it, and restarting with an earlier
* stop location. If we've already flushed data changes from WAL record X
* to disk, we mustn't start up until we reach X again. Zero when not
* doing archive recovery.
*
* backupStartPoint is the redo pointer of the backup start checkpoint, if
* we are recovering from an online backup and haven't reached the end of
* backup yet. It is reset to zero when the end of backup is reached, and
* we mustn't start up before that. A boolean would suffice otherwise, but
* we use the redo pointer as a cross-check when we see an end-of-backup
* record, to make sure the end-of-backup record corresponds the base
* backup we're recovering from.
*/
XLogRecPtr minRecoveryPoint;
XLogRecPtr backupStartPoint;
/*
* Parameter settings that determine if the WAL can be used for archival
* or hot standby.
*/
int wal_level;
int MaxConnections;
int max_prepared_xacts;
int max_locks_per_xact;
/*
* This data is used to check for hardware-architecture compatibility of
* the database and the backend executable. We need not check endianness
* explicitly, since the pg_control version will surely look wrong to a
* machine of different endianness, but we do need to worry about MAXALIGN
* and floating-point format. (Note: storage layout nominally also
* depends on SHORTALIGN and INTALIGN, but in practice these are the same
* on all architectures of interest.)
*
* Testing just one double value is not a very bulletproof test for
* floating-point compatibility, but it will catch most cases.
*/
uint32 maxAlign; /* alignment requirement for tuples */
double floatFormat; /* constant 1234567.0 */
#define FLOATFORMAT_VALUE 1234567.0
/*
* This data is used to make sure that configuration of this database is
* compatible with the backend executable.
*/
uint32 blcksz; /* data block size for this DB */
uint32 relseg_size; /* blocks per segment of large relation */
uint32 xlog_blcksz; /* block size within WAL files */
uint32 xlog_seg_size; /* size of each WAL segment */
uint32 nameDataLen; /* catalog name field width */
uint32 indexMaxKeys; /* max number of columns in an index */
uint32 toast_max_chunk_size; /* chunk size in TOAST tables */
/* flag indicating internal format of timestamp, interval, time */
bool enableIntTimes; /* int64 storage enabled? */
/* flags indicating pass-by-value status of various types */
bool float4ByVal; /* float4 pass-by-value? */
bool float8ByVal; /* float8, int8, etc pass-by-value? */
/* CRC of all above ... MUST BE LAST! */
pg_crc32 crc;
} ControlFileData;
/***********************************************************************************************************************************
Types from src/include/access/xlog_internal.h
***********************************************************************************************************************************/
/*
* Each page of XLOG file has a header like this:
*/
#define XLOG_PAGE_MAGIC 0xD066 /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData
{
uint16 xlp_magic; /* magic value for correctness checks */
uint16 xlp_info; /* flag bits, see below */
TimeLineID xlp_tli; /* TimeLineID of first record on page */
XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
} XLogPageHeaderData;
/*
* When the XLP_LONG_HEADER flag is set, we store additional fields in the
* page header. (This is ordinarily done just in the first page of an
* XLOG file.) The additional fields serve to identify the file accurately.
*/
typedef struct XLogLongPageHeaderData
{
XLogPageHeaderData std; /* standard header fields */
uint64 xlp_sysid; /* system identifier from pg_control */
uint32 xlp_seg_size; /* just as a cross-check */
uint32 xlp_xlog_blcksz; /* just as a cross-check */
} XLogLongPageHeaderData;
/* This flag indicates a "long" page header */
#define XLP_LONG_HEADER 0x0002

View File

@ -1,121 +1,10 @@
/***********************************************************************************************************************************
PostgreSQL 9.1 Interface
See postgres/interface.c for documentation.
See postgres/interface/version.intern.h for documentation.
***********************************************************************************************************************************/
#include "common/debug.h"
#include "common/log.h"
#include "postgres/interface/v091.h"
#define PG_VERSION PG_VERSION_91
#include "postgres/interface/v091.auto.c"
#include "postgres/interface/version.intern.h"
/**********************************************************************************************************************************/
bool
pgInterfaceControlIs091(const Buffer *controlFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(controlFile != NULL);
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
FUNCTION_TEST_RETURN(
controlData->pg_control_version == PG_CONTROL_VERSION && controlData->catalog_version_no == CATALOG_VERSION_NO);
}
/**********************************************************************************************************************************/
PgControl
pgInterfaceControl091(const Buffer *controlFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, controlFile);
FUNCTION_LOG_END();
ASSERT(controlFile != NULL);
ASSERT(pgInterfaceControlIs091(controlFile));
PgControl result = {0};
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
result.systemId = controlData->system_identifier;
result.controlVersion = controlData->pg_control_version;
result.catalogVersion = controlData->catalog_version_no;
result.pageSize = controlData->blcksz;
result.walSegmentSize = controlData->xlog_seg_size;
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
/**********************************************************************************************************************************/
bool
pgInterfaceWalIs091(const Buffer *walFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(walFile != NULL);
FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
}
/**********************************************************************************************************************************/
PgWal
pgInterfaceWal091(const Buffer *walFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, walFile);
FUNCTION_LOG_END();
ASSERT(walFile != NULL);
ASSERT(pgInterfaceWalIs091(walFile));
PgWal result = {0};
result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
FUNCTION_LOG_RETURN(PG_WAL, result);
}
#ifdef DEBUG
/**********************************************************************************************************************************/
void
pgInterfaceControlTest091(PgControl pgControl, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_CONTROL, pgControl);
FUNCTION_TEST_END();
ControlFileData *controlData = (ControlFileData *)bufPtr(buffer);
controlData->system_identifier = pgControl.systemId;
controlData->pg_control_version = pgControl.controlVersion == 0 ? PG_CONTROL_VERSION : pgControl.controlVersion;
controlData->catalog_version_no = pgControl.catalogVersion == 0 ? CATALOG_VERSION_NO : pgControl.catalogVersion;
controlData->blcksz = pgControl.pageSize;
controlData->xlog_seg_size = pgControl.walSegmentSize;
FUNCTION_TEST_RETURN_VOID();
}
/**********************************************************************************************************************************/
void
pgInterfaceWalTest091(PgWal pgWal, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_WAL, pgWal);
FUNCTION_TEST_END();
XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
walData->std.xlp_magic = XLOG_PAGE_MAGIC;
walData->xlp_sysid = pgWal.systemId;
FUNCTION_TEST_RETURN_VOID();
}
#endif
PG_INTERFACE(091);

View File

@ -1,25 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 9.1 Interface
***********************************************************************************************************************************/
#ifndef POSTGRES_INTERFACE_INTERFACE091_H
#define POSTGRES_INTERFACE_INTERFACE091_H
#include "postgres/interface.h"
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs091(const Buffer *controlFile);
PgControl pgInterfaceControl091(const Buffer *controlFile);
bool pgInterfaceWalIs091(const Buffer *walFile);
PgWal pgInterfaceWal091(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest091(PgControl pgControl, Buffer *buffer);
void pgInterfaceWalTest091(PgWal pgWal, Buffer *buffer);
#endif
#endif

View File

@ -1,300 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 9.2 Types
***********************************************************************************************************************************/
/***********************************************************************************************************************************
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uint32 TransactionId;
/* MultiXactId must be equivalent to TransactionId, to fit in t_xmax */
typedef TransactionId MultiXactId;
typedef uint32 MultiXactOffset;
/***********************************************************************************************************************************
Types from src/include/pgtime.h
***********************************************************************************************************************************/
/*
* The API of this library is generally similar to the corresponding
* C library functions, except that we use pg_time_t which (we hope) is
* 64 bits wide, and which is most definitely signed not unsigned.
*/
typedef int64 pg_time_t;
/***********************************************************************************************************************************
Types from src/include/postgres_ext.h
***********************************************************************************************************************************/
/*
* Object ID is a fundamental type in Postgres.
*/
typedef unsigned int Oid;
/***********************************************************************************************************************************
Types from src/include/utils/pg_crc32.h
***********************************************************************************************************************************/
typedef uint32 pg_crc32;
/***********************************************************************************************************************************
Types from src/include/access/xlogdefs.h
***********************************************************************************************************************************/
/*
* Pointer to a location in the XLOG. These pointers are 64 bits wide,
* because we don't want them ever to overflow.
*
* NOTE: xrecoff == 0 is used to indicate an invalid pointer. This is OK
* because we use page headers in the XLOG, so no XLOG record can start
* right at the beginning of a file.
*
* NOTE: the "log file number" is somewhat misnamed, since the actual files
* making up the XLOG are much smaller than 4Gb. Each actual file is an
* XLogSegSize-byte "segment" of a logical log file having the indicated
* xlogid. The log file number and segment number together identify a
* physical XLOG file. Segment number and offset within the physical file
* are computed from xrecoff div and mod XLogSegSize.
*/
typedef struct XLogRecPtr
{
uint32 xlogid; /* log file #, 0 based */
uint32 xrecoff; /* byte offset of location in log file */
} XLogRecPtr;
/*
* TimeLineID (TLI) - identifies different database histories to prevent
* confusion after restoring a prior state of a database installation.
* TLI does not change in a normal stop/restart of the database (including
* crash-and-recover cases); but we must assign a new TLI after doing
* a recovery to a prior state, a/k/a point-in-time recovery. This makes
* the new WAL logfile sequence we generate distinguishable from the
* sequence that was generated in the previous incarnation.
*/
typedef uint32 TimeLineID;
/***********************************************************************************************************************************
Types from src/include/catalog/catversion.h
***********************************************************************************************************************************/
/*
* We could use anything we wanted for version numbers, but I recommend
* following the "YYYYMMDDN" style often used for DNS zone serial numbers.
* YYYYMMDD are the date of the change, and N is the number of the change
* on that day. (Hopefully we'll never commit ten independent sets of
* catalog changes on the same day...)
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201204301
/***********************************************************************************************************************************
Types from src/include/catalog/pg_control.h
***********************************************************************************************************************************/
/* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 922
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
* a copy of the latest one in pg_control for possible disaster recovery.
* Changing this struct requires a PG_CONTROL_VERSION bump.
*/
typedef struct CheckPoint
{
XLogRecPtr redo; /* next RecPtr available when we began to
* create CheckPoint (i.e. REDO start point) */
TimeLineID ThisTimeLineID; /* current TLI */
bool fullPageWrites; /* current full_page_writes */
uint32 nextXidEpoch; /* higher-order bits of nextXid */
TransactionId nextXid; /* next free XID */
Oid nextOid; /* next free OID */
MultiXactId nextMulti; /* next free MultiXactId */
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
Oid oldestXidDB; /* database with minimum datfrozenxid */
pg_time_t time; /* time stamp of checkpoint */
/*
* Oldest XID still running. This is only needed to initialize hot standby
* mode from an online checkpoint, so we only bother calculating this for
* online checkpoints and only when wal_level is hot_standby. Otherwise
* it's set to InvalidTransactionId.
*/
TransactionId oldestActiveXid;
} CheckPoint;
/*
* System status indicator. Note this is stored in pg_control; if you change
* it, you must bump PG_CONTROL_VERSION
*/
typedef enum DBState
{
DB_STARTUP = 0,
DB_SHUTDOWNED,
DB_SHUTDOWNED_IN_RECOVERY,
DB_SHUTDOWNING,
DB_IN_CRASH_RECOVERY,
DB_IN_ARCHIVE_RECOVERY,
DB_IN_PRODUCTION
} DBState;
/*
* Contents of pg_control.
*
* NOTE: try to keep this under 512 bytes so that it will fit on one physical
* sector of typical disk drives. This reduces the odds of corruption due to
* power failure midway through a write.
*/
typedef struct ControlFileData
{
/*
* Unique system identifier --- to ensure we match up xlog files with the
* installation that produced them.
*/
uint64 system_identifier;
/*
* Version identifier information. Keep these fields at the same offset,
* especially pg_control_version; they won't be real useful if they move
* around. (For historical reasons they must be 8 bytes into the file
* rather than immediately at the front.)
*
* pg_control_version identifies the format of pg_control itself.
* catalog_version_no identifies the format of the system catalogs.
*
* There are additional version identifiers in individual files; for
* example, WAL logs contain per-page magic numbers that can serve as
* version cues for the WAL log.
*/
uint32 pg_control_version; /* PG_CONTROL_VERSION */
uint32 catalog_version_no; /* see catversion.h */
/*
* System status data
*/
DBState state; /* see enum above */
pg_time_t time; /* time stamp of last pg_control update */
XLogRecPtr checkPoint; /* last check point record ptr */
XLogRecPtr prevCheckPoint; /* previous check point record ptr */
CheckPoint checkPointCopy; /* copy of last check point record */
/*
* These two values determine the minimum point we must recover up to
* before starting up:
*
* minRecoveryPoint is updated to the latest replayed LSN whenever we
* flush a data change during archive recovery. That guards against
* starting archive recovery, aborting it, and restarting with an earlier
* stop location. If we've already flushed data changes from WAL record X
* to disk, we mustn't start up until we reach X again. Zero when not
* doing archive recovery.
*
* backupStartPoint is the redo pointer of the backup start checkpoint, if
* we are recovering from an online backup and haven't reached the end of
* backup yet. It is reset to zero when the end of backup is reached, and
* we mustn't start up before that. A boolean would suffice otherwise, but
* we use the redo pointer as a cross-check when we see an end-of-backup
* record, to make sure the end-of-backup record corresponds the base
* backup we're recovering from.
*
* backupEndPoint is the backup end location, if we are recovering from an
* online backup which was taken from the standby and haven't reached the
* end of backup yet. It is initialized to the minimum recovery point in
* pg_control which was backed up last. It is reset to zero when the end
* of backup is reached, and we mustn't start up before that.
*
* If backupEndRequired is true, we know for sure that we're restoring
* from a backup, and must see a backup-end record before we can safely
* start up. If it's false, but backupStartPoint is set, a backup_label
* file was found at startup but it may have been a leftover from a stray
* pg_start_backup() call, not accompanied by pg_stop_backup().
*/
XLogRecPtr minRecoveryPoint;
XLogRecPtr backupStartPoint;
XLogRecPtr backupEndPoint;
bool backupEndRequired;
/*
* Parameter settings that determine if the WAL can be used for archival
* or hot standby.
*/
int wal_level;
int MaxConnections;
int max_prepared_xacts;
int max_locks_per_xact;
/*
* This data is used to check for hardware-architecture compatibility of
* the database and the backend executable. We need not check endianness
* explicitly, since the pg_control version will surely look wrong to a
* machine of different endianness, but we do need to worry about MAXALIGN
* and floating-point format. (Note: storage layout nominally also
* depends on SHORTALIGN and INTALIGN, but in practice these are the same
* on all architectures of interest.)
*
* Testing just one double value is not a very bulletproof test for
* floating-point compatibility, but it will catch most cases.
*/
uint32 maxAlign; /* alignment requirement for tuples */
double floatFormat; /* constant 1234567.0 */
#define FLOATFORMAT_VALUE 1234567.0
/*
* This data is used to make sure that configuration of this database is
* compatible with the backend executable.
*/
uint32 blcksz; /* data block size for this DB */
uint32 relseg_size; /* blocks per segment of large relation */
uint32 xlog_blcksz; /* block size within WAL files */
uint32 xlog_seg_size; /* size of each WAL segment */
uint32 nameDataLen; /* catalog name field width */
uint32 indexMaxKeys; /* max number of columns in an index */
uint32 toast_max_chunk_size; /* chunk size in TOAST tables */
/* flag indicating internal format of timestamp, interval, time */
bool enableIntTimes; /* int64 storage enabled? */
/* flags indicating pass-by-value status of various types */
bool float4ByVal; /* float4 pass-by-value? */
bool float8ByVal; /* float8, int8, etc pass-by-value? */
/* CRC of all above ... MUST BE LAST! */
pg_crc32 crc;
} ControlFileData;
/***********************************************************************************************************************************
Types from src/include/access/xlog_internal.h
***********************************************************************************************************************************/
/*
* Each page of XLOG file has a header like this:
*/
#define XLOG_PAGE_MAGIC 0xD071 /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData
{
uint16 xlp_magic; /* magic value for correctness checks */
uint16 xlp_info; /* flag bits, see below */
TimeLineID xlp_tli; /* TimeLineID of first record on page */
XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
} XLogPageHeaderData;
/*
* When the XLP_LONG_HEADER flag is set, we store additional fields in the
* page header. (This is ordinarily done just in the first page of an
* XLOG file.) The additional fields serve to identify the file accurately.
*/
typedef struct XLogLongPageHeaderData
{
XLogPageHeaderData std; /* standard header fields */
uint64 xlp_sysid; /* system identifier from pg_control */
uint32 xlp_seg_size; /* just as a cross-check */
uint32 xlp_xlog_blcksz; /* just as a cross-check */
} XLogLongPageHeaderData;
/* This flag indicates a "long" page header */
#define XLP_LONG_HEADER 0x0002

View File

@ -1,121 +1,10 @@
/***********************************************************************************************************************************
PostgreSQL 9.2 Interface
See postgres/interface.c for documentation.
See postgres/interface/version.intern.h for documentation.
***********************************************************************************************************************************/
#include "common/debug.h"
#include "common/log.h"
#include "postgres/interface/v092.h"
#define PG_VERSION PG_VERSION_92
#include "postgres/interface/v092.auto.c"
#include "postgres/interface/version.intern.h"
/**********************************************************************************************************************************/
bool
pgInterfaceControlIs092(const Buffer *controlFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(controlFile != NULL);
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
FUNCTION_TEST_RETURN(
controlData->pg_control_version == PG_CONTROL_VERSION && controlData->catalog_version_no == CATALOG_VERSION_NO);
}
/**********************************************************************************************************************************/
PgControl
pgInterfaceControl092(const Buffer *controlFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, controlFile);
FUNCTION_LOG_END();
ASSERT(controlFile != NULL);
ASSERT(pgInterfaceControlIs092(controlFile));
PgControl result = {0};
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
result.systemId = controlData->system_identifier;
result.controlVersion = controlData->pg_control_version;
result.catalogVersion = controlData->catalog_version_no;
result.pageSize = controlData->blcksz;
result.walSegmentSize = controlData->xlog_seg_size;
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
/**********************************************************************************************************************************/
bool
pgInterfaceWalIs092(const Buffer *walFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(walFile != NULL);
FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
}
/**********************************************************************************************************************************/
PgWal
pgInterfaceWal092(const Buffer *walFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, walFile);
FUNCTION_LOG_END();
ASSERT(walFile != NULL);
ASSERT(pgInterfaceWalIs092(walFile));
PgWal result = {0};
result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
FUNCTION_LOG_RETURN(PG_WAL, result);
}
#ifdef DEBUG
/**********************************************************************************************************************************/
void
pgInterfaceControlTest092(PgControl pgControl, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_CONTROL, pgControl);
FUNCTION_TEST_END();
ControlFileData *controlData = (ControlFileData *)bufPtr(buffer);
controlData->system_identifier = pgControl.systemId;
controlData->pg_control_version = pgControl.controlVersion == 0 ? PG_CONTROL_VERSION : pgControl.controlVersion;
controlData->catalog_version_no = pgControl.catalogVersion == 0 ? CATALOG_VERSION_NO : pgControl.catalogVersion;
controlData->blcksz = pgControl.pageSize;
controlData->xlog_seg_size = pgControl.walSegmentSize;
FUNCTION_TEST_RETURN_VOID();
}
/**********************************************************************************************************************************/
void
pgInterfaceWalTest092(PgWal pgWal, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_WAL, pgWal);
FUNCTION_TEST_END();
XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
walData->std.xlp_magic = XLOG_PAGE_MAGIC;
walData->xlp_sysid = pgWal.systemId;
FUNCTION_TEST_RETURN_VOID();
}
#endif
PG_INTERFACE(092);

View File

@ -1,25 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 9.2 Interface
***********************************************************************************************************************************/
#ifndef POSTGRES_INTERFACE_INTERFACE092_H
#define POSTGRES_INTERFACE_INTERFACE092_H
#include "postgres/interface.h"
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs092(const Buffer *controlFile);
PgControl pgInterfaceControl092(const Buffer *controlFile);
bool pgInterfaceWalIs092(const Buffer *walFile);
PgWal pgInterfaceWal092(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest092(PgControl pgControl, Buffer *buffer);
void pgInterfaceWalTest092(PgWal pgWal, Buffer *buffer);
#endif
#endif

View File

@ -1,306 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 9.3 Types
***********************************************************************************************************************************/
/***********************************************************************************************************************************
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uint32 TransactionId;
/* MultiXactId must be equivalent to TransactionId, to fit in t_xmax */
typedef TransactionId MultiXactId;
typedef uint32 MultiXactOffset;
/***********************************************************************************************************************************
Types from src/include/pgtime.h
***********************************************************************************************************************************/
/*
* The API of this library is generally similar to the corresponding
* C library functions, except that we use pg_time_t which (we hope) is
* 64 bits wide, and which is most definitely signed not unsigned.
*/
typedef int64 pg_time_t;
/***********************************************************************************************************************************
Types from src/include/postgres_ext.h
***********************************************************************************************************************************/
/*
* Object ID is a fundamental type in Postgres.
*/
typedef unsigned int Oid;
/***********************************************************************************************************************************
Types from src/include/utils/pg_crc32.h
***********************************************************************************************************************************/
typedef uint32 pg_crc32;
/***********************************************************************************************************************************
Types from src/include/access/xlogdefs.h
***********************************************************************************************************************************/
/*
* Pointer to a location in the XLOG. These pointers are 64 bits wide,
* because we don't want them ever to overflow.
*/
typedef uint64 XLogRecPtr;
/*
* TimeLineID (TLI) - identifies different database histories to prevent
* confusion after restoring a prior state of a database installation.
* TLI does not change in a normal stop/restart of the database (including
* crash-and-recover cases); but we must assign a new TLI after doing
* a recovery to a prior state, a/k/a point-in-time recovery. This makes
* the new WAL logfile sequence we generate distinguishable from the
* sequence that was generated in the previous incarnation.
*/
typedef uint32 TimeLineID;
/***********************************************************************************************************************************
Types from src/include/catalog/catversion.h
***********************************************************************************************************************************/
/*
* We could use anything we wanted for version numbers, but I recommend
* following the "YYYYMMDDN" style often used for DNS zone serial numbers.
* YYYYMMDD are the date of the change, and N is the number of the change
* on that day. (Hopefully we'll never commit ten independent sets of
* catalog changes on the same day...)
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201306121
/***********************************************************************************************************************************
Types from src/include/catalog/pg_control.h
***********************************************************************************************************************************/
/* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 937
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
* a copy of the latest one in pg_control for possible disaster recovery.
* Changing this struct requires a PG_CONTROL_VERSION bump.
*/
typedef struct CheckPoint
{
XLogRecPtr redo; /* next RecPtr available when we began to
* create CheckPoint (i.e. REDO start point) */
TimeLineID ThisTimeLineID; /* current TLI */
TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new
* timeline (equals ThisTimeLineID otherwise) */
bool fullPageWrites; /* current full_page_writes */
uint32 nextXidEpoch; /* higher-order bits of nextXid */
TransactionId nextXid; /* next free XID */
Oid nextOid; /* next free OID */
MultiXactId nextMulti; /* next free MultiXactId */
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
Oid oldestXidDB; /* database with minimum datfrozenxid */
MultiXactId oldestMulti; /* cluster-wide minimum datminmxid */
Oid oldestMultiDB; /* database with minimum datminmxid */
pg_time_t time; /* time stamp of checkpoint */
/*
* Oldest XID still running. This is only needed to initialize hot standby
* mode from an online checkpoint, so we only bother calculating this for
* online checkpoints and only when wal_level is hot_standby. Otherwise
* it's set to InvalidTransactionId.
*/
TransactionId oldestActiveXid;
} CheckPoint;
/*
* System status indicator. Note this is stored in pg_control; if you change
* it, you must bump PG_CONTROL_VERSION
*/
typedef enum DBState
{
DB_STARTUP = 0,
DB_SHUTDOWNED,
DB_SHUTDOWNED_IN_RECOVERY,
DB_SHUTDOWNING,
DB_IN_CRASH_RECOVERY,
DB_IN_ARCHIVE_RECOVERY,
DB_IN_PRODUCTION
} DBState;
/*
* Contents of pg_control.
*
* NOTE: try to keep this under 512 bytes so that it will fit on one physical
* sector of typical disk drives. This reduces the odds of corruption due to
* power failure midway through a write.
*/
typedef struct ControlFileData
{
/*
* Unique system identifier --- to ensure we match up xlog files with the
* installation that produced them.
*/
uint64 system_identifier;
/*
* Version identifier information. Keep these fields at the same offset,
* especially pg_control_version; they won't be real useful if they move
* around. (For historical reasons they must be 8 bytes into the file
* rather than immediately at the front.)
*
* pg_control_version identifies the format of pg_control itself.
* catalog_version_no identifies the format of the system catalogs.
*
* There are additional version identifiers in individual files; for
* example, WAL logs contain per-page magic numbers that can serve as
* version cues for the WAL log.
*/
uint32 pg_control_version; /* PG_CONTROL_VERSION */
uint32 catalog_version_no; /* see catversion.h */
/*
* System status data
*/
DBState state; /* see enum above */
pg_time_t time; /* time stamp of last pg_control update */
XLogRecPtr checkPoint; /* last check point record ptr */
XLogRecPtr prevCheckPoint; /* previous check point record ptr */
CheckPoint checkPointCopy; /* copy of last check point record */
XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */
/*
* These two values determine the minimum point we must recover up to
* before starting up:
*
* minRecoveryPoint is updated to the latest replayed LSN whenever we
* flush a data change during archive recovery. That guards against
* starting archive recovery, aborting it, and restarting with an earlier
* stop location. If we've already flushed data changes from WAL record X
* to disk, we mustn't start up until we reach X again. Zero when not
* doing archive recovery.
*
* backupStartPoint is the redo pointer of the backup start checkpoint, if
* we are recovering from an online backup and haven't reached the end of
* backup yet. It is reset to zero when the end of backup is reached, and
* we mustn't start up before that. A boolean would suffice otherwise, but
* we use the redo pointer as a cross-check when we see an end-of-backup
* record, to make sure the end-of-backup record corresponds the base
* backup we're recovering from.
*
* backupEndPoint is the backup end location, if we are recovering from an
* online backup which was taken from the standby and haven't reached the
* end of backup yet. It is initialized to the minimum recovery point in
* pg_control which was backed up last. It is reset to zero when the end
* of backup is reached, and we mustn't start up before that.
*
* If backupEndRequired is true, we know for sure that we're restoring
* from a backup, and must see a backup-end record before we can safely
* start up. If it's false, but backupStartPoint is set, a backup_label
* file was found at startup but it may have been a leftover from a stray
* pg_start_backup() call, not accompanied by pg_stop_backup().
*/
XLogRecPtr minRecoveryPoint;
TimeLineID minRecoveryPointTLI;
XLogRecPtr backupStartPoint;
XLogRecPtr backupEndPoint;
bool backupEndRequired;
/*
* Parameter settings that determine if the WAL can be used for archival
* or hot standby.
*/
int wal_level;
int MaxConnections;
int max_prepared_xacts;
int max_locks_per_xact;
/*
* This data is used to check for hardware-architecture compatibility of
* the database and the backend executable. We need not check endianness
* explicitly, since the pg_control version will surely look wrong to a
* machine of different endianness, but we do need to worry about MAXALIGN
* and floating-point format. (Note: storage layout nominally also
* depends on SHORTALIGN and INTALIGN, but in practice these are the same
* on all architectures of interest.)
*
* Testing just one double value is not a very bulletproof test for
* floating-point compatibility, but it will catch most cases.
*/
uint32 maxAlign; /* alignment requirement for tuples */
double floatFormat; /* constant 1234567.0 */
#define FLOATFORMAT_VALUE 1234567.0
/*
* This data is used to make sure that configuration of this database is
* compatible with the backend executable.
*/
uint32 blcksz; /* data block size for this DB */
uint32 relseg_size; /* blocks per segment of large relation */
uint32 xlog_blcksz; /* block size within WAL files */
uint32 xlog_seg_size; /* size of each WAL segment */
uint32 nameDataLen; /* catalog name field width */
uint32 indexMaxKeys; /* max number of columns in an index */
uint32 toast_max_chunk_size; /* chunk size in TOAST tables */
/* flag indicating internal format of timestamp, interval, time */
bool enableIntTimes; /* int64 storage enabled? */
/* flags indicating pass-by-value status of various types */
bool float4ByVal; /* float4 pass-by-value? */
bool float8ByVal; /* float8, int8, etc pass-by-value? */
/* Are data pages protected by checksums? Zero if no checksum version */
uint32 data_checksum_version;
/* CRC of all above ... MUST BE LAST! */
pg_crc32 crc;
} ControlFileData;
/***********************************************************************************************************************************
Types from src/include/access/xlog_internal.h
***********************************************************************************************************************************/
/*
* Each page of XLOG file has a header like this:
*/
#define XLOG_PAGE_MAGIC 0xD075 /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData
{
uint16 xlp_magic; /* magic value for correctness checks */
uint16 xlp_info; /* flag bits, see below */
TimeLineID xlp_tli; /* TimeLineID of first record on page */
XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
/*
* When there is not enough space on current page for whole record, we
* continue on the next page. xlp_rem_len is the number of bytes
* remaining from a previous page.
*
* Note that xl_rem_len includes backup-block data; that is, it tracks
* xl_tot_len not xl_len in the initial header. Also note that the
* continuation data isn't necessarily aligned.
*/
uint32 xlp_rem_len; /* total len of remaining data for record */
} XLogPageHeaderData;
/*
* When the XLP_LONG_HEADER flag is set, we store additional fields in the
* page header. (This is ordinarily done just in the first page of an
* XLOG file.) The additional fields serve to identify the file accurately.
*/
typedef struct XLogLongPageHeaderData
{
XLogPageHeaderData std; /* standard header fields */
uint64 xlp_sysid; /* system identifier from pg_control */
uint32 xlp_seg_size; /* just as a cross-check */
uint32 xlp_xlog_blcksz; /* just as a cross-check */
} XLogLongPageHeaderData;
/* This flag indicates a "long" page header */
#define XLP_LONG_HEADER 0x0002

View File

@ -1,125 +1,10 @@
/***********************************************************************************************************************************
PostgreSQL 9.3 Interface
See postgres/interface.c for documentation.
See postgres/interface/version.intern.h for documentation.
***********************************************************************************************************************************/
#include "common/debug.h"
#include "common/log.h"
#include "postgres/interface/v093.h"
#define PG_VERSION PG_VERSION_93
#include "postgres/interface/v093.auto.c"
#include "postgres/interface/version.intern.h"
/**********************************************************************************************************************************/
bool
pgInterfaceControlIs093(const Buffer *controlFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(controlFile != NULL);
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
FUNCTION_TEST_RETURN(
controlData->pg_control_version == PG_CONTROL_VERSION && controlData->catalog_version_no == CATALOG_VERSION_NO);
}
/**********************************************************************************************************************************/
PgControl
pgInterfaceControl093(const Buffer *controlFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, controlFile);
FUNCTION_LOG_END();
ASSERT(controlFile != NULL);
ASSERT(pgInterfaceControlIs093(controlFile));
PgControl result = {0};
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
result.systemId = controlData->system_identifier;
result.controlVersion = controlData->pg_control_version;
result.catalogVersion = controlData->catalog_version_no;
result.pageSize = controlData->blcksz;
result.walSegmentSize = controlData->xlog_seg_size;
result.pageChecksum = controlData->data_checksum_version != 0;
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
/**********************************************************************************************************************************/
bool
pgInterfaceWalIs093(const Buffer *walFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(walFile != NULL);
FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
}
/**********************************************************************************************************************************/
PgWal
pgInterfaceWal093(const Buffer *walFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, walFile);
FUNCTION_LOG_END();
ASSERT(walFile != NULL);
ASSERT(pgInterfaceWalIs093(walFile));
PgWal result = {0};
result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
FUNCTION_LOG_RETURN(PG_WAL, result);
}
#ifdef DEBUG
/**********************************************************************************************************************************/
void
pgInterfaceControlTest093(PgControl pgControl, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_CONTROL, pgControl);
FUNCTION_TEST_END();
ControlFileData *controlData = (ControlFileData *)bufPtr(buffer);
controlData->system_identifier = pgControl.systemId;
controlData->pg_control_version = pgControl.controlVersion == 0 ? PG_CONTROL_VERSION : pgControl.controlVersion;
controlData->catalog_version_no = pgControl.catalogVersion == 0 ? CATALOG_VERSION_NO : pgControl.catalogVersion;
controlData->blcksz = pgControl.pageSize;
controlData->xlog_seg_size = pgControl.walSegmentSize;
controlData->data_checksum_version = pgControl.pageChecksum;
FUNCTION_TEST_RETURN_VOID();
}
/**********************************************************************************************************************************/
void
pgInterfaceWalTest093(PgWal pgWal, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_WAL, pgWal);
FUNCTION_TEST_END();
XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
walData->std.xlp_magic = XLOG_PAGE_MAGIC;
walData->xlp_sysid = pgWal.systemId;
FUNCTION_TEST_RETURN_VOID();
}
#endif
PG_INTERFACE(093);

View File

@ -1,25 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 9.3 Interface
***********************************************************************************************************************************/
#ifndef POSTGRES_INTERFACE_INTERFACE093_H
#define POSTGRES_INTERFACE_INTERFACE093_H
#include "postgres/interface.h"
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs093(const Buffer *controlFile);
PgControl pgInterfaceControl093(const Buffer *controlFile);
bool pgInterfaceWalIs093(const Buffer *walFile);
PgWal pgInterfaceWal093(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest093(PgControl pgControl, Buffer *buffer);
void pgInterfaceWalTest093(PgWal pgWal, Buffer *buffer);
#endif
#endif

View File

@ -1,309 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 9.4 Types
***********************************************************************************************************************************/
/***********************************************************************************************************************************
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uint32 TransactionId;
/* MultiXactId must be equivalent to TransactionId, to fit in t_xmax */
typedef TransactionId MultiXactId;
typedef uint32 MultiXactOffset;
/***********************************************************************************************************************************
Types from src/include/pgtime.h
***********************************************************************************************************************************/
/*
* The API of this library is generally similar to the corresponding
* C library functions, except that we use pg_time_t which (we hope) is
* 64 bits wide, and which is most definitely signed not unsigned.
*/
typedef int64 pg_time_t;
/***********************************************************************************************************************************
Types from src/include/postgres_ext.h
***********************************************************************************************************************************/
/*
* Object ID is a fundamental type in Postgres.
*/
typedef unsigned int Oid;
/***********************************************************************************************************************************
Types from src/include/utils/pg_crc32.h
***********************************************************************************************************************************/
typedef uint32 pg_crc32;
/***********************************************************************************************************************************
Types from src/include/access/xlogdefs.h
***********************************************************************************************************************************/
/*
* Pointer to a location in the XLOG. These pointers are 64 bits wide,
* because we don't want them ever to overflow.
*/
typedef uint64 XLogRecPtr;
/*
* TimeLineID (TLI) - identifies different database histories to prevent
* confusion after restoring a prior state of a database installation.
* TLI does not change in a normal stop/restart of the database (including
* crash-and-recover cases); but we must assign a new TLI after doing
* a recovery to a prior state, a/k/a point-in-time recovery. This makes
* the new WAL logfile sequence we generate distinguishable from the
* sequence that was generated in the previous incarnation.
*/
typedef uint32 TimeLineID;
/***********************************************************************************************************************************
Types from src/include/catalog/catversion.h
***********************************************************************************************************************************/
/*
* We could use anything we wanted for version numbers, but I recommend
* following the "YYYYMMDDN" style often used for DNS zone serial numbers.
* YYYYMMDD are the date of the change, and N is the number of the change
* on that day. (Hopefully we'll never commit ten independent sets of
* catalog changes on the same day...)
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201409291
/***********************************************************************************************************************************
Types from src/include/catalog/pg_control.h
***********************************************************************************************************************************/
/* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 942
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
* a copy of the latest one in pg_control for possible disaster recovery.
* Changing this struct requires a PG_CONTROL_VERSION bump.
*/
typedef struct CheckPoint
{
XLogRecPtr redo; /* next RecPtr available when we began to
* create CheckPoint (i.e. REDO start point) */
TimeLineID ThisTimeLineID; /* current TLI */
TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new
* timeline (equals ThisTimeLineID otherwise) */
bool fullPageWrites; /* current full_page_writes */
uint32 nextXidEpoch; /* higher-order bits of nextXid */
TransactionId nextXid; /* next free XID */
Oid nextOid; /* next free OID */
MultiXactId nextMulti; /* next free MultiXactId */
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
Oid oldestXidDB; /* database with minimum datfrozenxid */
MultiXactId oldestMulti; /* cluster-wide minimum datminmxid */
Oid oldestMultiDB; /* database with minimum datminmxid */
pg_time_t time; /* time stamp of checkpoint */
/*
* Oldest XID still running. This is only needed to initialize hot standby
* mode from an online checkpoint, so we only bother calculating this for
* online checkpoints and only when wal_level is hot_standby. Otherwise
* it's set to InvalidTransactionId.
*/
TransactionId oldestActiveXid;
} CheckPoint;
/*
* System status indicator. Note this is stored in pg_control; if you change
* it, you must bump PG_CONTROL_VERSION
*/
typedef enum DBState
{
DB_STARTUP = 0,
DB_SHUTDOWNED,
DB_SHUTDOWNED_IN_RECOVERY,
DB_SHUTDOWNING,
DB_IN_CRASH_RECOVERY,
DB_IN_ARCHIVE_RECOVERY,
DB_IN_PRODUCTION
} DBState;
/*
* Contents of pg_control.
*
* NOTE: try to keep this under 512 bytes so that it will fit on one physical
* sector of typical disk drives. This reduces the odds of corruption due to
* power failure midway through a write.
*/
typedef struct ControlFileData
{
/*
* Unique system identifier --- to ensure we match up xlog files with the
* installation that produced them.
*/
uint64 system_identifier;
/*
* Version identifier information. Keep these fields at the same offset,
* especially pg_control_version; they won't be real useful if they move
* around. (For historical reasons they must be 8 bytes into the file
* rather than immediately at the front.)
*
* pg_control_version identifies the format of pg_control itself.
* catalog_version_no identifies the format of the system catalogs.
*
* There are additional version identifiers in individual files; for
* example, WAL logs contain per-page magic numbers that can serve as
* version cues for the WAL log.
*/
uint32 pg_control_version; /* PG_CONTROL_VERSION */
uint32 catalog_version_no; /* see catversion.h */
/*
* System status data
*/
DBState state; /* see enum above */
pg_time_t time; /* time stamp of last pg_control update */
XLogRecPtr checkPoint; /* last check point record ptr */
XLogRecPtr prevCheckPoint; /* previous check point record ptr */
CheckPoint checkPointCopy; /* copy of last check point record */
XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */
/*
* These two values determine the minimum point we must recover up to
* before starting up:
*
* minRecoveryPoint is updated to the latest replayed LSN whenever we
* flush a data change during archive recovery. That guards against
* starting archive recovery, aborting it, and restarting with an earlier
* stop location. If we've already flushed data changes from WAL record X
* to disk, we mustn't start up until we reach X again. Zero when not
* doing archive recovery.
*
* backupStartPoint is the redo pointer of the backup start checkpoint, if
* we are recovering from an online backup and haven't reached the end of
* backup yet. It is reset to zero when the end of backup is reached, and
* we mustn't start up before that. A boolean would suffice otherwise, but
* we use the redo pointer as a cross-check when we see an end-of-backup
* record, to make sure the end-of-backup record corresponds the base
* backup we're recovering from.
*
* backupEndPoint is the backup end location, if we are recovering from an
* online backup which was taken from the standby and haven't reached the
* end of backup yet. It is initialized to the minimum recovery point in
* pg_control which was backed up last. It is reset to zero when the end
* of backup is reached, and we mustn't start up before that.
*
* If backupEndRequired is true, we know for sure that we're restoring
* from a backup, and must see a backup-end record before we can safely
* start up. If it's false, but backupStartPoint is set, a backup_label
* file was found at startup but it may have been a leftover from a stray
* pg_start_backup() call, not accompanied by pg_stop_backup().
*/
XLogRecPtr minRecoveryPoint;
TimeLineID minRecoveryPointTLI;
XLogRecPtr backupStartPoint;
XLogRecPtr backupEndPoint;
bool backupEndRequired;
/*
* Parameter settings that determine if the WAL can be used for archival
* or hot standby.
*/
int wal_level;
bool wal_log_hints;
int MaxConnections;
int max_worker_processes;
int max_prepared_xacts;
int max_locks_per_xact;
/*
* This data is used to check for hardware-architecture compatibility of
* the database and the backend executable. We need not check endianness
* explicitly, since the pg_control version will surely look wrong to a
* machine of different endianness, but we do need to worry about MAXALIGN
* and floating-point format. (Note: storage layout nominally also
* depends on SHORTALIGN and INTALIGN, but in practice these are the same
* on all architectures of interest.)
*
* Testing just one double value is not a very bulletproof test for
* floating-point compatibility, but it will catch most cases.
*/
uint32 maxAlign; /* alignment requirement for tuples */
double floatFormat; /* constant 1234567.0 */
#define FLOATFORMAT_VALUE 1234567.0
/*
* This data is used to make sure that configuration of this database is
* compatible with the backend executable.
*/
uint32 blcksz; /* data block size for this DB */
uint32 relseg_size; /* blocks per segment of large relation */
uint32 xlog_blcksz; /* block size within WAL files */
uint32 xlog_seg_size; /* size of each WAL segment */
uint32 nameDataLen; /* catalog name field width */
uint32 indexMaxKeys; /* max number of columns in an index */
uint32 toast_max_chunk_size; /* chunk size in TOAST tables */
uint32 loblksize; /* chunk size in pg_largeobject */
/* flag indicating internal format of timestamp, interval, time */
bool enableIntTimes; /* int64 storage enabled? */
/* flags indicating pass-by-value status of various types */
bool float4ByVal; /* float4 pass-by-value? */
bool float8ByVal; /* float8, int8, etc pass-by-value? */
/* Are data pages protected by checksums? Zero if no checksum version */
uint32 data_checksum_version;
/* CRC of all above ... MUST BE LAST! */
pg_crc32 crc;
} ControlFileData;
/***********************************************************************************************************************************
Types from src/include/access/xlog_internal.h
***********************************************************************************************************************************/
/*
* Each page of XLOG file has a header like this:
*/
#define XLOG_PAGE_MAGIC 0xD07E /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData
{
uint16 xlp_magic; /* magic value for correctness checks */
uint16 xlp_info; /* flag bits, see below */
TimeLineID xlp_tli; /* TimeLineID of first record on page */
XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
/*
* When there is not enough space on current page for whole record, we
* continue on the next page. xlp_rem_len is the number of bytes
* remaining from a previous page.
*
* Note that xl_rem_len includes backup-block data; that is, it tracks
* xl_tot_len not xl_len in the initial header. Also note that the
* continuation data isn't necessarily aligned.
*/
uint32 xlp_rem_len; /* total len of remaining data for record */
} XLogPageHeaderData;
/*
* When the XLP_LONG_HEADER flag is set, we store additional fields in the
* page header. (This is ordinarily done just in the first page of an
* XLOG file.) The additional fields serve to identify the file accurately.
*/
typedef struct XLogLongPageHeaderData
{
XLogPageHeaderData std; /* standard header fields */
uint64 xlp_sysid; /* system identifier from pg_control */
uint32 xlp_seg_size; /* just as a cross-check */
uint32 xlp_xlog_blcksz; /* just as a cross-check */
} XLogLongPageHeaderData;
/* This flag indicates a "long" page header */
#define XLP_LONG_HEADER 0x0002

View File

@ -1,125 +1,10 @@
/***********************************************************************************************************************************
PostgreSQL 9.4 Interface
See postgres/interface.c for documentation.
See postgres/interface/version.intern.h for documentation.
***********************************************************************************************************************************/
#include "common/debug.h"
#include "common/log.h"
#include "postgres/interface/v094.h"
#define PG_VERSION PG_VERSION_94
#include "postgres/interface/v094.auto.c"
#include "postgres/interface/version.intern.h"
/**********************************************************************************************************************************/
bool
pgInterfaceControlIs094(const Buffer *controlFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(controlFile != NULL);
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
FUNCTION_TEST_RETURN(
controlData->pg_control_version == PG_CONTROL_VERSION && controlData->catalog_version_no == CATALOG_VERSION_NO);
}
/**********************************************************************************************************************************/
PgControl
pgInterfaceControl094(const Buffer *controlFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, controlFile);
FUNCTION_LOG_END();
ASSERT(controlFile != NULL);
ASSERT(pgInterfaceControlIs094(controlFile));
PgControl result = {0};
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
result.systemId = controlData->system_identifier;
result.controlVersion = controlData->pg_control_version;
result.catalogVersion = controlData->catalog_version_no;
result.pageSize = controlData->blcksz;
result.walSegmentSize = controlData->xlog_seg_size;
result.pageChecksum = controlData->data_checksum_version != 0;
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
/**********************************************************************************************************************************/
bool
pgInterfaceWalIs094(const Buffer *walFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(walFile != NULL);
FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
}
/**********************************************************************************************************************************/
PgWal
pgInterfaceWal094(const Buffer *walFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, walFile);
FUNCTION_LOG_END();
ASSERT(walFile != NULL);
ASSERT(pgInterfaceWalIs094(walFile));
PgWal result = {0};
result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
FUNCTION_LOG_RETURN(PG_WAL, result);
}
#ifdef DEBUG
/**********************************************************************************************************************************/
void
pgInterfaceControlTest094(PgControl pgControl, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_CONTROL, pgControl);
FUNCTION_TEST_END();
ControlFileData *controlData = (ControlFileData *)bufPtr(buffer);
controlData->system_identifier = pgControl.systemId;
controlData->pg_control_version = pgControl.controlVersion == 0 ? PG_CONTROL_VERSION : pgControl.controlVersion;
controlData->catalog_version_no = pgControl.catalogVersion == 0 ? CATALOG_VERSION_NO : pgControl.catalogVersion;
controlData->blcksz = pgControl.pageSize;
controlData->xlog_seg_size = pgControl.walSegmentSize;
controlData->data_checksum_version = pgControl.pageChecksum;
FUNCTION_TEST_RETURN_VOID();
}
/**********************************************************************************************************************************/
void
pgInterfaceWalTest094(PgWal pgWal, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_WAL, pgWal);
FUNCTION_TEST_END();
XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
walData->std.xlp_magic = XLOG_PAGE_MAGIC;
walData->xlp_sysid = pgWal.systemId;
FUNCTION_TEST_RETURN_VOID();
}
#endif
PG_INTERFACE(094);

View File

@ -1,25 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 9.4 Interface
***********************************************************************************************************************************/
#ifndef POSTGRES_INTERFACE_INTERFACE094_H
#define POSTGRES_INTERFACE_INTERFACE094_H
#include "postgres/interface.h"
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs094(const Buffer *controlFile);
PgControl pgInterfaceControl094(const Buffer *controlFile);
bool pgInterfaceWalIs094(const Buffer *walFile);
PgWal pgInterfaceWal094(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest094(PgControl pgControl, Buffer *buffer);
void pgInterfaceWalTest094(PgWal pgWal, Buffer *buffer);
#endif
#endif

View File

@ -1,314 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 9.5 Types
***********************************************************************************************************************************/
/***********************************************************************************************************************************
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uint32 TransactionId;
/* MultiXactId must be equivalent to TransactionId, to fit in t_xmax */
typedef TransactionId MultiXactId;
typedef uint32 MultiXactOffset;
/***********************************************************************************************************************************
Types from src/include/pgtime.h
***********************************************************************************************************************************/
/*
* The API of this library is generally similar to the corresponding
* C library functions, except that we use pg_time_t which (we hope) is
* 64 bits wide, and which is most definitely signed not unsigned.
*/
typedef int64 pg_time_t;
/***********************************************************************************************************************************
Types from src/include/postgres_ext.h
***********************************************************************************************************************************/
/*
* Object ID is a fundamental type in Postgres.
*/
typedef unsigned int Oid;
/***********************************************************************************************************************************
Types from src/include/port/pg_crc32c.h
***********************************************************************************************************************************/
typedef uint32 pg_crc32c;
/***********************************************************************************************************************************
Types from src/include/access/xlogdefs.h
***********************************************************************************************************************************/
/*
* Pointer to a location in the XLOG. These pointers are 64 bits wide,
* because we don't want them ever to overflow.
*/
typedef uint64 XLogRecPtr;
/*
* TimeLineID (TLI) - identifies different database histories to prevent
* confusion after restoring a prior state of a database installation.
* TLI does not change in a normal stop/restart of the database (including
* crash-and-recover cases); but we must assign a new TLI after doing
* a recovery to a prior state, a/k/a point-in-time recovery. This makes
* the new WAL logfile sequence we generate distinguishable from the
* sequence that was generated in the previous incarnation.
*/
typedef uint32 TimeLineID;
/***********************************************************************************************************************************
Types from src/include/catalog/catversion.h
***********************************************************************************************************************************/
/*
* We could use anything we wanted for version numbers, but I recommend
* following the "YYYYMMDDN" style often used for DNS zone serial numbers.
* YYYYMMDD are the date of the change, and N is the number of the change
* on that day. (Hopefully we'll never commit ten independent sets of
* catalog changes on the same day...)
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201510051
/***********************************************************************************************************************************
Types from src/include/catalog/pg_control.h
***********************************************************************************************************************************/
/* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 942
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
* a copy of the latest one in pg_control for possible disaster recovery.
* Changing this struct requires a PG_CONTROL_VERSION bump.
*/
typedef struct CheckPoint
{
XLogRecPtr redo; /* next RecPtr available when we began to
* create CheckPoint (i.e. REDO start point) */
TimeLineID ThisTimeLineID; /* current TLI */
TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new
* timeline (equals ThisTimeLineID otherwise) */
bool fullPageWrites; /* current full_page_writes */
uint32 nextXidEpoch; /* higher-order bits of nextXid */
TransactionId nextXid; /* next free XID */
Oid nextOid; /* next free OID */
MultiXactId nextMulti; /* next free MultiXactId */
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
Oid oldestXidDB; /* database with minimum datfrozenxid */
MultiXactId oldestMulti; /* cluster-wide minimum datminmxid */
Oid oldestMultiDB; /* database with minimum datminmxid */
pg_time_t time; /* time stamp of checkpoint */
TransactionId oldestCommitTsXid; /* oldest Xid with valid commit
* timestamp */
TransactionId newestCommitTsXid; /* newest Xid with valid commit
* timestamp */
/*
* Oldest XID still running. This is only needed to initialize hot standby
* mode from an online checkpoint, so we only bother calculating this for
* online checkpoints and only when wal_level is hot_standby. Otherwise
* it's set to InvalidTransactionId.
*/
TransactionId oldestActiveXid;
} CheckPoint;
/*
* System status indicator. Note this is stored in pg_control; if you change
* it, you must bump PG_CONTROL_VERSION
*/
typedef enum DBState
{
DB_STARTUP = 0,
DB_SHUTDOWNED,
DB_SHUTDOWNED_IN_RECOVERY,
DB_SHUTDOWNING,
DB_IN_CRASH_RECOVERY,
DB_IN_ARCHIVE_RECOVERY,
DB_IN_PRODUCTION
} DBState;
/*
* Contents of pg_control.
*
* NOTE: try to keep this under 512 bytes so that it will fit on one physical
* sector of typical disk drives. This reduces the odds of corruption due to
* power failure midway through a write.
*/
typedef struct ControlFileData
{
/*
* Unique system identifier --- to ensure we match up xlog files with the
* installation that produced them.
*/
uint64 system_identifier;
/*
* Version identifier information. Keep these fields at the same offset,
* especially pg_control_version; they won't be real useful if they move
* around. (For historical reasons they must be 8 bytes into the file
* rather than immediately at the front.)
*
* pg_control_version identifies the format of pg_control itself.
* catalog_version_no identifies the format of the system catalogs.
*
* There are additional version identifiers in individual files; for
* example, WAL logs contain per-page magic numbers that can serve as
* version cues for the WAL log.
*/
uint32 pg_control_version; /* PG_CONTROL_VERSION */
uint32 catalog_version_no; /* see catversion.h */
/*
* System status data
*/
DBState state; /* see enum above */
pg_time_t time; /* time stamp of last pg_control update */
XLogRecPtr checkPoint; /* last check point record ptr */
XLogRecPtr prevCheckPoint; /* previous check point record ptr */
CheckPoint checkPointCopy; /* copy of last check point record */
XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */
/*
* These two values determine the minimum point we must recover up to
* before starting up:
*
* minRecoveryPoint is updated to the latest replayed LSN whenever we
* flush a data change during archive recovery. That guards against
* starting archive recovery, aborting it, and restarting with an earlier
* stop location. If we've already flushed data changes from WAL record X
* to disk, we mustn't start up until we reach X again. Zero when not
* doing archive recovery.
*
* backupStartPoint is the redo pointer of the backup start checkpoint, if
* we are recovering from an online backup and haven't reached the end of
* backup yet. It is reset to zero when the end of backup is reached, and
* we mustn't start up before that. A boolean would suffice otherwise, but
* we use the redo pointer as a cross-check when we see an end-of-backup
* record, to make sure the end-of-backup record corresponds the base
* backup we're recovering from.
*
* backupEndPoint is the backup end location, if we are recovering from an
* online backup which was taken from the standby and haven't reached the
* end of backup yet. It is initialized to the minimum recovery point in
* pg_control which was backed up last. It is reset to zero when the end
* of backup is reached, and we mustn't start up before that.
*
* If backupEndRequired is true, we know for sure that we're restoring
* from a backup, and must see a backup-end record before we can safely
* start up. If it's false, but backupStartPoint is set, a backup_label
* file was found at startup but it may have been a leftover from a stray
* pg_start_backup() call, not accompanied by pg_stop_backup().
*/
XLogRecPtr minRecoveryPoint;
TimeLineID minRecoveryPointTLI;
XLogRecPtr backupStartPoint;
XLogRecPtr backupEndPoint;
bool backupEndRequired;
/*
* Parameter settings that determine if the WAL can be used for archival
* or hot standby.
*/
int wal_level;
bool wal_log_hints;
int MaxConnections;
int max_worker_processes;
int max_prepared_xacts;
int max_locks_per_xact;
bool track_commit_timestamp;
/*
* This data is used to check for hardware-architecture compatibility of
* the database and the backend executable. We need not check endianness
* explicitly, since the pg_control version will surely look wrong to a
* machine of different endianness, but we do need to worry about MAXALIGN
* and floating-point format. (Note: storage layout nominally also
* depends on SHORTALIGN and INTALIGN, but in practice these are the same
* on all architectures of interest.)
*
* Testing just one double value is not a very bulletproof test for
* floating-point compatibility, but it will catch most cases.
*/
uint32 maxAlign; /* alignment requirement for tuples */
double floatFormat; /* constant 1234567.0 */
#define FLOATFORMAT_VALUE 1234567.0
/*
* This data is used to make sure that configuration of this database is
* compatible with the backend executable.
*/
uint32 blcksz; /* data block size for this DB */
uint32 relseg_size; /* blocks per segment of large relation */
uint32 xlog_blcksz; /* block size within WAL files */
uint32 xlog_seg_size; /* size of each WAL segment */
uint32 nameDataLen; /* catalog name field width */
uint32 indexMaxKeys; /* max number of columns in an index */
uint32 toast_max_chunk_size; /* chunk size in TOAST tables */
uint32 loblksize; /* chunk size in pg_largeobject */
/* flag indicating internal format of timestamp, interval, time */
bool enableIntTimes; /* int64 storage enabled? */
/* flags indicating pass-by-value status of various types */
bool float4ByVal; /* float4 pass-by-value? */
bool float8ByVal; /* float8, int8, etc pass-by-value? */
/* Are data pages protected by checksums? Zero if no checksum version */
uint32 data_checksum_version;
/* CRC of all above ... MUST BE LAST! */
pg_crc32c crc;
} ControlFileData;
/***********************************************************************************************************************************
Types from src/include/access/xlog_internal.h
***********************************************************************************************************************************/
/*
* Each page of XLOG file has a header like this:
*/
#define XLOG_PAGE_MAGIC 0xD087 /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData
{
uint16 xlp_magic; /* magic value for correctness checks */
uint16 xlp_info; /* flag bits, see below */
TimeLineID xlp_tli; /* TimeLineID of first record on page */
XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
/*
* When there is not enough space on current page for whole record, we
* continue on the next page. xlp_rem_len is the number of bytes
* remaining from a previous page.
*
* Note that xl_rem_len includes backup-block data; that is, it tracks
* xl_tot_len not xl_len in the initial header. Also note that the
* continuation data isn't necessarily aligned.
*/
uint32 xlp_rem_len; /* total len of remaining data for record */
} XLogPageHeaderData;
/*
* When the XLP_LONG_HEADER flag is set, we store additional fields in the
* page header. (This is ordinarily done just in the first page of an
* XLOG file.) The additional fields serve to identify the file accurately.
*/
typedef struct XLogLongPageHeaderData
{
XLogPageHeaderData std; /* standard header fields */
uint64 xlp_sysid; /* system identifier from pg_control */
uint32 xlp_seg_size; /* just as a cross-check */
uint32 xlp_xlog_blcksz; /* just as a cross-check */
} XLogLongPageHeaderData;
/* This flag indicates a "long" page header */
#define XLP_LONG_HEADER 0x0002

View File

@ -1,125 +1,10 @@
/***********************************************************************************************************************************
PostgreSQL 9.5 Interface
See postgres/interface.c for documentation.
See postgres/interface/version.intern.h for documentation.
***********************************************************************************************************************************/
#include "common/debug.h"
#include "common/log.h"
#include "postgres/interface/v095.h"
#define PG_VERSION PG_VERSION_95
#include "postgres/interface/v095.auto.c"
#include "postgres/interface/version.intern.h"
/**********************************************************************************************************************************/
bool
pgInterfaceControlIs095(const Buffer *controlFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(controlFile != NULL);
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
FUNCTION_TEST_RETURN(
controlData->pg_control_version == PG_CONTROL_VERSION && controlData->catalog_version_no == CATALOG_VERSION_NO);
}
/**********************************************************************************************************************************/
PgControl
pgInterfaceControl095(const Buffer *controlFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, controlFile);
FUNCTION_LOG_END();
ASSERT(controlFile != NULL);
ASSERT(pgInterfaceControlIs095(controlFile));
PgControl result = {0};
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
result.systemId = controlData->system_identifier;
result.controlVersion = controlData->pg_control_version;
result.catalogVersion = controlData->catalog_version_no;
result.pageSize = controlData->blcksz;
result.walSegmentSize = controlData->xlog_seg_size;
result.pageChecksum = controlData->data_checksum_version != 0;
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
/**********************************************************************************************************************************/
bool
pgInterfaceWalIs095(const Buffer *walFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(walFile != NULL);
FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
}
/**********************************************************************************************************************************/
PgWal
pgInterfaceWal095(const Buffer *walFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, walFile);
FUNCTION_LOG_END();
ASSERT(walFile != NULL);
ASSERT(pgInterfaceWalIs095(walFile));
PgWal result = {0};
result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
FUNCTION_LOG_RETURN(PG_WAL, result);
}
#ifdef DEBUG
/**********************************************************************************************************************************/
void
pgInterfaceControlTest095(PgControl pgControl, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_CONTROL, pgControl);
FUNCTION_TEST_END();
ControlFileData *controlData = (ControlFileData *)bufPtr(buffer);
controlData->system_identifier = pgControl.systemId;
controlData->pg_control_version = pgControl.controlVersion == 0 ? PG_CONTROL_VERSION : pgControl.controlVersion;
controlData->catalog_version_no = pgControl.catalogVersion == 0 ? CATALOG_VERSION_NO : pgControl.catalogVersion;
controlData->blcksz = pgControl.pageSize;
controlData->xlog_seg_size = pgControl.walSegmentSize;
controlData->data_checksum_version = pgControl.pageChecksum;
FUNCTION_TEST_RETURN_VOID();
}
/**********************************************************************************************************************************/
void
pgInterfaceWalTest095(PgWal pgWal, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_WAL, pgWal);
FUNCTION_TEST_END();
XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
walData->std.xlp_magic = XLOG_PAGE_MAGIC;
walData->xlp_sysid = pgWal.systemId;
FUNCTION_TEST_RETURN_VOID();
}
#endif
PG_INTERFACE(095);

View File

@ -1,25 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 9.5 Interface
***********************************************************************************************************************************/
#ifndef POSTGRES_INTERFACE_INTERFACE095_H
#define POSTGRES_INTERFACE_INTERFACE095_H
#include "postgres/interface.h"
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs095(const Buffer *controlFile);
PgControl pgInterfaceControl095(const Buffer *controlFile);
bool pgInterfaceWalIs095(const Buffer *walFile);
PgWal pgInterfaceWal095(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest095(PgControl pgControl, Buffer *buffer);
void pgInterfaceWalTest095(PgWal pgWal, Buffer *buffer);
#endif
#endif

View File

@ -1,314 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 9.6 Types
***********************************************************************************************************************************/
/***********************************************************************************************************************************
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uint32 TransactionId;
/* MultiXactId must be equivalent to TransactionId, to fit in t_xmax */
typedef TransactionId MultiXactId;
typedef uint32 MultiXactOffset;
/***********************************************************************************************************************************
Types from src/include/pgtime.h
***********************************************************************************************************************************/
/*
* The API of this library is generally similar to the corresponding
* C library functions, except that we use pg_time_t which (we hope) is
* 64 bits wide, and which is most definitely signed not unsigned.
*/
typedef int64 pg_time_t;
/***********************************************************************************************************************************
Types from src/include/postgres_ext.h
***********************************************************************************************************************************/
/*
* Object ID is a fundamental type in Postgres.
*/
typedef unsigned int Oid;
/***********************************************************************************************************************************
Types from src/include/port/pg_crc32c.h
***********************************************************************************************************************************/
typedef uint32 pg_crc32c;
/***********************************************************************************************************************************
Types from src/include/access/xlogdefs.h
***********************************************************************************************************************************/
/*
* Pointer to a location in the XLOG. These pointers are 64 bits wide,
* because we don't want them ever to overflow.
*/
typedef uint64 XLogRecPtr;
/*
* TimeLineID (TLI) - identifies different database histories to prevent
* confusion after restoring a prior state of a database installation.
* TLI does not change in a normal stop/restart of the database (including
* crash-and-recover cases); but we must assign a new TLI after doing
* a recovery to a prior state, a/k/a point-in-time recovery. This makes
* the new WAL logfile sequence we generate distinguishable from the
* sequence that was generated in the previous incarnation.
*/
typedef uint32 TimeLineID;
/***********************************************************************************************************************************
Types from src/include/catalog/catversion.h
***********************************************************************************************************************************/
/*
* We could use anything we wanted for version numbers, but I recommend
* following the "YYYYMMDDN" style often used for DNS zone serial numbers.
* YYYYMMDD are the date of the change, and N is the number of the change
* on that day. (Hopefully we'll never commit ten independent sets of
* catalog changes on the same day...)
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201608131
/***********************************************************************************************************************************
Types from src/include/catalog/pg_control.h
***********************************************************************************************************************************/
/* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 960
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
* a copy of the latest one in pg_control for possible disaster recovery.
* Changing this struct requires a PG_CONTROL_VERSION bump.
*/
typedef struct CheckPoint
{
XLogRecPtr redo; /* next RecPtr available when we began to
* create CheckPoint (i.e. REDO start point) */
TimeLineID ThisTimeLineID; /* current TLI */
TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new
* timeline (equals ThisTimeLineID otherwise) */
bool fullPageWrites; /* current full_page_writes */
uint32 nextXidEpoch; /* higher-order bits of nextXid */
TransactionId nextXid; /* next free XID */
Oid nextOid; /* next free OID */
MultiXactId nextMulti; /* next free MultiXactId */
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
Oid oldestXidDB; /* database with minimum datfrozenxid */
MultiXactId oldestMulti; /* cluster-wide minimum datminmxid */
Oid oldestMultiDB; /* database with minimum datminmxid */
pg_time_t time; /* time stamp of checkpoint */
TransactionId oldestCommitTsXid; /* oldest Xid with valid commit
* timestamp */
TransactionId newestCommitTsXid; /* newest Xid with valid commit
* timestamp */
/*
* Oldest XID still running. This is only needed to initialize hot standby
* mode from an online checkpoint, so we only bother calculating this for
* online checkpoints and only when wal_level is replica. Otherwise it's
* set to InvalidTransactionId.
*/
TransactionId oldestActiveXid;
} CheckPoint;
/*
* System status indicator. Note this is stored in pg_control; if you change
* it, you must bump PG_CONTROL_VERSION
*/
typedef enum DBState
{
DB_STARTUP = 0,
DB_SHUTDOWNED,
DB_SHUTDOWNED_IN_RECOVERY,
DB_SHUTDOWNING,
DB_IN_CRASH_RECOVERY,
DB_IN_ARCHIVE_RECOVERY,
DB_IN_PRODUCTION
} DBState;
/*
* Contents of pg_control.
*
* NOTE: try to keep this under 512 bytes so that it will fit on one physical
* sector of typical disk drives. This reduces the odds of corruption due to
* power failure midway through a write.
*/
typedef struct ControlFileData
{
/*
* Unique system identifier --- to ensure we match up xlog files with the
* installation that produced them.
*/
uint64 system_identifier;
/*
* Version identifier information. Keep these fields at the same offset,
* especially pg_control_version; they won't be real useful if they move
* around. (For historical reasons they must be 8 bytes into the file
* rather than immediately at the front.)
*
* pg_control_version identifies the format of pg_control itself.
* catalog_version_no identifies the format of the system catalogs.
*
* There are additional version identifiers in individual files; for
* example, WAL logs contain per-page magic numbers that can serve as
* version cues for the WAL log.
*/
uint32 pg_control_version; /* PG_CONTROL_VERSION */
uint32 catalog_version_no; /* see catversion.h */
/*
* System status data
*/
DBState state; /* see enum above */
pg_time_t time; /* time stamp of last pg_control update */
XLogRecPtr checkPoint; /* last check point record ptr */
XLogRecPtr prevCheckPoint; /* previous check point record ptr */
CheckPoint checkPointCopy; /* copy of last check point record */
XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */
/*
* These two values determine the minimum point we must recover up to
* before starting up:
*
* minRecoveryPoint is updated to the latest replayed LSN whenever we
* flush a data change during archive recovery. That guards against
* starting archive recovery, aborting it, and restarting with an earlier
* stop location. If we've already flushed data changes from WAL record X
* to disk, we mustn't start up until we reach X again. Zero when not
* doing archive recovery.
*
* backupStartPoint is the redo pointer of the backup start checkpoint, if
* we are recovering from an online backup and haven't reached the end of
* backup yet. It is reset to zero when the end of backup is reached, and
* we mustn't start up before that. A boolean would suffice otherwise, but
* we use the redo pointer as a cross-check when we see an end-of-backup
* record, to make sure the end-of-backup record corresponds the base
* backup we're recovering from.
*
* backupEndPoint is the backup end location, if we are recovering from an
* online backup which was taken from the standby and haven't reached the
* end of backup yet. It is initialized to the minimum recovery point in
* pg_control which was backed up last. It is reset to zero when the end
* of backup is reached, and we mustn't start up before that.
*
* If backupEndRequired is true, we know for sure that we're restoring
* from a backup, and must see a backup-end record before we can safely
* start up. If it's false, but backupStartPoint is set, a backup_label
* file was found at startup but it may have been a leftover from a stray
* pg_start_backup() call, not accompanied by pg_stop_backup().
*/
XLogRecPtr minRecoveryPoint;
TimeLineID minRecoveryPointTLI;
XLogRecPtr backupStartPoint;
XLogRecPtr backupEndPoint;
bool backupEndRequired;
/*
* Parameter settings that determine if the WAL can be used for archival
* or hot standby.
*/
int wal_level;
bool wal_log_hints;
int MaxConnections;
int max_worker_processes;
int max_prepared_xacts;
int max_locks_per_xact;
bool track_commit_timestamp;
/*
* This data is used to check for hardware-architecture compatibility of
* the database and the backend executable. We need not check endianness
* explicitly, since the pg_control version will surely look wrong to a
* machine of different endianness, but we do need to worry about MAXALIGN
* and floating-point format. (Note: storage layout nominally also
* depends on SHORTALIGN and INTALIGN, but in practice these are the same
* on all architectures of interest.)
*
* Testing just one double value is not a very bulletproof test for
* floating-point compatibility, but it will catch most cases.
*/
uint32 maxAlign; /* alignment requirement for tuples */
double floatFormat; /* constant 1234567.0 */
#define FLOATFORMAT_VALUE 1234567.0
/*
* This data is used to make sure that configuration of this database is
* compatible with the backend executable.
*/
uint32 blcksz; /* data block size for this DB */
uint32 relseg_size; /* blocks per segment of large relation */
uint32 xlog_blcksz; /* block size within WAL files */
uint32 xlog_seg_size; /* size of each WAL segment */
uint32 nameDataLen; /* catalog name field width */
uint32 indexMaxKeys; /* max number of columns in an index */
uint32 toast_max_chunk_size; /* chunk size in TOAST tables */
uint32 loblksize; /* chunk size in pg_largeobject */
/* flag indicating internal format of timestamp, interval, time */
bool enableIntTimes; /* int64 storage enabled? */
/* flags indicating pass-by-value status of various types */
bool float4ByVal; /* float4 pass-by-value? */
bool float8ByVal; /* float8, int8, etc pass-by-value? */
/* Are data pages protected by checksums? Zero if no checksum version */
uint32 data_checksum_version;
/* CRC of all above ... MUST BE LAST! */
pg_crc32c crc;
} ControlFileData;
/***********************************************************************************************************************************
Types from src/include/access/xlog_internal.h
***********************************************************************************************************************************/
/*
* Each page of XLOG file has a header like this:
*/
#define XLOG_PAGE_MAGIC 0xD093 /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData
{
uint16 xlp_magic; /* magic value for correctness checks */
uint16 xlp_info; /* flag bits, see below */
TimeLineID xlp_tli; /* TimeLineID of first record on page */
XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
/*
* When there is not enough space on current page for whole record, we
* continue on the next page. xlp_rem_len is the number of bytes
* remaining from a previous page.
*
* Note that xl_rem_len includes backup-block data; that is, it tracks
* xl_tot_len not xl_len in the initial header. Also note that the
* continuation data isn't necessarily aligned.
*/
uint32 xlp_rem_len; /* total len of remaining data for record */
} XLogPageHeaderData;
/*
* When the XLP_LONG_HEADER flag is set, we store additional fields in the
* page header. (This is ordinarily done just in the first page of an
* XLOG file.) The additional fields serve to identify the file accurately.
*/
typedef struct XLogLongPageHeaderData
{
XLogPageHeaderData std; /* standard header fields */
uint64 xlp_sysid; /* system identifier from pg_control */
uint32 xlp_seg_size; /* just as a cross-check */
uint32 xlp_xlog_blcksz; /* just as a cross-check */
} XLogLongPageHeaderData;
/* This flag indicates a "long" page header */
#define XLP_LONG_HEADER 0x0002

View File

@ -1,125 +1,10 @@
/***********************************************************************************************************************************
PostgreSQL 9.6 Interface
See postgres/interface.c for documentation.
See postgres/interface/version.intern.h for documentation.
***********************************************************************************************************************************/
#include "common/debug.h"
#include "common/log.h"
#include "postgres/interface/v096.h"
#define PG_VERSION PG_VERSION_96
#include "postgres/interface/v096.auto.c"
#include "postgres/interface/version.intern.h"
/**********************************************************************************************************************************/
bool
pgInterfaceControlIs096(const Buffer *controlFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(controlFile != NULL);
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
FUNCTION_TEST_RETURN(
controlData->pg_control_version == PG_CONTROL_VERSION && controlData->catalog_version_no == CATALOG_VERSION_NO);
}
/**********************************************************************************************************************************/
PgControl
pgInterfaceControl096(const Buffer *controlFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, controlFile);
FUNCTION_LOG_END();
ASSERT(controlFile != NULL);
ASSERT(pgInterfaceControlIs096(controlFile));
PgControl result = {0};
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
result.systemId = controlData->system_identifier;
result.controlVersion = controlData->pg_control_version;
result.catalogVersion = controlData->catalog_version_no;
result.pageSize = controlData->blcksz;
result.walSegmentSize = controlData->xlog_seg_size;
result.pageChecksum = controlData->data_checksum_version != 0;
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
/**********************************************************************************************************************************/
bool
pgInterfaceWalIs096(const Buffer *walFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(walFile != NULL);
FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
}
/**********************************************************************************************************************************/
PgWal
pgInterfaceWal096(const Buffer *walFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, walFile);
FUNCTION_LOG_END();
ASSERT(walFile != NULL);
ASSERT(pgInterfaceWalIs096(walFile));
PgWal result = {0};
result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
FUNCTION_LOG_RETURN(PG_WAL, result);
}
#ifdef DEBUG
/**********************************************************************************************************************************/
void
pgInterfaceControlTest096(PgControl pgControl, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_CONTROL, pgControl);
FUNCTION_TEST_END();
ControlFileData *controlData = (ControlFileData *)bufPtr(buffer);
controlData->system_identifier = pgControl.systemId;
controlData->pg_control_version = pgControl.controlVersion == 0 ? PG_CONTROL_VERSION : pgControl.controlVersion;
controlData->catalog_version_no = pgControl.catalogVersion == 0 ? CATALOG_VERSION_NO : pgControl.catalogVersion;
controlData->blcksz = pgControl.pageSize;
controlData->xlog_seg_size = pgControl.walSegmentSize;
controlData->data_checksum_version = pgControl.pageChecksum;
FUNCTION_TEST_RETURN_VOID();
}
/**********************************************************************************************************************************/
void
pgInterfaceWalTest096(PgWal pgWal, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_WAL, pgWal);
FUNCTION_TEST_END();
XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
walData->std.xlp_magic = XLOG_PAGE_MAGIC;
walData->xlp_sysid = pgWal.systemId;
FUNCTION_TEST_RETURN_VOID();
}
#endif
PG_INTERFACE(096);

View File

@ -1,25 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 9.6 Interface
***********************************************************************************************************************************/
#ifndef POSTGRES_INTERFACE_INTERFACE096_H
#define POSTGRES_INTERFACE_INTERFACE096_H
#include "postgres/interface.h"
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs096(const Buffer *controlFile);
PgControl pgInterfaceControl096(const Buffer *controlFile);
bool pgInterfaceWalIs096(const Buffer *walFile);
PgWal pgInterfaceWal096(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest096(PgControl pgControl, Buffer *buffer);
void pgInterfaceWalTest096(PgWal pgWal, Buffer *buffer);
#endif
#endif

View File

@ -1,317 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 10 Types
***********************************************************************************************************************************/
/***********************************************************************************************************************************
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uint32 TransactionId;
/* MultiXactId must be equivalent to TransactionId, to fit in t_xmax */
typedef TransactionId MultiXactId;
typedef uint32 MultiXactOffset;
/***********************************************************************************************************************************
Types from src/include/pgtime.h
***********************************************************************************************************************************/
/*
* The API of this library is generally similar to the corresponding
* C library functions, except that we use pg_time_t which (we hope) is
* 64 bits wide, and which is most definitely signed not unsigned.
*/
typedef int64 pg_time_t;
/***********************************************************************************************************************************
Types from src/include/postgres_ext.h
***********************************************************************************************************************************/
/*
* Object ID is a fundamental type in Postgres.
*/
typedef unsigned int Oid;
/***********************************************************************************************************************************
Types from src/include/port/pg_crc32c.h
***********************************************************************************************************************************/
typedef uint32 pg_crc32c;
/***********************************************************************************************************************************
Types from src/include/access/xlogdefs.h
***********************************************************************************************************************************/
/*
* Pointer to a location in the XLOG. These pointers are 64 bits wide,
* because we don't want them ever to overflow.
*/
typedef uint64 XLogRecPtr;
/*
* TimeLineID (TLI) - identifies different database histories to prevent
* confusion after restoring a prior state of a database installation.
* TLI does not change in a normal stop/restart of the database (including
* crash-and-recover cases); but we must assign a new TLI after doing
* a recovery to a prior state, a/k/a point-in-time recovery. This makes
* the new WAL logfile sequence we generate distinguishable from the
* sequence that was generated in the previous incarnation.
*/
typedef uint32 TimeLineID;
/***********************************************************************************************************************************
Types from src/include/catalog/catversion.h
***********************************************************************************************************************************/
/*
* We could use anything we wanted for version numbers, but I recommend
* following the "YYYYMMDDN" style often used for DNS zone serial numbers.
* YYYYMMDD are the date of the change, and N is the number of the change
* on that day. (Hopefully we'll never commit ten independent sets of
* catalog changes on the same day...)
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201707211
/***********************************************************************************************************************************
Types from src/include/catalog/pg_control.h
***********************************************************************************************************************************/
/* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 1002
/* Nonce key length, see below */
#define MOCK_AUTH_NONCE_LEN 32
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
* a copy of the latest one in pg_control for possible disaster recovery.
* Changing this struct requires a PG_CONTROL_VERSION bump.
*/
typedef struct CheckPoint
{
XLogRecPtr redo; /* next RecPtr available when we began to
* create CheckPoint (i.e. REDO start point) */
TimeLineID ThisTimeLineID; /* current TLI */
TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new
* timeline (equals ThisTimeLineID otherwise) */
bool fullPageWrites; /* current full_page_writes */
uint32 nextXidEpoch; /* higher-order bits of nextXid */
TransactionId nextXid; /* next free XID */
Oid nextOid; /* next free OID */
MultiXactId nextMulti; /* next free MultiXactId */
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
Oid oldestXidDB; /* database with minimum datfrozenxid */
MultiXactId oldestMulti; /* cluster-wide minimum datminmxid */
Oid oldestMultiDB; /* database with minimum datminmxid */
pg_time_t time; /* time stamp of checkpoint */
TransactionId oldestCommitTsXid; /* oldest Xid with valid commit
* timestamp */
TransactionId newestCommitTsXid; /* newest Xid with valid commit
* timestamp */
/*
* Oldest XID still running. This is only needed to initialize hot standby
* mode from an online checkpoint, so we only bother calculating this for
* online checkpoints and only when wal_level is replica. Otherwise it's
* set to InvalidTransactionId.
*/
TransactionId oldestActiveXid;
} CheckPoint;
/*
* System status indicator. Note this is stored in pg_control; if you change
* it, you must bump PG_CONTROL_VERSION
*/
typedef enum DBState
{
DB_STARTUP = 0,
DB_SHUTDOWNED,
DB_SHUTDOWNED_IN_RECOVERY,
DB_SHUTDOWNING,
DB_IN_CRASH_RECOVERY,
DB_IN_ARCHIVE_RECOVERY,
DB_IN_PRODUCTION
} DBState;
/*
* Contents of pg_control.
*/
typedef struct ControlFileData
{
/*
* Unique system identifier --- to ensure we match up xlog files with the
* installation that produced them.
*/
uint64 system_identifier;
/*
* Version identifier information. Keep these fields at the same offset,
* especially pg_control_version; they won't be real useful if they move
* around. (For historical reasons they must be 8 bytes into the file
* rather than immediately at the front.)
*
* pg_control_version identifies the format of pg_control itself.
* catalog_version_no identifies the format of the system catalogs.
*
* There are additional version identifiers in individual files; for
* example, WAL logs contain per-page magic numbers that can serve as
* version cues for the WAL log.
*/
uint32 pg_control_version; /* PG_CONTROL_VERSION */
uint32 catalog_version_no; /* see catversion.h */
/*
* System status data
*/
DBState state; /* see enum above */
pg_time_t time; /* time stamp of last pg_control update */
XLogRecPtr checkPoint; /* last check point record ptr */
XLogRecPtr prevCheckPoint; /* previous check point record ptr */
CheckPoint checkPointCopy; /* copy of last check point record */
XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */
/*
* These two values determine the minimum point we must recover up to
* before starting up:
*
* minRecoveryPoint is updated to the latest replayed LSN whenever we
* flush a data change during archive recovery. That guards against
* starting archive recovery, aborting it, and restarting with an earlier
* stop location. If we've already flushed data changes from WAL record X
* to disk, we mustn't start up until we reach X again. Zero when not
* doing archive recovery.
*
* backupStartPoint is the redo pointer of the backup start checkpoint, if
* we are recovering from an online backup and haven't reached the end of
* backup yet. It is reset to zero when the end of backup is reached, and
* we mustn't start up before that. A boolean would suffice otherwise, but
* we use the redo pointer as a cross-check when we see an end-of-backup
* record, to make sure the end-of-backup record corresponds the base
* backup we're recovering from.
*
* backupEndPoint is the backup end location, if we are recovering from an
* online backup which was taken from the standby and haven't reached the
* end of backup yet. It is initialized to the minimum recovery point in
* pg_control which was backed up last. It is reset to zero when the end
* of backup is reached, and we mustn't start up before that.
*
* If backupEndRequired is true, we know for sure that we're restoring
* from a backup, and must see a backup-end record before we can safely
* start up. If it's false, but backupStartPoint is set, a backup_label
* file was found at startup but it may have been a leftover from a stray
* pg_start_backup() call, not accompanied by pg_stop_backup().
*/
XLogRecPtr minRecoveryPoint;
TimeLineID minRecoveryPointTLI;
XLogRecPtr backupStartPoint;
XLogRecPtr backupEndPoint;
bool backupEndRequired;
/*
* Parameter settings that determine if the WAL can be used for archival
* or hot standby.
*/
int wal_level;
bool wal_log_hints;
int MaxConnections;
int max_worker_processes;
int max_prepared_xacts;
int max_locks_per_xact;
bool track_commit_timestamp;
/*
* This data is used to check for hardware-architecture compatibility of
* the database and the backend executable. We need not check endianness
* explicitly, since the pg_control version will surely look wrong to a
* machine of different endianness, but we do need to worry about MAXALIGN
* and floating-point format. (Note: storage layout nominally also
* depends on SHORTALIGN and INTALIGN, but in practice these are the same
* on all architectures of interest.)
*
* Testing just one double value is not a very bulletproof test for
* floating-point compatibility, but it will catch most cases.
*/
uint32 maxAlign; /* alignment requirement for tuples */
double floatFormat; /* constant 1234567.0 */
#define FLOATFORMAT_VALUE 1234567.0
/*
* This data is used to make sure that configuration of this database is
* compatible with the backend executable.
*/
uint32 blcksz; /* data block size for this DB */
uint32 relseg_size; /* blocks per segment of large relation */
uint32 xlog_blcksz; /* block size within WAL files */
uint32 xlog_seg_size; /* size of each WAL segment */
uint32 nameDataLen; /* catalog name field width */
uint32 indexMaxKeys; /* max number of columns in an index */
uint32 toast_max_chunk_size; /* chunk size in TOAST tables */
uint32 loblksize; /* chunk size in pg_largeobject */
/* flags indicating pass-by-value status of various types */
bool float4ByVal; /* float4 pass-by-value? */
bool float8ByVal; /* float8, int8, etc pass-by-value? */
/* Are data pages protected by checksums? Zero if no checksum version */
uint32 data_checksum_version;
/*
* Random nonce, used in authentication requests that need to proceed
* based on values that are cluster-unique, like a SASL exchange that
* failed at an early stage.
*/
char mock_authentication_nonce[MOCK_AUTH_NONCE_LEN];
/* CRC of all above ... MUST BE LAST! */
pg_crc32c crc;
} ControlFileData;
/***********************************************************************************************************************************
Types from src/include/access/xlog_internal.h
***********************************************************************************************************************************/
/*
* Each page of XLOG file has a header like this:
*/
#define XLOG_PAGE_MAGIC 0xD097 /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData
{
uint16 xlp_magic; /* magic value for correctness checks */
uint16 xlp_info; /* flag bits, see below */
TimeLineID xlp_tli; /* TimeLineID of first record on page */
XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
/*
* When there is not enough space on current page for whole record, we
* continue on the next page. xlp_rem_len is the number of bytes
* remaining from a previous page.
*
* Note that xl_rem_len includes backup-block data; that is, it tracks
* xl_tot_len not xl_len in the initial header. Also note that the
* continuation data isn't necessarily aligned.
*/
uint32 xlp_rem_len; /* total len of remaining data for record */
} XLogPageHeaderData;
/*
* When the XLP_LONG_HEADER flag is set, we store additional fields in the
* page header. (This is ordinarily done just in the first page of an
* XLOG file.) The additional fields serve to identify the file accurately.
*/
typedef struct XLogLongPageHeaderData
{
XLogPageHeaderData std; /* standard header fields */
uint64 xlp_sysid; /* system identifier from pg_control */
uint32 xlp_seg_size; /* just as a cross-check */
uint32 xlp_xlog_blcksz; /* just as a cross-check */
} XLogLongPageHeaderData;
/* This flag indicates a "long" page header */
#define XLP_LONG_HEADER 0x0002

View File

@ -1,125 +1,10 @@
/***********************************************************************************************************************************
PostgreSQL 10 Interface
See postgres/interface.c for documentation.
See postgres/interface/version.intern.h for documentation.
***********************************************************************************************************************************/
#include "common/debug.h"
#include "common/log.h"
#include "postgres/interface/v100.h"
#define PG_VERSION PG_VERSION_10
#include "postgres/interface/v100.auto.c"
#include "postgres/interface/version.intern.h"
/**********************************************************************************************************************************/
bool
pgInterfaceControlIs100(const Buffer *controlFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(controlFile != NULL);
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
FUNCTION_TEST_RETURN(
controlData->pg_control_version == PG_CONTROL_VERSION && controlData->catalog_version_no == CATALOG_VERSION_NO);
}
/**********************************************************************************************************************************/
PgControl
pgInterfaceControl100(const Buffer *controlFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, controlFile);
FUNCTION_LOG_END();
ASSERT(controlFile != NULL);
ASSERT(pgInterfaceControlIs100(controlFile));
PgControl result = {0};
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
result.systemId = controlData->system_identifier;
result.controlVersion = controlData->pg_control_version;
result.catalogVersion = controlData->catalog_version_no;
result.pageSize = controlData->blcksz;
result.walSegmentSize = controlData->xlog_seg_size;
result.pageChecksum = controlData->data_checksum_version != 0;
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
/**********************************************************************************************************************************/
bool
pgInterfaceWalIs100(const Buffer *walFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(walFile != NULL);
FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
}
/**********************************************************************************************************************************/
PgWal
pgInterfaceWal100(const Buffer *walFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, walFile);
FUNCTION_LOG_END();
ASSERT(walFile != NULL);
ASSERT(pgInterfaceWalIs100(walFile));
PgWal result = {0};
result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
FUNCTION_LOG_RETURN(PG_WAL, result);
}
#ifdef DEBUG
/**********************************************************************************************************************************/
void
pgInterfaceControlTest100(PgControl pgControl, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_CONTROL, pgControl);
FUNCTION_TEST_END();
ControlFileData *controlData = (ControlFileData *)bufPtr(buffer);
controlData->system_identifier = pgControl.systemId;
controlData->pg_control_version = pgControl.controlVersion == 0 ? PG_CONTROL_VERSION : pgControl.controlVersion;
controlData->catalog_version_no = pgControl.catalogVersion == 0 ? CATALOG_VERSION_NO : pgControl.catalogVersion;
controlData->blcksz = pgControl.pageSize;
controlData->xlog_seg_size = pgControl.walSegmentSize;
controlData->data_checksum_version = pgControl.pageChecksum;
FUNCTION_TEST_RETURN_VOID();
}
/**********************************************************************************************************************************/
void
pgInterfaceWalTest100(PgWal pgWal, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_WAL, pgWal);
FUNCTION_TEST_END();
XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
walData->std.xlp_magic = XLOG_PAGE_MAGIC;
walData->xlp_sysid = pgWal.systemId;
FUNCTION_TEST_RETURN_VOID();
}
#endif
PG_INTERFACE(100);

View File

@ -1,25 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 10 Interface
***********************************************************************************************************************************/
#ifndef POSTGRES_INTERFACE_INTERFACE100_H
#define POSTGRES_INTERFACE_INTERFACE100_H
#include "postgres/interface.h"
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs100(const Buffer *controlFile);
PgControl pgInterfaceControl100(const Buffer *controlFile);
bool pgInterfaceWalIs100(const Buffer *walFile);
PgWal pgInterfaceWal100(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest100(PgControl pgControl, Buffer *buffer);
void pgInterfaceWalTest100(PgWal pgWal, Buffer *buffer);
#endif
#endif

View File

@ -1,316 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 11 Types
***********************************************************************************************************************************/
/***********************************************************************************************************************************
Types from src/include/c.h
***********************************************************************************************************************************/
typedef int64_t int64;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef uint32 TransactionId;
/* MultiXactId must be equivalent to TransactionId, to fit in t_xmax */
typedef TransactionId MultiXactId;
typedef uint32 MultiXactOffset;
/***********************************************************************************************************************************
Types from src/include/pgtime.h
***********************************************************************************************************************************/
/*
* The API of this library is generally similar to the corresponding
* C library functions, except that we use pg_time_t which (we hope) is
* 64 bits wide, and which is most definitely signed not unsigned.
*/
typedef int64 pg_time_t;
/***********************************************************************************************************************************
Types from src/include/postgres_ext.h
***********************************************************************************************************************************/
/*
* Object ID is a fundamental type in Postgres.
*/
typedef unsigned int Oid;
/***********************************************************************************************************************************
Types from src/include/port/pg_crc32c.h
***********************************************************************************************************************************/
typedef uint32 pg_crc32c;
/***********************************************************************************************************************************
Types from src/include/access/xlogdefs.h
***********************************************************************************************************************************/
/*
* Pointer to a location in the XLOG. These pointers are 64 bits wide,
* because we don't want them ever to overflow.
*/
typedef uint64 XLogRecPtr;
/*
* TimeLineID (TLI) - identifies different database histories to prevent
* confusion after restoring a prior state of a database installation.
* TLI does not change in a normal stop/restart of the database (including
* crash-and-recover cases); but we must assign a new TLI after doing
* a recovery to a prior state, a/k/a point-in-time recovery. This makes
* the new WAL logfile sequence we generate distinguishable from the
* sequence that was generated in the previous incarnation.
*/
typedef uint32 TimeLineID;
/***********************************************************************************************************************************
Types from src/include/catalog/catversion.h
***********************************************************************************************************************************/
/*
* We could use anything we wanted for version numbers, but I recommend
* following the "YYYYMMDDN" style often used for DNS zone serial numbers.
* YYYYMMDD are the date of the change, and N is the number of the change
* on that day. (Hopefully we'll never commit ten independent sets of
* catalog changes on the same day...)
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201809051
/***********************************************************************************************************************************
Types from src/include/catalog/pg_control.h
***********************************************************************************************************************************/
/* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 1100
/* Nonce key length, see below */
#define MOCK_AUTH_NONCE_LEN 32
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
* a copy of the latest one in pg_control for possible disaster recovery.
* Changing this struct requires a PG_CONTROL_VERSION bump.
*/
typedef struct CheckPoint
{
XLogRecPtr redo; /* next RecPtr available when we began to
* create CheckPoint (i.e. REDO start point) */
TimeLineID ThisTimeLineID; /* current TLI */
TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new
* timeline (equals ThisTimeLineID otherwise) */
bool fullPageWrites; /* current full_page_writes */
uint32 nextXidEpoch; /* higher-order bits of nextXid */
TransactionId nextXid; /* next free XID */
Oid nextOid; /* next free OID */
MultiXactId nextMulti; /* next free MultiXactId */
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
Oid oldestXidDB; /* database with minimum datfrozenxid */
MultiXactId oldestMulti; /* cluster-wide minimum datminmxid */
Oid oldestMultiDB; /* database with minimum datminmxid */
pg_time_t time; /* time stamp of checkpoint */
TransactionId oldestCommitTsXid; /* oldest Xid with valid commit
* timestamp */
TransactionId newestCommitTsXid; /* newest Xid with valid commit
* timestamp */
/*
* Oldest XID still running. This is only needed to initialize hot standby
* mode from an online checkpoint, so we only bother calculating this for
* online checkpoints and only when wal_level is replica. Otherwise it's
* set to InvalidTransactionId.
*/
TransactionId oldestActiveXid;
} CheckPoint;
/*
* System status indicator. Note this is stored in pg_control; if you change
* it, you must bump PG_CONTROL_VERSION
*/
typedef enum DBState
{
DB_STARTUP = 0,
DB_SHUTDOWNED,
DB_SHUTDOWNED_IN_RECOVERY,
DB_SHUTDOWNING,
DB_IN_CRASH_RECOVERY,
DB_IN_ARCHIVE_RECOVERY,
DB_IN_PRODUCTION
} DBState;
/*
* Contents of pg_control.
*/
typedef struct ControlFileData
{
/*
* Unique system identifier --- to ensure we match up xlog files with the
* installation that produced them.
*/
uint64 system_identifier;
/*
* Version identifier information. Keep these fields at the same offset,
* especially pg_control_version; they won't be real useful if they move
* around. (For historical reasons they must be 8 bytes into the file
* rather than immediately at the front.)
*
* pg_control_version identifies the format of pg_control itself.
* catalog_version_no identifies the format of the system catalogs.
*
* There are additional version identifiers in individual files; for
* example, WAL logs contain per-page magic numbers that can serve as
* version cues for the WAL log.
*/
uint32 pg_control_version; /* PG_CONTROL_VERSION */
uint32 catalog_version_no; /* see catversion.h */
/*
* System status data
*/
DBState state; /* see enum above */
pg_time_t time; /* time stamp of last pg_control update */
XLogRecPtr checkPoint; /* last check point record ptr */
CheckPoint checkPointCopy; /* copy of last check point record */
XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */
/*
* These two values determine the minimum point we must recover up to
* before starting up:
*
* minRecoveryPoint is updated to the latest replayed LSN whenever we
* flush a data change during archive recovery. That guards against
* starting archive recovery, aborting it, and restarting with an earlier
* stop location. If we've already flushed data changes from WAL record X
* to disk, we mustn't start up until we reach X again. Zero when not
* doing archive recovery.
*
* backupStartPoint is the redo pointer of the backup start checkpoint, if
* we are recovering from an online backup and haven't reached the end of
* backup yet. It is reset to zero when the end of backup is reached, and
* we mustn't start up before that. A boolean would suffice otherwise, but
* we use the redo pointer as a cross-check when we see an end-of-backup
* record, to make sure the end-of-backup record corresponds the base
* backup we're recovering from.
*
* backupEndPoint is the backup end location, if we are recovering from an
* online backup which was taken from the standby and haven't reached the
* end of backup yet. It is initialized to the minimum recovery point in
* pg_control which was backed up last. It is reset to zero when the end
* of backup is reached, and we mustn't start up before that.
*
* If backupEndRequired is true, we know for sure that we're restoring
* from a backup, and must see a backup-end record before we can safely
* start up. If it's false, but backupStartPoint is set, a backup_label
* file was found at startup but it may have been a leftover from a stray
* pg_start_backup() call, not accompanied by pg_stop_backup().
*/
XLogRecPtr minRecoveryPoint;
TimeLineID minRecoveryPointTLI;
XLogRecPtr backupStartPoint;
XLogRecPtr backupEndPoint;
bool backupEndRequired;
/*
* Parameter settings that determine if the WAL can be used for archival
* or hot standby.
*/
int wal_level;
bool wal_log_hints;
int MaxConnections;
int max_worker_processes;
int max_prepared_xacts;
int max_locks_per_xact;
bool track_commit_timestamp;
/*
* This data is used to check for hardware-architecture compatibility of
* the database and the backend executable. We need not check endianness
* explicitly, since the pg_control version will surely look wrong to a
* machine of different endianness, but we do need to worry about MAXALIGN
* and floating-point format. (Note: storage layout nominally also
* depends on SHORTALIGN and INTALIGN, but in practice these are the same
* on all architectures of interest.)
*
* Testing just one double value is not a very bulletproof test for
* floating-point compatibility, but it will catch most cases.
*/
uint32 maxAlign; /* alignment requirement for tuples */
double floatFormat; /* constant 1234567.0 */
#define FLOATFORMAT_VALUE 1234567.0
/*
* This data is used to make sure that configuration of this database is
* compatible with the backend executable.
*/
uint32 blcksz; /* data block size for this DB */
uint32 relseg_size; /* blocks per segment of large relation */
uint32 xlog_blcksz; /* block size within WAL files */
uint32 xlog_seg_size; /* size of each WAL segment */
uint32 nameDataLen; /* catalog name field width */
uint32 indexMaxKeys; /* max number of columns in an index */
uint32 toast_max_chunk_size; /* chunk size in TOAST tables */
uint32 loblksize; /* chunk size in pg_largeobject */
/* flags indicating pass-by-value status of various types */
bool float4ByVal; /* float4 pass-by-value? */
bool float8ByVal; /* float8, int8, etc pass-by-value? */
/* Are data pages protected by checksums? Zero if no checksum version */
uint32 data_checksum_version;
/*
* Random nonce, used in authentication requests that need to proceed
* based on values that are cluster-unique, like a SASL exchange that
* failed at an early stage.
*/
char mock_authentication_nonce[MOCK_AUTH_NONCE_LEN];
/* CRC of all above ... MUST BE LAST! */
pg_crc32c crc;
} ControlFileData;
/***********************************************************************************************************************************
Types from src/include/access/xlog_internal.h
***********************************************************************************************************************************/
/*
* Each page of XLOG file has a header like this:
*/
#define XLOG_PAGE_MAGIC 0xD098 /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData
{
uint16 xlp_magic; /* magic value for correctness checks */
uint16 xlp_info; /* flag bits, see below */
TimeLineID xlp_tli; /* TimeLineID of first record on page */
XLogRecPtr xlp_pageaddr; /* XLOG address of this page */
/*
* When there is not enough space on current page for whole record, we
* continue on the next page. xlp_rem_len is the number of bytes
* remaining from a previous page.
*
* Note that xl_rem_len includes backup-block data; that is, it tracks
* xl_tot_len not xl_len in the initial header. Also note that the
* continuation data isn't necessarily aligned.
*/
uint32 xlp_rem_len; /* total len of remaining data for record */
} XLogPageHeaderData;
/*
* When the XLP_LONG_HEADER flag is set, we store additional fields in the
* page header. (This is ordinarily done just in the first page of an
* XLOG file.) The additional fields serve to identify the file accurately.
*/
typedef struct XLogLongPageHeaderData
{
XLogPageHeaderData std; /* standard header fields */
uint64 xlp_sysid; /* system identifier from pg_control */
uint32 xlp_seg_size; /* just as a cross-check */
uint32 xlp_xlog_blcksz; /* just as a cross-check */
} XLogLongPageHeaderData;
/* This flag indicates a "long" page header */
#define XLP_LONG_HEADER 0x0002

View File

@ -1,125 +1,10 @@
/***********************************************************************************************************************************
PostgreSQL 11 Interface
See postgres/interface.c for documentation.
See postgres/interface/version.intern.h for documentation.
***********************************************************************************************************************************/
#include "common/debug.h"
#include "common/log.h"
#include "postgres/interface/v110.h"
#define PG_VERSION PG_VERSION_11
#include "postgres/interface/v110.auto.c"
#include "postgres/interface/version.intern.h"
/**********************************************************************************************************************************/
bool
pgInterfaceControlIs110(const Buffer *controlFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(controlFile != NULL);
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
FUNCTION_TEST_RETURN(
controlData->pg_control_version == PG_CONTROL_VERSION && controlData->catalog_version_no == CATALOG_VERSION_NO);
}
/**********************************************************************************************************************************/
PgControl
pgInterfaceControl110(const Buffer *controlFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, controlFile);
FUNCTION_LOG_END();
ASSERT(controlFile != NULL);
ASSERT(pgInterfaceControlIs110(controlFile));
PgControl result = {0};
ControlFileData *controlData = (ControlFileData *)bufPtr(controlFile);
result.systemId = controlData->system_identifier;
result.controlVersion = controlData->pg_control_version;
result.catalogVersion = controlData->catalog_version_no;
result.pageSize = controlData->blcksz;
result.walSegmentSize = controlData->xlog_seg_size;
result.pageChecksum = controlData->data_checksum_version != 0;
FUNCTION_LOG_RETURN(PG_CONTROL, result);
}
/**********************************************************************************************************************************/
bool
pgInterfaceWalIs110(const Buffer *walFile)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(BUFFER, controlFile);
FUNCTION_TEST_END();
ASSERT(walFile != NULL);
FUNCTION_TEST_RETURN(((XLogPageHeaderData *)bufPtr(walFile))->xlp_magic == XLOG_PAGE_MAGIC);
}
/**********************************************************************************************************************************/
PgWal
pgInterfaceWal110(const Buffer *walFile)
{
FUNCTION_LOG_BEGIN(logLevelTrace);
FUNCTION_LOG_PARAM(BUFFER, walFile);
FUNCTION_LOG_END();
ASSERT(walFile != NULL);
ASSERT(pgInterfaceWalIs110(walFile));
PgWal result = {0};
result.systemId = ((XLogLongPageHeaderData *)bufPtr(walFile))->xlp_sysid;
FUNCTION_LOG_RETURN(PG_WAL, result);
}
#ifdef DEBUG
/**********************************************************************************************************************************/
void
pgInterfaceControlTest110(PgControl pgControl, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_CONTROL, pgControl);
FUNCTION_TEST_END();
ControlFileData *controlData = (ControlFileData *)bufPtr(buffer);
controlData->system_identifier = pgControl.systemId;
controlData->pg_control_version = pgControl.controlVersion == 0 ? PG_CONTROL_VERSION : pgControl.controlVersion;
controlData->catalog_version_no = pgControl.catalogVersion == 0 ? CATALOG_VERSION_NO : pgControl.catalogVersion;
controlData->blcksz = pgControl.pageSize;
controlData->xlog_seg_size = pgControl.walSegmentSize;
controlData->data_checksum_version = pgControl.pageChecksum;
FUNCTION_TEST_RETURN_VOID();
}
/**********************************************************************************************************************************/
void
pgInterfaceWalTest110(PgWal pgWal, Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(PG_WAL, pgWal);
FUNCTION_TEST_END();
XLogLongPageHeaderData *walData = (XLogLongPageHeaderData *)bufPtr(buffer);
walData->std.xlp_magic = XLOG_PAGE_MAGIC;
walData->xlp_sysid = pgWal.systemId;
FUNCTION_TEST_RETURN_VOID();
}
#endif
PG_INTERFACE(110);

View File

@ -1,25 +0,0 @@
/***********************************************************************************************************************************
PostgreSQL 11 Interface
***********************************************************************************************************************************/
#ifndef POSTGRES_INTERFACE_INTERFACE110_H
#define POSTGRES_INTERFACE_INTERFACE110_H
#include "postgres/interface.h"
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs110(const Buffer *controlFile);
PgControl pgInterfaceControl110(const Buffer *controlFile);
bool pgInterfaceWalIs110(const Buffer *walFile);
PgWal pgInterfaceWal110(const Buffer *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest110(PgControl pgControl, Buffer *buffer);
void pgInterfaceWalTest110(PgWal pgWal, Buffer *buffer);
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,105 @@
/***********************************************************************************************************************************
PostgreSQL Version Interface
***********************************************************************************************************************************/
#ifndef POSTGRES_INTERFACE_VERSION_H
#define POSTGRES_INTERFACE_VERSION_H
#include "postgres/interface.h"
/***********************************************************************************************************************************
Functions
***********************************************************************************************************************************/
bool pgInterfaceControlIs083(const unsigned char *controlFile);
PgControl pgInterfaceControl083(const unsigned char *controlFile);
bool pgInterfaceWalIs083(const unsigned char *walFile);
PgWal pgInterfaceWal083(const unsigned char *controlFile);
bool pgInterfaceControlIs084(const unsigned char *controlFile);
PgControl pgInterfaceControl084(const unsigned char *controlFile);
bool pgInterfaceWalIs084(const unsigned char *walFile);
PgWal pgInterfaceWal084(const unsigned char *controlFile);
bool pgInterfaceControlIs090(const unsigned char *controlFile);
PgControl pgInterfaceControl090(const unsigned char *controlFile);
bool pgInterfaceWalIs090(const unsigned char *walFile);
PgWal pgInterfaceWal090(const unsigned char *controlFile);
bool pgInterfaceControlIs091(const unsigned char *controlFile);
PgControl pgInterfaceControl091(const unsigned char *controlFile);
bool pgInterfaceWalIs091(const unsigned char *walFile);
PgWal pgInterfaceWal091(const unsigned char *controlFile);
bool pgInterfaceControlIs092(const unsigned char *controlFile);
PgControl pgInterfaceControl092(const unsigned char *controlFile);
bool pgInterfaceWalIs092(const unsigned char *walFile);
PgWal pgInterfaceWal092(const unsigned char *controlFile);
bool pgInterfaceControlIs093(const unsigned char *controlFile);
PgControl pgInterfaceControl093(const unsigned char *controlFile);
bool pgInterfaceWalIs093(const unsigned char *walFile);
PgWal pgInterfaceWal093(const unsigned char *controlFile);
bool pgInterfaceControlIs094(const unsigned char *controlFile);
PgControl pgInterfaceControl094(const unsigned char *controlFile);
bool pgInterfaceWalIs094(const unsigned char *walFile);
PgWal pgInterfaceWal094(const unsigned char *controlFile);
bool pgInterfaceControlIs095(const unsigned char *controlFile);
PgControl pgInterfaceControl095(const unsigned char *controlFile);
bool pgInterfaceWalIs095(const unsigned char *walFile);
PgWal pgInterfaceWal095(const unsigned char *controlFile);
bool pgInterfaceControlIs096(const unsigned char *controlFile);
PgControl pgInterfaceControl096(const unsigned char *controlFile);
bool pgInterfaceWalIs096(const unsigned char *walFile);
PgWal pgInterfaceWal096(const unsigned char *controlFile);
bool pgInterfaceControlIs100(const unsigned char *controlFile);
PgControl pgInterfaceControl100(const unsigned char *controlFile);
bool pgInterfaceWalIs100(const unsigned char *walFile);
PgWal pgInterfaceWal100(const unsigned char *controlFile);
bool pgInterfaceControlIs110(const unsigned char *controlFile);
PgControl pgInterfaceControl110(const unsigned char *controlFile);
bool pgInterfaceWalIs110(const unsigned char *walFile);
PgWal pgInterfaceWal110(const unsigned char *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
#ifdef DEBUG
void pgInterfaceControlTest083(PgControl pgControl, unsigned char *buffer);
void pgInterfaceWalTest083(PgWal pgWal, unsigned char *buffer);
void pgInterfaceControlTest084(PgControl pgControl, unsigned char *buffer);
void pgInterfaceWalTest084(PgWal pgWal, unsigned char *buffer);
void pgInterfaceControlTest090(PgControl pgControl, unsigned char *buffer);
void pgInterfaceWalTest090(PgWal pgWal, unsigned char *buffer);
void pgInterfaceControlTest091(PgControl pgControl, unsigned char *buffer);
void pgInterfaceWalTest091(PgWal pgWal, unsigned char *buffer);
void pgInterfaceControlTest092(PgControl pgControl, unsigned char *buffer);
void pgInterfaceWalTest092(PgWal pgWal, unsigned char *buffer);
void pgInterfaceControlTest093(PgControl pgControl, unsigned char *buffer);
void pgInterfaceWalTest093(PgWal pgWal, unsigned char *buffer);
void pgInterfaceControlTest094(PgControl pgControl, unsigned char *buffer);
void pgInterfaceWalTest094(PgWal pgWal, unsigned char *buffer);
void pgInterfaceControlTest095(PgControl pgControl, unsigned char *buffer);
void pgInterfaceWalTest095(PgWal pgWal, unsigned char *buffer);
void pgInterfaceControlTest096(PgControl pgControl, unsigned char *buffer);
void pgInterfaceWalTest096(PgWal pgWal, unsigned char *buffer);
void pgInterfaceControlTest100(PgControl pgControl, unsigned char *buffer);
void pgInterfaceWalTest100(PgWal pgWal, unsigned char *buffer);
void pgInterfaceControlTest110(PgControl pgControl, unsigned char *buffer);
void pgInterfaceWalTest110(PgWal pgWal, unsigned char *buffer);
#endif
#endif

View File

@ -0,0 +1,209 @@
/***********************************************************************************************************************************
PostgreSQL Version Interface
Macros for building version-specific functions that interface with the types in version.auto.h. Due to the way PostgreSQL types
evolve over time, this seems to be the easiest way to extract information from them.
These macros should be kept as simple as possible, with most of the logic contained in postgres/interface.c.
Each version of PostgreSQL will need a vXXX.c file to contain the version-specific functions created by these macros.
***********************************************************************************************************************************/
#ifndef POSTGRES_INTERFACE_IMPLEMENTATION_H
#define POSTGRES_INTERFACE_IMPLEMENTATION_H
#include "common/debug.h"
#include "postgres/interface/version.h"
#include "postgres/version.h"
#include "postgres/interface/version.auto.h"
/***********************************************************************************************************************************
Determine if the supplied pg_control is for this version of PostgreSQL
***********************************************************************************************************************************/
#if PG_VERSION > PG_VERSION_MAX
#elif PG_VERSION >= PG_VERSION_83
#define PG_INTERFACE_CONTROL_IS(version) \
bool \
pgInterfaceControlIs##version(const unsigned char *controlFile) \
{ \
ASSERT(controlFile != NULL); \
\
return \
((ControlFileData *)controlFile)->pg_control_version == PG_CONTROL_VERSION && \
((ControlFileData *)controlFile)->catalog_version_no == CATALOG_VERSION_NO; \
}
#endif
/***********************************************************************************************************************************
Read the version specific pg_control into a general data structure
***********************************************************************************************************************************/
#if PG_VERSION > PG_VERSION_MAX
#elif PG_VERSION >= PG_VERSION_93
#define PG_INTERFACE_CONTROL(version) \
PgControl \
pgInterfaceControl##version(const unsigned char *controlFile) \
{ \
ASSERT(controlFile != NULL); \
ASSERT(pgInterfaceControlIs##version(controlFile)); \
\
return (PgControl) \
{ \
.systemId = ((ControlFileData *)controlFile)->system_identifier, \
.controlVersion = ((ControlFileData *)controlFile)->pg_control_version, \
.catalogVersion = ((ControlFileData *)controlFile)->catalog_version_no, \
.pageSize = ((ControlFileData *)controlFile)->blcksz, \
.walSegmentSize = ((ControlFileData *)controlFile)->xlog_seg_size, \
.pageChecksum = ((ControlFileData *)controlFile)->data_checksum_version != 0, \
}; \
}
#elif PG_VERSION >= PG_VERSION_83
#define PG_INTERFACE_CONTROL(version) \
PgControl \
pgInterfaceControl##version(const unsigned char *controlFile) \
{ \
ASSERT(controlFile != NULL); \
ASSERT(pgInterfaceControlIs##version(controlFile)); \
\
return (PgControl) \
{ \
.systemId = ((ControlFileData *)controlFile)->system_identifier, \
.controlVersion = ((ControlFileData *)controlFile)->pg_control_version, \
.catalogVersion = ((ControlFileData *)controlFile)->catalog_version_no, \
.pageSize = ((ControlFileData *)controlFile)->blcksz, \
.walSegmentSize = ((ControlFileData *)controlFile)->xlog_seg_size, \
}; \
}
#endif
/***********************************************************************************************************************************
Create a pg_control file for testing
***********************************************************************************************************************************/
#if PG_VERSION > PG_VERSION_MAX
#elif PG_VERSION >= PG_VERSION_93
#define PG_INTERFACE_CONTROL_TEST(version) \
void \
pgInterfaceControlTest##version(PgControl pgControl, unsigned char *buffer) \
{ \
ASSERT(buffer != NULL); \
\
((ControlFileData *)buffer)->system_identifier = pgControl.systemId; \
((ControlFileData *)buffer)->pg_control_version = \
pgControl.controlVersion == 0 ? PG_CONTROL_VERSION : pgControl.controlVersion; \
((ControlFileData *)buffer)->catalog_version_no = \
pgControl.catalogVersion == 0 ? CATALOG_VERSION_NO : pgControl.catalogVersion; \
((ControlFileData *)buffer)->blcksz = pgControl.pageSize; \
((ControlFileData *)buffer)->xlog_seg_size = pgControl.walSegmentSize; \
((ControlFileData *)buffer)->data_checksum_version = pgControl.pageChecksum; \
}
#elif PG_VERSION >= PG_VERSION_83
#define PG_INTERFACE_CONTROL_TEST(version) \
void \
pgInterfaceControlTest##version(PgControl pgControl, unsigned char *buffer) \
{ \
ASSERT(buffer != NULL); \
ASSERT(!pgControl.pageChecksum); \
\
((ControlFileData *)buffer)->system_identifier = pgControl.systemId; \
((ControlFileData *)buffer)->pg_control_version = \
pgControl.controlVersion == 0 ? PG_CONTROL_VERSION : pgControl.controlVersion; \
((ControlFileData *)buffer)->catalog_version_no = \
pgControl.catalogVersion == 0 ? CATALOG_VERSION_NO : pgControl.catalogVersion; \
((ControlFileData *)buffer)->blcksz = pgControl.pageSize; \
((ControlFileData *)buffer)->xlog_seg_size = pgControl.walSegmentSize; \
}
#endif
/***********************************************************************************************************************************
Determine if the supplied WAL is for this version of PostgreSQL
***********************************************************************************************************************************/
#if PG_VERSION > PG_VERSION_MAX
#elif PG_VERSION >= PG_VERSION_83
#define PG_INTERFACE_WAL_IS(version) \
bool \
pgInterfaceWalIs##version(const unsigned char *walFile) \
{ \
ASSERT(walFile != NULL); \
\
return ((XLogPageHeaderData *)walFile)->xlp_magic == XLOG_PAGE_MAGIC; \
}
#endif
/***********************************************************************************************************************************
Read the version specific WAL header into a general data structure
***********************************************************************************************************************************/
#if PG_VERSION > PG_VERSION_MAX
#elif PG_VERSION >= PG_VERSION_83
#define PG_INTERFACE_WAL(version) \
PgWal \
pgInterfaceWal##version(const unsigned char *walFile) \
{ \
ASSERT(walFile != NULL); \
ASSERT(pgInterfaceWalIs##version(walFile)); \
\
return (PgWal) \
{ \
.systemId = ((XLogLongPageHeaderData *)walFile)->xlp_sysid, \
}; \
}
#endif
/***********************************************************************************************************************************
Create a WAL file file for testing
***********************************************************************************************************************************/
#if PG_VERSION > PG_VERSION_MAX
#elif PG_VERSION >= PG_VERSION_83
#define PG_INTERFACE_WAL_TEST(version) \
void \
pgInterfaceWalTest##version(PgWal pgWal, unsigned char *buffer) \
{ \
((XLogLongPageHeaderData *)buffer)->std.xlp_magic = XLOG_PAGE_MAGIC; \
((XLogLongPageHeaderData *)buffer)->xlp_sysid = pgWal.systemId; \
}
#endif
/***********************************************************************************************************************************
Call all macros with a single macro to make the vXXX.c files as simple as possible
***********************************************************************************************************************************/
#define PG_INTERFACE_BASE(version) \
PG_INTERFACE_CONTROL_IS(version) \
PG_INTERFACE_CONTROL(version) \
PG_INTERFACE_WAL_IS(version) \
PG_INTERFACE_WAL(version)
#ifdef DEBUG
#define PG_INTERFACE(version) \
PG_INTERFACE_BASE(version) \
PG_INTERFACE_CONTROL_TEST(version) \
PG_INTERFACE_WAL_TEST(version)
#else
#define PG_INTERFACE(version) \
PG_INTERFACE_BASE(version)
#endif
#endif

View File

@ -24,6 +24,8 @@ PostgreSQL version constants
#define PG_VERSION_10 100000
#define PG_VERSION_11 110000
#define PG_VERSION_MAX PG_VERSION_11
/***********************************************************************************************************************************
PostgreSQL version string constants for use in error messages
***********************************************************************************************************************************/