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

Commit 0249fb4

Browse files
committed
Merge commit '94540661566677a456e927050664b7e03db601d0' into PGPRO9_6
Conflicts: contrib/pg_probackup/pgut/getopt_long.c
2 parents f80dca2 + 9454066 commit 0249fb4

File tree

14 files changed

+733
-413
lines changed

14 files changed

+733
-413
lines changed

contrib/pg_probackup/backup.c

Lines changed: 70 additions & 116 deletions
Large diffs are not rendered by default.

contrib/pg_probackup/catalog.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,10 @@ pgBackupCreateDir(pgBackup *backup)
242242
char *subdirs[] = { DATABASE_DIR, NULL };
243243

244244
pgBackupGetPath(backup, path, lengthof(path), NULL);
245+
246+
if (!dir_is_empty(path))
247+
elog(ERROR, "backup destination is not empty \"%s\"", path);
248+
245249
dir_create_dir(path, DIR_PERMISSION);
246250

247251
/* create directories for actual backup files */
@@ -525,6 +529,8 @@ pgBackupGetPath(const pgBackup *backup, char *path, size_t len, const char *subd
525529
else
526530
snprintf(path, len, "%s/%s/%s", backup_path, BACKUPS_DIR, datetime);
527531
free(datetime);
532+
533+
make_native_path(path);
528534
}
529535

530536
void

contrib/pg_probackup/dir.c

Lines changed: 172 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ const char *pgdata_exclude_dir[] =
2525
"pg_xlog",
2626
"pg_stat_tmp",
2727
"pgsql_tmp",
28-
NULL, /* arclog_path will be set later */
2928
NULL, /* pg_log will be set later */
3029
NULL
3130
};
@@ -41,12 +40,18 @@ static char *pgdata_exclude_files[] =
4140
pgFile *pgFileNew(const char *path, bool omit_symlink);
4241
static int BlackListCompare(const void *str1, const void *str2);
4342

44-
/* create directory, also create parent directories if necessary */
43+
static void dir_list_file_internal(parray *files, const char *root,
44+
bool exclude, bool omit_symlink,
45+
bool add_root, parray *black_list);
46+
47+
/*
48+
* Create directory, also create parent directories if necessary.
49+
*/
4550
int
4651
dir_create_dir(const char *dir, mode_t mode)
4752
{
48-
char copy[MAXPGPATH];
49-
char parent[MAXPGPATH];
53+
char copy[MAXPGPATH];
54+
char parent[MAXPGPATH];
5055

5156
strncpy(copy, dir, MAXPGPATH);
5257
strncpy(parent, dirname(copy), MAXPGPATH);
@@ -60,8 +65,7 @@ dir_create_dir(const char *dir, mode_t mode)
6065
{
6166
if (errno == EEXIST) /* already exist */
6267
return 0;
63-
elog(ERROR, "cannot create directory \"%s\": %s", dir,
64-
strerror(errno));
68+
elog(ERROR, "cannot create directory \"%s\": %s", dir, strerror(errno));
6569
}
6670

6771
return 0;
@@ -295,7 +299,7 @@ dir_list_file(parray *files, const char *root, bool exclude, bool omit_symlink,
295299
parray_qsort(files, pgFileComparePath);
296300
}
297301

298-
void
302+
static void
299303
dir_list_file_internal(parray *files, const char *root, bool exclude,
300304
bool omit_symlink, bool add_root, parray *black_list)
301305
{
@@ -327,11 +331,7 @@ dir_list_file_internal(parray *files, const char *root, bool exclude,
327331
else
328332
file_name++;
329333

330-
/*
331-
* If the item in the exclude list starts with '/', compare to the
332-
* absolute path of the directory. Otherwise compare to the directory
333-
* name portion.
334-
*/
334+
/* Check if we need to exclude file by name */
335335
for (i = 0; pgdata_exclude_files[i]; i++)
336336
if (strcmp(file_name, pgdata_exclude_files[i]) == 0)
337337
/* Skip */
@@ -416,13 +416,10 @@ dir_list_file_internal(parray *files, const char *root, bool exclude,
416416
break;
417417
}
418418
}
419-
else
419+
else if (strcmp(dirname, pgdata_exclude_dir[i]) == 0)
420420
{
421-
if (strcmp(dirname, pgdata_exclude_dir[i]) == 0)
422-
{
423-
skip = true;
424-
break;
425-
}
421+
skip = true;
422+
break;
426423
}
427424
}
428425
if (skip)
@@ -468,74 +465,159 @@ dir_list_file_internal(parray *files, const char *root, bool exclude,
468465
}
469466
}
470467

