Skip to content

Commit d9fbced

Browse files
committed
[Issue #228] fix merge
1 parent cb70503 commit d9fbced

File tree

5 files changed

+79
-23
lines changed

5 files changed

+79
-23
lines changed

src/backup.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2161,7 +2161,7 @@ backup_files(void *arg)
21612161
arguments->nodeInfo->checksum_version,
21622162
arguments->nodeInfo->ptrack_version_num,
21632163
arguments->nodeInfo->ptrack_schema,
2164-
arguments->hdr_map, true);
2164+
arguments->hdr_map, false);
21652165
}
21662166
else
21672167
{

src/catalog.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,9 +474,11 @@ catalog_get_backup_list(const char *instance_name, time_t requested_backup_id)
474474
backup->database_dir = pgut_malloc(MAXPGPATH);
475475
join_path_components(backup->database_dir, backup->root_dir, DATABASE_DIR);
476476

477-
/* block header map */
477+
/* block header map, TODO: move to separate function */
478478
backup->hdr_map.path = pgut_malloc(MAXPGPATH);
479479
join_path_components(backup->hdr_map.path, backup->database_dir, HEADER_MAP);
480+
backup->hdr_map.path_tmp = pgut_malloc(MAXPGPATH);
481+
join_path_components(backup->hdr_map.path_tmp, backup->database_dir, HEADER_MAP_TMP);
480482
backup->hdr_map.fp = NULL;
481483

482484
/* TODO: save encoded backup id */
@@ -855,6 +857,8 @@ pgBackupCreateDir(pgBackup *backup)
855857
/* block header map */
856858
backup->hdr_map.path = pgut_malloc(MAXPGPATH);
857859
join_path_components(backup->hdr_map.path, backup->database_dir, HEADER_MAP);
860+
backup->hdr_map.path_tmp = pgut_malloc(MAXPGPATH);
861+
join_path_components(backup->hdr_map.path_tmp, backup->database_dir, HEADER_MAP_TMP);
858862
backup->hdr_map.fp = NULL;
859863

860864
/* create directories for actual backup files */
@@ -2282,6 +2286,7 @@ pgBackupInit(pgBackup *backup)
22822286
backup->content_crc = 0;
22832287

22842288
backup->hdr_map.path = NULL;
2289+
backup->hdr_map.path_tmp = NULL;
22852290
backup->hdr_map.fp = NULL;
22862291
backup->hdr_map.mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
22872292
}
@@ -2298,6 +2303,7 @@ pgBackupFree(void *backup)
22982303
pg_free(b->database_dir);
22992304
pg_free(b->note);
23002305
pg_free(b->hdr_map.path);
2306+
pg_free(b->hdr_map.path_tmp);
23012307
pg_free(backup);
23022308
}
23032309

src/data.c

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ typedef struct DataPage
3131
char data[BLCKSZ];
3232
} DataPage;
3333

34-
static BackupPageHeader2* get_data_file_headers(HeaderMap *hdr_map, pgFile *file, uint32 backup_version);
35-
static void write_page_headers(BackupPageHeader2 *headers, pgFile *file, HeaderMap *hdr_map);
3634
static bool get_compressed_page_meta(FILE *in, const char *fullpath, BackupPageHeader* bph,
3735
pg_crc32 *crc, bool use_crc32c);
3836

