diff --git a/doc/xml/release.xml b/doc/xml/release.xml index ad31a71e7..aca44e5d3 100644 --- a/doc/xml/release.xml +++ b/doc/xml/release.xml @@ -57,6 +57,10 @@

Remove redundant documentation from interface files and clarify ambiguous function names.

+ +

Add WAL info to interface.

+
+

Move WAL path prefix logic into walPath().

diff --git a/src/postgres/interface.c b/src/postgres/interface.c index 3e0c449d3..35353a21c 100644 --- a/src/postgres/interface.c +++ b/src/postgres/interface.c @@ -43,6 +43,12 @@ really old storage with 512-byte sectors. This is true across all versions of P #define PG_CONTROL_SIZE ((unsigned int)(8 * 1024)) #define PG_CONTROL_DATA_SIZE ((unsigned int)(512)) +/*********************************************************************************************************************************** +WAL header size. It doesn't seem worth tracking the exact size of the WAL header across versions of PostgreSQL so just set it to +something far larger needed but <= the minimum read size on just about any system. +***********************************************************************************************************************************/ +#define PG_WAL_HEADER_SIZE ((unsigned int)(512)) + /*********************************************************************************************************************************** PostgreSQL interface definitions @@ -61,9 +67,19 @@ typedef struct PgInterface // Convert pg_control to a common data structure PgControl (*control)(const Buffer *); + // Does the WAL header match this version of PostgreSQL? + bool (*walIs)(const Buffer *); + + // Convert WAL header to a common data structure + PgWal (*wal)(const Buffer *); + #ifdef DEBUG + // Create pg_control for testing void (*controlTest)(PgControl, Buffer *); + + // Create WAL header for testing + void (*walTest)(PgWal, Buffer *); #endif } PgInterface; @@ -75,8 +91,12 @@ static const PgInterface pgInterface[] = .controlIs = pgInterfaceControlIs110, .control = pgInterfaceControl110, + .walIs = pgInterfaceWalIs110, + .wal = pgInterfaceWal110, + #ifdef DEBUG .controlTest = pgInterfaceControlTest110, + .walTest = pgInterfaceWalTest110, #endif }, { @@ -85,8 +105,12 @@ static const PgInterface pgInterface[] = .controlIs = pgInterfaceControlIs100, .control = pgInterfaceControl100, + .walIs = pgInterfaceWalIs100, + .wal = pgInterfaceWal100, + #ifdef DEBUG .controlTest = pgInterfaceControlTest100, + .walTest = pgInterfaceWalTest100, #endif }, { @@ -95,8 +119,12 @@ static const PgInterface pgInterface[] = .controlIs = pgInterfaceControlIs096, .control = pgInterfaceControl096, + .walIs = pgInterfaceWalIs096, + .wal = pgInterfaceWal096, + #ifdef DEBUG .controlTest = pgInterfaceControlTest096, + .walTest = pgInterfaceWalTest096, #endif }, { @@ -105,8 +133,12 @@ static const PgInterface pgInterface[] = .controlIs = pgInterfaceControlIs095, .control = pgInterfaceControl095, + .walIs = pgInterfaceWalIs095, + .wal = pgInterfaceWal095, + #ifdef DEBUG .controlTest = pgInterfaceControlTest095, + .walTest = pgInterfaceWalTest095, #endif }, { @@ -115,8 +147,12 @@ static const PgInterface pgInterface[] = .controlIs = pgInterfaceControlIs094, .control = pgInterfaceControl094, + .walIs = pgInterfaceWalIs094, + .wal = pgInterfaceWal094, + #ifdef DEBUG .controlTest = pgInterfaceControlTest094, + .walTest = pgInterfaceWalTest094, #endif }, { @@ -125,8 +161,12 @@ static const PgInterface pgInterface[] = .controlIs = pgInterfaceControlIs093, .control = pgInterfaceControl093, + .walIs = pgInterfaceWalIs093, + .wal = pgInterfaceWal093, + #ifdef DEBUG .controlTest = pgInterfaceControlTest093, + .walTest = pgInterfaceWalTest093, #endif }, { @@ -135,8 +175,12 @@ static const PgInterface pgInterface[] = .controlIs = pgInterfaceControlIs092, .control = pgInterfaceControl092, + .walIs = pgInterfaceWalIs092, + .wal = pgInterfaceWal092, + #ifdef DEBUG .controlTest = pgInterfaceControlTest092, + .walTest = pgInterfaceWalTest092, #endif }, { @@ -145,8 +189,12 @@ static const PgInterface pgInterface[] = .controlIs = pgInterfaceControlIs091, .control = pgInterfaceControl091, + .walIs = pgInterfaceWalIs091, + .wal = pgInterfaceWal091, + #ifdef DEBUG .controlTest = pgInterfaceControlTest091, + .walTest = pgInterfaceWalTest091, #endif }, { @@ -155,8 +203,12 @@ static const PgInterface pgInterface[] = .controlIs = pgInterfaceControlIs090, .control = pgInterfaceControl090, + .walIs = pgInterfaceWalIs090, + .wal = pgInterfaceWal090, + #ifdef DEBUG .controlTest = pgInterfaceControlTest090, + .walTest = pgInterfaceWalTest090, #endif }, { @@ -165,8 +217,12 @@ static const PgInterface pgInterface[] = .controlIs = pgInterfaceControlIs084, .control = pgInterfaceControl084, + .walIs = pgInterfaceWalIs084, + .wal = pgInterfaceWal084, + #ifdef DEBUG .controlTest = pgInterfaceControlTest084, + .walTest = pgInterfaceWalTest084, #endif }, { @@ -175,8 +231,12 @@ static const PgInterface pgInterface[] = .controlIs = pgInterfaceControlIs083, .control = pgInterfaceControl083, + .walIs = pgInterfaceWalIs083, + .wal = pgInterfaceWal083, + #ifdef DEBUG .controlTest = pgInterfaceControlTest083, + .walTest = pgInterfaceWalTest083, #endif }, }; @@ -275,6 +335,89 @@ pgControlFromFile(const String *pgPath) FUNCTION_LOG_RETURN(PG_CONTROL, result); } +/*********************************************************************************************************************************** +These WAL header fields are common to all versions of PostgreSQL, so we can use them to generate error messages when the WAL magic +cannot be found. +***********************************************************************************************************************************/ +typedef struct PgWalCommon +{ + uint16_t magic; + uint16_t flag; +} PgWalCommon; + +#define PG_WAL_LONG_HEADER 0x0002 + +/*********************************************************************************************************************************** +Get info from WAL header +***********************************************************************************************************************************/ +PgWal +pgWalFromBuffer(const Buffer *walBuffer) +{ + FUNCTION_LOG_BEGIN(logLevelTrace); + FUNCTION_LOG_PARAM(BUFFER, walBuffer); + FUNCTION_LOG_END(); + + ASSERT(walBuffer != NULL); + + // Check that this is a long format WAL header + if (!(((PgWalCommon *)bufPtr(walBuffer))->flag & PG_WAL_LONG_HEADER)) + THROW_FMT(FormatError, "first page header in WAL file is expected to be in long format"); + + // 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++) + { + if (pgInterface[interfaceIdx].walIs(walBuffer)) + { + interface = &pgInterface[interfaceIdx]; + break; + } + } + + // If the version was not found then error with the magic that was found + if (interface == NULL) + { + THROW_FMT( + VersionNotSupportedError, + "unexpected WAL magic %u\n" + "HINT: is this version of PostgreSQL supported?", + ((PgWalCommon *)bufPtr(walBuffer))->magic); + } + + // Get info from the control file + PgWal result = interface->wal(walBuffer); + result.version = interface->version; + + FUNCTION_LOG_RETURN(PG_WAL, result); +} + +/*********************************************************************************************************************************** +Get info from a WAL segment +***********************************************************************************************************************************/ +PgWal +pgWalFromFile(const String *walFile) +{ + FUNCTION_LOG_BEGIN(logLevelDebug); + FUNCTION_LOG_PARAM(STRING, walFile); + FUNCTION_LOG_END(); + + ASSERT(walFile != NULL); + + PgWal result = {0}; + + MEM_CONTEXT_TEMP_BEGIN() + { + // Read WAL segment header + Buffer *walBuffer = storageGetP(storageNewReadNP(storageLocal(), walFile), .exactSize = PG_WAL_HEADER_SIZE); + + result = pgWalFromBuffer(walBuffer); + } + MEM_CONTEXT_TEMP_END(); + + FUNCTION_LOG_RETURN(PG_WAL, result); +} + /*********************************************************************************************************************************** Create pg_control for testing ***********************************************************************************************************************************/ @@ -318,6 +461,38 @@ pgControlTestToBuffer(PgControl pgControl) FUNCTION_TEST_RETURN(result); } +void +pgWalTestToBuffer(PgWal pgWal, Buffer *walBuffer) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(PG_WAL, pgWal); + FUNCTION_TEST_PARAM(BUFFER, walBuffer); + FUNCTION_TEST_END(); + + ASSERT(walBuffer != NULL); + + // Find the interface for the version of PostgreSQL + const PgInterface *interface = NULL; + + for (unsigned int interfaceIdx = 0; interfaceIdx < sizeof(pgInterface) / sizeof(PgInterface); interfaceIdx++) + { + if (pgInterface[interfaceIdx].version == pgWal.version) + { + interface = &pgInterface[interfaceIdx]; + break; + } + } + + // If the version was not found then error + if (interface == NULL) + THROW_FMT(AssertError, "invalid version %u", pgWal.version); + + // Generate pg_control + interface->walTest(pgWal, walBuffer); + + FUNCTION_TEST_RETURN_VOID(); +} + #endif /*********************************************************************************************************************************** @@ -387,3 +562,9 @@ pgControlToLog(const PgControl *pgControl) "{version: %u, systemId: %" PRIu64 ", walSegmentSize: %u, pageChecksum: %s}", pgControl->version, pgControl->systemId, pgControl->walSegmentSize, cvtBoolToConstZ(pgControl->pageChecksum)); } + +String * +pgWalToLog(const PgWal *pgWal) +{ + return strNewFmt("{version: %u, systemId: %" PRIu64 "}", pgWal->version, pgWal->systemId); +} diff --git a/src/postgres/interface.h b/src/postgres/interface.h index 542de01e6..273ad8ef6 100644 --- a/src/postgres/interface.h +++ b/src/postgres/interface.h @@ -33,6 +33,15 @@ typedef struct PgControl bool pageChecksum; } PgControl; +/*********************************************************************************************************************************** +PostgreSQL WAL Info +***********************************************************************************************************************************/ +typedef struct PgWal +{ + unsigned int version; + uint64_t systemId; +} PgWal; + /*********************************************************************************************************************************** Functions ***********************************************************************************************************************************/ @@ -41,21 +50,31 @@ PgControl pgControlFromBuffer(const Buffer *controlFile); unsigned int pgVersionFromStr(const String *version); String *pgVersionToStr(unsigned int version); +PgWal pgWalFromFile(const String *walFile); +PgWal pgWalFromBuffer(const Buffer *walBuffer); + /*********************************************************************************************************************************** Test Functions ***********************************************************************************************************************************/ #ifdef DEBUG Buffer *pgControlTestToBuffer(PgControl pgControl); + void pgWalTestToBuffer(PgWal pgWal, Buffer *walBuffer); #endif /*********************************************************************************************************************************** Macros for function logging ***********************************************************************************************************************************/ String *pgControlToLog(const PgControl *pgControl); +String *pgWalToLog(const PgWal *pgWal); #define FUNCTION_LOG_PG_CONTROL_TYPE \ PgControl #define FUNCTION_LOG_PG_CONTROL_FORMAT(value, buffer, bufferSize) \ FUNCTION_LOG_STRING_OBJECT_FORMAT(&value, pgControlToLog, buffer, bufferSize) +#define FUNCTION_LOG_PG_WAL_TYPE \ + PgWal +#define FUNCTION_LOG_PG_WAL_FORMAT(value, buffer, bufferSize) \ + FUNCTION_LOG_STRING_OBJECT_FORMAT(&value, pgWalToLog, buffer, bufferSize) + #endif diff --git a/src/postgres/interface/v083.auto.c b/src/postgres/interface/v083.auto.c index cbdeff4d1..9ce2d9171 100644 --- a/src/postgres/interface/v083.auto.c +++ b/src/postgres/interface/v083.auto.c @@ -6,6 +6,7 @@ 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; @@ -201,3 +202,35 @@ typedef struct ControlFileData /* 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 diff --git a/src/postgres/interface/v083.c b/src/postgres/interface/v083.c index 290c06014..a0ca82f5e 100644 --- a/src/postgres/interface/v083.c +++ b/src/postgres/interface/v083.c @@ -49,6 +49,37 @@ pgInterfaceControl083(const Buffer *controlFile) 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 /**********************************************************************************************************************************/ @@ -71,4 +102,20 @@ pgInterfaceControlTest083(PgControl pgControl, Buffer *buffer) 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 diff --git a/src/postgres/interface/v083.h b/src/postgres/interface/v083.h index 471987eaf..fe5d7806c 100644 --- a/src/postgres/interface/v083.h +++ b/src/postgres/interface/v083.h @@ -11,12 +11,15 @@ 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 diff --git a/src/postgres/interface/v084.auto.c b/src/postgres/interface/v084.auto.c index 0471b55f2..8f8eccbaf 100644 --- a/src/postgres/interface/v084.auto.c +++ b/src/postgres/interface/v084.auto.c @@ -6,6 +6,7 @@ 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; @@ -206,3 +207,35 @@ typedef struct ControlFileData /* 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 diff --git a/src/postgres/interface/v084.c b/src/postgres/interface/v084.c index 17c55aac9..2cca4a5f3 100644 --- a/src/postgres/interface/v084.c +++ b/src/postgres/interface/v084.c @@ -49,6 +49,37 @@ pgInterfaceControl084(const Buffer *controlFile) 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 /**********************************************************************************************************************************/ @@ -71,4 +102,20 @@ pgInterfaceControlTest084(PgControl pgControl, Buffer *buffer) 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 diff --git a/src/postgres/interface/v084.h b/src/postgres/interface/v084.h index 24b0c78dc..ceab85176 100644 --- a/src/postgres/interface/v084.h +++ b/src/postgres/interface/v084.h @@ -11,12 +11,15 @@ 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 diff --git a/src/postgres/interface/v090.auto.c b/src/postgres/interface/v090.auto.c index ef66c7f78..7eb6d38b4 100644 --- a/src/postgres/interface/v090.auto.c +++ b/src/postgres/interface/v090.auto.c @@ -6,6 +6,7 @@ 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; @@ -250,3 +251,35 @@ typedef struct ControlFileData /* 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 diff --git a/src/postgres/interface/v090.c b/src/postgres/interface/v090.c index 7ccdef515..162511625 100644 --- a/src/postgres/interface/v090.c +++ b/src/postgres/interface/v090.c @@ -49,6 +49,37 @@ pgInterfaceControl090(const Buffer *controlFile) 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 /**********************************************************************************************************************************/ @@ -71,4 +102,20 @@ pgInterfaceControlTest090(PgControl pgControl, Buffer *buffer) 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 diff --git a/src/postgres/interface/v090.h b/src/postgres/interface/v090.h index 1105daf88..dd6c350a3 100644 --- a/src/postgres/interface/v090.h +++ b/src/postgres/interface/v090.h @@ -11,12 +11,15 @@ 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 diff --git a/src/postgres/interface/v091.auto.c b/src/postgres/interface/v091.auto.c index 5929de710..2051fbf72 100644 --- a/src/postgres/interface/v091.auto.c +++ b/src/postgres/interface/v091.auto.c @@ -6,6 +6,7 @@ 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; @@ -250,3 +251,35 @@ typedef struct ControlFileData /* 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 diff --git a/src/postgres/interface/v091.c b/src/postgres/interface/v091.c index ec1214692..2abb0f6c1 100644 --- a/src/postgres/interface/v091.c +++ b/src/postgres/interface/v091.c @@ -49,6 +49,37 @@ pgInterfaceControl091(const Buffer *controlFile) 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 /**********************************************************************************************************************************/ @@ -71,4 +102,20 @@ pgInterfaceControlTest091(PgControl pgControl, Buffer *buffer) 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 diff --git a/src/postgres/interface/v091.h b/src/postgres/interface/v091.h index 906e436de..add914ddc 100644 --- a/src/postgres/interface/v091.h +++ b/src/postgres/interface/v091.h @@ -11,12 +11,15 @@ 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 diff --git a/src/postgres/interface/v092.auto.c b/src/postgres/interface/v092.auto.c index 913fb38c4..e06e6d631 100644 --- a/src/postgres/interface/v092.auto.c +++ b/src/postgres/interface/v092.auto.c @@ -6,6 +6,7 @@ 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; @@ -265,3 +266,35 @@ typedef struct ControlFileData /* 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 diff --git a/src/postgres/interface/v092.c b/src/postgres/interface/v092.c index e350f6f61..9e57ac452 100644 --- a/src/postgres/interface/v092.c +++ b/src/postgres/interface/v092.c @@ -49,6 +49,37 @@ pgInterfaceControl092(const Buffer *controlFile) 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 /**********************************************************************************************************************************/ @@ -71,4 +102,20 @@ pgInterfaceControlTest092(PgControl pgControl, Buffer *buffer) 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 diff --git a/src/postgres/interface/v092.h b/src/postgres/interface/v092.h index fc6a00848..63aad6f4a 100644 --- a/src/postgres/interface/v092.h +++ b/src/postgres/interface/v092.h @@ -11,12 +11,15 @@ 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 diff --git a/src/postgres/interface/v093.auto.c b/src/postgres/interface/v093.auto.c index 924c9ff4f..fb5a4841f 100644 --- a/src/postgres/interface/v093.auto.c +++ b/src/postgres/interface/v093.auto.c @@ -6,6 +6,7 @@ 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; @@ -260,3 +261,46 @@ typedef struct ControlFileData /* 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 diff --git a/src/postgres/interface/v093.c b/src/postgres/interface/v093.c index c72619178..34b6aca08 100644 --- a/src/postgres/interface/v093.c +++ b/src/postgres/interface/v093.c @@ -51,6 +51,37 @@ pgInterfaceControl093(const Buffer *controlFile) 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 /**********************************************************************************************************************************/ @@ -75,4 +106,20 @@ pgInterfaceControlTest093(PgControl pgControl, Buffer *buffer) 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 diff --git a/src/postgres/interface/v093.h b/src/postgres/interface/v093.h index 8a6443545..b4d7bcce6 100644 --- a/src/postgres/interface/v093.h +++ b/src/postgres/interface/v093.h @@ -11,12 +11,15 @@ 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 diff --git a/src/postgres/interface/v094.auto.c b/src/postgres/interface/v094.auto.c index a50905df1..159575207 100644 --- a/src/postgres/interface/v094.auto.c +++ b/src/postgres/interface/v094.auto.c @@ -6,6 +6,7 @@ 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; @@ -263,3 +264,46 @@ typedef struct ControlFileData /* 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 diff --git a/src/postgres/interface/v094.c b/src/postgres/interface/v094.c index a510f0748..fc65ab740 100644 --- a/src/postgres/interface/v094.c +++ b/src/postgres/interface/v094.c @@ -51,6 +51,37 @@ pgInterfaceControl094(const Buffer *controlFile) 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 /**********************************************************************************************************************************/ @@ -75,4 +106,20 @@ pgInterfaceControlTest094(PgControl pgControl, Buffer *buffer) 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 diff --git a/src/postgres/interface/v094.h b/src/postgres/interface/v094.h index f5645879c..055f9d460 100644 --- a/src/postgres/interface/v094.h +++ b/src/postgres/interface/v094.h @@ -11,12 +11,15 @@ 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 diff --git a/src/postgres/interface/v095.auto.c b/src/postgres/interface/v095.auto.c index 0ca268ce6..935ffbe1a 100644 --- a/src/postgres/interface/v095.auto.c +++ b/src/postgres/interface/v095.auto.c @@ -6,6 +6,7 @@ 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; @@ -268,3 +269,46 @@ typedef struct ControlFileData /* 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 diff --git a/src/postgres/interface/v095.c b/src/postgres/interface/v095.c index 558b60f25..341907dcc 100644 --- a/src/postgres/interface/v095.c +++ b/src/postgres/interface/v095.c @@ -51,6 +51,37 @@ pgInterfaceControl095(const Buffer *controlFile) 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 /**********************************************************************************************************************************/ @@ -75,4 +106,20 @@ pgInterfaceControlTest095(PgControl pgControl, Buffer *buffer) 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 diff --git a/src/postgres/interface/v095.h b/src/postgres/interface/v095.h index 6d9006028..e1a610c07 100644 --- a/src/postgres/interface/v095.h +++ b/src/postgres/interface/v095.h @@ -11,12 +11,15 @@ 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 diff --git a/src/postgres/interface/v096.auto.c b/src/postgres/interface/v096.auto.c index 2439e8145..0b93cf87d 100644 --- a/src/postgres/interface/v096.auto.c +++ b/src/postgres/interface/v096.auto.c @@ -6,6 +6,7 @@ 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; @@ -268,3 +269,46 @@ typedef struct ControlFileData /* 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 diff --git a/src/postgres/interface/v096.c b/src/postgres/interface/v096.c index 06dc342d5..9d6365deb 100644 --- a/src/postgres/interface/v096.c +++ b/src/postgres/interface/v096.c @@ -51,6 +51,37 @@ pgInterfaceControl096(const Buffer *controlFile) 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 /**********************************************************************************************************************************/ @@ -75,4 +106,20 @@ pgInterfaceControlTest096(PgControl pgControl, Buffer *buffer) 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 diff --git a/src/postgres/interface/v096.h b/src/postgres/interface/v096.h index 15724969a..77d079aef 100644 --- a/src/postgres/interface/v096.h +++ b/src/postgres/interface/v096.h @@ -11,12 +11,15 @@ 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 diff --git a/src/postgres/interface/v100.auto.c b/src/postgres/interface/v100.auto.c index 9202e5637..07308ee46 100644 --- a/src/postgres/interface/v100.auto.c +++ b/src/postgres/interface/v100.auto.c @@ -6,6 +6,7 @@ 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; @@ -271,3 +272,46 @@ typedef struct ControlFileData /* 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 diff --git a/src/postgres/interface/v100.c b/src/postgres/interface/v100.c index dd7fb6c86..8aefbe5e7 100644 --- a/src/postgres/interface/v100.c +++ b/src/postgres/interface/v100.c @@ -51,6 +51,37 @@ pgInterfaceControl100(const Buffer *controlFile) 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 /**********************************************************************************************************************************/ @@ -75,4 +106,20 @@ pgInterfaceControlTest100(PgControl pgControl, Buffer *buffer) 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 diff --git a/src/postgres/interface/v100.h b/src/postgres/interface/v100.h index 3de945d8a..ab458ed7e 100644 --- a/src/postgres/interface/v100.h +++ b/src/postgres/interface/v100.h @@ -11,12 +11,15 @@ 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 diff --git a/src/postgres/interface/v110.auto.c b/src/postgres/interface/v110.auto.c index e48fd6d62..ace681cff 100644 --- a/src/postgres/interface/v110.auto.c +++ b/src/postgres/interface/v110.auto.c @@ -6,6 +6,7 @@ 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; @@ -270,3 +271,46 @@ typedef struct ControlFileData /* 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 diff --git a/src/postgres/interface/v110.c b/src/postgres/interface/v110.c index ba47d1265..6f7e58d4b 100644 --- a/src/postgres/interface/v110.c +++ b/src/postgres/interface/v110.c @@ -51,6 +51,37 @@ pgInterfaceControl110(const Buffer *controlFile) 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 /**********************************************************************************************************************************/ @@ -75,4 +106,20 @@ pgInterfaceControlTest110(PgControl pgControl, Buffer *buffer) 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 diff --git a/src/postgres/interface/v110.h b/src/postgres/interface/v110.h index 5272f4b79..2beb07680 100644 --- a/src/postgres/interface/v110.h +++ b/src/postgres/interface/v110.h @@ -11,12 +11,15 @@ 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 diff --git a/test/define.yaml b/test/define.yaml index 70f86979c..117fe01e0 100644 --- a/test/define.yaml +++ b/test/define.yaml @@ -330,7 +330,7 @@ unit: test: # ---------------------------------------------------------------------------------------------------------------------------- - name: interface - total: 3 + total: 5 coverage: postgres/interface: full diff --git a/test/src/module/postgres/interfaceTest.c b/test/src/module/postgres/interfaceTest.c index 11a741741..ff1ea5165 100644 --- a/test/src/module/postgres/interfaceTest.c +++ b/test/src/module/postgres/interfaceTest.c @@ -89,6 +89,50 @@ testRun(void) TEST_RESULT_INT(info.version, PG_VERSION_83, " check version"); } + // ***************************************************************************************************************************** + if (testBegin("pgWalFromBuffer() and pgWalFromFile()")) + { + String *walFile = strNewFmt("%s/0000000F0000000F0000000F", testPath()); + + // Create a bogus control file, initially not in long format) + // -------------------------------------------------------------------------------------------------------------------------- + Buffer *result = bufNew((size_t)16 * 1024 * 1024); + memset(bufPtr(result), 0, bufSize(result)); + bufUsedSet(result, bufSize(result)); + ((PgWalCommon *)bufPtr(result))->magic = 777; + + TEST_ERROR(pgWalFromBuffer(result), FormatError, "first page header in WAL file is expected to be in long format"); + + // Add the long flag so that the version will now error + // -------------------------------------------------------------------------------------------------------------------------- + ((PgWalCommon *)bufPtr(result))->flag = PG_WAL_LONG_HEADER; + + TEST_ERROR( + pgWalFromBuffer(result), VersionNotSupportedError, + "unexpected WAL magic 777\n" + "HINT: is this version of PostgreSQL supported?"); + + //-------------------------------------------------------------------------------------------------------------------------- + TEST_ERROR(pgWalTestToBuffer((PgWal){.version = 0}, result), AssertError, "invalid version 0"); + + //-------------------------------------------------------------------------------------------------------------------------- + pgWalTestToBuffer((PgWal){.version = PG_VERSION_11, .systemId = 0xECAFECAF}, result); + storagePutNP(storageNewWriteNP(storageTest, walFile), result); + + PgWal info = {0}; + TEST_ASSIGN(info, pgWalFromFile(walFile), "get wal info v11"); + TEST_RESULT_INT(info.systemId, 0xECAFECAF, " check system id"); + TEST_RESULT_INT(info.version, PG_VERSION_11, " check version"); + + //-------------------------------------------------------------------------------------------------------------------------- + pgWalTestToBuffer((PgWal){.version = PG_VERSION_83, .systemId = 0xEAEAEAEA}, result); + storagePutNP(storageNewWriteNP(storageTest, walFile), result); + + TEST_ASSIGN(info, pgWalFromFile(walFile), "get wal info v8.3"); + TEST_RESULT_INT(info.systemId, 0xEAEAEAEA, " check system id"); + TEST_RESULT_INT(info.version, PG_VERSION_83, " check version"); + } + // ***************************************************************************************************************************** if (testBegin("pgControlToLog()")) { @@ -105,5 +149,20 @@ testRun(void) "{version: 110000, systemId: 1030522662895, walSegmentSize: 16777216, pageChecksum: true}", "check log"); } + + // ***************************************************************************************************************************** + if (testBegin("pgWalToLog()")) + { + PgWal pgWal = + { + .version = PG_VERSION_10, + .systemId = 0xFEFEFEFEFE + }; + + TEST_RESULT_STR( + strPtr(pgWalToLog(&pgWal)), + "{version: 100000, systemId: 1095199817470}", "check log"); + } + FUNCTION_HARNESS_RESULT_VOID(); }