471-
/* print mkdirs.sh */
468+
/*
469+
* List data directories excluding directories from
470+
* pgdata_exclude_dir array.
471+
*
472+
* **is_root** is a little bit hack. We exclude only first level of directories
473+
* and on the first level we check all files and directories.
474+
*/
472475
void
473-
dir_print_mkdirs_sh(FILE *out, const parray *files, const char *root)
476+
list_data_directories(parray *files, const char *path, bool is_root,
477+
bool exclude)
474478
{
475-
int i;
476-
477-
for (i = 0; i < parray_num(files); i++)
479+
DIR *dir;
480+
struct dirent *dent;
481+
int prev_errno;
482+
bool has_child_dirs = false;
483+
484+
/* open directory and list contents */
485+
dir = opendir(path);
486+
if (dir == NULL)
487+
elog(ERROR, "cannot open directory \"%s\": %s", path, strerror(errno));
488+
489+
errno = 0;
490+
while ((dent = readdir(dir)))
478491
{
479-
pgFile *file = (pgFile *) parray_get(files, i);
480-
if (S_ISDIR(file->mode))
492+
char child[MAXPGPATH];
493+
bool skip = false;
494+
struct stat st;
495+
496+
/* skip entries point current dir or parent dir */
497+
if (strcmp(dent->d_name, ".") == 0 ||
498+
strcmp(dent->d_name, "..") == 0)
499+
continue;
500+
501+
join_path_components(child, path, dent->d_name);
502+
503+
if (lstat(child, &st) == -1)
504+
elog(ERROR, "cannot stat file \"%s\": %s", child, strerror(errno));
505+
506+
if (!S_ISDIR(st.st_mode))
481507
{
482-
if (strstr(file->path, root) == file->path &&
483-
*(file->path + strlen(root)) == '/')
484-
{
485-
fprintf(out, "mkdir -m 700 -p %s\n", file->path + strlen(root) + 1);
486-
}
508+
/* Stop reading the directory if we met file */
509+
if (!is_root)
510+
break;
487511
else
512+
continue;
513+
}
514+
515+
/* Check for exclude for the first level of listing */
516+
if (is_root && exclude)
517+
{
518+
int i;
519+
520+
for (i = 0; pgdata_exclude_dir[i]; i++)
488521
{
489-
fprintf(out, "mkdir -m 700 -p %s\n", file->path);
522+
if (strcmp(dent->d_name, pgdata_exclude_dir[i]) == 0)
523+
{
524+
skip = true;
525+
break;
526+
}
490527
}
491528
}
492-
}
529+
if (skip)
530+
continue;
493531

494-
fprintf(out, "\n");
532+
has_child_dirs = true;
533+
list_data_directories(files, child, false, exclude);
534+
}
495535

496-
for (i = 0; i < parray_num(files); i++)
536+
/* List only full and last directories */
537+
if (!is_root && !has_child_dirs)
497538
{
498-
pgFile *file = (pgFile *) parray_get(files, i);
499-
if (S_ISLNK(file->mode))
500-
{
501-
fprintf(out, "rm -f %s\n", file->path + strlen(root) + 1);
502-
fprintf(out, "ln -s %s %s\n", file->linked, file->path + strlen(root) + 1);
503-
}
539+
pgFile *dir;
540+
541+
dir = pgFileNew(path, false);
542+
parray_append(files, dir);
504543
}
544+
545+
prev_errno = errno;
546+
closedir(dir);
547+
548+
if (prev_errno && prev_errno != ENOENT)
549+
elog(ERROR, "cannot read directory \"%s\": %s",
550+
path, strerror(prev_errno));
505551
}
506552

