Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit f8ad8c2

Browse files
committed
draft
1 parent 5190d57 commit f8ad8c2

File tree

6 files changed

+315
-35
lines changed

6 files changed

+315
-35
lines changed

contrib/pg_probackup/backup.c

Lines changed: 142 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,6 +1109,27 @@ backup_cleanup(bool fatal, void *userdata)
11091109
}
11101110
}
11111111

1112+
/*
1113+
* Count bytes in file
1114+
*/
1115+
static long
1116+
file_size(const char *file)
1117+
{
1118+
long r;
1119+
FILE *f = fopen(file, "r");
1120+
1121+
if (!f)
1122+
{
1123+
fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1124+
progname, file, strerror(errno));
1125+
return -1;
1126+
}
1127+
fseek(f, 0, SEEK_END);
1128+
r = ftell(f);
1129+
fclose(f);
1130+
return r;
1131+
}
1132+
11121133
/*
11131134
* Take differential backup at page level.
11141135
*/
@@ -1117,7 +1138,6 @@ backup_files(void *arg)
11171138
{
11181139
int i;
11191140
struct timeval tv;
1120-
11211141
backup_files_args *arguments = (backup_files_args *) arg;
11221142

11231143
gettimeofday(&tv, NULL);
@@ -1221,39 +1241,56 @@ backup_files(void *arg)
12211241
}
12221242
else
12231243
{
1224-
/* Check if the file is a cfs relation's segment */
1244+
/* Check first if the file is a cfs relation's segment */
12251245
bool is_cfs_relation_segment = false;
12261246
pgFile tmp_file;
12271247
pgFile **pre_search_file;
1248+
pgFile *prev_file = NULL;
1249+
12281250
tmp_file.path = psprintf("%s.cfm", file->path);
12291251
pre_search_file = (pgFile **) parray_bsearch(arguments->files, &tmp_file, pgFileComparePath);
12301252
if (pre_search_file != NULL)
12311253
{
1232-
is_cfs_relation_segment = true;
1233-
/* TODO If we don't have ptrack simply copy the file */
1234-
if (file->pagemap.bitmapsize == 0)
1254+
/* Now check if it's generation has changed since last backup */
1255+
if (arguments->prev_files)
12351256
{
1236-
is_cfs_relation_segment = false;
1237-
elog(NOTICE, "1 file '%s' is a cfs relation's segment, bitmapsize == 0 \n", file->path);
1257+
pgFile **p = (pgFile **) parray_bsearch(arguments->prev_files, file, pgFileComparePath);
1258+
if (p)
1259+
prev_file = *p;
1260+
elog(NOTICE, "file '%s' is a cfs relation's segment generation prev %d, now %d",
1261+
file->path, prev_file->generation, file->generation);
1262+
1263+
if (prev_file && prev_file->generation == file->generation)
1264+
{
1265+
elog(NOTICE, "prev->write_size %lu, file_size %lu", prev_file->write_size, file_size(file->path));
1266+
if (prev_file->write_size == file_size(file->path))
1267+
{
1268+
elog(NOTICE, "File hasn't changed since last backup. Don't copy at all");
1269+
is_cfs_relation_segment = true;
1270+
}
1271+
else
1272+
{
1273+
elog(NOTICE, "Backup part of the file. %s", file->path);
1274+
is_cfs_relation_segment = true;
1275+
}
1276+
}
12381277
}
12391278
}
12401279
pg_free(tmp_file.path);
12411280

12421281

12431282
if (is_cfs_relation_segment)
12441283
{
1245-
/*
1246-
* TODO backup cfs segment
1247-
* see backup_data_file()
1248-
*/
1249-
elog(NOTICE, "2 file '%s' is a cfs relation's segment \n", file->path);
1250-
elog(NOTICE, "2 file->pagemap.bitmapsize = %d", file->pagemap.bitmapsize);
1251-
datapagemap_iterator_t *iter;
1252-
BlockNumber blknum = 0;
1253-
1254-
iter = datapagemap_iterate(&file->pagemap);
1255-
while(datapagemap_next(iter, &blknum))
1256-
elog(NOTICE, "2 blknum %u", blknum);
1284+
/* backup cfs segment partly */
1285+
if (!copy_file_partly(arguments->from_root,
1286+
arguments->to_root,
1287+
file, prev_file->write_size))
1288+
{
1289+
/* record as skipped file in file_xxx.txt */
1290+
file->write_size = BYTES_INVALID;
1291+
elog(LOG, "skip");
1292+
continue;
1293+
}
12571294
}
12581295
else if (!copy_file(arguments->from_root,
12591296
arguments->to_root,
@@ -1338,16 +1375,32 @@ add_files(parray *files, const char *root, bool add_root, bool is_pgdata)
13381375
sprintf(tmp_file.path+path_len-7, ".%d", segno);
13391376
else
13401377
tmp_file.path[path_len-7] = '\0';
1378+
13411379
pre_search_file = (pgFile **) parray_bsearch(list_file, &tmp_file, pgFileComparePath);
1342-
if (pre_search_file != NULL)
1380+
/* Use another scheme for compressed files */
1381+
pgFile map_file;
1382+
pgFile **map_search_file;
1383+
map_file.path = pg_strdup(file->path);
1384+
if (segno > 0)
1385+
sprintf(map_file.path+path_len-7, ".%d.cfm", segno);
1386+
else
1387+
sprintf(map_file.path+path_len-7, ".cfm");
1388+
map_search_file = (pgFile **) parray_bsearch(list_file, &map_file, pgFileComparePath);
1389+
1390+
if (pre_search_file != NULL
1391+
&& map_search_file == NULL)
13431392
{
13441393
search_file = *pre_search_file;
13451394
search_file->ptrack_path = pg_strdup(file->path);
13461395
search_file->segno = segno;
1347-
} else {
1396+
}
1397+
else
1398+
{
13481399
pg_free(tmp_file.path);
1400+
pg_free(map_file.path);
13491401
break;
13501402
}
1403+
pg_free(map_file.path);
13511404
pg_free(tmp_file.path);
13521405
segno++;
13531406
}
@@ -1361,12 +1414,9 @@ add_files(parray *files, const char *root, bool add_root, bool is_pgdata)
13611414
/* compress map file it is not data file */
13621415
if (path_len > 4 && strncmp(file->path+(path_len-4), ".cfm", 4) == 0)
13631416
{
1364-
if (current.backup_mode == BACKUP_MODE_DIFF_PTRACK ||
1365-
current.backup_mode == BACKUP_MODE_DIFF_PAGE)
1366-
{
1367-
elog(NOTICE, "You can't use incremental backup with compress tablespace");
1368-
/* TODO Add here incremental backup for compressed tablespaces */
1369-
}
1417+
if (current.backup_mode == BACKUP_MODE_DIFF_PAGE)
1418+
elog(ERROR, "You can't use PAGE mode backup with compressed tablespace.\n"
1419+
"Try PTRACK mode instead.");
13701420
continue;
13711421
}
13721422

@@ -1420,8 +1470,34 @@ add_files(parray *files, const char *root, bool add_root, bool is_pgdata)
14201470
pre_search_file = (pgFile **) parray_bsearch(list_file, &tmp_file, pgFileComparePath);
14211471
if (pre_search_file != NULL)
14221472
{
1473+
FileMap* map;
1474+
int md = open(file->path, O_RDWR|PG_BINARY, 0);
1475+
if (md < 0)
1476+
elog(ERROR, "add_files(). cannot open cfm file '%s'", file->path);
1477+
1478+
map = cfs_mmap(md);
1479+
if (map == MAP_FAILED)
1480+
{
1481+
elog(LOG, "add_files(). cfs_compression_ration failed to map file %s: %m", file->path);
1482+
close(md);
1483+
break;
1484+
}
1485+
1486+
(*pre_search_file)->last_backup_write_size = map->last_backup_write_size;
1487+
(*pre_search_file)->generation = map->generation;
14231488
(*pre_search_file)->is_datafile = false;
1489+
map->last_backup_write_size = map->physSize;
1490+
1491+
if (cfs_msync(map) < 0)
1492+
elog(LOG, "add_files(). CFS failed to sync map %s: %m", file->path);
1493+
if (cfs_munmap(map) < 0)
1494+
elog(LOG, "add_files(). CFS failed to unmap file %s: %m", file->path);
1495+
if (close(md) < 0)
1496+
elog(LOG, "add_files(). CFS failed to close file %s: %m", file->path);
14241497
}
1498+
else
1499+
elog(ERROR, "corresponding segment '%s' is not found", tmp_file.path);
1500+
14251501
pg_free(tmp_file.path);
14261502
}
14271503
}
@@ -1693,3 +1769,42 @@ StreamLog(void *arg)
16931769
PQfinish(conn);
16941770
conn = NULL;
16951771
}
1772+
1773+
1774+
FileMap* cfs_mmap(int md)
1775+
{
1776+
FileMap* map;
1777+
#ifdef WIN32
1778+
HANDLE mh = CreateFileMapping(_get_osfhandle(md), NULL, PAGE_READWRITE,
1779+
0, (DWORD)sizeof(FileMap), NULL);
1780+
if (mh == NULL) {
1781+
return (FileMap*)MAP_FAILED;
1782+
}
1783+
map = (FileMap*)MapViewOfFile(mh, FILE_MAP_ALL_ACCESS, 0, 0, 0);
1784+
CloseHandle(mh);
1785+
if (map == NULL) {
1786+
return (FileMap*)MAP_FAILED;
1787+
}
1788+
#else
1789+
map = (FileMap*)mmap(NULL, sizeof(FileMap), PROT_WRITE | PROT_READ, MAP_SHARED, md, 0);
1790+
#endif
1791+
return map;
1792+
}
1793+
1794+
int cfs_munmap(FileMap* map)
1795+
{
1796+
#ifdef WIN32
1797+
return UnmapViewOfFile(map) ? 0 : -1;
1798+
#else
1799+
return munmap(map, sizeof(FileMap));
1800+
#endif
1801+
}
1802+
1803+
int cfs_msync(FileMap* map)
1804+
{
1805+
#ifdef WIN32
1806+
return FlushViewOfFile(map, sizeof(FileMap)) ? 0 : -1;
1807+
#else
1808+
return msync(map, sizeof(FileMap), MS_SYNC);
1809+
#endif
1810+
}