@@ -538,7 +536,7 @@ backup_data_file(ConnectionArgs* conn_arg, pgFile *file,
538536
XLogRecPtr prev_backup_start_lsn, BackupMode backup_mode,
539537
CompressAlg calg, int clevel, uint32 checksum_version,
540538
int ptrack_version_num, const char *ptrack_schema,
541-
HeaderMap *hdr_map, bool missing_ok)
539+
HeaderMap *hdr_map, bool is_merge)
542540
{
543541
int rc;
544542
bool use_pagemap;
@@ -629,7 +627,7 @@ backup_data_file(ConnectionArgs* conn_arg, pgFile *file,
629627
/* check for errors */
630628
if (rc == FILE_MISSING)
631629
{
632-
elog(LOG, "File \"%s\" is not found", from_fullpath);
630+
elog(is_merge ? ERROR : LOG, "File not found: \"%s\"", from_fullpath);
633631
file->write_size = FILE_NOT_FOUND;
634632
goto cleanup;
635633
}
@@ -685,7 +683,7 @@ backup_data_file(ConnectionArgs* conn_arg, pgFile *file,
685683
FIN_FILE_CRC32(true, file->crc);
686684

687685
/* dump page headers */
688-
write_page_headers(headers, file, hdr_map);
686+
write_page_headers(headers, file, hdr_map, is_merge);
689687

690688
pg_free(errmsg);
691689
pg_free(file->pagemap.bitmap);
@@ -818,8 +816,12 @@ restore_data_file(parray *parent_chain, pgFile *dest_file, FILE *out,
818816
/* set stdio buffering for input data file */
819817
setvbuf(in, in_buf, _IOFBF, STDIO_BUFSIZE);
820818

819+
// elog(INFO, "N_HEADERS: %i", tmp_file->n_headers);
820+
// elog(INFO, "File: %s", tmp_file->rel_path);
821+
// elog(INFO, "Backup: %s", base36enc(backup->start_time));
822+
821823
/* get headers for this file */
822-
if (use_headers)
824+
if (use_headers && tmp_file->n_headers > 0)
823825
headers = get_data_file_headers(&(backup->hdr_map), tmp_file,
824826
parse_program_version(backup->program_version));
825827

@@ -2163,8 +2165,8 @@ get_data_file_headers(HeaderMap *hdr_map, pgFile *file, uint32 backup_version)
21632165
FIN_FILE_CRC32(true, hdr_crc);
21642166

21652167
if (hdr_crc != file->hdr_crc)
2166-
elog(ERROR, "Header file crc mismatch \"%s\", current: %u, expected: %u",
2167-
hdr_map->path, hdr_crc, file->hdr_crc);
2168+
elog(ERROR, "Header map for file \"%s\" crc mismatch \"%s\" offset: %lu, len: %lu, current: %u, expected: %u",
2169+
file->rel_path, hdr_map->path, file->hdr_off, read_len, hdr_crc, file->hdr_crc);
21682170

21692171
if (fclose(in))
21702172
elog(ERROR, "Cannot close header file \"%s\": %s", hdr_map->path, strerror(errno));
@@ -2173,29 +2175,35 @@ get_data_file_headers(HeaderMap *hdr_map, pgFile *file, uint32 backup_version)
21732175
}
21742176

21752177
void
2176-
write_page_headers(BackupPageHeader2 *headers, pgFile *file, HeaderMap *hdr_map)
2178+
write_page_headers(BackupPageHeader2 *headers, pgFile *file, HeaderMap *hdr_map, bool is_merge)
21772179
{
2178-
size_t read_len = 0;
2180+
size_t read_len = 0;
2181+
char *map_path = NULL;
21792182

21802183
if (file->n_headers <= 0)
21812184
return;
21822185

2186+
/* when running merge we must save headers into the temp map */
2187+
map_path = (is_merge) ? hdr_map->path_tmp : hdr_map->path;
2188+
21832189
/* writing to header map must be serialized */
21842190
pthread_lock(&(hdr_map->mutex)); /* what if we crash while trying to obtain mutex? */
21852191

21862192
if (!hdr_map->fp)
21872193
{
2188-
hdr_map->fp = fopen(hdr_map->path, PG_BINARY_W);
2194+
elog(LOG, "Creating page header map \"%s\"", map_path);
2195+
2196+
hdr_map->fp = fopen(map_path, PG_BINARY_W);
21892197
if (hdr_map->fp == NULL)
21902198
elog(ERROR, "Cannot open header file \"%s\": %s",
2191-
hdr_map->path, strerror(errno));
2199+
map_path, strerror(errno));
21922200

21932201
/* disable buffering for header file */
21942202
setvbuf(hdr_map->fp, NULL, _IONBF, BUFSIZ);
21952203

21962204
/* update file permission */
2197-
if (chmod(hdr_map->path, FILE_PERMISSION) == -1)
2198-
elog(ERROR, "Cannot change mode of \"%s\": %s", hdr_map->path,
2205+
if (chmod(map_path, FILE_PERMISSION) == -1)
2206+
elog(ERROR, "Cannot change mode of \"%s\": %s", map_path,
21992207
strerror(errno));
22002208

22012209
file->hdr_off = 0;
@@ -2211,7 +2219,10 @@ write_page_headers(BackupPageHeader2 *headers, pgFile *file, HeaderMap *hdr_map)
22112219
FIN_FILE_CRC32(true, file->hdr_crc);
22122220

22132221
if (fwrite(headers, 1, read_len, hdr_map->fp) != read_len)
2214-
elog(ERROR, "Cannot write to file \"%s\": %s", hdr_map->path, strerror(errno));
2222+
elog(ERROR, "Cannot write to file \"%s\": %s", map_path, strerror(errno));
2223+
2224+
elog(VERBOSE, "Writing header map for file \"%s\" offset: %lu, len: %lu, crc: %u",
2225+
file->rel_path, file->hdr_off, read_len, file->hdr_crc);
22152226

22162227
pthread_mutex_unlock(&(hdr_map->mutex));
22172228
}

src/merge.c

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -550,11 +550,11 @@ merge_chain(parray *parent_chain, pgBackup *full_backup, pgBackup *dest_backup)
550550
elog(INFO, "Validate parent chain for backup %s",
551551
base36enc(dest_backup->start_time));
552552

553-
/* forbid merge retry for failed merges between 2.4.0 and any
553+
/* Forbid merge retry for failed merges between 2.4.0 and any
554554
* older version. Several format changes makes it impossible
555555
* to determine the exact format any speific file is got.
556556
*/
557-
if (full_backup->status == BACKUP_STATUS_MERGING &&
557+
if (is_retry &&
558558
parse_program_version(dest_backup->program_version) >= 20400 &&
559559
parse_program_version(full_backup->program_version) < 20400)
560560
{
@@ -705,6 +705,23 @@ merge_chain(parray *parent_chain, pgBackup *full_backup, pgBackup *dest_backup)
705705
elog(ERROR, "Backup files merging failed, time elapsed: %s",
706706
pretty_time);
707707

708+
/* If temp header map descriptor is open, then close it and make rename */
709+
if (full_backup->hdr_map.fp)
710+
{
711+
if (fclose(full_backup->hdr_map.fp))
712+
elog(ERROR, "Cannot close file \"%s\"", full_backup->hdr_map.path);
713+
714+
/* sync new header map to dist */
715+
if (fio_sync(full_backup->hdr_map.path_tmp, FIO_BACKUP_HOST) != 0)
716+
elog(ERROR, "Cannot sync temp header map \"%s\": %s",
717+
full_backup->hdr_map.path_tmp, strerror(errno));
718+
719+
/* Replace old header map with new one */
720+
if (rename(full_backup->hdr_map.path_tmp, full_backup->hdr_map.path) == -1)
721+
elog(ERROR, "Could not rename file \"%s\" to \"%s\": %s",
722+
full_backup->hdr_map.path_tmp, full_backup->hdr_map.path, strerror(errno));
723+
}
724+
708725
/*
709726
* Update FULL backup metadata.
710727
* We cannot set backup status to OK just yet,
@@ -847,6 +864,12 @@ merge_chain(parray *parent_chain, pgBackup *full_backup, pgBackup *dest_backup)
847864
full_backup->root_dir = pgut_strdup(destination_path);
848865
}
849866

867+
/* Reinit some path variables */
868+
join_path_components(full_backup->database_dir, full_backup->root_dir, DATABASE_DIR);
869+
join_path_components(full_backup->hdr_map.path, full_backup->database_dir, HEADER_MAP);
870+
join_path_components(full_backup->hdr_map.path_tmp, full_backup->database_dir, HEADER_MAP_TMP);
871+
full_backup->hdr_map.fp = NULL;
872+
850873
/* If we crash here, it will produce full backup in MERGED
851874
* status, located in directory with wrong backup id.
852875
* It should not be a problem.
@@ -1033,6 +1056,7 @@ merge_files(void *arg)
10331056
if (file &&
10341057
file->n_blocks == dest_file->n_blocks)
10351058
{
1059+
BackupPageHeader2 *headers = NULL;
10361060

10371061
elog(VERBOSE, "The file didn`t changed since FULL backup, skip merge: \"%s\"",
10381062
file->rel_path);
@@ -1052,6 +1076,18 @@ merge_files(void *arg)
10521076
else
10531077
tmp_file->uncompressed_size = tmp_file->write_size;
10541078

1079+
/* Copy header metadata from old map into a new one */
1080+
tmp_file->n_headers = file->n_headers;
1081+
headers = get_data_file_headers(&(arguments->full_backup->hdr_map), file,
1082+
parse_program_version(arguments->full_backup->program_version));
1083+
1084+
/* sanity */
1085+
if (!headers && file->n_headers > 0)
1086+
elog(ERROR, "Failed to get headers for file \"%s\"", file->rel_path);
1087+
1088+
write_page_headers(headers, tmp_file, &(arguments->full_backup->hdr_map), true);
1089+
pg_free(headers);
1090+
10551091
//TODO: report in_place merge bytes.
10561092
goto done;
10571093
}
@@ -1205,16 +1241,14 @@ merge_data_file(parray *parent_chain, pgBackup *full_backup,
12051241
* 16KB.
12061242
* TODO: maybe we should just trust dest_file->n_blocks?
12071243
* No, we can`t, because current binary can be used to merge
1208-
* 2 backups of old versions, were n_blocks is missing.
1244+
* 2 backups of old versions, where n_blocks is missing.
12091245
*/
12101246

12111247
backup_data_file(NULL, tmp_file, to_fullpath_tmp1, to_fullpath_tmp2,
12121248
InvalidXLogRecPtr, BACKUP_MODE_FULL,
12131249
dest_backup->compress_alg, dest_backup->compress_level,
12141250
dest_backup->checksum_version, 0, NULL,
1215-
1216-
/* TODO: add header map */
1217-
NULL, false);
1251+
&(full_backup->hdr_map), true);
12181252

12191253
/* drop restored temp file */
12201254
if (unlink(to_fullpath_tmp1) == -1)

src/pg_probackup.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ extern const char *PROGRAM_EMAIL;
6767
#define EXTERNAL_DIR "external_directories/externaldir"
6868
#define DATABASE_MAP "database_map"
6969
#define HEADER_MAP "block_header_map"
70+
#define HEADER_MAP_TMP "block_header_map_tmp"
7071

7172
/* Timeout defaults */
7273
#define ARCHIVE_TIMEOUT_DEFAULT 300
@@ -363,6 +364,7 @@ typedef struct PGNodeInfo
363364
typedef struct HeaderMap
364365
{
365366
char *path;
367+
char *path_tmp; /* used only in merge */
366368
FILE *fp;
367369
off_t offset;
368370
pthread_mutex_t mutex;
@@ -1014,6 +1016,9 @@ extern pid_t check_postmaster(const char *pgdata);
10141016

10151017
extern bool validate_file_pages(pgFile *file, const char *fullpath, XLogRecPtr stop_lsn,
10161018
uint32 checksum_version, uint32 backup_version, HeaderMap *hdr_map);
1019+
1020+
extern BackupPageHeader2* get_data_file_headers(HeaderMap *hdr_map, pgFile *file, uint32 backup_version);
1021+
extern void write_page_headers(BackupPageHeader2 *headers, pgFile *file, HeaderMap *hdr_map, bool is_merge);
10171022
/* parsexlog.c */
10181023
extern bool extractPageMap(const char *archivedir, uint32 wal_seg_size,
10191024
XLogRecPtr startpoint, TimeLineID start_tli,

0 commit comments

Comments
 (0)