@@ -30,6 +30,8 @@ typedef struct TablespaceListCell
3030struct TablespaceListCell * next ;
3131char old_dir [MAXPGPATH ];
3232char new_dir [MAXPGPATH ];
33+ bool checked ;/* If this mapping was checked during
34+ restore */
3335}TablespaceListCell ;
3436
3537typedef struct TablespaceList
@@ -54,6 +56,7 @@ typedef struct TablespaceCreatedList
5456static void restore_database (pgBackup * backup );
5557static void restore_directories (const char * pg_data_dir ,
5658const char * backup_dir );
59+ static void check_tablespace_mapping (pgBackup * backup );
5760static void create_recovery_conf (time_t backup_id ,
5861const char * target_time ,
5962const char * target_xid ,
@@ -82,20 +85,25 @@ do_restore(time_t backup_id,
8285{
8386int i ;
8487int base_index ;/* index of base (full) backup */
88+ int last_diff_index = -1 ;/* index of last differential backup */
8589int ret ;
8690parray * backups ;
8791
8892parray * timelines ;
8993pgBackup * base_backup = NULL ;
9094pgBackup * dest_backup = NULL ;
9195pgRecoveryTarget * rt = NULL ;
92- bool backup_id_found = false;
96+ bool need_recovery_conf = false;
9397
9498/* PGDATA and ARCLOG_PATH are always required */
9599if (pgdata == NULL )
96100elog (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+
99107elog (LOG ,"========================================" );
100108elog (LOG ,"restore start" );
101109
@@ -131,110 +139,91 @@ do_restore(time_t backup_id,
131139elog (LOG ,"searching recent full backup" );
132140for (i = 0 ;i < parray_num (backups );i ++ )
133141{
142+ bool satisfied = false;
143+
134144base_backup = (pgBackup * )parray_get (backups ,i );
135145
136146if (backup_id && base_backup -> start_time > backup_id )
137147continue ;
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+
143156dest_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-
151159if (dest_backup != NULL &&
152160base_backup -> backup_mode == BACKUP_MODE_FULL &&
153161base_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 " ,
155163base36enc (base_backup -> start_time ),
156164base36enc (dest_backup -> start_time ),
157165status2str (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 ))
161171continue ;
162172
163173if (target_tli )
164174{
165175if (satisfy_timeline (timelines ,base_backup )&&
166176satisfy_recovery_target (base_backup ,rt )&&
167- (backup_id_found || backup_id == 0 ))
168- goto base_backup_found ;
177+ (dest_backup || backup_id == 0 ))
178+ satisfied = true ;
169179}
170180else
171181if (satisfy_recovery_target (base_backup ,rt )&&
172- (backup_id_found || backup_id == 0 ))
173- goto base_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
180201base_backup_found :
181202base_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 )
238227create_recovery_conf (backup_id ,target_time ,target_xid ,
239228target_inclusive ,base_backup -> tli );
240229
@@ -470,9 +459,12 @@ restore_directories(const char *pg_data_dir, const char *backup_dir)
470459linked_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+ */
474466if (!dir_is_empty (linked_path ))
475- elog (ERROR ,"restore destination is not empty \"%s\"" ,
467+ elog (ERROR ,"restore destination is not empty: \"%s\"" ,
476468linked_path );
477469
478470if (link_sep )
@@ -523,6 +515,65 @@ restore_directories(const char *pg_data_dir, const char *backup_dir)
523515parray_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+ static void
526+ check_tablespace_mapping (pgBackup * backup )
527+ {
528+ char backup_path [MAXPGPATH ];
529+ parray * links ;
530+ size_t i ;
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+ const char * 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)
9981049elog (ERROR ,"new directory is not an absolute path in tablespace mapping: %s\n" ,
9991050cell -> new_dir );
10001051
1052+ cell -> checked = false;
1053+
10011054if (tablespace_dirs .tail )
10021055tablespace_dirs .tail -> next = cell ;
10031056else