17
17
#include <dirent.h>
18
18
#include <time.h>
19
19
20
+ #include "catalog/pg_control.h"
20
21
#include "libpq/pqsignal.h"
21
22
#include "pgut/pgut-port.h"
22
23
@@ -48,7 +49,7 @@ static void confirm_block_size(const char *name, int blcksz);
48
49
static void pg_start_backup (const char * label ,bool smooth ,pgBackup * backup );
49
50
static void pg_stop_backup (pgBackup * backup );
50
51
static void pg_switch_xlog (pgBackup * backup );
51
- static void get_lsn (PGresult * res ,TimeLineID * timeline , XLogRecPtr * lsn );
52
+ static void get_lsn (PGresult * res ,XLogRecPtr * lsn );
52
53
static void get_xid (PGresult * res ,uint32 * xid );
53
54
static bool execute_restartpoint (pgBackupOption bkupopt );
54
55
@@ -60,6 +61,7 @@ static bool dirExists(const char *path);
60
61
static void add_files (parray * files ,const char * root ,bool add_root ,bool is_pgdata );
61
62
static int strCompare (const void * str1 ,const void * str2 );
62
63
static void create_file_list (parray * files ,const char * root ,const char * prefix ,bool is_append );
64
+ static TimeLineID get_current_timeline (void );
63
65
64
66
/*
65
67
* Take a backup of database.
@@ -108,6 +110,13 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt)
108
110
current .total_data_bytes = 0 ;
109
111
current .read_data_bytes = 0 ;
110
112
113
+ /*
114
+ * Obtain current timeline by scanning control file, theh LSN
115
+ * obtained at output of pg_start_backup or pg_stop_backup does
116
+ * not contain this information.
117
+ */
118
+ current .tli = get_current_timeline ();
119
+
111
120
/* notify start of backup to PostgreSQL server */
112
121
time2iso (label ,lengthof (label ),current .start_time );
113
122
strncat (label ," with pg_rman" ,lengthof (label ));
@@ -492,8 +501,8 @@ do_backup_arclog(parray *backup_list)
492
501
pg_switch_xlog (& current );
493
502
494
503
/*
495
- * To take incremental backup, the file list of the last completed database
496
- * backup is needed.
504
+ * To take incremental backup, the file list of the last completed
505
+ *database backup is needed.
497
506
*/
498
507
prev_backup = catalog_get_last_arclog_backup (backup_list );
499
508
if (verbose && prev_backup == NULL )
@@ -985,10 +994,10 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup)
985
994
986
995
/* 2nd argument is 'fast'*/
987
996
params [1 ]= smooth ?"false" :"true" ;
988
- res = execute ("SELECT* from pg_xlogfile_name_offset( pg_start_backup($1, $2) )" ,2 ,params );
997
+ res = execute ("SELECT pg_start_backup($1, $2)" ,2 ,params );
989
998
990
999
if (backup != NULL )
991
- get_lsn (res ,& backup -> tli , & backup -> start_lsn );
1000
+ get_lsn (res ,& backup -> start_lsn );
992
1001
PQclear (res );
993
1002
disconnect ();
994
1003
}
@@ -998,22 +1007,42 @@ wait_for_archive(pgBackup *backup, const char *sql)
998
1007
{
999
1008
PGresult * res ;
1000
1009
char ready_path [MAXPGPATH ];
1010
+ char file_name [MAXFNAMELEN ];
1001
1011
int try_count ;
1012
+ XLogRecPtr lsn ;
1013
+ TimeLineID tli ;
1002
1014
1003
1015
reconnect ();
1004
1016
res = execute (sql ,0 ,NULL );
1017
+
1018
+ /* Get LSN from execution result */
1019
+ get_lsn (res ,& lsn );
1020
+
1021
+ /*
1022
+ * Enforce TLI obtention if backup is not present as this code
1023
+ * path can be taken as a callback at exit.
1024
+ */
1025
+ if (backup != NULL )
1026
+ tli = backup -> tli ;
1027
+ else
1028
+ tli = get_current_timeline ();
1029
+
1030
+ /* Fill in fields if backup exists */
1005
1031
if (backup != NULL )
1006
1032
{
1007
- get_lsn ( res , & backup -> tli , & backup -> stop_lsn ) ;
1033
+ backup -> stop_lsn = lsn ;
1008
1034
elog (LOG ,_ ("%s(): tli=%X lsn=%X/%08X" ),
1009
1035
__FUNCTION__ ,backup -> tli ,
1010
1036
(uint32 ) (backup -> stop_lsn >>32 ),
1011
1037
(uint32 )backup -> stop_lsn );
1012
1038
}
1013
1039
1014
- /* get filename from the result of pg_xlogfile_name_offset() */
1040
+ /* As well as WAL file name */
1041
+ XLogFileName (file_name ,tli ,lsn );
1042
+
1015
1043
snprintf (ready_path ,lengthof (ready_path ),
1016
- "%s/pg_xlog/archive_status/%s.ready" ,pgdata ,PQgetvalue (res ,0 ,0 ));
1044
+ "%s/pg_xlog/archive_status/%s.ready" ,pgdata ,
1045
+ file_name );
1017
1046
elog (LOG ,"%s() wait for %s" ,__FUNCTION__ ,ready_path );
1018
1047
1019
1048
PQclear (res );
@@ -1049,32 +1078,41 @@ static void
1049
1078
pg_stop_backup (pgBackup * backup )
1050
1079
{
1051
1080
wait_for_archive (backup ,
1052
- "SELECT * FROMpg_xlogfile_name_offset( pg_stop_backup() )" );
1081
+ "SELECT * FROM pg_stop_backup()" );
1053
1082
}
1054
1083
1055
1084
/*
1056
- * Force switch to a new transaction log file and update backup->tli.
1085
+ * Force switch to a new transaction log file
1057
1086
*/
1058
1087
static void
1059
1088
pg_switch_xlog (pgBackup * backup )
1060
1089
{
1061
1090
wait_for_archive (backup ,
1062
- "SELECT * FROMpg_xlogfile_name_offset( pg_switch_xlog())" );
1091
+ "SELECT * FROM pg_switch_xlog())" );
1063
1092
}
1064
1093
1065
1094
/*
1066
- * GetTimeLineID and LSN from result ofpg_xlogfile_name_offset ().
1095
+ * Get LSN from result ofpg_start_backup() or pg_stop_backup ().
1067
1096
*/
1068
1097
static void
1069
- get_lsn (PGresult * res ,TimeLineID * timeline , XLogRecPtr * lsn )
1098
+ get_lsn (PGresult * res ,XLogRecPtr * lsn )
1070
1099
{
1071
- if (res == NULL || PQntuples (res )!= 1 || PQnfields (res )!= 2 )
1100
+ uint32 xlogid ;
1101
+ uint32 xrecoff ;
1102
+
1103
+ if (res == NULL || PQntuples (res )!= 1 || PQnfields (res )!= 1 )
1072
1104
elog (ERROR_PG_COMMAND ,
1073
- _ ("result ofpg_xlogfile_name_offset() is invalid: %s" ),
1105
+ _ ("result ofbackup command is invalid: %s" ),
1074
1106
PQerrorMessage (connection ));
1075
1107
1076
- /* Extract timeline and LSN from result of pg_stop_backup() */
1077
- XLogFromFileName (PQgetvalue (res ,0 ,0 ),timeline ,lsn );
1108
+ /*
1109
+ * Extract timeline and LSN from results of pg_stop_backup()
1110
+ * and friends.
1111
+ */
1112
+ XLogDataFromLSN (PQgetvalue (res ,0 ,0 ),& xlogid ,& xrecoff );
1113
+
1114
+ /* Calculate LSN */
1115
+ * lsn = (XLogRecPtr ) ((uint64 )xlogid <<32 ) |xrecoff ;
1078
1116
}
1079
1117
1080
1118
/*
@@ -1598,3 +1636,27 @@ create_file_list(parray *files, const char *root, const char *prefix, bool is_ap
1598
1636
fclose (fp );
1599
1637
}
1600
1638
}
1639
+
1640
+ /*
1641
+ * Scan control file of given cluster at obtain the current timeline
1642
+ * since last checkpoint that occurred on it.
1643
+ */
1644
+ static TimeLineID
1645
+ get_current_timeline (void )
1646
+ {
1647
+ char * buffer ;
1648
+ size_t size ;
1649
+ ControlFileData control_file ;
1650
+
1651
+ /* First fetch file... */
1652
+ buffer = slurpFile (pgdata ,"global/pg_control" ,& size );
1653
+
1654
+ /* .. Then interpret it */
1655
+ if (size != PG_CONTROL_SIZE )
1656
+ elog (ERROR_CORRUPTED ,"unexpected control file size %d, expected %d\n" ,
1657
+ (int )size ,PG_CONTROL_SIZE );
1658
+ memcpy (& control_file ,buffer ,sizeof (ControlFileData ));
1659
+
1660
+ /* Finally return the timeline wanted */
1661
+ return control_file .checkPointCopy .ThisTimeLineID ;
1662
+ }