1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-01-18 04:58:51 +02:00

Info objects now parse JSON and use specified storage.

Use JSON code now that it is available and remove temporary hacks used to get things working initially.

Use passed storage objects rather than using storageLocal().  All storage objects in C are still local but this won't always be the case.

Also, move Postgres version conversion functions to postgres/info.c since they have no dependency on the info objects and will likely be useful elsewhere.
This commit is contained in:
David Steele 2018-09-06 10:12:14 -07:00
parent de1b74da0c
commit 960ad73298
15 changed files with 275 additions and 143 deletions

View File

@ -30,6 +30,10 @@
<release-item>
<p>Posix file functions now differentiate between open and missing errors.</p>
</release-item>
<release-item>
<p>Info objects now parse JSON and use specified storage.</p>
</release-item>
</release-development-list>
</release-core-list>
</release>

View File

@ -84,6 +84,7 @@ SRCS = \
common/time.c \
common/type/buffer.c \
common/type/convert.c \
common/type/json.c \
common/type/keyValue.c \
common/type/list.c \
common/type/string.c \
@ -102,6 +103,9 @@ SRCS = \
crypto/hash.c \
crypto/crypto.c \
crypto/random.c \
info/info.c \
info/infoArchive.c \
info/infoPg.c \
perl/config.c \
perl/exec.c \
postgres/info.c \
@ -288,7 +292,7 @@ info/info.o: info/info.c common/debug.h common/error.auto.h common/error.h commo
info/infoArchive.o: info/infoArchive.c common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h info/infoArchive.h info/infoPg.h storage/driver/posix/driverRead.h storage/driver/posix/driverWrite.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h version.h
$(CC) $(CFLAGS) -c info/infoArchive.c -o info/infoArchive.o
info/infoPg.o: info/infoPg.c common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/log.h common/logLevel.h common/memContext.h common/regExp.h common/stackTrace.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/list.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h crypto/hash.h info/info.h info/infoPg.h postgres/info.h postgres/version.h storage/driver/posix/driverRead.h storage/driver/posix/driverWrite.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h version.h
info/infoPg.o: info/infoPg.c common/assert.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/type/buffer.h common/type/convert.h common/type/json.h common/type/keyValue.h common/type/list.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h crypto/hash.h info/info.h info/infoPg.h postgres/info.h postgres/version.h storage/driver/posix/driverRead.h storage/driver/posix/driverWrite.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h version.h
$(CC) $(CFLAGS) -c info/infoPg.c -o info/infoPg.o
main.o: main.c command/archive/get/get.h command/archive/push/push.h command/command.h command/help/help.h common/debug.h common/error.auto.h common/error.h common/exit.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h config/load.h perl/exec.h version.h
@ -300,7 +304,7 @@ perl/config.o: perl/config.c common/debug.h common/error.auto.h common/error.h c
perl/exec.o: perl/exec.c ../libc/LibC.h common/debug.h common/encode.h common/error.auto.h common/error.h common/io/filter/filter.h common/lock.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h config/config.auto.h config/config.h config/define.auto.h config/define.h config/load.h config/parse.h crypto/cipher.h crypto/cipherBlock.h crypto/hash.h crypto/random.h perl/config.h perl/embed.auto.c perl/exec.h perl/libc.auto.c postgres/pageChecksum.h storage/driver/posix/driver.h storage/driver/posix/driverRead.h storage/driver/posix/driverWrite.h storage/info.h version.h ../libc/xs/common/encode.xsh ../libc/xs/crypto/cipherBlock.xsh ../libc/xs/crypto/hash.xsh
$(CC) $(CFLAGS) -c perl/exec.c -o perl/exec.o
postgres/info.o: postgres/info.c common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h postgres/info.h postgres/type.h postgres/version.h storage/driver/posix/driverRead.h storage/driver/posix/driverWrite.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h version.h
postgres/info.o: postgres/info.c common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/log.h common/logLevel.h common/memContext.h common/regExp.h common/stackTrace.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h postgres/info.h postgres/type.h postgres/version.h storage/driver/posix/driverRead.h storage/driver/posix/driverWrite.h storage/fileRead.h storage/fileWrite.h storage/helper.h storage/info.h storage/storage.h version.h
$(CC) $(CFLAGS) -c postgres/info.c -o postgres/info.o
postgres/pageChecksum.o: postgres/pageChecksum.c common/assert.h common/debug.h common/error.auto.h common/error.h common/log.h common/logLevel.h common/stackTrace.h common/type/convert.h postgres/pageChecksum.h postgres/type.h

View File

