PostgreSQL Source Code git master
Loading...
Searching...
No Matches
load_manifest.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * Load data from a backup manifest into memory.
4 *
5 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
7 *
8 * src/bin/pg_combinebackup/load_manifest.c
9 *
10 *-------------------------------------------------------------------------
11 */
12
13#include "postgres_fe.h"
14
15#include <sys/stat.h>
16#include <unistd.h>
17
19#include "common/logging.h"
21#include "load_manifest.h"
22
23/*
24 * For efficiency, we'd like our hash table containing information about the
25 * manifest to start out with approximately the correct number of entries.
26 * There's no way to know the exact number of entries without reading the whole
27 * file, but we can get an estimate by dividing the file size by the estimated
28 * number of bytes per line.
29 *
30 * This could be off by about a factor of two in either direction, because the
31 * checksum algorithm has a big impact on the line lengths; e.g. a SHA512
32 * checksum is 128 hex bytes, whereas a CRC-32C value is only 8, and there
33 * might be no checksum at all.
34 */
35#define ESTIMATED_BYTES_PER_MANIFEST_LINE 100
36
37/*
38 * size of json chunk to be read in
39 *
40 */
41#define READ_CHUNK_SIZE (128 * 1024)
42
43/*
44 * Define a hash table which we can use to store information about the files
45 * mentioned in the backup manifest.
46 */
47#define SH_PREFIX manifest_files
48#define SH_ELEMENT_TYPE manifest_file
49#define SH_KEY_TYPE const char *
50#define SH_KEY pathname
51#define SH_HASH_KEY(tb, key) hash_string(key)
52#define SH_EQUAL(tb, a, b) (strcmp(a, b) == 0)
53#define SH_SCOPE extern
54#define SH_RAW_ALLOCATOR pg_malloc0
55#define SH_DEFINE
56#include "lib/simplehash.h"
57
59 int manifest_version);
61 uint64 manifest_system_identifier);
63 const char *pathname, uint64 size,
64 pg_checksum_type checksum_type,
65 int checksum_length,
66 uint8 *checksum_payload);
68 TimeLineID tli,
69 XLogRecPtr start_lsn,
70 XLogRecPtr end_lsn);
72 const char *fmt, ...)
74
75/*
76 * Load backup_manifest files from an array of backups and produces an array
77 * of manifest_data objects.
78 *
79 * NB: Since load_backup_manifest() can return NULL, the resulting array could
80 * contain NULL entries.
81 */
94
95/*
96 * Parse the backup_manifest file in the named backup directory. Construct a
97 * hash table with information about all the files it mentions, and a linked
98 * list of all the WAL ranges it mentions.
99 *
100 * If the backup_manifest file simply doesn't exist, logs a warning and returns
101 * NULL. Any other error, or any error parsing the contents of the file, is
102 * fatal.
103 */
105load_backup_manifest(char *backup_directory)
106{
107 char pathname[MAXPGPATH];
108 int fd;
109 struct stat statbuf;
110 off_t estimate;
113 char *buffer;
116 size_t total_size;
117 const size_t chunk_size = READ_CHUNK_SIZE;
118
119 /* Open the manifest file. */
120 snprintf(pathname, MAXPGPATH, "%s/backup_manifest", backup_directory);
121 if ((fd = open(pathname, O_RDONLY | PG_BINARY, 0)) < 0)
122 {
123 if (errno == ENOENT)
124 {
125 pg_log_warning("file \"%s\" does not exist", pathname);
126 return NULL;
127 }
128 pg_fatal("could not open file \"%s\": %m", pathname);
129 }
130
131 /* Figure out how big the manifest is. */
132 if (fstat(fd, &statbuf) != 0)
133 pg_fatal("could not stat file \"%s\": %m", pathname);
134
135 /* Guess how large to make the hash table based on the manifest size. */
136 estimate = statbuf.st_size / ESTIMATED_BYTES_PER_MANIFEST_LINE;
137 initial_size = Min(PG_UINT32_MAX, Max(estimate, 256));
138
139 /* Create the hash table. */
141
143 result->files = ht;
144 context.private_data = result;
150
151 total_size = statbuf.st_size;
152
153 /*
154 * Parse the file, in chunks if necessary.
155 */
156 if (total_size <= chunk_size)
157 {
158 ssize_t rc;
159
160 buffer = pg_malloc(total_size);
161 rc = read(fd, buffer, total_size);
162 if (rc != total_size)
163 {
164 if (rc < 0)
165 pg_fatal("could not read file \"%s\": %m", pathname);
166 else
167 pg_fatal("could not read file \"%s\": read %zd of %zu",
168 pathname, rc, total_size);
169 }
170
171 /* Close the manifest file. */
172 close(fd);
173
174 /* Parse the manifest. */
175 json_parse_manifest(&context, buffer, total_size);
176 }
177 else
178 {
179 size_t bytes_left = total_size;
181
182 inc_state = json_parse_manifest_incremental_init(&context);
183
184 buffer = pg_malloc(chunk_size + 1);
185
186 while (bytes_left > 0)
187 {
188 ssize_t rc;
189 size_t bytes_to_read = chunk_size;
190
191 /*
192 * Make sure that the last chunk is sufficiently large. (i.e. at
193 * least half the chunk size) so that it will contain fully the
194 * piece at the end with the checksum.
195 */
196 if (bytes_left < chunk_size)
198 else if (bytes_left < 2 * chunk_size)
200 rc = read(fd, buffer, bytes_to_read);
201 if (rc != bytes_to_read)
202 {
203 if (rc < 0)
204 pg_fatal("could not read file \"%s\": %m", pathname);
205 else
206 pg_fatal("could not read file \"%s\": read %zu of %zu",
207 pathname,
208 total_size + rc - bytes_left,
209 total_size);
210 }
211 bytes_left -= rc;
212 json_parse_manifest_incremental_chunk(inc_state, buffer, rc, bytes_left == 0);
213 }
214
215 /* Release the incremental state memory */
217
218 close(fd);
219 }
220
221 /* All done. */
222 pg_free(buffer);
223 return result;
224}
225
226/*
227 * Report an error while parsing the manifest.
228 *
229 * We consider all such errors to be fatal errors. The manifest parser
230 * expects this function not to return.
231 */
232static void
234{
235 va_list ap;
236
237 va_start(ap, fmt);
239 va_end(ap);
240
241 exit(1);
242}
243
244/*
245 * This callback to validate the manifest version number for incremental backup.
246 */
247static void
249 int manifest_version)
250{
251 /* Incremental backups supported on manifest version 2 or later */
252 if (manifest_version == 1)
253 pg_fatal("backup manifest version 1 does not support incremental backup");
254}
255
256/*
257 * Record system identifier extracted from the backup manifest.
258 */
259static void
261 uint64 manifest_system_identifier)
262{
264
265 /* Validation will be at the later stage */
266 manifest->system_identifier = manifest_system_identifier;
267}
268
269/*
270 * Record details extracted from the backup manifest for one file.
271 */
272static void
274 const char *pathname, uint64 size,
275 pg_checksum_type checksum_type,
276 int checksum_length, uint8 *checksum_payload)
277{
279 manifest_file *m;
280 bool found;
281
282 /* Make a new entry in the hash table for this file. */
283 m = manifest_files_insert(manifest->files, pathname, &found);
284 if (found)
285 pg_fatal("duplicate path name in backup manifest: \"%s\"", pathname);
286
287 /* Initialize the entry. */
288 m->size = size;
289 m->checksum_type = checksum_type;
290 m->checksum_length = checksum_length;
291 m->checksum_payload = checksum_payload;
292}
293
294/*
295 * Record details extracted from the backup manifest for one WAL range.
296 */
297static void
299 TimeLineID tli,
300 XLogRecPtr start_lsn, XLogRecPtr end_lsn)
301{
304
305 /* Allocate and initialize a struct describing this WAL range. */
307 range->tli = tli;
308 range->start_lsn = start_lsn;
309 range->end_lsn = end_lsn;
310 range->prev = manifest->last_wal_range;
311 range->next = NULL;
312
313 /* Add it to the end of the list. */
314 if (manifest->first_wal_range == NULL)
315 manifest->first_wal_range = range;
316 else
317 manifest->last_wal_range->next = range;
318 manifest->last_wal_range = range;
319}
#define Min(x, y)
Definition c.h:1131
uint8_t uint8
Definition c.h:681
#define PG_UINT32_MAX
Definition c.h:733
#define pg_noreturn
Definition c.h:249
#define Max(x, y)
Definition c.h:1125
#define PG_BINARY
Definition c.h:1431
#define pg_attribute_printf(f, a)
Definition c.h:327
#define gettext(x)
Definition c.h:1308
uint64_t uint64
Definition c.h:684
uint32_t uint32
Definition c.h:683
uint32 result
pg_checksum_type
void * pg_malloc(size_t size)
Definition fe_memutils.c:53
void pg_free(void *ptr)
#define pg_malloc_array(type, count)
Definition fe_memutils.h:66
#define palloc_object(type)
Definition fe_memutils.h:89
#define pg_malloc0_object(type)
Definition fe_memutils.h:61
#define close(a)
Definition win32.h:12
#define read(a, b, c)
Definition win32.h:13
int i
Definition isn.c:77
#define ESTIMATED_BYTES_PER_MANIFEST_LINE
static pg_noreturn void manifest_data ** load_backup_manifests(int n_backups, char **backup_directories)
manifest_data * load_backup_manifest(char *backup_directory)
#define READ_CHUNK_SIZE
static void combinebackup_per_file_cb(JsonManifestParseContext *context, const char *pathname, uint64 size, pg_checksum_type checksum_type, int checksum_length, uint8 *checksum_payload)
static pg_noreturn void report_manifest_error(JsonManifestParseContext *context, const char *fmt,...) pg_attribute_printf(2
static void combinebackup_version_cb(JsonManifestParseContext *context, int manifest_version)
static void combinebackup_per_wal_range_cb(JsonManifestParseContext *context, TimeLineID tli, XLogRecPtr start_lsn, XLogRecPtr end_lsn)
static void combinebackup_system_identifier_cb(JsonManifestParseContext *context, uint64 manifest_system_identifier)
void pg_log_generic_v(enum pg_log_level level, enum pg_log_part part, const char *pg_restrict fmt, va_list ap)
Definition logging.c:233
@ PG_LOG_PRIMARY
Definition logging.h:67
@ PG_LOG_ERROR
Definition logging.h:43
void json_parse_manifest(JsonManifestParseContext *context, const char *buffer, size_t size)
JsonManifestParseIncrementalState * json_parse_manifest_incremental_init(JsonManifestParseContext *context)
void json_parse_manifest_incremental_shutdown(JsonManifestParseIncrementalState *incstate)
void json_parse_manifest_incremental_chunk(JsonManifestParseIncrementalState *incstate, const char *chunk, size_t size, bool is_last)
#define pg_fatal(...)
static bool manifest
static int64 total_size
#define MAXPGPATH
#define pg_log_warning(...)
Definition pgfnames.c:24
#define snprintf
Definition port.h:261
static int fd(const char *x, int i)
static int fb(int x)
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
json_manifest_per_wal_range_callback per_wal_range_cb
json_manifest_system_identifier_callback system_identifier_cb
json_manifest_error_callback error_cb
json_manifest_per_file_callback per_file_cb
json_manifest_version_callback version_cb
uint8 * checksum_payload
pg_checksum_type checksum_type
#define fstat
Definition win32_port.h:73
uint64 XLogRecPtr
Definition xlogdefs.h:21
uint32 TimeLineID
Definition xlogdefs.h:63