Skip to content

Commit 7f983c5

Browse files
committed
[Issue #169] Restore optimization
1 parent c6e7490 commit 7f983c5

File tree

3 files changed

+653
-13
lines changed

3 files changed

+653
-13
lines changed

src/data.c

+188-1
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,7 @@ restore_data_file(const char *to_path, pgFile *file, bool allow_truncate,
757757
}
758758

759759
/*
760-
* Open backup file for write. We use "r+" at first to overwrite only
760+
* Open backup file for write. We use "r+" at first to overwrite only
761761
* modified pages for differential restore. If the file does not exist,
762762
* re-open it with "w" to create an empty file.
763763
*/
@@ -961,6 +961,193 @@ restore_data_file(const char *to_path, pgFile *file, bool allow_truncate,
961961
fclose(in);
962962
}
963963

964+
/*
965+
* Restore files in the from_root directory to the to_root directory with
966+
* same relative path.
967+
*
968+
* If write_header is true then we add header to each restored block, currently
969+
* it is used for MERGE command.
970+
*
971+
* to_fullpath and from_fullpath are provided strictly for ERROR reporting
972+
*/
973+
void
974+
restore_data_file_new(FILE *in, FILE *out, pgFile *file, uint32 backup_version,
975+
const char *from_fullpath, const char *to_fullpath, int nblocks)
976+
{
977+
BackupPageHeader header;
978+
BlockNumber blknum = 0;
979+
size_t write_len = 0;
980+
981+
while (true)
982+
{
983+
off_t write_pos;
984+
size_t read_len;
985+
DataPage compressed_page; /* used as read buffer */
986+
DataPage page;
987+
int32 uncompressed_size = 0;
988+
989+
/* read BackupPageHeader */
990+
read_len = fread(&header, 1, sizeof(header), in);
991+
992+
if (read_len != sizeof(header))
993+
{
994+
int errno_tmp = errno;
995+
if (read_len == 0 && feof(in))
996+
break; /* EOF found */
997+
else if (read_len != 0 && feof(in))
998+
elog(ERROR, "Odd size page found at block %u of \"%s\"",
999+
blknum, from_fullpath);
1000+
else
1001+
elog(ERROR, "Cannot read header of block %u of \"%s\": %s",
1002+
blknum, from_fullpath, strerror(errno_tmp));
1003+
}
1004+
1005+
/* Consider empty block */
1006+
if (header.block == 0 && header.compressed_size == 0)
1007+
{
1008+
elog(VERBOSE, "Skip empty block of \"%s\"", from_fullpath);
1009+
continue;
1010+
}
1011+
1012+
/* sanity? */
1013+
if (header.block < blknum)
1014+
elog(ERROR, "Backup is broken at block %u of \"%s\"",
1015+
blknum, from_fullpath);
1016+
1017+
blknum = header.block;
1018+
1019+
/* no point in writing redundant data */
1020+
if (nblocks > 0 && blknum >= nblocks)
1021+
return;
1022+
1023+
if (header.compressed_size > BLCKSZ)
1024+
elog(ERROR, "Size of a blknum %i exceed BLCKSZ", blknum);
1025+
1026+
/* read a page from file */
1027+
read_len = fread(compressed_page.data, 1,
1028+
MAXALIGN(header.compressed_size), in);
1029+
1030+
if (read_len != MAXALIGN(header.compressed_size))
1031+
elog(ERROR, "Cannot read block %u of \"%s\", read %zu of %d",
1032+
blknum, from_fullpath, read_len, header.compressed_size);
1033+
1034+
/*
1035+
* if page size is smaller than BLCKSZ, decompress the page.
1036+
* BUGFIX for versions < 2.0.23: if page size is equal to BLCKSZ.
1037+
* we have to check, whether it is compressed or not using
1038+
* page_may_be_compressed() function.
1039+
*/
1040+
if (header.compressed_size != BLCKSZ
1041+
|| page_may_be_compressed(compressed_page.data, file->compress_alg,
1042+
backup_version))
1043+
{
1044+
const char *errormsg = NULL;
1045+
1046+
uncompressed_size = do_decompress(page.data, BLCKSZ,
1047+
compressed_page.data,
1048+
header.compressed_size,
1049+
file->compress_alg, &errormsg);
1050+
1051+
if (uncompressed_size < 0 && errormsg != NULL)
1052+
elog(WARNING, "An error occured during decompressing block %u of file \"%s\": %s",
1053+
blknum, from_fullpath, errormsg);
1054+
1055+
if (uncompressed_size != BLCKSZ)
1056+
elog(ERROR, "Page of file \"%s\" uncompressed to %d bytes. != BLCKSZ",
1057+
from_fullpath, uncompressed_size);
1058+
}
1059+
1060+
write_pos = blknum * BLCKSZ;
1061+
1062+
/*
1063+
* Seek and write the restored page.
1064+
* TODO: invent fio_pwrite().
1065+
*/
1066+
if (fio_fseek(out, write_pos) < 0)
1067+
elog(ERROR, "Cannot seek block %u of \"%s\": %s",
1068+
blknum, to_fullpath, strerror(errno));
1069+
1070+
/* if we uncompressed the page - write page.data,
1071+
* if page wasn't compressed -
1072+
* write what we've read - compressed_page.data
1073+
*/
1074+
if (uncompressed_size == BLCKSZ)
1075+
{
1076+
if (fio_fwrite(out, page.data, BLCKSZ) != BLCKSZ)
1077+
elog(ERROR, "Cannot write block %u of \"%s\": %s",
1078+
blknum, to_fullpath, strerror(errno));
1079+
}
1080+
else
1081+
{
1082+
if (fio_fwrite(out, compressed_page.data, BLCKSZ) != BLCKSZ)
1083+
elog(ERROR, "Cannot write block %u of \"%s\": %s",
1084+
blknum, to_fullpath, strerror(errno));
1085+
}
1086+
1087+
write_len += BLCKSZ;
1088+
}
1089+
1090+
elog(VERBOSE, "Copied file \"%s\": %lu bytes", from_fullpath, write_len);
1091+
}
1092+
1093+
/*
1094+
* Copy file to backup.
1095+
* We do not apply compression to these files, because
1096+
* it is either small control file or already compressed cfs file.
1097+
*/
1098+
void
1099+
restore_non_data_file(FILE *in, FILE *out, pgFile *file,
1100+
const char *from_fullpath, const char *to_fullpath)
1101+
{
1102+
size_t read_len = 0;
1103+
int errno_tmp;
1104+
char buf[BLCKSZ];
1105+
1106+
/* copy content */
1107+
for (;;)
1108+
{
1109+
read_len = 0;
1110+
1111+
if ((read_len = fio_fread(in, buf, sizeof(buf))) != sizeof(buf))
1112+
break;
1113+
1114+
if (fio_fwrite(out, buf, read_len) != read_len)
1115+
{
1116+
errno_tmp = errno;
1117+
/* oops */
1118+
fio_fclose(in);
1119+
fio_fclose(out);
1120+
elog(ERROR, "Cannot write to \"%s\": %s", to_fullpath,
1121+
strerror(errno_tmp));
1122+
}
1123+
}
1124+
1125+
errno_tmp = errno;
1126+
if (read_len < 0)
1127+
{
1128+
fio_fclose(in);
1129+
fio_fclose(out);
1130+
elog(ERROR, "Cannot read backup mode file \"%s\": %s",
1131+
from_fullpath, strerror(errno_tmp));
1132+
}
1133+
1134+
/* copy odd part. */
1135+
if (read_len > 0)
1136+
{
1137+
if (fio_fwrite(out, buf, read_len) != read_len)
1138+
{
1139+
errno_tmp = errno;
1140+
/* oops */
1141+
fio_fclose(in);
1142+
fio_fclose(out);
1143+
elog(ERROR, "Cannot write to \"%s\": %s", to_fullpath,
1144+
strerror(errno_tmp));
1145+
}
1146+
}
1147+
1148+
elog(VERBOSE, "Copied file \"%s\": %lu bytes", from_fullpath, file->write_size);
1149+
}
1150+
9641151
/*
9651152
* Copy file to backup.
9661153
* We do not apply compression to these files, because

src/pg_probackup.h

+6
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,8 @@ struct pgBackup
372372
* in the format suitable for recovery.conf */
373373
char *external_dir_str; /* List of external directories,
374374
* separated by ':' */
375+
parray *files; /* list of files belonging to this backup
376+
* must be populated by calling backup_populate() */
375377
};
376378

377379
/* Recovery target for restore and validate subcommands */
@@ -835,6 +837,10 @@ extern void restore_data_file(const char *to_path,
835837
pgFile *file, bool allow_truncate,
836838
bool write_header,
837839
uint32 backup_version);
840+
extern void restore_data_file_new(FILE *in, FILE *out, pgFile *file, uint32 backup_version,
841+
const char *from_fullpath, const char *to_fullpath, int nblocks);
842+
extern void restore_non_data_file(FILE *in, FILE *out, pgFile *file,
843+
const char *from_fullpath, const char *to_fullpath);
838844
extern bool copy_file(fio_location from_location, const char *to_root,
839845
fio_location to_location, pgFile *file, bool missing_ok);
840846
extern bool create_empty_file(fio_location from_location, const char *to_root,

0 commit comments

Comments
 (0)