@ -173,6 +173,7 @@ Internal function to load the copy and check validity
static bool
loadInternal(
Info *this, // Info object to load parsed buffer into
const Storage *storage,
bool copyFile) // Is this the copy file?
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
@ -188,8 +189,8 @@ loadInternal(
{
String *fileName = copyFile ? strCat(strDup(this->fileName), INI_COPY_EXT) : this->fileName;
// ??? Need to replace storageLocal when able
Buffer *buffer = storageGetNP(storageNewReadP(storageLocal(), fileName, .ignoreMissing = true));
// Attempt to load the file
Buffer *buffer = storageGetNP(storageNewReadP(storage, fileName, .ignoreMissing = true));
// If the file exists, parse and validate it
if (buffer != NULL)
@ -214,6 +215,7 @@ Load an Info object
***********************************************************************************************************************************/
Info *
infoNew(
const Storage *storage,
const String *fileName) // Full path/filename to load
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
@ -234,13 +236,14 @@ infoNew(
this->fileName = strDup(fileName);
// Attempt to load the main file. If it does not exist or is invalid, try to load the copy.
if (!loadInternal(this, false))
if (!loadInternal(this, storage, false))
{
if (!loadInternal(this, true))
if (!loadInternal(this, storage, true))
{
THROW_FMT(
FileMissingError, "unable to open %s or %s",
strPtr(this->fileName), strPtr(strCat(strDup(this->fileName), INI_COPY_EXT)));
strPtr(storagePathNP(storage, this->fileName)),
strPtr(strCat(storagePathNP(storage, this->fileName), INI_COPY_EXT)));
}
}
}

View File

@ -11,11 +11,12 @@ typedef struct Info Info;
#include "common/ini.h"
#include "crypto/hash.h"
#include "storage/storage.h"
/***********************************************************************************************************************************
Constructor
***********************************************************************************************************************************/
Info *infoNew(const String *fileName);
Info *infoNew(const Storage *storage, const String *fileName);
/***********************************************************************************************************************************
Getters

View File

@ -29,7 +29,7 @@ Create a new InfoArchive object
// ??? Need loadFile parameter
***********************************************************************************************************************************/
InfoArchive *
infoArchiveNew(const String *fileName, bool ignoreMissing)
infoArchiveNew(const Storage *storage, const String *fileName, bool ignoreMissing)
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STRING, fileName);
@ -45,13 +45,27 @@ infoArchiveNew(const String *fileName, bool ignoreMissing)
// Create object
this = memNew(sizeof(InfoArchive));
this->memContext = MEM_CONTEXT_NEW();
this->infoPg = infoPgNew(fileName, infoPgArchive);
// Catch file missing error and add archive-specific hints before rethrowing
TRY_BEGIN()
{
this->infoPg = infoPgNew(storage, fileName, infoPgArchive);
}
CATCH(FileMissingError)
{
THROW_FMT(
FileMissingError,
"%s\n"
"HINT: archive.info does not exist but is required to push/get WAL segments.\n"
"HINT: is archive_command configured 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.",
errorMessage());
}
TRY_END();
// Store the archiveId for the current PG db-version db-id
InfoPgData currentPg = infoPgDataCurrent(this->infoPg);
this->archiveId = strNew("");
strCatFmt(this->archiveId, "%s-%u", strPtr(infoPgVersionToString(currentPg.version)), currentPg.id);
this->archiveId = infoPgArchiveId(this->infoPg, 0);
}
MEM_CONTEXT_NEW_END();
@ -113,6 +127,21 @@ infoArchiveId(const InfoArchive *this)
FUNCTION_TEST_RESULT(STRING, this->archiveId);
}
/***********************************************************************************************************************************
Get PostgreSQL info
***********************************************************************************************************************************/
InfoPg *
infoArchivePg(const InfoArchive *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(INFO_ARCHIVE, this);
FUNCTION_TEST_ASSERT(this != NULL);
FUNCTION_TEST_END();
FUNCTION_TEST_RESULT(INFO_PG, this->infoPg);
}
/***********************************************************************************************************************************
Free the info
***********************************************************************************************************************************/

View File

