@ -38,16 +38,13 @@
# include "libpq/pqsignal.h"
# include "miscadmin.h"
# include "pgstat.h"
# include "postmaster/fork_process.h"
# include "postmaster/interrupt.h"
# include "postmaster/pgarch.h"
# include "postmaster/postmaster.h"
# include "storage/dsm.h"
# include "storage/fd.h"
# include "storage/ipc.h"
# include "storage/latch.h"
# include "storage/pg_shmem.h"
# include "storage/pmsignal.h"
# include "storage/procsignal.h"
# include "utils/guc.h"
# include "utils/ps_status.h"
@ -73,153 +70,99 @@
*/
# define NUM_ORPHAN_CLEANUP_RETRIES 3
/* Shared memory area for archiver process */
typedef struct PgArchData
{
int pgprocno ; /* pgprocno of archiver process */
} PgArchData ;
/* ----------
* Local data
* - - - - - - - - - -
*/
static time_t last_pgarch_start_time ;
static time_t last_sigterm_time = 0 ;
static PgArchData * PgArch = NULL ;
/*
* Flags set by interrupt handlers for later service in the main loop .
*/
static volatile sig_atomic_t wakened = false ;
static volatile sig_atomic_t ready_to_stop = false ;
/* ----------
* Local function forward declarations
* - - - - - - - - - -
*/
# ifdef EXEC_BACKEND
static pid_t pgarch_forkexec ( void ) ;
# endif
NON_EXEC_STATIC void PgArchiverMain ( int argc , char * argv [ ] ) pg_attribute_noreturn ( ) ;
static void pgarch_waken ( SIGNAL_ARGS ) ;
static void pgarch_waken_stop ( SIGNAL_ARGS ) ;
static void pgarch_MainLoop ( void ) ;
static void pgarch_ArchiverCopyLoop ( void ) ;
static bool pgarch_archiveXlog ( char * xlog ) ;
static bool pgarch_readyXlog ( char * xlog ) ;
static void pgarch_archiveDone ( char * xlog ) ;
static void pgarch_die ( int code , Datum arg ) ;
/* ------------------------------------------------------------
* Public functions called from postmaster follow
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
/*
* pgarch_start
*
* Called from postmaster at startup or after an existing archiver
* died . Attempt to fire up a fresh archiver process .
*
* Returns PID of child process , or 0 if fail .
*
* Note : if fail , we will be called again from the postmaster main loop .
*/
int
pgarch_start ( void )
/* Report shared memory space needed by PgArchShmemInit */
Size
PgArchShmemSize ( void )
{
time_t curtime ;
pid_t pgArchPid ;
/*
* Do nothing if no archiver needed
*/
if ( ! XLogArchivingActive ( ) )
return 0 ;
Size size = 0 ;
/*
* Do nothing if too soon since last archiver start . This is a safety
* valve to protect against continuous respawn attempts if the archiver is
* dying immediately at launch . Note that since we will be re - called from
* the postmaster main loop , we will get another chance later .
*/
curtime = time ( NULL ) ;
if ( ( unsigned int ) ( curtime - last_pgarch_start_time ) <
( unsigned int ) PGARCH_RESTART_INTERVAL )
return 0 ;
last_pgarch_start_time = curtime ;
size = add_size ( size , sizeof ( PgArchData ) ) ;
# ifdef EXEC_BACKEND
switch ( ( pgArchPid = pgarch_forkexec ( ) ) )
# else
switch ( ( pgArchPid = fork_process ( ) ) )
# endif
{
case - 1 :
ereport ( LOG ,
( errmsg ( " could not fork archiver: %m " ) ) ) ;
return 0 ;
# ifndef EXEC_BACKEND
case 0 :
/* in postmaster child ... */
InitPostmasterChild ( ) ;
/* Close the postmaster's sockets */
ClosePostmasterPorts ( false ) ;
return size ;
}
/* Drop our connection to postmaster's shared memory, as well */
dsm_detach_all ( ) ;
PGSharedMemoryDetach ( ) ;
/* Allocate and initialize archiver-related shared memory */
void
PgArchShmemInit ( void )
{
bool found ;
PgArchiverMain ( 0 , NULL ) ;
break ;
# endif
PgArch = ( PgArchData * )
ShmemInitStruct ( " Archiver Data " , PgArchShmemSize ( ) , & found ) ;
default :
return ( int ) pgArchPid ;
if ( ! found )
{
/* First time through, so initialize */
MemSet ( PgArch , 0 , PgArchShmemSize ( ) ) ;
PgArch - > pgprocno = INVALID_PGPROCNO ;
}
/* shouldn't get here */
return 0 ;
}
/* ------------------------------------------------------------
* Local functions called by archiver follow
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
# ifdef EXEC_BACKEND
/*
* pgarch_forkexec ( ) -
* PgArchCanRestart
*
* Return true and archiver is allowed to restart if enough time has
* passed since it was launched last to reach PGARCH_RESTART_INTERVAL .
* Otherwise return false .
*
* Format up the arglist for , then fork and exec , archive process
* This is a safety valve to protect against continuous respawn attempts if the
* archiver is dying immediately at launch . Note that since we will retry to
* launch the archiver from the postmaster main loop , we will get another
* chance later .
*/
static pid_t
pgarch_forkexec ( void )
bool
PgArchCanRestart ( void )
{
char * av [ 10 ] ;
int ac = 0 ;
static time_t last_pgarch_start_time = 0 ;
time_t curtime = time ( NULL ) ;
av [ ac + + ] = " postgres " ;
av [ ac + + ] = " --forkarch " ;
av [ ac + + ] = NULL ; /* filled in by postmaster_forkexec */
av [ ac ] = NULL ;
Assert ( ac < lengthof ( av ) ) ;
/*
* Return false and don ' t restart archiver if too soon since last archiver
* start .
*/
if ( ( unsigned int ) ( curtime - last_pgarch_start_time ) <
( unsigned int ) PGARCH_RESTART_INTERVAL )
return false ;
return postmaster_forkexec ( ac , av ) ;
last_pgarch_start_time = curtime ;
return true ;
}
# endif /* EXEC_BACKEND */
/*
* PgArchiverMain
*
* The argc / argv parameters are valid only in EXEC_BACKEND case . However ,
* since we don ' t use ' em , it hardly matters . . .
*/
NON_EXEC_STATIC void
PgArchiverMain ( int argc , char * argv [ ] )
/* Main entry point for archiver process */
void
PgArchiverMain ( void )
{
/*
* Ignore all signals usually bound to some action in the postmaster ,
@ -231,33 +174,51 @@ PgArchiverMain(int argc, char *argv[])
/* SIGQUIT handler was already set up by InitPostmasterChild */
pqsignal ( SIGALRM , SIG_IGN ) ;
pqsignal ( SIGPIPE , SIG_IGN ) ;
pqsignal ( SIGUSR1 , pgarch_waken ) ;
pqsignal ( SIGUSR1 , procsignal_sigusr1_handler ) ;
pqsignal ( SIGUSR2 , pgarch_waken_stop ) ;
/* Reset some signals that are accepted by postmaster but not here */
pqsignal ( SIGCHLD , SIG_DFL ) ;
/* Unblock signals (they were blocked when the postmaster forked us) */
PG_SETMASK ( & UnBlockSig ) ;
MyBackendType = B_ARCHIVER ;
init_ps_display ( NULL ) ;
/* We shouldn't be launched unnecessarily. */
Assert ( XLogArchivingActive ( ) ) ;
/* Arrange to clean up at archiver exit */
on_shmem_exit ( pgarch_die , 0 ) ;
/*
* Advertise our pgprocno so that backends can use our latch to wake us up
* while we ' re sleeping .
*/
PgArch - > pgprocno = MyProc - > pgprocno ;
pgarch_MainLoop ( ) ;
exit ( 0 ) ;
proc_ exit( 0 ) ;
}
/* SIGUSR1 signal handler for archiver process */
static void
pgarch_waken ( SIGNAL_ARGS )
/*
* Wake up the archiver
*/
void
PgArchWakeup ( void )
{
int save_errno = errno ;
int arch_pgprocno = PgArch - > pgproc no;
/* set flag that there is work to be done */
wakened = true ;
SetLatch ( MyLatch ) ;
errno = save_errno ;
/*
* We don ' t acquire ProcArrayLock here . It ' s actually fine because
* procLatch isn ' t ever freed , so we just can potentially set the wrong
* process ' ( or no process ' ) latch . Even in that case the archiver will
* be relaunched shortly and will start archiving .
*/
if ( arch_pgprocno ! = INVALID_PGPROCNO )
SetLatch ( & ProcGlobal - > allProcs [ arch_pgprocno ] . procLatch ) ;
}
/* SIGUSR2 signal handler for archiver process */
static void
pgarch_waken_stop ( SIGNAL_ARGS )
@ -282,14 +243,6 @@ pgarch_MainLoop(void)
pg_time_t last_copy_time = 0 ;
bool time_to_stop ;
/*
* We run the copy loop immediately upon entry , in case there are
* unarchived files left over from a previous database run ( or maybe the
* archiver died unexpectedly ) . After that we wait for a signal or
* timeout before doing more .
*/
wakened = true ;
/*
* There shouldn ' t be anything for the archiver to do except to wait for a
* signal . . . however , the archiver exists to protect our data , so she
@ -328,12 +281,8 @@ pgarch_MainLoop(void)
}
/* Do what we're here for */
if ( wakened | | time_to_stop )
{
wakened = false ;
pgarch_ArchiverCopyLoop ( ) ;
last_copy_time = time ( NULL ) ;
}
pgarch_ArchiverCopyLoop ( ) ;
last_copy_time = time ( NULL ) ;
/*
* Sleep until a signal is received , or until a poll is forced by
@ -354,13 +303,9 @@ pgarch_MainLoop(void)
WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH ,
timeout * 1000L ,
WAIT_EVENT_ARCHIVER_MAIN ) ;
if ( rc & WL_TIMEOUT )
wakened = true ;
if ( rc & WL_POSTMASTER_DEATH )
time_to_stop = true ;
}
else
wakened = true ;
}
/*
@ -744,3 +689,15 @@ pgarch_archiveDone(char *xlog)
StatusFilePath ( rlogdone , xlog , " .done " ) ;
( void ) durable_rename ( rlogready , rlogdone , WARNING ) ;
}
/*
* pgarch_die
*
* Exit - time cleanup handler
*/
static void
pgarch_die ( int code , Datum arg )
{
PgArch - > pgprocno = INVALID_PGPROCNO ;
}