@ -45,7 +45,13 @@ static void digestControlFile(ControlFileData *ControlFile,
const char * content , size_t size ) ;
static void getRestoreCommand ( const char * argv0 ) ;
static void sanityChecks ( void ) ;
static void findCommonAncestorTimeline ( XLogRecPtr * recptr , int * tliIndex ) ;
static TimeLineHistoryEntry * getTimelineHistory ( TimeLineID tli , bool is_source ,
int * nentries ) ;
static void findCommonAncestorTimeline ( TimeLineHistoryEntry * a_history ,
int a_nentries ,
TimeLineHistoryEntry * b_history ,
int b_nentries ,
XLogRecPtr * recptr , int * tliIndex ) ;
static void ensureCleanShutdown ( const char * argv0 ) ;
static void disconnect_atexit ( void ) ;
@ -134,6 +140,8 @@ main(int argc, char **argv)
XLogRecPtr chkptrec ;
TimeLineID chkpttli ;
XLogRecPtr chkptredo ;
TimeLineID source_tli ;
TimeLineID target_tli ;
XLogRecPtr target_wal_endrec ;
size_t size ;
char * buffer ;
@ -332,14 +340,28 @@ main(int argc, char **argv)
sanityChecks ( ) ;
/*
* Usually , the TLI can be found in the latest checkpoint record . But if
* the source server is just being promoted ( or it ' s a standby that ' s
* following a primary that ' s just being promoted ) , and the checkpoint
* requested by the promotion hasn ' t completed yet , the latest timeline is
* in minRecoveryPoint . So we check which is later , the TLI of the
* minRecoveryPoint or the latest checkpoint .
*/
source_tli = Max ( ControlFile_source . minRecoveryPointTLI ,
ControlFile_source . checkPointCopy . ThisTimeLineID ) ;
/* Similarly for the target. */
target_tli = Max ( ControlFile_target . minRecoveryPointTLI ,
ControlFile_target . checkPointCopy . ThisTimeLineID ) ;
/*
* Find the common ancestor timeline between the clusters .
*
* If both clusters are already on the same timeline , there ' s nothing to
* do .
*/
if ( ControlFile_target . checkPointCopy . ThisTimeLineID = =
ControlFile_source . checkPointCopy . ThisTimeLineID )
if ( target_tli = = source_tli )
{
pg_log_info ( " source and target cluster are on the same timeline " ) ;
rewind_needed = false ;
@ -348,12 +370,31 @@ main(int argc, char **argv)
else
{
XLogRecPtr chkptendrec ;
TimeLineHistoryEntry * sourceHistory ;
int sourceNentries ;
/*
* Retrieve timelines for both source and target , and find the point
* where they diverged .
*/
sourceHistory = getTimelineHistory ( source_tli , true , & sourceNentries ) ;
targetHistory = getTimelineHistory ( target_tli , false , & targetNentries ) ;
findCommonAncestorTimeline ( sourceHistory , sourceNentries ,
targetHistory , targetNentries ,
& divergerec , & lastcommontliIndex ) ;
findCommonAncestorTimeline ( & divergerec , & lastcommontliIndex ) ;
pg_log_info ( " servers diverged at WAL location %X/%X on timeline %u " ,
LSN_FORMAT_ARGS ( divergerec ) ,
targetHistory [ lastcommontliIndex ] . tli ) ;
/*
* Don ' t need the source history anymore . The target history is still
* needed by the routines in parsexlog . c , when we read the target WAL .
*/
pfree ( sourceHistory ) ;
/*
* Determine the end - of - WAL on the target .
*
@ -654,7 +695,8 @@ perform_rewind(filemap_t *filemap, rewind_source *source,
pg_fatal ( " source system was in unexpected state at end of rewind " ) ;
endrec = source - > get_current_wal_insert_lsn ( source ) ;
endtli = ControlFile_source_after . checkPointCopy . ThisTimeLineID ;
endtli = Max ( ControlFile_source_after . checkPointCopy . ThisTimeLineID ,
ControlFile_source_after . minRecoveryPointTLI ) ;
}
}
else
@ -796,16 +838,12 @@ MinXLogRecPtr(XLogRecPtr a, XLogRecPtr b)
}
/*
* Retrieve timeline history for given control file which should behold
* either source or target .
* Retrieve timeline history for the source or target system .
*/
static TimeLineHistoryEntry *
getTimelineHistory ( ControlFileData * controlFil e, int * nentries )
getTimelineHistory ( TimeLineID tli , bool is_sourc e, int * nentries )
{
TimeLineHistoryEntry * history ;
TimeLineID tli ;
tli = controlFile - > checkPointCopy . ThisTimeLineID ;
/*
* Timeline 1 does not have a history file , so there is no need to check
@ -826,12 +864,10 @@ getTimelineHistory(ControlFileData *controlFile, int *nentries)
TLHistoryFilePath ( path , tli ) ;
/* Get history file from appropriate source */
if ( controlF ile = = & ControlFile _source)
if ( is _source )
histfile = source - > fetch_file ( source , path , NULL ) ;
else if ( controlFile = = & ControlFile_target )
histfile = slurpFile ( datadir_target , path , NULL ) ;
else
pg_fatal ( " invalid control file " ) ;
histfile = slurpFile ( datadir_target , path , NULL ) ;
history = rewind_parseTimeLineHistory ( histfile , tli , nentries ) ;
pg_free ( histfile ) ;
@ -841,12 +877,10 @@ getTimelineHistory(ControlFileData *controlFile, int *nentries)
{
int i ;
if ( controlF ile = = & ControlFile _source)
if ( is _source )
pg_log_debug ( " Source timeline history: " ) ;
else if ( controlFile = = & ControlFile_target )
pg_log_debug ( " Target timeline history: " ) ;
else
Assert ( false ) ;
pg_log_debug ( " Target timeline history: " ) ;
/*
* Print the target timeline history .
@ -866,28 +900,19 @@ getTimelineHistory(ControlFileData *controlFile, int *nentries)
}
/*
* Determine the TLI of the last common timeline in the timeline history of the
* two clusters . targetHistory is filled with target timeline history and
* targetNentries is number of items in targetHistory . * tliIndex is set to the
* index of last common timeline in targetHistory array , and * recptr is set to
* the position where the timeline history diverged ( ie . the first WAL record
* that ' s not the same in both clusters ) .
*
* Control files of both clusters must be read into ControlFile_target / source
* before calling this routine .
* Determine the TLI of the last common timeline in the timeline history of
* two clusters . * tliIndex is set to the index of last common timeline in
* the arrays , and * recptr is set to the position where the timeline history
* diverged ( ie . the first WAL record that ' s not the same in both clusters ) .
*/
static void
findCommonAncestorTimeline ( XLogRecPtr * recptr , int * tliIndex )
findCommonAncestorTimeline ( TimeLineHistoryEntry * a_history , int a_nentries ,
TimeLineHistoryEntry * b_history , int b_nentries ,
XLogRecPtr * recptr , int * tliIndex )
{
TimeLineHistoryEntry * sourceHistory ;
int sourceNentries ;
int i ,
n ;
/* Retrieve timelines for both source and target */
sourceHistory = getTimelineHistory ( & ControlFile_source , & sourceNentries ) ;
targetHistory = getTimelineHistory ( & ControlFile_target , & targetNentries ) ;
/*
* Trace the history forward , until we hit the timeline diverge . It may
* still be possible that the source and target nodes used the same
@ -896,21 +921,19 @@ findCommonAncestorTimeline(XLogRecPtr *recptr, int *tliIndex)
* recovery processes . Hence check the start position of the new timeline
* as well and move down by one extra timeline entry if they do not match .
*/
n = Min ( sourceNentries , targetN entries) ;
n = Min ( a_nentries , b_n entries) ;
for ( i = 0 ; i < n ; i + + )
{
if ( sourceH istory[ i ] . tli ! = targetH istory[ i ] . tli | |
sourceH istory[ i ] . begin ! = targetH istory[ i ] . begin )
if ( a_h istory[ i ] . tli ! = b_h istory[ i ] . tli | |
a_h istory[ i ] . begin ! = b_h istory[ i ] . begin )
break ;
}
if ( i > 0 )
{
i - - ;
* recptr = MinXLogRecPtr ( sourceH istory[ i ] . end , targetH istory[ i ] . end ) ;
* recptr = MinXLogRecPtr ( a_h istory[ i ] . end , b_h istory[ i ] . end ) ;
* tliIndex = i ;
pg_free ( sourceHistory ) ;
return ;
}
else