1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-07-03 00:26:59 +02:00

Migrate page checksum filter to C.

This filter exactly mimics the behavior of the Perl filter so is a drop-in replacement.

The filter is not integrated yet since it requires the Perl-to-C storage layer interface coming in a future commit.
This commit is contained in:
David Steele
2019-06-17 07:52:03 -04:00
parent 892f35a728
commit ceafd8e19d
10 changed files with 457 additions and 13 deletions

View File

@ -2,9 +2,30 @@
Test Common Functions and Definitions for Backup and Expire Commands
***********************************************************************************************************************************/
#include "common/harnessConfig.h"
#include "common/io/bufferWrite.h"
#include "common/regExp.h"
#include "common/type/json.h"
#include "postgres/interface.h"
#include "storage/posix/storage.h"
#include <common/regExp.h>
/***********************************************************************************************************************************
Need these structures to mock up test data
***********************************************************************************************************************************/
typedef struct
{
uint32_t walid; // high bits
uint32_t xrecoff; // low bits
} PageWalRecPtr;
typedef struct PageHeaderData
{
// LSN is member of *any* block, not only page-organized ones
PageWalRecPtr pd_lsn; // Lsn for last change to this page
uint16_t pd_checksum; // checksum
uint16_t pd_flags; // flag bits, see below
uint16_t pd_lower; // offset to start of free space
uint16_t pd_upper; // offset to end of free space
} PageHeaderData;
/***********************************************************************************************************************************
Test Run
@ -106,5 +127,132 @@ testRun(void)
TEST_RESULT_BOOL(regExpMatchOne(filter, full), false, " does not match full");
}
// *****************************************************************************************************************************
if (testBegin("PageChecksum"))
{
TEST_RESULT_UINT(PG_SEGMENT_PAGE_DEFAULT, 131072, "check pages per segment");
// Test pages with all zeros (these are considered valid)
// -------------------------------------------------------------------------------------------------------------------------
Buffer *buffer = bufNew(PG_PAGE_SIZE_DEFAULT * 3);
Buffer *bufferOut = bufNew(0);
bufUsedSet(buffer, bufSize(buffer));
memset(bufPtr(buffer), 0, bufSize(buffer));
IoWrite *write = ioWriteFilterGroupSet(
ioBufferWriteNew(bufferOut),
ioFilterGroupAdd(ioFilterGroupNew(), pageChecksumNew(0, PG_SEGMENT_PAGE_DEFAULT, PG_PAGE_SIZE_DEFAULT, 0)));
ioWriteOpen(write);
ioWrite(write, buffer);
ioWriteClose(write);
TEST_RESULT_STR(
strPtr(jsonFromVar(ioFilterGroupResult(ioWriteFilterGroup(write), PAGE_CHECKSUM_FILTER_TYPE_STR), 0)),
"{\"align\":true,\"valid\":true}", "all zero pages");
// Single checksum error
// -------------------------------------------------------------------------------------------------------------------------
buffer = bufNew(PG_PAGE_SIZE_DEFAULT * 1);
bufUsedSet(buffer, bufSize(buffer));
memset(bufPtr(buffer), 0, bufSize(buffer));
// Page 0 has bogus checksum
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x00)))->pd_upper = 0x01;
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x00)))->pd_lsn.walid = 0xF0F0F0F0;
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x00)))->pd_lsn.xrecoff = 0xF0F0F0F0;
write = ioWriteFilterGroupSet(
ioBufferWriteNew(bufferOut),
ioFilterGroupAdd(
ioFilterGroupNew(), pageChecksumNew(0, PG_SEGMENT_PAGE_DEFAULT, PG_PAGE_SIZE_DEFAULT, 0xFACEFACE00000000)));
ioWriteOpen(write);
ioWrite(write, buffer);
ioWriteClose(write);
TEST_RESULT_STR(
strPtr(jsonFromVar(ioFilterGroupResult(ioWriteFilterGroup(write), PAGE_CHECKSUM_FILTER_TYPE_STR), 0)),
"{\"align\":true,\"error\":[0],\"valid\":false}", "single checksum error");
// Various checksum errors some of which will be skipped because of the LSN
// -------------------------------------------------------------------------------------------------------------------------
buffer = bufNew(PG_PAGE_SIZE_DEFAULT * 8 - (PG_PAGE_SIZE_DEFAULT - 512));
bufUsedSet(buffer, bufSize(buffer));
memset(bufPtr(buffer), 0, bufSize(buffer));
// Page 0 has bogus checksum
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x00)))->pd_upper = 0x01;
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x00)))->pd_lsn.walid = 0xF0F0F0F0;
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x00)))->pd_lsn.xrecoff = 0xF0F0F0F0;
// Page 1 has bogus checksum but lsn above the limit
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x01)))->pd_upper = 0x01;
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x01)))->pd_lsn.walid = 0xFACEFACE;
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x01)))->pd_lsn.xrecoff = 0x00000000;
// Page 2 has bogus checksum
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x02)))->pd_upper = 0x01;
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x02)))->pd_lsn.xrecoff = 0x2;
// Page 3 has bogus checksum
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x03)))->pd_upper = 0x01;
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x03)))->pd_lsn.xrecoff = 0x3;
// Page 4 has bogus checksum
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x04)))->pd_upper = 0x01;
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x04)))->pd_lsn.xrecoff = 0x4;
// Page 6 has bogus checksum
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x06)))->pd_upper = 0x01;
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x06)))->pd_lsn.xrecoff = 0x6;
// Page 7 has bogus checksum (and is misaligned but large enough to test)
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x07)))->pd_upper = 0x01;
((PageHeaderData *)(bufPtr(buffer) + (PG_PAGE_SIZE_DEFAULT * 0x07)))->pd_lsn.xrecoff = 0x7;
write = ioWriteFilterGroupSet(
ioBufferWriteNew(bufferOut),
ioFilterGroupAdd(
ioFilterGroupNew(), pageChecksumNew(0, PG_SEGMENT_PAGE_DEFAULT, PG_PAGE_SIZE_DEFAULT, 0xFACEFACE00000000)));
ioWriteOpen(write);
ioWrite(write, buffer);
ioWriteClose(write);
TEST_RESULT_STR(
strPtr(jsonFromVar(ioFilterGroupResult(ioWriteFilterGroup(write), PAGE_CHECKSUM_FILTER_TYPE_STR), 0)),
"{\"align\":false,\"error\":[0,[2,4],[6,7]],\"valid\":false}", "various checksum errors");
// Impossibly misaligned page
// -------------------------------------------------------------------------------------------------------------------------
buffer = bufNew(256);
bufUsedSet(buffer, bufSize(buffer));
memset(bufPtr(buffer), 0, bufSize(buffer));
write = ioWriteFilterGroupSet(
ioBufferWriteNew(bufferOut),
ioFilterGroupAdd(
ioFilterGroupNew(), pageChecksumNew(0, PG_SEGMENT_PAGE_DEFAULT, PG_PAGE_SIZE_DEFAULT, 0xFACEFACE00000000)));
ioWriteOpen(write);
ioWrite(write, buffer);
ioWriteClose(write);
TEST_RESULT_STR(
strPtr(jsonFromVar(ioFilterGroupResult(ioWriteFilterGroup(write), PAGE_CHECKSUM_FILTER_TYPE_STR), 0)),
"{\"align\":false,\"valid\":false}", "misalignment");
// Two misaligned buffers in a row
// -------------------------------------------------------------------------------------------------------------------------
buffer = bufNew(513);
bufUsedSet(buffer, bufSize(buffer));
memset(bufPtr(buffer), 0, bufSize(buffer));
write = ioWriteFilterGroupSet(
ioBufferWriteNew(bufferOut),
ioFilterGroupAdd(
ioFilterGroupNew(), pageChecksumNew(0, PG_SEGMENT_PAGE_DEFAULT, PG_PAGE_SIZE_DEFAULT, 0xFACEFACE00000000)));
ioWriteOpen(write);
ioWrite(write, buffer);
TEST_ERROR(ioWrite(write, buffer), AssertError, "should not be possible to see two misaligned pages in a row");
}
FUNCTION_HARNESS_RESULT_VOID();
}