aboutsummaryrefslogtreecommitdiff
path: root/src/bin/pg_combinebackup/load_manifest.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/pg_combinebackup/load_manifest.c')
-rw-r--r--src/bin/pg_combinebackup/load_manifest.c92
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);