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:
parent
de1b74da0c
commit
960ad73298
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
***********************************************************************************************************************************/
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
***********************************************************************************************************************************/
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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")));
|
||||
|
||||
|
@ -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()"))
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user