Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9ace401

Browse files
author
Artur Zakirov
committed
Refactoring do_restore() and do_validate(). Check tablespace mapping before actual restore
1 parent320d0b6 commit9ace401

File tree

5 files changed

+187
-141
lines changed

5 files changed

+187
-141
lines changed

‎doc/pg_probackup.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ Specifies whether to stop just after the specified recovery target (true), or ju
480480

481481
Specifies recovering into a particular timeline.
482482

483-
-T
483+
-TOLDDIR=NEWDIR
484484
--tablespace-mapping=OLDDIR=NEWDIR
485485

486486
Relocate the tablespace in directory`OLDDIR` to`NEWDIR` during restore. Both

‎restore.c

Lines changed: 120 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ typedef struct TablespaceListCell
3030
structTablespaceListCell*next;
3131
charold_dir[MAXPGPATH];
3232
charnew_dir[MAXPGPATH];
33+
boolchecked;/* If this mapping was checked during
34+
restore */
3335
}TablespaceListCell;
3436

3537
typedefstructTablespaceList
@@ -54,6 +56,7 @@ typedef struct TablespaceCreatedList
5456
staticvoidrestore_database(pgBackup*backup);
5557
staticvoidrestore_directories(constchar*pg_data_dir,
5658
constchar*backup_dir);
59+
staticvoidcheck_tablespace_mapping(pgBackup*backup);
5760
staticvoidcreate_recovery_conf(time_tbackup_id,
5861
constchar*target_time,
5962
constchar*target_xid,
@@ -82,20 +85,25 @@ do_restore(time_t backup_id,
8285
{
8386
inti;
8487
intbase_index;/* index of base (full) backup */
88+
intlast_diff_index=-1;/* index of last differential backup */
8589
intret;
8690
parray*backups;
8791

8892
parray*timelines;
8993
pgBackup*base_backup=NULL;
9094
pgBackup*dest_backup=NULL;
9195
pgRecoveryTarget*rt=NULL;
92-
boolbackup_id_found= false;
96+
boolneed_recovery_conf= false;
9397

9498
/* PGDATA and ARCLOG_PATH are always required */
9599
if (pgdata==NULL)
96100
elog(ERROR,
97101
"required parameter not specified: PGDATA (-D, --pgdata)");
98102

103+
/* Check if restore destination empty */
104+
if (!dir_is_empty(pgdata))
105+
elog(ERROR,"restore destination is not empty: \"%s\"",pgdata);
106+
99107
elog(LOG,"========================================");
100108
elog(LOG,"restore start");
101109

@@ -131,110 +139,91 @@ do_restore(time_t backup_id,
131139
elog(LOG,"searching recent full backup");
132140
for (i=0;i<parray_num(backups);i++)
133141
{
142+
boolsatisfied= false;
143+
134144
base_backup= (pgBackup*)parray_get(backups,i);
135145

136146
if (backup_id&&base_backup->start_time>backup_id)
137147
continue;
138148

139-
if (backup_id==base_backup->start_time&&
140-
base_backup->status==BACKUP_STATUS_OK)
149+
if (backup_id==base_backup->start_time)
141150
{
142-
backup_id_found= true;
151+
/* Checks for target backup */
152+
if (base_backup->status!=BACKUP_STATUS_OK)
153+
elog(ERROR,"given backup %s is in %s status",
154+
base36enc(backup_id),status2str(base_backup->status));
155+
143156
dest_backup=base_backup;
144157
}
145158

146-
if (backup_id==base_backup->start_time&&
147-
base_backup->status!=BACKUP_STATUS_OK)
148-
elog(ERROR,"given backup %s is %s",base36enc(backup_id),
149-
status2str(base_backup->status));
150-
151159
if (dest_backup!=NULL&&
152160
base_backup->backup_mode==BACKUP_MODE_FULL&&
153161
base_backup->status!=BACKUP_STATUS_OK)
154-
elog(ERROR,"base backup %s for given backup %s is%s",
162+
elog(ERROR,"base backup %s for given backup %s isin %s status",
155163
base36enc(base_backup->start_time),
156164
base36enc(dest_backup->start_time),
157165
status2str(base_backup->status));
158166

159-
if (base_backup->backup_mode<BACKUP_MODE_FULL||
160-
base_backup->status!=BACKUP_STATUS_OK)
167+
/* Dont check error backups */
168+
if (base_backup->status!=BACKUP_STATUS_OK||
169+
/* Dont check differential backups if we found latest */
170+
(last_diff_index >=0&&base_backup->backup_mode!=BACKUP_MODE_FULL))
161171
continue;
162172

163173
if (target_tli)
164174
{
165175
if (satisfy_timeline(timelines,base_backup)&&
166176
satisfy_recovery_target(base_backup,rt)&&
167-
(backup_id_found||backup_id==0))
168-
gotobase_backup_found;
177+
(dest_backup||backup_id==0))
178+
satisfied= true;
169179
}
170180
else
171181
if (satisfy_recovery_target(base_backup,rt)&&
172-
(backup_id_found||backup_id==0))
173-
gotobase_backup_found;
182+
(dest_backup||backup_id==0))
183+
satisfied= true;
174184

175-
backup_id_found= false;
185+
/* Target backup should satisfy restore options */
186+
if (backup_id==base_backup->start_time&& !satisfied)
187+
elog(ERROR,"backup %s does not satisfy restore options",
188+
base36enc(base_backup->start_time));
189+
190+
if (satisfied)
191+
{
192+
if (base_backup->backup_mode!=BACKUP_MODE_FULL)
193+
last_diff_index=i;
194+
else
195+
gotobase_backup_found;
196+
}
176197
}
177198
/* no full backup found, cannot restore */
178-
elog(ERROR,"no full backup found, cannot restore.");
199+
elog(ERROR,"no full backup found, cannot restore");
179200

180201
base_backup_found:
181202
base_index=i;
203+
if (last_diff_index==-1)
204+
last_diff_index=base_index;
182205

183-
/* Check if restore destination empty */
184-
if (!dir_is_empty(pgdata))
185-
elog(ERROR,"restore destination is not empty");
186-
187-
print_backup_lsn(base_backup);
188-
189-
if (backup_id!=0)
190-
stream_wal=base_backup->stream;
191-
192-
/* restore base backup */
193-
restore_database(base_backup);
194-
195-
/* restore following differential backup */
196-
elog(LOG,"searching differential backup...");
206+
Assert(last_diff_index <=base_index);
207+
/* Tablespace directories checking */
208+
check_tablespace_mapping((pgBackup*)parray_get(backups,last_diff_index));
197209

198-
for (i=base_index-1;i >=0;i--)
210+
/* Restore backups from base_index to last_diff_index */
211+
need_recovery_conf=target_time!=NULL||target_xid!=NULL;
212+
for (i=base_index;i >=last_diff_index;i--)
199213
{
200-
pgBackup*backup= (pgBackup*)parray_get(backups,i);
201-
202-
/* don't use incomplete nor different timeline backup */
203-
if (backup->status!=BACKUP_STATUS_OK||
204-
backup->tli!=base_backup->tli)
205-
continue;
206-
207-
if (backup->backup_mode==BACKUP_MODE_FULL)
208-
break;
214+
pgBackup*backup= (pgBackup*)parray_get(backups,i);
209215

210-
if (backup_id&&backup->start_time>backup_id)
211-
break;
212-
213-
/* use database backup only */
214-
if (backup->backup_mode!=BACKUP_MODE_DIFF_PAGE&&
215-
backup->backup_mode!=BACKUP_MODE_DIFF_PTRACK)
216-
continue;
217-
218-
/* is the backup is necessary for restore to target timeline ? */
219-
if (target_tli)
216+
if (backup->status==BACKUP_STATUS_OK)
220217
{
221-
if (!satisfy_timeline(timelines,backup)||
222-
!satisfy_recovery_target(backup,rt))
223-
continue;
224-
}
225-
else
226-
if (!satisfy_recovery_target(backup,rt))
227-
continue;
228-
229-
if (backup_id!=0)
230-
stream_wal=backup->stream;
218+
need_recovery_conf=need_recovery_conf|| !backup->stream;
231219

232-
print_backup_lsn(backup);
233-
restore_database(backup);
220+
print_backup_lsn(backup);
221+
restore_database(backup);
222+
}
234223
}
235224

236225
/* create recovery.conf */
237-
if (!stream_wal||target_time!=NULL||target_xid!=NULL)
226+
if (need_recovery_conf)
238227
create_recovery_conf(backup_id,target_time,target_xid,
239228
target_inclusive,base_backup->tli);
240229

@@ -470,9 +459,12 @@ restore_directories(const char *pg_data_dir, const char *backup_dir)
470459
linked_path,dir_created,link_name);
471460
}
472461