@ -10,11 +10,18 @@ Object type
typedef struct InfoArchive InfoArchive;
#include "common/type/string.h"
#include "info/infoPg.h"
#include "storage/storage.h"
/***********************************************************************************************************************************
Archive info filename
***********************************************************************************************************************************/
#define INFO_ARCHIVE_FILE "archive.info"
/***********************************************************************************************************************************
Constructor
***********************************************************************************************************************************/
InfoArchive *infoArchiveNew(const String *fileName, bool ignoreMissing);
InfoArchive *infoArchiveNew(const Storage *storage, const String *fileName, bool ignoreMissing);
/***********************************************************************************************************************************
Functions
@ -25,6 +32,7 @@ void infoArchiveCheckPg(const InfoArchive *this, unsigned int pgVersion, uint64_
Getters
***********************************************************************************************************************************/
const String *infoArchiveId(const InfoArchive *this);
InfoPg *infoArchivePg(const InfoArchive *this);
/***********************************************************************************************************************************
Destructor

View File

@ -6,12 +6,13 @@ PostgreSQL Info Handler
#include <stdio.h>
#include <string.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/log.h"
#include "common/memContext.h"
#include "common/ini.h"
#include "common/memContext.h"
#include "common/regExp.h"
#include "common/type/json.h"
#include "common/type/list.h"
#include "info/info.h"
#include "info/infoPg.h"
@ -43,46 +44,6 @@ struct InfoPg
Info *info; // Info contents
};
/***********************************************************************************************************************************
Return the PostgreSQL version constant given a string
***********************************************************************************************************************************/
unsigned int
infoPgVersionToUIntInternal(const String *version)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STRING, version);
FUNCTION_DEBUG_ASSERT(version != NULL);
FUNCTION_DEBUG_END();
unsigned int result = 0;
MEM_CONTEXT_TEMP_BEGIN()
{
// If format is not number.number (9.4) or number only (10) then error
if (!regExpMatchOne(strNew("^[0-9]+[.]*[0-9]+$"), version))
THROW_FMT(AssertError, "version %s format is invalid", strPtr(version));
size_t idxStart = (size_t)(strChr(version, '.'));
int minor = 0;
int major;
// If there is a dot, then set the major and minor versions, else just the major
if ((int)idxStart != -1)
minor = atoi(strPtr(strSub(version, idxStart + 1)));
else
idxStart = strSize(version);
major = atoi(strPtr(strSubN(version, 0, idxStart)));
// No check to see if valid/supported PG version is on purpose
result = (unsigned int)((major * 10000) + (minor * 100));
}
MEM_CONTEXT_TEMP_END();
FUNCTION_DEBUG_RESULT(UINT, result);
}
/***********************************************************************************************************************************
Load an InfoPg object
??? Need to consider adding the following parameters in order to throw errors
@ -92,7 +53,7 @@ Load an InfoPg object
??? Currently this assumes the file exists and loads data from it
***********************************************************************************************************************************/
InfoPg *
infoPgNew(const String *fileName, InfoPgType type)
infoPgNew(const Storage *storage, const String *fileName, InfoPgType type)
{
FUNCTION_DEBUG_BEGIN(logLevelDebug);
FUNCTION_DEBUG_PARAM(STRING, fileName);
@ -107,40 +68,60 @@ infoPgNew(const String *fileName, InfoPgType type)
// Create object
this = memNew(sizeof(InfoPg));
this->memContext = MEM_CONTEXT_NEW();
this->info = infoNew(fileName);
this->info = infoNew(storage, fileName);
Ini *infoPgIni = infoIni(this->info);
// ??? need to get the history list from the file in ascending order (important for ensuring currentIndex set properly in
// infoPgAdd) but need json parser so for now just getting current
// Get the pg history list
this->history = lstNew(sizeof(InfoPgData));
InfoPgData infoPgData = {0};
MEM_CONTEXT_TEMP_BEGIN()
{
String *dbSection = strNew(INFO_SECTION_DB);
infoPgData.systemId = varUInt64Force(iniGet(infoPgIni, dbSection, strNew(INFO_KEY_DB_SYSTEM_ID)));
infoPgData.id = (unsigned int)varIntForce(iniGet(infoPgIni, dbSection, strNew(INFO_KEY_DB_ID)));
const Ini *infoPgIni = infoIni(this->info);
const String *pgHistorySection = strNew(INFO_SECTION_DB_HISTORY);
const StringList *pgHistoryKey = iniSectionKeyList(infoPgIni, pgHistorySection);
const Variant *idKey = varNewStr(strNew(INFO_KEY_DB_ID));
const Variant *systemIdKey = varNewStr(strNew(INFO_KEY_DB_SYSTEM_ID));
const Variant *versionKey = varNewStr(strNew(INFO_KEY_DB_VERSION));
String *pgVersion = varStrForce(iniGet(infoPgIni, dbSection, strNew(INFO_KEY_DB_VERSION)));
// History must include at least one item or the file is corrupt
ASSERT(strLstSize(pgHistoryKey) > 0);
// ??? Temporary hack for removing the leading and trailing quotes from pgVersion until can get json parser
infoPgData.version = infoPgVersionToUIntInternal(strSubN(pgVersion, 1, strSize(pgVersion) - 2));
if ((type == infoPgBackup) || (type == infoPgManifest))
// Iterate in reverse because we would like the most recent pg history to be in position 0. If we need to look at the
// history list at all we'll be iterating from newest to oldest and putting newest in position 0 makes for more natural
// looping.
for (unsigned int pgHistoryIdx = strLstSize(pgHistoryKey) - 1; pgHistoryIdx < strLstSize(pgHistoryKey); pgHistoryIdx--)
{
infoPgData.catalogVersion =
(unsigned int)varIntForce(iniGet(infoPgIni, dbSection, strNew(INFO_KEY_DB_CATALOG_VERSION)));
infoPgData.controlVersion =
(unsigned int)varIntForce(iniGet(infoPgIni, dbSection, strNew(INFO_KEY_DB_CONTROL_VERSION)));
// Load JSON data into a KeyValue
const KeyValue *pgDataKv = jsonToKv(
varStr(iniGet(infoPgIni, pgHistorySection, strLstGet(pgHistoryKey, pgHistoryIdx))));
// Get db values that are common to all info files
InfoPgData infoPgData =
{
.id = cvtZToUInt(strPtr(strLstGet(pgHistoryKey, pgHistoryIdx))),
.version = pgVersionFromStr(varStr(kvGet(pgDataKv, versionKey))),
// This is different in archive.info due to a typo that can't be fixed without a format version bump
.systemId = varUInt64Force(kvGet(pgDataKv, type == infoPgArchive ? idKey : systemIdKey)),
};
// Get values that are only in backup and manifest files. These are really vestigial since stanza-create verifies
// the control and catalog versions so there is no good reason to store them. However, for backward compatability
// we must write them at least, even if we give up reading them.
if (type == infoPgBackup || type == infoPgManifest)
{
const Variant *catalogVersionKey = varNewStr(strNew(INFO_KEY_DB_CATALOG_VERSION));
const Variant *controlVersionKey = varNewStr(strNew(INFO_KEY_DB_CONTROL_VERSION));
infoPgData.catalogVersion = (unsigned int)varUInt64Force(kvGet(pgDataKv, catalogVersionKey));
infoPgData.controlVersion = (unsigned int)varUInt64Force(kvGet(pgDataKv, controlVersionKey));
}
else if (type != infoPgArchive)
THROW_FMT(AssertError, "invalid InfoPg type %u", type);
infoPgAdd(this, &infoPgData);
}
else if (type != infoPgArchive)
THROW_FMT(AssertError, "invalid InfoPg type %u", type);
}
MEM_CONTEXT_TEMP_END();
infoPgAdd(this, &infoPgData);
}
MEM_CONTEXT_NEW_END();
@ -168,6 +149,40 @@ infoPgAdd(InfoPg *this, const InfoPgData *infoPgData)
FUNCTION_DEBUG_RESULT(UINT, this->indexCurrent);
}
/***********************************************************************************************************************************
Construct archive id
***********************************************************************************************************************************/
String *
infoPgArchiveId(const InfoPg *this, unsigned int pgDataIdx)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(INFO_PG, this);
FUNCTION_DEBUG_PARAM(UINT, pgDataIdx);
FUNCTION_DEBUG_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
InfoPgData pgData = infoPgData(this, pgDataIdx);
FUNCTION_DEBUG_RESULT(STRING, strNewFmt("%s-%u", strPtr(pgVersionToStr(pgData.version)), pgData.id));
}
/***********************************************************************************************************************************
Return a structure of the Postgres data from a specific index
***********************************************************************************************************************************/
InfoPgData
infoPgData(const InfoPg *this, unsigned int pgDataIdx)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(INFO_PG, this);
FUNCTION_DEBUG_PARAM(UINT, pgDataIdx);
FUNCTION_DEBUG_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
FUNCTION_DEBUG_RESULT(INFO_PG_DATA, *((InfoPgData *)lstGet(this->history, pgDataIdx)));
}
/***********************************************************************************************************************************
Return a structure of the current Postgres data
***********************************************************************************************************************************/
@ -180,20 +195,22 @@ infoPgDataCurrent(const InfoPg *this)
FUNCTION_DEBUG_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
FUNCTION_DEBUG_RESULT(INFO_PG_DATA, *((InfoPgData *)lstGet(this->history, this->indexCurrent)));
FUNCTION_DEBUG_RESULT(INFO_PG_DATA, infoPgData(this, this->indexCurrent));
}
/***********************************************************************************************************************************
Return a string representation of the PostgreSQL version
Return total Postgres data in the history
***********************************************************************************************************************************/
String *
infoPgVersionToString(unsigned int version)
unsigned int
infoPgDataTotal(const InfoPg *this)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(UINT, version);
FUNCTION_DEBUG_PARAM(INFO_PG, this);
FUNCTION_DEBUG_ASSERT(this != NULL);
FUNCTION_DEBUG_END();
FUNCTION_DEBUG_RESULT(STRING, strNewFmt("%u.%u", ((unsigned int)(version / 10000)), ((version % 10000) / 100)));
FUNCTION_DEBUG_RESULT(UINT, lstSize(this->history));
}
/***********************************************************************************************************************************

View File

@ -11,6 +11,8 @@ typedef struct InfoPg InfoPg;
#include <stdint.h>
#include "storage/storage.h"
/***********************************************************************************************************************************
Information about the PostgreSQL cluster
***********************************************************************************************************************************/
@ -36,7 +38,7 @@ typedef enum
/***********************************************************************************************************************************
Constructor
***********************************************************************************************************************************/
InfoPg *infoPgNew(const String *fileName, InfoPgType type);
InfoPg *infoPgNew(const Storage *storage, const String *fileName, InfoPgType type);
/***********************************************************************************************************************************
Functions
@ -46,8 +48,11 @@ unsigned int infoPgAdd(InfoPg *this, const InfoPgData *infoPgData);
/***********************************************************************************************************************************
Getters
***********************************************************************************************************************************/
String *infoPgArchiveId(const InfoPg *this, unsigned int pgDataIdx);
InfoPgData infoPgData(const InfoPg *this, unsigned int pgDataIdx);
InfoPgData infoPgDataCurrent(const InfoPg *this);
String *infoPgVersionToString(unsigned int version);
unsigned int infoPgDataTotal(const InfoPg *this);
/***********************************************************************************************************************************
Destructor

View File

@ -4,6 +4,8 @@ PostgreSQL Info
#include "common/debug.h"
#include "common/log.h"
#include "common/memContext.h"
#include "common/type/convert.h"
#include "common/regExp.h"
#include "postgres/info.h"
#include "postgres/type.h"
#include "postgres/version.h"
@ -62,6 +64,63 @@ pgVersionMap(uint32_t controlVersion, uint32_t catalogVersion)
FUNCTION_TEST_RESULT(UINT, result);
}
/***********************************************************************************************************************************
Convert version string to version number
***********************************************************************************************************************************/
unsigned int
pgVersionFromStr(const String *version)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(STRING, version);
FUNCTION_DEBUG_ASSERT(version != NULL);
FUNCTION_DEBUG_END();
unsigned int result = 0;
MEM_CONTEXT_TEMP_BEGIN()
{
// If format is not number.number (9.4) or number only (10) then error
if (!regExpMatchOne(strNew("^[0-9]+[.]*[0-9]+$"), version))
THROW_FMT(AssertError, "version %s format is invalid", strPtr(version));
// If there is a dot set the major and minor versions, else just the major
int idxStart = strChr(version, '.');
unsigned int major;
unsigned int minor = 0;
if (idxStart != -1)
{
major = cvtZToUInt(strPtr(strSubN(version, 0, (size_t)idxStart)));
minor = cvtZToUInt(strPtr(strSub(version, (size_t)idxStart + 1)));
}
else
major = cvtZToUInt(strPtr(version));
// No check to see if valid/supported PG version is on purpose
result = major * 10000 + minor * 100;
}
MEM_CONTEXT_TEMP_END();
FUNCTION_DEBUG_RESULT(UINT, result);
}
/***********************************************************************************************************************************
Convert version number to string
***********************************************************************************************************************************/
String *
pgVersionToStr(unsigned int version)
{
FUNCTION_DEBUG_BEGIN(logLevelTrace);
FUNCTION_DEBUG_PARAM(UINT, version);
FUNCTION_DEBUG_END();
String *result = version >= PG_VERSION_10 ?
strNewFmt("%u", version / 10000) : strNewFmt("%u.%u", version / 10000, version % 10000 / 100);
FUNCTION_DEBUG_RESULT(STRING, result);
}
/***********************************************************************************************************************************
Get info from pg_control
***********************************************************************************************************************************/