contrib/pg_probackup/data.c

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ backup_data_file(const char *from_root, const char *to_root,
113113
/* confirm server version */
114114
check_server_version();
115115

116+
/* TODO If file is the segment of compressed table,
117+
* read its generation from cfm,
118+
* compare this generation with one in the file_database.txt and
119+
* respectively backup all file or just changed part.
120+
*/
116121

117122
/*
118123
* Read each page and write the page excluding hole. If it has been
@@ -681,6 +686,131 @@ copy_file(const char *from_root, const char *to_root, pgFile *file)
681686
return true;
682687
}
683688

689+
bool
690+
copy_file_partly(const char *from_root, const char *to_root,
691+
pgFile *file, size_t skip_size)
692+
{
693+
char to_path[MAXPGPATH];
694+
FILE *in;
695+
FILE *out;
696+
size_t read_len = 0;
697+
int errno_tmp;
698+
struct stat st;
699+
char buf[8192];
700+
701+
/* reset size summary */
702+
file->read_size = 0;
703+
file->write_size = 0;
704+
705+
/* open backup mode file for read */
706+
in = fopen(file->path, "r");
707+
if (in == NULL)
708+
{
709+
/* maybe deleted, it's not error */
710+
if (errno == ENOENT)
711+
return false;
712+
713+
elog(ERROR, "cannot open source file \"%s\": %s", file->path,
714+
strerror(errno));
715+
}
716+
717+
/* open backup file for write */
718+
if (check)
719+
snprintf(to_path, lengthof(to_path), "%s/tmp", backup_path);
720+
else
721+
join_path_components(to_path, to_root, file->path + strlen(from_root) + 1);
722+
out = fopen(to_path, "w");
723+
if (out == NULL)
724+
{
725+
int errno_tmp = errno;
726+
fclose(in);
727+
elog(ERROR, "cannot open destination file \"%s\": %s",
728+
to_path, strerror(errno_tmp));
729+
}
730+
731+
/* stat source file to change mode of destination file */
732+
if (fstat(fileno(in), &st) == -1)
733+
{
734+
fclose(in);
735+
fclose(out);
736+
elog(ERROR, "cannot stat \"%s\": %s", file->path,
737+
strerror(errno));
738+
}
739+
740+
if (fseek(in, skip_size, SEEK_SET) < 0)
741+
elog(ERROR, "cannot seek %lu of \"%s\": %s",
742+
skip_size, file->path, strerror(errno));
743+
744+
/* copy content and calc CRC */
745+
for (;;)
746+
{
747+
if ((read_len = fread(buf, 1, sizeof(buf), in)) != sizeof(buf))
748+
break;
749+
750+
if (fwrite(buf, 1, read_len, out) != read_len)
751+
{
752+
errno_tmp = errno;
753+
/* oops */
754+
fclose(in);
755+
fclose(out);
756+
elog(ERROR, "cannot write to \"%s\": %s", to_path,
757+
strerror(errno_tmp));
758+
}
759+
760+
file->write_size += sizeof(buf);
761+
file->read_size += sizeof(buf);
762+
}
763+
764+
errno_tmp = errno;
765+
if (!feof(in))
766+
{
767+
fclose(in);
768+
fclose(out);
769+
elog(ERROR, "cannot read backup mode file \"%s\": %s",
770+
file->path, strerror(errno_tmp));
771+
}
772+
773+
/* copy odd part. */
774+
if (read_len > 0)
775+
{
776+
if (fwrite(buf, 1, read_len, out) != read_len)
777+
{
778+
errno_tmp = errno;
779+
/* oops */
780+
fclose(in);
781+
fclose(out);
782+
elog(ERROR, "cannot write to \"%s\": %s", to_path,
783+
strerror(errno_tmp));
784+
}
785+
786+
file->write_size += read_len;
787+
file->read_size += read_len;
788+
}
789+
790+
/* update file permission */
791+
if (chmod(to_path, st.st_mode) == -1)
792+
{
793+
errno_tmp = errno;
794+
fclose(in);
795+
fclose(out);
796+
elog(ERROR, "cannot change mode of \"%s\": %s", to_path,
797+
strerror(errno_tmp));
798+
}
799+
800+
elog(NOTICE, "copy_file_partly(). %s file->write_size %lu", to_path, file->write_size);
801+
pgFile newfile;
802+
newfile.path = pg_strdup(to_path);
803+
file->crc = pgFileGetCRC(&newfile);
804+
805+
fclose(in);
806+
fclose(out);
807+
808+
if (check)
809+
remove(to_path);
810+
811+
return true;
812+
}
813+
684814
bool
685815
calc_file(pgFile *file)
686816
{

0 commit comments

Comments
 (0)