You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-07-05 00:28:52 +02:00
Migrate walIsPartial(), walIsSegment(), and walSegmentFind() from Perl to C.
Also refactor regular expression defines to make them more reusable.
This commit is contained in:
@ -38,6 +38,10 @@
|
|||||||
<release-item>
|
<release-item>
|
||||||
<p>Add helper for repository storage.</p>
|
<p>Add helper for repository storage.</p>
|
||||||
</release-item>
|
</release-item>
|
||||||
|
|
||||||
|
<release-item>
|
||||||
|
<p>Migrate <code>walIsPartial()</code>, <code>walIsSegment()</code>, and <code>walSegmentFind()</code> from Perl to C.</p>
|
||||||
|
</release-item>
|
||||||
</release-development-list>
|
</release-development-list>
|
||||||
</release-core-list>
|
</release-core-list>
|
||||||
</release>
|
</release>
|
||||||
|
@ -140,7 +140,7 @@ install: pgbackrest
|
|||||||
####################################################################################################################################
|
####################################################################################################################################
|
||||||
# Compile rules
|
# Compile rules
|
||||||
####################################################################################################################################
|
####################################################################################################################################
|
||||||
command/archive/common.o: command/archive/common.c command/archive/common.h common/assert.h 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 common/wait.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
|
command/archive/common.o: command/archive/common.c command/archive/common.h common/assert.h 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 common/wait.h postgres/version.h protocol/storage/helper.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 command/archive/common.c -o command/archive/common.o
|
$(CC) $(CFLAGS) -c command/archive/common.c -o command/archive/common.o
|
||||||
|
|
||||||
command/archive/get/get.o: command/archive/get/get.c command/archive/common.h command/command.h common/assert.h common/debug.h common/error.auto.h common/error.h common/fork.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.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 common/wait.h config/config.auto.h config/config.h config/define.auto.h config/define.h config/load.h perl/exec.h postgres/info.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
|
command/archive/get/get.o: command/archive/get/get.c command/archive/common.h command/command.h common/assert.h common/debug.h common/error.auto.h common/error.h common/fork.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.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 common/wait.h config/config.auto.h config/config.h config/define.auto.h config/define.h config/load.h perl/exec.h postgres/info.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
|
||||||
|
@ -10,8 +10,10 @@ Archive Push Command
|
|||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
#include "common/memContext.h"
|
#include "common/memContext.h"
|
||||||
|
#include "common/regExp.h"
|
||||||
#include "common/wait.h"
|
#include "common/wait.h"
|
||||||
#include "postgres/version.h"
|
#include "postgres/version.h"
|
||||||
|
#include "protocol/storage/helper.h"
|
||||||
#include "storage/helper.h"
|
#include "storage/helper.h"
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
@ -111,6 +113,102 @@ archiveAsyncStatus(ArchiveMode archiveMode, const String *walSegment, bool confe
|
|||||||
FUNCTION_DEBUG_RESULT(BOOL, result);
|
FUNCTION_DEBUG_RESULT(BOOL, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Is the segment partial?
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
bool
|
||||||
|
walIsPartial(const String *walSegment)
|
||||||
|
{
|
||||||
|
FUNCTION_DEBUG_BEGIN(logLevelTrace);
|
||||||
|
FUNCTION_DEBUG_PARAM(STRING, walSegment);
|
||||||
|
|
||||||
|
FUNCTION_DEBUG_ASSERT(walSegment != NULL);
|
||||||
|
FUNCTION_DEBUG_ASSERT(walIsSegment(walSegment));
|
||||||
|
FUNCTION_DEBUG_END();
|
||||||
|
|
||||||
|
FUNCTION_DEBUG_RESULT(BOOL, strEndsWithZ(walSegment, WAL_SEGMENT_PARTIAL_EXT));
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Is the file a segment or some other file (e.g. .history, .backup, etc)
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
bool
|
||||||
|
walIsSegment(const String *walSegment)
|
||||||
|
{
|
||||||
|
FUNCTION_DEBUG_BEGIN(logLevelTrace);
|
||||||
|
FUNCTION_DEBUG_PARAM(STRING, walSegment);
|
||||||
|
|
||||||
|
FUNCTION_DEBUG_ASSERT(walSegment != NULL);
|
||||||
|
FUNCTION_DEBUG_END();
|
||||||
|
|
||||||
|
// Create the regular expression to identify WAL segments if it does not already exist
|
||||||
|
static RegExp *regExpSegment = NULL;
|
||||||
|
|
||||||
|
if (regExpSegment == NULL)
|
||||||
|
{
|
||||||
|
MEM_CONTEXT_BEGIN(memContextTop())
|
||||||
|
{
|
||||||
|
regExpSegment = regExpNew(strNew(WAL_SEGMENT_PARTIAL_REGEXP));
|
||||||
|
}
|
||||||
|
MEM_CONTEXT_END();
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION_DEBUG_RESULT(BOOL, regExpMatch(regExpSegment, walSegment));
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Find a WAL segment in the repository
|
||||||
|
|
||||||
|
The file name can have several things appended such as a hash, compression extension, and partial extension so it is possible to
|
||||||
|
have multiple files that match the segment, though more than one match is not a good thing.
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
String *
|
||||||
|
walSegmentFind(const Storage *storage, const String *archiveId, const String *walSegment)
|
||||||
|
{
|
||||||
|
FUNCTION_DEBUG_BEGIN(logLevelDebug);
|
||||||
|
FUNCTION_DEBUG_PARAM(STORAGE, storage);
|
||||||
|
FUNCTION_DEBUG_PARAM(STRING, archiveId);
|
||||||
|
FUNCTION_DEBUG_PARAM(STRING, walSegment);
|
||||||
|
|
||||||
|
FUNCTION_DEBUG_ASSERT(storage != NULL);
|
||||||
|
FUNCTION_DEBUG_ASSERT(archiveId != NULL);
|
||||||
|
FUNCTION_DEBUG_ASSERT(walSegment != NULL);
|
||||||
|
FUNCTION_DEBUG_ASSERT(walIsSegment(walSegment));
|
||||||
|
FUNCTION_DEBUG_END();
|
||||||
|
|
||||||
|
String *result = NULL;
|
||||||
|
|
||||||
|
MEM_CONTEXT_TEMP_BEGIN()
|
||||||
|
{
|
||||||
|
// Get a list of all WAL segments that match
|
||||||
|
StringList *list = storageListP(
|
||||||
|
storage, strNewFmt(STORAGE_REPO_ARCHIVE "/%s/%s", strPtr(archiveId), strPtr(strSubN(walSegment, 0, 16))),
|
||||||
|
.expression = strNewFmt("^%s%s-[0-f]{40}(\\.gz){0,1}$", strPtr(strSubN(walSegment, 0, 24)),
|
||||||
|
walIsPartial(walSegment) ? WAL_SEGMENT_PARTIAL_EXT : ""));
|
||||||
|
|
||||||
|
// If there are results
|
||||||
|
if (list != NULL && strLstSize(list) > 0)
|
||||||
|
{
|
||||||
|
// Error if there is more than one match
|
||||||
|
if (strLstSize(list) > 1)
|
||||||
|
{
|
||||||
|
THROW_FMT(
|
||||||
|
ArchiveDuplicateError,
|
||||||
|
"duplicates found in archive for WAL segment %s: %s\n"
|
||||||
|
"HINT: are multiple primaries archiving to this stanza?",
|
||||||
|
strPtr(walSegment), strPtr(strLstJoin(strLstSort(list, sortOrderAsc), ", ")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy file name of WAL segment found into the calling context
|
||||||
|
memContextSwitch(MEM_CONTEXT_OLD());
|
||||||
|
result = strDup(strLstGet(list, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MEM_CONTEXT_TEMP_END();
|
||||||
|
|
||||||
|
FUNCTION_DEBUG_RESULT(STRING, result);
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Get the next WAL segment given a WAL segment and WAL segment size
|
Get the next WAL segment given a WAL segment and WAL segment size
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
|
@ -18,12 +18,22 @@ typedef enum
|
|||||||
} ArchiveMode;
|
} ArchiveMode;
|
||||||
|
|
||||||
#include "common/type/stringList.h"
|
#include "common/type/stringList.h"
|
||||||
|
#include "storage/storage.h"
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
WAL segment constants
|
WAL segment constants
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
// Only match on a WAL segment without checksum appended
|
// Extension for partial segments
|
||||||
#define WAL_SEGMENT_REGEXP "^[0-F]{24}$"
|
#define WAL_SEGMENT_PARTIAL_EXT ".partial"
|
||||||
|
|
||||||
|
// Match when the first 24 characters match a WAL segment
|
||||||
|
#define WAL_SEGMENT_PREFIX_REGEXP "^[0-F]{24}"
|
||||||
|
|
||||||
|
// Match on a WAL segment without checksum appended
|
||||||
|
#define WAL_SEGMENT_REGEXP WAL_SEGMENT_PREFIX_REGEXP "$"
|
||||||
|
|
||||||
|
// Match on a WAL segment with partial allowed
|
||||||
|
#define WAL_SEGMENT_PARTIAL_REGEXP WAL_SEGMENT_PREFIX_REGEXP "(\\.partial){0,1}$"
|
||||||
|
|
||||||
// Defines the size of standard WAL segment name -- this should never changed
|
// Defines the size of standard WAL segment name -- this should never changed
|
||||||
#define WAL_SEGMENT_NAME_SIZE ((unsigned int)24)
|
#define WAL_SEGMENT_NAME_SIZE ((unsigned int)24)
|
||||||
@ -36,6 +46,9 @@ Functions
|
|||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
bool archiveAsyncStatus(ArchiveMode archiveMode, const String *walSegment, bool confessOnError);
|
bool archiveAsyncStatus(ArchiveMode archiveMode, const String *walSegment, bool confessOnError);
|
||||||
|
|
||||||
|
bool walIsPartial(const String *walSegment);
|
||||||
|
bool walIsSegment(const String *walSegment);
|
||||||
|
String *walSegmentFind(const Storage *storage, const String *archiveId, const String *walSegment);
|
||||||
String *walSegmentNext(const String *walSegment, size_t walSegmentSize, unsigned int pgVersion);
|
String *walSegmentNext(const String *walSegment, size_t walSegmentSize, unsigned int pgVersion);
|
||||||
StringList *walSegmentRange(const String *walSegmentBegin, size_t walSegmentSize, unsigned int pgVersion, unsigned int range);
|
StringList *walSegmentRange(const String *walSegmentBegin, size_t walSegmentSize, unsigned int pgVersion, unsigned int range);
|
||||||
|
|
||||||
|
@ -593,7 +593,7 @@ unit:
|
|||||||
test:
|
test:
|
||||||
# ----------------------------------------------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------------------------------------------
|
||||||
- name: common
|
- name: common
|
||||||
total: 3
|
total: 6
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
command/archive/common: full
|
command/archive/common: full
|
||||||
|
@ -5,6 +5,8 @@ Test Archive Common
|
|||||||
|
|
||||||
#include "common/harnessConfig.h"
|
#include "common/harnessConfig.h"
|
||||||
|
|
||||||
|
#include "protocol/storage/helper.h"
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Test Run
|
Test Run
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
@ -13,6 +15,9 @@ testRun(void)
|
|||||||
{
|
{
|
||||||
FUNCTION_HARNESS_VOID();
|
FUNCTION_HARNESS_VOID();
|
||||||
|
|
||||||
|
// Create default storage object for testing
|
||||||
|
Storage *storageTest = storageNewP(strNew(testPath()), .write = true);
|
||||||
|
|
||||||
// *****************************************************************************************************************************
|
// *****************************************************************************************************************************
|
||||||
if (testBegin("archiveAsyncStatus()"))
|
if (testBegin("archiveAsyncStatus()"))
|
||||||
{
|
{
|
||||||
@ -98,6 +103,62 @@ testRun(void)
|
|||||||
unlink(strPtr(storagePathNP(storageSpool(), strNewFmt(STORAGE_SPOOL_ARCHIVE_OUT "/%s.error", strPtr(segment)))));
|
unlink(strPtr(storagePathNP(storageSpool(), strNewFmt(STORAGE_SPOOL_ARCHIVE_OUT "/%s.error", strPtr(segment)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// *****************************************************************************************************************************
|
||||||
|
if (testBegin("walIsPartial()"))
|
||||||
|
{
|
||||||
|
TEST_RESULT_BOOL(walIsPartial(strNew("000000010000000100000001")), false, "not partial");
|
||||||
|
TEST_RESULT_BOOL(walIsPartial(strNew("FFFFFFFFFFFFFFFFFFFFFFFF.partial")), true, "partial");
|
||||||
|
}
|
||||||
|
|
||||||
|
// *****************************************************************************************************************************
|
||||||
|
if (testBegin("walIsSegment()"))
|
||||||
|
{
|
||||||
|
TEST_RESULT_BOOL(walIsSegment(strNew("000000010000000100000001")), true, "wal segment");
|
||||||
|
TEST_RESULT_BOOL(walIsSegment(strNew("FFFFFFFFFFFFFFFFFFFFFFFF.partial")), true, "partial wal segment");
|
||||||
|
TEST_RESULT_BOOL(walIsSegment(strNew("0000001A.history")), false, "history file");
|
||||||
|
}
|
||||||
|
|
||||||
|
// *****************************************************************************************************************************
|
||||||
|
if (testBegin("walSegmentFind()"))
|
||||||
|
{
|
||||||
|
// Load configuration to set repo-path and stanza
|
||||||
|
StringList *argList = strLstNew();
|
||||||
|
strLstAddZ(argList, "pgbackrest");
|
||||||
|
strLstAddZ(argList, "--stanza=db");
|
||||||
|
strLstAdd(argList, strNewFmt("--repo-path=%s", testPath()));
|
||||||
|
strLstAddZ(argList, "archive-get");
|
||||||
|
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
|
||||||
|
|
||||||
|
TEST_RESULT_PTR(walSegmentFind(storageRepo(), strNew("9.6-2"), strNew("123456781234567812345678")), NULL, "no path");
|
||||||
|
|
||||||
|
storagePathCreateNP(storageTest, strNew("archive/db/9.6-2/1234567812345678"));
|
||||||
|
TEST_RESULT_PTR(walSegmentFind(storageRepo(), strNew("9.6-2"), strNew("123456781234567812345678")), NULL, "no segment");
|
||||||
|
|
||||||
|
storagePutNP(
|
||||||
|
storageNewWriteNP(
|
||||||
|
storageTest,
|
||||||
|
strNew("archive/db/9.6-2/1234567812345678/123456781234567812345678-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
TEST_RESULT_STR(
|
||||||
|
strPtr(walSegmentFind(storageRepo(), strNew("9.6-2"), strNew("123456781234567812345678"))),
|
||||||
|
"123456781234567812345678-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "found segment");
|
||||||
|
|
||||||
|
storagePutNP(
|
||||||
|
storageNewWriteNP(
|
||||||
|
storageTest,
|
||||||
|
strNew("archive/db/9.6-2/1234567812345678/123456781234567812345678-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.gz")),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
TEST_ERROR(
|
||||||
|
walSegmentFind(storageRepo(), strNew("9.6-2"), strNew("123456781234567812345678")),
|
||||||
|
ArchiveDuplicateError,
|
||||||
|
"duplicates found in archive for WAL segment 123456781234567812345678:"
|
||||||
|
" 123456781234567812345678-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||||
|
", 123456781234567812345678-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.gz"
|
||||||
|
"\nHINT: are multiple primaries archiving to this stanza?");
|
||||||
|
}
|
||||||
|
|
||||||
// *****************************************************************************************************************************
|
// *****************************************************************************************************************************
|
||||||
if (testBegin("walSegmentNext()"))
|
if (testBegin("walSegmentNext()"))
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user