diff --git a/doc/xml/release.xml b/doc/xml/release.xml index 8d6df37b5..0f24d479f 100644 --- a/doc/xml/release.xml +++ b/doc/xml/release.xml @@ -64,6 +64,14 @@

WAL prior to the first full backup was previously expired after the first full backup. Now it is preserved according to retention settings.

+ + + + + +

Allow pg-path1 to be optional for synchronous archive-push.

+
+ diff --git a/src/command/archive/push/push.c b/src/command/archive/push/push.c index 60cd4c731..8aa10cdf4 100644 --- a/src/command/archive/push/push.c +++ b/src/command/archive/push/push.c @@ -200,9 +200,10 @@ typedef struct ArchivePushCheckResult } ArchivePushCheckResult; static ArchivePushCheckResult -archivePushCheck(CipherType cipherType, const String *cipherPass) +archivePushCheck(bool pgPathSet, CipherType cipherType, const String *cipherPass) { FUNCTION_LOG_BEGIN(logLevelDebug); + FUNCTION_LOG_PARAM(BOOL, pgPathSet); FUNCTION_LOG_PARAM(ENUM, cipherType); FUNCTION_TEST_PARAM(STRING, cipherPass); FUNCTION_LOG_END(); @@ -211,9 +212,6 @@ archivePushCheck(CipherType cipherType, const String *cipherPass) MEM_CONTEXT_TEMP_BEGIN() { - // Get info from pg_control - PgControl controlInfo = pgControlFromFile(storagePg()); - // Attempt to load the archive info file InfoArchive *info = infoArchiveLoadFile(storageRepo(), INFO_ARCHIVE_PATH_FILE_STR, cipherType, cipherPass); @@ -221,21 +219,27 @@ archivePushCheck(CipherType cipherType, const String *cipherPass) String *archiveId = infoPgArchiveId(infoArchivePg(info), infoPgDataCurrentId(infoArchivePg(info))); InfoPgData archiveInfo = infoPgData(infoArchivePg(info), infoPgDataCurrentId(infoArchivePg(info))); - // Ensure that the version and system identifier match - if (controlInfo.version != archiveInfo.version || controlInfo.systemId != archiveInfo.systemId) + // Ensure that stanza version and system identifier match pg_control when available + if (pgPathSet) { - THROW_FMT( - ArchiveMismatchError, - "PostgreSQL version %s, system-id %" PRIu64 " do not match stanza version %s, system-id %" PRIu64 - "\nHINT: are you archiving to the correct stanza?", - strPtr(pgVersionToStr(controlInfo.version)), controlInfo.systemId, strPtr(pgVersionToStr(archiveInfo.version)), - archiveInfo.systemId); + // Get info from pg_control + PgControl controlInfo = pgControlFromFile(storagePg()); + + if (controlInfo.version != archiveInfo.version || controlInfo.systemId != archiveInfo.systemId) + { + THROW_FMT( + ArchiveMismatchError, + "PostgreSQL version %s, system-id %" PRIu64 " do not match stanza version %s, system-id %" PRIu64 + "\nHINT: are you archiving to the correct stanza?", + strPtr(pgVersionToStr(controlInfo.version)), controlInfo.systemId, strPtr(pgVersionToStr(archiveInfo.version)), + archiveInfo.systemId); + } } MEM_CONTEXT_PRIOR_BEGIN() { - result.pgVersion = controlInfo.version; - result.pgSystemId = controlInfo.systemId; + result.pgVersion = archiveInfo.version; + result.pgSystemId = archiveInfo.systemId; result.archiveId = strDup(archiveId); result.archiveCipherPass = strDup(infoArchiveCipherPass(info)); } @@ -278,6 +282,10 @@ cmdArchivePush(void) bool forked = false; // Has the async process been forked yet? bool throwOnError = false; // Should we throw errors? + // pg1-path is not optional for async mode + if (!cfgOptionTest(cfgOptPgPath)) + THROW(OptionRequiredError, "'" CFGCMD_ARCHIVE_PUSH "' command in async mode requires option '" CFGOPT_PG1_PATH "'"); + // Loop and wait for the WAL segment to be pushed Wait *wait = waitNew((TimeMSec)(cfgOptionDbl(cfgOptArchiveTimeout) * MSEC_PER_SEC)); @@ -341,7 +349,8 @@ cmdArchivePush(void) // Get archive info ArchivePushCheckResult archiveInfo = archivePushCheck( - cipherType(cfgOptionStr(cfgOptRepoCipherType)), cfgOptionStrNull(cfgOptRepoCipherPass)); + cfgOptionTest(cfgOptPgPath), cipherType(cfgOptionStr(cfgOptRepoCipherType)), + cfgOptionStrNull(cfgOptRepoCipherPass)); // Check if the push queue has been exceeded if (cfgOptionTest(cfgOptArchivePushQueueMax) && @@ -484,7 +493,7 @@ cmdArchivePushAsync(void) // Get archive info jobData.archiveInfo = archivePushCheck( - cipherType(cfgOptionStr(cfgOptRepoCipherType)), cfgOptionStrNull(cfgOptRepoCipherPass)); + true, cipherType(cfgOptionStr(cfgOptRepoCipherType)), cfgOptionStrNull(cfgOptRepoCipherPass)); // Create the parallel executor ProtocolParallel *parallelExec = protocolParallelNew( diff --git a/test/src/module/command/archivePushTest.c b/test/src/module/command/archivePushTest.c index 68177abfd..7e391b887 100644 --- a/test/src/module/command/archivePushTest.c +++ b/test/src/module/command/archivePushTest.c @@ -133,7 +133,7 @@ testRun(void) "1={\"db-id\":5555555555555555555,\"db-version\":\"9.4\"}\n")); TEST_ERROR( - archivePushCheck(cipherTypeNone, NULL), ArchiveMismatchError, + archivePushCheck(true, cipherTypeNone, NULL), ArchiveMismatchError, "PostgreSQL version 9.6, system-id 18072658121562454734 do not match stanza version 9.4, system-id 5555555555555555555" "\nHINT: are you archiving to the correct stanza?"); @@ -148,7 +148,7 @@ testRun(void) "1={\"db-id\":5555555555555555555,\"db-version\":\"9.6\"}\n")); TEST_ERROR( - archivePushCheck(cipherTypeNone, NULL), ArchiveMismatchError, + archivePushCheck(true, cipherTypeNone, NULL), ArchiveMismatchError, "PostgreSQL version 9.6, system-id 18072658121562454734 do not match stanza version 9.6, system-id 5555555555555555555" "\nHINT: are you archiving to the correct stanza?"); @@ -163,7 +163,7 @@ testRun(void) "1={\"db-id\":18072658121562454734,\"db-version\":\"9.6\"}\n")); ArchivePushCheckResult result = {0}; - TEST_ASSIGN(result, archivePushCheck(cipherTypeNone, NULL), "get archive check result"); + TEST_ASSIGN(result, archivePushCheck(true, cipherTypeNone, NULL), "get archive check result"); TEST_RESULT_UINT(result.pgVersion, PG_VERSION_96, "check pg version"); TEST_RESULT_UINT(result.pgSystemId, 0xFACEFACEFACEFACE, "check pg system id"); @@ -290,12 +290,16 @@ testRun(void) TEST_ERROR(cmdArchivePush(), ArchiveDuplicateError, "WAL file '000000010000000100000001' already exists in the archive"); - // Save it to a new file instead - argListTemp = strLstDup(argList); - strLstAddZ(argListTemp, "pg_wal/000000010000000100000002"); + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("WAL with absolute path and no pg1-path"); + + argListTemp = strLstNew(); + strLstAddZ(argListTemp, "--" CFGOPT_STANZA "=test"); + strLstAdd(argListTemp, strNewFmt("--" CFGOPT_REPO1_PATH "=%s/repo", testPath())); + strLstAdd(argListTemp, strNewFmt("%s/pg/pg_wal/000000010000000100000002", testPath())); harnessCfgLoad(cfgCmdArchivePush, argListTemp); - storagePutP(storageNewWriteP(storagePgWrite(), strNew("pg_wal/000000010000000100000002")), walBuffer2); + TEST_RESULT_VOID(storagePutP(storageNewWriteP(storageTest, strNew("pg/pg_wal/000000010000000100000002")), walBuffer2), "write WAL"); TEST_RESULT_VOID(cmdArchivePush(), "push the WAL segment"); harnessLogResult("P00 INFO: pushed WAL file '000000010000000100000002' to the archive"); @@ -433,6 +437,18 @@ testRun(void) TEST_ERROR(cmdArchivePush(), HostInvalidError, "archive-push command must be run on the PostgreSQL host"); + // ------------------------------------------------------------------------------------------------------------------------- + TEST_TITLE("pg1-path must be set when async"); + + argList = strLstNew(); + strLstAddZ(argList, "--" CFGOPT_SPOOL_PATH "=/spool"); + strLstAddZ(argList, "--" CFGOPT_STANZA "=test2"); + strLstAddZ(argList, "--" CFGOPT_ARCHIVE_ASYNC); + strLstAddZ(argList, "/000000010000000100000001"); + harnessCfgLoadRole(cfgCmdArchivePush, cfgCmdRoleAsync, argList); + + TEST_ERROR(cmdArchivePush(), OptionRequiredError, "'archive-push' command in async mode requires option 'pg1-path'"); + // Call with a bogus exe name so the async process will error out and we can make sure timeouts work // ------------------------------------------------------------------------------------------------------------------------- argList = strLstNew();