Skip to content

Commit c21ac0b

Browse files
committed
Add restartpoint_command option to recovery.conf. Fix bug in %r handling
in recovery_end_command, it always came out as 0 because InRedo was cleared before recovery_end_command was executed. Also, always take ControlFileLock when reading checkpoint location for %r. The recovery_end_command bug and the missing locking was present in 8.4 as well, that part of this patch will be backported separately.
1 parent 6407fa9 commit c21ac0b

File tree

2 files changed

+91
-45
lines changed

2 files changed

+91
-45
lines changed

doc/src/sgml/recovery-config.sgml

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/recovery-config.sgml,v 2.2 2010/02/25 09:32:19 heikki Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/recovery-config.sgml,v 2.3 2010/03/18 09:17:18 heikki Exp $ -->
22

33
<chapter Id="recovery-config">
44
<title>Recovery Configuration</title>
@@ -59,14 +59,15 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
5959
</listitem>
6060
</varlistentry>
6161

62-
<varlistentry id="recovery-end-command" xreflabel="recovery_end_command">
63-
<term><varname>recovery_end_command</varname> (<type>string</type>)</term>
62+
<varlistentry id="restartpoint-command" xreflabel="restartpoint_command">
63+
<term><varname>restartpoint_command</varname> (<type>string</type>)</term>
6464
<listitem>
6565
<para>
66-
This parameter specifies a shell command that will be executed once only
67-
at the end of recovery. This parameter is optional. The purpose of the
68-
<varname>recovery_end_command</> is to provide a mechanism for cleanup
69-
following replication or recovery.
66+
This parameter specifies a shell command that will be executed at
67+
every restartpoint. This parameter is optional. The purpose of the
68+
<varname>restartpoint_command</> is to provide a mechanism for cleaning
69+
up old archived WAL files that are no longer needed by the standby
70+
server.
7071
Any <literal>%r</> is replaced by the name of the file
7172
containing the last valid restart point. That is the earliest file that
7273
must be kept to allow a restore to be restartable, so this information
@@ -77,6 +78,24 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
7778
Write <literal>%%</> to embed an actual <literal>%</> character
7879
in the command.
7980
</para>
81+
<para>
82+
If the command returns a non-zero exit status then a WARNING log
83+
message will be written.
84+
</para>
85+
</listitem>
86+
</varlistentry>
87+
88+
<varlistentry id="recovery-end-command" xreflabel="recovery_end_command">
89+
<term><varname>recovery_end_command</varname> (<type>string</type>)</term>
90+
<listitem>
91+
<para>
92+
This parameter specifies a shell command that will be executed once only
93+
at the end of recovery. This parameter is optional. The purpose of the
94+
<varname>recovery_end_command</> is to provide a mechanism for cleanup
95+
following replication or recovery.
96+
Any <literal>%r</> is replaced by the name of the file containing the
97+
last valid restart point, like in <xref linkend="restartpoint-command">.
98+
</para>
8099
<para>
81100
If the command returns a non-zero exit status then a WARNING log
82101
message will be written and the database will proceed to start up

src/backend/access/transam/xlog.c

Lines changed: 65 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.381 2010/03/15 18:49:17 sriggs Exp $
10+
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.382 2010/03/18 09:17:18 heikki Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -171,6 +171,7 @@ static bool restoredFromArchive = false;
171171
/* options taken from recovery.conf for archive recovery */
172172
static char *recoveryRestoreCommand = NULL;
173173
static char *recoveryEndCommand = NULL;
174+
static char *restartPointCommand = NULL;
174175
static bool recoveryTarget = false;
175176
static bool recoveryTargetExact = false;
176177
static bool recoveryTargetInclusive = true;
@@ -370,6 +371,11 @@ typedef struct XLogCtlData
370371
int XLogCacheBlck; /* highest allocated xlog buffer index */
371372
TimeLineID ThisTimeLineID;
372373
TimeLineID RecoveryTargetTLI;
374+
/*
375+
* restartPointCommand is read from recovery.conf but needs to be in
376+
* shared memory so that the bgwriter process can access it.
377+
*/
378+
char restartPointCommand[MAXPGPATH];
373379

