Received: from maia.hub.org (unknown [200.46.204.183]) by mail.postgresql.org (Postfix) with ESMTP id A7A30633613 for ; Thu, 14 May 2009 13:25:23 -0300 (ADT) Received: from mail.postgresql.org ([200.46.204.86]) by maia.hub.org (mx1.hub.org [200.46.204.183]) (amavisd-maia, port 10024) with ESMTP id 13275-02 for ; Thu, 14 May 2009 13:25:22 -0300 (ADT) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from outmail128067.authsmtp.com (outmail128067.authsmtp.com [62.13.128.67]) by mail.postgresql.org (Postfix) with ESMTP id C81FA633369 for ; Thu, 14 May 2009 13:25:21 -0300 (ADT) Received: from mail-c189.authsmtp.com (mail-c189.authsmtp.com [62.13.128.71]) by punt10.authsmtp.com (8.14.2/8.14.2/Kp) with ESMTP id n4EGP8dp029390; Thu, 14 May 2009 17:25:08 +0100 (BST) Received: from [192.168.0.5] (85-211-225-42.dyn.gotadsl.co.uk [85.211.225.42]) (authenticated bits=0) by mail.authsmtp.com (8.14.2/8.14.2/Kp) with ESMTP id n4EGP4Xt004438; Thu, 14 May 2009 17:25:06 +0100 (BST) Subject: Re: New trigger option of pg_standby From: Simon Riggs To: Heikki Linnakangas Cc: Tom Lane , Fujii Masao , Guillaume Smet , Peter Eisentraut , Kevin Grittner , pgsql-hackers In-Reply-To: <1242247404.3843.503.camel@ebony.2ndQuadrant> References: <3f0b79eb0903242329j12865d55s348f5c873a956e71@mail.gmail.com> <1239381103.16396.30.camel@ebony.2ndQuadrant> <3f0b79eb0904122252t1f4c5860v919d199f399ccf72@mail.gmail.com> <3f0b79eb0904132241p18084914g792cb8e5ab3eebb3@mail.gmail.com> <3f0b79eb0904150101pb1c59a3ubb422867e8e6a944@mail.gmail.com> <49EE1E3F.9050307@enterprisedb.com> <3f0b79eb0904212209i7fbd8b68k71db1fef09c62751@mail.gmail.com> <49F01D79.8020805@enterprisedb.com> <3f0b79eb0904230515p751b5248n6ef96880617db055@mail.gmail.com> <4A095A39.3030100@enterprisedb.com> <3f0b79eb0905130127u3a3275b1w79f4d8cb729ded36@mail.gmail.com> <4A0A86D2.9080602@enterprisedb.com> <1985.1242234105@sss.pgh.pa.us> <4A0B10C7.2040309@enterprisedb.com> <1242247404.3843.503.camel@ebony.2ndQuadrant> Content-Type: multipart/mixed; boundary="=-Tl0cAz6Hen4an3fyAJTH" Date: Thu, 14 May 2009 16:36:55 +0100 Message-Id: <1242315415.3843.526.camel@ebony.2ndQuadrant> Mime-Version: 1.0 X-Mailer: Evolution 2.12.0 X-Server-Quench: c99b3ca3-40a3-11de-bc7b-001f29070be2 X-AuthRoute: OCdxZQATClZOTQEd DAteCiNZVAwpPBRK HVkIKg5MJUcNSQVJ NksacRtFaQFbYFhI HGQLW11EUVp7W2Z/ aw0fZQBDYEtPQQdo VVZNQE1QEQdtHhxP WBprJXl2H0FGeHp0 Zk4sX3BbVEQ0Jk90 EE0HRG4bYWcxa30e URQNalEHd1FXfh9E PFJ2VHQNMzAFKBg1 TUcAHxkaHhhlExEd ZAwSZU4IQEkEEyR0 QAgeHDIpVUoLDz08 GAc6I1gQFld5 X-Authentic-SMTP: 61633235383639.kestrel.dmpriest.net.uk:1562/Kp X-Report-SPAM: If SPAM / abuse - report it at: http://www.authsmtp.com/abuse X-Virus-Status: No virus detected - but ensure you scan with your own anti-virus system. X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=0 tagged_above=0 required=5 tests=none X-Spam-Level: X-Archive-Number: 200905/614 X-Sequence-Number: 138156 --=-Tl0cAz6Hen4an3fyAJTH Content-Type: text/plain Content-Transfer-Encoding: 7bit On Wed, 2009-05-13 at 21:43 +0100, Simon Riggs wrote: > On Wed, 2009-05-13 at 21:26 +0300, Heikki Linnakangas wrote: > > > This whole thing can be considered to be a new feature. > > recovery.conf will contain a new optional parameter: > > recovery_end_command (string) Implemented. Some possibility of re-factoring in calc of %r, though that has not been done to ensure code clarity and avoid need for retesting other aspects of recovery at this stage of beta. -- Simon Riggs www.2ndQuadrant.com PostgreSQL Training, Services and Support --=-Tl0cAz6Hen4an3fyAJTH Content-Disposition: attachment; filename=recovery_end_command.v1.patch Content-Type: text/x-patch; name=recovery_end_command.v1.patch; charset=utf-8 Content-Transfer-Encoding: 7bit Index: doc/src/sgml/backup.sgml =================================================================== RCS file: /home/sriggs/pg/REPOSITORY/pgsql/doc/src/sgml/backup.sgml,v retrieving revision 2.125 diff -c -r2.125 backup.sgml *** doc/src/sgml/backup.sgml 27 Apr 2009 16:27:35 -0000 2.125 --- doc/src/sgml/backup.sgml 14 May 2009 15:14:35 -0000 *************** *** 1126,1131 **** --- 1126,1154 ---- + + recovery_end_command (string) + + + This parameter specifies a shell command that will be executed once only + at the end of recovery. This parameter is optional. The purpose of the + recovery_end_command is to provide a mechanism for cleanup following + replication or recovery. + Any %r is replaced by the name of the file + containing the last valid restart point. That is the earliest file that + must be kept to allow a restore to be restartable, so this information + can be used to truncate the archive to just the minimum required to + support restart of the current restore. %r would only be + used in a warm-standby configuration (see ). + Write %% to embed an actual % character + in the command. + If the command returns a non-zero exit status then a WARNING log + message will be written, unless signalled in which case we return + a FATAL error. + + + + recovery_target_time (timestamp) Index: doc/src/sgml/pgstandby.sgml =================================================================== RCS file: /home/sriggs/pg/REPOSITORY/pgsql/doc/src/sgml/pgstandby.sgml,v retrieving revision 2.7 diff -c -r2.7 pgstandby.sgml *** doc/src/sgml/pgstandby.sgml 27 Feb 2009 09:30:21 -0000 2.7 --- doc/src/sgml/pgstandby.sgml 14 May 2009 15:33:18 -0000 *************** *** 210,215 **** --- 210,216 ---- archive_command = 'cp %p .../archive/%f' restore_command = 'pg_standby -l -d -s 2 -t /tmp/pgsql.trigger.5442 .../archive %f %p %r 2>>standby.log' + recovery_end_command = 'rm /tmp/pgsql.trigger.5442' where the archive directory is physically located on the standby server, *************** *** 241,246 **** --- 242,252 ---- + remove the trigger file when recovery ends + + + + remove no-longer-needed files from the archive directory Index: src/backend/access/transam/xlog.c =================================================================== RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/backend/access/transam/xlog.c,v retrieving revision 1.337 diff -c -r1.337 xlog.c *** src/backend/access/transam/xlog.c 7 May 2009 11:25:25 -0000 1.337 --- src/backend/access/transam/xlog.c 14 May 2009 15:19:41 -0000 *************** *** 147,152 **** --- 147,153 ---- /* options taken from recovery.conf */ static char *recoveryRestoreCommand = NULL; + static char *recoveryEndCommand = NULL; static bool recoveryTarget = false; static bool recoveryTargetExact = false; static bool recoveryTargetInclusive = true; *************** *** 463,468 **** --- 464,470 ---- static void XLogFileClose(void); static bool RestoreArchivedFile(char *path, const char *xlogfname, const char *recovername, off_t expectedSize); + static void ExecuteRecoveryEndCommand(void); static void PreallocXlogFiles(XLogRecPtr endptr); static void RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr); static void ValidateXLOGDirectoryStructure(void); *************** *** 2850,2855 **** --- 2852,2965 ---- } /* + * Attempt to execute the recovery_end_command. + */ + static void + ExecuteRecoveryEndCommand(void) + { + char xlogRecoveryEndCmd[MAXPGPATH]; + char lastRestartPointFname[MAXPGPATH]; + char *dp; + char *endp; + const char *sp; + int rc; + bool signaled; + uint32 restartLog; + uint32 restartSeg; + + Assert(recoveryEndCommand); + + /* + * Calculate the archive file cutoff point for use during log shipping + * replication. All files earlier than this point can be deleted + * from the archive, though there is no requirement to do so. + * + * We initialise this with the filename of an InvalidXLogRecPtr, which + * will prevent the deletion of any WAL files from the archive + * because of the alphabetic sorting property of WAL filenames. + * + * Once we have successfully located the redo pointer of the checkpoint + * from which we start recovery we never request a file prior to the redo + * pointer of the last restartpoint. When redo begins we know that we + * have successfully located it, so there is no need for additional + * status flags to signify the point when we can begin deleting WAL files + * from the archive. + */ + if (InRedo) + { + XLByteToSeg(ControlFile->checkPointCopy.redo, + restartLog, restartSeg); + XLogFileName(lastRestartPointFname, + ControlFile->checkPointCopy.ThisTimeLineID, + restartLog, restartSeg); + } + else + XLogFileName(lastRestartPointFname, 0, 0, 0); + + /* + * construct the command to be executed + */ + dp = xlogRecoveryEndCmd; + endp = xlogRecoveryEndCmd + MAXPGPATH - 1; + *endp = '\0'; + + for (sp = recoveryEndCommand; *sp; sp++) + { + if (*sp == '%') + { + switch (sp[1]) + { + case 'r': + /* %r: filename of last restartpoint */ + sp++; + StrNCpy(dp, lastRestartPointFname, endp - dp); + dp += strlen(dp); + break; + case '%': + /* convert %% to a single % */ + sp++; + if (dp < endp) + *dp++ = *sp; + break; + default: + /* otherwise treat the % as not special */ + if (dp < endp) + *dp++ = *sp; + break; + } + } + else + { + if (dp < endp) + *dp++ = *sp; + } + } + *dp = '\0'; + + ereport(DEBUG3, + (errmsg_internal("executing recovery end command \"%s\"", + xlogRecoveryEndCmd))); + + /* + * Copy xlog from archival storage to XLOGDIR + */ + rc = system(xlogRecoveryEndCmd); + if (rc != 0) + { + /* + * If the failure was due to any sort of signal, it's best to punt and + * abort recovery. See also detailed comments on signals in + * RestoreArchivedFile(). + */ + signaled = WIFSIGNALED(rc) || WEXITSTATUS(rc) > 125; + + ereport(signaled ? FATAL : WARNING, + (errmsg("recovery_end_command \"%s\": return code %d", + xlogRecoveryEndCmd, rc))); + } + } + + /* * Preallocate log files beyond the specified log endpoint. * * XXX this is currently extremely conservative, since it forces only one *************** *** 4664,4669 **** --- 4774,4786 ---- (errmsg("restore_command = '%s'", recoveryRestoreCommand))); } + else if (strcmp(tok1, "recovery_end_command") == 0) + { + recoveryEndCommand = pstrdup(tok2); + ereport(LOG, + (errmsg("recovery_end_command = '%s'", + recoveryEndCommand))); + } else if (strcmp(tok1, "recovery_target_timeline") == 0) { rtliGiven = true; *************** *** 5622,5627 **** --- 5739,5747 ---- * allows some extra error checking in xlog_redo. */ CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE); + + if (recoveryEndCommand) + ExecuteRecoveryEndCommand(); } /* --=-Tl0cAz6Hen4an3fyAJTH--