473-
/* Check if restore destination empty */
462+
/*
463+
* This check was done in check_tablespace_mapping(). But do
464+
* it again.
465+
*/
474466
if (!dir_is_empty(linked_path))
475-
elog(ERROR,"restore destination is not empty \"%s\"",
467+
elog(ERROR,"restore destination is not empty: \"%s\"",
476468
linked_path);
477469

478470
if (link_sep)
@@ -523,6 +515,65 @@ restore_directories(const char *pg_data_dir, const char *backup_dir)
523515
parray_free(dirs);
524516
}
525517

518+
/*
519+
* Check that all tablespace mapping entries have correct linked directory
520+
* paths. Linked directories should be empty or do not exist.
521+
*
522+
* If tablespace-mapping option is supplied all OLDDIR entries should have
523+
* entries in tablespace_map file.
524+
*/
525+
staticvoid
526+
check_tablespace_mapping(pgBackup*backup)
527+
{
528+
charbackup_path[MAXPGPATH];
529+
parray*links;
530+
size_ti;
531+
TablespaceListCell*cell;
532+
533+
links=parray_new();
534+
535+
pgBackupGetPath(backup,backup_path,lengthof(backup_path),NULL);
536+
read_tablespace_map(links,backup_path);
537+
538+
elog(LOG,"check tablespace directories...");
539+
540+
/* 1 - all linked directories should be empty */
541+
for (i=0;i<parray_num(links);i++)
542+
{
543+
pgFile*link= (pgFile*)parray_get(links,i);
544+
constchar*linked_path=link->linked;
545+
TablespaceListCell*cell;
546+
547+
for (cell=tablespace_dirs.head;cell;cell=cell->next)
548+
if (strcmp(link->linked,cell->old_dir)==0)
549+
{
550+
linked_path=cell->new_dir;
551+
cell->checked= true;
552+
break;
553+
}
554+
555+
if (!is_absolute_path(linked_path))
556+
elog(ERROR,"tablespace directory is not an absolute path: %s\n",
557+
linked_path);
558+
559+
if (!dir_is_empty(linked_path))
560+
elog(ERROR,"restore destination is not empty: \"%s\"",
561+
linked_path);
562+
}
563+
564+
/* 2 - OLDDIR should has an entry in links */
565+
for (cell=tablespace_dirs.head;cell;cell=cell->next)
566+
{
567+
if (!cell->checked)
568+
elog(ERROR,"--tablespace-mapping option's old directory "
569+
"has not an entry in tablespace_map file: \"%s\"",
570+
cell->old_dir);
571+
}
572+
573+
parray_walk(links,pgBackupFree);
574+
parray_free(links);
575+
}
576+
526577
/*
527578
* Restore files into $PGDATA.
528579
*/
@@ -998,6 +1049,8 @@ opt_tablespace_map(pgut_option *opt, const char *arg)
9981049
elog(ERROR,"new directory is not an absolute path in tablespace mapping: %s\n",
9991050
cell->new_dir);
10001051

