diff --git a/src/command/repo/push.c b/src/command/repo/push.c index 720b8e6871..da1ae61be6 100644 --- a/src/command/repo/push.c +++ b/src/command/repo/push.c @@ -76,9 +76,10 @@ storagePushProcess(const String *file, CompressType compressType, int compressLe IoFilterGroup *const writeFilterGroup = ioWriteFilterGroup(destinationIo); const String *manifestFileName = strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strZ(backupLabel)); - Manifest *manifest = manifestLoadFile( - storage, manifestFileName, - cipherTypeNone, NULL); + const String *manifestFileNameCopy = strNewFmt("%s" INFO_COPY_EXT, strZ(manifestFileName)); + + // Load main manifest only. Don't fallback to copy. So resumable backup cannot be made to appear complete. + Manifest *manifest = manifestNewLoad(storageReadIo(storageNewReadP(storage, manifestFileName))); // Add SHA1 filter ioFilterGroupAdd(writeFilterGroup, cryptoHashNew(hashTypeSha1)); @@ -151,6 +152,7 @@ storagePushProcess(const String *file, CompressType compressType, int compressLe manifestFile.sizeRepo = customFile.sizeRepo; manifestFile.timestamp = customFile.timestamp; manifestFile.checksumSha1 = customFile.checksumSha1; + manifestFile.checksumRepoSha1 = customFile.checksumRepoSha1; manifestCustomFileUpdate(manifest, &manifestFile); found = true; @@ -161,14 +163,18 @@ storagePushProcess(const String *file, CompressType compressType, int compressLe if (!found) manifestCustomFileAdd(manifest, &customFile); - // Save manifest + // Save copy first and then copy it to the main manifest, matching backup completion semantics. IoWrite *const manifestWrite = storageWriteIo( storageNewWriteP( storageRepoWrite(), - manifestFileName + manifestFileNameCopy )); manifestSave(manifest, manifestWrite); + + storageCopy( + storageNewReadP(storage, manifestFileNameCopy), + storageNewWriteP(storageRepoWrite(), manifestFileName)); } MEM_CONTEXT_TEMP_END(); diff --git a/test/src/module/command/repoTest.c b/test/src/module/command/repoTest.c index 97ef3666b6..d7080344af 100644 --- a/test/src/module/command/repoTest.c +++ b/test/src/module/command/repoTest.c @@ -18,6 +18,7 @@ Test Repo Commands #include "info/infoBackup.h" #define TEST_BACKUP_LABEL_FULL "20260201-173010F" +#define TEST_BACKUP_LABEL_RESUME "20260201-173011F" #define TEST_STANZA "testStanza01" #define TEST_DATA \ @@ -132,6 +133,23 @@ testManifestCustomFilesValidate(Manifest *manifest) FUNCTION_HARNESS_RETURN(STRING, result); } +static bool +testBackupManifestCopyValidate(const Storage *const storage, const String *const backupLabel) +{ + FUNCTION_HARNESS_BEGIN(); + FUNCTION_HARNESS_PARAM(STORAGE, storage); + FUNCTION_HARNESS_PARAM(STRING, backupLabel); + FUNCTION_HARNESS_END(); + + const String *const manifestFile = strNewFmt(STORAGE_REPO_BACKUP "/%s/" BACKUP_MANIFEST_FILE, strZ(backupLabel)); + + const bool result = bufEq( + storageGetP(storageNewReadP(storage, manifestFile)), + storageGetP(storageNewReadP(storage, strNewFmt("%s" INFO_COPY_EXT, strZ(manifestFile))))); + + FUNCTION_HARNESS_RETURN(BOOL, result); +} + /*********************************************************************************************************************************** Test Run ***********************************************************************************************************************************/ @@ -1518,7 +1536,11 @@ testRun(void) TEST_RESULT_VOID(cmdStoragePush(), "push file"); TEST_RESULT_LOG("P00 INFO: push file path/aaa.txt to the archive."); - TEST_STORAGE_LIST(storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL, "aaa.txt\nbackup.manifest\n", .comment = "check path exists and file added"); + TEST_STORAGE_LIST( + storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL, + "aaa.txt\nbackup.manifest\nbackup.manifest.copy\n", .comment = "check path exists and file added"); + TEST_RESULT_BOOL( + testBackupManifestCopyValidate(storageRepo(), STRDEF(TEST_BACKUP_LABEL_FULL)), true, "check manifest copy"); TEST_STORAGE_GET(storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL "/aaa.txt", "TESTDATA"); @@ -1538,7 +1560,11 @@ testRun(void) TEST_RESULT_VOID(cmdStoragePush(), "push file"); TEST_RESULT_LOG("P00 INFO: push file path/aaa.txt to the archive."); - TEST_STORAGE_LIST(storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL, "aaa.txt\nbackup.manifest\n", .comment = "check path exists and file added"); + TEST_STORAGE_LIST( + storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL, + "aaa.txt\nbackup.manifest\nbackup.manifest.copy\n", .comment = "check path exists and file added"); + TEST_RESULT_BOOL( + testBackupManifestCopyValidate(storageRepo(), STRDEF(TEST_BACKUP_LABEL_FULL)), true, "check manifest copy"); TEST_STORAGE_GET(storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL "/aaa.txt", TEST_DATA); @@ -1562,15 +1588,37 @@ testRun(void) hrnCfgArgRawZ(argList, cfgOptCompressLevel, "3"); strLstAddZ(argList, "path/aaa.txt"); + HRN_CFG_LOAD(cfgCmdRepoPush, argList); + + TEST_RESULT_VOID(cmdStoragePush(), "push file"); + TEST_RESULT_LOG("P00 INFO: push file path/aaa.txt to the archive."); + TEST_STORAGE_LIST( + storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL, + "aaa.txt\naaa.txt.gz\nbackup.manifest\nbackup.manifest.copy\n", .comment = "check path exists and file added"); + TEST_RESULT_BOOL( + testBackupManifestCopyValidate(storageRepo(), STRDEF(TEST_BACKUP_LABEL_FULL)), true, "check manifest copy"); + + TEST_STORAGE_GET(storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL "/aaa.txt", TEST_DATA, .compressType = compressTypeGz); + + manifest = manifestLoadFile( + storageRepo(), STR(STORAGE_REPO_BACKUP "/" TEST_BACKUP_LABEL_FULL "/" BACKUP_MANIFEST_FILE), cipherTypeNone, NULL); + + /* Check manifest record */ + TEST_RESULT_STR_Z( + testManifestCustomFilesValidate(manifest), + "aaa.txt 445\naaa.txt.gz 445\n", + "compare file list"); + + TEST_TITLE("do not push to resumable backup manifest copy"); HRN_INFO_PUT( - storageRepoWrite(), STORAGE_REPO_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL "/" BACKUP_MANIFEST_FILE, + storageRepoWrite(), STORAGE_REPO_BACKUP "/" TEST_BACKUP_LABEL_RESUME "/" BACKUP_MANIFEST_FILE INFO_COPY_EXT, TEST_MANIFEST_HEADER "\n" "[backup:db]\n" "db-catalog-version=201608131\n" "db-control-version=960\n" "db-id=1\n" - "db-system-id=" HRN_PG_SYSTEMID_94_Z "\n" // 9.4 system id is used so version will trigger error + "db-system-id=" HRN_PG_SYSTEMID_94_Z "\n" "db-version=\"9.6\"\n" TEST_MANIFEST_OPTION_ALL TEST_MANIFEST_TARGET @@ -1581,24 +1629,27 @@ testRun(void) TEST_MANIFEST_LINK_DEFAULT TEST_MANIFEST_PATH TEST_MANIFEST_PATH_DEFAULT, - .comment = "manifest db section mismatch"); + .comment = "manifest copy only"); + + argList = strLstNew(); + hrnCfgArgKeyRawZ(argList, cfgOptRepoPath, 1, TEST_PATH "/bogus"); + hrnCfgArgKeyRawZ(argList, cfgOptRepoPath, 2, TEST_PATH "/repo"); + hrnCfgArgRawZ(argList, cfgOptCompressType, "none"); + hrnCfgArgRawZ(argList, cfgOptStanza, TEST_STANZA); + hrnCfgArgRawZ(argList, cfgOptSet, TEST_BACKUP_LABEL_RESUME); + hrnCfgArgRawZ(argList, cfgOptRepo, "2"); + strLstAddZ(argList, "path/aaa.txt"); HRN_CFG_LOAD(cfgCmdRepoPush, argList); - TEST_RESULT_VOID(cmdStoragePush(), "push file"); + TEST_ERROR( + cmdStoragePush(), FileMissingError, + "unable to open missing file '" TEST_PATH "/repo/backup/" TEST_STANZA "/" TEST_BACKUP_LABEL_RESUME + "/backup.manifest' for read"); TEST_RESULT_LOG("P00 INFO: push file path/aaa.txt to the archive."); - TEST_STORAGE_LIST(storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL, "aaa.txt\naaa.txt.gz\nbackup.manifest\n", .comment = "check path exists and file added"); - - TEST_STORAGE_GET(storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_FULL "/aaa.txt", TEST_DATA, .compressType = compressTypeGz); - - manifest = manifestLoadFile( - storageRepo(), STR(STORAGE_REPO_BACKUP "/" TEST_BACKUP_LABEL_FULL "/" BACKUP_MANIFEST_FILE), cipherTypeNone, NULL); - - /* Check manifest record */ - TEST_RESULT_STR_Z( - testManifestCustomFilesValidate(manifest), - "aaa.txt 445\naaa.txt.gz 445\n", - "compare file list"); + TEST_STORAGE_LIST( + storageRepo(), STORAGE_PATH_BACKUP "/" TEST_STANZA "/" TEST_BACKUP_LABEL_RESUME, + "backup.manifest.copy\n", .comment = "main manifest was not created"); TEST_TITLE("push encrypted file not supported"); argList = strLstNew();