Skip to content

Commit a9f3e80

Browse files
committed
[PGPRO-5421] rewrite --wal-file-path logic and tests
1 parent 5bc3fb2 commit a9f3e80

File tree

9 files changed

+194
-136
lines changed

9 files changed

+194
-136
lines changed

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ env:
4646
# - PG_VERSION=13 PG_BRANCH=REL_13_STABLE PTRACK_PATCH_PG_BRANCH=REL_13_STABLE MODE=replica
4747
# - PG_VERSION=13 PG_BRANCH=REL_13_STABLE PTRACK_PATCH_PG_BRANCH=off MODE=retention
4848
# - PG_VERSION=13 PG_BRANCH=REL_13_STABLE PTRACK_PATCH_PG_BRANCH=REL_13_STABLE MODE=restore
49-
- PG_VERSION=15 PG_BRANCH=master
5049
- PG_VERSION=14 PG_BRANCH=REL_14_STABLE MODE=archive
5150
- PG_VERSION=13 PG_BRANCH=REL_13_STABLE MODE=archive
5251
- PG_VERSION=12 PG_BRANCH=REL_12_STABLE MODE=archive

src/archive.c

Lines changed: 14 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* archive.c: - pg_probackup specific archive commands for archive backups.
44
*
55
*
6-
* Portions Copyright (c) 2018-2019, Postgres Professional
6+
* Portions Copyright (c) 2018-2021, Postgres Professional
77
*
88
*-------------------------------------------------------------------------
99
*/
@@ -113,18 +113,13 @@ static parray *setup_push_filelist(const char *archive_status_dir,
113113
* Where archlog_path is $BACKUP_PATH/wal/instance_name
114114
*/
115115
void
116-
do_archive_push(InstanceState *instanceState, InstanceConfig *instance, char *wal_file_path,
116+
do_archive_push(InstanceState *instanceState, InstanceConfig *instance, char *pg_xlog_dir,
117117
char *wal_file_name, int batch_size, bool overwrite,
118118
bool no_sync, bool no_ready_rename)
119119
{
120120
uint64 i;
121-
char current_dir[MAXPGPATH];
122-
/* directory with wal files to be archived (usually instance pgdata/pg_wal) */
123-
char pg_xlog_dir[MAXPGPATH];
124-
/* usually instance pgdata/pg_wal/archive_status */
125-
char archive_status_dir[MAXPGPATH];
126-
char xlog_wal_path[MAXPGPATH];
127-
uint64 system_id;
121+
/* usually instance pgdata/pg_wal/archive_status, empty if no_ready_rename or batch_size == 1 */
122+
char archive_status_dir[MAXPGPATH] = "";
128123
bool is_compress = false;
129124

130125
/* arrays with meta info for multi threaded backup */
@@ -144,50 +139,8 @@ do_archive_push(InstanceState *instanceState, InstanceConfig *instance, char *wa
144139
parray *batch_files = NULL;
145140
int n_threads;
146141

147-
if (wal_file_name == NULL)
148-
elog(ERROR, "Required parameter is not specified: --wal-file-name %%f");
149-
150-
join_path_components(xlog_wal_path, PG_XLOG_DIR, wal_file_name);
151-
152-
if (wal_file_path == NULL)
153-
{
154-
elog(INFO, "Optional parameter is not specified: --wal_file_path %%p "
155-
"Setting wal-file-path by default");
156-
wal_file_path = xlog_wal_path;
157-
}
158-
159-
if (strcmp(wal_file_path, xlog_wal_path) != 0)
160-
{
161-
elog(INFO, "wal_file_path is setted by user %s", wal_file_path);
162-
163-
join_path_components(pg_xlog_dir, instance->pgdata, XLOGDIR);
164-
}
165-
else
166-
{
167-
/* Create 'archlog_path' directory. Do nothing if it already exists. */
168-
//fio_mkdir(instance->arclog_path, DIR_PERMISSION, FIO_BACKUP_HOST);
169-
170-
if (!getcwd(current_dir, sizeof(current_dir)))
171-
elog(ERROR, "getcwd() error");
172-
173-
/* verify that archive-push --instance parameter is valid */
174-
system_id = get_system_identifier(current_dir, FIO_DB_HOST);
175-
176-
if (instance->pgdata == NULL)
177-
elog(ERROR, "Cannot read pg_probackup.conf for this instance");
178-
179-
if (system_id != instance->system_identifier)
180-
elog(ERROR, "Refuse to push WAL segment %s into archive. Instance parameters mismatch."
181-
"Instance '%s' should have SYSTEM_ID = " UINT64_FORMAT " instead of " UINT64_FORMAT,
182-
wal_file_name, instanceState->instance_name, instance->system_identifier, system_id);
183-
184-
if (instance->compress_alg == PGLZ_COMPRESS)
185-
elog(ERROR, "Cannot use pglz for WAL compression");
186-
187-
join_path_components(pg_xlog_dir, current_dir, XLOGDIR);
188-
}
189-
190-
join_path_components(archive_status_dir, pg_xlog_dir, "archive_status");
142+
if (!no_ready_rename || batch_size > 1)
143+
join_path_components(archive_status_dir, pg_xlog_dir, "archive_status");
191144

192145
#ifdef HAVE_LIBZ
193146
if (instance->compress_alg == ZLIB_COMPRESS)
@@ -226,12 +179,13 @@ do_archive_push(InstanceState *instanceState, InstanceConfig *instance, char *wa
226179
{
227180
int rc;
228181
WALSegno *xlogfile = (WALSegno *) parray_get(batch_files, i);
182+
bool first_wal = strcmp(xlogfile->name, wal_file_name) == 0;
229183

230-
rc = push_file(xlogfile, archive_status_dir,
184+
rc = push_file(xlogfile, first_wal ? NULL : archive_status_dir,
231185
pg_xlog_dir, instanceState->instance_wal_subdir_path,
232186
overwrite, no_sync,
233187
instance->archive_timeout,
234-
no_ready_rename || (strcmp(xlogfile->name, wal_file_name) == 0) ? true : false,
188+
no_ready_rename || first_wal,
235189
is_compress && IsXLogFileName(xlogfile->name) ? true : false,
236190
instance->compress_level);
237191
if (rc == 0)
@@ -255,7 +209,7 @@ do_archive_push(InstanceState *instanceState, InstanceConfig *instance, char *wa
255209
arg->first_filename = wal_file_name;
256210
arg->archive_dir = instanceState->instance_wal_subdir_path;
257211
arg->pg_xlog_dir = pg_xlog_dir;
258-
arg->archive_status_dir = archive_status_dir;
212+
arg->archive_status_dir = (!no_ready_rename || batch_size > 1) ? archive_status_dir : NULL;
259213
arg->overwrite = overwrite;
260214
arg->compress = is_compress;
261215
arg->no_sync = no_sync;
@@ -298,7 +252,7 @@ do_archive_push(InstanceState *instanceState, InstanceConfig *instance, char *wa
298252

299253
/* Note, that we are leaking memory here,
300254
* because pushing into archive is a very
301-
* time-sensetive operation, so we skip freeing stuff.
255+
* time-sensitive operation, so we skip freeing stuff.
302256
*/
303257

304258
push_done:
@@ -378,9 +332,6 @@ push_file(WALSegno *xlogfile, const char *archive_status_dir,
378332
int compress_level)
379333
{
380334
int rc;
381-
char wal_file_dummy[MAXPGPATH];
382-
383-
join_path_components(wal_file_dummy, archive_status_dir, xlogfile->name);
384335

385336
elog(LOG, "pushing file \"%s\"", xlogfile->name);
386337

@@ -397,11 +348,13 @@ push_file(WALSegno *xlogfile, const char *archive_status_dir,
397348
#endif
398349

399350
/* take '--no-ready-rename' flag into account */
400-
if (!no_ready_rename)
351+
if (!no_ready_rename && archive_status_dir != NULL)
401352
{
353+
char wal_file_dummy[MAXPGPATH];
402354
char wal_file_ready[MAXPGPATH];
403355
char wal_file_done[MAXPGPATH];
404356

357+
join_path_components(wal_file_dummy, archive_status_dir, xlogfile->name);
405358
snprintf(wal_file_ready, MAXPGPATH, "%s.%s", wal_file_dummy, "ready");
406359
snprintf(wal_file_done, MAXPGPATH, "%s.%s", wal_file_dummy, "done");
407360

src/pg_probackup.c

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
* which includes info about pgdata directory and connection.
3636
*
3737
* Portions Copyright (c) 2009-2013, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
38-
* Portions Copyright (c) 2015-2019, Postgres Professional
38+
* Portions Copyright (c) 2015-2021, Postgres Professional
3939
*
4040
*-------------------------------------------------------------------------
4141
*/
@@ -151,6 +151,7 @@ static char *wal_file_path;
151151
static char *wal_file_name;
152152
static bool file_overwrite = false;
153153
static bool no_ready_rename = false;
154+
static char archive_push_xlog_dir[MAXPGPATH] = "";
154155

155156
/* archive get options */
156157
static char *prefetch_dir;
@@ -788,14 +789,95 @@ main(int argc, char *argv[])
788789
current.stream = stream_wal = true;
789790
if (instance_config.external_dir_str)
790791
elog(ERROR, "external directories not supported fom \"%s\" command", get_subcmd_name(backup_subcmd));
791-
// TODO проверить instance_config.conn_opt
792+
// TODO check instance_config.conn_opt
792793
}
793794

794795
/* sanity */
795796
if (backup_subcmd == VALIDATE_CMD && restore_params->no_validate)
796797
elog(ERROR, "You cannot specify \"--no-validate\" option with the \"%s\" command",
797798
get_subcmd_name(backup_subcmd));
798799

800+
if (backup_subcmd == ARCHIVE_PUSH_CMD)
801+
{
802+
/* Check archive-push parameters and construct archive_push_xlog_dir
803+
*
804+
* There are 3 cases:
805+
* 1. no --wal-file-path specified -- use cwd, ./PG_XLOG_DIR for wal files
806+
* (and ./PG_XLOG_DIR/archive_status for .done files inside do_archive_push())
807+
* in this case we can use batches and threads
808+
* 2. --wal-file-path is specified and it is the same dir as stored in pg_probackup.conf (instance_config.pgdata)
809+
* in this case we can use this path, as well as batches and thread
810+
* 3. --wal-file-path is specified and it is different from instance_config.pgdata
811+
* disable optimizations and work with user specified path
812+
*/
813+
bool check_system_id = true;
814+
uint64 system_id;
815+
816+
if (wal_file_name == NULL)
817+
elog(ERROR, "Required parameter is not specified: --wal-file-name %%f");
818+
819+
if (instance_config.pgdata == NULL)
820+
elog(ERROR, "Cannot read pg_probackup.conf for this instance");
821+
822+
/* TODO may be remove in preference of checking inside compress_init()? */
823+
if (instance_config.compress_alg == PGLZ_COMPRESS)
824+
elog(ERROR, "Cannot use pglz for WAL compression");
825+
826+
if (wal_file_path == NULL)
827+
{
828+
/* 1st case */
829+
char current_dir[MAXPGPATH];
830+
if (!getcwd(current_dir, sizeof(current_dir)))
831+
elog(ERROR, "getcwd() error");
832+
833+
system_id = get_system_identifier(current_dir, FIO_DB_HOST);
834+
join_path_components(archive_push_xlog_dir, current_dir, XLOGDIR);
835+
}
836+
else
837+
{
838+
/*
839+
* Usually we get something like
840+
* wal_file_path = "pg_wal/0000000100000000000000A1"
841+
* wal_file_name = "0000000100000000000000A1"
842+
* instance_config.pgdata = "/pgdata/.../node/data"
843+
* We need to strip wal_file_name from wal_file_path, add XLOGDIR to instance_config.pgdata
844+
* and compare this directories.
845+
* Note, that pg_wal can be symlink (see test_waldir_outside_pgdata_archiving)
846+
*/
847+
char *stripped_wal_file_path = pgut_str_strip_trailing_filename(wal_file_path, wal_file_name);
848+
join_path_components(archive_push_xlog_dir, instance_config.pgdata, XLOGDIR);
849+
if (fio_is_same_file(stripped_wal_file_path, archive_push_xlog_dir, true, FIO_DB_HOST))
850+
{
851+
/* 2nd case */
852+
system_id = get_system_identifier(instance_config.pgdata, FIO_DB_HOST);
853+
/* archive_push_xlog_dir already have right value */
854+
}
855+
else
856+
{
857+
/* 3rd case */
858+
check_system_id = false;
859+
if (strlen(stripped_wal_file_path) < MAXPGPATH)
860+
strncpy(archive_push_xlog_dir, stripped_wal_file_path, MAXPGPATH);
861+
else
862+
elog(ERROR, "Value specified to --wal_file_path is too long");
863+
864+
if (batch_size > 1 || num_threads > 1 || !no_ready_rename)
865+
{
866+
elog(WARNING, "Supplied --wal_file_path is outside pgdata, force safe values for options: --batch-size=1 -j 1 --no-ready-rename");
867+
batch_size = 1;
868+
num_threads = 1;
869+
no_ready_rename = true;
870+
}
871+
}
872+
pfree(stripped_wal_file_path);
873+
}
874+
875+
if (check_system_id && system_id != instance_config.system_identifier)
876+
elog(ERROR, "Refuse to push WAL segment %s into archive. Instance parameters mismatch."
877+
"Instance '%s' should have SYSTEM_ID = " UINT64_FORMAT " instead of " UINT64_FORMAT,
878+
wal_file_name, instanceState->instance_name, instance_config.system_identifier, system_id);
879+
}
880+
799881
#if PG_VERSION_NUM >= 100000
800882
if (temp_slot && perm_slot)
801883
elog(ERROR, "You cannot specify \"--perm-slot\" option with the \"--temp-slot\" option");
@@ -819,7 +901,7 @@ main(int argc, char *argv[])
819901
switch (backup_subcmd)
820902
{
821903
case ARCHIVE_PUSH_CMD:
822-
do_archive_push(instanceState, &instance_config, wal_file_path, wal_file_name,
904+
do_archive_push(instanceState, &instance_config, archive_push_xlog_dir, wal_file_name,
823905
batch_size, file_overwrite, no_sync, no_ready_rename);
824906
break;
825907
case ARCHIVE_GET_CMD:

src/pg_probackup.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,7 @@ extern int do_init(CatalogState *catalogState);
889889
extern int do_add_instance(InstanceState *instanceState, InstanceConfig *instance);
890890

891891
/* in archive.c */
892-
extern void do_archive_push(InstanceState *instanceState, InstanceConfig *instance, char *wal_file_path,
892+
extern void do_archive_push(InstanceState *instanceState, InstanceConfig *instance, char *pg_xlog_dir,
893893
char *wal_file_name, int batch_size, bool overwrite,
894894
bool no_sync, bool no_ready_rename);
895895
extern void do_archive_get(InstanceState *instanceState, InstanceConfig *instance, const char *prefetch_dir_arg, char *wal_file_path,

src/utils/file.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,6 +1141,33 @@ fio_stat(char const* path, struct stat* st, bool follow_symlink, fio_location lo
11411141
}
11421142
}
11431143

1144+
/*
1145+
* Compare, that filename1 and filename2 is the same file
1146+
* in windows compare only filenames
1147+
*/
1148+
bool
1149+
fio_is_same_file(char const* filename1, char const* filename2, bool follow_symlink, fio_location location)
1150+
{
1151+
#ifndef WIN32
1152+
struct stat stat1, stat2;
1153+
1154+
if (fio_stat(filename1, &stat1, follow_symlink, location) < 0)
1155+
elog(ERROR, "Can't stat file \"%s\": %s", filename1, strerror(errno));
1156+
1157+
if (fio_stat(filename2, &stat2, follow_symlink, location) < 0)
1158+
elog(ERROR, "Can't stat file \"%s\": %s", filename2, strerror(errno));
1159+
1160+
return stat1.st_ino == stat2.st_ino && stat1.st_dev == stat2.st_dev;
1161+
#else
1162+
char *abs_name1 = make_absolute_path(filename1);
1163+
char *abs_name2 = make_absolute_path(filename2);
1164+
bool result = strcmp(abs_name1, abs_name2) == 0;
1165+
free(abs_name2);
1166+
free(abs_name1);
1167+
return result;
1168+
#endif
1169+
}
1170+
11441171
/*
11451172
* Read value of a symbolic link
11461173
* this is a wrapper about readlink() syscall

src/utils/file.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ extern int fio_mkdir(char const* path, int mode, fio_location location);
129129
extern int fio_chmod(char const* path, int mode, fio_location location);
130130
extern int fio_access(char const* path, int mode, fio_location location);
131131
extern int fio_stat(char const* path, struct stat* st, bool follow_symlinks, fio_location location);
132+
extern bool fio_is_same_file(char const* filename1, char const* filename2, bool follow_symlink, fio_location location);
132133
extern ssize_t fio_readlink(const char *path, char *value, size_t valsiz, fio_location location);
133134
extern DIR* fio_opendir(char const* path, fio_location location);
134135
extern struct dirent * fio_readdir(DIR *dirp);

src/utils/pgut.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,22 @@ pgut_strndup(const char *str, size_t n)
977977
return ret;
978978
}
979979

980+
/*
981+
* Allocates new string, that contains part of filepath string minus trailing filename string
982+
* If trailing filename string not found, returns copy of filepath.
983+
* Result must be free by caller.
984+
*/
985+
char *
986+
pgut_str_strip_trailing_filename(const char *filepath, const char *filename)
987+
{
988+
size_t fp_len = strlen(filepath);
989+
size_t fn_len = strlen(filename);
990+
if (strncmp(filepath + fp_len - fn_len, filename, fn_len) == 0)
991+
return pgut_strndup(filepath, fp_len - fn_len);
992+
else
993+
return pgut_strndup(filepath, fp_len);
994+
}
995+
980996
FILE *
981997
pgut_fopen(const char *path, const char *mode, bool missing_ok)
982998
{

src/utils/pgut.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ extern void *pgut_malloc0(size_t size);
6363
extern void *pgut_realloc(void *p, size_t size);
6464
extern char *pgut_strdup(const char *str);
6565
extern char *pgut_strndup(const char *str, size_t n);
66+
extern char *pgut_str_strip_trailing_filename(const char *filepath, const char *filename);
6667

6768
#define pgut_new(type) ((type *) pgut_malloc(sizeof(type)))
6869
#define pgut_new0(type) ((type *) pgut_malloc0(sizeof(type)))

0 commit comments

Comments
 (0)