You've already forked pgbackrest
							
							
				mirror of
				https://github.com/pgbackrest/pgbackrest.git
				synced 2025-10-30 23:37:45 +02:00 
			
		
		
		
	Improve archive-push command fault tolerance.
3b8f0ef missed some cases that could cause archive-push to fail:
* Checking archive info.
* Checking to see if a WAL segment already exists.
These cases are now handled so archive-push can succeed on any valid repos.This commit is contained in:
		| @@ -71,6 +71,7 @@ | ||||
|                         <commit subject="Make --repo optional for remaining commands except stanza-delete."/> | ||||
|                         <commit subject="Allow stanza-* commands to be run remotely."/> | ||||
|                         <commit subject="Improve info command fault tolerance."/> | ||||
|                         <commit subject="Improve archive-push command fault tolerance."/> | ||||
|  | ||||
|                         <release-item-contributor-list> | ||||
|                             <release-item-contributor id="cynthia.shang"/> | ||||
|   | ||||
| @@ -29,6 +29,23 @@ typedef enum | ||||
|     archivePushFileIoTypeClose, | ||||
| } ArchivePushFileIoType; | ||||
|  | ||||
| // Helper to add errors to the list | ||||
| static void | ||||
| archivePushErrorAdd(StringList *errorList, unsigned int repoIdx) | ||||
| { | ||||
|     FUNCTION_TEST_BEGIN(); | ||||
|         FUNCTION_TEST_PARAM(STRING_LIST, errorList); | ||||
|         FUNCTION_TEST_PARAM(UINT, repoIdx); | ||||
|     FUNCTION_TEST_END(); | ||||
|  | ||||
|     strLstAdd( | ||||
|         errorList, | ||||
|         strNewFmt( | ||||
|             "repo%u: [%s] %s", cfgOptionGroupIdxToKey(cfgOptGrpRepo, repoIdx), errorTypeName(errorType()), errorMessage())); | ||||
|  | ||||
|     FUNCTION_TEST_RETURN_VOID(); | ||||
| } | ||||
|  | ||||
| static bool | ||||
| archivePushFileIo(ArchivePushFileIoType type, IoWrite *write, const Buffer *buffer, unsigned int repoIdx, StringList *errorList) | ||||
| { | ||||
| @@ -67,10 +84,7 @@ archivePushFileIo(ArchivePushFileIoType type, IoWrite *write, const Buffer *buff | ||||
|     // Handle errors | ||||
|     CATCH_ANY() | ||||
|     { | ||||
|         strLstAdd( | ||||
|             errorList, | ||||
|             strNewFmt( | ||||
|                 "repo%u: [%s] %s", cfgOptionGroupIdxToKey(cfgOptGrpRepo, repoIdx), errorTypeName(errorType()), errorMessage())); | ||||
|         archivePushErrorAdd(errorList, repoIdx); | ||||
|         result = false; | ||||
|     } | ||||
|     TRY_END(); | ||||
| @@ -82,7 +96,7 @@ archivePushFileIo(ArchivePushFileIoType type, IoWrite *write, const Buffer *buff | ||||
| ArchivePushFileResult | ||||
| archivePushFile( | ||||
|     const String *walSource, unsigned int pgVersion, uint64_t pgSystemId, const String *archiveFile, CompressType compressType, | ||||
|     int compressLevel, const ArchivePushFileRepoData *repoData) | ||||
|     int compressLevel, const List *const repoList, const StringList *const priorErrorList) | ||||
| { | ||||
|     FUNCTION_LOG_BEGIN(logLevelDebug); | ||||
|         FUNCTION_LOG_PARAM(STRING, walSource); | ||||
| @@ -91,21 +105,21 @@ archivePushFile( | ||||
|         FUNCTION_LOG_PARAM(STRING, archiveFile); | ||||
|         FUNCTION_LOG_PARAM(ENUM, compressType); | ||||
|         FUNCTION_LOG_PARAM(INT, compressLevel); | ||||
|         FUNCTION_LOG_PARAM_P(VOID, repoData); | ||||
|         FUNCTION_LOG_PARAM_P(VOID, repoList); | ||||
|         FUNCTION_LOG_PARAM(STRING_LIST, priorErrorList); | ||||
|     FUNCTION_LOG_END(); | ||||
|  | ||||
|     ASSERT(walSource != NULL); | ||||
|     ASSERT(archiveFile != NULL); | ||||
|     ASSERT(repoData != NULL); | ||||
|     ASSERT(repoList != NULL); | ||||
|     ASSERT(priorErrorList != NULL); | ||||
|     ASSERT(lstSize(repoList) > 0); | ||||
|  | ||||
|     ArchivePushFileResult result = {.warnList = strLstNew()}; | ||||
|     StringList *errorList = strLstNew(); | ||||
|     StringList *errorList = strLstDup(priorErrorList); | ||||
|  | ||||
|     MEM_CONTEXT_TEMP_BEGIN() | ||||
|     { | ||||
|         // Total repos to push files to | ||||
|         unsigned int repoTotal = cfgOptionGroupIdxTotal(cfgOptGrpRepo); | ||||
|  | ||||
|         // Is this a WAL segment? | ||||
|         bool isSegment = walIsSegment(archiveFile); | ||||
|  | ||||
| @@ -129,10 +143,10 @@ archivePushFile( | ||||
|  | ||||
|         // Assume that all repos need a copy of the archive file | ||||
|         bool destinationCopyAny = true; | ||||
|         bool *destinationCopy = memNew(sizeof(bool) * repoTotal); | ||||
|         bool *destinationCopy = memNew(sizeof(bool) * lstSize(repoList)); | ||||
|  | ||||
|         for (unsigned int repoIdx = 0; repoIdx < repoTotal; repoIdx++) | ||||
|             destinationCopy[repoIdx] = true; | ||||
|         for (unsigned int repoListIdx = 0; repoListIdx < lstSize(repoList); repoListIdx++) | ||||
|             destinationCopy[repoListIdx] = true; | ||||
|  | ||||
|         // Get wal segment checksum and compare it to what exists in the repo, if any | ||||
|         if (isSegment) | ||||
| @@ -148,11 +162,29 @@ archivePushFile( | ||||
|             const String *walSegmentChecksum = varStr(ioFilterGroupResult(ioReadFilterGroup(read), CRYPTO_HASH_FILTER_TYPE_STR)); | ||||
|  | ||||
|             // Check each repo for the WAL segment | ||||
|             for (unsigned int repoIdx = 0; repoIdx < repoTotal; repoIdx++) | ||||
|             for (unsigned int repoListIdx = 0; repoListIdx < lstSize(repoList); repoListIdx++) | ||||
|             { | ||||
|                 // If the wal segment already exists in the repo then compare checksums | ||||
|                 const String *walSegmentFile = walSegmentFind(storageRepoIdx(repoIdx), repoData[repoIdx].archiveId, archiveFile, 0); | ||||
|                 const ArchivePushFileRepoData *const repoData = lstGet(repoList, repoListIdx); | ||||
|  | ||||
|                 // Check if the WAL segement already exists in the repo | ||||
|                 const String *walSegmentFile = NULL; | ||||
|  | ||||
|                 TRY_BEGIN() | ||||
|                 { | ||||
|                     walSegmentFile = walSegmentFind(storageRepoIdx(repoData->repoIdx), repoData->archiveId, archiveFile, 0); | ||||
|                 } | ||||
|                 CATCH_ANY() | ||||
|                 { | ||||
|                     archivePushErrorAdd(errorList, repoData->repoIdx); | ||||
|                     destinationCopy[repoListIdx] = false; | ||||
|                 } | ||||
|                 TRY_END(); | ||||
|  | ||||
|                 // If there was an error try the next repo | ||||
|                 if (!destinationCopy[repoListIdx]) | ||||
|                     continue; | ||||
|  | ||||
|                 // If the WAL segment was found validate the checksum | ||||
|                 if (walSegmentFile != NULL) | ||||
|                 { | ||||
|                     String *walSegmentRepoChecksum = strSubN(walSegmentFile, strSize(archiveFile) + 1, HASH_TYPE_SHA1_SIZE_HEX); | ||||
| @@ -168,19 +200,20 @@ archivePushFile( | ||||
|                                 strNewFmt( | ||||
|                                     "WAL file '%s' already exists in the repo%u archive with the same checksum" | ||||
|                                     "\nHINT: this is valid in some recovery scenarios but may also indicate a problem.", | ||||
|                                     strZ(archiveFile), cfgOptionGroupIdxToKey(cfgOptGrpRepo, repoIdx))); | ||||
|                                     strZ(archiveFile), cfgOptionGroupIdxToKey(cfgOptGrpRepo, repoData->repoIdx))); | ||||
|                         } | ||||
|                         MEM_CONTEXT_PRIOR_END(); | ||||
|  | ||||
|                         // No need to copy to this repo | ||||
|                         destinationCopy[repoIdx] = false; | ||||
|                         destinationCopy[repoListIdx] = false; | ||||
|                     } | ||||
|                     // Else error so we don't overwrite the existing segment | ||||
|                     // Else error so we don't overwrite the existing segment. Do not continue processing after this error since it | ||||
|                     // indicates corruption, split brain, or some other unrecoverable error. | ||||
|                     else | ||||
|                     { | ||||
|                         THROW_FMT( | ||||
|                             ArchiveDuplicateError, "WAL file '%s' already exists in the repo%u archive with a different checksum", | ||||
|                             strZ(archiveFile), cfgOptionGroupIdxToKey(cfgOptGrpRepo, repoIdx)); | ||||
|                             strZ(archiveFile), cfgOptionGroupIdxToKey(cfgOptGrpRepo, repoData->repoIdx)); | ||||
|                     } | ||||
|                 } | ||||
|                 // Else the repo needs a copy | ||||
| @@ -210,26 +243,27 @@ archivePushFile( | ||||
|             } | ||||
|  | ||||
|             // Initialize per-repo destination files | ||||
|             StorageWrite **destination = memNew(sizeof(StorageWrite *) * repoTotal); | ||||
|             StorageWrite **destination = memNew(sizeof(StorageWrite *) * lstSize(repoList)); | ||||
|  | ||||
|             for (unsigned int repoIdx = 0; repoIdx < repoTotal; repoIdx++) | ||||
|             for (unsigned int repoListIdx = 0; repoListIdx < lstSize(repoList); repoListIdx++) | ||||
|             { | ||||
|                 const ArchivePushFileRepoData *const repoData = lstGet(repoList, repoListIdx); | ||||
|  | ||||
|                 // Does this repo need a copy? | ||||
|                 if (destinationCopy[repoIdx]) | ||||
|                 if (destinationCopy[repoListIdx]) | ||||
|                 { | ||||
|                     // Create destination file | ||||
|                     destination[repoIdx] = storageNewWriteP( | ||||
|                         storageRepoIdxWrite(repoIdx), | ||||
|                         strNewFmt(STORAGE_REPO_ARCHIVE "/%s/%s", strZ(repoData[repoIdx].archiveId), strZ(archiveDestination)), | ||||
|                     destination[repoListIdx] = storageNewWriteP( | ||||
|                         storageRepoIdxWrite(repoData->repoIdx), | ||||
|                         strNewFmt(STORAGE_REPO_ARCHIVE "/%s/%s", strZ(repoData->archiveId), strZ(archiveDestination)), | ||||
|                         .compressible = compressible); | ||||
|  | ||||
|                     // If there is a cipher then add the encrypt filter | ||||
|                     if (repoData[repoIdx].cipherType != cipherTypeNone) | ||||
|                     if (repoData->cipherType != cipherTypeNone) | ||||
|                     { | ||||
|                         ioFilterGroupAdd( | ||||
|                             ioWriteFilterGroup(storageWriteIo(destination[repoIdx])), | ||||
|                             cipherBlockNew( | ||||
|                                 cipherModeEncrypt, repoData[repoIdx].cipherType, BUFSTR(repoData[repoIdx].cipherPass), NULL)); | ||||
|                             ioWriteFilterGroup(storageWriteIo(destination[repoListIdx])), | ||||
|                             cipherBlockNew(cipherModeEncrypt, repoData->cipherType, BUFSTR(repoData->cipherPass), NULL)); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| @@ -238,12 +272,14 @@ archivePushFile( | ||||
|             ioReadOpen(storageReadIo(source)); | ||||
|  | ||||
|             // Open the destination files now that we know the source file exists and is readable | ||||
|             for (unsigned int repoIdx = 0; repoIdx < repoTotal; repoIdx++) | ||||
|             for (unsigned int repoListIdx = 0; repoListIdx < lstSize(repoList); repoListIdx++) | ||||
|             { | ||||
|                 if (destinationCopy[repoIdx]) | ||||
|                 const unsigned int repoIdx = ((ArchivePushFileRepoData *)lstGet(repoList, repoListIdx))->repoIdx; | ||||
|  | ||||
|                 if (destinationCopy[repoListIdx]) | ||||
|                 { | ||||
|                     destinationCopy[repoIdx] = archivePushFileIo( | ||||
|                         archivePushFileIoTypeOpen, storageWriteIo(destination[repoIdx]), NULL, repoIdx, errorList); | ||||
|                     destinationCopy[repoListIdx] = archivePushFileIo( | ||||
|                         archivePushFileIoTypeOpen, storageWriteIo(destination[repoListIdx]), NULL, repoIdx, errorList); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
| @@ -256,12 +292,14 @@ archivePushFile( | ||||
|                 ioRead(storageReadIo(source), read); | ||||
|  | ||||
|                 // Write to each destination | ||||
|                 for (unsigned int repoIdx = 0; repoIdx < repoTotal; repoIdx++) | ||||
|                 for (unsigned int repoListIdx = 0; repoListIdx < lstSize(repoList); repoListIdx++) | ||||
|                 { | ||||
|                     if (destinationCopy[repoIdx]) | ||||
|                     const unsigned int repoIdx = ((ArchivePushFileRepoData *)lstGet(repoList, repoListIdx))->repoIdx; | ||||
|  | ||||
|                     if (destinationCopy[repoListIdx]) | ||||
|                     { | ||||
|                         destinationCopy[repoIdx] = archivePushFileIo( | ||||
|                             archivePushFileIoTypeWrite, storageWriteIo(destination[repoIdx]), read, repoIdx, errorList); | ||||
|                         destinationCopy[repoListIdx] = archivePushFileIo( | ||||
|                             archivePushFileIoTypeWrite, storageWriteIo(destination[repoListIdx]), read, repoIdx, errorList); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
| @@ -273,12 +311,14 @@ archivePushFile( | ||||
|             // Close the source and destination files | ||||
|             ioReadClose(storageReadIo(source)); | ||||
|  | ||||
|             for (unsigned int repoIdx = 0; repoIdx < repoTotal; repoIdx++) | ||||
|             for (unsigned int repoListIdx = 0; repoListIdx < lstSize(repoList); repoListIdx++) | ||||
|             { | ||||
|                 if (destinationCopy[repoIdx]) | ||||
|                 const unsigned int repoIdx = ((ArchivePushFileRepoData *)lstGet(repoList, repoListIdx))->repoIdx; | ||||
|  | ||||
|                 if (destinationCopy[repoListIdx]) | ||||
|                 { | ||||
|                     destinationCopy[repoIdx] = archivePushFileIo( | ||||
|                         archivePushFileIoTypeClose, storageWriteIo(destination[repoIdx]), NULL, repoIdx, errorList); | ||||
|                     destinationCopy[repoListIdx] = archivePushFileIo( | ||||
|                         archivePushFileIoTypeClose, storageWriteIo(destination[repoListIdx]), NULL, repoIdx, errorList); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -15,6 +15,7 @@ archivePushFile() with size equal to cfgOptionGroupIdxTotal(cfgOptGrpRepo). | ||||
| ***********************************************************************************************************************************/ | ||||
| typedef struct ArchivePushFileRepoData | ||||
| { | ||||
|     unsigned int repoIdx; | ||||
|     const String *archiveId; | ||||
|     CipherType cipherType; | ||||
|     const String *cipherPass; | ||||
| @@ -31,6 +32,6 @@ typedef struct ArchivePushFileResult | ||||
| // Copy a file from the source to the archive | ||||
| ArchivePushFileResult archivePushFile( | ||||
|     const String *walSource, unsigned int pgVersion, uint64_t pgSystemId, const String *archiveFile, CompressType compressType, | ||||
|     int compressLevel, const ArchivePushFileRepoData *repoData); | ||||
|     int compressLevel, const List *const repoList, const StringList *const priorErrorList); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -31,28 +31,31 @@ archivePushFileProtocol(const VariantList *paramList, ProtocolServer *server) | ||||
|  | ||||
|     MEM_CONTEXT_TEMP_BEGIN() | ||||
|     { | ||||
|         const unsigned int paramFixed = 6;                          // Fixed params before the repo param array | ||||
|         const unsigned int paramRepo = 3;                           // Parameters in each index of the repo array | ||||
|         // Build the repo data list | ||||
|         List *repoList = lstNewP(sizeof(ArchivePushFileRepoData)); | ||||
|         unsigned int repoListSize = varUIntForce(varLstGet(paramList, 7)); | ||||
|         unsigned int paramIdx = 8; | ||||
|  | ||||
|         // Check that the correct number of repo parameters were passed | ||||
|         CHECK(varLstSize(paramList) - paramFixed == cfgOptionGroupIdxTotal(cfgOptGrpRepo) * paramRepo); | ||||
|  | ||||
|         // Build the repo data array | ||||
|         ArchivePushFileRepoData *repoData = memNew(cfgOptionGroupIdxTotal(cfgOptGrpRepo) * sizeof(ArchivePushFileRepoData)); | ||||
|  | ||||
|         for (unsigned int repoIdx = 0; repoIdx < cfgOptionGroupIdxTotal(cfgOptGrpRepo); repoIdx++) | ||||
|         for (unsigned int repoListIdx = 0; repoListIdx < repoListSize; repoListIdx++) | ||||
|         { | ||||
|             repoData[repoIdx].archiveId = varStr(varLstGet(paramList, paramFixed + (repoIdx * paramRepo))); | ||||
|             repoData[repoIdx].cipherType = (CipherType)varUIntForce( | ||||
|                 varLstGet(paramList, paramFixed + (repoIdx * paramRepo) + 1)); | ||||
|             repoData[repoIdx].cipherPass = varStr(varLstGet(paramList, paramFixed + (repoIdx * paramRepo) + 2)); | ||||
|             lstAdd( | ||||
|                 repoList, | ||||
|                 &(ArchivePushFileRepoData) | ||||
|                 { | ||||
|                     .repoIdx = varUIntForce(varLstGet(paramList, paramIdx)), | ||||
|                     .archiveId = varStr(varLstGet(paramList, paramIdx + 1)), | ||||
|                     .cipherType = (CipherType)varUIntForce(varLstGet(paramList, paramIdx + 2)), | ||||
|                     .cipherPass = varStr(varLstGet(paramList, paramIdx + 3)), | ||||
|                 }); | ||||
|  | ||||
|             paramIdx += 4; | ||||
|         } | ||||
|  | ||||
|         // Push the file | ||||
|         ArchivePushFileResult fileResult = archivePushFile( | ||||
|             varStr(varLstGet(paramList, 0)), varUIntForce(varLstGet(paramList, 1)), varUInt64(varLstGet(paramList, 2)), | ||||
|             varStr(varLstGet(paramList, 3)), (CompressType)varUIntForce(varLstGet(paramList, 4)), | ||||
|             varIntForce(varLstGet(paramList, 5)), repoData); | ||||
|             varIntForce(varLstGet(paramList, 5)), repoList, strLstNewVarLst(varVarLst(varLstGet(paramList, 6)))); | ||||
|  | ||||
|         // Return result | ||||
|         VariantList *result = varLstNew(); | ||||
|   | ||||
| @@ -25,6 +25,11 @@ Archive Push Command | ||||
| #include "protocol/parallel.h" | ||||
| #include "storage/helper.h" | ||||
|  | ||||
| /*********************************************************************************************************************************** | ||||
| Constants for log messages that are used multiple times to keep them consistent | ||||
| ***********************************************************************************************************************************/ | ||||
| #define UNABLE_TO_FIND_VALID_REPO_MSG                               "unable to find a valid repository" | ||||
|  | ||||
| /*********************************************************************************************************************************** | ||||
| Ready file extension constants | ||||
| ***********************************************************************************************************************************/ | ||||
| @@ -191,7 +196,8 @@ typedef struct ArchivePushCheckResult | ||||
| { | ||||
|     unsigned int pgVersion;                                         // PostgreSQL version | ||||
|     uint64_t pgSystemId;                                            // PostgreSQL system id | ||||
|     ArchivePushFileRepoData *repoData;                              // Data for each repo | ||||
|     List *repoList;                                                 // Data for each repo | ||||
|     StringList *errorList;                                          // Errors while checking repos | ||||
| } ArchivePushCheckResult; | ||||
|  | ||||
| static ArchivePushCheckResult | ||||
| @@ -201,7 +207,7 @@ archivePushCheck(bool pgPathSet) | ||||
|         FUNCTION_LOG_PARAM(BOOL, pgPathSet); | ||||
|     FUNCTION_LOG_END(); | ||||
|  | ||||
|     ArchivePushCheckResult result = {.repoData = memNew(cfgOptionGroupIdxTotal(cfgOptGrpRepo) * sizeof(ArchivePushFileRepoData))}; | ||||
|     ArchivePushCheckResult result = {.repoList = lstNewP(sizeof(ArchivePushFileRepoData)), .errorList = strLstNew()}; | ||||
|  | ||||
|     MEM_CONTEXT_TEMP_BEGIN() | ||||
|     { | ||||
| @@ -217,50 +223,78 @@ archivePushCheck(bool pgPathSet) | ||||
|  | ||||
|         for (unsigned int repoIdx = 0; repoIdx < cfgOptionGroupIdxTotal(cfgOptGrpRepo); repoIdx++) | ||||
|         { | ||||
|             // Get the repo storage in case it is remote and encryption settings need to be pulled down | ||||
|             storageRepoIdx(repoIdx); | ||||
|  | ||||
|             // Set cipher type in repo data | ||||
|             result.repoData[repoIdx].cipherType = cipherType(cfgOptionIdxStr(cfgOptRepoCipherType, repoIdx)); | ||||
|  | ||||
|             // Attempt to load the archive info file | ||||
|             InfoArchive *info = infoArchiveLoadFile( | ||||
|                 storageRepoIdx(repoIdx), INFO_ARCHIVE_PATH_FILE_STR, result.repoData[repoIdx].cipherType, | ||||
|                 cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx)); | ||||
|  | ||||
|             // Get archive id for the most recent version -- archive-push will only operate against the most recent version | ||||
|             String *archiveId = infoPgArchiveId(infoArchivePg(info), infoPgDataCurrentId(infoArchivePg(info))); | ||||
|             InfoPgData archiveInfo = infoPgData(infoArchivePg(info), infoPgDataCurrentId(infoArchivePg(info))); | ||||
|  | ||||
|             // Ensure that stanza version and system identifier match pg_control when available or the other repos when pg_control | ||||
|             // is not available | ||||
|             if (pgPathSet || repoIdx > 0) | ||||
|             TRY_BEGIN() | ||||
|             { | ||||
|                 if (result.pgVersion != archiveInfo.version || result.pgSystemId != archiveInfo.systemId) | ||||
|                 // Get the repo storage in case it is remote and encryption settings need to be pulled down | ||||
|                 storageRepoIdx(repoIdx); | ||||
|  | ||||
|                 // Get cipher type | ||||
|                 CipherType repoCipherType = cipherType(cfgOptionIdxStr(cfgOptRepoCipherType, repoIdx)); | ||||
|  | ||||
|                 // Attempt to load the archive info file | ||||
|                 InfoArchive *info = infoArchiveLoadFile( | ||||
|                     storageRepoIdx(repoIdx), INFO_ARCHIVE_PATH_FILE_STR, repoCipherType, | ||||
|                     cfgOptionIdxStrNull(cfgOptRepoCipherPass, repoIdx)); | ||||
|  | ||||
|                 // Get archive id for the most recent version -- archive-push will only operate against the most recent version | ||||
|                 String *archiveId = infoPgArchiveId(infoArchivePg(info), infoPgDataCurrentId(infoArchivePg(info))); | ||||
|                 InfoPgData archiveInfo = infoPgData(infoArchivePg(info), infoPgDataCurrentId(infoArchivePg(info))); | ||||
|  | ||||
|                 // Ensure that stanza version and system identifier match pg_control when available or the other repos when | ||||
|                 // pg_control is not available | ||||
|                 if (pgPathSet || repoIdx > 0) | ||||
|                 { | ||||
|                     THROW_FMT( | ||||
|                         ArchiveMismatchError, | ||||
|                         "%s version %s, system-id %" PRIu64 " do not match %s stanza version %s, system-id %" PRIu64 | ||||
|                         "\nHINT: are you archiving to the correct stanza?", | ||||
|                         pgPathSet ? PG_NAME : strZ(strNewFmt("repo%u stanza", cfgOptionGroupIdxToKey(cfgOptGrpRepo, 0))), | ||||
|                         strZ(pgVersionToStr(result.pgVersion)), result.pgSystemId, | ||||
|                         strZ(strNewFmt("repo%u", cfgOptionGroupIdxToKey(cfgOptGrpRepo, repoIdx))), | ||||
|                         strZ(pgVersionToStr(archiveInfo.version)), archiveInfo.systemId); | ||||
|                     if (result.pgVersion != archiveInfo.version || result.pgSystemId != archiveInfo.systemId) | ||||
|                     { | ||||
|                         THROW_FMT( | ||||
|                             ArchiveMismatchError, | ||||
|                             "%s version %s, system-id %" PRIu64 " do not match %s stanza version %s, system-id %" PRIu64 | ||||
|                             "\nHINT: are you archiving to the correct stanza?", | ||||
|                             pgPathSet ? PG_NAME : strZ(strNewFmt("repo%u stanza", cfgOptionGroupIdxToKey(cfgOptGrpRepo, 0))), | ||||
|                             strZ(pgVersionToStr(result.pgVersion)), result.pgSystemId, | ||||
|                             strZ(strNewFmt("repo%u", cfgOptionGroupIdxToKey(cfgOptGrpRepo, repoIdx))), | ||||
|                             strZ(pgVersionToStr(archiveInfo.version)), archiveInfo.systemId); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             MEM_CONTEXT_PRIOR_BEGIN() | ||||
|             { | ||||
|                 result.pgVersion = archiveInfo.version; | ||||
|                 result.pgSystemId = archiveInfo.systemId; | ||||
|                 result.repoData[repoIdx].archiveId = strDup(archiveId); | ||||
|                 result.repoData[repoIdx].cipherPass = strDup(infoArchiveCipherPass(info)); | ||||
|                 MEM_CONTEXT_PRIOR_BEGIN() | ||||
|                 { | ||||
|                     result.pgVersion = archiveInfo.version; | ||||
|                     result.pgSystemId = archiveInfo.systemId; | ||||
|  | ||||
|                     lstAdd( | ||||
|                         result.repoList, | ||||
|                         &(ArchivePushFileRepoData) | ||||
|                         { | ||||
|                             .repoIdx = repoIdx, | ||||
|                             .archiveId = strDup(archiveId), | ||||
|                             .cipherType = repoCipherType, | ||||
|                             .cipherPass = strDup(infoArchiveCipherPass(info)), | ||||
|                         }); | ||||
|                 } | ||||
|                 MEM_CONTEXT_PRIOR_END(); | ||||
|             } | ||||
|             MEM_CONTEXT_PRIOR_END(); | ||||
|             CATCH_ANY() | ||||
|             { | ||||
|                 strLstAdd( | ||||
|                     result.errorList, | ||||
|                     strNewFmt( | ||||
|                         "repo%u: [%s] %s", cfgOptionGroupIdxToKey(cfgOptGrpRepo, repoIdx), errorTypeName(errorType()), | ||||
|                         errorMessage())); | ||||
|             } | ||||
|             TRY_END(); | ||||
|         } | ||||
|     } | ||||
|     MEM_CONTEXT_TEMP_END(); | ||||
|  | ||||
|     // If no valid repos were found then error | ||||
|     if (lstEmpty(result.repoList)) | ||||
|     { | ||||
|         ASSERT(strLstSize(result.errorList) > 0); | ||||
|  | ||||
|         THROW_FMT(RepoInvalidError, UNABLE_TO_FIND_VALID_REPO_MSG ":\n%s", strZ(strLstJoin(result.errorList, "\n"))); | ||||
|     } | ||||
|  | ||||
|     FUNCTION_LOG_RETURN_STRUCT(result); | ||||
| } | ||||
|  | ||||
| @@ -379,7 +413,8 @@ cmdArchivePush(void) | ||||
|                 // Push the file to the archive | ||||
|                 ArchivePushFileResult fileResult = archivePushFile( | ||||
|                     walFile, archiveInfo.pgVersion, archiveInfo.pgSystemId, archiveFile, | ||||
|                     compressTypeEnum(cfgOptionStr(cfgOptCompressType)), cfgOptionInt(cfgOptCompressLevel), archiveInfo.repoData); | ||||
|                     compressTypeEnum(cfgOptionStr(cfgOptCompressType)), cfgOptionInt(cfgOptCompressLevel), archiveInfo.repoList, | ||||
|                     archiveInfo.errorList); | ||||
|  | ||||
|                 // If a warning was returned then log it | ||||
|                 for (unsigned int warnIdx = 0; warnIdx < strLstSize(fileResult.warnList); warnIdx++) | ||||
| @@ -432,13 +467,18 @@ archivePushAsyncCallback(void *data, unsigned int clientIdx) | ||||
|         protocolCommandParamAdd(command, VARSTR(walFile)); | ||||
|         protocolCommandParamAdd(command, VARUINT(jobData->compressType)); | ||||
|         protocolCommandParamAdd(command, VARINT(jobData->compressLevel)); | ||||
|         protocolCommandParamAdd(command, varNewVarLst(varLstNewStrLst(jobData->archiveInfo.errorList))); | ||||
|         protocolCommandParamAdd(command, VARUINT(lstSize(jobData->archiveInfo.repoList))); | ||||
|  | ||||
|         // Add data for each repo to push to | ||||
|         for (unsigned int repoIdx = 0; repoIdx < cfgOptionGroupIdxTotal(cfgOptGrpRepo); repoIdx++) | ||||
|         for (unsigned int repoListIdx = 0; repoListIdx < lstSize(jobData->archiveInfo.repoList); repoListIdx++) | ||||
|         { | ||||
|             protocolCommandParamAdd(command, VARSTR(jobData->archiveInfo.repoData[repoIdx].archiveId)); | ||||
|             protocolCommandParamAdd(command, VARUINT(jobData->archiveInfo.repoData[repoIdx].cipherType)); | ||||
|             protocolCommandParamAdd(command, VARSTR(jobData->archiveInfo.repoData[repoIdx].cipherPass)); | ||||
|             ArchivePushFileRepoData *data = lstGet(jobData->archiveInfo.repoList, repoListIdx); | ||||
|  | ||||
|             protocolCommandParamAdd(command, VARUINT(data->repoIdx)); | ||||
|             protocolCommandParamAdd(command, VARSTR(data->archiveId)); | ||||
|             protocolCommandParamAdd(command, VARUINT(data->cipherType)); | ||||
|             protocolCommandParamAdd(command, VARSTR(data->cipherPass)); | ||||
|         } | ||||
|  | ||||
|         FUNCTION_TEST_RETURN(protocolParallelJobNew(VARSTR(walFile), command)); | ||||
|   | ||||
| @@ -4,14 +4,15 @@ run 001 - rmt 0, storage posix, enc 1, cmp lz4 | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --stanza=db archive-push [TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000001 | ||||
| ------------------------------------------------------------------------------------------------------------------------------------ | ||||
| P00   INFO: archive-push command begin [BACKREST-VERSION]: [[TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000001] --buffer-size=[BUFFER-SIZE] --compress-level=3 --compress-type=none --config=[TEST_PATH]/db-primary/pgbackrest.conf --db-timeout=45 --exec-id=[EXEC-ID] --job-retry=0 --lock-path=[TEST_PATH]/db-primary/lock --log-level-console=detail --log-level-file=[LOG-LEVEL-FILE] --log-level-stderr=off --log-path=[TEST_PATH]/db-primary/log[] --no-log-timestamp --pg1-path=[TEST_PATH]/db-primary/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=[TEST_PATH]/db-primary/repo --stanza=db | ||||
| P00  ERROR: [055]: unable to load info file '[TEST_PATH]/db-primary/repo/archive/db/archive.info' or '[TEST_PATH]/db-primary/repo/archive/db/archive.info.copy': | ||||
| P00  ERROR: [103]: unable to find a valid repository: | ||||
|             repo1: [FileMissingError] unable to load info file '[TEST_PATH]/db-primary/repo/archive/db/archive.info' or '[TEST_PATH]/db-primary/repo/archive/db/archive.info.copy': | ||||
|             FileMissingError: unable to open missing file '[TEST_PATH]/db-primary/repo/archive/db/archive.info' for read | ||||
|             FileMissingError: unable to open missing file '[TEST_PATH]/db-primary/repo/archive/db/archive.info.copy' for read | ||||
|             HINT: archive.info cannot be opened but is required to push/get WAL segments. | ||||
|             HINT: is archive_command configured correctly in postgresql.conf? | ||||
|             HINT: has a stanza-create been performed? | ||||
|             HINT: use --no-archive-check to disable archive checks during backup if you have an alternate archiving scheme. | ||||
| P00   INFO: archive-push command end: aborted with exception [055] | ||||
| P00   INFO: archive-push command end: aborted with exception [103] | ||||
|  | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --stanza=db archive-get 000000010000000100000001 [TEST_PATH]/db-primary/db/base/pg_xlog/RECOVERYXLOG | ||||
| ------------------------------------------------------------------------------------------------------------------------------------ | ||||
| @@ -115,9 +116,10 @@ P00   INFO: archive-get command end: aborted with exception [103] | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --stanza=db archive-push [TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000002 | ||||
| ------------------------------------------------------------------------------------------------------------------------------------ | ||||
| P00   INFO: archive-push command begin [BACKREST-VERSION]: [[TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000002] --buffer-size=[BUFFER-SIZE] --compress-level=3 --compress-type=none --config=[TEST_PATH]/db-primary/pgbackrest.conf --db-timeout=45 --exec-id=[EXEC-ID] --job-retry=0 --lock-path=[TEST_PATH]/db-primary/lock --log-level-console=detail --log-level-file=[LOG-LEVEL-FILE] --log-level-stderr=off --log-path=[TEST_PATH]/db-primary/log[] --no-log-timestamp --pg1-path=[TEST_PATH]/db-primary/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=[TEST_PATH]/db-primary/repo --stanza=db | ||||
| P00  ERROR: [044]: PostgreSQL version 9.4, system-id 1000000000000000094 do not match repo1 stanza version 9.4, system-id 5000900090001855000 | ||||
| P00  ERROR: [103]: unable to find a valid repository: | ||||
|             repo1: [ArchiveMismatchError] PostgreSQL version 9.4, system-id 1000000000000000094 do not match repo1 stanza version 9.4, system-id 5000900090001855000 | ||||
|             HINT: are you archiving to the correct stanza? | ||||
| P00   INFO: archive-push command end: aborted with exception [044] | ||||
| P00   INFO: archive-push command end: aborted with exception [103] | ||||
|  | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --stanza=db archive-get 000000010000000100000001 [TEST_PATH]/db-primary/db/base/pg_xlog/RECOVERYXLOG | ||||
| ------------------------------------------------------------------------------------------------------------------------------------ | ||||
|   | ||||
| @@ -4,14 +4,15 @@ run 002 - rmt 1, storage s3, enc 0, cmp zst | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --stanza=db archive-push [TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000001 | ||||
| ------------------------------------------------------------------------------------------------------------------------------------ | ||||
| P00   INFO: archive-push command begin [BACKREST-VERSION]: [[TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000001] --buffer-size=[BUFFER-SIZE] --compress-level=3 --compress-level-network=1 --compress-type=none --config=[TEST_PATH]/db-primary/pgbackrest.conf --db-timeout=45 --exec-id=[EXEC-ID] --job-retry=0 --lock-path=[TEST_PATH]/db-primary/lock --log-level-console=detail --log-level-file=[LOG-LEVEL-FILE] --log-level-stderr=off --log-path=[TEST_PATH]/db-primary/log[] --no-log-timestamp --pg1-path=[TEST_PATH]/db-primary/db/base --protocol-timeout=60 --repo1-host=backup --repo1-host-cmd=[BACKREST-BIN] --repo1-host-config=[TEST_PATH]/backup/pgbackrest.conf --repo1-host-user=[USER-1] --stanza=db | ||||
| P00  ERROR: [055]: unable to load info file '/archive/db/archive.info' or '/archive/db/archive.info.copy': | ||||
| P00  ERROR: [103]: unable to find a valid repository: | ||||
|             repo1: [FileMissingError] unable to load info file '/archive/db/archive.info' or '/archive/db/archive.info.copy': | ||||
|             FileMissingError: raised from remote-0 protocol on 'backup': unable to open missing file '/archive/db/archive.info' for read | ||||
|             FileMissingError: raised from remote-0 protocol on 'backup': unable to open missing file '/archive/db/archive.info.copy' for read | ||||
|             HINT: archive.info cannot be opened but is required to push/get WAL segments. | ||||
|             HINT: is archive_command configured correctly in postgresql.conf? | ||||
|             HINT: has a stanza-create been performed? | ||||
|             HINT: use --no-archive-check to disable archive checks during backup if you have an alternate archiving scheme. | ||||
| P00   INFO: archive-push command end: aborted with exception [055] | ||||
| P00   INFO: archive-push command end: aborted with exception [103] | ||||
|  | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --stanza=db archive-get 000000010000000100000001 [TEST_PATH]/db-primary/db/base/pg_xlog/RECOVERYXLOG | ||||
| ------------------------------------------------------------------------------------------------------------------------------------ | ||||
| @@ -110,9 +111,10 @@ P00   INFO: archive-get command end: aborted with exception [103] | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --stanza=db archive-push [TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000002 | ||||
| ------------------------------------------------------------------------------------------------------------------------------------ | ||||
| P00   INFO: archive-push command begin [BACKREST-VERSION]: [[TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000002] --buffer-size=[BUFFER-SIZE] --compress-level=3 --compress-level-network=1 --compress-type=none --config=[TEST_PATH]/db-primary/pgbackrest.conf --db-timeout=45 --exec-id=[EXEC-ID] --job-retry=0 --lock-path=[TEST_PATH]/db-primary/lock --log-level-console=detail --log-level-file=[LOG-LEVEL-FILE] --log-level-stderr=off --log-path=[TEST_PATH]/db-primary/log[] --no-log-timestamp --pg1-path=[TEST_PATH]/db-primary/db/base --protocol-timeout=60 --repo1-host=backup --repo1-host-cmd=[BACKREST-BIN] --repo1-host-config=[TEST_PATH]/backup/pgbackrest.conf --repo1-host-user=[USER-1] --stanza=db | ||||
| P00  ERROR: [044]: PostgreSQL version 9.4, system-id 1000000000000000094 do not match repo1 stanza version 9.4, system-id 5000900090001855000 | ||||
| P00  ERROR: [103]: unable to find a valid repository: | ||||
|             repo1: [ArchiveMismatchError] PostgreSQL version 9.4, system-id 1000000000000000094 do not match repo1 stanza version 9.4, system-id 5000900090001855000 | ||||
|             HINT: are you archiving to the correct stanza? | ||||
| P00   INFO: archive-push command end: aborted with exception [044] | ||||
| P00   INFO: archive-push command end: aborted with exception [103] | ||||
|  | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --stanza=db archive-get 000000010000000100000001 [TEST_PATH]/db-primary/db/base/pg_xlog/RECOVERYXLOG | ||||
| ------------------------------------------------------------------------------------------------------------------------------------ | ||||
|   | ||||
| @@ -56,12 +56,14 @@ backrest-checksum="[CHECKSUM]" | ||||
|  | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000002 | ||||
| ------------------------------------------------------------------------------------------------------------------------------------ | ||||
| P00  ERROR: [044]: PostgreSQL version 9.4, system-id 1000000000000000094 do not match repo1 stanza version 8.0, system-id 1000000000000000094 | ||||
| P00  ERROR: [103]: unable to find a valid repository: | ||||
|             repo1: [ArchiveMismatchError] PostgreSQL version 9.4, system-id 1000000000000000094 do not match repo1 stanza version 8.0, system-id 1000000000000000094 | ||||
|             HINT: are you archiving to the correct stanza? | ||||
|  | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000003 | ||||
| ------------------------------------------------------------------------------------------------------------------------------------ | ||||
| P00  ERROR: [044]: PostgreSQL version 9.4, system-id 1000000000000000094 do not match repo1 stanza version 8.0, system-id 1000000000000000094 | ||||
| P00  ERROR: [103]: unable to find a valid repository: | ||||
|             repo1: [ArchiveMismatchError] PostgreSQL version 9.4, system-id 1000000000000000094 do not match repo1 stanza version 8.0, system-id 1000000000000000094 | ||||
|             HINT: are you archiving to the correct stanza? | ||||
|  | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000004 --repo1-host=bogus | ||||
|   | ||||
| @@ -48,13 +48,15 @@ backrest-checksum="[CHECKSUM]" | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000001 | ||||
| ------------------------------------------------------------------------------------------------------------------------------------ | ||||
|  | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db --repo1-host=bogus archive-push [TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000002 | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000002 --repo1-host=bogus | ||||
| ------------------------------------------------------------------------------------------------------------------------------------ | ||||
| P00  ERROR: [125]: remote-0 process on 'bogus' terminated unexpectedly [255]: ssh: Could not resolve hostname bogus: Name or service not known | ||||
| P00  ERROR: [103]: unable to find a valid repository: | ||||
|             repo1: [UnknownError] remote-0 process on 'bogus' terminated unexpectedly [255]: ssh: Could not resolve hostname bogus: Name or service not known | ||||
|  | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db --repo1-host=bogus archive-push [TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000003 | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000003 --repo1-host=bogus | ||||
| ------------------------------------------------------------------------------------------------------------------------------------ | ||||
| P00  ERROR: [125]: remote-0 process on 'bogus' terminated unexpectedly [255]: ssh: Could not resolve hostname bogus: Name or service not known | ||||
| P00  ERROR: [103]: unable to find a valid repository: | ||||
|             repo1: [UnknownError] remote-0 process on 'bogus' terminated unexpectedly [255]: ssh: Could not resolve hostname bogus: Name or service not known | ||||
|  | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000004 --repo1-host=bogus | ||||
| ------------------------------------------------------------------------------------------------------------------------------------ | ||||
|   | ||||
| @@ -250,7 +250,8 @@ P00   INFO: archive-push command end: completed successfully | ||||
|  | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000001 | ||||
| ------------------------------------------------------------------------------------------------------------------------------------ | ||||
| P00  ERROR: [044]: PostgreSQL version 9.4, system-id 1000000000000000094 do not match repo1 stanza version 9.3, system-id 1000000000000000093 | ||||
| P00  ERROR: [103]: unable to find a valid repository: | ||||
|             repo1: [ArchiveMismatchError] PostgreSQL version 9.4, system-id 1000000000000000094 do not match repo1 stanza version 9.3, system-id 1000000000000000093 | ||||
|             HINT: are you archiving to the correct stanza? | ||||
|  | ||||
| stanza-upgrade db - successful upgrade creates additional history (db-primary host) | ||||
|   | ||||
| @@ -241,7 +241,8 @@ P00   INFO: archive-push command end: completed successfully | ||||
|  | ||||
| > [CONTAINER-EXEC] db-primary [BACKREST-BIN] --config=[TEST_PATH]/db-primary/pgbackrest.conf --log-level-console=warn --archive-push-queue-max=33554432 --stanza=db archive-push [TEST_PATH]/db-primary/db/base/pg_xlog/000000010000000100000001 | ||||
| ------------------------------------------------------------------------------------------------------------------------------------ | ||||
| P00  ERROR: [044]: PostgreSQL version 9.4, system-id 1000000000000000094 do not match repo1 stanza version 9.3, system-id 1000000000000000093 | ||||
| P00  ERROR: [103]: unable to find a valid repository: | ||||
|             repo1: [ArchiveMismatchError] PostgreSQL version 9.4, system-id 1000000000000000094 do not match repo1 stanza version 9.3, system-id 1000000000000000093 | ||||
|             HINT: are you archiving to the correct stanza? | ||||
|  | ||||
| stanza-upgrade db - successful upgrade creates additional history (backup host) | ||||
|   | ||||
| @@ -150,7 +150,6 @@ sub archivePush | ||||
|         ' --config=' . $self->backrestConfig() . | ||||
|         ' --log-level-console=warn --archive-push-queue-max=' . int(2 * PG_WAL_SIZE_TEST) . | ||||
|         ' --stanza=' . $self->stanza() . | ||||
|         (defined($iExpectedError) && $iExpectedError == ERROR_UNKNOWN ? ' --repo1-host=bogus' : '') . | ||||
|         ($bAsync ? '' : ' --no-archive-async') . | ||||
|         " archive-push" . (defined($strSourceFile) ? " ${strSourceFile}" : '') . | ||||
|         (defined($strOptionalParam) ? " ${strOptionalParam}" : ''), | ||||
|   | ||||
| @@ -102,12 +102,12 @@ sub run | ||||
|         &log(INFO, '    push second WAL'); | ||||
|  | ||||
|         $oHostDbPrimary->archivePush( | ||||
|             $strWalPath, $strWalTestFile, 2, $iError ? ERROR_UNKNOWN : ERROR_ARCHIVE_MISMATCH); | ||||
|             $strWalPath, $strWalTestFile, 2, ERROR_REPO_INVALID, undef, $iError ? '--repo1-host=bogus' : undef); | ||||
|  | ||||
|         &log(INFO, '    push third WAL'); | ||||
|  | ||||
|         $oHostDbPrimary->archivePush( | ||||
|             $strWalPath, $strWalTestFile, 3, $iError ? ERROR_UNKNOWN : ERROR_ARCHIVE_MISMATCH); | ||||
|             $strWalPath, $strWalTestFile, 3, ERROR_REPO_INVALID, undef, $iError ? '--repo1-host=bogus' : undef); | ||||
|  | ||||
|         # Now this segment will get dropped | ||||
|         &log(INFO, '    push fourth WAL'); | ||||
|   | ||||
| @@ -135,7 +135,7 @@ sub run | ||||
|  | ||||
|         $oHostDbPrimary->executeSimple( | ||||
|             $strCommandPush . " ${strWalPath}/${strSourceFile1}", | ||||
|             {iExpectedExitStatus => ERROR_FILE_MISSING, oLogTest => $self->expect()}); | ||||
|             {iExpectedExitStatus => ERROR_REPO_INVALID, oLogTest => $self->expect()}); | ||||
|  | ||||
|         $oHostDbPrimary->executeSimple( | ||||
|             $strCommandGet . " ${strSourceFile1} ${strWalPath}/RECOVERYXLOG", | ||||
| @@ -293,7 +293,7 @@ sub run | ||||
|  | ||||
|         $oHostDbPrimary->executeSimple( | ||||
|             $strCommandPush . " ${strWalPath}/${strSourceFile}", | ||||
|             {iExpectedExitStatus => ERROR_ARCHIVE_MISMATCH, oLogTest => $self->expect()}); | ||||
|             {iExpectedExitStatus => ERROR_REPO_INVALID, oLogTest => $self->expect()}); | ||||
|  | ||||
|         $oHostDbPrimary->executeSimple( | ||||
|             $strCommandGet . " ${strSourceFile1} ${strWalPath}/RECOVERYXLOG", | ||||
|   | ||||
| @@ -159,7 +159,7 @@ sub run | ||||
|         forceStorageMode(storageTest(), $oHostDbPrimary->dbBasePath() . '/' . DB_FILE_PGCONTROL, '600'); | ||||
|  | ||||
|         # Fail on attempt to push an archive | ||||
|         $oHostDbPrimary->archivePush($strWalPath, $strArchiveTestFile, 1, ERROR_ARCHIVE_MISMATCH); | ||||
|         $oHostDbPrimary->archivePush($strWalPath, $strArchiveTestFile, 1, ERROR_REPO_INVALID); | ||||
|  | ||||
|         # Perform a successful stanza upgrade noting additional history lines in info files for new version of the database | ||||
|         #-------------------------------------------------------------------------------------------------------------------------- | ||||
|   | ||||
| @@ -133,9 +133,10 @@ testRun(void) | ||||
|                 "1={\"db-id\":5555555555555555555,\"db-version\":\"9.4\"}\n")); | ||||
|  | ||||
|         TEST_ERROR( | ||||
|             archivePushCheck(true), ArchiveMismatchError, | ||||
|             "PostgreSQL version 9.6, system-id 18072658121562454734 do not match repo1 stanza version 9.4, system-id" | ||||
|                 " 5555555555555555555" | ||||
|             archivePushCheck(true), RepoInvalidError, | ||||
|             "unable to find a valid repository:\n" | ||||
|             "repo1: [ArchiveMismatchError] PostgreSQL version 9.6, system-id 18072658121562454734 do not match repo1 stanza version" | ||||
|                 " 9.4, system-id 5555555555555555555" | ||||
|                 "\nHINT: are you archiving to the correct stanza?"); | ||||
|  | ||||
|         // Fix the version | ||||
| @@ -149,9 +150,10 @@ testRun(void) | ||||
|                 "1={\"db-id\":5555555555555555555,\"db-version\":\"9.6\"}\n")); | ||||
|  | ||||
|         TEST_ERROR( | ||||
|             archivePushCheck(true), ArchiveMismatchError, | ||||
|             "PostgreSQL version 9.6, system-id 18072658121562454734 do not match repo1 stanza version 9.6, system-id" | ||||
|                 " 5555555555555555555" | ||||
|             archivePushCheck(true), RepoInvalidError, | ||||
|             "unable to find a valid repository:\n" | ||||
|             "repo1: [ArchiveMismatchError] PostgreSQL version 9.6, system-id 18072658121562454734 do not match repo1 stanza version" | ||||
|                 " 9.6, system-id 5555555555555555555" | ||||
|                 "\nHINT: are you archiving to the correct stanza?"); | ||||
|  | ||||
|         // Fix archive info | ||||
| @@ -169,9 +171,12 @@ testRun(void) | ||||
|  | ||||
|         TEST_RESULT_UINT(result.pgVersion, PG_VERSION_96, "check pg version"); | ||||
|         TEST_RESULT_UINT(result.pgSystemId, 0xFACEFACEFACEFACE, "check pg system id"); | ||||
|         TEST_RESULT_STR_Z(result.repoData[0].archiveId, "9.6-1", "check archive id"); | ||||
|         TEST_RESULT_UINT(result.repoData[0].cipherType, cipherTypeNone, "check cipher type"); | ||||
|         TEST_RESULT_STR_Z(result.repoData[0].cipherPass, NULL, "check cipher pass (not set in this test)"); | ||||
|  | ||||
|         ArchivePushFileRepoData *repoData = lstGet(result.repoList, 0); | ||||
|         TEST_RESULT_UINT(repoData->repoIdx, 0, "check repo idx"); | ||||
|         TEST_RESULT_STR_Z(repoData->archiveId, "9.6-1", "check archive id"); | ||||
|         TEST_RESULT_UINT(repoData->cipherType, cipherTypeNone, "check cipher type"); | ||||
|         TEST_RESULT_STR_Z(repoData->cipherPass, NULL, "check cipher pass (not set in this test)"); | ||||
|  | ||||
|         // ------------------------------------------------------------------------------------------------------------------------- | ||||
|         TEST_TITLE("mismatched repos when pg-path not present"); | ||||
| @@ -202,11 +207,22 @@ testRun(void) | ||||
|                 "[db:history]\n" | ||||
|                 "1={\"db-id\":5555555555555555555,\"db-version\":\"9.4\"}\n")); | ||||
|  | ||||
|         TEST_ERROR( | ||||
|             archivePushCheck(false), ArchiveMismatchError, | ||||
|             "repo2 stanza version 9.6, system-id 18072658121562454734 do not match repo4 stanza version 9.4, system-id" | ||||
|                 " 5555555555555555555" | ||||
|                 "\nHINT: are you archiving to the correct stanza?"); | ||||
|         TEST_ASSIGN(result, archivePushCheck(false), "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"); | ||||
|         TEST_RESULT_STRLST_Z( | ||||
|             result.errorList, | ||||
|             "repo4: [ArchiveMismatchError] repo2 stanza version 9.6, system-id 18072658121562454734 do not match repo4 stanza" | ||||
|                 " version 9.4, system-id 5555555555555555555\n" | ||||
|             "HINT: are you archiving to the correct stanza?\n", | ||||
|             "check error list"); | ||||
|  | ||||
|         repoData = lstGet(result.repoList, 0); | ||||
|         TEST_RESULT_UINT(repoData->repoIdx, 0, "check repo idx"); | ||||
|         TEST_RESULT_STR_Z(repoData->archiveId, "9.6-1", "check archive id"); | ||||
|         TEST_RESULT_UINT(repoData->cipherType, cipherTypeNone, "check cipher type"); | ||||
|         TEST_RESULT_STR_Z(repoData->cipherPass, NULL, "check cipher pass (not set in this test)"); | ||||
|  | ||||
|         // ------------------------------------------------------------------------------------------------------------------------- | ||||
|         TEST_TITLE("matched repos when pg-path not present"); | ||||
| @@ -226,12 +242,18 @@ testRun(void) | ||||
|  | ||||
|         TEST_RESULT_UINT(result.pgVersion, PG_VERSION_96, "check pg version"); | ||||
|         TEST_RESULT_UINT(result.pgSystemId, 0xFACEFACEFACEFACE, "check pg system id"); | ||||
|         TEST_RESULT_STR_Z(result.repoData[0].archiveId, "9.6-1", "check repo2 archive id"); | ||||
|         TEST_RESULT_UINT(result.repoData[0].cipherType, cipherTypeNone, "check repo2 cipher pass"); | ||||
|         TEST_RESULT_STR_Z(result.repoData[0].cipherPass, NULL, "check repo2 cipher pass (not set in this test)"); | ||||
|         TEST_RESULT_STR_Z(result.repoData[1].archiveId, "9.6-2", "check repo4 archive id"); | ||||
|         TEST_RESULT_UINT(result.repoData[1].cipherType, cipherTypeNone, "check repo4 cipher type"); | ||||
|         TEST_RESULT_STR_Z(result.repoData[1].cipherPass, NULL, "check repo4 cipher pass (not set in this test)"); | ||||
|  | ||||
|         repoData = lstGet(result.repoList, 0); | ||||
|         TEST_RESULT_UINT(repoData->repoIdx, 0, "check repo idx"); | ||||
|         TEST_RESULT_STR_Z(repoData->archiveId, "9.6-1", "check repo2 archive id"); | ||||
|         TEST_RESULT_UINT(repoData->cipherType, cipherTypeNone, "check repo2 cipher pass"); | ||||
|         TEST_RESULT_STR_Z(repoData->cipherPass, NULL, "check repo2 cipher pass (not set in this test)"); | ||||
|  | ||||
|         repoData = lstGet(result.repoList, 1); | ||||
|         TEST_RESULT_UINT(repoData->repoIdx, 1, "check repo idx"); | ||||
|         TEST_RESULT_STR_Z(repoData->archiveId, "9.6-2", "check repo4 archive id"); | ||||
|         TEST_RESULT_UINT(repoData->cipherType, cipherTypeNone, "check repo4 cipher type"); | ||||
|         TEST_RESULT_STR_Z(repoData->cipherPass, NULL, "check repo4 cipher pass (not set in this test)"); | ||||
|     } | ||||
|  | ||||
|     // ***************************************************************************************************************************** | ||||
| @@ -435,6 +457,9 @@ testRun(void) | ||||
|         varLstAdd(paramList, varNewStrZ("000000010000000100000002")); | ||||
|         varLstAdd(paramList, varNewBool(false)); | ||||
|         varLstAdd(paramList, varNewInt(6)); | ||||
|         varLstAdd(paramList, varNewVarLst(varLstNewStrLst(strLstNew()))); | ||||
|         varLstAdd(paramList, varNewUInt(1)); | ||||
|         varLstAdd(paramList, varNewUInt(0)); | ||||
|         varLstAdd(paramList, varNewStrZ("11-1")); | ||||
|         varLstAdd(paramList, varNewUInt64(cipherTypeNone)); | ||||
|         varLstAdd(paramList, NULL); | ||||
| @@ -564,6 +589,50 @@ testRun(void) | ||||
|             "P00   WARN: WAL file '000000010000000100000002' already exists in the repo3 archive with the same checksum\n" | ||||
|             "            HINT: this is valid in some recovery scenarios but may also indicate a problem.\n" | ||||
|             "P00   INFO: pushed WAL file '000000010000000100000002' to the archive"); | ||||
|  | ||||
|         // ------------------------------------------------------------------------------------------------------------------------- | ||||
|         TEST_TITLE("push succeeds on one repo when other repo fails to load archive.info"); | ||||
|  | ||||
|         TEST_STORAGE_REMOVE( | ||||
|             storageTest, strZ(strNewFmt("repo2/archive/test/11-1/0000000100000001/000000010000000100000002-%s", walBuffer2Sha1))); | ||||
|         TEST_STORAGE_REMOVE( | ||||
|             storageTest, strZ(strNewFmt("repo3/archive/test/11-1/0000000100000001/000000010000000100000002-%s", walBuffer2Sha1))); | ||||
|         HRN_STORAGE_MODE(storageTest, "repo2", .mode = 0200); | ||||
|  | ||||
|         TEST_ERROR( | ||||
|             cmdArchivePush(), CommandError, | ||||
|             "archive-push command encountered error(s):\n" | ||||
|             "repo2: [FileOpenError] unable to load info file '{[path]}/repo2/archive/test/archive.info' or" | ||||
|                 " '{[path]}/repo2/archive/test/archive.info.copy':\n" | ||||
|             "FileOpenError: unable to open file '{[path]}/repo2/archive/test/archive.info' for read: [13] Permission denied\n" | ||||
|             "FileOpenError: unable to open file '{[path]}/repo2/archive/test/archive.info.copy' for read: [13] Permission denied\n" | ||||
|             "HINT: archive.info cannot be opened but is required to push/get WAL segments.\n" | ||||
|             "HINT: is archive_command configured correctly in postgresql.conf?\n" | ||||
|             "HINT: has a stanza-create been performed?\n" | ||||
|             "HINT: use --no-archive-check to disable archive checks during backup if you have an alternate archiving scheme."); | ||||
|  | ||||
|         // Make sure WAL got pushed to repo3 | ||||
|         TEST_STORAGE_REMOVE( | ||||
|             storageTest, strZ(strNewFmt("repo3/archive/test/11-1/0000000100000001/000000010000000100000002-%s", walBuffer2Sha1))); | ||||
|  | ||||
|         HRN_STORAGE_MODE(storageTest, "repo2"); | ||||
|  | ||||
|         // ------------------------------------------------------------------------------------------------------------------------- | ||||
|         TEST_TITLE("push succeeds on one repo when other repo fails to read path"); | ||||
|  | ||||
|         HRN_STORAGE_MODE(storageTest, "repo2/archive/test/11-1", .mode = 0200); | ||||
|  | ||||
|         TEST_ERROR( | ||||
|             cmdArchivePush(), CommandError, | ||||
|             "archive-push command encountered error(s):\n" | ||||
|             "repo2: [PathOpenError] unable to list file info for path '{[path]}/repo2/archive/test/11-1/0000000100000001': [13]" | ||||
|                 " Permission denied"); | ||||
|  | ||||
|         // Make sure WAL got pushed to repo3 | ||||
|         TEST_STORAGE_REMOVE( | ||||
|             storageTest, strZ(strNewFmt("repo3/archive/test/11-1/0000000100000001/000000010000000100000002-%s", walBuffer2Sha1))); | ||||
|  | ||||
|         HRN_STORAGE_MODE(storageTest, "repo2/archive/test/11-1"); | ||||
|     } | ||||
|  | ||||
|     // ***************************************************************************************************************************** | ||||
|   | ||||
		Reference in New Issue
	
	Block a user