374380
/*
375381
* SharedRecoveryInProgress indicates if we're still in crash or archive
@@ -520,7 +526,8 @@ static bool XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt,
520526
static void XLogFileClose(void);
521527
static bool RestoreArchivedFile(char *path, const char *xlogfname,
522528
const char *recovername, off_t expectedSize);
523-
static void ExecuteRecoveryEndCommand(void);
529+
static void ExecuteRecoveryCommand(char *command, char *commandName,
530+
bool failOnerror);
524531
static void PreallocXlogFiles(XLogRecPtr endptr);
525532
static void RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr);
526533
static void ValidateXLOGDirectoryStructure(void);
@@ -2990,12 +2997,19 @@ RestoreArchivedFile(char *path, const char *xlogfname,
29902997
}
29912998

29922999
/*
2993-
* Attempt to execute the recovery_end_command.
3000+
* Attempt to execute an external shell command during recovery.
3001+
*
3002+
* 'command' is the shell command to be executed, 'commandName' is a
3003+
* human-readable name describing the command emitted in the logs. If
3004+
* 'failonSignal' is true and the command is killed by a signal, a FATAL
3005+
* error is thrown. Otherwise a WARNING is emitted.
3006+
*
3007+
* This is currently used for restore_end_command and restartpoint_command.
29943008
*/
29953009
static void
2996-
ExecuteRecoveryEndCommand(void)
3010+
ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal)
29973011
{
2998-
char xlogRecoveryEndCmd[MAXPGPATH];
3012+
char xlogRecoveryCmd[MAXPGPATH];
29993013
char lastRestartPointFname[MAXPGPATH];
30003014
char *dp;
30013015
char *endp;
@@ -3005,43 +3019,29 @@ ExecuteRecoveryEndCommand(void)
30053019
uint32 restartLog;
30063020
uint32 restartSeg;
30073021

3008-
Assert(recoveryEndCommand);
3022+
Assert(command && commandName);
30093023

30103024
/*
30113025
* Calculate the archive file cutoff point for use during log shipping
30123026
* replication. All files earlier than this point can be deleted from the
30133027
* archive, though there is no requirement to do so.
3014-
*
3015-
* We initialise this with the filename of an InvalidXLogRecPtr, which
3016-
* will prevent the deletion of any WAL files from the archive because of
3017-
* the alphabetic sorting property of WAL filenames.
3018-
*
3019-
* Once we have successfully located the redo pointer of the checkpoint
3020-
* from which we start recovery we never request a file prior to the redo
3021-
* pointer of the last restartpoint. When redo begins we know that we have
3022-
* successfully located it, so there is no need for additional status
3023-
* flags to signify the point when we can begin deleting WAL files from
3024-
* the archive.
30253028
*/
3026-
if (InRedo)
3027-
{
3028-
XLByteToSeg(ControlFile->checkPointCopy.redo,
3029-
restartLog, restartSeg);
3030-
XLogFileName(lastRestartPointFname,
3031-
ControlFile->checkPointCopy.ThisTimeLineID,
3032-
restartLog, restartSeg);
3033-
}
3034-
else
3035-
XLogFileName(lastRestartPointFname, 0, 0, 0);
3029+
LWLockAcquire(ControlFileLock, LW_SHARED);
3030+
XLByteToSeg(ControlFile->checkPointCopy.redo,
3031+
restartLog, restartSeg);
3032+
XLogFileName(lastRestartPointFname,
3033+
ControlFile->checkPointCopy.ThisTimeLineID,
3034+
restartLog, restartSeg);
3035+
LWLockRelease(ControlFileLock);
30363036

30373037
/*
30383038
* construct the command to be executed
30393039
*/
3040-
dp = xlogRecoveryEndCmd;
3041-
endp = xlogRecoveryEndCmd + MAXPGPATH - 1;
3040+
dp = xlogRecoveryCmd;
3041+
endp = xlogRecoveryCmd + MAXPGPATH - 1;
30423042
*endp = '\0';
30433043

3044-
for (sp = recoveryEndCommand; *sp; sp++)
3044+
for (sp = command; *sp; sp++)
30453045
{
30463046
if (*sp == '%')
30473047
{
@@ -3075,13 +3075,12 @@ ExecuteRecoveryEndCommand(void)
30753075
*dp = '\0';
30763076

30773077
ereport(DEBUG3,
3078-
(errmsg_internal("executing recovery end command \"%s\"",
3079-
xlogRecoveryEndCmd)));
3078+
(errmsg_internal("executing %s \"%s\"", commandName, command)));
30803079

30813080
/*
30823081
* execute the constructed command
30833082
*/
3084-
rc = system(xlogRecoveryEndCmd);
3083+
rc = system(xlogRecoveryCmd);
30853084
if (rc != 0)
30863085
{
30873086
/*
@@ -3091,9 +3090,13 @@ ExecuteRecoveryEndCommand(void)
30913090
*/
30923091
signaled = WIFSIGNALED(rc) || WEXITSTATUS(rc) > 125;
30933092

3094-
ereport(signaled ? FATAL : WARNING,
3095-
(errmsg("recovery_end_command \"%s\": return code %d",
3096-
xlogRecoveryEndCmd, rc)));
3093+
/*
3094+
* translator: First %s represents a recovery.conf parameter name like
3095+
* "recovery_end_command", and the 2nd is the value of that parameter.
3096+
*/
3097+
ereport((signaled && failOnSignal) ? FATAL : WARNING,
3098+
(errmsg("%s \"%s\": return code %d", commandName,
3099+
command, rc)));
30973100
}
30983101
}
30993102

@@ -4936,6 +4939,13 @@ readRecoveryCommandFile(void)
49364939
(errmsg("recovery_end_command = '%s'",
49374940
recoveryEndCommand)));
49384941
}
4942+
else if (strcmp(tok1, "restartpoint_command") == 0)
4943+
{
4944+
restartPointCommand = pstrdup(tok2);
4945+
ereport(DEBUG2,
4946+
(errmsg("restartpoint_command = '%s'",
4947+
restartPointCommand)));
4948+
}
49394949
else if (strcmp(tok1, "recovery_target_timeline") == 0)
49404950
{
49414951
rtliGiven = true;
@@ -5505,8 +5515,14 @@ StartupXLOG(void)
55055515
recoveryTargetTLI,
55065516
ControlFile->checkPointCopy.ThisTimeLineID)));
55075517