507-
/* print file list */
553+
/*
554+
* Read names of symbolik names of tablespaces with links to directories from
555+
* tablespace_map or tablespace_map.txt.
556+
*/
508557
void
509-
dir_print_file_list(FILE *out, const parray *files, const char *root, const char *prefix)
558+
read_tablespace_map(parray *files, const char *backup_dir)
510559
{
511-
int i;
512-
int root_len = 0;
560+
FILE *fp;
561+
char db_path[MAXPGPATH],
562+
map_path[MAXPGPATH];
563+
char buf[MAXPGPATH * 2];
513564

514-
/* calculate length of root directory portion */
515-
if (root)
565+
join_path_components(db_path, backup_dir, DATABASE_DIR);
566+
join_path_components(map_path, db_path, "tablespace_map");
567+
568+
/* Exit if database/tablespace_map don't exists */
569+
if (!fileExists(map_path))
516570
{
517-
root_len = strlen(root);
518-
if (root[root_len - 1] != '/')
519-
root_len++;
571+
elog(LOG, "there is no file tablespace_map");
572+
return;
520573
}
521574

575+
fp = fopen(map_path, "rt");
576+
if (fp == NULL)
577+
elog(ERROR, "cannot open \"%s\": %s", map_path, strerror(errno));
578+
579+
while (fgets(buf, lengthof(buf), fp))
580+
{
581+
char link_name[MAXPGPATH],
582+
path[MAXPGPATH];
583+
pgFile *file;
584+
585+
if (sscanf(buf, "%s %s", link_name, path) != 2)
586+
elog(ERROR, "invalid format found in \"%s\"", map_path);
587+
588+
file = pgut_new(pgFile);
589+
memset(file, 0, sizeof(pgFile));
590+
591+
file->path = pgut_malloc(strlen(link_name) + 1);
592+
strcpy(file->path, link_name);
593+
594+
file->linked = pgut_malloc(strlen(path) + 1);
595+
strcpy(file->linked, path);
596+
597+
parray_append(files, file);
598+
}
599+
600+
fclose(fp);
601+
}
602+
603+
/*
604+
* Print file list.
605+
*/
606+
void
607+
print_file_list(FILE *out, const parray *files, const char *root)
608+
{
609+
size_t i;
610+
522611
/* print each file in the list */
523612
for (i = 0; i < parray_num(files); i++)
524613
{
525-
pgFile *file = (pgFile *)parray_get(files, i);
526-
char path[MAXPGPATH];
527-
char *ptr = file->path;
528-
char type;
614+
pgFile *file = (pgFile *) parray_get(files, i);
615+
char *path = file->path;
616+
char type;
529617

530618
/* omit root directory portion */
531-
if (root && strstr(ptr, root) == ptr)
532-
ptr = JoinPathEnd(ptr, root);
533-
534-
/* append prefix if not NULL */
535-
if (prefix)
536-
join_path_components(path, prefix, ptr);
537-
else
538-
strcpy(path, ptr);
619+
if (root && strstr(path, root) == path)
620+
path = JoinPathEnd(path, root);
539621

540622
if (S_ISREG(file->mode) && file->is_datafile)
541623
type = 'F';
@@ -556,7 +638,8 @@ dir_print_file_list(FILE *out, const parray *files, const char *root, const char
556638
fprintf(out, " %s", file->linked);
557639
else
558640
{
559-
char timestamp[20];
641+
char timestamp[20];
642+
560643
time2iso(timestamp, 20, file->mtime);
561644
fprintf(out, " %s", timestamp);
562645
}
@@ -683,45 +766,39 @@ dir_read_file_list(const char *root, const char *file_txt)
683766
}
684767

685768
/*
686-
* Copy contents of directory from_root into to_root.
769+
* Check if directory empty.
687770
*/
688-
void
689-
dir_copy_files(const char *from_root, const char *to_root)
771+
bool
772+
dir_is_empty(const char *path)
690773
{
691-
size_t i;
692-
parray *files = parray_new();
774+
DIR *dir;
775+
struct dirent *dir_ent;
693776

694-
/* don't copy root directory */
695-
dir_list_file(files, from_root, false, true, false);
696-
697-
for (i = 0; i < parray_num(files); i++)
777+
dir = opendir(path);
778+
if (dir == NULL)
698779
{
699-
pgFile *file = (pgFile *) parray_get(files, i);
700-
701-
if (S_ISDIR(file->mode))
702-
{
703-
char to_path[MAXPGPATH];
780+
/* Directory in path doesn't exist */
781+
if (errno == ENOENT)
782+
return true;
783+
elog(ERROR, "cannot open directory \"%s\": %s", path, strerror(errno));
784+
}
704785

705-
join_path_components(to_path, to_root,
706-
file->path + strlen(from_root) + 1);
786+
errno = 0;
787+
while ((dir_ent = readdir(dir)))
788+
{
789+
/* Skip entries point current dir or parent dir */
790+
if (strcmp(dir_ent->d_name, ".") == 0 ||
791+
strcmp(dir_ent->d_name, "..") == 0)
792+
continue;
707793

708-
if (verbose && !check)
709-
elog(LOG, "creating directory \"%s\"",
710-
file->path + strlen(from_root) + 1);
711-
if (!check)
712-
dir_create_dir(to_path, DIR_PERMISSION);
713-
}
714-
else if (S_ISREG(file->mode))
715-
{
716-
if (verbose && !check)
717-
elog(LOG, "copying \"%s\"",
718-
file->path + strlen(from_root) + 1);
719-
if (!check)
720-
copy_file(from_root, to_root, file);
721-
}
794+
/* Directory is not empty */
795+
closedir(dir);
796+
return false;
722797
}
798+
if (errno)
799+
elog(ERROR, "cannot read directory \"%s\": %s", path, strerror(errno));
800+
801+
closedir(dir);
723802

724-
/* cleanup */
725-
parray_walk(files, pgFileFree);
726-
parray_free(files);
803+
return true;
727804
}

contrib/pg_probackup/doc/pg_probackup.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,12 @@ Specifies whether to stop just after the specified recovery target (true), or ju
477477

478478
Specifies recovering into a particular timeline.
479479

480+
-T
481+
--tablespace-mapping=OLDDIR=NEWDIR
482+
483+
Relocate the tablespace in directory `OLDDIR` to `NEWDIR` during restore. Both
484+
`OLDDIR` and `NEWDIR` must be absolute paths.
485+
480486
### Delete options:
481487

482488
--wal

0 commit comments

Comments
 (0)