@@ -41,6 +41,7 @@ const char *progname = "pg_arman";
41
41
parray * backup_files_list ;
42
42
static volatile uint32 total_copy_files_increment ;
43
43
static uint32 total_files_num ;
44
+ static PGconn * start_stop_connect = NULL ;
44
45
45
46
typedef struct
46
47
{
@@ -61,7 +62,7 @@ static void confirm_block_size(const char *name, int blcksz);
61
62
static void pg_start_backup (const char * label , bool smooth , pgBackup * backup );
62
63
static void pg_stop_backup (pgBackup * backup );
63
64
static bool pg_is_standby (void );
64
- static void get_lsn (PGresult * res , XLogRecPtr * lsn );
65
+ static void get_lsn (PGconn * conn , PGresult * res , XLogRecPtr * lsn , bool stop_backup );
65
66
static void get_xid (PGresult * res , uint32 * xid );
66
67
static void pg_ptrack_clear (void );
67
68
static char * pg_ptrack_get_and_clear (Oid tablespace_oid ,
@@ -74,7 +75,7 @@ static void create_file_list(parray *files,
74
75
const char * subdir ,
75
76
const char * prefix ,
76
77
bool is_append );
77
- static void wait_for_archive (pgBackup * backup , const char * sql );
78
+ static void wait_for_archive (PGconn * conn , pgBackup * backup , const char * sql , bool stop_backup );
78
79
static void make_pagemap_from_ptrack (parray * files );
79
80
static void StreamLog (void * arg );
80
81
@@ -112,7 +113,7 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt)
112
113
pgBackup * prev_backup = NULL ;
113
114
114
115
/* Block backup operations on a standby */
115
- if (pg_is_standby ())
116
+ if (pg_is_standby () && ! from_replica )
116
117
elog (ERROR , "Backup cannot run on a standby." );
117
118
118
119
elog (LOG , "database backup start" );
@@ -164,18 +165,21 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt)
164
165
strncat (label , " with pg_arman" , lengthof (label ));
165
166
pg_start_backup (label , smooth_checkpoint , & current );
166
167
167
- /* If backup_label does not exist in $PGDATA, stop taking backup */
168
- snprintf (path , lengthof (path ), "%s/backup_label" , pgdata );
169
- make_native_path (path );
170
- if (!fileExists (path ))
171
- has_backup_label = false;
172
-
173
- /* Leave if no backup file */
174
- if (!has_backup_label )
168
+ if (!from_replica )
175
169
{
176
- elog (LOG , "backup_label does not exist, stopping backup" );
177
- pg_stop_backup (NULL );
178
- elog (ERROR , "backup_label does not exist in PGDATA." );
170
+ /* If backup_label does not exist in $PGDATA, stop taking backup */
171
+ snprintf (path , lengthof (path ), "%s/backup_label" , pgdata );
172
+ make_native_path (path );
173
+ if (!fileExists (path ))
174
+ has_backup_label = false;
175
+
176
+ /* Leave if no backup file */
177
+ if (!has_backup_label )
178
+ {
179
+ elog (LOG , "backup_label does not exist, stopping backup" );
180
+ pg_stop_backup (NULL );
181
+ elog (ERROR , "backup_label does not exist in PGDATA." );
182
+ }
179
183
}
180
184
181
185
/*
@@ -246,7 +250,7 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt)
246
250
if (current .backup_mode == BACKUP_MODE_DIFF_PAGE )
247
251
{
248
252
/* Enforce archiving of last segment and wait for it to be here */
249
- wait_for_archive (& current , "SELECT * FROM pg_switch_xlog()" );
253
+ wait_for_archive (connection , & current , "SELECT * FROM pg_switch_xlog()" , false );
250
254
251
255
/* Now build the page map */
252
256
parray_qsort (backup_files_list , pgFileComparePathDesc );
@@ -563,6 +567,13 @@ check_server_version(void)
563
567
(server_version / 100 ) % 100 ,
564
568
server_version % 100 , "9.5" );
565
569
570
+ if (from_replica && server_version < 90600 )
571
+ elog (ERROR ,
572
+ "server version is %d.%d.%d, must be %s or higher for backup from replica." ,
573
+ server_version / 10000 ,
574
+ (server_version / 100 ) % 100 ,
575
+ server_version % 100 , "9.6" );
576
+
566
577
/* confirm block_size (BLCKSZ) and wal_block_size (XLOG_BLCKSZ) */
567
578
confirm_block_size ("block_size" , BLCKSZ );
568
579
confirm_block_size ("wal_block_size" , XLOG_BLCKSZ );
@@ -601,16 +612,27 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup)
601
612
602
613
params [0 ] = label ;
603
614
604
- reconnect ();
615
+ if (start_stop_connect == NULL )
616
+ start_stop_connect = pgut_connect (ERROR );
605
617
606
618
/* 2nd argument is 'fast'*/
607
619
params [1 ] = smooth ? "false" : "true" ;
608
- res = execute ("SELECT pg_start_backup($1, $2)" , 2 , params );
620
+ if (from_replica )
621
+ res = pgut_execute (start_stop_connect ,
622
+ "SELECT pg_start_backup($1, $2, false)" ,
623
+ 2 ,
624
+ params ,
625
+ ERROR );
626
+ else
627
+ res = pgut_execute (start_stop_connect ,
628
+ "SELECT pg_start_backup($1, $2)" ,
629
+ 2 ,
630
+ params ,
631
+ ERROR );
609
632
610
633
if (backup != NULL )
611
- get_lsn (res , & backup -> start_lsn );
634
+ get_lsn (start_stop_connect , res , & backup -> start_lsn , false );
612
635
PQclear (res );
613
- disconnect ();
614
636
}
615
637
616
638
static void
@@ -670,7 +692,7 @@ pg_ptrack_get_and_clear(Oid tablespace_oid, Oid db_oid, Oid rel_oid, size_t *res
670
692
}
671
693
672
694
static void
673
- wait_for_archive (pgBackup * backup , const char * sql )
695
+ wait_for_archive (PGconn * conn , pgBackup * backup , const char * sql , bool stop_backup )
674
696
{
675
697
PGresult * res ;
676
698
char ready_path [MAXPGPATH ];
@@ -680,17 +702,18 @@ wait_for_archive(pgBackup *backup, const char *sql)
680
702
TimeLineID tli ;
681
703
XLogSegNo targetSegNo ;
682
704
683
- reconnect ();
705
+ if (conn == NULL )
706
+ conn = pgut_connect (ERROR );
684
707
685
708
/* Remove annoying NOTICE messages generated by backend */
686
- res = execute ( "SET client_min_messages = warning;" , 0 , NULL );
709
+ res = pgut_execute ( conn , "SET client_min_messages = warning;" , 0 , NULL , ERROR );
687
710
PQclear (res );
688
711
689
712
/* And execute the query wanted */
690
- res = execute ( sql , 0 , NULL );
713
+ res = pgut_execute ( conn , sql , 0 , NULL , ERROR );
691
714
692
715
/* Get LSN from execution result */
693
- get_lsn (res , & lsn );
716
+ get_lsn (conn , res , & lsn , stop_backup );
694
717
695
718
/*
696
719
* Enforce TLI obtention if backup is not present as this code
@@ -720,13 +743,15 @@ wait_for_archive(pgBackup *backup, const char *sql)
720
743
721
744
PQclear (res );
722
745
723
- res = execute (TXID_CURRENT_SQL , 0 , NULL );
746
+ if (from_replica )
747
+ res = pgut_execute (conn , TXID_CURRENT_IF_SQL , 0 , NULL , ERROR );
748
+ else
749
+ res = pgut_execute (conn , TXID_CURRENT_SQL , 0 , NULL , ERROR );
724
750
if (backup != NULL )
725
751
{
726
752
get_xid (res , & backup -> recovery_xid );
727
753
backup -> recovery_time = time (NULL );
728
754
}
729
- disconnect ();
730
755
731
756
/* wait until switched WAL is archived */
732
757
try_count = 0 ;
@@ -756,17 +781,22 @@ pg_stop_backup(pgBackup *backup)
756
781
PGresult * res ;
757
782
TimeLineID tli ;
758
783
759
- reconnect ();
784
+ //reconnect();
785
+ if (start_stop_connect == NULL )
786
+ start_stop_connect = pgut_connect (ERROR );
760
787
761
788
/* Remove annoying NOTICE messages generated by backend */
762
- res = execute ( "SET client_min_messages = warning;" , 0 , NULL );
789
+ res = pgut_execute ( start_stop_connect , "SET client_min_messages = warning;" , 0 , NULL , ERROR );
763
790
PQclear (res );
764
791
765
792
/* And execute the query wanted */
766
- res = execute ("SELECT * FROM pg_stop_backup()" , 0 , NULL );
793
+ if (from_replica )
794
+ res = pgut_execute (start_stop_connect ,"SELECT * FROM pg_stop_backup(false)" , 0 , NULL , ERROR );
795
+ else
796
+ res = pgut_execute (start_stop_connect ,"SELECT * FROM pg_stop_backup()" , 0 , NULL , ERROR );
767
797
768
798
/* Get LSN from execution result */
769
- get_lsn (res , & stop_backup_lsn );
799
+ get_lsn (start_stop_connect , res , & stop_backup_lsn , true );
770
800
PQclear (res );
771
801
772
802
/*
@@ -786,18 +816,33 @@ pg_stop_backup(pgBackup *backup)
786
816
(uint32 ) backup -> stop_lsn );
787
817
}
788
818
789
- res = execute (TXID_CURRENT_SQL , 0 , NULL );
819
+ if (from_replica )
820
+ res = pgut_execute (start_stop_connect , TXID_CURRENT_IF_SQL , 0 , NULL , ERROR );
821
+ else
822
+ res = pgut_execute (start_stop_connect , TXID_CURRENT_SQL , 0 , NULL , ERROR );
790
823
if (backup != NULL )
791
824
{
792
825
get_xid (res , & backup -> recovery_xid );
793
826
backup -> recovery_time = time (NULL );
794
827
}
795
828
PQclear (res );
796
- disconnect ();
829
+ //disconnect();
830
+ pgut_disconnect (start_stop_connect );
797
831
}
798
832
else
799
- wait_for_archive (backup ,
800
- "SELECT * FROM pg_stop_backup()" );
833
+ {
834
+ if (from_replica )
835
+ wait_for_archive (start_stop_connect ,
836
+ backup ,
837
+ "SELECT * FROM pg_stop_backup(false)" ,
838
+ true);
839
+ else
840
+ wait_for_archive (start_stop_connect ,
841
+ backup ,
842
+ "SELECT * FROM pg_stop_backup()" ,
843
+ true);
844
+ pgut_disconnect (start_stop_connect );
845
+ }
801
846
}
802
847
803
848
@@ -818,15 +863,15 @@ pg_is_standby(void)
818
863
* Get LSN from result of pg_start_backup() or pg_stop_backup().
819
864
*/
820
865
static void
821
- get_lsn (PGresult * res , XLogRecPtr * lsn )
866
+ get_lsn (PGconn * conn , PGresult * res , XLogRecPtr * lsn , bool stop_backup )
822
867
{
823
868
uint32 xlogid ;
824
869
uint32 xrecoff ;
825
870
826
- if (res == NULL || PQntuples (res ) != 1 || PQnfields (res ) != 1 )
871
+ if (res == NULL || PQntuples (res ) != 1 || ( PQnfields (res ) != 1 && PQnfields ( res ) != 3 ) )
827
872
elog (ERROR ,
828
873
"result of backup command is invalid: %s" ,
829
- PQerrorMessage (connection ));
874
+ PQerrorMessage (conn ));
830
875
831
876
/*
832
877
* Extract timeline and LSN from results of pg_stop_backup()
@@ -836,6 +881,36 @@ get_lsn(PGresult *res, XLogRecPtr *lsn)
836
881
XLogDataFromLSN (PQgetvalue (res , 0 , 0 ), & xlogid , & xrecoff );
837
882
/* Calculate LSN */
838
883
* lsn = (XLogRecPtr ) ((uint64 ) xlogid << 32 ) | xrecoff ;
884
+
885
+ if (stop_backup && from_replica && PQnfields (res ) == 3 )
886
+ {
887
+ char path [MAXPGPATH ];
888
+ char path_backup_label [MAXPGPATH ];
889
+ char path_tablespace_map [MAXPGPATH ];
890
+ FILE * fp ;
891
+
892
+ pgBackupGetPath (& current , path , lengthof (path ), DATABASE_DIR );
893
+ snprintf (path_backup_label , lengthof (path_backup_label ), "%s/backup_label" , path );
894
+ snprintf (path_tablespace_map , lengthof (path_tablespace_map ), "%s/tablespace_map" , path );
895
+
896
+ fp = fopen (path_backup_label , "w" );
897
+ if (fp == NULL )
898
+ elog (ERROR , "can't open backup label file \"%s\": %s" ,
899
+ path_backup_label , strerror (errno ));
900
+
901
+ fwrite (PQgetvalue (res , 0 , 1 ), 1 , strlen (PQgetvalue (res , 0 , 1 )), fp );
902
+ fclose (fp );
903
+ if (strlen (PQgetvalue (res , 0 , 2 )) == 0 )
904
+ return ;
905
+
906
+ fp = fopen (path_tablespace_map , "w" );
907
+ if (fp == NULL )
908
+ elog (ERROR , "can't open tablespace map file \"%s\": %s" ,
909
+ path_tablespace_map , strerror (errno ));
910
+
911
+ fwrite (PQgetvalue (res , 0 , 2 ), 1 , strlen (PQgetvalue (res , 0 , 2 )), fp );
912
+ fclose (fp );
913
+ }
839
914
}
840
915
841
916
/*
0 commit comments