5508-
/* Save the selected recovery target timeline ID in shared memory */
5518+
/*
5519+
* Save the selected recovery target timeline ID and restartpoint_command
5520+
* in shared memory so that other processes can see them
5521+
*/
55095522
XLogCtl->RecoveryTargetTLI = recoveryTargetTLI;
5523+
strncpy(XLogCtl->restartPointCommand,
5524+
restartPointCommand ? restartPointCommand : "",
5525+
sizeof(XLogCtl->restartPointCommand));
55105526

55115527
if (read_backup_label(&checkPointLoc))
55125528
{
@@ -6129,7 +6145,9 @@ StartupXLOG(void)
61296145
* And finally, execute the recovery_end_command, if any.
61306146
*/
61316147
if (recoveryEndCommand)
6132-
ExecuteRecoveryEndCommand();
6148+
ExecuteRecoveryCommand(recoveryEndCommand,
6149+
"recovery_end_command",
6150+
true);
61336151
}
61346152

61356153
/*
@@ -7318,6 +7336,15 @@ CreateRestartPoint(int flags)
73187336
timestamptz_to_str(GetLatestXLogTime()))));
73197337

73207338
LWLockRelease(CheckpointLock);
7339+
7340+
/*
7341+
* Finally, execute restartpoint_command, if any.
7342+
*/
7343+
if (XLogCtl->restartPointCommand[0])
7344+
ExecuteRecoveryCommand(XLogCtl->restartPointCommand,
7345+
"restartpoint_command",
7346+
false);
7347+
73217348
return true;
73227349
}
73237350

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy