Fix checksum validation for relations that have more than one segment.
A blkno argument passed to pg_checksum_page procedure should be not a relative block number in a given segment but an absolute block number in the entire relation. It's the same for the segment number 0, but for segment number N the difference is RELSEG_SIZE * N. Aleksander Alekseev
This commit is contained in:
parent
b163cdaa53
commit
052ed01129
@ -59,7 +59,7 @@ not require any manual adjustments of the Makefile.
|
|||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
Invocation:
|
Invocation:
|
||||||
|
|
||||||
pg_filedump [-abcdfhikxy] [-R startblock [endblock]] [-S blocksize] file
|
pg_filedump [-abcdfhikxy] [-R startblock [endblock]] [-S blocksize] [-s segsize] [-n segnumber] file
|
||||||
|
|
||||||
Defaults are: relative addressing, range of the entire file, block size
|
Defaults are: relative addressing, range of the entire file, block size
|
||||||
as listed on block 0 in the file
|
as listed on block 0 in the file
|
||||||
@ -80,6 +80,8 @@ The following options are valid for heap and index files:
|
|||||||
[startblock]: block to start at
|
[startblock]: block to start at
|
||||||
[endblock]: block to end at
|
[endblock]: block to end at
|
||||||
A startblock without an endblock will format the single block
|
A startblock without an endblock will format the single block
|
||||||
|
-s Force segment size to [segsize]
|
||||||
|
-n Force segment number to [segnumber]
|
||||||
-S Force block size to [blocksize]
|
-S Force block size to [blocksize]
|
||||||
-x Force interpreted formatting of block items as index items
|
-x Force interpreted formatting of block items as index items
|
||||||
-y Force interpreted formatting of block items as heap items
|
-y Force interpreted formatting of block items as heap items
|
||||||
|
105
pg_filedump.c
105
pg_filedump.c
@ -52,6 +52,12 @@ static unsigned int blockSize = 0;
|
|||||||
/* Current block in file */
|
/* Current block in file */
|
||||||
static unsigned int currentBlock = 0;
|
static unsigned int currentBlock = 0;
|
||||||
|
|
||||||
|
/* Segment size in bytes */
|
||||||
|
static unsigned int segmentSize = RELSEG_SIZE * BLCKSZ;
|
||||||
|
|
||||||
|
/* Number of current segment */
|
||||||
|
static unsigned int segmentNumber = 0;
|
||||||
|
|
||||||
/* Offset of current block */
|
/* Offset of current block */
|
||||||
static unsigned int pageOffset = 0;
|
static unsigned int pageOffset = 0;
|
||||||
|
|
||||||
@ -95,7 +101,7 @@ DisplayOptions(unsigned int validOptions)
|
|||||||
FD_VERSION, FD_PG_VERSION);
|
FD_VERSION, FD_PG_VERSION);
|
||||||
|
|
||||||
printf
|
printf
|
||||||
("\nUsage: pg_filedump [-abcdfhikxy] [-R startblock [endblock]] [-S blocksize] file\n\n"
|
("\nUsage: pg_filedump [-abcdfhikxy] [-R startblock [endblock]] [-S blocksize] [-s segsize] [-n segnumber] file\n\n"
|
||||||
"Display formatted contents of a PostgreSQL heap/index/control file\n"
|
"Display formatted contents of a PostgreSQL heap/index/control file\n"
|
||||||
"Defaults are: relative addressing, range of the entire file, block\n"
|
"Defaults are: relative addressing, range of the entire file, block\n"
|
||||||
" size as listed on block 0 in the file\n\n"
|
" size as listed on block 0 in the file\n\n"
|
||||||
@ -114,6 +120,8 @@ DisplayOptions(unsigned int validOptions)
|
|||||||
" indexed from 0)\n" " [startblock]: block to start at\n"
|
" indexed from 0)\n" " [startblock]: block to start at\n"
|
||||||
" [endblock]: block to end at\n"
|
" [endblock]: block to end at\n"
|
||||||
" A startblock without an endblock will format the single block\n"
|
" A startblock without an endblock will format the single block\n"
|
||||||
|
" -s Force segment size to [segsize]\n"
|
||||||
|
" -n Force segment number to [segnumber]\n"
|
||||||
" -S Force block size to [blocksize]\n"
|
" -S Force block size to [blocksize]\n"
|
||||||
" -x Force interpreted formatting of block items as index items\n"
|
" -x Force interpreted formatting of block items as index items\n"
|
||||||
" -y Force interpreted formatting of block items as heap items\n\n"
|
" -y Force interpreted formatting of block items as heap items\n\n"
|
||||||
@ -124,6 +132,31 @@ DisplayOptions(unsigned int validOptions)
|
|||||||
"\nReport bugs to <pgsql-bugs@postgresql.org>\n");
|
"\nReport bugs to <pgsql-bugs@postgresql.org>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine segment number by segment file name. For instance, if file
|
||||||
|
* name is /path/to/xxxx.7 procedure returns 7. Default return value is 0.
|
||||||
|
*/
|
||||||
|
static unsigned int
|
||||||
|
GetSegmentNumberFromFileName(const char* fileName)
|
||||||
|
{
|
||||||
|
int segnumOffset = strlen(fileName) - 1;
|
||||||
|
|
||||||
|
if(segnumOffset < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while(isdigit(fileName[segnumOffset]))
|
||||||
|
{
|
||||||
|
segnumOffset--;
|
||||||
|
if(segnumOffset < 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fileName[segnumOffset] != '.')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return atoi(&fileName[segnumOffset+1]);
|
||||||
|
}
|
||||||
|
|
||||||
/* Iterate through the provided options and set the option flags. */
|
/* Iterate through the provided options and set the option flags. */
|
||||||
/* An error will result in a positive rc and will force a display */
|
/* An error will result in a positive rc and will force a display */
|
||||||
/* of the usage information. This routine returns enum */
|
/* of the usage information. This routine returns enum */
|
||||||
@ -235,6 +268,69 @@ ConsumeOptions(int numOptions, char **options)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Check for the special case where the user forces a segment size. */
|
||||||
|
else if ((optionStringLength == 2)
|
||||||
|
&& (strcmp(optionString, "-s") == 0))
|
||||||
|
{
|
||||||
|
int localSegmentSize;
|
||||||
|
|
||||||
|
SET_OPTION(segmentOptions, SEGMENT_SIZE_FORCED, 's');
|
||||||
|
/* Only accept the forced size option once */
|
||||||
|
if (rc == OPT_RC_DUPLICATE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* The token immediately following -s is the segment size */
|
||||||
|
if (x >= (numOptions - 2))
|
||||||
|
{
|
||||||
|
rc = OPT_RC_INVALID;
|
||||||
|
printf("Error: Missing segment size identifier.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next option encountered must be forced segment size */
|
||||||
|
optionString = options[++x];
|
||||||
|
if ((localSegmentSize = GetOptionValue(optionString)) > 0)
|
||||||
|
segmentSize = (unsigned int) localSegmentSize;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = OPT_RC_INVALID;
|
||||||
|
printf("Error: Invalid segment size requested <%s>.\n",
|
||||||
|
optionString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Check for the special case where the user forces a segment number */
|
||||||
|
/* instead of having the tool determine it by file name. */
|
||||||
|
else if ((optionStringLength == 2)
|
||||||
|
&& (strcmp(optionString, "-n") == 0))
|
||||||
|
{
|
||||||
|
int localSegmentNumber;
|
||||||
|
|
||||||
|
SET_OPTION(segmentOptions, SEGMENT_NUMBER_FORCED, 'n');
|
||||||
|
/* Only accept the forced segment number option once */
|
||||||
|
if (rc == OPT_RC_DUPLICATE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* The token immediately following -n is the segment number */
|
||||||
|
if (x >= (numOptions - 2))
|
||||||
|
{
|
||||||
|
rc = OPT_RC_INVALID;
|
||||||
|
printf("Error: Missing segment number identifier.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next option encountered must be forced segment number */
|
||||||
|
optionString = options[++x];
|
||||||
|
if ((localSegmentNumber = GetOptionValue(optionString)) > 0)
|
||||||
|
segmentNumber = (unsigned int) localSegmentNumber;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = OPT_RC_INVALID;
|
||||||
|
printf("Error: Invalid segment number requested <%s>.\n",
|
||||||
|
optionString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* The last option MUST be the file name */
|
/* The last option MUST be the file name */
|
||||||
else if (x == (numOptions - 1))
|
else if (x == (numOptions - 1))
|
||||||
{
|
{
|
||||||
@ -243,7 +339,11 @@ ConsumeOptions(int numOptions, char **options)
|
|||||||
{
|
{
|
||||||
fp = fopen(optionString, "rb");
|
fp = fopen(optionString, "rb");
|
||||||
if (fp)
|
if (fp)
|
||||||
|
{
|
||||||
fileName = options[x];
|
fileName = options[x];
|
||||||
|
if(!(segmentOptions & SEGMENT_NUMBER_FORCED))
|
||||||
|
segmentNumber = GetSegmentNumberFromFileName(fileName);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rc = OPT_RC_FILE;
|
rc = OPT_RC_FILE;
|
||||||
@ -691,7 +791,8 @@ FormatHeader(Page page, BlockNumber blkno)
|
|||||||
|
|
||||||
if (blockOptions & BLOCK_CHECKSUMS)
|
if (blockOptions & BLOCK_CHECKSUMS)
|
||||||
{
|
{
|
||||||
uint16 calc_checksum = pg_checksum_page(page, blkno);
|
uint32 delta = (segmentSize/blockSize)*segmentNumber;
|
||||||
|
uint16 calc_checksum = pg_checksum_page(page, delta + blkno);
|
||||||
|
|
||||||
if (calc_checksum != pageHeader->pd_checksum)
|
if (calc_checksum != pageHeader->pd_checksum)
|
||||||
printf(" Error: checksum failure: calculated 0x%04x.\n\n",
|
printf(" Error: checksum failure: calculated 0x%04x.\n\n",
|
||||||
|
@ -55,6 +55,15 @@ typedef enum blockSwitches
|
|||||||
BLOCK_CHECKSUMS = 0x00000040 /* -k: verify block checksums */
|
BLOCK_CHECKSUMS = 0x00000040 /* -k: verify block checksums */
|
||||||
} blockSwitches;
|
} blockSwitches;
|
||||||
|
|
||||||
|
/* Segment-related options */
|
||||||
|
static unsigned int segmentOptions = 0;
|
||||||
|
|
||||||
|
typedef enum segmentSwitches
|
||||||
|
{
|
||||||
|
SEGMENT_SIZE_FORCED = 0x00000001, /* -s: Segment size forced */
|
||||||
|
SEGMENT_NUMBER_FORCED = 0x00000002, /* -n: Segment number forced */
|
||||||
|
} segmentSwitches;
|
||||||
|
|
||||||
/* -R[start]:Block range start */
|
/* -R[start]:Block range start */
|
||||||
static int blockStart = -1;
|
static int blockStart = -1;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user