pg_verifybackup: Refactor parse_manifest_file.

Return a pointer to the manifest_data instead of individual pointers
to relevant data stored within the manifest_data object. The previous
approach scales poorly if we add more things to the backup manifest,
as has been proposed.

Amul Sul, reviewed by Sravan Velagandula, Michael Paquier, and me.

Discussion: http://postgr.es/m/CAAJ_b95=1LONf99-M_ep588fL_WgLJfdnb7XG4GWE7JDD22E4w@mail.gmail.com
This commit is contained in:
Robert Haas 2024-03-04 14:42:17 -05:00
parent dd7ea37c43
commit dc8f2d7c06
1 changed files with 34 additions and 41 deletions

View File

@ -94,31 +94,28 @@ typedef struct manifest_wal_range
} manifest_wal_range;
/*
* Details we need in callbacks that occur while parsing a backup manifest.
* All the data parsed from a backup_manifest file.
*/
typedef struct parser_context
typedef struct manifest_data
{
manifest_files_hash *ht;
manifest_files_hash *files;
manifest_wal_range *first_wal_range;
manifest_wal_range *last_wal_range;
} parser_context;
} manifest_data;
/*
* All of the context information we need while checking a backup manifest.
*/
typedef struct verifier_context
{
manifest_files_hash *ht;
manifest_data *manifest;
char *backup_directory;
SimpleStringList ignore_list;
bool exit_on_error;
bool saw_any_error;
} verifier_context;
static void parse_manifest_file(char *manifest_path,
manifest_files_hash **ht_p,
manifest_wal_range **first_wal_range_p);
static manifest_data *parse_manifest_file(char *manifest_path);
static void verifybackup_per_file_cb(JsonManifestParseContext *context,
char *pathname, size_t size,
pg_checksum_type checksum_type,
@ -142,8 +139,7 @@ static void verify_file_checksum(verifier_context *context,
manifest_file *m, char *fullpath);
static void parse_required_wal(verifier_context *context,
char *pg_waldump_path,
char *wal_directory,
manifest_wal_range *first_wal_range);
char *wal_directory);
static void report_backup_error(verifier_context *context,
const char *pg_restrict fmt,...)
@ -185,7 +181,6 @@ main(int argc, char **argv)
int c;
verifier_context context;
manifest_wal_range *first_wal_range;
char *manifest_path = NULL;
bool no_parse_wal = false;
bool quiet = false;
@ -338,7 +333,7 @@ main(int argc, char **argv)
* the manifest as fatal; there doesn't seem to be much point in trying to
* verify the backup directory against a corrupted manifest.
*/
parse_manifest_file(manifest_path, &context.ht, &first_wal_range);
context.manifest = parse_manifest_file(manifest_path);
/*
* Now scan the files in the backup directory. At this stage, we verify
@ -367,8 +362,7 @@ main(int argc, char **argv)
* not to do so.
*/
if (!no_parse_wal)
parse_required_wal(&context, pg_waldump_path,
wal_directory, first_wal_range);
parse_required_wal(&context, pg_waldump_path, wal_directory);
/*
* If everything looks OK, tell the user this, unless we were asked to
@ -385,9 +379,8 @@ main(int argc, char **argv)
* all the files it mentions, and a linked list of all the WAL ranges it
* mentions.
*/
static void
parse_manifest_file(char *manifest_path, manifest_files_hash **ht_p,
manifest_wal_range **first_wal_range_p)
static manifest_data *
parse_manifest_file(char *manifest_path)
{
int fd;
struct stat statbuf;
@ -396,8 +389,8 @@ parse_manifest_file(char *manifest_path, manifest_files_hash **ht_p,
manifest_files_hash *ht;
char *buffer;
int rc;
parser_context private_context;
JsonManifestParseContext context;
manifest_data *result;
/* Open the manifest file. */
if ((fd = open(manifest_path, O_RDONLY | PG_BINARY, 0)) < 0)
@ -436,10 +429,9 @@ parse_manifest_file(char *manifest_path, manifest_files_hash **ht_p,
close(fd);
/* Parse the manifest. */
private_context.ht = ht;
private_context.first_wal_range = NULL;
private_context.last_wal_range = NULL;
context.private_data = &private_context;
result = pg_malloc0(sizeof(manifest_data));
result->files = ht;
context.private_data = result;
context.per_file_cb = verifybackup_per_file_cb;
context.per_wal_range_cb = verifybackup_per_wal_range_cb;
context.error_cb = report_manifest_error;
@ -448,9 +440,7 @@ parse_manifest_file(char *manifest_path, manifest_files_hash **ht_p,
/* Done with the buffer. */
pfree(buffer);
/* Return the file hash table and WAL range list we constructed. */
*ht_p = ht;
*first_wal_range_p = private_context.first_wal_range;
return result;
}
/*
@ -480,8 +470,8 @@ verifybackup_per_file_cb(JsonManifestParseContext *context,
pg_checksum_type checksum_type,
int checksum_length, uint8 *checksum_payload)
{
parser_context *pcxt = context->private_data;
manifest_files_hash *ht = pcxt->ht;
manifest_data *manifest = context->private_data;
manifest_files_hash *ht = manifest->files;
manifest_file *m;
bool found;
@ -508,7 +498,7 @@ verifybackup_per_wal_range_cb(JsonManifestParseContext *context,
TimeLineID tli,
XLogRecPtr start_lsn, XLogRecPtr end_lsn)
{
parser_context *pcxt = context->private_data;
manifest_data *manifest = context->private_data;
manifest_wal_range *range;
/* Allocate and initialize a struct describing this WAL range. */
@ -516,15 +506,15 @@ verifybackup_per_wal_range_cb(JsonManifestParseContext *context,
range->tli = tli;
range->start_lsn = start_lsn;
range->end_lsn = end_lsn;
range->prev = pcxt->last_wal_range;
range->prev = manifest->last_wal_range;
range->next = NULL;
/* Add it to the end of the list. */
if (pcxt->first_wal_range == NULL)
pcxt->first_wal_range = range;
if (manifest->first_wal_range == NULL)
manifest->first_wal_range = range;
else
pcxt->last_wal_range->next = range;
pcxt->last_wal_range = range;
manifest->last_wal_range->next = range;
manifest->last_wal_range = range;
}
/*
@ -639,7 +629,7 @@ verify_backup_file(verifier_context *context, char *relpath, char *fullpath)
}
/* Check whether there's an entry in the manifest hash. */
m = manifest_files_lookup(context->ht, relpath);
m = manifest_files_lookup(context->manifest->files, relpath);
if (m == NULL)
{
report_backup_error(context,
@ -679,11 +669,12 @@ verify_backup_file(verifier_context *context, char *relpath, char *fullpath)
static void
report_extra_backup_files(verifier_context *context)
{
manifest_data *manifest = context->manifest;
manifest_files_iterator it;
manifest_file *m;
manifest_files_start_iterate(context->ht, &it);
while ((m = manifest_files_iterate(context->ht, &it)) != NULL)
manifest_files_start_iterate(manifest->files, &it);
while ((m = manifest_files_iterate(manifest->files, &it)) != NULL)
if (!m->matched && !should_ignore_relpath(context, m->pathname))
report_backup_error(context,
"\"%s\" is present in the manifest but not on disk",
@ -698,13 +689,14 @@ report_extra_backup_files(verifier_context *context)
static void
verify_backup_checksums(verifier_context *context)
{
manifest_data *manifest = context->manifest;
manifest_files_iterator it;
manifest_file *m;
progress_report(false);
manifest_files_start_iterate(context->ht, &it);
while ((m = manifest_files_iterate(context->ht, &it)) != NULL)
manifest_files_start_iterate(manifest->files, &it);
while ((m = manifest_files_iterate(manifest->files, &it)) != NULL)
{
if (should_verify_checksum(m) &&
!should_ignore_relpath(context, m->pathname))
@ -833,9 +825,10 @@ verify_file_checksum(verifier_context *context, manifest_file *m,
*/
static void
parse_required_wal(verifier_context *context, char *pg_waldump_path,
char *wal_directory, manifest_wal_range *first_wal_range)
char *wal_directory)
{
manifest_wal_range *this_wal_range = first_wal_range;
manifest_data *manifest = context->manifest;
manifest_wal_range *this_wal_range = manifest->first_wal_range;
while (this_wal_range != NULL)
{