diff options
Diffstat (limited to 'src/bin/pg_combinebackup/load_manifest.c')
-rw-r--r-- | src/bin/pg_combinebackup/load_manifest.c | 92 |
1 files changed, 70 insertions, 22 deletions
diff --git a/src/bin/pg_combinebackup/load_manifest.c b/src/bin/pg_combinebackup/load_manifest.c index 7bc10fbe108..58677e5e3e7 100644 --- a/src/bin/pg_combinebackup/load_manifest.c +++ b/src/bin/pg_combinebackup/load_manifest.c @@ -35,6 +35,12 @@ #define ESTIMATED_BYTES_PER_MANIFEST_LINE 100 /* + * size of json chunk to be read in + * + */ +#define READ_CHUNK_SIZE (128 * 1024) + +/* * Define a hash table which we can use to store information about the files * mentioned in the backup manifest. */ @@ -109,6 +115,7 @@ load_backup_manifest(char *backup_directory) int rc; JsonManifestParseContext context; manifest_data *result; + int chunk_size = READ_CHUNK_SIZE; /* Open the manifest file. */ snprintf(pathname, MAXPGPATH, "%s/backup_manifest", backup_directory); @@ -133,27 +140,6 @@ load_backup_manifest(char *backup_directory) /* Create the hash table. */ ht = manifest_files_create(initial_size, NULL); - /* - * Slurp in the whole file. - * - * This is not ideal, but there's currently no way to get pg_parse_json() - * to perform incremental parsing. - */ - buffer = pg_malloc(statbuf.st_size); - rc = read(fd, buffer, statbuf.st_size); - if (rc != statbuf.st_size) - { - if (rc < 0) - pg_fatal("could not read file \"%s\": %m", pathname); - else - pg_fatal("could not read file \"%s\": read %d of %lld", - pathname, rc, (long long int) statbuf.st_size); - } - - /* Close the manifest file. */ - close(fd); - - /* Parse the manifest. */ result = pg_malloc0(sizeof(manifest_data)); result->files = ht; context.private_data = result; @@ -162,7 +148,69 @@ load_backup_manifest(char *backup_directory) context.per_file_cb = combinebackup_per_file_cb; context.per_wal_range_cb = combinebackup_per_wal_range_cb; context.error_cb = report_manifest_error; - json_parse_manifest(&context, buffer, statbuf.st_size); + + /* + * Parse the file, in chunks if necessary. + */ + if (statbuf.st_size <= chunk_size) + { + buffer = pg_malloc(statbuf.st_size); + rc = read(fd, buffer, statbuf.st_size); + if (rc != statbuf.st_size) + { + if (rc < 0) + pg_fatal("could not read file \"%s\": %m", pathname); + else + pg_fatal("could not read file \"%s\": read %d of %lld", + pathname, rc, (long long int) statbuf.st_size); + } + + /* Close the manifest file. */ + close(fd); + + /* Parse the manifest. */ + json_parse_manifest(&context, buffer, statbuf.st_size); + } + else + { + int bytes_left = statbuf.st_size; + JsonManifestParseIncrementalState *inc_state; + + inc_state = json_parse_manifest_incremental_init(&context); + + buffer = pg_malloc(chunk_size + 1); + + while (bytes_left > 0) + { + int bytes_to_read = chunk_size; + + /* + * Make sure that the last chunk is sufficiently large. (i.e. at + * least half the chunk size) so that it will contain fully the + * piece at the end with the checksum. + */ + if (bytes_left < chunk_size) + bytes_to_read = bytes_left; + else if (bytes_left < 2 * chunk_size) + bytes_to_read = bytes_left / 2; + rc = read(fd, buffer, bytes_to_read); + if (rc != bytes_to_read) + { + if (rc < 0) + pg_fatal("could not read file \"%s\": %m", pathname); + else + pg_fatal("could not read file \"%s\": read %lld of %lld", + pathname, + (long long int) (statbuf.st_size + rc - bytes_left), + (long long int) statbuf.st_size); + } + bytes_left -= rc; + json_parse_manifest_incremental_chunk( + inc_state, buffer, rc, bytes_left == 0); + } + + close(fd); + } /* All done. */ pfree(buffer); |