View File

@ -24,6 +24,8 @@ typedef struct PgControlInfo
Functions
***********************************************************************************************************************************/
PgControlInfo pgControlInfo(const String *pgPath);
unsigned int pgVersionFromStr(const String *version);
String *pgVersionToStr(unsigned int version);
/***********************************************************************************************************************************
Macros for function logging

View File

@ -334,7 +334,7 @@ unit:
test:
# ----------------------------------------------------------------------------------------------------------------------------
- name: info
total: 2
total: 3
coverage:
postgres/info: full
@ -557,7 +557,7 @@ unit:
# ----------------------------------------------------------------------------------------------------------------------------
- name: info-pg
total: 2
total: 1
coverage:
info/infoPg: full

View File

@ -16,12 +16,22 @@ testRun(void)
String *content = NULL;
String *fileName = strNewFmt("%s/test.ini", testPath());
TEST_ERROR_FMT(
infoArchiveNew(storageLocal(), fileName, true), FileMissingError,
"unable to open %s/test.ini or %s/test.ini.copy\n"
"HINT: archive.info does not exist but is required to push/get WAL segments.\n"
"HINT: is archive_command configured 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.",
testPath(), testPath());
//--------------------------------------------------------------------------------------------------------------------------
content = strNew
(
"[backrest]\n"
"backrest-checksum=\"b34b238ce89d8e1365c9e392ce59e7b03342ceb9\"\n"
"backrest-checksum=\"1efa53e0611604ad7d833c5547eb60ff716e758c\"\n"
"backrest-format=5\n"
"backrest-version=\"2.04dev\"\n"
"backrest-version=\"2.04\"\n"
"\n"
"[db]\n"
"db-id=1\n"
@ -37,8 +47,9 @@ testRun(void)
InfoArchive *info = NULL;
TEST_ASSIGN(info, infoArchiveNew(fileName, true), " new archive info");
TEST_ASSIGN(info, infoArchiveNew(storageLocal(), fileName, true), " new archive info");
TEST_RESULT_STR(strPtr(infoArchiveId(info)), "9.4-1", " archiveId set");
TEST_RESULT_PTR(infoArchivePg(info), info->infoPg, " infoPg set");
// Check PG version
//--------------------------------------------------------------------------------------------------------------------------

View File

@ -19,9 +19,9 @@ testRun(void)
content = strNew
(
"[backrest]\n"
"backrest-checksum=\"b34b238ce89d8e1365c9e392ce59e7b03342ceb9\"\n"
"backrest-checksum=\"1efa53e0611604ad7d833c5547eb60ff716e758c\"\n"
"backrest-format=5\n"
"backrest-version=\"2.04dev\"\n"
"backrest-version=\"2.04\"\n"
"\n"
"[db]\n"
"db-id=1\n"
@ -36,7 +36,7 @@ testRun(void)
InfoPg *infoPg = NULL;
TEST_ASSIGN(infoPg, infoPgNew(fileName, infoPgArchive), "new infoPg archive - load file");
TEST_ASSIGN(infoPg, infoPgNew(storageLocal(), fileName, infoPgArchive), "new infoPg archive - load file");
TEST_RESULT_INT(lstSize(infoPg->history), 1, " history record added");
TEST_RESULT_INT(infoPg->indexCurrent, 0, " current index set");
@ -47,17 +47,17 @@ testRun(void)
TEST_RESULT_INT(infoPgData.systemId, 6569239123849665679, " system-id set");
TEST_RESULT_INT(infoPgData.catalogVersion, 0, " catalog-version not set");
TEST_RESULT_INT(infoPgData.controlVersion, 0, " control-version not set");
TEST_RESULT_STR(strPtr(infoPgVersionToString(infoPgData.version)), "9.4", " version conversion back to string");
TEST_RESULT_INT(infoPgDataTotal(infoPg), 1, " check pg data total");
TEST_RESULT_STR(strPtr(infoPgArchiveId(infoPg, 0)), "9.4-1", " check pg archive id");
// Backup info
//--------------------------------------------------------------------------------------------------------------------------
content = strNew
(
"[backrest]\n"
"backrest-checksum=\"fc1d9ca71ebf1f5562f1fd21c4959233c9d04b18\"\n"
"backrest-checksum=\"5c17df9523543f5283efdc3c5aa7eb933c63ea0b\"\n"
"backrest-format=5\n"
"backrest-version=\"2.04dev\"\n"
"backrest-version=\"2.04\"\n"
"\n"
"[db]\n"
"db-catalog-version=201409291\n"
@ -68,12 +68,12 @@ testRun(void)
"\n"
"[db:history]\n"
"1={\"db-catalog-version\":201409291,\"db-control-version\":942,\"db-system-id\":6569239123849665679,"
"\"db-version\":\"9.4\"}\n"
"\"db-version\":\"9.4\"}\n"
);
TEST_RESULT_VOID(storagePutNP(storageNewWriteNP(storageLocalWrite(), fileName), bufNewStr(content)), "put info to file");
TEST_ASSIGN(infoPg, infoPgNew(fileName, infoPgBackup), "new infoPg backup - load file");
TEST_ASSIGN(infoPg, infoPgNew(storageLocal(), fileName, infoPgBackup), "new infoPg backup - load file");
TEST_RESULT_INT(lstSize(infoPg->history), 1, " history record added");
TEST_RESULT_INT(infoPg->indexCurrent, 0, " current index set");
@ -87,7 +87,7 @@ testRun(void)
// Manifest info
//--------------------------------------------------------------------------------------------------------------------------
TEST_ASSIGN(infoPg, infoPgNew(fileName, infoPgManifest), "new infoPg manifest - load file");
TEST_ASSIGN(infoPg, infoPgNew(storageLocal(), fileName, infoPgManifest), "new infoPg manifest - load file");
TEST_RESULT_INT(lstSize(infoPg->history), 1, "history record added");
TEST_RESULT_INT(infoPg->indexCurrent, 0, "current index set");
@ -117,8 +117,9 @@ testRun(void)
// Errors
//--------------------------------------------------------------------------------------------------------------------------
TEST_ERROR(infoPgNew(fileName, 10), AssertError, "invalid InfoPg type 10");
TEST_ERROR(infoPgNew(NULL, infoPgManifest), AssertError, "function debug assertion 'fileName != NULL' failed");
TEST_ERROR(infoPgNew(storageLocal(), fileName, 10), AssertError, "invalid InfoPg type 10");
TEST_ERROR(
infoPgNew(storageLocal(), NULL, infoPgManifest), AssertError, "function debug assertion 'fileName != NULL' failed");
TEST_ERROR(infoPgDataCurrent(NULL), AssertError, "function debug assertion 'this != NULL' failed");
@ -150,32 +151,4 @@ testRun(void)
"{\"id: 4294967295, version: 4294967295, systemId 18446744073709551615, catalog 4294967295, control 4294967295\"}",
" check max format");
}
// *****************************************************************************************************************************
if (testBegin("infoPgVersionToUIntInternal(), infoPgVersionToString()"))
{
String *version = NULL;
// infoPgVersionToUIntInternal
//--------------------------------------------------------------------------------------------------------------------------
version = strNew("10");
TEST_RESULT_INT(infoPgVersionToUIntInternal(version), PG_VERSION_10, "Valid pg version 10 integer identifier");
// Internal function - doesn't check for validity since requested not to
version = strNew("15");
TEST_RESULT_INT(infoPgVersionToUIntInternal(version), 150000, "version 15 is converted");
version = strNew("9.3.4");
TEST_ERROR(infoPgVersionToUIntInternal(version), AssertError, "version 9.3.4 format is invalid");
version = strNew("abc");
TEST_ERROR(infoPgVersionToUIntInternal(version), AssertError, "version abc format is invalid");
TEST_ERROR(infoPgVersionToUIntInternal(NULL), AssertError, "function debug assertion 'version != NULL' failed");
// infoPgVersionToString
//--------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_STR(strPtr(infoPgVersionToString(PG_VERSION_11)), "11.0", "infoPgVersionToString 11.0");
TEST_RESULT_STR(strPtr(infoPgVersionToString(PG_VERSION_96)), "9.6", "infoPgVersionToString 9.6");
TEST_RESULT_STR(strPtr(infoPgVersionToString(123456)), "12.34", "infoPgVersionToString 123456");
}
}

View File

@ -21,9 +21,9 @@ testRun(void)
content = strNew
(
"[backrest]\n"
"backrest-checksum=\"b34b238ce89d8e1365c9e392ce59e7b03342ceb9\"\n"
"backrest-checksum=\"1efa53e0611604ad7d833c5547eb60ff716e758c\"\n"
"backrest-format=5\n"
"backrest-version=\"2.04dev\"\n"
"backrest-version=\"2.04\"\n"
"\n"
"[db]\n"
"db-id=1\n"
@ -38,14 +38,14 @@ testRun(void)
//--------------------------------------------------------------------------------------------------------------------------
String *missingInfoError = strNewFmt("unable to open %s or %s", strPtr(fileName), strPtr(fileNameCopy));
TEST_ERROR(infoNew(fileName), FileMissingError, strPtr(missingInfoError));
TEST_ERROR(infoNew(storageLocal(), fileName), FileMissingError, strPtr(missingInfoError));
// Only copy exists and one is required
//--------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_VOID(
storagePutNP(storageNewWriteNP(storageLocalWrite(), fileNameCopy), bufNewStr(content)), "put info.copy to file");
TEST_ASSIGN(info, infoNew(fileName), "infoNew() - load copy file");
TEST_ASSIGN(info, infoNew(storageLocal(), fileName), "infoNew() - load copy file");
TEST_RESULT_STR(strPtr(infoFileName(info)), strPtr(fileName), " infoFileName() is set");
TEST_RESULT_PTR(infoIni(info), info->ini, " infoIni() returns pointer to info->ini");
@ -55,7 +55,7 @@ testRun(void)
storageMoveNP(storageNewReadNP(storageLocal(), fileNameCopy), storageNewWriteNP(storageLocalWrite(), fileName));
// Only main info exists and is required
TEST_ASSIGN(info, infoNew(fileName), "infoNew() - load file");
TEST_ASSIGN(info, infoNew(storageLocal(), fileName), "infoNew() - load file");
TEST_RESULT_STR(strPtr(infoFileName(info)), strPtr(fileName), " infoFileName() is set");
@ -66,9 +66,9 @@ testRun(void)
content = strNew
(
"[backrest]\n"
"backrest-checksum=\"3ad6cbfc41984548747c65498a5079be96a4e4ef\"\n"
"backrest-checksum=\"14617b089cb5c9b3224e739bb794e865b9bcdf4b\"\n"
"backrest-format=4\n"
"backrest-version=\"2.04dev\"\n"
"backrest-version=\"2.04\"\n"
"\n"
"[db]\n"
"db-catalog-version=201409291\n"
@ -86,7 +86,7 @@ testRun(void)
TEST_RESULT_VOID(
storagePutNP(storageNewWriteNP(storageLocalWrite(), fileName), bufNewStr(content)), "put invalid br format to file");
TEST_ERROR(infoNew(fileName), FileMissingError, strPtr(missingInfoError));
TEST_ERROR(infoNew(storageLocal(), fileName), FileMissingError, strPtr(missingInfoError));
harnessLogResult(
strPtr(
strNewFmt("P00 WARN: invalid format in '%s', expected %d but found %d", strPtr(fileName), PGBACKREST_FORMAT, 4)));
@ -94,7 +94,7 @@ testRun(void)
storageCopyNP(storageNewReadNP(storageLocal(), fileName), storageNewWriteNP(storageLocalWrite(), fileNameCopy));
TEST_ERROR(
infoNew(fileName), FormatError,
infoNew(storageLocal(), fileName), FormatError,
strPtr(strNewFmt("invalid format in '%s', expected %d but found %d", strPtr(fileName), PGBACKREST_FORMAT, 4)));
harnessLogResult(
strPtr(
@ -149,7 +149,7 @@ testRun(void)
// Copy file error
TEST_ERROR(
infoNew(fileName), ChecksumError,
infoNew(storageLocal(), fileName), ChecksumError,
strPtr(strNewFmt("invalid checksum in '%s', expected '%s' but found '%s'", strPtr(fileName),
"4306ec205f71417c301e403c4714090e61c8a736", "4306ec205f71417c301e403c4714090e61c8a999")));

View File

@ -44,6 +44,22 @@ testRun(void)
TEST_ERROR_FMT(pgVersionMap(1100, 0), VersionNotSupportedError, MAP_ERROR, 1100);
}
// *****************************************************************************************************************************
if (testBegin("pgVersionFromStr() and pgVersionToStr()"))
{
TEST_ERROR(pgVersionFromStr(strNew("9.3.4")), AssertError, "version 9.3.4 format is invalid");
TEST_ERROR(pgVersionFromStr(strNew("abc")), AssertError, "version abc format is invalid");
TEST_ERROR(pgVersionFromStr(NULL), AssertError, "function debug assertion 'version != NULL' failed");
TEST_RESULT_INT(pgVersionFromStr(strNew("10")), PG_VERSION_10, "valid pg version 10");
TEST_RESULT_INT(pgVersionFromStr(strNew("9.6")), 90600, "valid pg version 9.6");
//--------------------------------------------------------------------------------------------------------------------------
TEST_RESULT_STR(strPtr(pgVersionToStr(PG_VERSION_11)), "11", "infoPgVersionToString 11");
TEST_RESULT_STR(strPtr(pgVersionToStr(PG_VERSION_96)), "9.6", "infoPgVersionToString 9.6");
TEST_RESULT_STR(strPtr(pgVersionToStr(83456)), "8.34", "infoPgVersionToString 83456");
}
// -----------------------------------------------------------------------------------------------------------------------------
if (testBegin("pgControlInfo()"))
{