1052+
cell->checked= false;
1053+
10011054
if (tablespace_dirs.tail)
10021055
tablespace_dirs.tail->next=cell;
10031056
else

‎tests/restore_test.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ def test_restore_with_tablespace_mapping_12(self):
515515

516516
# 1 - Try to restore to existing directory
517517
node.stop()
518-
self.assertEqual(six.b("ERROR: restore destination is not empty\n"),
518+
self.assertIn(six.b("ERROR: restore destination is not empty"),
519519
self.restore_pb(node))
520520

521521
# 2 - Try to restore to existing tablespace directory
@@ -524,7 +524,6 @@ def test_restore_with_tablespace_mapping_12(self):
524524
self.restore_pb(node))
525525

526526
# 3 - Restore using tablespace-mapping
527-
node.cleanup()
528527
tblspc_path_new=path.join(node.base_dir,"tblspc_new")
529528
self.assertIn(six.b("INFO: restore complete."),
530529
self.restore_pb(node,

‎tests/validate_test.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def test_validate_wal_1(self):
5656
id_backup=self.show_pb(node)[0].id
5757

5858
# Validate to real time
59-
self.assertIn(six.b("INFO:Backup validationstopped on"),
59+
self.assertIn(six.b("INFO:backup validationcompleted successfully on"),
6060
self.validate_pb(node,options=["--time='{:%Y-%m-%d %H:%M:%S}'".format(
6161
target_time)]))
6262

@@ -66,20 +66,20 @@ def test_validate_wal_1(self):
6666
target_time-timedelta(days=2))]))
6767

6868
# Validate to unreal time #2
69-
self.assertIn(six.b("ERROR:there are no WAL records to time"),
69+
self.assertIn(six.b("ERROR:not enough WAL records to time"),
7070
self.validate_pb(node,options=["--time='{:%Y-%m-%d %H:%M:%S}'".format(
7171
target_time+timedelta(days=2))]))
7272

7373
# Validate to real xid
74-
self.assertIn(six.b("INFO:Backup validationstopped on"),
74+
self.assertIn(six.b("INFO:backup validationcompleted successfully on"),
7575
self.validate_pb(node,options=["--xid=%s"%target_xid]))
7676

7777
# Validate to unreal xid
78-
self.assertIn(six.b("ERROR:there are no WAL records to xid"),
78+
self.assertIn(six.b("ERROR:not enough WAL records to xid"),
7979
self.validate_pb(node,options=["--xid=%d"% (int(target_xid)+1000)]))
8080

8181
# Validate with backup ID
82-
self.assertIn(six.b("INFO:Backup validationstopped on"),
82+
self.assertIn(six.b("INFO:backup validationcompleted successfully on"),
8383
self.validate_pb(node,id_backup))
8484

8585
# Validate broken WAL
@@ -91,4 +91,4 @@ def test_validate_wal_1(self):
9191
f.write(six.b("blablabla"))
9292

9393
res=self.validate_pb(node,id_backup,options=['--xid=%s'%target_xid])
94-
self.assertIn(six.b("there are no WAL records to xid"),res)
94+
self.assertIn(six.b("not enough WAL records to xid"),res)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp