From 321a28f6b0c6c522b8b8120e9fccfec09de4c6f4 Mon Sep 17 00:00:00 2001 From: David Steele Date: Sun, 29 Apr 2018 11:47:50 -0400 Subject: [PATCH] Add walSegmentNext() and walSegmentRange(). --- doc/xml/release.xml | 4 ++ src/command/archive/common.c | 83 ++++++++++++++++++++++++++++ src/command/archive/common.h | 6 +- test/define.yaml | 2 +- test/src/module/archive/commonTest.c | 48 ++++++++++++++++ 5 files changed, 141 insertions(+), 2 deletions(-) diff --git a/doc/xml/release.xml b/doc/xml/release.xml index 42f1bafd8..8ce3a77f3 100644 --- a/doc/xml/release.xml +++ b/doc/xml/release.xml @@ -90,6 +90,10 @@

Add pgControlInfo() to read pg_control and determine the version.

+ +

Add walSegmentNext() and walSegmentRange().

+
+

Add THROWP_* macro variants for error handling. These macros allow an ErrorType pointer to be passed and are required for functions that may return different errors based on a parameter.

diff --git a/src/command/archive/common.c b/src/command/archive/common.c index 42048d494..56d1b76b6 100644 --- a/src/command/archive/common.c +++ b/src/command/archive/common.c @@ -1,12 +1,16 @@ /*********************************************************************************************************************************** Archive Push Command ***********************************************************************************************************************************/ +#include +#include #include #include "command/archive/common.h" +#include "common/assert.h" #include "common/log.h" #include "common/memContext.h" #include "common/wait.h" +#include "postgres/version.h" #include "storage/helper.h" /*********************************************************************************************************************************** @@ -94,3 +98,82 @@ archiveAsyncStatus(const String *walSegment, bool confessOnError) return result; } + +/*********************************************************************************************************************************** +Get the next WAL segment given a WAL segment and WAL segment size +***********************************************************************************************************************************/ +String * +walSegmentNext(const String *walSegment, size_t walSegmentSize, uint pgVersion) +{ + ASSERT_DEBUG(walSegment != NULL); + ASSERT_DEBUG(strSize(walSegment) == 24); + ASSERT_DEBUG(UINT32_MAX % walSegmentSize == walSegmentSize - 1); + ASSERT_DEBUG(pgVersion >= PG_VERSION_11 || walSegmentSize == 16 * 1024 * 1024); + + // Extract WAL parts + uint32_t timeline = 0; + uint32_t major = 0; + uint32_t minor = 0; + + MEM_CONTEXT_TEMP_BEGIN() + { + timeline = (uint32_t)strtol(strPtr(strSubN(walSegment, 0, 8)), NULL, 16); + major = (uint32_t)strtol(strPtr(strSubN(walSegment, 8, 8)), NULL, 16); + minor = (uint32_t)strtol(strPtr(strSubN(walSegment, 16, 8)), NULL, 16); + + // Increment minor and adjust major dir on overflow + minor++; + + if (minor > UINT32_MAX / walSegmentSize) + { + major++; + minor = 0; + } + + // Special hack for PostgreSQL < 9.3 which skipped minor FF + if (minor == 0xFF && pgVersion < PG_VERSION_93) + { + major++; + minor = 0; + } + } + MEM_CONTEXT_TEMP_END(); + + return strNewFmt("%08X%08X%08X", timeline, major, minor); +} + +/*********************************************************************************************************************************** +Build a list of WAL segments based on a beginning WAL and number of WAL in the range (inclusive) +***********************************************************************************************************************************/ +StringList * +walSegmentRange(const String *walSegmentBegin, size_t walSegmentSize, uint pgVersion, uint range) +{ + ASSERT_DEBUG(range > 0); + + StringList *result = NULL; + + MEM_CONTEXT_TEMP_BEGIN() + { + result = strLstAdd(strLstNew(), walSegmentBegin); + + if (range > 1) + { + String *current = strDup(walSegmentBegin); + + for (uint rangeIdx = 0; rangeIdx < range - 1; rangeIdx++) + { + String *next = walSegmentNext(current, walSegmentSize, pgVersion); + + strLstAdd(result, next); + + strFree(current); + current = next; + } + } + + strLstMove(result, MEM_CONTEXT_OLD()); + } + MEM_CONTEXT_TEMP_END(); + + return result; +} diff --git a/src/command/archive/common.h b/src/command/archive/common.h index 45054a497..404c6a2a2 100644 --- a/src/command/archive/common.h +++ b/src/command/archive/common.h @@ -4,11 +4,15 @@ Archive Common #ifndef COMMAND_ARCHIVE_COMMON_H #define COMMAND_ARCHIVE_COMMON_H -#include "common/type/string.h" +#include + +#include "common/type/stringList.h" /*********************************************************************************************************************************** Functions ***********************************************************************************************************************************/ bool archiveAsyncStatus(const String *walSegment, bool confessOnError); +String *walSegmentNext(const String *walSegment, size_t walSegmentSize, uint pgVersion); +StringList *walSegmentRange(const String *walSegmentBegin, size_t walSegmentSize, uint pgVersion, uint range); #endif diff --git a/test/define.yaml b/test/define.yaml index 3a00b43a2..7cde400d9 100644 --- a/test/define.yaml +++ b/test/define.yaml @@ -506,7 +506,7 @@ unit: test: # ---------------------------------------------------------------------------------------------------------------------------- - name: common - total: 1 + total: 3 coverage: command/archive/common: full diff --git a/test/src/module/archive/commonTest.c b/test/src/module/archive/commonTest.c index 62fa4c6d3..effdfdc47 100644 --- a/test/src/module/archive/commonTest.c +++ b/test/src/module/archive/commonTest.c @@ -87,4 +87,52 @@ testRun() unlink(strPtr(storagePathNP(storageSpool(), strNewFmt(STORAGE_SPOOL_ARCHIVE_OUT "/%s.error", strPtr(segment))))); } + + // ***************************************************************************************************************************** + if (testBegin("walSegmentNext()")) + { + TEST_RESULT_STR( + strPtr(walSegmentNext(strNew("000000010000000100000001"), 16 * 1024 * 1024, PG_VERSION_10)), + "000000010000000100000002", "get next"); + TEST_RESULT_STR( + strPtr(walSegmentNext(strNew("0000000100000001000000FE"), 16 * 1024 * 1024, PG_VERSION_93)), + "0000000100000001000000FF", "get next"); + TEST_RESULT_STR( + strPtr(walSegmentNext(strNew("0000009900000001000000FF"), 16 * 1024 * 1024, PG_VERSION_93)), + "000000990000000200000000", "get next overflow >= 9.3"); + TEST_RESULT_STR( + strPtr(walSegmentNext(strNew("0000000100000001000000FE"), 16 * 1024 * 1024, PG_VERSION_92)), + "000000010000000200000000", "get next overflow < 9.3"); + TEST_RESULT_STR( + strPtr(walSegmentNext(strNew("000000010000000100000003"), 1024 * 1024 * 1024, PG_VERSION_11)), + "000000010000000200000000", "get next overflow >= 11/1GB"); + TEST_RESULT_STR( + strPtr(walSegmentNext(strNew("000000010000006700000FFF"), 1024 * 1024, PG_VERSION_11)), + "000000010000006800000000", "get next overflow >= 11/1MB"); + } + + // ***************************************************************************************************************************** + if (testBegin("walSegmentRange()")) + { + TEST_RESULT_STR( + strPtr(strLstJoin(walSegmentRange(strNew("000000010000000100000000"), 16 * 1024 * 1024, PG_VERSION_92, 1), "|")), + "000000010000000100000000", "get single"); + TEST_RESULT_STR( + strPtr(strLstJoin(walSegmentRange(strNew("0000000100000001000000FD"), 16 * 1024 * 1024, PG_VERSION_92, 4), "|")), + "0000000100000001000000FD|0000000100000001000000FE|000000010000000200000000|000000010000000200000001", + "get range < 9.3"); + TEST_RESULT_STR( + strPtr(strLstJoin(walSegmentRange(strNew("0000000100000001000000FD"), 16 * 1024 * 1024, PG_VERSION_93, 4), "|")), + "0000000100000001000000FD|0000000100000001000000FE|0000000100000001000000FF|000000010000000200000000", + "get range >= 9.3"); + TEST_RESULT_STR( + strPtr(strLstJoin(walSegmentRange(strNew("000000080000000A00000000"), 1024 * 1024 * 1024, PG_VERSION_11, 8), "|")), + "000000080000000A00000000|000000080000000A00000001|000000080000000A00000002|000000080000000A00000003|" + "000000080000000B00000000|000000080000000B00000001|000000080000000B00000002|000000080000000B00000003", + "get range >= 11/1GB"); + TEST_RESULT_STR( + strPtr(strLstJoin(walSegmentRange(strNew("000000070000000700000FFE"), 1024 * 1024, PG_VERSION_11, 4), "|")), + "000000070000000700000FFE|000000070000000700000FFF|000000070000000800000000|000000070000000800000001", + "get range >= 11/1MB"); + } }